summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/Makefile12
-rw-r--r--examples/Makefile.http.in12
-rw-r--r--examples/Makefile.telnet.in12
-rw-r--r--examples/OCamlMakefile1154
-rw-r--r--examples/http.ml688
-rw-r--r--examples/telnet.ml181
6 files changed, 2059 insertions, 0 deletions
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
index 0000000..2b9d33d
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,12 @@
+# OCaml-Lastfm examples.
+#
+# Copyright 2007 by the Savonet team.
+#
+# $Id: Makefile 4694 2007-10-23 23:33:11Z smimram $
+
+all clean:
+ $(MAKE) -f Makefile.telnet $@
+ $(MAKE) -f Makefile.http $@
+
+distclean: clean
+ rm -rf autom4te.cache config.log config.status autom4te.cache
diff --git a/examples/Makefile.http.in b/examples/Makefile.http.in
new file mode 100644
index 0000000..d560b96
--- /dev/null
+++ b/examples/Makefile.http.in
@@ -0,0 +1,12 @@
+SOURCES = http.ml
+RESULT = http
+INCDIRS = ../src @ALL_INC@
+OCAMLC = @OCAMLC@ -thread
+OCAMLOPT = @OCAMLOPT@ -thread
+LIBS = @all_requires@ duppy
+PP = camlp4o -I ../src pa_duppy.cmo
+export PP
+
+all: nc
+
+-include OCamlMakefile
diff --git a/examples/Makefile.telnet.in b/examples/Makefile.telnet.in
new file mode 100644
index 0000000..5cc1869
--- /dev/null
+++ b/examples/Makefile.telnet.in
@@ -0,0 +1,12 @@
+SOURCES = telnet.ml
+RESULT = telnet
+INCDIRS = ../src @ALL_INC@
+OCAMLC = @OCAMLC@ -thread
+OCAMLOPT = @OCAMLOPT@ -thread
+LIBS = @all_requires@ duppy
+PP = camlp4o -I ../src pa_duppy.cmo
+export PP
+
+all: nc
+
+-include OCamlMakefile
diff --git a/examples/OCamlMakefile b/examples/OCamlMakefile
new file mode 100644
index 0000000..6f62c91
--- /dev/null
+++ b/examples/OCamlMakefile
@@ -0,0 +1,1154 @@
+###########################################################################
+# OCamlMakefile
+# Copyright (C) 1999-2004 Markus Mottl
+#
+# For updates see:
+# http://www.ocaml.info/home/ocaml_sources.html
+#
+# $Id: OCamlMakefile,v 1.72 2005/12/09 15:30:50 mottl Exp $
+#
+###########################################################################
+
+# Modified by damien for .glade.ml compilation
+
+# Set these variables to the names of the sources to be processed and
+# the result variable. Order matters during linkage!
+
+ifndef SOURCES
+ SOURCES := foo.ml
+endif
+export SOURCES
+
+ifndef RES_CLIB_SUF
+ RES_CLIB_SUF := _stubs
+endif
+export RES_CLIB_SUF
+
+ifndef RESULT
+ RESULT := foo
+endif
+export RESULT
+
+export LIB_PACK_NAME
+
+ifndef DOC_FILES
+ DOC_FILES := $(filter %.mli, $(SOURCES))
+endif
+export DOC_FILES
+
+export BCSUFFIX
+export NCSUFFIX
+
+ifndef TOPSUFFIX
+ TOPSUFFIX := .top
+endif
+export TOPSUFFIX
+
+# Eventually set include- and library-paths, libraries to link,
+# additional compilation-, link- and ocamlyacc-flags
+# Path- and library information needs not be written with "-I" and such...
+# Define THREADS if you need it, otherwise leave it unset (same for
+# USE_CAMLP4)!
+
+export THREADS
+export VMTHREADS
+export ANNOTATE
+export USE_CAMLP4
+
+export INCDIRS
+export LIBDIRS
+export EXTLIBDIRS
+export RESULTDEPS
+export OCAML_DEFAULT_DIRS
+
+export LIBS
+export CLIBS
+
+export OCAMLFLAGS
+export OCAMLNCFLAGS
+export OCAMLBCFLAGS
+
+export OCAMLLDFLAGS
+export OCAMLNLDFLAGS
+export OCAMLBLDFLAGS
+
+ifndef OCAMLCPFLAGS
+ OCAMLCPFLAGS := a
+endif
+
+export OCAMLCPFLAGS
+
+export PPFLAGS
+
+export YFLAGS
+export IDLFLAGS
+
+export OCAMLDOCFLAGS
+
+export OCAMLFIND_INSTFLAGS
+
+export DVIPSFLAGS
+
+export STATIC
+
+# Add a list of optional trash files that should be deleted by "make clean"
+export TRASH
+
+#################### variables depending on your OCaml-installation
+
+ifdef MINGW
+ export MINGW
+ WIN32 := 1
+ CFLAGS_WIN32 := -mno-cygwin
+endif
+ifdef MSVC
+ export MSVC
+ WIN32 := 1
+ ifndef STATIC
+ CPPFLAGS_WIN32 := -DCAML_DLL
+ endif
+ CFLAGS_WIN32 += -nologo
+ EXT_OBJ := obj
+ EXT_LIB := lib
+ ifeq ($(CC),gcc)
+ # work around GNU Make default value
+ ifdef THREADS
+ CC := cl -MT
+ else
+ CC := cl
+ endif
+ endif
+ ifeq ($(CXX),g++)
+ # work around GNU Make default value
+ CXX := $(CC)
+ endif
+ CFLAG_O := -Fo
+endif
+ifdef WIN32
+ EXT_CXX := cpp
+ EXE := .exe
+endif
+
+ifndef EXT_OBJ
+ EXT_OBJ := o
+endif
+ifndef EXT_LIB
+ EXT_LIB := a
+endif
+ifndef EXT_CXX
+ EXT_CXX := cc
+endif
+ifndef EXE
+ EXE := # empty
+endif
+ifndef CFLAG_O
+ CFLAG_O := -o # do not delete this comment (preserves trailing whitespace)!
+endif
+
+export CC
+export CXX
+export CFLAGS
+export CXXFLAGS
+export LDFLAGS
+export CPPFLAGS
+
+ifndef RPATH_FLAG
+ RPATH_FLAG := -R
+endif
+export RPATH_FLAG
+
+ifndef MSVC
+ifndef PIC_CFLAGS
+ PIC_CFLAGS := -fPIC
+endif
+ifndef PIC_CPPFLAGS
+ PIC_CPPFLAGS := -DPIC
+endif
+endif
+
+export PIC_CFLAGS
+export PIC_CPPFLAGS
+
+BCRESULT := $(addsuffix $(BCSUFFIX), $(RESULT))
+NCRESULT := $(addsuffix $(NCSUFFIX), $(RESULT))
+TOPRESULT := $(addsuffix $(TOPSUFFIX), $(RESULT))
+
+ifndef OCAMLFIND
+ OCAMLFIND := ocamlfind
+endif
+export OCAMLFIND
+
+ifndef OCAMLC
+ OCAMLC := ocamlc
+endif
+export OCAMLC
+
+ifndef OCAMLOPT
+ OCAMLOPT := ocamlopt
+endif
+export OCAMLOPT
+
+ifndef OCAMLMKTOP
+ OCAMLMKTOP := ocamlmktop
+endif
+export OCAMLMKTOP
+
+ifndef OCAMLCP
+ OCAMLCP := ocamlcp
+endif
+export OCAMLCP
+
+ifndef OCAMLDEP
+ OCAMLDEP := ocamldep
+endif
+export OCAMLDEP
+
+ifndef OCAMLLEX
+ OCAMLLEX := ocamllex
+endif
+export OCAMLLEX
+
+ifndef OCAMLYACC
+ OCAMLYACC := ocamlyacc
+endif
+export OCAMLYACC
+
+ifndef OCAMLMKLIB
+ OCAMLMKLIB := ocamlmklib
+endif
+export OCAMLMKLIB
+
+ifndef OCAML_GLADECC
+ OCAML_GLADECC := lablgladecc2
+endif
+export OCAML_GLADECC
+
+ifndef OCAML_GLADECC_FLAGS
+ OCAML_GLADECC_FLAGS :=
+endif
+export OCAML_GLADECC_FLAGS
+
+ifndef CAMELEON_REPORT
+ CAMELEON_REPORT := report
+endif
+export CAMELEON_REPORT
+
+ifndef CAMELEON_REPORT_FLAGS
+ CAMELEON_REPORT_FLAGS :=
+endif
+export CAMELEON_REPORT_FLAGS
+
+ifndef CAMELEON_ZOGGY
+ CAMELEON_ZOGGY := camlp4o pa_zog.cma pr_o.cmo
+endif
+export CAMELEON_ZOGGY
+
+ifndef CAMELEON_ZOGGY_FLAGS
+ CAMELEON_ZOGGY_FLAGS :=
+endif
+export CAMELEON_ZOGGY_FLAGS
+
+ifndef OXRIDL
+ OXRIDL := oxridl
+endif
+export OXRIDL
+
+ifndef CAMLIDL
+ CAMLIDL := camlidl
+endif
+export CAMLIDL
+
+ifndef CAMLIDLDLL
+ CAMLIDLDLL := camlidldll
+endif
+export CAMLIDLDLL
+
+ifndef NOIDLHEADER
+ MAYBE_IDL_HEADER := -header
+endif
+export NOIDLHEADER
+
+export NO_CUSTOM
+
+ifndef CAMLP4
+ CAMLP4 := camlp4
+endif
+export CAMLP4
+
+ifndef REAL_OCAMLFIND
+ ifdef PACKS
+ ifndef CREATE_LIB
+ ifdef THREADS
+ PACKS += threads
+ endif
+ endif
+ empty :=
+ space := $(empty) $(empty)
+ comma := ,
+ ifdef PREDS
+ PRE_OCAML_FIND_PREDICATES := $(subst $(space),$(comma),$(PREDS))
+ PRE_OCAML_FIND_PACKAGES := $(subst $(space),$(comma),$(PACKS))
+ OCAML_FIND_PREDICATES := -predicates $(PRE_OCAML_FIND_PREDICATES)
+ # OCAML_DEP_PREDICATES := -syntax $(PRE_OCAML_FIND_PREDICATES)
+ OCAML_FIND_PACKAGES := $(OCAML_FIND_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES)
+ OCAML_DEP_PACKAGES := $(OCAML_DEP_PREDICATES) -package $(PRE_OCAML_FIND_PACKAGES)
+ else
+ OCAML_FIND_PACKAGES := -package $(subst $(space),$(comma),$(PACKS))
+ OCAML_DEP_PACKAGES :=
+ endif
+ OCAML_FIND_LINKPKG := -linkpkg
+ REAL_OCAMLFIND := $(OCAMLFIND)
+ endif
+endif
+
+export OCAML_FIND_PACKAGES
+export OCAML_DEP_PACKAGES
+export OCAML_FIND_LINKPKG
+export REAL_OCAMLFIND
+
+ifndef OCAMLDOC
+ OCAMLDOC := ocamldoc
+endif
+export OCAMLDOC
+
+ifndef LATEX
+ LATEX := latex
+endif
+export LATEX
+
+ifndef DVIPS
+ DVIPS := dvips
+endif
+export DVIPS
+
+ifndef PS2PDF
+ PS2PDF := ps2pdf
+endif
+export PS2PDF
+
+ifndef OCAMLMAKEFILE
+ OCAMLMAKEFILE := OCamlMakefile
+endif
+export OCAMLMAKEFILE
+
+ifndef OCAMLLIBPATH
+ OCAMLLIBPATH := \
+ $(shell $(OCAMLC) 2>/dev/null -where || echo /usr/lib/ocaml)
+endif
+export OCAMLLIBPATH
+
+ifndef OCAML_LIB_INSTALL
+ OCAML_LIB_INSTALL := $(OCAMLLIBPATH)/contrib
+endif
+export OCAML_LIB_INSTALL
+
+###########################################################################
+
+#################### change following sections only if
+#################### you know what you are doing!
+
+# delete target files when a build command fails
+.PHONY: .DELETE_ON_ERROR
+.DELETE_ON_ERROR:
+
+# for pedants using "--warn-undefined-variables"
+export MAYBE_IDL
+export REAL_RESULT
+export CAMLIDLFLAGS
+export THREAD_FLAG
+export RES_CLIB
+export MAKEDLL
+export ANNOT_FLAG
+export C_OXRIDL
+export SUBPROJS
+export CFLAGS_WIN32
+export CPPFLAGS_WIN32
+
+INCFLAGS :=
+
+SHELL := /bin/sh
+
+MLDEPDIR := ._d
+BCDIDIR := ._bcdi
+NCDIDIR := ._ncdi
+
+FILTER_EXTNS := %.mli %.ml %.mll %.mly %.idl %.oxridl %.c %.$(EXT_CXX) %.rep %.zog %.glade
+
+FILTERED := $(filter $(FILTER_EXTNS), $(SOURCES))
+SOURCE_DIRS := $(filter-out ./, $(sort $(dir $(FILTERED))))
+
+FILTERED_REP := $(filter %.rep, $(FILTERED))
+DEP_REP := $(FILTERED_REP:%.rep=$(MLDEPDIR)/%.d)
+AUTO_REP := $(FILTERED_REP:.rep=.ml)
+
+FILTERED_ZOG := $(filter %.zog, $(FILTERED))
+DEP_ZOG := $(FILTERED_ZOG:%.zog=$(MLDEPDIR)/%.d)
+AUTO_ZOG := $(FILTERED_ZOG:.zog=.ml)
+
+FILTERED_GLADE := $(filter %.glade, $(FILTERED))
+DEP_GLADE := $(FILTERED_GLADE:%.glade=$(MLDEPDIR)/%.d)
+AUTO_GLADE := $(FILTERED_GLADE:.glade=.ml)
+
+FILTERED_ML := $(filter %.ml, $(FILTERED))
+DEP_ML := $(FILTERED_ML:%.ml=$(MLDEPDIR)/%.d)
+
+FILTERED_MLI := $(filter %.mli, $(FILTERED))
+DEP_MLI := $(FILTERED_MLI:.mli=.di)
+
+FILTERED_MLL := $(filter %.mll, $(FILTERED))
+DEP_MLL := $(FILTERED_MLL:%.mll=$(MLDEPDIR)/%.d)
+AUTO_MLL := $(FILTERED_MLL:.mll=.ml)
+
+FILTERED_MLY := $(filter %.mly, $(FILTERED))
+DEP_MLY := $(FILTERED_MLY:%.mly=$(MLDEPDIR)/%.d) $(FILTERED_MLY:.mly=.di)
+AUTO_MLY := $(FILTERED_MLY:.mly=.mli) $(FILTERED_MLY:.mly=.ml)
+
+FILTERED_IDL := $(filter %.idl, $(FILTERED))
+DEP_IDL := $(FILTERED_IDL:%.idl=$(MLDEPDIR)/%.d) $(FILTERED_IDL:.idl=.di)
+C_IDL := $(FILTERED_IDL:%.idl=%_stubs.c)
+ifndef NOIDLHEADER
+ C_IDL += $(FILTERED_IDL:.idl=.h)
+endif
+OBJ_C_IDL := $(FILTERED_IDL:%.idl=%_stubs.$(EXT_OBJ))
+AUTO_IDL := $(FILTERED_IDL:.idl=.mli) $(FILTERED_IDL:.idl=.ml) $(C_IDL)
+
+FILTERED_OXRIDL := $(filter %.oxridl, $(FILTERED))
+DEP_OXRIDL := $(FILTERED_OXRIDL:%.oxridl=$(MLDEPDIR)/%.d) $(FILTERED_OXRIDL:.oxridl=.di)
+AUTO_OXRIDL := $(FILTERED_OXRIDL:.oxridl=.mli) $(FILTERED_OXRIDL:.oxridl=.ml) $(C_OXRIDL)
+
+FILTERED_C_CXX := $(filter %.c %.$(EXT_CXX), $(FILTERED))
+OBJ_C_CXX := $(FILTERED_C_CXX:.c=.$(EXT_OBJ))
+OBJ_C_CXX := $(OBJ_C_CXX:.$(EXT_CXX)=.$(EXT_OBJ))
+
+PRE_TARGETS += $(AUTO_MLL) $(AUTO_MLY) $(AUTO_IDL) $(AUTO_OXRIDL) $(AUTO_ZOG) $(AUTO_REP) $(AUTO_GLADE)
+
+ALL_DEPS := $(DEP_ML) $(DEP_MLI) $(DEP_MLL) $(DEP_MLY) $(DEP_IDL) $(DEP_OXRIDL) $(DEP_ZOG) $(DEP_REP) $(DEP_GLADE)
+
+MLDEPS := $(filter %.d, $(ALL_DEPS))
+MLIDEPS := $(filter %.di, $(ALL_DEPS))
+BCDEPIS := $(MLIDEPS:%.di=$(BCDIDIR)/%.di)
+NCDEPIS := $(MLIDEPS:%.di=$(NCDIDIR)/%.di)
+
+ALLML := $(filter %.mli %.ml %.mll %.mly %.idl %.oxridl %.rep %.zog %.glade, $(FILTERED))
+
+IMPLO_INTF := $(ALLML:%.mli=%.mli.__)
+IMPLO_INTF := $(foreach file, $(IMPLO_INTF), \
+ $(basename $(file)).cmi $(basename $(file)).cmo)
+IMPLO_INTF := $(filter-out %.mli.cmo, $(IMPLO_INTF))
+IMPLO_INTF := $(IMPLO_INTF:%.mli.cmi=%.cmi)
+
+IMPLX_INTF := $(IMPLO_INTF:.cmo=.cmx)
+
+INTF := $(filter %.cmi, $(IMPLO_INTF))
+IMPL_CMO := $(filter %.cmo, $(IMPLO_INTF))
+IMPL_CMX := $(IMPL_CMO:.cmo=.cmx)
+IMPL_ASM := $(IMPL_CMO:.cmo=.asm)
+IMPL_S := $(IMPL_CMO:.cmo=.s)
+
+OBJ_LINK := $(OBJ_C_IDL) $(OBJ_C_CXX)
+OBJ_FILES := $(IMPL_CMO:.cmo=.$(EXT_OBJ)) $(OBJ_LINK)
+
+EXECS := $(addsuffix $(EXE), \
+ $(sort $(TOPRESULT) $(BCRESULT) $(NCRESULT)))
+ifdef WIN32
+ EXECS += $(BCRESULT).dll $(NCRESULT).dll
+endif
+
+CLIB_BASE := $(RESULT)$(RES_CLIB_SUF)
+ifneq ($(strip $(OBJ_LINK)),)
+ RES_CLIB := lib$(CLIB_BASE).$(EXT_LIB)
+endif
+
+ifdef WIN32
+DLLSONAME := $(CLIB_BASE).dll
+else
+DLLSONAME := dll$(CLIB_BASE).so
+endif
+
+NONEXECS := $(INTF) $(IMPL_CMO) $(IMPL_CMX) $(IMPL_ASM) $(IMPL_S) \
+ $(OBJ_FILES) $(PRE_TARGETS) $(BCRESULT).cma $(NCRESULT).cmxa \
+ $(NCRESULT).$(EXT_LIB) $(BCRESULT).cmi $(BCRESULT).cmo \
+ $(NCRESULT).cmi $(NCRESULT).cmx $(NCRESULT).o \
+ $(RES_CLIB) $(IMPL_CMO:.cmo=.annot) \
+ $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(LIB_PACK_NAME).cmx $(LIB_PACK_NAME).o
+
+ifndef STATIC
+ NONEXECS += $(DLLSONAME)
+endif
+
+ifndef LIBINSTALL_FILES
+ LIBINSTALL_FILES := $(RESULT).mli $(RESULT).cmi $(RESULT).cma \
+ $(RESULT).cmxa $(RESULT).$(EXT_LIB) $(RES_CLIB)
+ ifndef STATIC
+ ifneq ($(strip $(OBJ_LINK)),)
+ LIBINSTALL_FILES += $(DLLSONAME)
+ endif
+ endif
+endif
+
+export LIBINSTALL_FILES
+
+ifdef WIN32
+ # some extra stuff is created while linking DLLs
+ NONEXECS += $(BCRESULT).$(EXT_LIB) $(BCRESULT).exp $(NCRESULT).exp $(CLIB_BASE).exp $(CLIB_BASE).lib
+endif
+
+TARGETS := $(EXECS) $(NONEXECS)
+
+# If there are IDL-files
+ifneq ($(strip $(FILTERED_IDL)),)
+ MAYBE_IDL := -cclib -lcamlidl
+endif
+
+ifdef USE_CAMLP4
+ CAMLP4PATH := \
+ $(shell $(CAMLP4) -where 2>/dev/null || echo /usr/lib/camlp4)
+ INCFLAGS := -I $(CAMLP4PATH)
+ CINCFLAGS := -I$(CAMLP4PATH)
+endif
+
+DINCFLAGS := $(INCFLAGS) $(SOURCE_DIRS:%=-I %) $(OCAML_DEFAULT_DIRS:%=-I %)
+INCFLAGS := $(DINCFLAGS) $(INCDIRS:%=-I %)
+CINCFLAGS += $(SOURCE_DIRS:%=-I%) $(INCDIRS:%=-I%) $(OCAML_DEFAULT_DIRS:%=-I%)
+
+ifndef MSVC
+CLIBFLAGS += $(SOURCE_DIRS:%=-L%) $(LIBDIRS:%=-L%) \
+ $(EXTLIBDIRS:%=-L%) $(EXTLIBDIRS:%=-Wl,$(RPATH_FLAG)%) \
+ $(OCAML_DEFAULT_DIRS:%=-L%)
+endif
+
+ifndef PROFILING
+ INTF_OCAMLC := $(OCAMLC)
+else
+ ifndef THREADS
+ INTF_OCAMLC := $(OCAMLCP) -p $(OCAMLCPFLAGS)
+ else
+ # OCaml does not support profiling byte code
+ # with threads (yet), therefore we force an error.
+ ifndef REAL_OCAMLC
+ $(error Profiling of multithreaded byte code not yet supported by OCaml)
+ endif
+ INTF_OCAMLC := $(OCAMLC)
+ endif
+endif
+
+ifndef MSVC
+COMMON_LDFLAGS := $(LDFLAGS:%=-ccopt %) $(SOURCE_DIRS:%=-ccopt -L%) \
+ $(LIBDIRS:%=-ccopt -L%) $(EXTLIBDIRS:%=-ccopt -L%) \
+ $(EXTLIBDIRS:%=-ccopt -Wl,$(RPATH_FLAG)%) \
+ $(OCAML_DEFAULT_DIRS:%=-ccopt -L%)
+else
+COMMON_LDFLAGS := -ccopt "/link -NODEFAULTLIB:LIBC $(LDFLAGS:%=%) $(SOURCE_DIRS:%=-LIBPATH:%) \
+ $(LIBDIRS:%=-LIBPATH:%) $(EXTLIBDIRS:%=-LIBPATH:%) \
+ $(OCAML_DEFAULT_DIRS:%=-LIBPATH:%) "
+endif
+
+CLIBS_OPTS := $(CLIBS:%=-cclib -l%)
+ifdef MSVC
+ ifndef STATIC
+ # MSVC libraries do not have 'lib' prefix
+ CLIBS_OPTS := $(CLIBS:%=-cclib %.lib)
+ endif
+endif
+
+ifneq ($(strip $(OBJ_LINK)),)
+ ifdef CREATE_LIB
+ OBJS_LIBS := -cclib -l$(CLIB_BASE) $(CLIBS_OPTS) $(MAYBE_IDL)
+ else
+ OBJS_LIBS := $(OBJ_LINK) $(CLIBS_OPTS) $(MAYBE_IDL)
+ endif
+else
+ OBJS_LIBS := $(CLIBS_OPTS) $(MAYBE_IDL)
+endif
+
+# If we have to make byte-code
+ifndef REAL_OCAMLC
+ BYTE_OCAML := y
+
+ # EXTRADEPS is added dependencies we have to insert for all
+ # executable files we generate. Ideally it should be all of the
+ # libraries we use, but it's hard to find the ones that get searched on
+ # the path since I don't know the paths built into the compiler, so
+ # just include the ones with slashes in their names.
+ EXTRADEPS := $(addsuffix .cma,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i))))
+ SPECIAL_OCAMLFLAGS := $(OCAMLBCFLAGS)
+
+ REAL_OCAMLC := $(INTF_OCAMLC)
+
+ REAL_IMPL := $(IMPL_CMO)
+ REAL_IMPL_INTF := $(IMPLO_INTF)
+ IMPL_SUF := .cmo
+
+ DEPFLAGS :=
+ MAKE_DEPS := $(MLDEPS) $(BCDEPIS)
+
+ ifdef CREATE_LIB
+ override CFLAGS := $(PIC_CFLAGS) $(CFLAGS)
+ override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS)
+ ifndef STATIC
+ ifneq ($(strip $(OBJ_LINK)),)
+ MAKEDLL := $(DLLSONAME)
+ ALL_LDFLAGS := -dllib $(DLLSONAME)
+ endif
+ endif
+ endif
+
+ ifndef NO_CUSTOM
+ ifneq "$(strip $(OBJ_LINK) $(THREADS) $(MAYBE_IDL) $(CLIBS))" ""
+ ALL_LDFLAGS += -custom
+ endif
+ endif
+
+ ALL_LDFLAGS += $(INCFLAGS) $(OCAMLLDFLAGS) $(OCAMLBLDFLAGS) \
+ $(COMMON_LDFLAGS) $(LIBS:%=%.cma)
+ CAMLIDLDLLFLAGS :=
+
+ ifdef THREADS
+ ifdef VMTHREADS
+ THREAD_FLAG := -vmthread
+ else
+ THREAD_FLAG := -thread
+ endif
+ ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS)
+ ifndef CREATE_LIB
+ ifndef REAL_OCAMLFIND
+ ALL_LDFLAGS := unix.cma threads.cma $(ALL_LDFLAGS)
+ endif
+ endif
+ endif
+
+# we have to make native-code
+else
+ EXTRADEPS := $(addsuffix .cmxa,$(foreach i,$(LIBS),$(if $(findstring /,$(i)),$(i))))
+ ifndef PROFILING
+ SPECIAL_OCAMLFLAGS := $(OCAMLNCFLAGS)
+ PLDFLAGS :=
+ else
+ SPECIAL_OCAMLFLAGS := -p $(OCAMLNCFLAGS)
+ PLDFLAGS := -p
+ endif
+
+ REAL_IMPL := $(IMPL_CMX)
+ REAL_IMPL_INTF := $(IMPLX_INTF)
+ IMPL_SUF := .cmx
+
+ override CPPFLAGS := -DNATIVE_CODE $(CPPFLAGS)
+
+ DEPFLAGS := -native
+ MAKE_DEPS := $(MLDEPS) $(NCDEPIS)
+
+ ALL_LDFLAGS := $(PLDFLAGS) $(INCFLAGS) $(OCAMLLDFLAGS) \
+ $(OCAMLNLDFLAGS) $(COMMON_LDFLAGS)
+ CAMLIDLDLLFLAGS := -opt
+
+ ifndef CREATE_LIB
+ ALL_LDFLAGS += $(LIBS:%=%.cmxa)
+ else
+ override CFLAGS := $(PIC_CFLAGS) $(CFLAGS)
+ override CPPFLAGS := $(PIC_CPPFLAGS) $(CPPFLAGS)
+ endif
+
+ ifdef THREADS
+ THREAD_FLAG := -thread
+ ALL_LDFLAGS := $(THREAD_FLAG) $(ALL_LDFLAGS)
+ ifndef CREATE_LIB
+ ifndef REAL_OCAMLFIND
+ ALL_LDFLAGS := unix.cmxa threads.cmxa $(ALL_LDFLAGS)
+ endif
+ endif
+ endif
+endif
+
+export MAKE_DEPS
+
+ifdef ANNOTATE
+ ANNOT_FLAG := -dtypes
+else
+endif
+
+ALL_OCAMLCFLAGS := $(THREAD_FLAG) $(ANNOT_FLAG) $(OCAMLFLAGS) \
+ $(INCFLAGS) $(SPECIAL_OCAMLFLAGS)
+
+ifdef make_deps
+ -include $(MAKE_DEPS)
+ PRE_TARGETS :=
+endif
+
+###########################################################################
+# USER RULES
+
+# Call "OCamlMakefile QUIET=" to get rid of all of the @'s.
+QUIET=@
+
+# generates byte-code (default)
+byte-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes
+bc: byte-code
+
+byte-code-nolink: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes
+bcnl: byte-code-nolink
+
+top: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(TOPRESULT) \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes
+
+# generates native-code
+
+native-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ make_deps=yes
+nc: native-code
+
+native-code-nolink: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ make_deps=yes
+ncnl: native-code-nolink
+
+# generates byte-code libraries
+byte-code-library: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(BCRESULT).cma \
+ REAL_RESULT="$(BCRESULT)" \
+ CREATE_LIB=yes \
+ make_deps=yes
+bcl: byte-code-library
+
+# generates native-code libraries
+native-code-library: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(NCRESULT).cmxa \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ CREATE_LIB=yes \
+ make_deps=yes
+ncl: native-code-library
+
+ifdef WIN32
+# generates byte-code dll
+byte-code-dll: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(BCRESULT).dll \
+ REAL_RESULT="$(BCRESULT)" \
+ make_deps=yes
+bcd: byte-code-dll
+
+# generates native-code dll
+native-code-dll: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(NCRESULT).dll \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ make_deps=yes
+ncd: native-code-dll
+endif
+
+# generates byte-code with debugging information
+debug-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes \
+ OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dc: debug-code
+
+debug-code-nolink: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) nolink \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes \
+ OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dcnl: debug-code-nolink
+
+# generates byte-code libraries with debugging information
+debug-code-library: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(BCRESULT).cma \
+ REAL_RESULT="$(BCRESULT)" make_deps=yes \
+ CREATE_LIB=yes \
+ OCAMLFLAGS="-g $(OCAMLFLAGS)" \
+ OCAMLLDFLAGS="-g $(OCAMLLDFLAGS)"
+dcl: debug-code-library
+
+# generates byte-code for profiling
+profiling-byte-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT) \
+ REAL_RESULT="$(BCRESULT)" PROFILING="y" \
+ make_deps=yes
+pbc: profiling-byte-code
+
+# generates native-code
+
+profiling-native-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(NCRESULT) \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ PROFILING="y" \
+ make_deps=yes
+pnc: profiling-native-code
+
+# generates byte-code libraries
+profiling-byte-code-library: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(BCRESULT).cma \
+ REAL_RESULT="$(BCRESULT)" PROFILING="y" \
+ CREATE_LIB=yes \
+ make_deps=yes
+pbcl: profiling-byte-code-library
+
+# generates native-code libraries
+profiling-native-code-library: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(RES_CLIB) $(NCRESULT).cmxa \
+ REAL_RESULT="$(NCRESULT)" PROFILING="y" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ CREATE_LIB=yes \
+ make_deps=yes
+pncl: profiling-native-code-library
+
+# packs byte-code objects
+pack-byte-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) $(BCRESULT).cmo \
+ REAL_RESULT="$(BCRESULT)" \
+ PACK_LIB=yes make_deps=yes
+pabc: pack-byte-code
+
+# packs native-code objects
+pack-native-code: $(PRE_TARGETS)
+ $(QUIET)$(MAKE) -r -f $(OCAMLMAKEFILE) \
+ $(NCRESULT).cmx $(NCRESULT).o \
+ REAL_RESULT="$(NCRESULT)" \
+ REAL_OCAMLC="$(OCAMLOPT)" \
+ PACK_LIB=yes make_deps=yes
+panc: pack-native-code
+
+# generates HTML-documentation
+htdoc: doc/$(RESULT)/html
+
+# generates Latex-documentation
+ladoc: doc/$(RESULT)/latex
+
+# generates PostScript-documentation
+psdoc: doc/$(RESULT)/latex/doc.ps
+
+# generates PDF-documentation
+pdfdoc: doc/$(RESULT)/latex/doc.pdf
+
+# generates all supported forms of documentation
+doc: htdoc ladoc psdoc pdfdoc
+
+###########################################################################
+# LOW LEVEL RULES
+
+$(REAL_RESULT): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS) $(RESULTDEPS)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) \
+ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \
+ $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \
+ $(REAL_IMPL)
+
+nolink: $(REAL_IMPL_INTF) $(OBJ_LINK)
+
+ifdef WIN32
+$(REAL_RESULT).dll: $(REAL_IMPL_INTF) $(OBJ_LINK)
+ $(CAMLIDLDLL) $(CAMLIDLDLLFLAGS) $(OBJ_LINK) $(CLIBS) \
+ -o $@ $(REAL_IMPL)
+endif
+
+%$(TOPSUFFIX): $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS)
+ $(REAL_OCAMLFIND) $(OCAMLMKTOP) \
+ $(OCAML_FIND_PACKAGES) $(OCAML_FIND_LINKPKG) \
+ $(ALL_LDFLAGS) $(OBJS_LIBS) -o $@$(EXE) \
+ $(REAL_IMPL)
+
+.SUFFIXES: .mli .ml .cmi .cmo .cmx .cma .cmxa .$(EXT_OBJ) \
+ .mly .di .d .$(EXT_LIB) .idl %.oxridl .c .$(EXT_CXX) .h .so \
+ .rep .zog .glade
+
+ifndef STATIC
+ifdef MINGW
+$(DLLSONAME): $(OBJ_LINK)
+ $(CC) $(CFLAGS) $(CFLAGS_WIN32) $(OBJ_LINK) -shared -o $@ \
+ -Wl,--whole-archive $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/lib%.a))) \
+ $(OCAMLLIBPATH)/ocamlrun.a \
+ -Wl,--export-all-symbols \
+ -Wl,--no-whole-archive
+else
+ifdef MSVC
+$(DLLSONAME): $(OBJ_LINK)
+ link /NOLOGO /DLL /OUT:$@ $(OBJ_LINK) \
+ $(wildcard $(foreach dir,$(LIBDIRS),$(CLIBS:%=$(dir)/%.lib))) \
+ $(OCAMLLIBPATH)/ocamlrun.lib
+
+else
+$(DLLSONAME): $(OBJ_LINK)
+ $(OCAMLMKLIB) $(INCFLAGS) $(CLIBFLAGS) \
+ -o $(CLIB_BASE) $(OBJ_LINK) $(CLIBS:%=-l%) \
+ $(OCAMLMKLIB_FLAGS)
+endif
+endif
+endif
+
+ifndef LIB_PACK_NAME
+$(RESULT).cma: $(REAL_IMPL_INTF) $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) \
+ $(OBJS_LIBS) -o $@ $(OCAMLBLDFLAGS) $(REAL_IMPL)
+
+$(RESULT).cmxa $(RESULT).$(EXT_LIB): $(REAL_IMPL_INTF) $(EXTRADEPS) $(RESULTDEPS)
+ $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(ALL_LDFLAGS) $(OBJS_LIBS) \
+ $(OCAMLNLDFLAGS) -o $@ $(REAL_IMPL)
+else
+ifdef BYTE_OCAML
+$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo: $(REAL_IMPL_INTF)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmo $(REAL_IMPL)
+else
+$(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx: $(REAL_IMPL_INTF)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack -o $(LIB_PACK_NAME).cmx $(REAL_IMPL)
+endif
+
+$(RESULT).cma: $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmo $(MAKEDLL) $(EXTRADEPS) $(RESULTDEPS)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) -a $(ALL_LDFLAGS) \
+ $(OBJS_LIBS) -o $@ $(OCAMLBLDFLAGS) $(LIB_PACK_NAME).cmo
+
+$(RESULT).cmxa $(RESULT).$(EXT_LIB): $(LIB_PACK_NAME).cmi $(LIB_PACK_NAME).cmx $(EXTRADEPS) $(RESULTDEPS)
+ $(REAL_OCAMLFIND) $(OCAMLOPT) -a $(ALL_LDFLAGS) $(OBJS_LIBS) \
+ $(OCAMLNLDFLAGS) -o $@ $(LIB_PACK_NAME).cmx
+endif
+
+$(RES_CLIB): $(OBJ_LINK)
+ifndef MSVC
+ ifneq ($(strip $(OBJ_LINK)),)
+ $(AR) rcs $@ $(OBJ_LINK)
+ endif
+else
+ ifneq ($(strip $(OBJ_LINK)),)
+ lib -nologo -debugtype:cv -out:$(RES_CLIB) $(OBJ_LINK)
+ endif
+endif
+
+.mli.cmi: $(EXTRADEPS)
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ echo $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c $(THREAD_FLAG) $(ANNOT_FLAG) \
+ $(OCAMLFLAGS) $(INCFLAGS) $<; \
+ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c $(THREAD_FLAG) $(ANNOT_FLAG) \
+ $(OCAMLFLAGS) $(INCFLAGS) $<; \
+ else \
+ echo $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c -pp \"$$pp $(PPFLAGS)\" $(THREAD_FLAG) $(ANNOT_FLAG) \
+ $(OCAMLFLAGS) $(INCFLAGS) $<; \
+ $(REAL_OCAMLFIND) $(INTF_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c -pp "$$pp $(PPFLAGS)" $(THREAD_FLAG) $(ANNOT_FLAG) \
+ $(OCAMLFLAGS) $(INCFLAGS) $<; \
+ fi
+
+.ml.cmi .ml.$(EXT_OBJ) .ml.cmx .ml.cmo: $(EXTRADEPS)
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ echo $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c $(ALL_OCAMLCFLAGS) $<; \
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c $(ALL_OCAMLCFLAGS) $<; \
+ else \
+ echo $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c -pp \"$$pp $(PPFLAGS)\" $(ALL_OCAMLCFLAGS) $<; \
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) $(OCAML_FIND_PACKAGES) \
+ -c -pp "$$pp $(PPFLAGS)" $(ALL_OCAMLCFLAGS) $<; \
+ fi
+
+ifdef PACK_LIB
+$(REAL_RESULT).cmo $(REAL_RESULT).cmx $(REAL_RESULT).o: $(REAL_IMPL_INTF) $(OBJ_LINK) $(EXTRADEPS)
+ $(REAL_OCAMLFIND) $(REAL_OCAMLC) -pack $(ALL_LDFLAGS) \
+ $(OBJS_LIBS) -o $@ $(REAL_IMPL)
+endif
+
+.PRECIOUS: %.ml
+%.ml: %.mll
+ $(OCAMLLEX) $<
+
+.PRECIOUS: %.ml %.mli
+%.ml %.mli: %.mly
+ $(OCAMLYACC) $(YFLAGS) $<
+ $(QUIET)pp=`sed -n -e 's/.*(\*pp \([^*]*\) \*).*/\1/p;q' $<`; \
+ if [ ! -z "$$pp" ]; then \
+ mv $*.ml $*.ml.temporary; \
+ echo "(*pp $$pp $(PPFLAGS)*)" > $*.ml; \
+ cat $*.ml.temporary >> $*.ml; \
+ rm $*.ml.temporary; \
+ mv $*.mli $*.mli.temporary; \
+ echo "(*pp $$pp $(PPFLAGS)*)" > $*.mli; \
+ cat $*.mli.temporary >> $*.mli; \
+ rm $*.mli.temporary; \
+ fi
+
+
+.PRECIOUS: %.ml
+%.ml: %.rep
+ $(CAMELEON_REPORT) $(CAMELEON_REPORT_FLAGS) -gen $<
+
+.PRECIOUS: %.ml
+%.ml: %.zog
+ $(CAMELEON_ZOGGY) $(CAMELEON_ZOGGY_FLAGS) -impl $< > $@
+
+.PRECIOUS: %.ml
+%.ml: %.glade
+ $(OCAML_GLADECC) $(OCAML_GLADECC_FLAGS) $< > $@
+
+.PRECIOUS: %.ml %.mli
+%.ml %.mli: %.oxridl
+ $(OXRIDL) $<
+
+.PRECIOUS: %.ml %.mli %_stubs.c %.h
+%.ml %.mli %_stubs.c %.h: %.idl
+ $(CAMLIDL) $(MAYBE_IDL_HEADER) $(IDLFLAGS) \
+ $(CAMLIDLFLAGS) $<
+ $(QUIET)if [ $(NOIDLHEADER) ]; then touch $*.h; fi
+
+.c.$(EXT_OBJ):
+ $(OCAMLC) -c -cc "$(CC)" -ccopt "$(CFLAGS) \
+ $(CPPFLAGS) $(CPPFLAGS_WIN32) \
+ $(CFLAGS_WIN32) $(CINCFLAGS) $(CFLAG_O)$@ " $<
+
+.$(EXT_CXX).$(EXT_OBJ):
+ $(CXX) -c $(CXXFLAGS) $(CINCFLAGS) $(CPPFLAGS) \
+ -I'$(OCAMLLIBPATH)' \
+ $< $(CFLAG_O)$@
+
+$(MLDEPDIR)/%.d: %.ml
+ $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ echo $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
+ $(DINCFLAGS) $< \> $@; \
+ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
+ $(DINCFLAGS) $< > $@; \
+ else \
+ echo $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
+ -pp \"$$pp $(PPFLAGS)\" $(DINCFLAGS) $< \> $@; \
+ $(REAL_OCAMLFIND) $(OCAMLDEP) $(OCAML_DEP_PACKAGES) \
+ -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \
+ fi
+
+$(BCDIDIR)/%.di $(NCDIDIR)/%.di: %.mli
+ $(QUIET)if [ ! -d $(@D) ]; then mkdir -p $(@D); fi
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ echo $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(DINCFLAGS) $< \> $@; \
+ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) $(DINCFLAGS) $< > $@; \
+ else \
+ echo $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \
+ -pp \"$$pp $(PPFLAGS)\" $(DINCFLAGS) $< \> $@; \
+ $(REAL_OCAMLFIND) $(OCAMLDEP) $(DEPFLAGS) \
+ -pp "$$pp $(PPFLAGS)" $(DINCFLAGS) $< > $@; \
+ fi
+
+doc/$(RESULT)/html: $(DOC_FILES)
+ rm -rf $@
+ mkdir -p $@
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ echo $(OCAMLDOC) -html -d $@ $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \
+ $(OCAMLDOC) -html -d $@ $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES); \
+ else \
+ echo $(OCAMLDOC) -pp \"$$pp $(PPFLAGS)\" -html -d $@ $(OCAMLDOCFLAGS) \
+ $(INCFLAGS) $(DOC_FILES); \
+ $(OCAMLDOC) -pp "$$pp $(PPFLAGS)" -html -d $@ $(OCAMLDOCFLAGS) \
+ $(INCFLAGS) $(DOC_FILES); \
+ fi
+
+doc/$(RESULT)/latex: $(DOC_FILES)
+ rm -rf $@
+ mkdir -p $@
+ $(QUIET)pp=`sed -n -e '/^#/d' -e 's/(\*pp \([^*]*\) \*)/\1/p;q' $<`; \
+ if [ -z "$$pp" ]; then \
+ echo $(OCAMLDOC) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) \
+ $(DOC_FILES) -o $@/doc.tex; \
+ $(OCAMLDOC) -latex $(OCAMLDOCFLAGS) $(INCFLAGS) $(DOC_FILES) \
+ -o $@/doc.tex; \
+ else \
+ echo $(OCAMLDOC) -pp \"$$pp $(PPFLAGS)\" -latex $(OCAMLDOCFLAGS) \
+ $(INCFLAGS) $(DOC_FILES) -o $@/doc.tex; \
+ $(OCAMLDOC) -pp "$$pp $(PPFLAGS)" -latex $(OCAMLDOCFLAGS) \
+ $(INCFLAGS) $(DOC_FILES) -o $@/doc.tex; \
+ fi
+
+doc/$(RESULT)/latex/doc.ps: doc/$(RESULT)/latex
+ cd doc/$(RESULT)/latex && \
+ $(LATEX) doc.tex && \
+ $(LATEX) doc.tex && \
+ $(DVIPS) $(DVIPSFLAGS) doc.dvi -o $(@F)
+
+doc/$(RESULT)/latex/doc.pdf: doc/$(RESULT)/latex/doc.ps
+ cd doc/$(RESULT)/latex && $(PS2PDF) $(<F)
+
+define make_subproj
+.PHONY:
+subproj_$(1):
+ $$(eval $$(call PROJ_$(1)))
+ $(QUIET)if [ "$(SUBTARGET)" != "all" ]; then \
+ $(MAKE) -f $(OCAMLMAKEFILE) $(SUBTARGET); \
+ fi
+endef
+
+$(foreach subproj,$(SUBPROJS),$(eval $(call make_subproj,$(subproj))))
+
+.PHONY:
+subprojs: $(SUBPROJS:%=subproj_%)
+
+###########################################################################
+# (UN)INSTALL RULES FOR LIBRARIES
+
+.PHONY: libinstall
+libinstall: all
+ $(QUIET)printf "\nInstalling library with ocamlfind\n"
+ $(OCAMLFIND) install $(OCAMLFIND_INSTFLAGS) $(RESULT) META $(LIBINSTALL_FILES)
+ $(QUIET)printf "\nInstallation successful.\n"
+
+.PHONY: libuninstall
+libuninstall:
+ $(QUIET)printf "\nUninstalling library with ocamlfind\n"
+ $(OCAMLFIND) remove $(OCAMLFIND_INSTFLAGS) $(RESULT)
+ $(QUIET)printf "\nUninstallation successful.\n"
+
+.PHONY: rawinstall
+rawinstall: all
+ $(QUIET)printf "\nInstalling library to: $(OCAML_LIB_INSTALL)\n"
+ -install -d $(OCAML_LIB_INSTALL)
+ for i in $(LIBINSTALL_FILES); do \
+ if [ -f $$i ]; then \
+ install -c -m 0644 $$i $(OCAML_LIB_INSTALL); \
+ fi; \
+ done
+ $(QUIET)printf "\nInstallation successful.\n"
+
+.PHONY: rawuninstall
+rawuninstall:
+ $(QUIET)printf "\nUninstalling library from: $(OCAML_LIB_INSTALL)\n"
+ cd $(OCAML_LIB_INSTALL) && rm $(notdir $(LIBINSTALL_FILES))
+ $(QUIET)printf "\nUninstallation successful.\n"
+
+###########################################################################
+# MAINTAINANCE RULES
+
+.PHONY: clean
+clean::
+ rm -f $(TARGETS) $(TRASH)
+ rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR)
+
+.PHONY: cleanup
+cleanup::
+ rm -f $(NONEXECS) $(TRASH)
+ rm -rf $(BCDIDIR) $(NCDIDIR) $(MLDEPDIR)
+
+.PHONY: clean-doc
+clean-doc::
+ rm -rf doc
+
+.PHONY: nobackup
+nobackup:
+ rm -f *.bak *~ *.dup
diff --git a/examples/http.ml b/examples/http.ml
new file mode 100644
index 0000000..85964a9
--- /dev/null
+++ b/examples/http.ml
@@ -0,0 +1,688 @@
+(*pp $PP *)
+
+let non_blocking_queues = ref 3
+let maybe_blocking_queues = ref 1
+let files_path = ref ""
+let port = ref 8080
+
+let usage = "usage: http [options] /path/to/files"
+
+let () =
+ let pnum = ref 0 in
+ let arg s =
+ incr pnum;
+ if !pnum > 1 then
+ (Printf.eprintf "Error: too many arguments\n"; exit 1)
+ else
+ files_path := s
+ in
+ Arg.parse
+ [
+ "--non_blocking_queues", Arg.Int (fun i -> non_blocking_queues := i),
+ (Printf.sprintf
+ "Number of non-blocking queues. (default: %d)" !non_blocking_queues);
+ "--maybe_blocking_queues", Arg.Int (fun i -> maybe_blocking_queues := i),
+ (Printf.sprintf
+ "Number of maybe-blocking queues. (default: %d)" !maybe_blocking_queues) ;
+ "--port", Arg.Int (fun i -> port := i),
+ (Printf.sprintf
+ "Port used to bind the server. (default: %d)" !port) ;
+ ] arg usage ;
+ if !files_path = "" then
+ (
+ Printf.printf "%s\n" usage;
+ exit 1
+ )
+
+
+type priority =
+ Maybe_blocking
+ | Non_blocking
+
+let scheduler = Duppy.create ()
+
+type http_method = Post | Get
+
+type http_protocol = Http_11 | Http_10
+
+let string_of_protocol =
+ function
+ | Http_11 -> "HTTP/1.1"
+ | Http_10 -> "HTTP/1.0"
+
+let protocol_of_string =
+ function
+ | "HTTP/1.1" -> Http_11
+ | "HTTP/1.0" -> Http_10
+ | _ -> assert false
+
+let string_of_method =
+ function
+ | Post -> "POST"
+ | Get -> "GET"
+
+let method_of_string =
+ function
+ | "POST" -> Post
+ | "GET" -> Get
+ | _ -> assert false
+
+type data = None | String of string | File of Unix.file_descr
+
+type request =
+ { request_protocol : http_protocol ;
+ request_method : http_method ;
+ request_uri : string ;
+ request_headers : (string*string) list ;
+ request_data : data }
+
+type reply =
+ { reply_protocol : http_protocol ;
+ reply_status : int*string ;
+ reply_headers : (string*string) list ;
+ reply_data : data }
+
+exception Assoc of string
+
+let assoc_uppercase x y =
+ try
+ List.iter
+ (fun (l,v) -> if String.uppercase l = x then
+ raise (Assoc v)) y ;
+ raise Not_found
+ with
+ | Assoc s -> s
+
+let server = "dhttpd"
+
+let html_template =
+ Printf.sprintf
+ "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" \
+ \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\r\n\
+ <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\">\r\n\
+ %s</html>"
+
+let server_error status protocol =
+ let (code,explanation) = status in
+ let data =
+ String
+ (html_template
+ (Printf.sprintf
+ "<head><title>%s</title></head>\r\n\
+ <body>%s !</body>" explanation explanation))
+ in
+ { reply_protocol = protocol ;
+ reply_status = status ;
+ reply_headers = [ "Content-Type","text/html; charset=UTF-8";
+ "Server", server ] ;
+ reply_data = data }
+
+let error_404 =
+ server_error (404,"File Not Found")
+
+let error_500 =
+ server_error (500,"Bad Request") Http_10
+
+let error_403 =
+ server_error (403,"Forbidden")
+
+let http_302 protocol uri =
+ { reply_protocol = protocol ;
+ reply_status = (302,"Found") ;
+ reply_headers = ["Location",uri];
+ reply_data = String "" }
+
+type socket_status = Keep | Close
+
+let send_reply h reply =
+ let write s =
+ duppy_write
+ s
+ with
+ { priority = Non_blocking ;
+ handler = h }
+ in
+ let (code,status) = reply.reply_status in
+ let http_header =
+ Printf.sprintf
+ "%s %d %s\r\n\
+ %s\r\n\
+ \r\n"
+ (string_of_protocol reply.reply_protocol) code status
+ (String.concat "\r\n"
+ (List.map
+ (fun (x,y) ->
+ Printf.sprintf "%s: %s" x y) reply.reply_headers))
+ in
+ duppy_do
+ write http_header ;
+ begin
+ match reply.reply_data with
+ | String s ->
+ write s
+ | File fd ->
+ let stats = Unix.fstat fd in
+ let ba =
+ Bigarray.Array1.map_file
+ fd Bigarray.char Bigarray.c_layout false
+ (stats.Unix.st_size)
+ in
+ let close () =
+ try
+ Unix.close fd
+ with
+ | _ -> ()
+ in
+ let on_error e =
+ close () ;
+ h.Duppy.Monad.Io.on_error e
+ in
+ let h =
+ { h with
+ Duppy.Monad.Io.
+ on_error = on_error }
+ in
+ duppy_do
+ duppy_write_bigarray
+ ba
+ with
+ { priority = Non_blocking ;
+ handler = h } ;
+ duppy_return (close ())
+ done
+ | None -> duppy_return ()
+ end
+ done
+
+let parse_headers headers =
+ let split_header l h =
+ try
+ let rex = Pcre.regexp "([^:\\r\\n]+):\\s*([^\\r\\n]+)" in
+ let sub = Pcre.exec ~rex h in
+ duppy_return
+ ((Pcre.get_substring sub 1,
+ Pcre.get_substring sub 2) :: l)
+ with
+ | Not_found -> duppy_raise error_500
+ in
+ duppy_fold_left split_header [] headers
+
+let index_uri path index protocol uri =
+ let uri =
+ try
+ let ret =
+ Pcre.extract ~rex:(Pcre.regexp "([^\\?]*)\\?")
+ uri
+ in
+ ret.(1)
+ with
+ | Not_found -> uri
+ in
+ try
+ if Sys.is_directory
+ (Printf.sprintf "%s%s" path uri)
+ then
+ if uri.[String.length uri - 1] <> '/' then
+ duppy_raise (http_302 protocol (Printf.sprintf "%s/" uri))
+ else
+ begin
+ let index = Printf.sprintf "%s/%s" uri index in
+ if Sys.file_exists
+ (Printf.sprintf "%s/%s" path index) then
+ duppy_return index
+ else
+ duppy_return uri
+ end
+ else
+ duppy_return uri
+ with
+ | _ -> duppy_return uri
+
+let file_request path _ request =
+ let uri =
+ try
+ let ret =
+ Pcre.extract ~rex:(Pcre.regexp "([^\\?]*)\\?.*")
+ request.request_uri
+ in
+ ret.(1)
+ with
+ | Not_found -> request.request_uri
+ in
+ duppy uri =
+ index_uri path "index.html"
+ request.request_protocol uri
+ in
+ let fname =
+ Printf.sprintf "%s%s" path uri
+ in
+ if Sys.file_exists fname then
+ try
+ let fd = Unix.openfile fname [Unix.O_RDONLY] 0o640 in
+ let stats = Unix.fstat fd in
+ let headers =
+ [ "Server", server;
+ "Content-Length", string_of_int (stats.Unix.st_size) ]
+ in
+ let headers =
+ if Pcre.pmatch ~rex:(Pcre.regexp "\\.html$") fname then
+ ("Content-Type","text/html") :: headers
+ else if Pcre.pmatch ~rex:(Pcre.regexp "\\.css$") fname then
+ ("Content-Type","text/css") :: headers
+ else
+ headers
+ in
+ duppy_raise
+ { reply_protocol = request.request_protocol ;
+ reply_status = (200,"OK") ;
+ reply_headers = headers ;
+ reply_data = File fd }
+ with
+ | _ -> duppy_raise (error_403 request.request_protocol)
+ else
+ duppy_raise (error_404 request.request_protocol)
+
+let file_handler =
+ (fun _ -> duppy_return true),file_request !files_path
+
+let cgi_handler process path h request =
+ let uri,args,suffix =
+ try
+ let ret =
+ Pcre.extract ~rex:(Pcre.regexp "([^\\?]*)\\?(.*)")
+ request.request_uri
+ in
+ begin
+ try
+ let ans =
+ Pcre.extract ~rex:(Pcre.regexp "^([^/]*)/([^&=]*)$")
+ ret.(2)
+ in
+ ret.(1),ans.(1),ans.(2)
+ with
+ | Not_found -> ret.(1),ret.(2),""
+ end
+ with
+ | Not_found -> request.request_uri,"",""
+ in
+ duppy script =
+ index_uri path "index.php"
+ request.request_protocol
+ uri
+ in
+ let script =
+ Printf.sprintf "%s%s" path script
+ in
+ let env =
+ Printf.sprintf
+ "export SERVER_SOFTWARE=Duppy-httpd/1.0; \
+ export SERVER_NAME=localhost; \
+ export GATEWAY_INTERFACE=CGI/1.1; \
+ export SERVER_PROTOCOL=%s; \
+ export SERVER_PORT=%d; \
+ export REQUEST_METHOD=%s; \
+ export REQUEST_URI=%s; \
+ export REDIRECT_STATUS=200; \
+ export SCRIPT_FILENAME=%s"
+ (string_of_protocol (request.request_protocol))
+ !port
+ (string_of_method (request.request_method))
+ (Filename.quote uri)
+ (Filename.quote script)
+ in
+ let env =
+ Printf.sprintf "%s; export QUERY_STRING=%s"
+ env
+ (Filename.quote args)
+ in
+ let env =
+ let tr_suffix =
+ Printf.sprintf "%s%s" path suffix
+ in
+ (* Trick ! *)
+ let tr_suffix =
+ Printf.sprintf "%s/%s" (Filename.dirname tr_suffix)
+ (Filename.basename tr_suffix)
+ in
+ Printf.sprintf "%s; export PATH_TRANSLATED=%s; \
+ export PATH_INFO=%s"
+ env
+ (Filename.quote tr_suffix)
+ (Filename.quote suffix)
+ in
+ let sanitize s =
+ Pcre.replace ~pat:"-" ~templ:"_" (String.uppercase s)
+ in
+ let headers =
+ List.map (fun (x,y) -> (sanitize x,y)) request.request_headers
+ in
+ let append env key =
+ if List.mem_assoc key headers then
+ Printf.sprintf "%s; export %s=%s"
+ env key (Filename.quote (List.assoc key headers))
+ else
+ env
+ in
+ let env = append env "CONTENT_TYPE" in
+ let env = append env "CONTENT_LENGTH" in
+ duppy env =
+ if List.mem_assoc "AUTHORIZATION" headers then
+ begin
+ let ret =
+ Pcre.extract ~rex:(Pcre.regexp "(^[^\\s]*\\s.*)$")
+ (List.assoc "AUTHORIZATION" headers)
+ in
+ if Array.length ret > 0 then
+ duppy_return (Printf.sprintf "%s; extract AUTH_TYPE=%s" env (ret.(1)))
+ else
+ duppy_raise error_500
+ end
+ else
+ duppy_return env
+ in
+ let f env (x,y) =
+ Printf.sprintf "%s; export HTTP_%s=%s"
+ env x (Filename.quote y)
+ in
+ let env = List.fold_left f env headers in
+ let data =
+ match request.request_data with
+ | None -> ""
+ | String s -> s
+ | _ -> assert false (* not implemented *)
+ in
+ let process =
+ Printf.sprintf "%s; %s 2>/dev/null"
+ env process
+ in
+ let in_c,out_c =
+ Unix.open_process process
+ in
+ let out_s =
+ Unix.descr_of_out_channel out_c
+ in
+ let h =
+ { h with
+ Duppy.Monad.Io.
+ socket = out_s ;
+ data = ""
+ }
+ in
+ duppy () =
+ duppy_write
+ data
+ with
+ { priority = Non_blocking ;
+ handler = h }
+ in
+ let in_s =
+ Unix.descr_of_in_channel in_c
+ in
+ let h =
+ { h with
+ Duppy.Monad.Io.
+ socket = in_s ;
+ data = ""
+ }
+ in
+ duppy headers =
+ duppy_read
+ Duppy.Io.Split "[\r]?\n[\r]?\n"
+ with
+ { priority = Non_blocking ;
+ handler = h }
+ in
+ duppy data =
+ duppy_try
+ duppy_read_all
+ in_s
+ with
+ { priority = Non_blocking ;
+ scheduler = h.Duppy.Monad.Io.scheduler }
+ with
+ | (s,_) -> duppy_return s
+ in
+ let data =
+ Printf.sprintf "%s%s" h.Duppy.Monad.Io.data data
+ in
+ ignore(Unix.close_process (in_c,out_c)) ;
+ duppy headers =
+ let headers = Pcre.split ~pat:"\r\n" headers in
+ parse_headers headers
+ in
+ duppy status,headers =
+ if List.mem_assoc "Status" headers then
+ try
+ let ans = Pcre.extract ~rex:(Pcre.regexp "([\\d]+)\\s(.*)")
+ (List.assoc "Status" headers)
+ in
+ duppy_return
+ ((int_of_string ans.(1),
+ ans.(2)),
+ List.filter (fun (x,y) -> x <> "Status") headers)
+ with _ -> duppy_raise error_500
+ else duppy_return ((200,"OK"),headers)
+ in
+ let headers =
+ ("Content-length",string_of_int (String.length data))::
+ headers
+ in
+ duppy_raise
+ { reply_protocol = request.request_protocol ;
+ reply_status = status ;
+ reply_headers = headers ;
+ reply_data = String data }
+
+let php_handler =
+ (fun request ->
+ duppy uri =
+ index_uri !files_path "index.php"
+ request.request_protocol
+ request.request_uri
+ in
+ duppy_return (Pcre.pmatch ~rex:(Pcre.regexp "\\.php$") uri)),
+ cgi_handler "php-cgi" !files_path
+
+let handlers = [php_handler;file_handler]
+
+let handle_request h request =
+ let f (check,handler) =
+ duppy check = check request in
+ if check then
+ handler h request
+ else
+ duppy_return ()
+ in
+ duppy_try
+ duppy_do
+ duppy_iter f handlers ;
+ duppy_return (error_404 request.request_protocol)
+ done
+ with
+ | reply -> duppy_return reply
+
+let parse_request h r =
+ try
+ let headers = Pcre.split ~pat:"\r\n" r in
+ duppy request,headers =
+ match headers with
+ | e :: l ->
+ duppy headers =
+ parse_headers l
+ in
+ duppy_return (e,headers)
+ | _ -> duppy_raise error_500
+ in
+ let rex = Pcre.regexp "([\\w]+)\\s([^\\s]+)\\s(HTTP/1.[01])" in
+ duppy http_method,uri,protocol =
+ try
+ let sub = Pcre.exec ~rex request in
+ let http_method,uri,protocol =
+ Pcre.get_substring sub 1,
+ Pcre.get_substring sub 2,
+ Pcre.get_substring sub 3
+ in
+ duppy_return
+ (method_of_string http_method,
+ uri,
+ protocol_of_string protocol)
+ with
+ | _ -> duppy_raise error_500
+ in
+ duppy data =
+ match http_method with
+ | Get -> duppy_return None
+ | Post ->
+ duppy len =
+ try
+ let length = assoc_uppercase "CONTENT-LENGTH" headers in
+ duppy_return (int_of_string length)
+ with
+ | Not_found -> duppy_return 0
+ | _ -> duppy_raise error_500
+ in
+ match len with
+ | 0 -> duppy_return None
+ | d ->
+ duppy data =
+ duppy_read
+ Duppy.Io.Length d
+ with
+ { priority = Non_blocking ;
+ handler = h }
+ in
+ duppy_return (String data)
+ in
+ duppy_return
+ { request_method = http_method ;
+ request_protocol = protocol ;
+ request_uri = uri ;
+ request_headers = headers ;
+ request_data = data }
+ with
+ | _ -> duppy_raise error_500
+
+let handle_client socket =
+ (* Read and process lines *)
+ let on_error e =
+ error_500
+ in
+ let h =
+ { Duppy.Monad.Io.
+ scheduler = scheduler ;
+ socket = socket ;
+ data = "";
+ on_error = on_error }
+ in
+ let rec exec () =
+ duppy (keep,reply) =
+ duppy_try
+ duppy data =
+ duppy_read
+ Duppy.Io.Split "\r\n\r\n"
+ with
+ { priority = Non_blocking ;
+ handler = h }
+ in
+ duppy request =
+ parse_request h data
+ in
+ duppy reply =
+ handle_request h request
+ in
+ let close_header headers =
+ try
+ (assoc_uppercase "CONNECTION" headers) = "close"
+ with
+ | Not_found -> false
+ in
+ let keep =
+ if
+ request.request_protocol = Http_10 ||
+ close_header request.request_headers ||
+ close_header reply.reply_headers
+ then
+ Close
+ else
+ Keep
+ in
+ duppy_return (keep,reply)
+ with
+ | reply -> duppy_return (Close,reply)
+ in
+ duppy_do
+ send_reply h reply ;
+ if keep = Keep then
+ exec ()
+ else
+ duppy_return ()
+ done
+ in
+ let finish _ =
+ try
+ Unix.close socket
+ with
+ | _ -> ()
+ in
+ duppy_run
+ exec ()
+ with
+ { return = finish ;
+ raise = finish }
+
+let new_queue ~priority ~name () =
+ let priorities p = p = priority in
+ let queue () =
+ Duppy.queue scheduler ~log:(fun _ -> ()) ~priorities name
+ in
+ Thread.create queue ()
+
+let bind_addr_inet = Unix.inet_addr_of_string "0.0.0.0"
+let bind_addr = Unix.ADDR_INET(bind_addr_inet, !port)
+let max_conn = 100
+let sock = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0
+let () =
+ (* See http://caml.inria.fr/mantis/print_bug_page.php?bug_id=4640
+ * for this: we want Unix EPIPE error and not SIGPIPE, which
+ * crashes the program.. *)
+ Sys.set_signal Sys.sigpipe Sys.Signal_ignore;
+ ignore (Unix.sigprocmask Unix.SIG_BLOCK [Sys.sigpipe]);
+ Unix.setsockopt sock Unix.SO_REUSEADDR true ;
+ let rec incoming _ =
+ begin
+ try
+ let (s,caller) = Unix.accept sock in
+ handle_client s
+ with e ->
+ Printf.printf "Failed to accept new client: %S\n"
+ (Printexc.to_string e)
+ end ;
+ [{ Duppy.Task.
+ priority = Non_blocking ;
+ events = [`Read sock] ;
+ handler = incoming }]
+ in
+ begin
+ try
+ Unix.bind sock bind_addr
+ with
+ | Unix.Unix_error(Unix.EADDRINUSE, "bind", "") ->
+ failwith (Printf.sprintf "port %d already taken" !port)
+ end ;
+ Unix.listen sock max_conn ;
+ Duppy.Task.add scheduler
+ { Duppy.Task.
+ priority = Non_blocking ;
+ events = [`Read sock] ;
+ handler = incoming } ;
+ for i = 1 to !non_blocking_queues do
+ ignore(new_queue ~priority:Non_blocking
+ ~name:(Printf.sprintf "Non blocking queue #%d" i)
+ ())
+ done ;
+ for i = 1 to !maybe_blocking_queues do
+ ignore(new_queue ~priority:Maybe_blocking
+ ~name:(Printf.sprintf "Maybe blocking queue #%d" i)
+ ())
+ done ;
+ Duppy.queue scheduler ~log:(fun _ -> ()) "root"
diff --git a/examples/telnet.ml b/examples/telnet.ml
new file mode 100644
index 0000000..f1e60a2
--- /dev/null
+++ b/examples/telnet.ml
@@ -0,0 +1,181 @@
+(*pp $PP *)
+
+type priority = Non_blocking | Maybe_blocking
+let io_priority = Non_blocking
+
+(* Create scheduler *)
+let scheduler = Duppy.create ()
+
+(* Create two queues,
+ * one for non blocking events
+ * and another for blocking
+ * events *)
+let new_queue ~priority ~name () =
+ let log =
+ Printf.printf "%s: %s\n%!" name
+ in
+ let priorities p = p = priority in
+ let queue () =
+ Duppy.queue scheduler ~log ~priorities name
+ in
+ Thread.create queue ()
+
+let th =
+ ignore(new_queue ~priority:Non_blocking
+ ~name:"Non blocking queue" ()) ;
+ ignore(new_queue ~priority:Maybe_blocking
+ ~name:"Maybe blocking queue #1" ()) ;
+ new_queue ~priority:Maybe_blocking
+ ~name:"Maybe blocking queue #2" ()
+
+let exec_command s () =
+ let chan = Unix.open_process_in s in
+ let rec aux () =
+ match
+ try Some (input_line chan) with End_of_file -> None
+ with
+ | None -> []
+ | Some s -> s::(aux ())
+ in
+ let l = aux () in
+ ignore (Unix.close_process_in chan) ;
+ duppy_return (String.concat "\r\n" l)
+
+
+let commands = Hashtbl.create 10
+let () = Hashtbl.add commands "hello" (false,fun () -> duppy_return "world") ;
+ Hashtbl.add commands "foo" (false,fun () -> duppy_return "bar") ;
+ Hashtbl.add commands "uptime" (true,exec_command "uptime") ;
+ Hashtbl.add commands "date" (true,exec_command "date") ;
+ Hashtbl.add commands "whoami" (true,exec_command "whoami") ;
+ Hashtbl.add commands "sleep" (true,exec_command "sleep 15") ;
+ Hashtbl.add commands "exit" (true,fun () -> duppy_raise ())
+(* Add commands here *)
+let help = Buffer.create 10
+let () = Buffer.add_string help "List of commands:" ;
+ Hashtbl.iter
+ (fun x _ -> Buffer.add_string help (Printf.sprintf "\r\n%s" x))
+ commands ;
+ Hashtbl.add commands "help" (false,fun () -> duppy_return (Buffer.contents help))
+
+let handle_client socket =
+ let on_error e =
+ match e with
+ | Duppy.Io.Io_error ->
+ Printf.printf "Client disconnected"
+ | Duppy.Io.Unix (c,p,m) ->
+ Printf.printf "%s" (Printexc.to_string
+ (Unix.Unix_error (c,p,m)))
+ | Duppy.Io.Unknown e ->
+ Printf.printf "%s" (Printexc.to_string e)
+ in
+ let h =
+ { Duppy.Monad.Io.
+ scheduler = scheduler ;
+ socket = socket ;
+ data = "";
+ on_error = on_error }
+ in
+ (* Read and process lines *)
+ let rec exec () =
+ duppy req =
+ duppy_read
+ Duppy.Io.Split "[\r\n]+"
+ with
+ { priority = io_priority ;
+ handler = h }
+ in
+ duppy ans =
+ try
+ let blocking,command = Hashtbl.find commands req in
+ if not blocking then
+ command ()
+ else
+ begin
+ duppy_exec
+ command ()
+ with
+ { priority = Maybe_blocking ;
+ handler = h }
+ end
+ with
+ | Not_found ->
+ duppy_return "ERROR: unknown command, type \"help\" to get a \
+ list of commands."
+ in
+ duppy_do
+ duppy_write
+ "BEGIN\r\n";
+ ans;
+ "\r\nEND\r\n"
+ with
+ { priority = io_priority ;
+ handler = h } ;
+ exec ()
+ done
+ in
+ let close () =
+ try
+ Unix.close socket
+ with
+ | _ -> ()
+ in
+ let return () =
+ let on_error e =
+ on_error e ;
+ close ()
+ in
+ Duppy.Io.write ~priority:io_priority
+ ~on_error
+ ~exec:close scheduler
+ ~string:"Bye!\r\n" socket
+ in
+ duppy_run
+ exec ()
+ with
+ { return = return ;
+ raise = close }
+
+open Unix
+
+let port = 4123
+let bind_addr_inet = inet_addr_of_string "0.0.0.0"
+let bind_addr = ADDR_INET(bind_addr_inet, port)
+let max_conn = 10
+let sock = socket PF_INET SOCK_STREAM 0
+
+let () =
+ setsockopt sock SO_REUSEADDR true ;
+ let rec incoming _ =
+ begin
+ try
+ let (s,caller) = accept sock in
+ let ip =
+ let a = match caller with
+ | ADDR_INET (a,_) -> a
+ | _ -> assert false
+ in
+ try
+ (gethostbyaddr a).h_name
+ with
+ | Not_found -> string_of_inet_addr a
+ in
+ Printf.printf "New client: %s\n" ip ;
+ handle_client s
+ with e ->
+ Printf.printf "Failed to accept new client: %S\n" (Printexc.to_string e)
+ end ;
+ [{ Duppy.Task.priority = io_priority ;
+ Duppy.Task.events = [`Read sock] ;
+ Duppy.Task.handler = incoming }]
+ in
+ begin try bind sock bind_addr with
+ | Unix.Unix_error(Unix.EADDRINUSE, "bind", "") ->
+ failwith (Printf.sprintf "port %d already taken" port)
+ end ;
+ listen sock max_conn ;
+ Duppy.Task.add scheduler
+ { Duppy.Task.priority = io_priority ;
+ Duppy.Task.events = [`Read sock] ;
+ Duppy.Task.handler = incoming } ;
+ Thread.join th