[thrift] highly concurrent Erlang goodness
Summary:
* shim to use object-oriented code as gen_servers
* high(er) performance Erlang-style server and transport
* sane packaging based on otp-base, i.e. Makefiles and real structure
Test Plan: tutorial server offers the same (subset of) functionality as previous version
Revert Plan: ok
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665164 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/erl/tools/.appgen/blank_app/Makefile b/lib/erl/tools/.appgen/blank_app/Makefile
new file mode 100755
index 0000000..0f2c8a8
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app/Makefile
@@ -0,0 +1,7 @@
+MODULES = \
+ src
+
+all clean docs:
+ for dir in $(MODULES); do \
+ (cd $$dir; ${MAKE} $@); \
+ done
diff --git a/lib/erl/tools/.appgen/blank_app/include/blank_app.hrl b/lib/erl/tools/.appgen/blank_app/include/blank_app.hrl
new file mode 100755
index 0000000..e69de29
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app/include/blank_app.hrl
diff --git a/lib/erl/tools/.appgen/blank_app/src/Makefile b/lib/erl/tools/.appgen/blank_app/src/Makefile
new file mode 100755
index 0000000..13b06f0
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app/src/Makefile
@@ -0,0 +1,112 @@
+# $Id: Makefile,v 1.3 2004/08/13 16:35:59 mlogan Exp $
+#
+include ../../../build/otp.mk
+include ../../../build/colors.mk
+include ../../../build/buildtargets.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+
+include ../vsn.mk
+APP_NAME=%%APP_NAME%%
+PFX=%%PFX%%
+VSN=$(%%APP_NAME_UPPER_CASE%%_VSN)
+
+# ----------------------------------------------------
+# Install directory specification
+# WARNING: INSTALL_DIR the command to install a directory.
+# INSTALL_DST is the target directory
+# ----------------------------------------------------
+INSTALL_DST = $(ERLANG_OTP)/lib/$(APP_NAME)-$(VSN)
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+
+MODULES = $(shell ls *.erl | sed s/.erl//)
+MODULES_COMMA = $(shell ls *.erl | sed s/\\.erl/,/)
+
+HRL_FILES=
+INTERNAL_HRL_FILES= $(APP_NAME).hrl
+ERL_FILES= $(MODULES:%=%.erl)
+DOC_FILES=$(ERL_FILES)
+
+APP_FILE= $(APP_NAME).app
+APPUP_FILE= $(APP_NAME).appup
+
+APP_SRC= $(APP_FILE).src
+APPUP_SRC= $(APPUP_FILE).src
+
+APP_TARGET= $(EBIN)/$(APP_FILE)
+APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
+
+BEAMS= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+TARGET_FILES= $(BEAMS) $(APP_TARGET) $(APPUP_TARGET)
+
+WEB_TARGET=/var/yaws/www/$(APP_NAME)
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+ERL_FLAGS +=
+ERL_COMPILE_FLAGS += -I../include -I../../fslib/include -I../../system_status/include
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+all debug opt: $(EBIN) $(TARGET_FILES)
+
+#$(EBIN)/rm_logger.beam: $(APP_NAME).hrl
+include ../../../build/docs.mk
+
+# Note: In the open-source build clean must not destroy the preloaded
+# beam files.
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f core
+ rm -rf $(EBIN)
+ rm -rf *html
+
+$(EBIN):
+ mkdir $(EBIN)
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+$(APP_TARGET): $(APP_SRC) ../vsn.mk $(BEAMS)
+ sed -e 's;%VSN%;$(VSN);' \
+ -e 's;%PFX%;$(PFX);' \
+ -e 's;%APP_NAME%;$(APP_NAME);' \
+ -e 's;%MODULES%;%MODULES%$(MODULES_COMMA);' \
+ $< > $<".tmp"
+ sed -e 's/%MODULES%\(.*\),/\1/' \
+ $<".tmp" > $@
+ rm $<".tmp"
+
+
+$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+$(WEB_TARGET): ../markup/*
+ rm -rf $(WEB_TARGET)
+ mkdir $(WEB_TARGET)
+ cp -r ../markup/ $(WEB_TARGET)
+ cp -r ../skins/ $(WEB_TARGET)
+
+# ----------------------------------------------------
+# Install Target
+# ----------------------------------------------------
+
+install: all $(WEB_TARGET)
+# $(INSTALL_DIR) $(INSTALL_DST)/src
+# $(INSTALL_DATA) $(ERL_FILES) $(INSTALL_DST)/src
+# $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(INSTALL_DST)/src
+# $(INSTALL_DIR) $(INSTALL_DST)/include
+# $(INSTALL_DATA) $(HRL_FILES) $(INSTALL_DST)/include
+# $(INSTALL_DIR) $(INSTALL_DST)/ebin
+# $(INSTALL_DATA) $(TARGET_FILES) $(INSTALL_DST)/ebin
diff --git a/lib/erl/tools/.appgen/blank_app/src/ba_server.erl b/lib/erl/tools/.appgen/blank_app/src/ba_server.erl
new file mode 100755
index 0000000..9a98f1c
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app/src/ba_server.erl
@@ -0,0 +1,124 @@
+%%%-------------------------------------------------------------------
+%%% @doc
+%%% @end
+%%%-------------------------------------------------------------------
+-module(%%PFX%%_server).
+
+-behaviour(gen_server).
+%%--------------------------------------------------------------------
+%% Include files
+%%--------------------------------------------------------------------
+-include("%%APP_NAME%%.hrl").
+
+%%--------------------------------------------------------------------
+%% External exports
+%%--------------------------------------------------------------------
+-export([
+ start_link/0,
+ stop/0
+ ]).
+
+%%--------------------------------------------------------------------
+%% gen_server callbacks
+%%--------------------------------------------------------------------
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
+
+%%--------------------------------------------------------------------
+%% record definitions
+%%--------------------------------------------------------------------
+-record(state, {}).
+
+%%--------------------------------------------------------------------
+%% macro definitions
+%%--------------------------------------------------------------------
+-define(SERVER, ?MODULE).
+
+%%====================================================================
+%% External functions
+%%====================================================================
+%%--------------------------------------------------------------------
+%% @doc Starts the server.
+%% @spec start_link() -> {ok, pid()} | {error, Reason}
+%% @end
+%%--------------------------------------------------------------------
+start_link() ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
+
+%%--------------------------------------------------------------------
+%% @doc Stops the server.
+%% @spec stop() -> ok
+%% @end
+%%--------------------------------------------------------------------
+stop() ->
+ gen_server:cast(?SERVER, stop).
+
+%%====================================================================
+%% Server functions
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% Function: init/1
+%% Description: Initiates the server
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%--------------------------------------------------------------------
+init([]) ->
+ {ok, #state{}}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_call/3
+%% Description: Handling call messages
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_call(Request, From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_cast/2
+%% Description: Handling cast messages
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_cast(stop, State) ->
+ {stop, normal, State};
+handle_cast(Msg, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: handle_info/2
+%% Description: Handling all non call/cast messages
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_info(Info, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% Function: terminate/2
+%% Description: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%--------------------------------------------------------------------
+terminate(Reason, State) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%% Returns: {ok, NewState}
+%%--------------------------------------------------------------------
+code_change(OldVsn, State, Extra) ->
+ {ok, State}.
+
+%%====================================================================
+%%% Internal functions
+%%====================================================================
diff --git a/lib/erl/tools/.appgen/blank_app/src/ba_sup.erl b/lib/erl/tools/.appgen/blank_app/src/ba_sup.erl
new file mode 100755
index 0000000..b5f48d1
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app/src/ba_sup.erl
@@ -0,0 +1,74 @@
+%%%-------------------------------------------------------------------
+%%% @doc
+%%% @end
+%%%-------------------------------------------------------------------
+-module(%%PFX%%_sup).
+
+-behaviour(supervisor).
+%%--------------------------------------------------------------------
+%% Include files
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% External exports
+%%--------------------------------------------------------------------
+-export([
+ start_link/1
+ ]).
+
+%%--------------------------------------------------------------------
+%% Internal exports
+%%--------------------------------------------------------------------
+-export([
+ init/1
+ ]).
+
+%%--------------------------------------------------------------------
+%% Macros
+%%--------------------------------------------------------------------
+-define(SERVER, ?MODULE).
+
+%%--------------------------------------------------------------------
+%% Records
+%%--------------------------------------------------------------------
+
+%%====================================================================
+%% External functions
+%%====================================================================
+%%--------------------------------------------------------------------
+%% @doc Starts the supervisor.
+%% @spec start_link(StartArgs) -> {ok, pid()} | Error
+%% @end
+%%--------------------------------------------------------------------
+start_link(StartArgs) ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+%%====================================================================
+%% Server functions
+%%====================================================================
+%%--------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, {SupFlags, [ChildSpec]}} |
+%% ignore |
+%% {error, Reason}
+%%--------------------------------------------------------------------
+init([]) ->
+ RestartStrategy = one_for_one,
+ MaxRestarts = 1000,
+ MaxTimeBetRestarts = 3600,
+
+ SupFlags = {RestartStrategy, MaxRestarts, MaxTimeBetRestarts},
+
+ ChildSpecs =
+ [
+ {%%PFX%%_server,
+ {%%PFX%%_server, start_link, []},
+ permanent,
+ 1000,
+ worker,
+ [%%PFX%%_server]}
+ ],
+ {ok,{SupFlags, ChildSpecs}}.
+%%====================================================================
+%% Internal functions
+%%====================================================================
diff --git a/lib/erl/tools/.appgen/blank_app/src/blank_app.app.src b/lib/erl/tools/.appgen/blank_app/src/blank_app.app.src
new file mode 100755
index 0000000..a1513fb
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app/src/blank_app.app.src
@@ -0,0 +1,41 @@
+%%% -*- mode:erlang -*-
+{application, %APP_NAME%,
+ [
+ % A quick description of the application.
+ {description, "An Erlang Application."},
+
+ % The version of the applicaton
+ {vsn, "%VSN%"},
+
+ % All modules used by the application.
+ {modules,
+ [
+ %MODULES%
+ ]},
+
+ % All of the registered names the application uses. This can be ignored.
+ {registered, []},
+
+ % Applications that are to be started prior to this one. This can be ignored
+ % leave it alone unless you understand it well and let the .rel files in
+ % your release handle this.
+ {applications,
+ [
+ kernel,
+ stdlib
+ ]},
+
+ % OTP application loader will load, but not start, included apps. Again
+ % this can be ignored as well. To load but not start an application it
+ % is easier to include it in the .rel file followed by the atom 'none'
+ {included_applications, []},
+
+ % configuration parameters similar to those in the config file specified
+ % on the command line. can be fetched with gas:get_env
+ {env, []},
+
+ % The Module and Args used to start this application.
+ {mod, {%APP_NAME%, []}}
+ ]
+}.
+
diff --git a/lib/erl/tools/.appgen/blank_app/src/blank_app.appup.src b/lib/erl/tools/.appgen/blank_app/src/blank_app.appup.src
new file mode 100755
index 0000000..54a6383
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app/src/blank_app.appup.src
@@ -0,0 +1 @@
+{"%VSN%",[],[]}.
diff --git a/lib/erl/tools/.appgen/blank_app/src/blank_app.erl b/lib/erl/tools/.appgen/blank_app/src/blank_app.erl
new file mode 100755
index 0000000..8db6fe0
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app/src/blank_app.erl
@@ -0,0 +1,63 @@
+%%%-------------------------------------------------------------------
+%%% @doc
+%%% @end
+%%%-------------------------------------------------------------------
+-module(%%APP_NAME%%).
+
+-behaviour(application).
+%%--------------------------------------------------------------------
+%% Include files
+%%--------------------------------------------------------------------
+-include("%%APP_NAME%%.hrl").
+
+%%--------------------------------------------------------------------
+%% External exports
+%%--------------------------------------------------------------------
+-export([
+ start/2,
+ shutdown/0,
+ stop/1
+ ]).
+
+%%--------------------------------------------------------------------
+%% Macros
+%%--------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Records
+%%--------------------------------------------------------------------
+
+%%====================================================================
+%% External functions
+%%====================================================================
+%%--------------------------------------------------------------------
+%% @doc The starting point for an erlang application.
+%% @spec start(Type, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}
+%% @end
+%%--------------------------------------------------------------------
+start(Type, StartArgs) ->
+ case %%PFX%%_sup:start_link(StartArgs) of
+ {ok, Pid} ->
+ {ok, Pid};
+ Error ->
+ Error
+ end.
+
+%%--------------------------------------------------------------------
+%% @doc Called to shudown the %%APP_NAME%% application.
+%% @spec shutdown() -> ok
+%% @end
+%%--------------------------------------------------------------------
+shutdown() ->
+ application:stop(%%APP_NAME%%).
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
+
+%%--------------------------------------------------------------------
+%% Called upon the termintion of an application.
+%%--------------------------------------------------------------------
+stop(State) ->
+ ok.
+
diff --git a/lib/erl/tools/.appgen/blank_app/vsn.mk b/lib/erl/tools/.appgen/blank_app/vsn.mk
new file mode 100755
index 0000000..9ba174b
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app/vsn.mk
@@ -0,0 +1 @@
+%%APP_NAME_UPPER_CASE%%_VSN=1.0
diff --git a/lib/erl/tools/.appgen/blank_app_rel/Makefile b/lib/erl/tools/.appgen/blank_app_rel/Makefile
new file mode 100755
index 0000000..5d35956
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app_rel/Makefile
@@ -0,0 +1,298 @@
+# ----------------------------------------------------
+# Make file for creating an otp release.
+# ----------------------------------------------------
+
+##
+# Basename of this release.
+##
+RELS=$(shell basename `pwd`)
+APP_NAME=$(shell echo $(RELS) | sed s/_rel$$//)
+
+include ../../build/otp.mk
+
+include ./vsn.mk
+
+#include $(ERL_TOP)/make/target.mk
+#include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+USR_LIBPATH=../../lib
+INSTALL_DIR=/usr/local/lib
+ABS_USER_LIBPATH=$(shell cd ../../lib;pwd)
+
+# ----------------------------------------------------
+# CREATE DIR STRUCTURE HERE
+# ----------------------------------------------------
+
+HTDOCS=$(wildcard $(ABS_USER_LIBPATH)/$(APP_NAME)/htdocs/*.html) \
+ $(wildcard $(ABS_USER_LIBPATH)/$(APP_NAME)/htdocs/*.htm) \
+ $(wildcard $(ABS_USER_LIBPATH)/$(APP_NAME)/htdocs/*.yaws)
+BUILD_FILES=fs_boot_smithe.beam fs_lists.beam fs_lib.beam
+
+LOCAL_DIR=local
+#LOCAL_DIR=$(shell cat $(RELS).rel.src |grep -m 1 '$(APP_NAME)' |awk -F '"' '{printf "%s-%s", $$2,$$4}')
+
+DIR_STRUCTURE= \
+ $(LOCAL_DIR) \
+ $(LOCAL_DIR)/log/$(REL_VSN) \
+ $(LOCAL_DIR)/var/$(REL_VSN) \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/conf \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/htdocs
+
+PRODUCTION_DIR_STRUCTURE= \
+ $(RELS) \
+ $(RELS)/release/$(REL_VSN) \
+ $(RELS)/stage \
+ $(RELS)/log/$(REL_VSN) \
+ $(RELS)/var/$(REL_VSN) \
+ $(RELS)/var/$(REL_VSN)/www \
+ $(RELS)/var/$(REL_VSN)/www/htdocs \
+ $(RELS)/var/$(REL_VSN)/www/conf
+
+# ----------------------------------------------------
+SCRIPT_AND_BOOT_FILES= \
+ $(RELS).script \
+ $(RELS).boot
+
+LOCAL_SCRIPT_AND_BOOT_FILES= \
+ $(LOCAL_DIR)/$(RELS).script \
+ $(LOCAL_DIR)/$(RELS).boot
+
+LOCAL_HTTP_CONF= \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/conf/yaws.conf \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/conf/mime.types
+
+PRODUCTION_HTTP_CONF= \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/conf/yaws.conf \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/conf/mime.types
+
+LOCAL_TARGET_FILES=$(LOCAL_HTTP_CONF) $(LOCAL_DIR)/$(RELS).config $(LOCAL_SCRIPT_AND_BOOT_FILES)
+
+LOCAL_TARGETS=$(LOCAL_DIR)/$(RELS).sh vsnit $(LOCAL_TARGET_FILES)
+
+PRODUCTION_TARGETS=$(RELS)/build/$(REL_VSN) \
+ $(RELS)/lib \
+ $(RELS)/stage/$(RELS).rel.src \
+ $(RELS)/stage/$(RELS).config.src \
+ $(RELS)/stage/yaws.conf.src \
+ $(RELS)/stage/$(RELS).sh.src \
+ $(RELS)/var/$(REL_VSN)/www/htdocs \
+ $(RELS)/install.sh \
+ $(RELS)/release/$(REL_VSN)/clean_release
+
+# ----------------------------------------------------
+# TARGETS
+# ----------------------------------------------------
+
+all debug opt instr script: $(DIR_STRUCTURE) $(LOCAL_TARGETS) $(PRODUCTION_DIR_STRUCTURE) $(PRODUCTION_TARGETS)
+ @echo $(HTDOCS)
+
+install: stage
+
+tar: $(RELS)-$(LOCATION)-$(REL_VSN).tgz
+
+$(DIR_STRUCTURE):
+ mkdir -p $@
+
+$(PRODUCTION_DIR_STRUCTURE):
+ mkdir -p $@
+
+clean:
+ $(RM) $(REL_SCRIPTS) $(TARGET_FILES)
+ $(RM) -r $(LOCAL_DIR) $(PRODN_DIR)
+ $(RM) $(RELS).rel
+ $(RM) -r $(RELS)
+ $(RM) $(RELS)*.tgz
+ $(RM) $(RELS).rel.src.tmp
+ $(RM) $(SCRIPT_AND_BOOT_FILES)
+
+docs:
+
+# ----------------------------------------------------
+# TARGETS FOR LOCAL MODE
+# ----------------------------------------------------
+
+# startup script for local mode
+$(LOCAL_DIR)/$(RELS).sh:
+ @echo '#!/bin/sh' > $@
+ @echo "cd $(CURDIR)/$(LOCAL_DIR)" >> $@
+ @echo "erl -name $${USER}_$(RELS) -boot $(RELS) -config $(RELS).config \$$@" >> $@
+ chmod +x $@
+ @echo
+ @echo "==== Start local node with \"sh $@\" ===="
+ @echo
+
+# Create the config file for local mode.
+$(LOCAL_DIR)/$(RELS).config: $(RELS).config.src
+ sed -e 's;%LOG_OTP%;$(CURDIR)/$(LOCAL_DIR)/log/$(REL_VSN);' \
+ -e 's;%VAR_OTP%;$(CURDIR)/$(LOCAL_DIR)/var/$(REL_VSN);' \
+ -e 's;%RELS%;$(RELS);g' \
+ -e 's;%HOME%;$(HOME);g' \
+ -e 's;%BROADCAST_ADDRESS%;$(BROADCAST_ADDRESS);g' \
+ -e 's;%CONTACT_NODE%;$(CONTACT_NODE);g' \
+ -e "s;%HOSTNAME%;`hostname --long`;" \
+ -e 's;%APP_NAME%;$(APP_NAME);' \
+ -e 's;%APP_VERSION%;$(APP_VERSION);g' \
+ $< > $@
+
+# Create the httpd conf file for local mode.
+$(LOCAL_DIR)/var/$(REL_VSN)/www/conf/yaws.conf: yaws.conf.src
+ sed -e 's;%VAR_OTP%;$(CURDIR)/$(LOCAL_DIR)/var/$(REL_VSN);' \
+ -e 's;%LOG_OTP%;$(CURDIR)/$(LOCAL_DIR)/log/$(REL_VSN);' \
+ -e 's;%HTDOC_ROOT%;$(ABS_USER_LIBPATH)/$(APP_NAME)/htdocs;' \
+ -e 's;%APP_NAME%;$(APP_NAME);' \
+ -e 's;%RELS%;$(RELS);' \
+ -e 's;%USER%;$(USER);' \
+ -e 's;%HTDOC_ROOT%;$(ABS_USER_LIBPATH);' \
+ -e 's;%MHOST%;$(MHOST);' \
+ $< > $@
+
+# Create the config file for local mode.
+vsnit: $(RELS).rel.src
+ sed -e 's;%REL_VSN%;$(REL_VSN);' \
+ $< > $<.tmp
+
+# Create and position script and boot files for local mode.
+$(LOCAL_SCRIPT_AND_BOOT_FILES):
+ @ erl -pz $(USR_LIBPATH)/fslib/ebin \
+ -noshell \
+ -s fs_lib s_apply fs_boot_smithe make_script_and_boot "[\"$(ERL_RUN_TOP)/*\", \"$(USR_LIBPATH)\"]. " \
+ \"$$(basename `pwd`)".rel.src.tmp\". " \
+ "[local]. " \
+ -s init stop
+ cp $(SCRIPT_AND_BOOT_FILES) $(LOCAL_DIR)/
+
+$(LOCAL_DIR)/var/$(REL_VSN)/www/conf/mime.types: ../../build/mime.types
+ cp $< $@
+
+# ----------------------------------------------------
+# TARGETS FOR PRODUCTION MODE
+# ----------------------------------------------------
+$(RELS)/lib:
+ # For some reason this will not happen if added to PRODUCTION_DIR_STRUCTURE
+ mkdir $@
+ @ erl -pz $(RELS)/build/$(REL_VSN) \
+ -noshell \
+ -s fs_lib s_apply fs_boot_smithe stage_from_relsrc "[\"$(USR_LIBPATH)\"]. " \
+ \"$$(basename `pwd`)".rel.src\". " \
+ \"$@\"". " \
+ -s init stop
+
+# Move the htdocs from the local apps to the production htdoc root directory.
+$(RELS)/var/$(REL_VSN)/www/htdocs/: $(HTDOCS)
+ @mkdir -p $(RELS)/var/$(REL_VSN)/www/htdocs; \
+ for x in $(HTDOCS);do \
+ cp $$x $@; \
+ done
+
+# startup script for production mode
+$(RELS)/stage/$(RELS).sh.src:
+ @echo '#!/bin/sh' > $@
+ @echo "cd %INSTALL_DIR%/$(RELS)/release/$(REL_VSN)" >> $@
+ @echo "erl -name $(RELS) -boot $(RELS) -config $(RELS).config -detached \$$@" >> $@
+ chmod +x $@
+
+$(RELS)/build/$(REL_VSN): $(USR_LIBPATH)/fslib/ebin
+ mkdir -p $(RELS)/build/$(REL_VSN)
+ cp $</fs_boot_smithe.beam $@
+ cp $</fs_lib.beam $@
+ cp $</fs_lists.beam $@
+
+$(RELS)/stage/$(RELS).rel.src: $(RELS).rel.src.tmp
+ cp $< $@
+
+$(RELS)/stage/$(RELS).config.src: $(RELS).config.src
+ cp $< $@
+
+$(RELS)/stage/yaws.conf.src: yaws.conf.src
+ cp $< $@
+
+$(RELS)/install.sh:
+ @echo '#!/bin/sh' > $@
+ @echo "" >> $@
+ @echo "if [ \$$# -eq 1 ];then" >> $@
+ @echo " INSTALL_DIR=\$$1;" >> $@
+ @echo "else" >> $@
+ @echo " INSTALL_DIR=$(INSTALL_DIR);" >> $@
+ @echo "fi" >> $@
+ @echo "" >> $@
+ @echo "function munge() {" >> $@
+ @echo " sed -e \"s;%LOG_OTP%;\$$INSTALL_DIR/$(RELS)/log/$(REL_VSN);g\" \\" >> $@
+ @echo " -e \"s;%VAR_OTP%;\$$INSTALL_DIR/$(RELS)/var/$(REL_VSN);g\" \\" >> $@
+ @echo " -e \"s;%RELS%;$(RELS);g\" \\" >> $@
+ @echo " -e \"s;%REL_VSN%;$(REL_VSN);g\" \\" >> $@
+ @echo " -e \"s;%USER%;$$USER;g\" \\" >> $@
+ @echo " -e \"s;%HTDOC_ROOT%;\$$INSTALL_DIR/$(RELS)/var/$(REL_VSN)/www/htdocs;g\" \\" >> $@
+ @echo " -e \"s;%MHOST%;\`hostname\`;g\" \\" >> $@
+ @echo " -e \"s;%BROADCAST_ADDRESS%;$(BROADCAST_ADDRESS);g\" \\" >> $@
+ @echo " -e \"s;%INSTALL_DIR%;\$$INSTALL_DIR;g\" \\" >> $@
+ @echo " -e \"s;%CONTACT_NODE%;$(CONTACT_NODE);g\" \\" >> $@
+ @echo " -e \"s;%HOSTNAME%;\`hostname --long\`;g\" \\" >> $@
+ @echo " -e \"s;%APP_NAME%;$(APP_NAME);g\" \\" >> $@
+ @echo " -e \"s;%APP_VERSION%;$(APP_VERSION);g\" \\" >> $@
+ @echo ' $$1 > $$2' >> $@
+ @echo "}" >> $@
+ @echo "" >> $@
+ @echo "munge stage/yaws.conf.src var/$(REL_VSN)/www/conf/yaws.conf;" >> $@
+ @echo "munge stage/$(RELS).config.src release/$(REL_VSN)/$(RELS).config;" >> $@
+ @echo "munge stage/$(RELS).sh.src release/$(REL_VSN)/$(RELS).sh;" >> $@
+ @echo "munge stage/$(RELS).rel.src release/$(REL_VSN)/$(RELS).rel;" >> $@
+ @echo "chmod +x release/$(REL_VSN)/$(RELS).sh;" >> $@
+ @echo "" >> $@
+ @echo "cd ..;" >> $@
+ @echo "find $(RELS) | cpio -o > \$$INSTALL_DIR/$(RELS).cpio;" >> $@
+ @echo "cd -;" >> $@
+ @echo "cd \$$INSTALL_DIR; " >> $@
+ @echo "echo -n \"Unpacked: \"" >> $@
+ @echo "cpio -uid < $(RELS).cpio;" >> $@
+ @echo "rm $(RELS).cpio;" >> $@
+ @echo "" >> $@
+ @echo "echo \"pwd is \`pwd\`\";" >> $@
+ @echo "cd $(RELS);" >> $@
+ @echo " erl -pz build/$(REL_VSN) \\" >> $@
+ @echo " -noshell \\" >> $@
+ @echo -n " -s fs_lib s_apply fs_boot_smithe make_script_and_boot \"[\\\"$(ERL_RUN_TOP)/*\\\", \\\"lib/\\\"]. \" " >> $@
+ @echo -n "\"\\\"stage/$$(basename `pwd`).rel.src\\\". \" " >> $@
+ @echo -n "\"[local]. \" " >> $@
+ @echo "-s init stop | egrep '*terminate*|ERROR'" >> $@
+ @echo "if [ \$$? -eq 0 ]; then" >> $@
+ @echo "echo \"============================================\";" >> $@
+ @echo "echo \"STAGE FAILURE \$$? - Silence the discord.\";" >> $@
+ @echo "echo \"============================================\";" >> $@
+ @echo "exit 1;" >> $@
+ @echo "fi" >> $@
+ @echo "" >> $@
+ @echo "mv $(RELS).rel $(RELS).script $(RELS).boot release/$(REL_VSN);" >> $@
+ @echo "" >> $@
+ @echo "rm -r stage;" >> $@
+ @echo "rm -r build;" >> $@
+ @echo "cd -;" >> $@
+ @echo "" >> $@
+ @echo "chgrp -R erts $(RELS); " >> $@
+ @echo "chmod -R 775 $(RELS); " >> $@
+ @echo "cd -" >> $@
+ @echo "" >> $@
+ @echo "rm -f /usr/local/bin/$(APP_NAME);" >> $@
+ @echo "ln -s \$$INSTALL_DIR/$(RELS)/release/$(REL_VSN)/$(RELS).sh /usr/local/bin/$(APP_NAME);" >> $@
+ @echo "chgrp -R erts /usr/local/bin/$(APP_NAME); " >> $@
+ @echo "chmod -R 775 /usr/local/bin/$(APP_NAME); " >> $@
+ @echo "rm \$$INSTALL_DIR/$(RELS)/install.sh;" >> $@
+ @echo "echo -n $$'\e[0;32m'" >> $@
+ @echo "echo \"$(APP_NAME) installation to \$$INSTALL_DIR complete.\"" >> $@
+ @echo "echo -n $$'\e[0m'" >> $@
+ chmod +x $@
+
+
+stage: $(RELS)
+ cd $(RELS); \
+ ./install.sh; \
+ cd -
+
+$(RELS)/var/$(REL_VSN)/www/conf/mime.types: ../../build/mime.types
+ cp $< $@
+
+$(RELS)-$(LOCATION)-$(REL_VSN).tgz: $(RELS)
+ tar -zcvf $@ $<
+
+$(RELS)/release/$(REL_VSN)/clean_release: ../../tools/utilities/clean_release
+ cp $< $@
+
diff --git a/lib/erl/tools/.appgen/blank_app_rel/blank_app_rel.config.src b/lib/erl/tools/.appgen/blank_app_rel/blank_app_rel.config.src
new file mode 100755
index 0000000..c701c5a
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app_rel/blank_app_rel.config.src
@@ -0,0 +1,26 @@
+%%% -*- mode:erlang -*-
+%%% Parameter settings for apps on %APP_NAME%
+%%% Warning - this config file *must* end with <dot><whitespace>
+
+%% write log files to sasl_dir
+[
+ {sasl,
+ [
+ {sasl_error_logger, {file, "%LOG_OTP%/sasl_log"}}
+ ]},
+
+
+ {gas,
+ [
+ {mod_specs, [{elwrap, {fs_elwrap_h, start_link}}]},
+
+ % elwrap config.
+ {err_log, "%LOG_OTP%/err_log"},
+ {err_log_wrap_info, {{err,5000000,10},{sasl,5000000,10}}},
+ {err_log_tty, true} % Log to the screen
+ ]},
+
+ {%APP_NAME%,
+ [
+ ]}
+].
diff --git a/lib/erl/tools/.appgen/blank_app_rel/blank_app_rel.rel.src b/lib/erl/tools/.appgen/blank_app_rel/blank_app_rel.rel.src
new file mode 100755
index 0000000..f69578e
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app_rel/blank_app_rel.rel.src
@@ -0,0 +1,14 @@
+%%% -*- mode:erlang -*-
+{release,
+ {"%%APP_NAME%%_rel", "%REL_VSN%"},
+ erts,
+ [
+ kernel,
+ stdlib,
+ sasl,
+ fslib,
+ gas,
+ %%APP_NAME%%
+ ]
+}.
+
diff --git a/lib/erl/tools/.appgen/blank_app_rel/vsn.mk b/lib/erl/tools/.appgen/blank_app_rel/vsn.mk
new file mode 100755
index 0000000..0ac8e07
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app_rel/vsn.mk
@@ -0,0 +1 @@
+REL_VSN=1.0
diff --git a/lib/erl/tools/.appgen/blank_app_rel/yaws.conf.src b/lib/erl/tools/.appgen/blank_app_rel/yaws.conf.src
new file mode 100644
index 0000000..8857aac
--- /dev/null
+++ b/lib/erl/tools/.appgen/blank_app_rel/yaws.conf.src
@@ -0,0 +1,166 @@
+
+# conf for yaws
+
+
+# first we have a set of globals
+# That apply to all virtual servers
+
+
+# This is the directory where all logfiles for
+# all virtual servers will be written
+
+logdir = /var/log/yaws
+
+# This the path to a directory where additional
+# beam code can be placed. The daemon will add this
+# directory to its search path
+
+ebin_dir = /var/yaws/ebin
+
+
+# This is a directory where application specific .hrl
+# files can be placed. application specifig .yaws code can
+# then include these .hrl files
+
+include_dir = /var/yaws/include
+
+
+
+
+
+# This is a debug variable, possible values are http | traffic | false
+# It is also possible to set the trace (possibly to the tty) while
+# invoking yaws from the shell as in
+# yaws -i -T -x (see man yaws)
+
+trace = false
+
+
+
+
+
+# it is possible to have yaws start additional
+# application specific code at startup
+#
+# runmod = mymodule
+
+
+# By default yaws will copy the erlang error_log and
+# end write it to a wrap log called report.log (in the logdir)
+# this feature can be turned off. This would typically
+# be the case when yaws runs within another larger app
+
+copy_error_log = true
+
+
+# Logs are wrap logs
+
+log_wrap_size = 1000000
+
+
+# Possibly resolve all hostnames in logfiles so webalizer
+# can produce the nice geography piechart
+
+log_resolve_hostname = false
+
+
+
+# fail completely or not if yaws fails
+# to bind a listen socket
+fail_on_bind_err = true
+
+
+
+# If yaws is started as root, it can, once it has opened
+# all relevant sockets for listening, change the uid to a
+# user with lower accessrights than root
+
+# username = nobody
+
+
+# If HTTP auth is used, it is possible to have a specific
+# auth log.
+
+auth_log = true
+
+
+# When we're running multiple yaws systems on the same
+# host, we need to give each yaws system an individual
+# name. Yaws will write a number of runtime files under
+# /tmp/yaws/${id}
+# The default value is "default"
+
+
+# id = myname
+
+
+# earlier versions of Yaws picked the first virtual host
+# in a list of hosts with the same IP/PORT when the Host:
+# header doesn't match any name on any Host
+# This is often nice in testing environments but not
+# acceptable in real live hosting scenarios
+
+pick_first_virthost_on_nomatch = true
+
+
+# All unices are broken since it's not possible to bind to
+# a privileged port (< 1024) unless uid==0
+# There is a contrib in jungerl which makes it possible by means
+# of an external setuid root programm called fdsrv to listen to
+# to privileged port.
+# If we use this feature, it requires fdsrv to be properly installed.
+# Doesn't yet work with SSL.
+
+use_fdsrv = false
+
+
+
+
+# end then a set of virtual servers
+# First two virthosted servers on the same IP (0.0.0.0)
+# in this case, but an explicit IP can be given as well
+
+<server core.martinjlogan.com>
+ port = 80
+ listen = 0.0.0.0
+ docroot = /var/yaws/www
+ arg_rewrite_mod = pwr_arg_rewrite_mod
+ appmods = <pwr, pwr_main_controller_appmod>
+</server>
+
+<server localhost>
+ port = 80
+ listen = 0.0.0.0
+ docroot = /tmp
+ dir_listings = true
+ dav = true
+ <auth>
+ realm = foobar
+ dir = /
+ user = foo:bar
+ user = baz:bar
+ </auth>
+</server>
+
+
+
+# And then an ssl server
+
+<server core.martinjlogan.com>
+ port = 443
+ docroot = /tmp
+ listen = 0.0.0.0
+ dir_listings = true
+ <ssl>
+ keyfile = /usr/local/yaws/etc/yaws-key.pem
+ certfile = /usr/local/yaws/etc/yaws-cert.pem
+ </ssl>
+</server>
+
+
+
+
+
+
+
+
diff --git a/lib/erl/tools/.appgen/rename.sh b/lib/erl/tools/.appgen/rename.sh
new file mode 100755
index 0000000..6f077c2
--- /dev/null
+++ b/lib/erl/tools/.appgen/rename.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+
+if [ $# -eq 3 ]; then
+ OLD_PREFIX=$1
+ NEW_PREFIX=$2
+ FILENAME=$3
+ NEW_FILENAME=$(echo $FILENAME | sed -e "s/$OLD_PREFIX/$NEW_PREFIX/")
+ echo "moving $FILENAME to $NEW_FILENAME"
+ mv $FILENAME $NEW_FILENAME
+ exit 0;
+fi
+
+
+if [ $# -eq 2 ]; then
+ while read line;
+ do
+ OLD_PREFIX=$1
+ NEW_PREFIX=$2
+ NEW_FILENAME=$(echo ${line} | sed -e "s/$OLD_PREFIX/$NEW_PREFIX/")
+ echo "moving ${line} to $NEW_FILENAME"
+ mv ${line} $NEW_FILENAME
+ done
+ exit 0
+fi
+
diff --git a/lib/erl/tools/.appgen/substitute.sh b/lib/erl/tools/.appgen/substitute.sh
new file mode 100755
index 0000000..5305b75
--- /dev/null
+++ b/lib/erl/tools/.appgen/substitute.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+
+if [ $# -lt 2 ]; then
+ echo "usage: substitute.sh <variable to replace> <value to replace with> <filename | STDIN>"
+ exit 1
+fi
+
+if [ $# -eq 3 ]; then
+ VARIABLE=$1
+ VALUE=$2
+ FILENAME=$3
+
+ echo "replacing $VARIABLE with $VALUE in $FILENAME"
+ sed -e "s/$VARIABLE/$VALUE/" $FILENAME > "$FILENAME"_tmp
+ mv "$FILENAME"_tmp $FILENAME
+ exit 0
+fi
+
+if [ $# -eq 2 ]; then
+ while read line;
+ do
+ VARIABLE=$1
+ VALUE=$2
+ FILENAME=${line}
+
+ echo "replacing $VARIABLE with $VALUE in $FILENAME"
+ sed -e "s/$VARIABLE/$VALUE/" $FILENAME > "$FILENAME"_tmp
+ mv "$FILENAME"_tmp $FILENAME
+ done
+ exit 0
+fi
+
diff --git a/lib/erl/tools/.appgen/thrift_rel/Makefile b/lib/erl/tools/.appgen/thrift_rel/Makefile
new file mode 100755
index 0000000..5d35956
--- /dev/null
+++ b/lib/erl/tools/.appgen/thrift_rel/Makefile
@@ -0,0 +1,298 @@
+# ----------------------------------------------------
+# Make file for creating an otp release.
+# ----------------------------------------------------
+
+##
+# Basename of this release.
+##
+RELS=$(shell basename `pwd`)
+APP_NAME=$(shell echo $(RELS) | sed s/_rel$$//)
+
+include ../../build/otp.mk
+
+include ./vsn.mk
+
+#include $(ERL_TOP)/make/target.mk
+#include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+USR_LIBPATH=../../lib
+INSTALL_DIR=/usr/local/lib
+ABS_USER_LIBPATH=$(shell cd ../../lib;pwd)
+
+# ----------------------------------------------------
+# CREATE DIR STRUCTURE HERE
+# ----------------------------------------------------
+
+HTDOCS=$(wildcard $(ABS_USER_LIBPATH)/$(APP_NAME)/htdocs/*.html) \
+ $(wildcard $(ABS_USER_LIBPATH)/$(APP_NAME)/htdocs/*.htm) \
+ $(wildcard $(ABS_USER_LIBPATH)/$(APP_NAME)/htdocs/*.yaws)
+BUILD_FILES=fs_boot_smithe.beam fs_lists.beam fs_lib.beam
+
+LOCAL_DIR=local
+#LOCAL_DIR=$(shell cat $(RELS).rel.src |grep -m 1 '$(APP_NAME)' |awk -F '"' '{printf "%s-%s", $$2,$$4}')
+
+DIR_STRUCTURE= \
+ $(LOCAL_DIR) \
+ $(LOCAL_DIR)/log/$(REL_VSN) \
+ $(LOCAL_DIR)/var/$(REL_VSN) \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/conf \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/htdocs
+
+PRODUCTION_DIR_STRUCTURE= \
+ $(RELS) \
+ $(RELS)/release/$(REL_VSN) \
+ $(RELS)/stage \
+ $(RELS)/log/$(REL_VSN) \
+ $(RELS)/var/$(REL_VSN) \
+ $(RELS)/var/$(REL_VSN)/www \
+ $(RELS)/var/$(REL_VSN)/www/htdocs \
+ $(RELS)/var/$(REL_VSN)/www/conf
+
+# ----------------------------------------------------
+SCRIPT_AND_BOOT_FILES= \
+ $(RELS).script \
+ $(RELS).boot
+
+LOCAL_SCRIPT_AND_BOOT_FILES= \
+ $(LOCAL_DIR)/$(RELS).script \
+ $(LOCAL_DIR)/$(RELS).boot
+
+LOCAL_HTTP_CONF= \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/conf/yaws.conf \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/conf/mime.types
+
+PRODUCTION_HTTP_CONF= \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/conf/yaws.conf \
+ $(LOCAL_DIR)/var/$(REL_VSN)/www/conf/mime.types
+
+LOCAL_TARGET_FILES=$(LOCAL_HTTP_CONF) $(LOCAL_DIR)/$(RELS).config $(LOCAL_SCRIPT_AND_BOOT_FILES)
+
+LOCAL_TARGETS=$(LOCAL_DIR)/$(RELS).sh vsnit $(LOCAL_TARGET_FILES)
+
+PRODUCTION_TARGETS=$(RELS)/build/$(REL_VSN) \
+ $(RELS)/lib \
+ $(RELS)/stage/$(RELS).rel.src \
+ $(RELS)/stage/$(RELS).config.src \
+ $(RELS)/stage/yaws.conf.src \
+ $(RELS)/stage/$(RELS).sh.src \
+ $(RELS)/var/$(REL_VSN)/www/htdocs \
+ $(RELS)/install.sh \
+ $(RELS)/release/$(REL_VSN)/clean_release
+
+# ----------------------------------------------------
+# TARGETS
+# ----------------------------------------------------
+
+all debug opt instr script: $(DIR_STRUCTURE) $(LOCAL_TARGETS) $(PRODUCTION_DIR_STRUCTURE) $(PRODUCTION_TARGETS)
+ @echo $(HTDOCS)
+
+install: stage
+
+tar: $(RELS)-$(LOCATION)-$(REL_VSN).tgz
+
+$(DIR_STRUCTURE):
+ mkdir -p $@
+
+$(PRODUCTION_DIR_STRUCTURE):
+ mkdir -p $@
+
+clean:
+ $(RM) $(REL_SCRIPTS) $(TARGET_FILES)
+ $(RM) -r $(LOCAL_DIR) $(PRODN_DIR)
+ $(RM) $(RELS).rel
+ $(RM) -r $(RELS)
+ $(RM) $(RELS)*.tgz
+ $(RM) $(RELS).rel.src.tmp
+ $(RM) $(SCRIPT_AND_BOOT_FILES)
+
+docs:
+
+# ----------------------------------------------------
+# TARGETS FOR LOCAL MODE
+# ----------------------------------------------------
+
+# startup script for local mode
+$(LOCAL_DIR)/$(RELS).sh:
+ @echo '#!/bin/sh' > $@
+ @echo "cd $(CURDIR)/$(LOCAL_DIR)" >> $@
+ @echo "erl -name $${USER}_$(RELS) -boot $(RELS) -config $(RELS).config \$$@" >> $@
+ chmod +x $@
+ @echo
+ @echo "==== Start local node with \"sh $@\" ===="
+ @echo
+
+# Create the config file for local mode.
+$(LOCAL_DIR)/$(RELS).config: $(RELS).config.src
+ sed -e 's;%LOG_OTP%;$(CURDIR)/$(LOCAL_DIR)/log/$(REL_VSN);' \
+ -e 's;%VAR_OTP%;$(CURDIR)/$(LOCAL_DIR)/var/$(REL_VSN);' \
+ -e 's;%RELS%;$(RELS);g' \
+ -e 's;%HOME%;$(HOME);g' \
+ -e 's;%BROADCAST_ADDRESS%;$(BROADCAST_ADDRESS);g' \
+ -e 's;%CONTACT_NODE%;$(CONTACT_NODE);g' \
+ -e "s;%HOSTNAME%;`hostname --long`;" \
+ -e 's;%APP_NAME%;$(APP_NAME);' \
+ -e 's;%APP_VERSION%;$(APP_VERSION);g' \
+ $< > $@
+
+# Create the httpd conf file for local mode.
+$(LOCAL_DIR)/var/$(REL_VSN)/www/conf/yaws.conf: yaws.conf.src
+ sed -e 's;%VAR_OTP%;$(CURDIR)/$(LOCAL_DIR)/var/$(REL_VSN);' \
+ -e 's;%LOG_OTP%;$(CURDIR)/$(LOCAL_DIR)/log/$(REL_VSN);' \
+ -e 's;%HTDOC_ROOT%;$(ABS_USER_LIBPATH)/$(APP_NAME)/htdocs;' \
+ -e 's;%APP_NAME%;$(APP_NAME);' \
+ -e 's;%RELS%;$(RELS);' \
+ -e 's;%USER%;$(USER);' \
+ -e 's;%HTDOC_ROOT%;$(ABS_USER_LIBPATH);' \
+ -e 's;%MHOST%;$(MHOST);' \
+ $< > $@
+
+# Create the config file for local mode.
+vsnit: $(RELS).rel.src
+ sed -e 's;%REL_VSN%;$(REL_VSN);' \
+ $< > $<.tmp
+
+# Create and position script and boot files for local mode.
+$(LOCAL_SCRIPT_AND_BOOT_FILES):
+ @ erl -pz $(USR_LIBPATH)/fslib/ebin \
+ -noshell \
+ -s fs_lib s_apply fs_boot_smithe make_script_and_boot "[\"$(ERL_RUN_TOP)/*\", \"$(USR_LIBPATH)\"]. " \
+ \"$$(basename `pwd`)".rel.src.tmp\". " \
+ "[local]. " \
+ -s init stop
+ cp $(SCRIPT_AND_BOOT_FILES) $(LOCAL_DIR)/
+
+$(LOCAL_DIR)/var/$(REL_VSN)/www/conf/mime.types: ../../build/mime.types
+ cp $< $@
+
+# ----------------------------------------------------
+# TARGETS FOR PRODUCTION MODE
+# ----------------------------------------------------
+$(RELS)/lib:
+ # For some reason this will not happen if added to PRODUCTION_DIR_STRUCTURE
+ mkdir $@
+ @ erl -pz $(RELS)/build/$(REL_VSN) \
+ -noshell \
+ -s fs_lib s_apply fs_boot_smithe stage_from_relsrc "[\"$(USR_LIBPATH)\"]. " \
+ \"$$(basename `pwd`)".rel.src\". " \
+ \"$@\"". " \
+ -s init stop
+
+# Move the htdocs from the local apps to the production htdoc root directory.
+$(RELS)/var/$(REL_VSN)/www/htdocs/: $(HTDOCS)
+ @mkdir -p $(RELS)/var/$(REL_VSN)/www/htdocs; \
+ for x in $(HTDOCS);do \
+ cp $$x $@; \
+ done
+
+# startup script for production mode
+$(RELS)/stage/$(RELS).sh.src:
+ @echo '#!/bin/sh' > $@
+ @echo "cd %INSTALL_DIR%/$(RELS)/release/$(REL_VSN)" >> $@
+ @echo "erl -name $(RELS) -boot $(RELS) -config $(RELS).config -detached \$$@" >> $@
+ chmod +x $@
+
+$(RELS)/build/$(REL_VSN): $(USR_LIBPATH)/fslib/ebin
+ mkdir -p $(RELS)/build/$(REL_VSN)
+ cp $</fs_boot_smithe.beam $@
+ cp $</fs_lib.beam $@
+ cp $</fs_lists.beam $@
+
+$(RELS)/stage/$(RELS).rel.src: $(RELS).rel.src.tmp
+ cp $< $@
+
+$(RELS)/stage/$(RELS).config.src: $(RELS).config.src
+ cp $< $@
+
+$(RELS)/stage/yaws.conf.src: yaws.conf.src
+ cp $< $@
+
+$(RELS)/install.sh:
+ @echo '#!/bin/sh' > $@
+ @echo "" >> $@
+ @echo "if [ \$$# -eq 1 ];then" >> $@
+ @echo " INSTALL_DIR=\$$1;" >> $@
+ @echo "else" >> $@
+ @echo " INSTALL_DIR=$(INSTALL_DIR);" >> $@
+ @echo "fi" >> $@
+ @echo "" >> $@
+ @echo "function munge() {" >> $@
+ @echo " sed -e \"s;%LOG_OTP%;\$$INSTALL_DIR/$(RELS)/log/$(REL_VSN);g\" \\" >> $@
+ @echo " -e \"s;%VAR_OTP%;\$$INSTALL_DIR/$(RELS)/var/$(REL_VSN);g\" \\" >> $@
+ @echo " -e \"s;%RELS%;$(RELS);g\" \\" >> $@
+ @echo " -e \"s;%REL_VSN%;$(REL_VSN);g\" \\" >> $@
+ @echo " -e \"s;%USER%;$$USER;g\" \\" >> $@
+ @echo " -e \"s;%HTDOC_ROOT%;\$$INSTALL_DIR/$(RELS)/var/$(REL_VSN)/www/htdocs;g\" \\" >> $@
+ @echo " -e \"s;%MHOST%;\`hostname\`;g\" \\" >> $@
+ @echo " -e \"s;%BROADCAST_ADDRESS%;$(BROADCAST_ADDRESS);g\" \\" >> $@
+ @echo " -e \"s;%INSTALL_DIR%;\$$INSTALL_DIR;g\" \\" >> $@
+ @echo " -e \"s;%CONTACT_NODE%;$(CONTACT_NODE);g\" \\" >> $@
+ @echo " -e \"s;%HOSTNAME%;\`hostname --long\`;g\" \\" >> $@
+ @echo " -e \"s;%APP_NAME%;$(APP_NAME);g\" \\" >> $@
+ @echo " -e \"s;%APP_VERSION%;$(APP_VERSION);g\" \\" >> $@
+ @echo ' $$1 > $$2' >> $@
+ @echo "}" >> $@
+ @echo "" >> $@
+ @echo "munge stage/yaws.conf.src var/$(REL_VSN)/www/conf/yaws.conf;" >> $@
+ @echo "munge stage/$(RELS).config.src release/$(REL_VSN)/$(RELS).config;" >> $@
+ @echo "munge stage/$(RELS).sh.src release/$(REL_VSN)/$(RELS).sh;" >> $@
+ @echo "munge stage/$(RELS).rel.src release/$(REL_VSN)/$(RELS).rel;" >> $@
+ @echo "chmod +x release/$(REL_VSN)/$(RELS).sh;" >> $@
+ @echo "" >> $@
+ @echo "cd ..;" >> $@
+ @echo "find $(RELS) | cpio -o > \$$INSTALL_DIR/$(RELS).cpio;" >> $@
+ @echo "cd -;" >> $@
+ @echo "cd \$$INSTALL_DIR; " >> $@
+ @echo "echo -n \"Unpacked: \"" >> $@
+ @echo "cpio -uid < $(RELS).cpio;" >> $@
+ @echo "rm $(RELS).cpio;" >> $@
+ @echo "" >> $@
+ @echo "echo \"pwd is \`pwd\`\";" >> $@
+ @echo "cd $(RELS);" >> $@
+ @echo " erl -pz build/$(REL_VSN) \\" >> $@
+ @echo " -noshell \\" >> $@
+ @echo -n " -s fs_lib s_apply fs_boot_smithe make_script_and_boot \"[\\\"$(ERL_RUN_TOP)/*\\\", \\\"lib/\\\"]. \" " >> $@
+ @echo -n "\"\\\"stage/$$(basename `pwd`).rel.src\\\". \" " >> $@
+ @echo -n "\"[local]. \" " >> $@
+ @echo "-s init stop | egrep '*terminate*|ERROR'" >> $@
+ @echo "if [ \$$? -eq 0 ]; then" >> $@
+ @echo "echo \"============================================\";" >> $@
+ @echo "echo \"STAGE FAILURE \$$? - Silence the discord.\";" >> $@
+ @echo "echo \"============================================\";" >> $@
+ @echo "exit 1;" >> $@
+ @echo "fi" >> $@
+ @echo "" >> $@
+ @echo "mv $(RELS).rel $(RELS).script $(RELS).boot release/$(REL_VSN);" >> $@
+ @echo "" >> $@
+ @echo "rm -r stage;" >> $@
+ @echo "rm -r build;" >> $@
+ @echo "cd -;" >> $@
+ @echo "" >> $@
+ @echo "chgrp -R erts $(RELS); " >> $@
+ @echo "chmod -R 775 $(RELS); " >> $@
+ @echo "cd -" >> $@
+ @echo "" >> $@
+ @echo "rm -f /usr/local/bin/$(APP_NAME);" >> $@
+ @echo "ln -s \$$INSTALL_DIR/$(RELS)/release/$(REL_VSN)/$(RELS).sh /usr/local/bin/$(APP_NAME);" >> $@
+ @echo "chgrp -R erts /usr/local/bin/$(APP_NAME); " >> $@
+ @echo "chmod -R 775 /usr/local/bin/$(APP_NAME); " >> $@
+ @echo "rm \$$INSTALL_DIR/$(RELS)/install.sh;" >> $@
+ @echo "echo -n $$'\e[0;32m'" >> $@
+ @echo "echo \"$(APP_NAME) installation to \$$INSTALL_DIR complete.\"" >> $@
+ @echo "echo -n $$'\e[0m'" >> $@
+ chmod +x $@
+
+
+stage: $(RELS)
+ cd $(RELS); \
+ ./install.sh; \
+ cd -
+
+$(RELS)/var/$(REL_VSN)/www/conf/mime.types: ../../build/mime.types
+ cp $< $@
+
+$(RELS)-$(LOCATION)-$(REL_VSN).tgz: $(RELS)
+ tar -zcvf $@ $<
+
+$(RELS)/release/$(REL_VSN)/clean_release: ../../tools/utilities/clean_release
+ cp $< $@
+
diff --git a/lib/erl/tools/.appgen/thrift_rel/thrift_rel.config.src b/lib/erl/tools/.appgen/thrift_rel/thrift_rel.config.src
new file mode 100755
index 0000000..c701c5a
--- /dev/null
+++ b/lib/erl/tools/.appgen/thrift_rel/thrift_rel.config.src
@@ -0,0 +1,26 @@
+%%% -*- mode:erlang -*-
+%%% Parameter settings for apps on %APP_NAME%
+%%% Warning - this config file *must* end with <dot><whitespace>
+
+%% write log files to sasl_dir
+[
+ {sasl,
+ [
+ {sasl_error_logger, {file, "%LOG_OTP%/sasl_log"}}
+ ]},
+
+
+ {gas,
+ [
+ {mod_specs, [{elwrap, {fs_elwrap_h, start_link}}]},
+
+ % elwrap config.
+ {err_log, "%LOG_OTP%/err_log"},
+ {err_log_wrap_info, {{err,5000000,10},{sasl,5000000,10}}},
+ {err_log_tty, true} % Log to the screen
+ ]},
+
+ {%APP_NAME%,
+ [
+ ]}
+].
diff --git a/lib/erl/tools/.appgen/thrift_rel/thrift_rel.rel.src b/lib/erl/tools/.appgen/thrift_rel/thrift_rel.rel.src
new file mode 100644
index 0000000..a11d240
--- /dev/null
+++ b/lib/erl/tools/.appgen/thrift_rel/thrift_rel.rel.src
@@ -0,0 +1,14 @@
+%%% -*- mode:erlang -*-
+{release,
+ {"thrift_rel", "%REL_VSN%"},
+ erts,
+ [
+ kernel,
+ stdlib,
+ sasl,
+ fslib,
+ gas,
+ thrift
+ ]
+}.
+
diff --git a/lib/erl/tools/.appgen/thrift_rel/vsn.mk b/lib/erl/tools/.appgen/thrift_rel/vsn.mk
new file mode 100755
index 0000000..0ac8e07
--- /dev/null
+++ b/lib/erl/tools/.appgen/thrift_rel/vsn.mk
@@ -0,0 +1 @@
+REL_VSN=1.0
diff --git a/lib/erl/tools/.appgen/thrift_rel/yaws.conf.src b/lib/erl/tools/.appgen/thrift_rel/yaws.conf.src
new file mode 100644
index 0000000..8857aac
--- /dev/null
+++ b/lib/erl/tools/.appgen/thrift_rel/yaws.conf.src
@@ -0,0 +1,166 @@
+
+# conf for yaws
+
+
+# first we have a set of globals
+# That apply to all virtual servers
+
+
+# This is the directory where all logfiles for
+# all virtual servers will be written
+
+logdir = /var/log/yaws
+
+# This the path to a directory where additional
+# beam code can be placed. The daemon will add this
+# directory to its search path
+
+ebin_dir = /var/yaws/ebin
+
+
+# This is a directory where application specific .hrl
+# files can be placed. application specifig .yaws code can
+# then include these .hrl files
+
+include_dir = /var/yaws/include
+
+
+
+
+
+# This is a debug variable, possible values are http | traffic | false
+# It is also possible to set the trace (possibly to the tty) while
+# invoking yaws from the shell as in
+# yaws -i -T -x (see man yaws)
+
+trace = false
+
+
+
+
+
+# it is possible to have yaws start additional
+# application specific code at startup
+#
+# runmod = mymodule
+
+
+# By default yaws will copy the erlang error_log and
+# end write it to a wrap log called report.log (in the logdir)
+# this feature can be turned off. This would typically
+# be the case when yaws runs within another larger app
+
+copy_error_log = true
+
+
+# Logs are wrap logs
+
+log_wrap_size = 1000000
+
+
+# Possibly resolve all hostnames in logfiles so webalizer
+# can produce the nice geography piechart
+
+log_resolve_hostname = false
+
+
+
+# fail completely or not if yaws fails
+# to bind a listen socket
+fail_on_bind_err = true
+
+
+
+# If yaws is started as root, it can, once it has opened
+# all relevant sockets for listening, change the uid to a
+# user with lower accessrights than root
+
+# username = nobody
+
+
+# If HTTP auth is used, it is possible to have a specific
+# auth log.
+
+auth_log = true
+
+
+# When we're running multiple yaws systems on the same
+# host, we need to give each yaws system an individual
+# name. Yaws will write a number of runtime files under
+# /tmp/yaws/${id}
+# The default value is "default"
+
+
+# id = myname
+
+
+# earlier versions of Yaws picked the first virtual host
+# in a list of hosts with the same IP/PORT when the Host:
+# header doesn't match any name on any Host
+# This is often nice in testing environments but not
+# acceptable in real live hosting scenarios
+
+pick_first_virthost_on_nomatch = true
+
+
+# All unices are broken since it's not possible to bind to
+# a privileged port (< 1024) unless uid==0
+# There is a contrib in jungerl which makes it possible by means
+# of an external setuid root programm called fdsrv to listen to
+# to privileged port.
+# If we use this feature, it requires fdsrv to be properly installed.
+# Doesn't yet work with SSL.
+
+use_fdsrv = false
+
+
+
+
+# end then a set of virtual servers
+# First two virthosted servers on the same IP (0.0.0.0)
+# in this case, but an explicit IP can be given as well
+
+<server core.martinjlogan.com>
+ port = 80
+ listen = 0.0.0.0
+ docroot = /var/yaws/www
+ arg_rewrite_mod = pwr_arg_rewrite_mod
+ appmods = <pwr, pwr_main_controller_appmod>
+</server>
+
+<server localhost>
+ port = 80
+ listen = 0.0.0.0
+ docroot = /tmp
+ dir_listings = true
+ dav = true
+ <auth>
+ realm = foobar
+ dir = /
+ user = foo:bar
+ user = baz:bar
+ </auth>
+</server>
+
+
+
+# And then an ssl server
+
+<server core.martinjlogan.com>
+ port = 443
+ docroot = /tmp
+ listen = 0.0.0.0
+ dir_listings = true
+ <ssl>
+ keyfile = /usr/local/yaws/etc/yaws-key.pem
+ certfile = /usr/local/yaws/etc/yaws-cert.pem
+ </ssl>
+</server>
+
+
+
+
+
+
+
+
diff --git a/lib/erl/tools/emacs/erlang-start.el b/lib/erl/tools/emacs/erlang-start.el
new file mode 100755
index 0000000..5181b9a
--- /dev/null
+++ b/lib/erl/tools/emacs/erlang-start.el
@@ -0,0 +1,115 @@
+;; erlang-start.el --- Load this file to initialize the Erlang package.
+
+;; Copyright (C) 1998 Ericsson Telecom AB
+
+;; Author: Anders Lindgren
+;; Version: 2.3
+;; Keywords: erlang, languages, processes
+;; Created: 1996-09-18
+;; Date: 1998-03-16
+
+;;; Commentary:
+
+;; Introduction:
+;; ------------
+;;
+;; This package provides support for the programming language Erlang.
+;; The package provides an editing mode with lots of bells and
+;; whistles, compilation support, and it makes it possible for the
+;; user to start Erlang shells that run inside Emacs.
+;;
+;; See the Erlang distribution for full documentation of this package.
+
+;; Installation:
+;; ------------
+;;
+;; Place this file in Emacs load path, byte-compile it, and add the
+;; following line to the appropriate init file:
+;;
+;; (require 'erlang-start)
+;;
+;; The full documentation contains much more extensive description of
+;; the installation procedure.
+
+;; Reporting Bugs:
+;; --------------
+;;
+;; Please send bug reports to the following email address:
+;; support@erlang.ericsson.se
+;;
+;; Please state as exactly as possible:
+;; - Version number of Erlang Mode (see the menu), Emacs, Erlang,
+;; and of any other relevant software.
+;; - What the expected result was.
+;; - What you did, preferably in a repeatable step-by-step form.
+;; - A description of the unexpected result.
+;; - Relevant pieces of Erlang code causing the problem.
+;; - Personal Emacs customisations, if any.
+;;
+;; Should the Emacs generate an error, please set the emacs variable
+;; `debug-on-error' to `t'. Repeat the error and enclose the debug
+;; information in your bug-report.
+;;
+;; To set the variable you can use the following command:
+;; M-x set-variable RET debug-on-error RET t RET
+;;; Code:
+
+;;
+;; Declare functions in "erlang.el".
+;;
+
+(autoload 'erlang-mode "erlang" "Major mode for editing Erlang code." t)
+(autoload 'erlang-version "erlang"
+ "Return the current version of Erlang mode." t)
+(autoload 'erlang-shell "erlang" "Start a new Erlang shell." t)
+(autoload 'run-erlang "erlang" "Start a new Erlang shell." t)
+
+(autoload 'erlang-compile "erlang"
+ "Compile Erlang module in current buffer." t)
+
+(autoload 'erlang-man-module "erlang"
+ "Find manual page for MODULE." t)
+(autoload 'erlang-man-function "erlang"
+ "Find manual page for NAME, where NAME is module:function." t)
+
+(autoload 'erlang-find-tag "erlang"
+ "Like `find-tag'. Capable of retreiving Erlang modules.")
+(autoload 'erlang-find-tag-other-window "erlang"
+ "Like `find-tag-other-window'. Capable of retreiving Erlang modules.")
+
+
+;;
+;; Associate files extensions ".erl" and ".hrl" with Erlang mode.
+;;
+
+(let ((a '("\\.erl\\'" . erlang-mode))
+ (b '("\\.hrl\\'" . erlang-mode)))
+ (or (assoc (car a) auto-mode-alist)
+ (setq auto-mode-alist (cons a auto-mode-alist)))
+ (or (assoc (car b) auto-mode-alist)
+ (setq auto-mode-alist (cons b auto-mode-alist))))
+
+
+;;
+;; Ignore files ending in ".jam", ".vee", and ".beam" when performing
+;; file completion.
+;;
+
+(let ((erl-ext '(".jam" ".vee" ".beam")))
+ (while erl-ext
+ (let ((cie completion-ignored-extensions))
+ (while (and cie (not (string-equal (car cie) (car erl-ext))))
+ (setq cie (cdr cie)))
+ (if (null cie)
+ (setq completion-ignored-extensions
+ (cons (car erl-ext) completion-ignored-extensions))))
+ (setq erl-ext (cdr erl-ext))))
+
+
+;;
+;; The end.
+;;
+
+(provide 'erlang-start)
+
+;; erlang-start.el ends here.
diff --git a/lib/erl/tools/emacs/erlang.el b/lib/erl/tools/emacs/erlang.el
new file mode 100755
index 0000000..5916f73
--- /dev/null
+++ b/lib/erl/tools/emacs/erlang.el
@@ -0,0 +1,6291 @@
+;; $Id: erlang.el,v 1.21 2004/08/03 20:38:43 mlogan Exp $
+;; erlang.el --- Major modes for editing and running Erlang
+
+;; Copyright (C) 1995-1998,2000 Ericsson Telecom AB
+
+;; Author: Anders Lindgren
+;; Version: 2.4
+;; Keywords: erlang, languages, processes
+;; Date: 2000-09-11
+
+;; Lars Thorsén's modifications of 2000-06-07 included.
+
+;; The original version of this package was written by Robert Virding.
+;;
+;; Most skeletons has been written at Ericsson Telecom by
+;; magnus@erix.ericsson.se and janne@erix.ericsson.se
+
+;;; Commentary:
+
+;; Introduction:
+;; ------------
+;;
+;; This package provides support for the programming language Erlang.
+;; The package provides an editing mode with lots of bells and
+;; whistles, compilation support, and it makes it possible for the
+;; user to start Erlang shells that run inside Emacs.
+;;
+;; See the Erlang distribution for full documentation of this package.
+
+;; Installation:
+;; ------------
+;;
+;; Place this file in Emacs load path, byte-compile it, and add the
+;; following line to the appropriate init file:
+;;
+;; (require 'erlang-start)
+;;
+;; The full documentation contains much more extensive description of
+;; the installation procedure.
+
+;; Reporting Bugs:
+;; --------------
+;;
+;; Please send bug reports to the following email address:
+;; support@erlang.ericsson.se
+;;
+;; Please state as exactly as possible:
+;; - Version number of Erlang Mode (see the menu), Emacs, Erlang,
+;; and of any other relevant software.
+;; - What the expected result was.
+;; - What you did, preferably in a repeatable step-by-step form.
+;; - A description of the unexpected result.
+;; - Relevant pieces of Erlang code causing the problem.
+;; - Personal Emacs customisations, if any.
+;;
+;; Should the Emacs generate an error, please set the emacs variable
+;; `debug-on-error' to `t'. Repeat the error and enclose the debug
+;; information in your bug-report.
+;;
+;; To set the variable you can use the following command:
+;; M-x set-variable RET debug-on-error RET t RET
+
+;;; Code:
+
+;; Variables:
+
+(defconst erlang-version "2.4"
+ "The version number of Erlang mode.")
+
+(defvar erlang-root-dir nil
+ "The directory where the Erlang system is installed.
+The name should not contain the ending slash.
+
+Should this variable be nil, no manual pages will show up in the
+Erlang mode menu.")
+
+(defvar erlang-menu-items '(erlang-menu-base-items
+ erlang-menu-skel-items
+ erlang-menu-shell-items
+ erlang-menu-compile-items
+ erlang-menu-man-items
+ erlang-menu-personal-items
+ erlang-menu-version-items)
+ "*List of menu item list to combine to create Erland mode menu.
+
+External programs which temporary adds menu items to the Erland mode
+menu use this variable. Please use the function `add-hook' to add
+items.
+
+Please call the function `erlang-menu-init' after every change to this
+variable.")
+
+(defvar erlang-menu-base-items
+ '(("Indent"
+ (("Indent Line" erlang-indent-command)
+ ("Indent Region " erlang-indent-region
+ (if erlang-xemacs-p (mark) mark-active))
+ ("Indent Clause" erlang-indent-clause)
+ ("Indent Function" erlang-indent-function)
+ ("Indent Buffer" erlang-indent-current-buffer)))
+ ("Edit"
+ (("Fill Comment" erlang-fill-paragraph)
+ ("Comment Region" comment-region
+ (if erlang-xemacs-p (mark) mark-active))
+ ("Uncomment Region" erlang-uncomment-region
+ (if erlang-xemacs-p (mark) mark-active))
+ nil
+ ("Beginning of Function" erlang-beginning-of-function)
+ ("End of Function" erlang-end-of-function)
+ ("Mark Function" erlang-mark-function)
+ nil
+ ("Beginning of Clause" erlang-beginning-of-clause)
+ ("End of Clause" erlang-end-of-clause)
+ ("Mark Clause" erlang-mark-clause)
+ nil
+ ("New Clause" erlang-generate-new-clause)
+ ("Clone Arguments" erlang-clone-arguments)))
+ ("Syntax Highlighting"
+ (("Level 3" erlang-font-lock-level-3)
+ ("Level 2" erlang-font-lock-level-2)
+ ("Level 1" erlang-font-lock-level-1)
+ ("Off" erlang-font-lock-level-0)))
+ ("TAGS"
+ (("Find Tag" find-tag)
+ ("Find Next Tag" erlang-find-next-tag)
+ ;("Find Regexp" find-tag-regexp)
+ ("Complete Word" erlang-complete-tag)
+ ("Tags Apropos" tags-apropos)
+ ("Search Files" tags-search))))
+ "*Description of menu used in Erlang mode.
+
+This variable must be a list. The elements are either nil representing
+a horisontal line or a list with two or three elements. The first is
+the name of the menu item, the second is the function to call, or a
+submenu, on the same same form as ITEMS. The third optional argument
+is an expression which is evaluated every time the menu is displayed.
+Should the expression evaluate to nil the menu item is ghosted.
+
+Example:
+ '((\"Func1\" function-one)
+ (\"SubItem\"
+ ((\"Yellow\" function-yellow)
+ (\"Blue\" function-blue)))
+ nil
+ (\"Region Funtion\" spook-function midnight-variable))
+
+Call the function `erlang-menu-init' after modifying this variable.")
+
+(defvar erlang-menu-shell-items
+ '(nil
+ ("Shell"
+ (("Start New Shell" erlang-shell)
+ ("Display Shell" erlang-shell-display))))
+ "*Description of the Shell menu used by Erlang mode.
+
+Please see the documentation of `erlang-menu-base-items'.")
+
+(defvar erlang-menu-compile-items
+ '(("Compile"
+ (("Compile Buffer" erlang-compile)
+ ("Display Result" erlang-compile-display)
+ ("Next Error" erlang-next-error))))
+ "*Description of the Compile menu used by Erlang mode.
+
+Please see the documentation of `erlang-menu-base-items'.")
+
+(defvar erlang-menu-version-items
+ '(nil
+ ("Version" erlang-version))
+ "*Description of the version menu used in Erlang mode.")
+
+(defvar erlang-menu-personal-items nil
+ "*Description of personal menu items used in Erlang mode.
+
+Please see the variable `erlang-menu-base-items' for a description
+of the format.")
+
+(defvar erlang-menu-man-items nil
+ "The menu containing man pages.
+
+The format of the menu should be compatible with `erlang-menu-base-items'.
+This variable is added to the list of Erlang menus stored in
+`erlang-menu-items'.")
+
+(defvar erlang-menu-skel-items '()
+ "Description of the menu containing the skeleton entries.
+The menu is in the form described by the variable `erlang-menu-base-items'.")
+
+(defvar erlang-mode-hook nil
+ "*Functions to run when Erlang mode is activated.
+
+This hook is used to change the behaviour of Erlang mode. It is
+normally used by the user to personalise the programming environment.
+When used in a site init file, it could be used to customise Erlang
+mode for all users on the system.
+
+The functions added to this hook is runed every time Erlang mode is
+started. See also `erlang-load-hook', a hook which is runed once,
+when Erlang mode is loaded into Emacs, and `erlang-shell-mode-hook'
+which is run every time a new inferior Erlang shell is started.
+
+To use a hook, create an Emacs lisp function to perform your actions
+and add the function to the hook by calling `add-hook'.
+
+The following example binds the key sequence C-c C-c to the command
+`erlang-compile' (normally bound to C-c C-k). The example also
+activates Font Lock mode to fontify the buffer and adds a menu
+containing all functions defined in the current buffer.
+
+To use the example, copy the following lines to your `~/.emacs' file:
+
+ (add-hook 'erlang-mode-hook 'my-erlang-mode-hook)
+
+ (defun my-erlang-mode-hook ()
+ (local-set-key \"\\C-c\\C-c\" 'erlang-compile)
+ (if window-system
+ (progn
+ (setq font-lock-maximum-decoration t)
+ (font-lock-mode 1)))
+ (if (and window-system (fboundp 'imenu-add-to-menubar))
+ (imenu-add-to-menubar \"Imenu\")))")
+
+(defvar erlang-load-hook nil
+ "*Functions to run when Erlang mode is loaded.
+
+This hook is used to change the behaviour of Erlang mode. It is
+normally used by the user to personalise the programming environment.
+When used in a site init file, it could be used to customize Erlang
+mode for all users on the system.
+
+The difference between this hook and `erlang-mode-hook' and
+`erlang-shell-mode-hook' is that the functions in this hook
+is only called once, when the Erlang mode is loaded into Emacs
+the first time.
+
+Natural actions for the functions added to this hook are actions which
+only should be performed once, and actions which should be performed
+before starting Erlang mode. For example, a number of variables are
+used by Erlang mode before `erlang-mode-hook' is runed.
+
+The following example sets the variable `erlang-root-dir' so that the
+manual pages can be retrieved (note that you must set the value of
+`erlang-root-dir' to match the loation of Erlang on your system):
+
+ (add-hook 'erlang-load-hook 'my-erlang-load-hook)
+
+ (defun my-erlang-load-hook ()
+ (setq erlang-root-dir \"/usr/local/erlang\"))")
+
+(defvar erlang-new-file-hook nil
+ "Functions to run when a new Erlang source file is being edited.
+
+A useful function is `tempo-template-erlang-normal-header'.
+\(This function only exists when the `tempo' packags is available.)")
+
+(defvar erlang-check-module-name 'ask
+ "*Non-nil means check that module name and file name agrees when saving.
+
+If the value of this variable is the atom `ask', the user is
+prompted. If the value is t the source is silently changed.")
+
+(defvar erlang-electric-commands
+ '(erlang-electric-comma
+ erlang-electric-semicolon
+ erlang-electric-gt)
+ "*List of activated electric commands.
+
+The list should contain the electric commands which should be active.
+Currently, the available electric commands are:
+ erlang-electric-comma
+ erlang-electric-semicolon
+ erlang-electric-gt
+ erlang-electric-newline
+
+Should the variable be bound to t, all electric commands
+are activated.
+
+To deactivate all electric commands, set this variable to nil.")
+
+(defvar erlang-electric-newline-inhibit t
+ "*Set to non-nil to inhibit newline after electric command.
+
+This is useful since a lot of people press return after executing an
+electric command.
+
+In order to work, the command must also be in the
+list `erlang-electric-newline-inhibit-list'.
+
+Note that commands in this list are required to set the variable
+`erlang-electric-newline-inhibit' to nil when the newline shouldn't be
+inhibited.")
+
+(defvar erlang-electric-newline-inhibit-list
+ '(erlang-electric-semicolon
+ erlang-electric-comma
+ erlang-electric-gt)
+ "*Command which can inhibit the next newline.")
+
+(defvar erlang-electric-semicolon-insert-blank-lines nil
+ "*Number of blank lines inserted before header, or nil.
+
+This variable controls the behaviour of `erlang-electric-semicolon'
+when a new function header is generated. When nil, no blank line is
+inserted between the current line and the new header. When bound to a
+number it represents the number of blank lines which should be
+inserted.")
+
+(defvar erlang-electric-semicolon-criteria
+ '(erlang-next-lines-empty-p
+ erlang-at-keyword-end-p
+ erlang-at-end-of-function-p)
+ "*List of functions controlling `erlang-electric-semicolon'.
+The functions in this list are called, in order, whenever a semicolon
+is typed. Each function in the list is called with no arguments,
+and should return one of the following values:
+
+ nil -- no determination made, continue checking
+ 'stop -- do not create prototype for next line
+ (anything else) -- insert prototype, and stop checking
+
+If every function in the list is called with no determination made,
+then no prototype is inserted.
+
+The test is performed by the function `erlang-test-criteria-list'.")
+
+(defvar erlang-electric-comma-criteria
+ '(erlang-stop-when-inside-argument-list
+ erlang-stop-when-at-guard
+ erlang-next-lines-empty-p
+ erlang-at-keyword-end-p
+ erlang-at-end-of-function-p)
+ "*List of functions controlling `erlang-electric-comma'.
+The functions in this list are called, in order, whenever a comma
+is typed. Each function in the list is called with no arguments,
+and should return one of the following values:
+
+ nil -- no determination made, continue checking
+ 'stop -- do not create prototype for next line
+ (anything else) -- insert prototype, and stop checking
+
+If every function in the list is called with no determination made,
+then no prototype is inserted.
+
+The test is performed by the function `erlang-test-criteria-list'.")
+
+(defvar erlang-electric-arrow-criteria
+ '(erlang-next-lines-empty-p
+ erlang-at-end-of-function-p)
+ "*List of functions controlling the arrow aspect of `erlang-electric-gt'.
+The functions in this list are called, in order, whenever a `>'
+is typed. Each function in the list is called with no arguments,
+and should return one of the following values:
+
+ nil -- no determination made, continue checking
+ 'stop -- do not create prototype for next line
+ (anything else) -- insert prototype, and stop checking
+
+If every function in the list is called with no determination made,
+then no prototype is inserted.
+
+The test is performed by the function `erlang-test-criteria-list'.")
+
+(defvar erlang-electric-newline-criteria
+ '(t)
+ "*List of functions controlling `erlang-electric-newline'.
+
+The electric newline commands indents the next line. Should the
+current line begin with a comment the comment start is copied to
+the newly created line.
+
+The functions in this list are called, in order, whenever a comma
+is typed. Each function in the list is called with no arguments,
+and should return one of the following values:
+
+ nil -- no determination made, continue checking
+ 'stop -- do not create prototype for next line
+ (anything else) -- trigger the electric command.
+
+If every function in the list is called with no determination made,
+then no prototype is inserted. Should the atom t be a member of the
+list, it is treated as a function triggering the electric command.
+
+The test is performed by the function `erlang-test-criteria-list'.")
+
+(defvar erlang-next-lines-empty-threshold 2
+ "*Number of blank lines required to activate an electric command.
+
+Actually, this value controls the behaviour of the function
+`erlang-next-lines-empty-p' which normally is a member of the
+criteria lists controlling the electric commands. (Please see
+the variables `erlang-electric-semicolon-criteria' and
+`erlang-electric-comma-criteria'.)
+
+The variable is bound to a threshold value, a number, representing the
+number of lines which must be empty.
+
+Setting this variable to zero, electric commands will always be
+triggered by `erlang-next-lines-empty-p', unless inhibited by other
+rules.
+
+Should this variable be `nil', `erlang-next-lines-empty-p' will never
+trigger an electric command. The same effect would be reached if the
+function `erlang-next-lines-empty-p' would be removed from the criteria
+lists.
+
+Note that even if `erlang-next-lines-empty-p' should not trigger an
+electric command, other functions in the criteria list could.")
+
+(defvar erlang-new-clause-with-arguments nil
+ "*Non-nil means that the arguments are cloned when a clause is generated.
+
+A new function header can be generated by calls to the function
+`erlang-generate-new-clause' and by use of the electric semicolon.")
+
+(defvar erlang-compile-use-outdir t
+ "*When nil, go to the directory containing source file when compiling.
+
+This is a workaround for a bug in the `outdir' option of compile. If the
+outdir is not in the current load path, Erlang doesn't load the object
+module after it has been compiled.
+
+To activate the workaround, place the following in your `~/.emacs' file:
+ (setq erlang-compile-use-outdir nil)")
+
+(defvar erlang-indent-level 4
+ "*Indentation of Erlang calls/clauses within blocks.")
+
+(defvar erlang-indent-guard 2
+ "*Indentation of Erlang guards.")
+
+(defvar erlang-argument-indent 2
+ "*Indentation of the first argument in a function call.
+When nil, indent to the column after the `(' of the
+function.")
+
+(defvar erlang-tab-always-indent t
+ "*Non-nil means TAB in Erlang mode should always reindent the current line,
+regardless of where in the line point is when the TAB command is used.")
+
+(defvar erlang-error-regexp-alist
+ '(("^\\([^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)[:) \t]" . (1 2)))
+ "*Patterns for matching Erlang errors.")
+
+(defvar erlang-man-inhibit (eq system-type 'windows-nt)
+ "Inhibit the creation of the Erlang Manual Pages menu.
+
+The Windows distribution of Erlang does not include man pages, hence
+there is no idea to create the menu.")
+
+(defvar erlang-man-dirs
+ '(("Man - Commands" "/man/man1" t)
+ ("Man - Modules" "/man/man3" t)
+ ("Man - Unsupported" "/uc/man/man3" t))
+ "*The man directories displayed in the Erlang menu.
+
+Each item in the list should be a list with three elements, the first
+the name of the menu, the second the directory, and the last a flag.
+Should the flag the nil, the directory is absolute, should it be non-nil
+the directory is relative to the variable `erlang-root-dir'.")
+
+(defvar erlang-man-max-menu-size 20
+ "*The maximum number of menu items in one menu allowed.")
+
+(defvar erlang-man-display-function 'erlang-man-display
+ "*Function used to display man page.
+
+The function is called with one argument, the name of the file
+containing the man page. Use this variable when the default
+function, erlang-man-display, does not work on your system.")
+
+(defconst erlang-atom-regexp "\\([a-z][a-zA-Z0-9_]*\\|'[^\n']*[^\\]'\\)"
+ "Regexp which should match an Erlang atom.
+
+The regexp must be surrounded with a pair of regexp parentheses.")
+(defconst erlang-atom-regexp-matches 1
+ "Number of regexp parenthesis pairs in `erlang-atom-regexp'.
+
+This is used to determine parenthesis matches in complex regexps which
+contains `erlang-atom-regexp'.")
+
+(defconst erlang-variable-regexp "\\([A-Z_][a-zA-Z0-9_]*\\)"
+ "Regexp which should match an Erlang variable.
+
+The regexp must be surrounded with a pair of regexp parenthesis.")
+(defconst erlang-variable-regexp-matches 1
+ "Number of regexp parenthesis pairs in `erlang-variable-regexp'.
+
+This is used to determine matches in complex rexeps which contains
+`erlang-variable-regexp'.")
+
+(defvar erlang-defun-prompt-regexp (concat "^" erlang-atom-regexp "\\s *(")
+ "*Regexp which should match beginning of a clause.")
+
+(defvar erlang-file-name-extension-regexp "\\.[eh]rl$"
+ "*Regexp which should match an erlang file name.
+
+This regexp is used when an Erlang module name is extracted from the
+name of an Erlang source file.
+
+The regexp should only match the section of the file name which should
+be excluded from the module name.
+
+To match all files set this variable to \"\\\\(\\\\..*\\\\|\\\\)$\".
+The matches all except the extension. This is useful if the Erlang
+tags system should interpretate tags on the form `module:tag' for
+files written in other languages than Erlang.")
+
+(defvar erlang-mode-map nil
+ "*Keymap used in Erlang mode.")
+(defvar erlang-mode-abbrev-table nil
+ "Abbrev table in use in Erlang-mode buffers.")
+(defvar erlang-mode-syntax-table nil
+ "Syntax table in use in Erlang-mode buffers.")
+
+(defconst erlang-emacs-major-version
+ (if (boundp 'emacs-major-version)
+ emacs-major-version
+ (string-match "\\([0-9]+\\)\\.\\([0-9]+\\)" emacs-version)
+ (string-to-int (substring emacs-version
+ (match-beginning 1) (match-end 1))))
+ "Major version number of Emacs.")
+
+(defconst erlang-emacs-minor-version
+ (if (boundp 'emacs-minor-version)
+ emacs-minor-version
+ (string-match "\\([0-9]+\\)\\.\\([0-9]+\\)" emacs-version)
+ (string-to-int (substring emacs-version
+ (match-beginning 2) (match-end 2))))
+ "Minor version number of Emacs.")
+
+(defconst erlang-xemacs-p (string-match "Lucid\\|XEmacs" emacs-version)
+ "Non-nil when running under XEmacs or Lucid Emacs.")
+
+(defvar erlang-xemacs-popup-menu '("Erlang Mode Commands" . nil)
+ "Common popup menu for all buffers in Erlang mode.
+
+This variable is destructively modified every time the Erlang menu
+is modified. The effect is that all changes take effekt in all
+buffers in Erlang mode, just like under GNU Emacs.
+
+Never EVER set this variable!")
+
+
+;; Tempo skeleton templates:
+
+(defvar erlang-skel
+ '(("If" "if" erlang-skel-if)
+ ("Case" "case" erlang-skel-case)
+ ("Receive" "receive" erlang-skel-receive)
+ ("Receive After" "after" erlang-skel-receive-after)
+ ("Receive Loop" "loop" erlang-skel-receive-loop)
+ ("Module" "module" erlang-skel-module)
+ ("Author" "author" erlang-skel-author)
+ ()
+ ("Small Header" "small-header"
+ erlang-skel-small-header erlang-skel-header)
+ ("Normal Header" "normal-header"
+ erlang-skel-normal-header erlang-skel-header)
+ ("Large Header" "large-header"
+ erlang-skel-large-header erlang-skel-header)
+ ()
+ ("Small Server" "small-server"
+ erlang-skel-small-server erlang-skel-header)
+ ()
+ ("Application" "application"
+ erlang-skel-application erlang-skel-header)
+ ("General Tcp Receive" "fs_gen_tcp_recv"
+ erlang-skel-fs-gen-tcp-recv erlang-skel-header)
+ ("Test Suite" "test-suite"
+ erlang-skel-test-suite erlang-skel-header)
+ ("Tcp Gateway" "fs_tcp_gateway"
+ erlang-skel-fs-tcp-gateway erlang-skel-header)
+ ("Edoc function" "fs_edoc_header"
+ erlang-skel-fs-edoc-header erlang-skel-header)
+ ("DB Initialize" "fs_db_init"
+ erlang-skel-fs-db-init erlang-skel-header)
+ ("gen_leader" "generic-leader"
+ erlang-skel-generic-leader erlang-skel-header)
+ ("Supervisor" "supervisor"
+ erlang-skel-supervisor erlang-skel-header)
+ ("supervisor_bridge" "supervisor-bridge"
+ erlang-skel-supervisor-bridge erlang-skel-header)
+ ("gen_server" "generic-server"
+ erlang-skel-generic-server erlang-skel-header)
+ ("gen_event" "gen-event"
+ erlang-skel-gen-event erlang-skel-header)
+ ("gen_fsm" "gen-fsm"
+ erlang-skel-gen-fsm erlang-skel-header)
+ ("Library module" "gen-lib"
+ erlang-skel-lib erlang-skel-header)
+ ("Corba callback" "gen-corba-cb"
+ erlang-skel-corba-callback erlang-skel-header))
+ "*Description of all skeletons templates.
+Both functions and menu entries will be created.
+
+Each entry in `erlang-skel' should be a list with three or four
+elements, or the empty list.
+
+The first element is the name which shows up in the menu. The second
+is the `tempo' identfier (The string \"erlang-\" will be added in
+front of it). The third is the skeleton descriptor, a variable
+containing `tempo' attributes as described in the function
+`tempo-define-template'. The optional fourth elements denotes a
+function which should be called when the menu is selected.
+
+Functions corresponding to every template will be created. The name
+of the function will be `tempo-template-erlang-X' where `X' is the
+tempo identifier as specified in the second argument of the elements
+in this list.
+
+A list with zero elements means that the a horisontal line should
+be placed in the menu.")
+
+;; In XEmacs `user-mail-address' returns "x@y.z (Foo Bar)" ARGH!
+;; What's wrong with that? RFC 822 says it's legal. [sverkerw]
+(defvar erlang-skel-mail-address
+ (concat (user-login-name) "@"
+ (or (and (boundp 'mail-host-address)
+ (symbol-value 'mail-host-address))
+ (system-name)))
+ "Mail address of the user.")
+
+;; Expression templates:
+(defvar erlang-skel-case
+ '((erlang-skel-skip-blank) o >
+ "case " p " of" n> p "_ ->" n> p "ok" n> "end" p)
+ "*The skeleton of a `case' expression.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-if
+ '((erlang-skel-skip-blank) o >
+ "if" n> p " ->" n> p "ok" n> "end" p)
+ "The skeleton of an `if' expression.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-receive
+ '((erlang-skel-skip-blank) o >
+ "receive" n> p "_ ->" n> p "ok" n> "end" p)
+ "*The skeleton of a `receive' expression.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-receive-after
+ '((erlang-skel-skip-blank) o >
+ "receive" n> p "_ ->" n> p "ok" n> "after " p "T ->" n>
+ p "ok" n> "end" p)
+ "*The skeleton of a `receive' expression with an `after' clause.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-receive-loop
+ '(& o "loop(" p ") ->" n> "receive" n> p "_ ->" n>
+ "loop(" p ")" n> "end.")
+ "*The skeleton of a simple `recieve' loop.
+Please see the function `tempo-define-template'.")
+
+
+;; Attribute templates
+
+(defvar erlang-skel-module
+ '(& "-module("
+ (erlang-add-quotes-if-needed (erlang-get-module-from-file-name))
+ ")." n)
+ "*The skeleton of a `module' attribute.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-author
+ '(& "-author('" erlang-skel-mail-address "')." n)
+ "*The skeleton of a `author' attribute.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-vc nil
+ "*The skeleton template to generate a version control attribute.
+The default is to insert nothing. Example of usage:
+
+ (setq erlang-skel-vc '(& \"-rcs(\\\"$\Id: $ \\\").\") n)
+
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-export
+ '(& "-export([" n> "])." n)
+ "*The skeleton of an `export' attribute.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-import
+ '(& "%%-import(Module, [Function/Arity, ...])." n)
+ "*The skeleton of an `import' attribute.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-compile nil
+;; '(& "%%-compile(export_all)." n)
+ "*The skeleton of a `compile' attribute.
+Please see the function `tempo-define-template'.")
+
+
+;; Comment templates.
+
+(defvar erlang-skel-date-function 'erlang-skel-dd-mmm-yyyy
+ "*Function which returns date string.
+Look in the module `time-stamp' for a battery of functions.")
+
+(defvar erlang-skel-copyright-comment '()
+ "*The template for a copyright line in the header, normally empty.
+This variable should be bound to a `tempo' template, for example:
+ '(& \"%%% Copyright (C) 2000, Yoyodyne, Inc.\" n)
+
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-created-comment
+ '(& "%%% Created : " (funcall erlang-skel-date-function) " by "
+ (user-full-name) " <" erlang-skel-mail-address ">" n)
+ "*The template for the \"Created:\" comment line.")
+
+(defvar erlang-skel-author-comment
+ '(& "%%% Author : " (user-full-name) " <" erlang-skel-mail-address ">" n)
+ "*The template for creating the \"Author:\" line in the header.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-file-comment
+ '(& "%%% File : " (file-name-nondirectory buffer-file-name) n)
+ "*The template for creating the \"Module:\" line in the header.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-small-header
+ '(o (erlang-skel-include erlang-skel-module)
+;; erlang-skel-author)
+ n
+ (erlang-skel-include erlang-skel-compile
+;; erlang-skel-export
+ erlang-skel-vc))
+ "*The template of a small header without any comments.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-normal-header
+ '(o (erlang-skel-include erlang-skel-copyright-comment
+ erlang-skel-file-comment
+ erlang-skel-author-comment)
+ "%%% Description : " p n
+ (erlang-skel-include erlang-skel-created-comment) n
+ (erlang-skel-include erlang-skel-small-header) n)
+ "*The template of a normal header.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-large-header
+ '(o "%%% $Id: erlang.el,v 1.21 2004/08/03 20:38:43 mlogan Exp $" n (erlang-skel-separator)
+ (erlang-skel-include erlang-skel-copyright-comment
+ erlang-skel-file-comment
+ erlang-skel-author-comment)
+ "%%%" n
+ "%%% @doc " p n
+ "%%% @end" n
+ "%%%" n
+ (erlang-skel-include erlang-skel-created-comment)
+ (erlang-skel-separator)
+ (erlang-skel-include erlang-skel-small-header) )
+ "*The template of a large header.
+Please see the function `tempo-define-template'.")
+
+
+;; Server templates.
+
+(defvar erlang-skel-small-server
+ '((erlang-skel-include erlang-skel-large-header)
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2) n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([start_link/0])." n n
+ (erlang-skel-separator 2)
+ "%% Internal exports" n
+ (erlang-skel-separator 2)
+ "-export([init/1])." n n
+ n
+ (erlang-skel-separator 2)
+ "%% Macros" n
+ (erlang-skel-separator 2)
+ "-define(SERVER, ?MODULE)." n
+ n
+ (erlang-skel-separator 2)
+ "%% Records" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% @doc The starting point." n
+ "%% @spec start_link() -> {ok, Pid}" n
+ "%% @end" n
+ (erlang-skel-separator 2)
+ "start_link() ->" n>
+ "proc_lib:start_link(?MODULE, init, [self()])." n n
+ (erlang-skel-double-separator 2)
+ "%% Server functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% Description: Initializes this server." n
+ "%% Variables:" n
+ "%% From - The pid of the parent process." n
+ (erlang-skel-separator 2)
+ "init(From) ->" n>
+ "register(?SERVER, self())," n>
+ "proc_lib:init_ack(From, {ok, self()})," n>
+ "loop(From)." n n
+ (erlang-skel-double-separator 2)
+ "%% Internal functions" n
+ (erlang-skel-double-separator 2)
+ "loop(From) ->" n>
+ "receive" n>
+ p "_ ->" n>
+ "loop(From)" n>
+ "end."
+ )
+ "*Template of a small server.
+Please see the function `tempo-define-template'.")
+
+;; Behaviour templates.
+
+(defvar erlang-skel-application
+ '((erlang-skel-include erlang-skel-large-header)
+ "-behaviour(application)." n
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([" n>
+ "start/2," n>
+ "shutdown/0," n>
+ "stop/1" n>
+ "])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Macros" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% Records" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% @doc The starting point for an erlang application." n
+ "%% @spec start(Type, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}" n
+ "%% @end" n
+ (erlang-skel-separator 2)
+ "start(Type, StartArgs) ->" n>
+ "case "(erlang-get-module-from-file-name)"_sup:start_link(StartArgs) of" n>
+ "{ok, Pid} -> " n>
+ "{ok, Pid};" n>
+ "Error ->" n>
+ "Error" n>
+ "end." n
+ n
+ (erlang-skel-separator 2)
+ "%% @doc Called to shudown the "(erlang-get-module-from-file-name)" application." n
+ "%% @spec shutdown() -> ok "n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "shutdown() ->" n>
+ "application:stop("(erlang-get-module-from-file-name)")." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Internal functions" n
+ (erlang-skel-double-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% Called upon the termintion of an application." n
+ (erlang-skel-separator 2)
+ "stop(State) ->" n>
+ "ok." n
+ n
+ )
+ "*The template of an application behaviour.
+Please see the function `tempo-define-template'.")
+
+;; Martins work
+
+;; test server test suite template
+(defvar erlang-skel-test-suite
+ '((erlang-skel-include erlang-skel-copyright-comment
+ erlang-skel-file-comment
+ erlang-skel-author-comment)
+ "%%%" n
+ "%%% @doc " p n
+ "%%% <p>A test spec consists of the test server required functions as detailed" n
+ "%%% by the comments for the functions themselves further down in this" n
+ "%%% file. The rest of a test suite consists of user defined Case functions" n
+ "%%% as referenced by the suite clause of the all/1 function and "n
+ "%%% described below.</p>"n
+ "%%%"n
+ "%%% <strong>"
+ "%%% Case(doc) -> [Decription]" n
+ "%%% Case(suite) -> [] | TestSpec | {skip, Comment}" n
+ "%%% Case(Config) -> {skip, Comment} | {comment, Comment} | Ok" n
+ "%%% </strong><pre>"n
+ "%%%"n
+ "%%% Variables:" n
+ "%%% Description - Short description of the test case TestSpec" n
+ "%%% Comment - This comment will be printed on the HTML result page " n
+ "%%%"n
+ "%%% Types:" n
+ "%%% Description = string()" n
+ "%%% TestSpec = list()" n
+ "%%% Ok = term()" n
+ "%%% Comment = string()" n
+ "%%% Config = term()" n
+ "%%% </pre>" n
+ "%%% <p>The documentation clause (argument doc) can be used for" n
+ "%%% automatic generation of test documentation or test descriptions.</p>" n
+ "%%%"n
+ "%%% <p>The specification clause (argument spec) shall return an empty" n
+ "%%% list, the test specification for the test case or {skip,Comment}." n
+ "%%% The syntax of a test specification is described in the reference " n
+ "%%% manual for the Test Server application.</p>" n
+ "%%%"n
+ "%%% <p>Note that the specification clause always is executed on "n
+ "%%% the controller host.</p>"n
+ "%%%"n
+ "%%% <p>The execution clause (argument Config) is only called if "n
+ "%%% the specification clause returns an empty list. The execution "n
+ "%%% clause is the real test case. Here you must call the functions "n
+ "%%% you want to test, and do whatever you need to check the result. "n
+ "%%% If someting fails, make sure the process crashes or call "n
+ "%%% test_server:fail/0/1 (which also will cause the process to crash).</p>"n
+ "%%%"n
+ "%%% <p>You can return {skip,Comment} if you decide not to run the "n
+ "%%% test case after all, e.g. if it is not applicable on this platform.</p>"n
+ "%%%"n
+ "%%% <p>You can return {comment,Comment} if you wish to print some "n
+ "%%% information in the 'Comment' field on the HTML result page.</p>"n
+ "%%%"n
+ "%%% <p>If the execution clause returns anything else, it is considered "n
+ "%%% a success. </p>"n
+ "%%% @end" n
+ "%%%" n
+ (erlang-skel-include erlang-skel-created-comment)
+ (erlang-skel-separator)
+ (erlang-skel-include erlang-skel-small-header)
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% Macro Definitions" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% Test Suite Exports" n
+ (erlang-skel-separator 2)
+ "-export(["n>"all/1,"n>"init_per_testcase/2,"n>"fin_per_testcase/2"n>"])." n
+ n
+ (erlang-skel-separator 2)
+ "%% External Exports - test cases must be exported." n
+ (erlang-skel-separator 2)
+ "-export(["n>"])."n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Test Server Functions" n
+ (erlang-skel-double-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% @doc This function returns the test specification for the test suite module."n
+ "%% <pre>"n
+ "%% Types:"n
+ "%% TestSpec = list()"n
+ "%% Comment = string()"n
+ "%%"n
+ "%% </pre>"n
+ "%% @spec all(suite) -> TestSpec | {skip, Comment}"n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "all(doc) -> [];"n
+ "all(suite) -> []."n n
+ n
+ (erlang-skel-separator 2)
+ "%% @doc This function is called before each test case."n
+ "%% <pre>"n
+ "%% Types:"n
+ "%% Case = atom()"n
+ "%% Config = NewConfig = term()"n
+ "%%"n
+ "%% </pre>"n
+ "%% @spec init_per_testcase(Case, Config) -> NewConfig"n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "init_per_testcase(Case, Config) -> []."n n
+ n
+ (erlang-skel-separator 2)
+ "%% @doc This function is called after each test case."n
+ "%% <pre>"n
+ "%% Types:"n
+ "%% Case = atom()"n
+ "%% Config = term()"n
+ "%%"n
+ "%% </pre>"n
+ "%% @spec fin_per_testcase(Case, Config) -> void()"n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "fin_per_testcase(Case, Config) -> ok."n n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Individual Test Case Functions" n
+ (erlang-skel-double-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% @doc ." n
+ "%% @end" n
+ (erlang-skel-separator 2)
+ "Case(doc) -> [];"n
+ "Case(suite) -> [];"n
+ "Case(Config) when list(Config) -> ok."n n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Internal Functions" n
+ (erlang-skel-double-separator 2)
+ )
+ "*The template of an application behaviour.
+Please see the function `tempo-define-template'.")
+
+
+;; fs_tcp_gateway template
+(defvar erlang-skel-fs-tcp-gateway
+ '((erlang-skel-include erlang-skel-large-header)
+ "%% TODO Implement this behaviour" n
+ "%% -behaviour(tcp_gateway)." n
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([" n> "start_link/1, init/0, sync_request/5, async_request/5, terminate/2" n
+ " ])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Macros" n
+ (erlang-skel-separator 2)
+ "-define(SERVER, ?MODULE)." n
+ n
+ (erlang-skel-separator 2)
+ "%% Records" n
+ (erlang-skel-separator 2)
+ "-record(state, {})."n
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% @doc Starts the gateway server."n
+ "%% <pre>"n
+ "%%"n
+ "%% Expects:"n
+ "%% Port - The port number to bind to."n
+ "%%"n
+ "%% Types:"n
+ "%% Port = integer()"n
+ "%%"n
+ "%% </pre>"n
+ "%%"n
+ "%% @spec start_link(Port) -> {ok, pid()}"n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "start_link(Port) ->" n>
+ "CallBackModule = ?MODULE,"n>
+ " fs_tcp_gateway:start_link(CallBackModule, Port)."n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Callbacks" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% @doc Initialization stage for each new connection to the gateway server."n
+ "%% <pre>"n
+ "%%"n
+ "%% Types:"n
+ "%% State = term()"n
+ "%%"n
+ "%% </pre>"n
+ "%%"n
+ "%% @spec init() -> {ok, State}"n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "init() ->"n>
+ "{ok, #state{}}."n
+ n
+ (erlang-skel-separator 2)
+ "%% @doc Called when the server receives a syncronous request from a client."n
+ "%% <pre>"n
+ "%%"n
+ "%% Expects:"n
+ "%% ID - The request ID number"n
+ "%% M - module name"n
+ "%% F - function name"n
+ "%% A - List of arguments"n
+ "%% Reply - A message sent back over the tcp stream to the client"n
+ "%%"n
+ "%% Types:"n
+ "%% ID = M = F = Reply = string()"n
+ "%% A = [string()]"n
+ "%% State = term()"n
+ "%% Reply = string()"n
+ "%%"n
+ "%% </pre>"n
+ "%%"n
+ "%% @spec sync_request(ID, M, F, A, State) ->"n
+ "%% {reply, Reply, State} | {stop, Reply, Reason, State} | {noreply, State}"n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "sync_request(ID, M, F, A, State) ->"n>
+ "{reply, \"sync ok\", State}."n
+ n
+ (erlang-skel-separator 2)
+ "%% @doc Called when the server receives a asyncronous request from a client."n
+ "%% <pre>"n
+ "%%"n
+ "%% Expects:"n
+ "%% ID - The request ID number"n
+ "%% M - module name"n
+ "%% F - function name"n
+ "%% A - List of arguments"n
+ "%% Reply - A message sent back over the tcp stream to the client"n
+ "%%"n
+ "%% Types:"n
+ "%% ID = M = F = string()"n
+ "%% A = [string()]"n
+ "%% State = term()"n
+ "%% Reply = string()"n
+ "%%"n
+ "%% </pre>"n
+ "%%"n
+ "%% @spec async_request(ID, M, F, A, State) ->"n
+ "%% {stop, Reason, State} | {noreply, State}"n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "async_request(ID, M, F, A, State) ->"n>
+ "{noreply, State}."n
+ n
+ (erlang-skel-separator 2)
+ "%% @doc Called upon the shutdown of a connection."n
+ "%% @spec terminate(Reason, State) -> void()"n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "terminate(Reason, State) ->"n>
+ "ok."n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Internal functions" n
+ (erlang-skel-double-separator 2)
+ )
+ "*The template of a fs_tcp_gateway behaviour.
+Please see the function `tempo-define-template'.")
+
+
+;; gen_tcp_recv template
+(defvar erlang-skel-fs-gen-tcp-recv
+ '((erlang-skel-include erlang-skel-large-header)
+ "%% TODO Implement this behaviour" n
+ "%% -behaviour(gen_tcp_recv)." n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([" n> "start_link/0" n> "])." n n
+ (erlang-skel-separator 2)
+ "%% Server Callbacks" n
+ (erlang-skel-separator 2)
+ "-export([" n> "init/1," n> "handle_packet/3," n> "handle_call/4" n>
+ "handle_info/3" n> "terminate/2" n> "])." n n
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% API - External Exports" n
+ (erlang-skel-separator 2)
+ "-export([" n>
+ "start_link/1" n>
+ "])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Macros" n
+ (erlang-skel-separator 2)
+ "-define(SERVER, ?MODULE)." n
+ n
+ (erlang-skel-separator 2)
+ "%% Records" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2) n
+ (erlang-skel-separator 2)
+ "%% @doc Starts the fs_gen_tcp_recv server." n
+ "%% @spec start_link() -> {ok, Pid}" n
+ "%% @end" n
+ (erlang-skel-separator 2)
+ "start_link() ->" n>
+ "fs_gen_tcp_recv:start_link(CallbackModule, ?TCP_PORT, [], [], [])." n n n
+ (erlang-skel-double-separator 2)
+ "%% Server Functions" n
+ (erlang-skel-double-separator 2) n
+ (erlang-skel-separator 2)
+ "%% Initializes the state for a gen_tcp_recv server." n
+ "%% Returns: {ok, State}" n
+ "%% State = term()" n
+ (erlang-skel-separator 2)
+ "init([]) ->" n>
+ "{ok, []}." n n n
+ (erlang-skel-separator 2)
+ "%% Receives packets from the socket. Also receives timout messages." n
+ "%% Types:" n
+ "%% Socket = socket()" n
+ "%% Packet = binary() | string(). Can be altered in TCPOptions" n
+ "%% Reply = binary() | string(). Can be altered in TCPOptions" n
+ "%% State = NewState = term()" n
+ "%% Timeout = integer() in miliseconds." n
+ "%% Returns: " n
+ "%% {noreply, NewState} {noreply, NewState, Timeout}" n
+ "%% {reply, Reply, NewState} {reply, Reply, NewState, Timeout}" n
+ "%% {stop, Reason, NewState}" n
+ (erlang-skel-separator 2)
+ "handle_packet(Socket, Packet, State) ->" n>
+ "{noreply, State}." n n n
+ (erlang-skel-separator 2)
+ "%% Receives sync calls from a client." n
+ "%% Variables:" n
+ "%% Reply - A message sent back to the caller." n
+ "%% " n
+ "%% Types:" n
+ "%% Socket = socket()" n
+ "%% Msg = Reply = term()" n
+ "%% State = NewState = term()" n
+ "%% Timeout = integer() in miliseconds." n
+ "%% Returns: " n
+ "%% {noreply, NewState} {noreply, NewState, Timeout}" n
+ "%% {reply, Reply, NewState} {reply, Reply, NewState, Timeout}" n
+ "%% {stop, Reason, NewState} | {stop, Reason, Reply, NewState}" n
+ (erlang-skel-separator 2)
+ "handle_call(Socket, From, Msg, State) ->" n>
+ "{reply, Reply, State}." n n n
+ (erlang-skel-separator 2)
+ "%% Receives messages from other processes and timeouts." n
+ "%% Types:" n
+ "%% Socket = socket()" n
+ "%% Msg = term() | timeout" n
+ "%% State = NewState = term()" n
+ "%% Timeout = integer() in miliseconds." n
+ "%% Returns: " n
+ "%% {noreply, NewState} {noreply, NewState, Timeout}" n
+ "%% {stop, Reason, NewState}" n
+ (erlang-skel-separator 2)
+ "handle_info(Socket, Msg, State) ->" n>
+ "{noreply, State}." n n n
+ (erlang-skel-separator 2)
+ "%% Called after a socket closes or {stop, Reason, NewState}" n
+ "%% Types:" n
+ "%% Socket = socket()" n
+ "%% State = NewState = term()" n
+ "%% Returns: term()" n
+ (erlang-skel-separator 2)
+ "terminate(Socket, State) ->" n>
+ "ok." n n n
+ (erlang-skel-double-separator 2)
+ "%%% Internal Functions" n
+ (erlang-skel-double-separator 2)
+ )
+ "*The template of a fs_gen_tcp_recv behaviour.
+Please see the function `tempo-define-template'.")
+
+;; fs_edoc_header template
+(defvar erlang-skel-fs-edoc-header
+ '((erlang-skel-separator 2)
+ "%% @doc" n
+ "%% <pre>" n
+ "%% Variables:" n
+ "%% Types:" n
+ "%% </pre> term()" n
+ "%% @spec" n
+ "%% @end" n
+ (erlang-skel-separator 2)
+ )
+ "*The template of an edoc function header.
+Please see the function `tempo-define-template'.")
+
+;; fs_db_init template
+(defvar erlang-skel-fs-db-init
+ '((erlang-skel-include erlang-skel-large-header)
+ "%% TODO Implement this behaviour" n
+ "%% -behaviour(db_init)." n
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([" n> "start_link/1, start_link/3, init/1, local_init/0, remote_init/0" n
+ " ])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Macros" n
+ (erlang-skel-separator 2)
+ "-define(SERVER, ?MODULE)." n
+ n
+ (erlang-skel-separator 2)
+ "%% Records" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-separator 2)
+ "%% @doc Starts the server. " n>
+ "%% <pre>" n>
+ "%% Variables:" n>
+ "%% CallBackModule - The module that exhibits the db init behaviour." n>
+ "%% Args - A list of arguments delivered to the CallBackModule:init/1 function." n>
+ "%% Options - A list of options for fs_db_init." n>
+ "%%" n>
+ "%% The options are as follows:" n>
+ "%% {schema_type, Type}" n>
+ "%%" n>
+ "%% Types:" n>
+ "%% Args = list()" n>
+ "%% Options = list()" n>
+ "%% Type = ram_copies | disc_copies | disc_only_copies" n>
+ "%%" n>
+ "%% </pre>" n>
+ "%% @spec start_link(CallBackModule, Args, Options) -> {ok, pid()} | {error, Reason}" n>
+ "%% @end" n>
+ "(erlang-skel-separator 2)"
+ "start_link(CallBackModule, Args, Options) ->" n>
+ "proc_lib:start_link(?MODULE, db_init, [self(), CallBackModule, Args, Options])." n>
+ n
+ "%% @spec start_link(CallBackModule) -> {ok, pid()} | {error, Reason}" n>
+ "%% @equiv start_link(CallBackModule, [], [])" n>
+ "start_link(CallBackModule) ->" n>
+ "start_link(CallBackModule, [], [])." n>
+ n
+ (erlang-skel-double-separator 2)
+ "%% Callbacks" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% @doc" n
+ "%% Returns a list of nodes that db_init should try to replicate with." n
+ "%%" n
+ "%% <pre>" n
+ "%% Types:" n
+ "%% DBNodes = [node()]" n
+ "%% </pre>" n
+ "%%" n
+ "%% @spec init(Args) -> {ok, DBNodes} | no_init" n
+ "%% @end" n
+ (erlang-skel-separator 2)
+ "init(Args) ->" n
+ " {ok, DBNodesToReplicateFrom = []}." n
+ (erlang-skel-separator 2)
+ "%% @doc" n
+ "%% Created a schema and seeds the local database." n
+ "%% Returns a list of records with their initial data." n
+ "%% These are to be the tables and initial values for the database." n
+ "%%" n
+ "%% <pre>" n
+ "%% Reclist = [record()]" n
+ "%% Reason = atom()" n
+ "%% </pre>" n
+ "%%" n
+ "%% @spec local_init() -> {ok, RecList} | {error, Reason}" n
+ "%% @end" n
+ (erlang-skel-separator 2)
+ "local_init() ->" n
+ " {ok, []}." n
+ (erlang-skel-separator 2)
+ "%% @doc Pushes the schema and the table definitions to the node" n
+ "%% specified by the variable node." n
+ "%% NOTE: Do not include the schema in this list." n
+ "%%" n
+ "%% <pre>" n
+ "%% Types " n
+ "%% Node = node()" n
+ "%% TableList = [{Table, Type}]" n
+ "%% Table = atom()" n
+ "%% Type = ram_copies, disc_copies" n
+ "%% Reason = atom()" n
+ "%% </pre>" n
+ "%%" n
+ "%% @spec remote_init() -> {ok, TableList} | {error, Reason}" n
+ "%% @end" n
+ (erlang-skel-separator 2)
+ "remote_init() ->" n
+ " {ok, [{ini, ram_copies}]}." n
+ n
+ )
+ "*The template of a fs_db_init behaviour.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-supervisor
+ '((erlang-skel-include erlang-skel-large-header)
+ "-behaviour(supervisor)." n
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([" n> "start_link/1" n
+ " ])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Internal exports" n
+ (erlang-skel-separator 2)
+ "-export([" n> "init/1" n
+ " ])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Macros" n
+ (erlang-skel-separator 2)
+ "-define(SERVER, ?MODULE)." n
+ n
+ (erlang-skel-separator 2)
+ "%% Records" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% @doc Starts the supervisor." n
+ "%% @spec start_link(StartArgs) -> {ok, pid()} | Error" n
+ "%% @end" n
+ (erlang-skel-separator 2)
+ "start_link(StartArgs) ->" n>
+ "supervisor:start_link({local, ?SERVER}, ?MODULE, [])." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Server functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% Func: init/1" n
+ "%% Returns: {ok, {SupFlags, [ChildSpec]}} |" n
+ "%% ignore |" n
+ "%% {error, Reason} " n
+ (erlang-skel-separator 2)
+ "init([]) ->" n>
+ "RestartStrategy = one_for_one," n>
+ "MaxRestarts = 1000," n>
+ "MaxTimeBetRestarts = 3600," n>
+ n>
+ "SupFlags = {RestartStrategy, MaxRestarts, MaxTimeBetRestarts}," n>
+ n>
+ "ChildSpecs =" n>
+ "[" n>
+ "{AppName," n>
+ "{AppName, start_link, []}," n>
+ "permanent," n>
+ "1000," n>
+ "worker," n>
+ "[AppName]}" n>
+ "]," n>
+ "{ok,{SupFlags, ChildSpecs}}." n
+
+ (erlang-skel-double-separator 2)
+ "%% Internal functions" n
+ (erlang-skel-double-separator 2)
+ )
+ "*The template of an supervisor behaviour.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-supervisor-bridge
+ '((erlang-skel-include erlang-skel-large-header)
+ "-behaviour(supervisor_bridge)." n
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([" n> "start_link/0" n
+ " ])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Internal exports" n
+ (erlang-skel-separator 2)
+ "-export([" n> "init/1, " n> "terminate/2" n
+ " ])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Macros" n
+ (erlang-skel-separator 2)
+ "-define(SERVER, ?MODULE)." n
+ n
+ (erlang-skel-separator 2)
+ "%% Records" n
+ (erlang-skel-separator 2)
+ "-record(state, {})." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% Function: start_link/0" n
+ "%% Description: Starts the supervisor bridge" n
+ (erlang-skel-separator 2)
+ "start_link() ->" n>
+ "supervisor_bridge:start_link({local, ?SERVER}, ?MODULE, [])." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Server functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% Func: init/1" n
+ "%% Returns: {ok, Pid, State} |" n
+ "%% ignore |" n
+ "%% {error, Reason} " n
+ (erlang-skel-separator 2)
+ "init([]) ->" n>
+ "case 'AModule':start_link() of" n>
+ "{ok, Pid} ->" n>
+ "{ok, Pid, #state{}};" n>
+ "Error ->" n>
+ "Error" n>
+ "end." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: terminate/2" n
+ "%% Purpose: Synchronized shutdown of the underlying sub system." n
+ "%% Returns: any" n
+ (erlang-skel-separator 2)
+ "terminate(Reason, State) ->" n>
+ "'AModule':stop()," n>
+ "ok." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Internal functions" n
+ (erlang-skel-double-separator 2)
+ )
+ "*The template of an supervisor_bridge behaviour.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-generic-server
+ '((erlang-skel-include erlang-skel-large-header)
+ "-behaviour(gen_server)." n
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([" n>"start_link/0,"n>"stop/0"n>"])." n
+ n
+ (erlang-skel-separator 2)
+ "%% gen_server callbacks" n
+ (erlang-skel-separator 2)
+ "-export([init/1, handle_call/3, handle_cast/2, "
+ "handle_info/2, terminate/2, code_change/3])." n n
+ (erlang-skel-separator 2)
+ "%% record definitions" n
+ (erlang-skel-separator 2)
+ "-record(state, {})." n n
+ (erlang-skel-separator 2)
+ "%% macro definitions" n
+ (erlang-skel-separator 2)
+ "-define(SERVER, ?MODULE)." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% @doc Starts the server." n
+ "%% @spec start_link() -> {ok, pid()} | {error, Reason}" n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "start_link() ->" n>
+ "gen_server:start_link({local, ?SERVER}, ?MODULE, [], [])." n
+ n
+ (erlang-skel-separator 2)
+ "%% @doc Stops the server." n
+ "%% @spec stop() -> ok" n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "stop() ->" n>
+ "gen_server:cast(?SERVER, stop)." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Server functions" n
+ (erlang-skel-double-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% Function: init/1" n
+ "%% Description: Initiates the server" n
+ "%% Returns: {ok, State} |" n
+ "%% {ok, State, Timeout} |" n
+ "%% ignore |" n
+ "%% {stop, Reason}" n
+ (erlang-skel-separator 2)
+ "init([]) ->" n>
+ "{ok, #state{}}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Function: handle_call/3" n
+ "%% Description: Handling call messages" n
+ "%% Returns: {reply, Reply, State} |" n
+ "%% {reply, Reply, State, Timeout} |" n
+ "%% {noreply, State} |" n
+ "%% {noreply, State, Timeout} |" n
+ "%% {stop, Reason, Reply, State} | (terminate/2 is called)" n
+ "%% {stop, Reason, State} (terminate/2 is called)" n
+ (erlang-skel-separator 2)
+ "handle_call(Request, From, State) ->" n>
+ "Reply = ok," n>
+ "{reply, Reply, State}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Function: handle_cast/2" n
+ "%% Description: Handling cast messages" n
+ "%% Returns: {noreply, State} |" n
+ "%% {noreply, State, Timeout} |" n
+ "%% {stop, Reason, State} (terminate/2 is called)" n
+ (erlang-skel-separator 2)
+ "handle_cast(stop, State) ->" n>
+ "{stop, normal, State};" n
+ "handle_cast(Msg, State) ->" n>
+ "{noreply, State}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Function: handle_info/2" n
+ "%% Description: Handling all non call/cast messages" n
+ "%% Returns: {noreply, State} |" n
+ "%% {noreply, State, Timeout} |" n
+ "%% {stop, Reason, State} (terminate/2 is called)" n
+ (erlang-skel-separator 2)
+ "handle_info(Info, State) ->" n>
+ "{noreply, State}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Function: terminate/2" n
+ "%% Description: Shutdown the server" n
+ "%% Returns: any (ignored by gen_server)" n
+ (erlang-skel-separator 2)
+ "terminate(Reason, State) ->" n>
+ "ok." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: code_change/3" n
+ "%% Purpose: Convert process state when code is changed" n
+ "%% Returns: {ok, NewState}" n
+ (erlang-skel-separator 2)
+ "code_change(OldVsn, State, Extra) ->" n>
+ "{ok, State}." n
+ n
+ (erlang-skel-double-separator 2)
+ "%%% Internal functions" n
+ (erlang-skel-double-separator 2)
+ )
+ "*The template of a generic server.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-gen-event
+ '((erlang-skel-include erlang-skel-large-header)
+ "-behaviour(gen_event)." n
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([start_link/0, add_handler/0])." n
+ n
+ (erlang-skel-separator 2)
+ "%% gen_event callbacks" n
+ (erlang-skel-separator 2)
+ "-export([init/1, handle_event/2, handle_call/2, "
+ "handle_info/2, terminate/2, code_change/3])." n n
+ (erlang-skel-separator 2)
+ "%% Record Definitions" n
+ (erlang-skel-separator 2)
+ "-record(state, {})." n n
+ (erlang-skel-separator 2)
+ "%% Macro Definitions" n
+ (erlang-skel-separator 2)
+ "-define(SERVER, ?MODULE)." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% @doc Starts the server" n
+ "%% @spec start_link() -> {ok, Pid} | {error, {already_started, Pid}}" n
+ "%% @end" n
+ (erlang-skel-separator 2)
+ "start_link() ->" n>
+ "gen_event:start_link({local, ?SERVER}). " n
+ n
+ (erlang-skel-separator 2)
+ "%% @doc Adds an event handler" n
+ "%% @spec add_handler() -> ok | {'EXIT', Reason}" n
+ "%% @end" n
+ (erlang-skel-separator 2)
+ "add_handler() ->" n>
+ "gen_event:add_handler(?SERVER, ?MODULE, [])." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Server functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% Func: init/1" n
+ "%% Returns: {ok, State} |" n
+ "%% Other" n
+ (erlang-skel-separator 2)
+ "init([]) ->" n>
+ "{ok, #state{}}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: handle_event/2" n
+ "%% Returns: {ok, State} |" n
+ "%% {swap_handler, Args1, State1, Mod2, Args2} |" n
+ "%% remove_handler " n
+ (erlang-skel-separator 2)
+ "handle_event(Event, State) ->" n>
+ "{ok, State}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: handle_call/2" n
+ "%% Returns: {ok, Reply, State} |" n
+ "%% {swap_handler, Reply, Args1, State1, Mod2, Args2} |" n
+ "%% {remove_handler, Reply} " n
+ (erlang-skel-separator 2)
+ "handle_call(Request, State) ->" n>
+ "Reply = ok," n>
+ "{ok, Reply, State}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: handle_info/2" n
+ "%% Returns: {ok, State} |" n
+ "%% {swap_handler, Args1, State1, Mod2, Args2} |" n
+ "%% remove_handler " n
+ (erlang-skel-separator 2)
+ "handle_info(Info, State) ->" n>
+ "{ok, State}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: terminate/2" n
+ "%% Purpose: Shutdown the server" n
+ "%% Returns: any" n
+ (erlang-skel-separator 2)
+ "terminate(Reason, State) ->" n>
+ "ok." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: code_change/3" n
+ "%% Purpose: Convert process state when code is changed" n
+ "%% Returns: {ok, NewState}" n
+ (erlang-skel-separator 2)
+ "code_change(OldVsn, State, Extra) ->" n>
+ "{ok, State}." n
+ n
+ (erlang-skel-separator 2)
+ "%%% Internal functions" n
+ (erlang-skel-separator 2)
+ )
+ "*The template of a gen_event.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-gen-fsm
+ '((erlang-skel-include erlang-skel-large-header)
+ "-behaviour(gen_fsm)." n
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ "-export([start_link/0])." n
+ n
+ "%% gen_fsm callbacks" n
+ "-export([init/1, state_name/2, state_name/3, handle_event/3," n>
+ "handle_sync_event/4, handle_info/3, terminate/3, code_change/4])." n n
+ "-record(state, {})." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% Function: start_link/0" n
+ "%% Description: Starts the server" n
+ (erlang-skel-separator 2)
+ "start_link() ->" n>
+ "gen_fsm:start_link({local, ?SERVER}, ?MODULE, [], [])." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Server functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% Func: init/1" n
+ "%% Returns: {ok, StateName, StateData} |" n
+ "%% {ok, StateName, StateData, Timeout} |" n
+ "%% ignore |" n
+ "%% {stop, StopReason} " n
+ (erlang-skel-separator 2)
+ "init([]) ->" n>
+ "{ok, state_name, #state{}}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: StateName/2" n
+ "%% Returns: {next_state, NextStateName, NextStateData} |" n
+ "%% {next_state, NextStateName, NextStateData, Timeout} |" n
+ "%% {stop, Reason, NewStateData} " n
+ (erlang-skel-separator 2)
+ "state_name(Event, StateData) ->" n>
+ "{next_state, state_name, StateData}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: StateName/3" n
+ "%% Returns: {next_state, NextStateName, NextStateData} |" n
+ "%% {next_state, NextStateName, NextStateData, Timeout} |" n
+ "%% {reply, Reply, NextStateName, NextStateData} |" n
+ "%% {reply, Reply, NextStateName, NextStateData, Timeout} |" n
+ "%% {stop, Reason, NewStateData} |" n
+ "%% {stop, Reason, Reply, NewStateData} " n
+ (erlang-skel-separator 2)
+ "state_name(Event, From, StateData) ->" n>
+ "Reply = ok," n>
+ "{reply, Reply, state_name, StateData}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: handle_event/3" n
+ "%% Returns: {next_state, NextStateName, NextStateData} |" n
+ "%% {next_state, NextStateName, NextStateData, Timeout} |" n
+ "%% {stop, Reason, NewStateData} " n
+ (erlang-skel-separator 2)
+ "handle_event(Event, StateName, StateData) ->" n>
+ "{next_state, StateName, StateData}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: handle_sync_event/4" n
+ "%% Returns: {next_state, NextStateName, NextStateData} |" n
+ "%% {next_state, NextStateName, NextStateData, Timeout} |" n
+ "%% {reply, Reply, NextStateName, NextStateData} |" n
+ "%% {reply, Reply, NextStateName, NextStateData, Timeout} |" n
+ "%% {stop, Reason, NewStateData} |" n
+ "%% {stop, Reason, Reply, NewStateData} " n
+ (erlang-skel-separator 2)
+ "handle_sync_event(Event, From, StateName, StateData) ->" n>
+ "Reply = ok," n>
+ "{reply, Reply, StateName, StateData}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: handle_info/3" n
+ "%% Returns: {next_state, NextStateName, NextStateData} |" n
+ "%% {next_state, NextStateName, NextStateData, Timeout} |" n
+ "%% {stop, Reason, NewStateData} " n
+ (erlang-skel-separator 2)
+ "handle_info(Info, StateName, StateData) ->" n>
+ "{next_state, StateName, StateData}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: terminate/3" n
+ "%% Purpose: Shutdown the fsm" n
+ "%% Returns: any" n
+ (erlang-skel-separator 2)
+ "terminate(Reason, StateName, StatData) ->" n>
+ "ok." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: code_change/4" n
+ "%% Purpose: Convert process state when code is changed" n
+ "%% Returns: {ok, NewState, NewStateData}" n
+ (erlang-skel-separator 2)
+ "code_change(OldVsn, StateName, StateData, Extra) ->" n>
+ "{ok, StateName, StateData}." n
+ n
+ (erlang-skel-separator 2)
+ "%%% Internal functions" n
+ (erlang-skel-separator 2)
+ )
+ "*The template of a gen_fsm.
+Please see the function `tempo-define-template'.")
+
+(defvar erlang-skel-lib
+ '((erlang-skel-include erlang-skel-large-header)
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([" n
+ " ])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Internal exports" n
+ (erlang-skel-separator 2)
+ "-export([" n
+ " ])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Macros" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% Records" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% @doc" n
+ "%% @spec " n
+ "%% @end " n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-double-separator 2)
+ "%% Internal functions" n
+ (erlang-skel-double-separator 2)
+ )
+ "*The template of a library module.
+Please see the function `tempo-define-template'.")
+
+
+(defvar erlang-skel-generic-leader
+ '((erlang-skel-include erlang-skel-large-header)
+ "-behaviour(fs_gen_leader)." n
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([" n>"start_link/0,"n>"stop/0"n>"])." n
+ n
+ (erlang-skel-separator 2)
+ "%% gen_leader callbacks" n
+ (erlang-skel-separator 2)
+ "-export([init/1," n>
+ "elected/2," n>
+ "surrendered/3," n>
+ "handle_DOWN/3," n>
+ "handle_leader_call/4," n>
+ "handle_leader_cast/3," n>
+ "from_leader/3," n>
+ "handle_call/3," n>
+ "handle_cast/2," n>
+ "handle_info/2," n>
+ "terminate/2," n>
+ "code_change/4" n>
+ "])." n>
+ (erlang-skel-separator 2)
+ "%% record definitions" n
+ (erlang-skel-separator 2)
+ "-record(state, {})." n n
+ (erlang-skel-separator 2)
+ "%% macro definitions" n
+ (erlang-skel-separator 2)
+ "-define(SERVER, ?MODULE)." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% @doc Starts the gen_leader." n
+ "%% @spec start_link() -> {ok, pid()} | {error, Reason}" n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "start_link() ->" n>
+ "Candidates = [node()|nodes()]," n>
+ "Workers = []," n>
+ "gen_leader:start_link({local, ?SERVER}, Candidates, Workers, ?MODULE, [], [])." n
+ n
+ (erlang-skel-separator 2)
+ "%% @doc Stops the gen_leader." n
+ "%% @spec stop() -> ok" n
+ "%% @end"n
+ (erlang-skel-separator 2)
+ "stop() ->" n>
+ "gen_leader:cast(?SERVER, stop)." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Server functions" n
+ (erlang-skel-double-separator 2)
+ n
+
+
+
+ (erlang-skel-separator 2)
+ "%% Function: init/1" n>
+ "%% Description: Initiates the server" n>
+ "%% Returns: {ok, State} |" n>
+ "%% {ok, State, Timeout} |" n>
+ "%% ignore |" n>
+ "%% {stop, Reason}" n>
+ (erlang-skel-separator 2)
+ "init([]) ->" n>
+ "{ok, #state{}}." n
+ n
+
+ (erlang-skel-separator 2)
+ "%% Called when we become the leader." n>
+ "%%" n>
+ "%% elected(State::state(), E::election()) -> {ok, Broadcast, NState}" n>
+ (erlang-skel-separator 2)
+ "elected(State, E) ->" n>
+ "BroadcastToAllCandidates = [],"n>
+ "{ok, BroadcastToAllCandidates , State}." n
+ n
+
+ (erlang-skel-separator 2)
+ "%% Called by each candidate when it recognizes another instance as leader." n>
+ "%% Strictly speaking, this function is called when the candidate " n>
+ "%% acknowledges a leader and receives a Synch message in return." n>
+ "%%" n>
+ "%% surrendered(State::state(), Synch::broadcast(), E::election()) -> {ok, NState}" n>
+ (erlang-skel-separator 2)
+ "surrendered(State, BCastFromLeaderElectedCall, E) ->" n>
+ "{ok, State#state{leader_node = LeaderNode}}."n
+ n
+
+ (erlang-skel-separator 2)
+ "%% Called by the leader when it detects loss of a candidate node." n>
+ "%% If the function returns a broadcast() object, this will" n>
+ "%% be sent to all candidates, and they will receive it in the function" n>
+ "%% link from_leader/3. from_leader/3" n>
+ "%%" n>
+ "%% handle_DOWN(Node::node(), State::state(), E::election()) -> {ok, NState} | {ok, Broadcast, NState}" n>
+ (erlang-skel-separator 2)
+ "handle_DOWN(Node, State, _E) ->" n>
+ "{ok, State}." n>
+
+ (erlang-skel-separator 2)
+ "%% handle_leader_call(Msg::term(), From::callerRef(), State::state(), E::election()) -> " n>
+ "%% {reply, Reply, NState} |" n>
+ "%% {reply, Reply, Broadcast, NState} |" n>
+ "%% {noreply, state()} |" n>
+ "%% {stop, Reason, Reply, NState} |" n>
+ "%% commonReply()" n>
+ "%%" n>
+ "%% Called by the leader in response to a gen_leader:leader_call/2. leader_call()." n>
+ (erlang-skel-separator 2)
+ "handle_leader_call(Msg, _From, State, _E) ->" n>
+ "{reply, Reply = [], State}." n
+ n
+
+ (erlang-skel-separator 2)
+ "%% Called by the leader in response to a gen_leader:leader_cast/2 leader_cast()" n>
+ "%% handle_leader_cast(Msg::term(), State::term(), E::election()) -> commonReply()" n>
+ "%%" n>
+ "%% BUG: This has not yet been implemented." n>
+ (erlang-skel-separator 2)
+ "handle_leader_cast(_Msg, State, _E) ->" n>
+ "{ok, State}." n
+ n
+
+ (erlang-skel-separator 2)
+ "%% Called by each candidate in response to a message from the leader. " n>
+ "%% In this particular module, the leader passes an update function to be " n>
+ "%% applied to the candidate's state. " n>
+ "%% " n>
+ "%% from_leader(Msg::term(), State::state(), E::election()) -> {ok, NState} " n>
+ (erlang-skel-separator 2)
+ "from_leader(MSG, State, _E) -> " n>
+ "{ok, State}. " n
+ n
+
+ n
+ (erlang-skel-separator 2)
+ "%% Function: handle_call/3" n
+ "%% Description: Handling call messages" n
+ "%% Returns: {reply, Reply, State} |" n
+ "%% {reply, Reply, State, Timeout} |" n
+ "%% {noreply, State} |" n
+ "%% {noreply, State, Timeout} |" n
+ "%% {stop, Reason, Reply, State} | (terminate/2 is called)" n
+ "%% {stop, Reason, State} (terminate/2 is called)" n
+ (erlang-skel-separator 2)
+ "handle_call(Request, From, State) ->" n>
+ "Reply = ok," n>
+ "{reply, Reply, State}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Function: handle_cast/2" n
+ "%% Description: Handling cast messages" n
+ "%% Returns: {noreply, State} |" n
+ "%% {noreply, State, Timeout} |" n
+ "%% {stop, Reason, State} (terminate/2 is called)" n
+ (erlang-skel-separator 2)
+ "handle_cast(stop, State) ->" n>
+ "{stop, normal, State};" n
+ "handle_cast(Msg, State) ->" n>
+ "{noreply, State}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Function: handle_info/2" n
+ "%% Description: Handling all non call/cast messages" n
+ "%% Returns: {noreply, State} |" n
+ "%% {noreply, State, Timeout} |" n
+ "%% {stop, Reason, State} (terminate/2 is called)" n
+ (erlang-skel-separator 2)
+ "handle_info(Info, State) ->" n>
+ "{noreply, State}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Function: terminate/2" n
+ "%% Description: Shutdown the server" n
+ "%% Returns: any (ignored by gen_server)" n
+ (erlang-skel-separator 2)
+ "terminate(Reason, State) ->" n>
+ "ok." n
+ n
+ (erlang-skel-separator 2)
+ "%% Func: code_change/3" n
+ "%% Purpose: Convert process state when code is changed" n
+ "%% Returns: {ok, NewState}" n
+ (erlang-skel-separator 2)
+ "code_change(OldVsn, State, _E, _Extra) ->" n>
+ "{ok, State}." n
+ n
+
+ n
+ (erlang-skel-separator 2)
+ "%%% Internal functions" n
+ (erlang-skel-separator 2)
+ )
+ "*The template of a generic leader.
+Please see the function `tempo-define-template'.")
+
+
+(defvar erlang-skel-corba-callback
+ '((erlang-skel-include erlang-skel-large-header)
+ (erlang-skel-separator 2)
+ "%% Include files" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% External exports" n
+ (erlang-skel-separator 2)
+ "-export([" n> "init/1, " n> "terminate/2," n> "code_change/3" n
+ " ])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Internal exports" n
+ (erlang-skel-separator 2)
+ "-export([" n
+ " ])." n
+ n
+ (erlang-skel-separator 2)
+ "%% Macros" n
+ (erlang-skel-separator 2)
+ n
+ (erlang-skel-separator 2)
+ "%% Records" n
+ (erlang-skel-separator 2)
+ "-record(state, {})." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% External functions" n
+ (erlang-skel-double-separator 2)
+ (erlang-skel-separator 2)
+ "%% Function: init/1" n
+ "%% Description: Initiates the server" n
+ "%% Returns: {ok, State} |" n
+ "%% {ok, State, Timeout} |" n
+ "%% ignore |" n
+ "%% {stop, Reason}" n
+ (erlang-skel-separator 2)
+ "init([]) ->" n>
+ "{ok, #state{}}." n
+ n
+ (erlang-skel-separator 2)
+ "%% Function: terminate/2" n
+ "%% Description: Shutdown the server" n
+ "%% Returns: any (ignored by gen_server)" n
+ (erlang-skel-separator 2)
+ "terminate(Reason, State) ->" n>
+ "ok." n
+ n
+ (erlang-skel-separator 2)
+ "%% Function: code_change/3" n
+ "%% Description: Convert process state when code is changed" n
+ "%% Returns: {ok, NewState}" n
+ (erlang-skel-separator 2)
+ "code_change(OldVsn, State, Extra) ->" n>
+ "{ok, State}." n
+ n
+ (erlang-skel-double-separator 2)
+ "%% Internal functions" n
+ (erlang-skel-double-separator 2)
+ )
+ "*The template of a library module.
+Please see the function `tempo-define-template'.")
+
+
+
+;; Font-lock variables
+
+(defvar erlang-font-lock-modern-p
+ (cond ((>= erlang-emacs-major-version 20) t)
+ (erlang-xemacs-p (>= erlang-emacs-minor-version 14))
+ ((= erlang-emacs-major-version 19) (>= erlang-emacs-minor-version 29))
+ (t nil))
+ "Non-nil when this version of Emacs uses a modern version of Font Lock.
+
+This is determinated by checking the version of Emacs used, the actual
+font-lock code is not loaded.")
+
+
+;; The next few variables define different Erlang font-lock patterns.
+;; They could be appended to form a custom font-lock appearence.
+;;
+;; The function `erlang-font-lock-set-face' could be used to change
+;; the face of a pattern.
+;;
+;; Note that Erlang strings and atoms are hightlighted with using
+;; syntactix analysis.
+
+(defvar erlang-font-lock-keywords-func
+ (list
+ (list (concat "^" erlang-atom-regexp "\\s *(")
+ 1 'font-lock-function-name-face t))
+ "Font lock keyword highlighting a function header.")
+
+(defvar erlang-font-lock-keywords-dollar
+ (list
+ (list "\\(\\$\\([^\\]\\|\\\\\\([^0-7^\n]\\|[0-7]+\\|\\^[a-zA-Z]\\)\\)\\)"
+ 1 'font-lock-string-face))
+ "Font lock keyword highlighting numbers in ascii-form (e.g. $A).")
+
+(defvar erlang-font-lock-keywords-arrow
+ (list
+ (list "\\(->\\|:-\\)\\(\\s \\|$\\)" 2 'font-lock-function-name-face))
+ "Font lock keyword highlighting clause arrow.")
+
+(defvar erlang-font-lock-keywords-lc
+ (list
+ (list "\\(<-\\)\\(\\s \\|$\\)" 1 'font-lock-keyword-face)
+ (list "\\(||\\)\\(\\s \\|$\\)" 1 'font-lock-keyword-face))
+ "Font lock keyword highlighting list comprehension operators.")
+
+(defvar erlang-font-lock-keywords-keywords
+ (list
+ (list (concat "\\<\\(after\\|begin\\|c\\(atch\\|ase\\)\\|end\\|fun\\|if"
+ "\\|of\\|receive\\|when\\|query\\)\\([^a-zA-Z0-9_]\\|$\\)")
+ 1 'font-lock-keyword-face))
+ "Font lock keyword highlighting Erlang keywords.")
+
+(defvar erlang-font-lock-keywords-attr
+ (list
+ (list (concat "^\\(-" erlang-atom-regexp "\\)\\s *\\(\\.\\|(\\)")
+ 1 'font-lock-function-name-face))
+ "Font lock keyword highlighting attribues.")
+
+(defvar erlang-font-lock-keywords-quotes
+ (list
+ (list "`\\([-+a-zA-Z0-9_:*][-+a-zA-Z0-9_:*]+\\)'"
+ 1
+ (if erlang-font-lock-modern-p
+ 'font-lock-reference-face
+ 'font-lock-keyword-face)
+ t))
+ "Font lock keyword highlighting words in single quotes in comments.
+
+This is not the keyword hightlighting Erlang strings and atoms, they
+are highlighted by syntactic analysis.")
+
+;; Note: The guard `float' collides with the bif `float'.
+(defvar erlang-font-lock-keywords-guards
+ (list
+ (list
+
+ ;; XXX:
+; (concat "\\<"
+; (regexp-opt '("atom" "binary" "constant" "float" "integer" "list"
+; "number" "pid" "port" "reference" "record" "tuple")
+; t)
+; "\\>")
+
+ (concat "\\<\\(atom\\|binary\\|constant\\|float\\|integer\\|list\\|"
+ "number\\|p\\(id\\|ort\\)\\|re\\(ference\\|cord\\)\\|tuple"
+ "\\)\\s *(")
+
+ 1
+ (if erlang-font-lock-modern-p
+ 'font-lock-reference-face
+ 'font-lock-keyword-face)))
+ "Font lock keyword highlighting guards.")
+
+(defvar erlang-font-lock-keywords-bifs
+ (list
+ (list
+ (concat
+ "\\<\\("
+ "a\\(bs\\|live\\|pply\\|tom_to_list\\)\\|"
+ "binary_to_\\(list\\|term\\)\\|"
+ "concat_binary\\|d\\(ate\\|isconnect_node\\)\\|"
+ "e\\(lement\\|rase\\|xit\\)\\|"
+ "float\\(\\|_to_list\\)\\|"
+ "g\\(arbage_collect\\|et\\(\\|_keys\\)\\|roup_leader\\)\\|"
+ "h\\(alt\\|d\\)\\|"
+ "i\\(nte\\(ger_to_list\\|rnal_bif\\)\\|s_alive\\)\\|"
+ "l\\(ength\\|i\\(nk\\|st_to_\\(atom\\|binary\\|float\\|integer"
+ "\\|pid\\|tuple\\)\\)\\)\\|"
+ "make_ref\\|no\\(de\\(\\|_\\(link\\|unlink\\)\\|s\\)\\|talive\\)\\|"
+ "open_port\\|"
+ "p\\(id_to_list\\|rocess\\(_\\(flag\\|info\\)\\|es\\)\\|ut\\)\\|"
+ "r\\(egister\\(\\|ed\\)\\|ound\\)\\|"
+ "s\\(e\\(lf\\|telement\\)\\|ize\\|"
+ "p\\(awn\\(\\|_link\\)\\|lit_binary\\)\\|tatistics\\)\\|"
+ "t\\(erm_to_binary\\|hrow\\|ime\\|l\\|"
+ "r\\(ace\\|unc\\)\\|uple_to_list\\)\\|"
+ "un\\(link\\|register\\)\\|whereis"
+ "\\)\\s *(")
+ 1
+ 'font-lock-keyword-face))
+ "Font lock keyword highlighting built in functions.")
+
+(defvar erlang-font-lock-keywords-macros
+ (list
+ (list (concat "?\\s *\\(" erlang-atom-regexp
+ "\\|" erlang-variable-regexp "\\)\\>")
+ 1 (if erlang-font-lock-modern-p
+ 'font-lock-reference-face
+ 'font-lock-type-face))
+ (list (concat "^-\\(define\\|ifn?def\\)\\s *(\\s *\\(" erlang-atom-regexp
+ "\\|" erlang-variable-regexp "\\)\\>")
+ 2 (if erlang-font-lock-modern-p
+ 'font-lock-reference-face
+ 'font-lock-type-face)))
+ "Font lock keyword highlighting macros.
+This must be placed in front of `erlang-font-lock-keywords-vars'.")
+
+(defvar erlang-font-lock-keywords-records
+ (list
+ (list (concat "#\\s *" erlang-atom-regexp "\\>")
+ 1 'font-lock-type-face)
+ ;; Don't highlight numerical constants.
+ (list "\\<[0-9][0-9]?#\\([0-9a-fA_F]+\\)\\>"
+ 1 nil t)
+ (list (concat "^-record(\\s *" erlang-atom-regexp "\\>")
+ 1 'font-lock-type-face))
+ "Font lock keyword highlighting Erlang records.
+This must be placed in front of `erlang-font-lock-keywords-vars'.")
+
+(defvar erlang-font-lock-keywords-vars
+ (list
+ (list (concat "\\<" erlang-variable-regexp "\\>")
+ 1 (if erlang-font-lock-modern-p
+ 'font-lock-variable-name-face
+ 'font-lock-type-face)))
+ "Font lock keyword highlighting Erlang variables.
+Must be preceded by `erlang-font-lock-keywords-macros' and `-records'
+to work properly.")
+
+
+(defvar erlang-font-lock-keywords-1
+ (append erlang-font-lock-keywords-func
+ erlang-font-lock-keywords-dollar
+ erlang-font-lock-keywords-arrow
+ erlang-font-lock-keywords-keywords)
+ ;; DocStringOrig: erlang-font-lock-keywords
+ "Font-lock keywords used by Erlang Mode.
+
+There exists three levels of Font Lock keywords for Erlang:
+ `erlang-font-lock-keywords-1' - Function headers and reserved keywords.
+ `erlang-font-lock-keywords-2' - Bifs, guards and `singel quotes'.
+ `erlang-font-lock-keywords-3' - Variables, macros and records.
+
+To use a specific level, please set the variable
+`font-lock-maximum-decoration' to the appropriate level. Note that the
+variable must be set before Erlang mode is activated.
+
+Example:
+ (setq font-lock-maximum-decoration 2)")
+
+
+(defvar erlang-font-lock-keywords-2
+ (append erlang-font-lock-keywords-1
+ erlang-font-lock-keywords-attr
+ erlang-font-lock-keywords-quotes
+ erlang-font-lock-keywords-guards
+ erlang-font-lock-keywords-bifs)
+ ;; DocStringCopy: erlang-font-lock-keywords
+ "Font-lock keywords used by Erlang Mode.
+
+There exists three levels of Font Lock keywords for Erlang:
+ `erlang-font-lock-keywords-1' - Function headers and reserved keywords.
+ `erlang-font-lock-keywords-2' - Bifs, guards and `single quotes'.
+ `erlang-font-lock-keywords-3' - Variables, macros and records.
+
+To use a specific level, please set the variable
+`font-lock-maximum-decoration' to the appropriate level. Note that the
+variable must be set before Erlang mode is activated.
+
+Example:
+ (setq font-lock-maximum-decoration 2)")
+
+
+(defvar erlang-font-lock-keywords-3
+ (append erlang-font-lock-keywords-2
+ erlang-font-lock-keywords-macros
+ erlang-font-lock-keywords-records
+ erlang-font-lock-keywords-vars)
+ ;; DocStringCopy: erlang-font-lock-keywords
+ "Font-lock keywords used by Erlang Mode.
+
+There exists three levels of Font Lock keywords for Erlang:
+ `erlang-font-lock-keywords-1' - Function headers and reserved keywords.
+ `erlang-font-lock-keywords-2' - Bifs, guards and `single quotes'.
+ `erlang-font-lock-keywords-3' - Variables, macros and records.
+
+To use a specific level, please set the variable
+`font-lock-maximum-decoration' to the appropriate level. Note that the
+variable must be set before Erlang mode is activated.
+
+Example:
+ (setq font-lock-maximum-decoration 2)")
+
+
+(defvar erlang-font-lock-keywords erlang-font-lock-keywords-3
+ ;; DocStringCopy: erlang-font-lock-keywords
+ "Font-lock keywords used by Erlang Mode.
+
+There exists three levels of Font Lock keywords for Erlang:
+ `erlang-font-lock-keywords-1' - Function headers and reserved keywords.
+ `erlang-font-lock-keywords-2' - Bifs, guards and `single quotes'.
+ `erlang-font-lock-keywords-3' - Variables, macros and records.
+
+To use a specific level, please set the variable
+`font-lock-maximum-decoration' to the appropriate level. Note that the
+variable must be set before Erlang mode is activated.
+
+Example:
+ (setq font-lock-maximum-decoration 2)")
+
+
+(defvar erlang-font-lock-syntax-table nil
+ "Syntax table used by Font Lock mode.
+
+The difference between this and the standard Erlang Mode
+syntax table is that `_' is treated as part of words by
+this syntax table.
+
+Unfortuantely, XEmacs hasn't got support for a special Font
+Lock syntax table. The effect is that `apply' in the atom
+`foo_apply' will be highlighted as a bif.")
+
+
+;;; Avoid errors while compiling this file.
+
+;; `eval-when-compile' is not defined in Emacs 18. We define it as a
+;; no-op.
+(or (fboundp 'eval-when-compile)
+ (defmacro eval-when-compile (&rest rest) nil))
+
+;; These umm...functions are new in Emacs 20. And, yes, until version
+;; 19.27 Emacs backquotes were this ugly.
+
+(or (fboundp 'unless)
+ (defmacro unless (condition &rest body)
+ "(unless CONDITION BODY...): If CONDITION is false, do BODY, else return nil."
+ (` (if (, condition)
+ nil
+ (,@ body)))))
+
+(or (fboundp 'when)
+ (defmacro when (condition &rest body)
+ "(when CONDITION BODY...): If CONDITION is true, do BODY, else return nil."
+ (` (if (, condition)
+ (progn (,@ body))
+ nil))))
+
+(or (fboundp 'char-before)
+ (defmacro char-before (&optional pos)
+ "Return the character in the current buffer just before POS."
+ (` (char-after (1- (or (, pos) (point)))))))
+
+(or (fboundp 'regexp-opt)
+ (defun regexp-opt (strings &optional paren)
+ "Return a regular expression that matches any string in
+STRINGS. If PAREN is true, it will always enclose the regular
+expression in parentheses.
+
+Unlike its Emacs-20 namesake, it will not optimize the generated
+expression."
+ ;; This stop-gap definition is taken from
+ ;; _GNU_Emacs_Lisp_Reference_Manual_, ed 2.5, for Emacs 20.3.
+ (let ((open (if paren "\\(" ""))
+ (close (if paren "\\)" "")))
+ (concat open
+ (mapconcat 'regexp-quote strings "\\|")
+ close))))
+
+(eval-when-compile
+ (if (or (featurep 'bytecomp)
+ (featurep 'byte-compile))
+ (progn
+ (cond ((string-match "Lucid\\|XEmacs" emacs-version)
+ (put 'comment-indent-hook 'byte-obsolete-variable nil)
+ ;; Do not warn for unused variables
+ ;; when compiling under XEmacs.
+ (setq byte-compile-warnings
+ '(free-vars unresolved callargs redefine))))
+ (require 'comint)
+ (require 'compile))))
+
+
+(defun erlang-version ()
+ "Return the current version of Erlang mode."
+ (interactive)
+ (if (interactive-p)
+ (message "Erlang mode version %s, written by Anders Lindgren"
+ erlang-version))
+ erlang-version)
+
+
+;;;###autoload
+(defun erlang-mode ()
+ "Major mode for editing Erlang source files in Emacs.
+It knows about syntax and comment, it can indent code, it is capable
+of fontifying the source file, the TAGS commands are aware of Erlang
+modules, and the Erlang man pages can be accessed.
+
+Should this module, \"erlang.el\", be installed properly, Erlang mode
+is activated whenever an Erlang source or header file is loaded into
+Emacs. To indicate this, the mode line should contain the word
+\"Erlang\".
+
+The main feature of Erlang mode is indentation, press TAB and the
+current line will be indented correctly.
+
+Comments starting with only one `%' are indented to the column stored
+in the variable `comment-column'. Comments starting with two `%':s
+are indented with the same indentation as code. Comments starting
+with at least three `%':s are indented to the first column.
+
+However, Erlang mode contains much more, this is a list of the most
+useful commands:
+ TAB - Indent the line.
+ C-c C-q - Indent current function.
+ M-; - Create a comment at the end of the line.
+ M-q - Fill a comment, i.e. wrap lines so that they (hopefully)
+ will look better.
+ M-a - Goto the beginning of an Erlang clause.
+ M-C-a - Ditto for function.
+ M-e - Goto the end of an Erlang clause.
+ M-C-e - Ditto for function.
+ M-h - Mark current Erlang clause.
+ M-C-h - Ditto for function.
+ C-c C-z - Start, or switch to, an inferior Erlang shell.
+ C-c C-k - Compile current file.
+ C-x ` - Next error.
+ , - Electric comma.
+ ; - Electric semicolon.
+
+Erlang mode check the name of the file against the module name when
+saving, whenever a mismatch occurs Erlang mode offers to modify the
+source.
+
+The variable `erlang-electric-commands' controls the electric
+commands. To deactivate all of them, set it to nil.
+
+There exists a large number of commands and variables in the Erlang
+module. Please press `M-x apropos RET erlang RET' to see a complete
+list. Press `C-h f name-of-function RET' and `C-h v name-of-variable
+RET'to see the full description of functions and variables,
+respectively.
+
+On entry to this mode the contents of the hook `erlang-mode-hook' is
+executed.
+
+Please see the beginning of the file `erlang.el' for more information
+and examples of hooks.
+
+Other commands:
+\\{erlang-mode-map}"
+ (interactive)
+ (kill-all-local-variables)
+ (setq major-mode 'erlang-mode)
+ (setq mode-name "Erlang")
+ (erlang-syntax-table-init)
+ (erlang-keymap-init)
+ (erlang-electric-init)
+ (erlang-menu-init)
+ (erlang-mode-variables)
+ (erlang-check-module-name-init)
+ (erlang-add-compilation-alist erlang-error-regexp-alist)
+ (erlang-man-init)
+ (erlang-tags-init)
+ (erlang-font-lock-init)
+ (erlang-skel-init)
+ (run-hooks 'erlang-mode-hook)
+ (if (zerop (buffer-size))
+ (run-hooks 'erlang-new-file-hook)))
+
+
+(defun erlang-syntax-table-init ()
+ (if (null erlang-mode-syntax-table)
+ (let ((table (make-syntax-table)))
+ (modify-syntax-entry ?\n ">" table)
+ (modify-syntax-entry ?\" "\"" table)
+ (modify-syntax-entry ?# "." table)
+ (modify-syntax-entry ?$ "/" table)
+ (modify-syntax-entry ?% "<" table)
+ (modify-syntax-entry ?& "." table)
+ (modify-syntax-entry ?\' "\"" table)
+ (modify-syntax-entry ?* "." table)
+ (modify-syntax-entry ?+ "." table)
+ (modify-syntax-entry ?- "." table)
+ (modify-syntax-entry ?/ "." table)
+ (modify-syntax-entry ?: "." table)
+ (modify-syntax-entry ?< "." table)
+ (modify-syntax-entry ?= "." table)
+ (modify-syntax-entry ?> "." table)
+ (modify-syntax-entry ?\\ "\\" table)
+ (modify-syntax-entry ?_ "_" table)
+ (modify-syntax-entry ?| "." table)
+ (modify-syntax-entry ?^ "/" table)
+
+ ;; Pseudo bit-syntax: Latin1 double angle quotes as parens.
+ ;;(modify-syntax-entry ?\253 "(?\273" table)
+ ;;(modify-syntax-entry ?\273 ")?\253" table)
+
+ (setq erlang-mode-syntax-table table)))
+
+ (set-syntax-table erlang-mode-syntax-table))
+
+
+(defun erlang-keymap-init ()
+ (if erlang-mode-map
+ nil
+ (setq erlang-mode-map (make-sparse-keymap))
+ (erlang-mode-commands erlang-mode-map))
+ (use-local-map erlang-mode-map))
+
+
+(defun erlang-mode-commands (map)
+ (define-key map "\t" 'erlang-indent-command)
+ (define-key map ";" 'erlang-electric-semicolon)
+ (define-key map "," 'erlang-electric-comma)
+ (define-key map "<" 'erlang-electric-lt)
+ (define-key map ">" 'erlang-electric-gt)
+ (define-key map "\C-m" 'erlang-electric-newline)
+ (define-key map "\177" 'backward-delete-char-untabify)
+ (define-key map "\M-q" 'erlang-fill-paragraph)
+ (define-key map "\M-\C-a" 'erlang-beginning-of-function)
+ (define-key map "\M-\C-e" 'erlang-end-of-function)
+ (define-key map "\M-\C-h" 'erlang-mark-function)
+ (define-key map "\M-\t" 'erlang-complete-tag)
+ (define-key map "\C-c\M-\t" 'tempo-complete-tag)
+ (define-key map "\C-c\M-a" 'erlang-beginning-of-clause)
+ (define-key map "\C-c\M-b" 'tempo-backward-mark)
+ (define-key map "\C-c\M-e" 'erlang-end-of-clause)
+ (define-key map "\C-c\M-f" 'tempo-forward-mark)
+ (define-key map "\C-c\M-h" 'erlang-mark-clause)
+ (define-key map "\C-c\C-c" 'comment-region)
+ (define-key map "\C-c\C-j" 'erlang-generate-new-clause)
+ (define-key map "\C-c\C-k" 'erlang-compile)
+ (define-key map "\C-c\C-l" 'erlang-compile-display)
+ (define-key map "\C-c\C-s" 'erlang-show-syntactic-information)
+ (define-key map "\C-c\C-q" 'erlang-indent-function)
+ (define-key map "\C-c\C-u" 'erlang-uncomment-region)
+ (define-key map "\C-c\C-y" 'erlang-clone-arguments)
+ (define-key map "\C-c\C-z" 'erlang-shell-display)
+ (define-key map "\C-x`" 'erlang-next-error))
+
+
+(defun erlang-electric-init ()
+ ;; Set up electric character functions to work with
+ ;; delsel/pending-del mode. Also, set up text properties for bit
+ ;; syntax handling.
+ (mapcar #'(lambda (cmd)
+ (put cmd 'delete-selection t) ;for delsel (Emacs)
+ (put cmd 'pending-delete t)) ;for pending-del (XEmacs)
+ '(erlang-electric-semicolon
+ erlang-electric-comma
+ erlang-electric-gt))
+
+ (put 'bitsyntax-open-outer 'syntax-table '(4 . ?>))
+ (put 'bitsyntax-open-outer 'rear-nonsticky '(category))
+ (put 'bitsyntax-open-inner 'rear-nonsticky '(category))
+ (put 'bitsyntax-close-inner 'rear-nonsticky '(category))
+ (put 'bitsyntax-close-outer 'syntax-table '(5 . ?<))
+ (put 'bitsyntax-close-outer 'rear-nonsticky '(category))
+ (setq parse-sexp-lookup-properties 't))
+
+
+
+(defun erlang-mode-variables ()
+ (or erlang-mode-abbrev-table
+ (define-abbrev-table 'erlang-mode-abbrev-table ()))
+ (setq local-abbrev-table erlang-mode-abbrev-table)
+ (make-local-variable 'paragraph-start)
+ (setq paragraph-start (concat "^$\\|" page-delimiter))
+ (make-local-variable 'paragraph-separate)
+ (setq paragraph-separate paragraph-start)
+ (make-local-variable 'paragraph-ignore-fill-prefix)
+ (setq paragraph-ignore-fill-prefix t)
+ (make-local-variable 'require-final-newline)
+ (setq require-final-newline t)
+ (make-local-variable 'defun-prompt-regexp)
+ (setq defun-prompt-regexp erlang-defun-prompt-regexp)
+ (make-local-variable 'comment-start)
+ (setq comment-start "%")
+ (make-local-variable 'comment-start-skip)
+ (setq comment-start-skip "%+\\s *")
+ (make-local-variable 'comment-column)
+ (setq comment-column 48)
+ (make-local-variable 'indent-line-function)
+ (setq indent-line-function 'erlang-indent-command)
+ (make-local-variable 'indent-region-function)
+ (setq indent-region-function 'erlang-indent-region)
+ (set (make-local-variable 'comment-indent-function) 'erlang-comment-indent)
+ (if (<= erlang-emacs-major-version 18)
+ (set (make-local-variable 'comment-indent-hook) 'erlang-comment-indent))
+ (set (make-local-variable 'parse-sexp-ignore-comments) t)
+ (set (make-local-variable 'dabbrev-case-fold-search) nil)
+ (set (make-local-variable 'imenu-prev-index-position-function)
+ 'erlang-beginning-of-function)
+ (set (make-local-variable 'imenu-extract-index-name-function)
+ 'erlang-get-function-name)
+ (set (make-local-variable 'tempo-match-finder)
+ "[^-a-zA-Z0-9_]\\([-a-zA-Z0-9_]*\\)\\="))
+
+
+;; Compilation.
+;;
+;; The following code is compatible with the standard package `compilation',
+;; making it possible to go to errors using `erlang-next-error'.
+;;
+;; The normal `compile' command works ofcourse. For best result, please
+;; execute `make' with the `-w' flag.
+;;
+;; Please see the variables named `compiling-..' above.
+
+(defun erlang-add-compilation-alist (alist)
+ (require 'compile)
+ (cond ((boundp 'compilation-error-regexp-alist) ; Emacs 19
+ (while alist
+ (or (assoc (car (car alist)) compilation-error-regexp-alist)
+ (setq compilation-error-regexp-alist
+ (cons (car alist) compilation-error-regexp-alist)))
+ (setq alist (cdr alist))))
+ ((boundp 'compilation-error-regexp)
+ ;; Emacs 18, Only one regexp is allowed.
+ (funcall (symbol-function 'set)
+ 'compilation-error-regexp (car (car alist))))))
+
+(defun erlang-font-lock-init ()
+ "Initialize Font Lock for Erlang mode."
+ (or erlang-font-lock-syntax-table
+ (setq erlang-font-lock-syntax-table
+ (let ((table (copy-syntax-table erlang-mode-syntax-table)))
+ (modify-syntax-entry ?_ "w" table)
+ table)))
+ (set (make-local-variable 'font-lock-syntax-table)
+ erlang-font-lock-syntax-table)
+ (set (make-local-variable 'font-lock-beginning-of-syntax-function)
+ 'erlang-beginning-of-clause)
+ (make-local-variable 'font-lock-keywords)
+ (let ((level (cond ((boundp 'font-lock-maximum-decoration)
+ (symbol-value 'font-lock-maximum-decoration))
+ ((boundp 'font-lock-use-maximal-decoration)
+ (symbol-value 'font-lock-use-maximal-decoration))
+ (t nil))))
+ (if (consp level)
+ (setq level (cdr-safe (or (assq 'erlang-mode level)
+ (assq t level)))))
+ ;; `level' can here be:
+ ;; A number - The fontification level
+ ;; nil - Use the default
+ ;; t - Use maximum
+ (cond ((eq level nil)
+ (set 'font-lock-keywords erlang-font-lock-keywords))
+ ((eq level 1)
+ (set 'font-lock-keywords erlang-font-lock-keywords-1))
+ ((eq level 2)
+ (set 'font-lock-keywords erlang-font-lock-keywords-2))
+ (t
+ (set 'font-lock-keywords erlang-font-lock-keywords-3))))
+
+ ;; Modern font-locks can handle the above much more elegant:
+ (set (make-local-variable 'font-lock-defaults)
+ '((erlang-font-lock-keywords erlang-font-lock-keywords-1
+ erlang-font-lock-keywords-2 erlang-font-lock-keywords-3)
+ nil nil ((?_ . "w")) erlang-beginning-of-clause
+ (font-lock-comment-start-regexp . "%")
+ (font-lock-mark-block-function . erlang-mark-clause))))
+
+
+
+;; Useful when definig yout own keywords.
+(defun erlang-font-lock-set-face (ks &rest faces)
+ "Replace the face components in a list of keywords.
+
+The first argument, KS, is a list of keywords. The rest of the
+arguments are expressions to replace the face information with. The
+first expression replaces the face of the first keyword, the second
+expression the second keyword etc.
+
+Should an expression be nil, the face of the corresponding keyword is
+not changed.
+
+Should fewer expressions than keywords be given, the last expression
+is used for all remaining keywords.
+
+Normally, the expressions are just atoms representing the new face.
+They could however be more complex, returning different faces in
+different situations.
+
+This function does only handle keywords with elements on the forms:
+ (REGEXP NUMBER FACE)
+ (REGEXP NUMBER FACE OVERWRITE)
+
+This could be used when defining your own special font-lock setup, e.g:
+
+\(setq my-font-lock-keywords
+ (append erlang-font-lock-keywords-func
+ erlang-font-lock-keywords-dollar
+ (erlang-font-lock-set-face
+ erlang-font-lock-keywords-macros 'my-neon-green-face)
+ (erlang-font-lock-set-face
+ erlang-font-lock-keywords-lc 'my-deep-red 'my-light-red)
+ erlang-font-lock-keywords-attr))
+
+For a more elaborate example, please see the beginning of the file
+`erlang.el'."
+ (let ((res '()))
+ (while ks
+ (let* ((regexp (car (car ks)))
+ (number (car (cdr (car ks))))
+ (new-face (if (and faces (car faces))
+ (car faces)
+ (car (cdr (cdr (car ks))))))
+ (overwrite (car (cdr (cdr (cdr (car ks))))))
+ (new-keyword (list regexp number new-face)))
+ (if overwrite (nconc new-keyword (list overwrite)))
+ (setq res (cons new-keyword res))
+ (setq ks (cdr ks))
+ (if (and faces (cdr faces))
+ (setq faces (cdr faces)))))
+ (nreverse res)))
+
+
+(defun erlang-font-lock-level-0 ()
+ ;; DocStringOrig: font-cmd
+ "Fontify current buffer. Level ranges from 0 (off) to 3 (Christmas Tree).
+
+The following fontification level exists:
+ 0 - No fontification
+ 1 - Function headers, reserved keywords, strings and comments.
+ 2 - Bifs, guards and `single quotes'.
+ 3 - Variables, macros and records.
+
+To automatically activate font lock mode, place the following lines
+in your ~/.emacs file:
+
+\(defun my-erlang-mode-hook ()
+ (cond (window-system
+ (font-lock-mode 1))))
+\(add-hook 'erlang-mode-hook 'my-erlang-mode-hook)
+\(setq font-lock-maximum-decoration t)"
+ (interactive)
+ (font-lock-mode 0))
+
+
+(defun erlang-font-lock-level-1 ()
+ ;; DocStringCopy: font-cmd
+ "Fontify current buffer. Level ranges from 0 (off) to 3 (Christmas Tree).
+
+The following fontification level exists:
+ 0 - No fontification
+ 1 - Function headers, reserved keywords, strings and comments.
+ 2 - Bifs, guards and `single quotes'.
+ 3 - Variables, macros and records.
+
+To automatically activate font lock mode, place the following lines
+in your ~/.emacs file:
+
+\(defun my-erlang-mode-hook ()
+ (cond (window-system
+ (font-lock-mode 1))))
+\(add-hook 'erlang-mode-hook 'my-erlang-mode-hook)
+\(setq font-lock-maximum-decoration t)"
+ (interactive)
+ (require 'font-lock)
+ (set 'font-lock-keywords erlang-font-lock-keywords-1)
+ (font-lock-mode 1)
+ (funcall (symbol-function 'font-lock-fontify-buffer)))
+
+
+(defun erlang-font-lock-level-2 ()
+ ;; DocStringCopy: font-cmd
+ "Fontify current buffer. Level ranges from 0 (off) to 3 (Christmas Tree).
+
+The following fontification level exists:
+ 0 - No fontification
+ 1 - Function headers, reserved keywords, strings and comments.
+ 2 - Bifs, guards and `single quotes'.
+ 3 - Variables, macros and records.
+
+To automatically activate font lock mode, place the following lines
+in your ~/.emacs file:
+
+\(defun my-erlang-mode-hook ()
+ (cond (window-system
+ (font-lock-mode 1))))
+\(add-hook 'erlang-mode-hook 'my-erlang-mode-hook)
+\(setq font-lock-maximum-decoration t)"
+ (interactive)
+ (require 'font-lock)
+ (set 'font-lock-keywords erlang-font-lock-keywords-2)
+ (font-lock-mode 1)
+ (funcall (symbol-function 'font-lock-fontify-buffer)))
+
+
+(defun erlang-font-lock-level-3 ()
+ ;; DocStringCopy: font-cmd
+ "Fontify current buffer. Level ranges from 0 (off) to 3 (Christmas Tree).
+
+The following fontification level exists:
+ 0 - No fontification
+ 1 - Function headers, reserved keywords, strings and comments.
+ 2 - Bifs, guards and `single quotes'.
+ 3 - Variables, macros and records.
+
+To automatically activate font lock mode, place the following lines
+in your ~/.emacs file:
+
+\(defun my-erlang-mode-hook ()
+ (cond (window-system
+ (font-lock-mode 1))))
+\(add-hook 'erlang-mode-hook 'my-erlang-mode-hook)
+\(setq font-lock-maximum-decoration t)"
+ (interactive)
+ (require 'font-lock)
+ (set 'font-lock-keywords erlang-font-lock-keywords-3)
+ (font-lock-mode 1)
+ (funcall (symbol-function 'font-lock-fontify-buffer)))
+
+
+(defun erlang-menu-init ()
+ "Init menus for Erlang mode.
+
+The variable `erlang-menu-items' contain a description of the Erlang
+mode menu. Normally, the list contains atoms, representing variables
+bound to pieces of the menu.
+
+Personal extentions could be added to `erlang-menu-personal-items'.
+
+Should any variable describing the menu configuration, this function
+should be called."
+ (erlang-menu-install "Erlang" erlang-menu-items erlang-mode-map t))
+
+
+(defun erlang-menu-install (name items keymap &optional popup)
+ "Install a menu on Emacs 19 or XEmacs based on an abstract description.
+
+NAME is the name of the menu.
+
+ITEMS is a list. The elements are either nil representing a horisontal
+line or a list with two or three elements. The first is the name of
+the menu item, the second the function to call, or a submenu, on the
+same same form as ITEMS. The third optional element is an expression
+which is evaluated every time the menu is displayed. Should the
+expression evaluate to nil the menu item is ghosted.
+
+KEYMAP is the keymap to add to menu to. (When using XEmacs, the menu
+will only be visible when this meny is the global, the local, or an
+activated minor mode keymap.)
+
+If POPUP is non-nil, the menu is bound to the XEmacs `mode-popup-menu'
+variable, i.e. it will popup when pressing the right mouse button.
+
+Please see the variable `erlang-menu-base-items'."
+ (cond (erlang-xemacs-p
+ (let ((menu (erlang-menu-xemacs name items keymap)))
+ ;; We add the menu to the global menubar.
+ ;;(funcall (symbol-function 'set-buffer-menubar)
+ ;; (symbol-value 'current-menubar))
+ (funcall (symbol-function 'add-submenu) nil menu)
+ (setcdr erlang-xemacs-popup-menu (cdr menu))
+ (if (and popup (boundp 'mode-popup-menu))
+ (funcall (symbol-function 'set)
+ 'mode-popup-menu erlang-xemacs-popup-menu))))
+ ((>= erlang-emacs-major-version 19)
+ (define-key keymap (vector 'menu-bar (intern name))
+ (erlang-menu-make-keymap name items)))
+ (t nil)))
+
+
+(defun erlang-menu-make-keymap (name items)
+ "Build a menu for Emacs 19."
+ (let ((menumap (funcall (symbol-function 'make-sparse-keymap)
+ name))
+ (count 0)
+ id def first second third)
+ (setq items (reverse items))
+ (while items
+ ;; Replace any occurence of atoms by their value.
+ (while (and items (atom (car items)) (not (null (car items))))
+ (if (and (boundp (car items))
+ (listp (symbol-value (car items))))
+ (setq items (append (reverse (symbol-value (car items)))
+ (cdr items)))
+ (setq items (cdr items))))
+ (setq first (car-safe (car items)))
+ (setq second (car-safe (cdr-safe (car items))))
+ (setq third (car-safe (cdr-safe (cdr-safe (car items)))))
+ (cond ((null first)
+ (setq count (+ count 1))
+ (setq id (intern (format "separator-%d" count)))
+ (setq def '("--" . nil)))
+ ((and (consp second) (eq (car second) 'lambda))
+ (setq count (+ count 1))
+ (setq id (intern (format "lambda-%d" count)))
+ (setq def (cons first second)))
+ ((symbolp second)
+ (setq id second)
+ (setq def (cons first second)))
+ (t
+ (setq count (+ count 1))
+ (setq id (intern (format "submenu-%d" count)))
+ (setq def (erlang-menu-make-keymap first second))))
+ (define-key menumap (vector id) def)
+ (if third
+ (put id 'menu-enable third))
+ (setq items (cdr items)))
+ (cons name menumap)))
+
+
+(defun erlang-menu-xemacs (name items &optional keymap)
+ "Build a menu for XEmacs."
+ (let ((res '())
+ first second third entry)
+ (while items
+ ;; Replace any occurence of atoms by their value.
+ (while (and items (atom (car items)) (not (null (car items))))
+ (if (and (boundp (car items))
+ (listp (symbol-value (car items))))
+ (setq items (append (reverse (symbol-value (car items)))
+ (cdr items)))
+ (setq items (cdr items))))
+ (setq first (car-safe (car items)))
+ (setq second (car-safe (cdr-safe (car items))))
+ (setq third (car-safe (cdr-safe (cdr-safe (car items)))))
+ (cond ((null first)
+ (setq res (cons "------" res)))
+ ((symbolp second)
+ (setq res (cons (vector first second (or third t)) res)))
+ ((and (consp second) (eq (car second) 'lambda))
+ (setq res (cons (vector first (list 'call-interactively second)
+ (or third t)) res)))
+ (t
+ (setq res (cons (cons first
+ (cdr (erlang-menu-xemacs
+ first second)))
+ res))))
+ (setq items (cdr items)))
+ (setq res (reverse res))
+ ;; When adding a menu to a minor-mode keymap under Emacs 19,
+ ;; it disappears when the mode is disabled. The expression
+ ;; generated below imitates this behaviour.
+ ;; (This could be expressed much clearer using backquotes,
+ ;; but I don't want to pull in every package.)
+ (if keymap
+ (let ((expr (list 'or
+ (list 'eq keymap 'global-map)
+ (list 'eq keymap (list 'current-local-map))
+ (list 'symbol-value
+ (list 'car-safe
+ (list 'rassq
+ keymap
+ 'minor-mode-map-alist))))))
+ (setq res (cons ':included (cons expr res)))))
+ (cons name res)))
+
+
+(defun erlang-menu-substitute (items alist)
+ "Substitute functions in menu described by ITEMS.
+
+The menu ITEMS is updated destructively.
+
+ALIST is list of pairs where the car is the old function and cdr the new."
+ (let (first second pair)
+ (while items
+ (setq first (car-safe (car items)))
+ (setq second (car-safe (cdr-safe (car items))))
+ (cond ((null first))
+ ((symbolp second)
+ (setq pair (and second (assq second alist)))
+ (if pair
+ (setcar (cdr (car items)) (cdr pair))))
+ ((and (consp second) (eq (car second) 'lambda)))
+ (t
+ (erlang-menu-substitute second alist)))
+ (setq items (cdr items)))))
+
+
+(defun erlang-menu-add-above (entry above items)
+ "Add menu ENTRY above menu entry ABOVE in menu ITEMS.
+Do nothing if the items already should be in the menu.
+Should ABOVE not be in the list, the entry is added at
+the bottom of the menu.
+
+The new menu is returned. No guarantee is given that the original
+menu is left unchanged.
+
+The equality test is performed by `eq'.
+
+Example: (erlang-menu-add-above 'my-erlang-menu-items
+ 'erlang-menu-man-items)"
+ (erlang-menu-add-below entry above items t))
+
+
+(defun erlang-menu-add-below (entry below items &optional above-p)
+ "Add menu ENTRY below menu items BELOW in the Erlang menu.
+Do nothing if the items already should be in the menu.
+Should BELOW not be in the list, items is added at the bottom
+of the menu.
+
+The new menu is returned. No guarantee is given that the original
+menu is left unchanged.
+
+The equality test is performed by `eq'.
+
+Example:
+
+\(setq erlang-menu-items
+ (erlang-menu-add-below 'my-erlang-menu-items
+ 'erlang-menu-base-items
+ erlang-menu-items))"
+ (if (memq entry items)
+ items ; Return the original menu.
+ (let ((head '())
+ (done nil)
+ res)
+ (while (not done)
+ (cond ((null items)
+ (setq res (append head (list entry)))
+ (setq done t))
+ ((eq below (car items))
+ (setq res
+ (if above-p
+ (append head (cons entry items))
+ (append head (cons (car items)
+ (cons entry (cdr items))))))
+ (setq done t))
+ (t
+ (setq head (append head (list (car items))))
+ (setq items (cdr items)))))
+ res)))
+
+(defun erlang-menu-delete (entry items)
+ "Delete ENTRY from menu ITEMS.
+
+The new menu is returned. No guarantee is given that the original
+menu is left unchanged."
+ (delq entry items))
+
+;; Man code:
+
+(defun erlang-man-init ()
+ "Add menus containing the manual pages of the Erlang.
+
+The variable `erlang-man-dirs' contains entries describing
+the location of the manual pages."
+ (interactive)
+ (if erlang-man-inhibit
+ ()
+ (setq erlang-menu-man-items
+ '(nil
+ ("Man - Function" erlang-man-function)))
+ (if erlang-man-dirs
+ (setq erlang-menu-man-items
+ (append erlang-menu-man-items
+ (erlang-man-make-top-menu erlang-man-dirs))))
+ (setq erlang-menu-items
+ (erlang-menu-add-above 'erlang-menu-man-items
+ 'erlang-menu-version-items
+ erlang-menu-items))
+ (erlang-menu-init)))
+
+
+(defun erlang-man-uninstall ()
+ "Remove the man pages from the Erlang mode."
+ (interactive)
+ (setq erlang-menu-items
+ (erlang-menu-delete 'erlang-menu-man-items erlang-menu-items))
+ (erlang-menu-init))
+
+
+;; The man menu is a hierarchal structure, with the manual sections
+;; at the top, described by `erlang-man-dirs'. The next level could
+;; either be the manual pages if not to many, otherwise it is an index
+;; menu whose submenus will contain up to `erlang-man-max-menu-size'
+;; manual pages.
+
+(defun erlang-man-make-top-menu (dir-list)
+ "Create one menu entry per element of DIR-LIST.
+The format is described in the documentation of `erlang-man-dirs'."
+ (let ((menu '())
+ dir)
+ (while dir-list
+ (setq dir (cond ((nth 2 (car dir-list))
+ ;; Relative to `erlang-root-dir'.
+ (and (stringp erlang-root-dir)
+ (concat erlang-root-dir (nth 1 (car dir-list)))))
+ (t
+ ;; Absolute
+ (nth 1 (car dir-list)))))
+ (if (and dir
+ (file-readable-p dir))
+ (setq menu (cons (list (car (car dir-list))
+ (erlang-man-make-middle-menu
+ (erlang-man-get-files dir)))
+ menu)))
+ (setq dir-list (cdr dir-list)))
+ ;; Should no menus be found, generate a menu item which
+ ;; will display a help text, when selected.
+ (if menu
+ (nreverse menu)
+ '(("Man Pages"
+ (("Error! Why?" erlang-man-describe-error)))))))
+
+
+;; Should the menu be to long, let's split it into a number of
+;; smaller menus. Warning, this code contains beatiful
+;; destructive operations!
+(defun erlang-man-make-middle-menu (filelist)
+ "Create the second level menu from FILELIST.
+
+Should the list be longer than `erlang-man-max-menu-size', a tree of
+menus is created."
+ (if (<= (length filelist) erlang-man-max-menu-size)
+ (erlang-man-make-menu filelist)
+ (let ((menu '())
+ (filelist (copy-sequence filelist))
+ segment submenu pair)
+ (while filelist
+ (setq pair (nthcdr (- erlang-man-max-menu-size 1) filelist))
+ (setq segment filelist)
+ (if (null pair)
+ (setq filelist nil)
+ (setq filelist (cdr pair))
+ (setcdr pair nil))
+ (setq submenu (erlang-man-make-menu segment))
+ (setq menu (cons (list (concat (car (car submenu))
+ " -- "
+ (car (car (reverse submenu))))
+ submenu)
+ menu)))
+ (nreverse menu))))
+
+
+(defun erlang-man-make-menu (filelist)
+ "Make a leaf menu based on FILELIST."
+ (let ((menu '())
+ item)
+ (while filelist
+ (setq item (erlang-man-make-menu-item (car filelist)))
+ (if item
+ (setq menu (cons item menu)))
+ (setq filelist (cdr filelist)))
+ (nreverse menu)))
+
+
+(defun erlang-man-make-menu-item (file)
+ "Create a menu item containing the name of the man page."
+ (and (string-match ".*/\\([^/]+\\)\\.[^.]$" file)
+ (let ((page (substring file (match-beginning 1) (match-end 1))))
+ (list (capitalize page)
+ (list 'lambda '()
+ '(interactive)
+ (list 'funcall 'erlang-man-display-function
+ file))))))
+
+
+(defun erlang-man-get-files (dir)
+ "Return files in directory DIR."
+ (directory-files dir t ".*\\.[0-9]\\'"))
+
+
+(defun erlang-man-module (&optional module)
+ "Find manual page for MODULE, defaults to module of function under point.
+This function is aware of imported functions."
+ (interactive
+ (list (let* ((mod (car-safe (erlang-get-function-under-point)))
+ (input (read-string
+ (format "Manual entry for module%s: "
+ (if (or (null mod) (string= mod ""))
+ ""
+ (format " (default %s)" mod))))))
+ (if (string= input "")
+ mod
+ input))))
+ (or module (setq module (car (erlang-get-function-under-point))))
+ (if (or (null module) (string= module ""))
+ (error "No Erlang module name given"))
+ (let ((dir-list erlang-man-dirs)
+ (pat (concat "\\b" (regexp-quote module) "\\.[^.]$"))
+ (file nil)
+ file-list)
+ (while (and dir-list (null file))
+ (setq file-list (erlang-man-get-files
+ (if (nth 2 (car dir-list))
+ (concat erlang-root-dir (nth 1 (car dir-list)))
+ (nth 1 (car dir-list)))))
+ (while (and file-list (null file))
+ (if (string-match pat (car file-list))
+ (setq file (car file-list)))
+ (setq file-list (cdr file-list)))
+ (setq dir-list (cdr dir-list)))
+ (if file
+ (funcall erlang-man-display-function file)
+ (error "No manual page for module %s found." module))))
+
+
+;; Warning, the function `erlang-man-function' is a hack!
+;; It links itself into the man code in a non-clean way. I have
+;; choosed to keep it since it provides a very useful functionality
+;; which is not possible to achive using a clean approach.
+;; / AndersL
+
+(defvar erlang-man-function-name nil
+ "Name of function for last `erlang-man-function' call.
+Used for commnication between `erlang-man-function' and the
+patch to `Man-notify-when-ready'.")
+
+(defun erlang-man-function (&optional name)
+ "Find manual page for NAME, where NAME is module:function.
+The entry for `function' is displayed.
+
+This function is aware of imported functions."
+ (interactive
+ (list (let* ((mod-func (erlang-get-function-under-point))
+ (mod (car-safe mod-func))
+ (func (nth 1 mod-func))
+ (input (read-string
+ (format
+ "Manual entry for `module:func' or `module'%s: "
+ (if (or (null mod) (string= mod ""))
+ ""
+ (format " (default %s:%s)" mod func))))))
+ (if (string= input "")
+ (if (and mod func)
+ (concat mod ":" func)
+ mod)
+ input))))
+ ;; Emacs 18 doesn't provide `man'...
+ (condition-case nil
+ (require 'man)
+ (error nil))
+ (let ((modname nil)
+ (funcname nil))
+ (cond ((null name)
+ (let ((mod-func (erlang-get-function-under-point)))
+ (setq modname (car-safe mod-func))
+ (setq funcname (nth 1 mod-func))))
+ ((string-match ":" name)
+ (setq modname (substring name 0 (match-beginning 0)))
+ (setq funcname (substring name (match-end 0) nil)))
+ ((stringp name)
+ (setq modname name)))
+ (if (or (null modname) (string= modname ""))
+ (error "No Erlang module name given"))
+ (cond ((fboundp 'Man-notify-when-ready)
+ ;; Emacs 19: The man command could possibly start an
+ ;; asyncronous process, i.e. we must hook ourselves into
+ ;; the system to be activated when the man-process
+ ;; terminates.
+ (if (null funcname)
+ ()
+ (erlang-man-patch-notify)
+ (setq erlang-man-function-name funcname))
+ (condition-case nil
+ (erlang-man-module modname)
+ (error (setq erlang-man-function-name nil))))
+ (t
+ (erlang-man-module modname)
+ (if funcname
+ (erlang-man-find-function
+ (or (get-buffer "*Manual Entry*") ; Emacs 18
+ (current-buffer)) ; XEmacs
+ funcname))))))
+
+
+;; Should the defadvice be at the top level, the package `advice' would
+;; be required. Now it is only required when this functionality
+;; is used. (Emacs 19 specific.)
+(defun erlang-man-patch-notify ()
+ "Patch the function `Man-notify-when-ready' to search for function.
+The variable `erlang-man-function-name' is assumed to be bound to
+the function name, or to nil.
+
+The reason for patching a function is that under Emacs 19, the man
+command is executed asynchronously."
+ (condition-case nil
+ (require 'advice)
+ ;; This should never happend since this is only called when
+ ;; running under Emacs 19.
+ (error (error (concat "This commands needs the package `advice', "
+ "please upgrade your Emacs."))))
+ (require 'man)
+ (defadvice Man-notify-when-ready
+ (after erlang-Man-notify-when-ready activate)
+ "Sets point at the documentation of the function name in
+erlang-man-function-name when the man-page is displayed."
+ (if erlang-man-function-name
+ (erlang-man-find-function (ad-get-arg 0) erlang-man-function-name))
+ (setq erlang-man-function-name nil)))
+
+
+(defun erlang-man-find-function (buf func)
+ "Find manual page for function in `erlang-man-function-name' in buffer BUF."
+ (if func
+ (let ((win (get-buffer-window buf)))
+ (if win
+ (progn
+ (set-buffer buf)
+ (goto-char (point-min))
+ (if (re-search-forward
+ (concat "^[ \t]+" func " ?(")
+ (point-max) t)
+ (progn
+ (forward-word -1)
+ (set-window-point win (point)))
+ (message "Could not find function `%s'" func)))))))
+
+
+(defun erlang-man-display (file)
+ "Display FILE as a `man' file.
+This is de default manual page display function.
+The variables `erlang-man-display-function' contains the function
+to be used."
+ ;; Emacs 18 doesn't `provide' man.
+ (condition-case nil
+ (require 'man)
+ (error nil))
+ (if file
+ (let ((process-environment (copy-sequence process-environment)))
+ (if (string-match "\\(.*\\)/man[^/]*/\\([^/]+\\)\\.[^.]$" file)
+ (let ((dir (substring file (match-beginning 1) (match-end 1)))
+ (page (substring file (match-beginning 2) (match-end 2))))
+ (if (fboundp 'setenv)
+ (setenv "MANPATH" dir)
+ ;; Emacs 18
+ (setq process-environment (cons (concat "MANPATH=" dir)
+ process-environment)))
+ (cond ((not (and (not erlang-xemacs-p)
+ (= erlang-emacs-major-version 19)
+ (< erlang-emacs-minor-version 29)))
+ (manual-entry page))
+ (t
+ ;; Emacs 19.28 and earlier versions of 19:
+ ;; The manual-entry command unconditionally prompts
+ ;; the user :-(
+ (funcall (symbol-function 'Man-getpage-in-background)
+ page))))
+ (error "Can't find man page for %s\n" file)))))
+
+
+(defun erlang-man-describe-error ()
+ "Describe why the manual pages weren't found."
+ (interactive)
+ (with-output-to-temp-buffer "*Erlang Man Error*"
+ (princ "Normally, this menu should contain Erlang manual pages.
+
+In order to find the manual pages, the variable `erlang-root-dir'
+should be bound to the name of the directory containing the Erlang
+installation. The name should not include the final slash.
+
+Practically, you should add a line on the following form to
+your ~/.emacs, or ask your system administrator to add it to
+the site init file:
+ (setq erlang-root-dir \"/the/erlang/root/dir/goes/here\")
+
+For example:
+ (setq erlang-root-dir \"/usr/local/erlang\")
+
+After installing the line, kill and restart Emacs, or restart Erlang
+mode with the command `M-x erlang-mode RET'.")))
+
+;; Skeleton code:
+
+;; This code is based on the package `tempo' which is part of modern
+;; Emacsen. (GNU Emacs 19.25 (?) and XEmacs 19.14.)
+
+(defun erlang-skel-init ()
+ "Generate the skeleton functions and menu items.
+The variable `erlang-skel' contains the name and descriptions of
+all skeletons.
+
+The skeleton routines are based on the `tempo' package. Should this
+package not be present, this function does nothing."
+ (interactive)
+ (condition-case nil
+ (require 'tempo)
+ (error t))
+ (if (featurep 'tempo)
+ (let ((skel erlang-skel)
+ (menu '()))
+ (while skel
+ (cond ((null (car skel))
+ (setq menu (cons nil menu)))
+ (t
+ (funcall (symbol-function 'tempo-define-template)
+ (concat "erlang-" (nth 1 (car skel)))
+ ;; The tempo template used contains an `include'
+ ;; function call only, hence changes to the
+ ;; variables describing the templates take effect
+ ;; immdiately.
+ (list (list 'erlang-skel-include (nth 2 (car skel))))
+ (nth 1 (car skel)))
+ (setq menu (cons (erlang-skel-make-menu-item
+ (car skel)) menu))))
+ (setq skel (cdr skel)))
+ (setq erlang-menu-skel-items
+ (list nil (list "Skeletons" (nreverse menu))))
+ (setq erlang-menu-items
+ (erlang-menu-add-above 'erlang-menu-skel-items
+ 'erlang-menu-version-items
+ erlang-menu-items))
+ (erlang-menu-init))))
+
+(defun erlang-skel-make-menu-item (skel)
+ (let ((func (intern (concat "tempo-template-erlang-" (nth 1 skel)))))
+ (cond ((null (nth 3 skel))
+ (list (car skel) func))
+ (t
+ (list (car skel)
+ (list 'lambda '()
+ '(interactive)
+ (list 'funcall
+ (list 'quote (nth 3 skel))
+ (list 'quote func))))))))
+
+;; Functions designed to be added to the skeleton menu.
+;; (Not normally used)
+(defun erlang-skel-insert (func)
+ "Insert skeleton generated by FUNC and goto first tempo mark."
+ (save-excursion (funcall func))
+ (funcall (symbol-function 'tempo-forward-mark)))
+
+(defun erlang-skel-header (func)
+ "Insert the header generated by FUNC at the beginning of the buffer."
+ (goto-char (point-min))
+ (save-excursion (funcall func))
+ (funcall (symbol-function 'tempo-forward-mark)))
+
+
+;; Functions used inside the skeleton descriptions.
+(defun erlang-skel-skip-blank ()
+ (skip-chars-backward " \t")
+ nil)
+
+(defun erlang-skel-include (&rest args)
+ "Include a template inside another template.
+
+Example of use, assuming that `erlang-skel-func' is defined:
+
+ (defvar foo-skeleton '(\"%%% New function:\"
+ (erlang-skel-include erlang-skel-func)))
+
+Techically, this function returns the `tempo' attribute`(l ...)' which
+can contain other `tempo' attributes. Please see the function
+`tempo-define-template' for a description of the `(l ...)' attribute."
+ (let ((res '())
+ entry)
+ (while args
+ (setq entry (car args))
+ (while entry
+ (setq res (cons (car entry) res))
+ (setq entry (cdr entry)))
+ (setq args (cdr args)))
+ (cons 'l (nreverse res))))
+
+(defun erlang-skel-separator (&optional percent)
+ "Return a comment separator."
+ (let ((percent (or percent 3)))
+ (concat (make-string percent ?%)
+ (make-string (- 70 percent) ?-)
+ "\n")))
+
+(defun erlang-skel-double-separator (&optional percent)
+ "Return a comment separator."
+ (let ((percent (or percent 3)))
+ (concat (make-string percent ?%)
+ (make-string (- 70 percent) ?=)
+ "\n")))
+
+(defun erlang-skel-dd-mmm-yyyy ()
+ "Return the current date as a string in \"DD Mon YYYY\" form.
+The first character of DD is space if the value is less than 10."
+ (let ((date (current-time-string)))
+ (format "%2d %s %s"
+ (string-to-int (substring date 8 10))
+ (substring date 4 7)
+ (substring date -4))))
+
+;; Indentation code:
+
+(defun erlang-indent-command (&optional whole-exp)
+ "Indent current line as Erlang code.
+With argument, indent any additional lines of the same clause
+rigidly along with this one."
+ (interactive "P")
+ (if whole-exp
+ ;; If arg, alwys indent this line as Erlang
+ ;; and shift remaining lines of clause the same amount.
+ (let ((shift-amt (erlang-indent-line))
+ beg end)
+ (save-excursion
+ (if erlang-tab-always-indent
+ (beginning-of-line))
+ (setq beg (point))
+ (erlang-end-of-clause 1)
+ (setq end (point))
+ (goto-char beg)
+ (forward-line 1)
+ (setq beg (point)))
+ (if (> end beg)
+ (indent-code-rigidly beg end shift-amt "\n")))
+ (if (and (not erlang-tab-always-indent)
+ (save-excursion
+ (skip-chars-backward " \t")
+ (not (bolp))))
+ (insert-tab)
+ (erlang-indent-line))))
+
+
+(defun erlang-indent-line ()
+ "Indent current line as Erlang code.
+Return the amount the indentation changed by."
+ (let ((pos (- (point-max) (point)))
+ indent beg
+ shift-amt)
+ (beginning-of-line 1)
+ (setq beg (point))
+ (skip-chars-forward " \t")
+ (cond ((looking-at "%")
+ (setq indent (funcall comment-indent-function))
+ (setq shift-amt (- indent (current-column))))
+ (t
+ (setq indent (erlang-calculate-indent))
+ (cond ((null indent)
+ (setq indent (current-indentation)))
+ ((eq indent t)
+ ;; This should never occur here.
+ (error "Erlang mode error"))
+ ((= (char-syntax (following-char)) ?\))
+ (setq indent (1- indent))))
+ (setq shift-amt (- indent (current-column)))))
+ (if (zerop shift-amt)
+ nil
+ (delete-region beg (point))
+ (indent-to indent))
+ ;; If initial point was within line's indentation, position
+ ;; after the indentation. Else stay at same point in text.
+ (if (> (- (point-max) pos) (point))
+ (goto-char (- (point-max) pos)))
+ shift-amt))
+
+
+(defun erlang-indent-region (beg end)
+ "Indent region of erlang code.
+
+This is automagically called by the user level function `indent-region'."
+ (interactive "r")
+ (save-excursion
+ (let ((case-fold-search nil)
+ (continue t)
+ (from-end (- (point-max) end))
+ indent-point ;; The beginning of the current line
+ indent ;; The indent amount
+ state)
+ (goto-char beg)
+ (beginning-of-line)
+ (setq indent-point (point))
+ (erlang-beginning-of-clause)
+ ;; Parse the Erlang code from the beginning of the clause to
+ ;; the beginning of the region.
+ (while (< (point) indent-point)
+ (setq state (erlang-partial-parse (point) indent-point state)))
+ ;; Indent every line in the region
+ (while continue
+ (goto-char indent-point)
+ (skip-chars-forward " \t")
+ (cond ((looking-at "%")
+ ;; Do not use our stack to help the user to customize
+ ;; comment indentation.
+ (setq indent (funcall comment-indent-function)))
+ ((looking-at "$")
+ ;; Don't indent empty lines.
+ (setq indent 0))
+ (t
+ (setq indent
+ (save-excursion
+ (erlang-calculate-stack-indent (point) state)))
+ (cond ((null indent)
+ (setq indent (current-indentation)))
+ ((eq indent t)
+ ;; This should never occur here.
+ (error "Erlang mode error"))
+ ((= (char-syntax (following-char)) ?\))
+ (setq indent (1- indent))))))
+ (if (zerop (- indent (current-column)))
+ nil
+ (delete-region indent-point (point))
+ (indent-to indent))
+ ;; Find the next line in the region
+ (goto-char indent-point)
+ (save-excursion
+ (forward-line 1)
+ (setq indent-point (point)))
+ (if (>= from-end (- (point-max) indent-point))
+ (setq continue nil)
+ (while (< (point) indent-point)
+ (setq state (erlang-partial-parse
+ (point) indent-point state))))))))
+
+
+(defun erlang-indent-current-buffer ()
+ "Indent current buffer as Erlang code."
+ (interactive)
+ (save-excursion
+ (save-restriction
+ (widen)
+ (erlang-indent-region (point-min) (point-max)))))
+
+
+(defun erlang-indent-function ()
+ "Indent current Erlang function."
+ (interactive)
+ (save-excursion
+ (let ((end (progn (erlang-end-of-function 1) (point)))
+ (beg (progn (erlang-beginning-of-function 1) (point))))
+ (erlang-indent-region beg end))))
+
+
+(defun erlang-indent-clause ()
+ "Indent current Erlang clause."
+ (interactive)
+ (save-excursion
+ (let ((end (progn (erlang-end-of-clause 1) (point)))
+ (beg (progn (erlang-beginning-of-clause 1) (point))))
+ (erlang-indent-region beg end))))
+
+
+(defmacro erlang-push (x stack) (list 'setq stack (list 'cons x stack)))
+(defmacro erlang-pop (stack) (list 'setq stack (list 'cdr stack)))
+;; Would much prefer to make caddr a macro but this clashes.
+(defun erlang-caddr (x) (car (cdr (cdr x))))
+
+
+(defun erlang-calculate-indent (&optional parse-start)
+ "Compute appropriate indentation for current line as Erlang code.
+Return nil if line starts inside string, t if in a comment."
+ (save-excursion
+ (let ((indent-point (point))
+ (case-fold-search nil)
+ (state nil))
+ (if parse-start
+ (goto-char parse-start)
+ (erlang-beginning-of-clause))
+ (while (< (point) indent-point)
+ (setq state (erlang-partial-parse (point) indent-point state)))
+ (erlang-calculate-stack-indent indent-point state))))
+
+(defun erlang-show-syntactic-information ()
+ "Show syntactic information for current line."
+
+ (interactive)
+
+ (save-excursion
+ (let ((starting-point (point))
+ (case-fold-search nil)
+ (state nil))
+ (erlang-beginning-of-clause)
+ (while (< (point) starting-point)
+ (setq state (erlang-partial-parse (point) starting-point state)))
+ (message "%S" state))))
+
+
+(defun erlang-partial-parse (from to &optional state)
+ "Parse Erlang syntax starting at FROM until TO, with an optional STATE.
+Value is list (stack token-start token-type in-what)."
+ (goto-char from) ; Start at the beginning
+ (erlang-skip-blank to)
+ (let ((cs (char-syntax (following-char)))
+ (stack (car state))
+ (token (point))
+ in-what)
+ (cond
+
+ ;; Done: Return previous state.
+ ((>= token to)
+ (setq token (nth 1 state))
+ (setq cs (nth 2 state))
+ (setq in-what (nth 3 state)))
+ ;; Word constituent: check and handle keywords.
+ ((= cs ?w)
+ (if (looking-at "\\(end\\|after\\)[^_a-zA-Z0-9]")
+ ;; Must pop top icr layer, `after' will push a new
+ ;; layer next.
+ (progn
+ (while (and stack (eq (car (car stack)) '->))
+ (erlang-pop stack))
+ (if (and stack (memq (car (car stack)) '(icr begin)))
+ (erlang-pop stack))))
+ (cond ((looking-at
+ "\\(if\\|case\\|receive\\|after\\)[^_a-zA-Z0-9]")
+ ;; Must push a new icr (if/case/receive) layer.
+ (erlang-push (list 'icr token (current-column)) stack))
+ ((looking-at "\\(fun\\)[^_a-zA-Z0-9]")
+ ;; Puch a new icr layer if we are defining a `fun'
+ ;; expression, not when we are refering an existing
+ ;; function.
+ (if (save-excursion
+ (goto-char (match-end 1))
+ (erlang-skip-blank to)
+ (eq (following-char) ?\())
+ (erlang-push (list 'icr token (current-column)) stack)))
+ ((looking-at "\\(begin\\|query\\)[^_a-zA-Z0-9]")
+ (erlang-push (list 'begin token (current-column)) stack))
+ ((looking-at "when[^_a-zA-Z0-9]")
+ (erlang-push (list 'when token (current-column)) stack)))
+ (forward-sexp 1))
+
+ ;; String: Try to skip over it. (Catch error if not complete.)
+ ((= cs ?\")
+ (condition-case nil
+ (progn
+ (forward-sexp 1)
+ (if (> (point) to)
+ (progn
+ (setq in-what 'string)
+ (goto-char to))))
+ (error
+ (setq in-what 'string)
+ (goto-char to))))
+
+ ;; Symbol constituent, punctuation, or expression prefix?
+ ((memq cs '(?. ?_ ?'))
+ (cond
+
+ ;; Clause end
+ ((= (following-char) ?\;)
+ (if (and stack (eq (car (car stack)) '->))
+ (erlang-pop stack))
+ (forward-char 1))
+
+ ;; Function end
+ ((looking-at "\\.\\(\\s \\|\n\\|\\s<\\)")
+ (setq stack nil)
+ (forward-char 1))
+
+ ;; Function head
+ ((looking-at "->\\|:-")
+ (if (and stack (eq (car (car stack)) 'when))
+ (erlang-pop stack))
+ (erlang-push (list '-> token (current-column)) stack)
+ (forward-char 2))
+
+ ;; List-comprehension divider
+ ((looking-at "||")
+ (erlang-push (list '|| token (current-column)) stack)
+ (forward-char 2))
+
+ ;; Bit-syntax open paren
+ ((looking-at "<<")
+ (erlang-push (list '\( token (current-column)) stack)
+ (forward-char 2))
+
+ ;; Bbit-syntax close paren
+ ((looking-at ">>")
+ (while (memq (car (car stack)) '(|| ->))
+ (erlang-pop stack))
+ (cond ((eq (car (car stack)) '\()
+ (erlang-pop stack))
+ ((memq (car (car stack)) '(icr begin))
+ (error "Missing `end'"))
+ (t
+ (error "Unbalanced parentheses")))
+ (forward-char 2))
+
+ ;; Macro
+ ((= (following-char) ??)
+ ;; Skip over macro name and any following whitespace.
+ (forward-word 1)
+ (skip-syntax-forward "-" to)
+ ;; Macro might have an argument list. Skip it too.
+ (when (= (following-char) ?\()
+ (forward-list 1)))
+
+ ;; Other punctuation: Skip over it and any following punctuation
+ ((= cs ?.)
+ ;; Skip over all characters in the operand.
+ (skip-syntax-forward "."))
+
+ ;; Other char: Skip over it.
+ (t
+ (forward-char 1))))
+
+ ;; Open parenthesis
+ ((= cs ?\()
+ (erlang-push (list '\( token (current-column)) stack)
+ (forward-char 1))
+
+ ;; Close parenthesis
+ ((= cs ?\))
+ (while (memq (car (car stack)) '(|| ->))
+ (erlang-pop stack))
+ (cond ((eq (car (car stack)) '\()
+ (erlang-pop stack))
+ ((memq (car (car stack)) '(icr begin))
+ (error "Missing `end'"))
+ (t
+ (error "Unbalanced parenthesis")))
+ (forward-char 1))
+
+ ;; Character quote: Skip it and the quoted char.
+ ((= cs ?/)
+ (forward-char 2))
+
+ ;; Character escape: Skip it and the escape sequence.
+ ((= cs ?\\)
+ (forward-char 1)
+ (skip-syntax-forward "w"))
+
+ ;; Everything else
+ (t
+ (forward-char 1)))
+ (list stack token cs in-what)))
+
+
+(defun erlang-calculate-stack-indent (indent-point state)
+ "From the given last position and state (stack) calculate indentation.
+Return nil if inside string, t if in a comment."
+ (let* ((stack (and state (car state)))
+ (token (nth 1 state))
+ (stack-top (and stack (car stack))))
+ (cond ((null state) ;No state
+ 0)
+ ((nth 3 state)
+ ;; Return nil or t.
+ (eq (nth 3 state) 'comment))
+ ((null stack)
+ (if (looking-at "when[^_a-zA-Z0-9]")
+ erlang-indent-guard
+ 0))
+ ((eq (car stack-top) '\()
+ ;; Element of list, tuple or part of an expression,
+ (if (null erlang-argument-indent)
+ ;; indent to next column.
+ (1+ (nth 2 stack-top))
+ (goto-char (nth 1 stack-top))
+ (cond ((looking-at "[({]\\s *\\($\\|%\\)")
+ ;; Line ends with parenthesis.
+ (+ (erlang-indent-find-preceding-expr)
+ erlang-argument-indent))
+ (t
+ ;; Indent to the same column as the first
+ ;; argument.
+ (goto-char (1+ (nth 1 stack-top)))
+ (skip-chars-forward " \t")
+ (current-column)))))
+ ((eq (car stack-top) 'icr)
+ ;; The default indentation is the column of the option
+ ;; directly following the keyword. (This does not apply to
+ ;; `case'.) Should no option be on the same line, the
+ ;; indentation is the indentation of the keyword +
+ ;; `erlang-indent-level'.
+ ;;
+ ;; `after' should be indentated to the save level as the
+ ;; corresponding receive.
+ (if (looking-at "after[^_a-zA-Z0-9]")
+ (nth 2 stack-top)
+ (save-excursion
+ (goto-char (nth 1 stack-top))
+ (if (looking-at "case[^_a-zA-Z0-9]")
+ (+ (nth 2 stack-top) erlang-indent-level)
+ (skip-chars-forward "a-z")
+ (skip-chars-forward " \t")
+ (if (memq (following-char) '(?% ?\n))
+ (+ (nth 2 stack-top) erlang-indent-level)
+ (current-column))))))
+ ;; Real indentation, where operators create extra indentation etc.
+ ((memq (car stack-top) '(-> || begin))
+ (goto-char (nth 1 stack-top))
+ ;; Check if there is more code after the '->' on the
+ ;; same line. If so use this indentation as base, else
+ ;; use parent indentation + 2 * level as base.
+ (let ((off erlang-indent-level)
+ (skip 2))
+ (cond ((null (cdr stack))) ; Top level in function.
+ ((eq (car stack-top) 'begin)
+ (setq skip 5))
+ ((eq (car stack-top) '->)
+ (setq off (* 2 erlang-indent-level))))
+ (let ((base (erlang-indent-find-base stack indent-point off skip)))
+ ;; Look at last thing to see how we are to move relative
+ ;; to the base.
+ (goto-char token)
+ (cond ((looking-at "||\\|,\\|->\\|:-")
+ base)
+ ((erlang-at-keyword)
+ (+ (current-column) erlang-indent-level))
+ ((or (= (char-syntax (following-char)) ?.)
+ (erlang-at-operator))
+ (+ base erlang-indent-level))
+ (t
+ (goto-char indent-point)
+ (cond ((memq (following-char) '(?\( ?{))
+ ;; Function application or record.
+ (+ (erlang-indent-find-preceding-expr)
+ erlang-argument-indent))
+ ;; Empty line, or end; treat it as the end of
+ ;; the block. (Here we have a choice: should
+ ;; the user be forced to reindent continued
+ ;; lines, or should the "end" be reindented?)
+ ((looking-at "\\(end\\|after\\)[^_a-zA-Z0-9]\\|$")
+ (if (eq (car (car stack)) '->)
+ (erlang-pop stack))
+ (if stack
+ (erlang-caddr (car stack))
+ 0))
+ ;; Avoid trating comments a continued line.
+ ((= (following-char) ?%)
+ base)
+ ;; Continued line (e.g. line beginning
+ ;; with an operator.)
+ (t (+ base erlang-indent-level))))))))
+ ((eq (car stack-top) 'when)
+ (goto-char (nth 1 stack-top))
+ (if (looking-at "when\\s *\\($\\|%\\)")
+ (progn
+ (erlang-pop stack)
+ (if (and stack (eq (nth 0 (car stack)) 'icr))
+ (progn
+ (goto-char (nth 1 (car stack)))
+ (+ (nth 2 (car stack)) erlang-indent-guard
+ ;; receive XYZ or receive
+ ;; XYZ
+ (if (looking-at "[a-z]+\\s *\\($\\|%\\)")
+ erlang-indent-level
+ (* 2 erlang-indent-level))))
+ erlang-indent-guard))
+ ;; "when" is followed by code, let's indent to the same
+ ;; column.
+ (forward-char 4) ; Skip "when"
+ (skip-chars-forward " \t")
+ (current-column))))))
+
+
+(defun erlang-indent-find-base (stack indent-point &optional offset skip)
+ "Find the base column for current stack."
+ (or skip (setq skip 2))
+ (or offset (setq offset erlang-indent-level))
+ (save-excursion
+ (let* ((stack-top (car stack)))
+ (goto-char (nth 1 stack-top))
+ (forward-char skip)
+ (if (looking-at "\\s *\\($\\|%\\)")
+ (progn
+ (if (memq (car stack-top) '(-> ||))
+ (erlang-pop stack))
+ ;; Take parent identation + offset,
+ ;; else just erlang-indent-level if no parent
+ (if stack
+ (+ (erlang-caddr (car stack))
+ offset)
+ erlang-indent-level))
+ (erlang-skip-blank indent-point)
+ (current-column)))))
+
+
+;; Does not handle `begin' .. `end'.
+(defun erlang-indent-find-preceding-expr ()
+ "Return the first column of the preceding expression.
+This assumes that the preceding expression is either simple
+\(i.e. an atom) or parenthesized."
+ (save-excursion
+ (forward-sexp -1)
+ (let ((col (current-column)))
+ (skip-chars-backward " \t")
+ ;; Needed to match the colon in "'foo':'bar'".
+ (if (not (memq (preceding-char) '(?# ?:)))
+ col
+ (backward-char 1)
+ (forward-sexp -1)
+ (current-column)))))
+
+
+(defun erlang-skip-blank (&optional lim)
+ "Skip over whitespace and comments until limit reached."
+ (or lim (setq lim (point-max)))
+ (let (stop)
+ (while (and (not stop) (< (point) lim))
+ (cond ((= (following-char) ?%)
+ (skip-chars-forward "^\n" lim))
+ ((= (following-char) ?\n)
+ (skip-chars-forward "\n" lim))
+ ((looking-at "\\s ")
+ (if (re-search-forward "\\S " lim 'move)
+ (forward-char -1)))
+ (t
+ (setq stop t))))
+ stop))
+
+(defun erlang-at-keyword ()
+ "Are we looking at an Erlang keyword which will increase indentation?"
+ (looking-at (concat "\\(when\\|if\\|fun\\|case\\|begin\\|query\\|"
+ "of\\|receive\\|after\\|catch\\)[^_a-zA-Z0-9]")))
+
+(defun erlang-at-operator ()
+ "Are we looking at an Erlang operator?"
+ (looking-at
+ "\\(bnot\\|div\\|mod\\|band\\|bor\\|bxor\\|bsl\\|bsr\\)[^_a-zA-Z0-9]"))
+
+(defun erlang-comment-indent ()
+ "Compute erlang comment indentation.
+
+Used both by `indent-for-comment' and the erlang specific indentation
+commands."
+ (cond ((looking-at "%%%") 0)
+ ((looking-at "%%")
+ (or (erlang-calculate-indent)
+ (current-indentation)))
+ (t
+ (save-excursion
+ (skip-chars-backward " \t")
+ (max (if (bolp) 0 (1+ (current-column)))
+ comment-column)))))
+
+;;; Erlang movement commands
+
+;; All commands below work as movement commands. I.e. if the point is
+;; at the end of the clause, and the command `erlang-end-of-clause' is
+;; executed, the point is moved to the end of the NEXT clause. (This
+;; mimics the behaviour of `end-of-defun'.)
+;;
+;; Personally I would like to rewrite them to be "pure", and add a set
+;; of movement functions, like `erlang-next-clause',
+;; `erlang-previous-clause', and the same for functions.
+;;
+;; The current implementation makes it hopeless to use the functions as
+;; subroutines in more complex commands. /andersl
+
+(defun erlang-beginning-of-clause (&optional arg)
+ "Move backward to previous start of clause.
+With argument, do this that many times.
+Return t unless search stops due to end of buffer."
+ (interactive "p")
+ (or arg (setq arg 1))
+ (if (< arg 0)
+ ;; Step back to the end of the previous line, unless we are at
+ ;; the beginning of the buffer. The reason for this move is
+ ;; that the regexp below includes the last character of the
+ ;; previous line.
+ (if (bobp)
+ (or (looking-at "\n")
+ (forward-char 1))
+ (forward-char -1)
+ (if (looking-at "\\`\n")
+ (forward-char 1))))
+ ;; The regexp matches a function header that isn't
+ ;; included in a string.
+ (and (re-search-forward "\\(\\`\\|\\`\n\\|[^\\]\n\\)\\([a-z]\\|'\\|-\\)"
+ nil 'move (- arg))
+ (let ((beg (match-beginning 2)))
+ (and beg (goto-char beg))
+ t)))
+
+(defun erlang-end-of-clause (&optional arg)
+ "Move to the end of the current clause.
+With argument, do this that many times."
+ (interactive "p")
+ (or arg (setq arg 1))
+ (while (and (looking-at "[ \t]*[%\n]")
+ (zerop (forward-line 1))))
+ ;; Move to the next clause.
+ (erlang-beginning-of-clause (- arg))
+ (beginning-of-line) ;; Just to be sure...
+ (let ((continue t))
+ (while (and (not (bobp)) continue)
+ (forward-line -1)
+ (skip-chars-forward " \t")
+ (if (looking-at "[%\n]")
+ nil
+ (end-of-line)
+ (setq continue nil)))))
+
+(defun erlang-mark-clause ()
+ "Put mark at end of clause, point at beginning."
+ (interactive)
+ (push-mark (point))
+ (erlang-end-of-clause 1)
+ ;; Sets the region. In Emacs 19 and XEmacs, we wants to activate
+ ;; the region.
+ (condition-case nil
+ (push-mark (point) nil t)
+ (error (push-mark (point))))
+ (erlang-beginning-of-clause 1)
+ ;; The above function deactivates the mark.
+ (if (boundp 'deactivate-mark)
+ (funcall (symbol-function 'set) 'deactivate-mark nil)))
+
+(defun erlang-beginning-of-function (&optional arg)
+ "Move backward to previous start of function.
+With positive argument, do this that many times.
+With negative argument, search forward.
+
+Return t unless search stops due to end of buffer."
+ (interactive "p")
+ (or arg (setq arg 1))
+ (cond
+ ;; Search backward
+ ((> arg 0)
+ (while (and (> arg 0)
+ (and (erlang-beginning-of-clause 1)
+ (let ((start (point))
+ (name (erlang-name-of-function))
+ (arity (erlang-get-function-arity)))
+ ;; Note: "arity" is nil for e.g. "-import", hence
+ ;; two "-import" clauses are not considered to
+ ;; be part of the same function.
+ (while (and (erlang-beginning-of-clause 1)
+ (string-equal name
+ (erlang-name-of-function))
+ arity
+ (equal arity
+ (erlang-get-function-arity)))
+ (setq start (point)))
+ (goto-char start)
+ t)))
+ (setq arg (1- arg))))
+ ;; Search forward
+ ((< arg 0)
+ (end-of-line)
+ (erlang-beginning-of-clause 1)
+ ;; Step -arg functions forward.
+ (while (and (< arg 0)
+ ;; Step one function forward, or stop if the end of
+ ;; the buffer was reached. Return t if we found the
+ ;; function.
+ (let ((name (erlang-name-of-function))
+ (arity (erlang-get-function-arity))
+ (found (erlang-beginning-of-clause -1)))
+ (while (and found
+ (string-equal name (erlang-name-of-function))
+ arity
+ (equal arity
+ (erlang-get-function-arity)))
+ (setq found (erlang-beginning-of-clause -1)))
+ found))
+ (setq arg (1+ arg)))))
+ (zerop arg))
+
+
+(defun erlang-end-of-function (&optional arg)
+ "Move forward to next end of function.
+
+With argument, do this that many times.
+With negative argument go towards the beginning of the buffer."
+ (interactive "p")
+ (or arg (setq arg 1))
+ (let ((first t))
+ ;; Forward
+ (while (and (> arg 0) (< (point) (point-max)))
+ (let ((pos (point)))
+ (while (progn
+ (if (and first
+ (progn
+ (forward-char 1)
+ (erlang-beginning-of-clause 1)))
+ nil
+ (or (bobp) (forward-char -1))
+ (erlang-beginning-of-clause -1))
+ (setq first nil)
+ (erlang-pass-over-function)
+ (skip-chars-forward " \t")
+ (if (looking-at "[%\n]")
+ (forward-line 1))
+ (<= (point) pos))))
+ (setq arg (1- arg)))
+ ;; Backward
+ (while (< arg 0)
+ (let ((pos (point)))
+ (erlang-beginning-of-clause 1)
+ (erlang-pass-over-function)
+ (forward-line 1)
+ (if (>= (point) pos)
+ (if (erlang-beginning-of-function 2)
+ (progn
+ (erlang-pass-over-function)
+ (skip-chars-forward " \t")
+ (if (looking-at "[%\n]")
+ (forward-line 1)))
+ (goto-char (point-min)))))
+ (setq arg (1+ arg)))))
+
+(defun erlang-mark-function ()
+ "Put mark at end of function, point at beginning."
+ (interactive)
+ (push-mark (point))
+ (erlang-end-of-function 1)
+ ;; Sets the region. In Emacs 19 and XEmacs, we wants to activate
+ ;; the region.
+ (condition-case nil
+ (push-mark (point) nil t)
+ (error (push-mark (point))))
+ (erlang-beginning-of-function 1)
+ ;; The above function deactivates the mark.
+ (if (boundp 'deactivate-mark)
+ (funcall (symbol-function 'set) 'deactivate-mark nil)))
+
+(defun erlang-pass-over-function ()
+ (while (progn
+ (erlang-skip-blank)
+ (and (not (looking-at "\\.\\(\\s \\|\n\\|\\s<\\)"))
+ (not (eobp))))
+ (forward-sexp 1))
+ (if (not (eobp))
+ (forward-char 1)))
+
+(defun erlang-name-of-function ()
+ (save-excursion
+ ;; Skip over attribute leader.
+ (if (looking-at "-[ \t]*")
+ (re-search-forward "-[ \t]*" nil 'move))
+ (let ((start (point)))
+ (forward-sexp 1)
+ (buffer-substring start (point)))))
+
+
+;;; Miscellaneous
+
+(defun erlang-fill-paragraph (&optional justify)
+ "Like \\[fill-paragraph], but handle Erlang comments.
+If any of the current line is a comment, fill the comment or the
+paragraph of it that point is in, preserving the comment's indentation
+and initial `%':s."
+ (interactive "P")
+ (let ((has-comment nil)
+ ;; If has-comment, the appropriate fill-prefix for the comment.
+ comment-fill-prefix)
+ ;; Figure out what kind of comment we are looking at.
+ (save-excursion
+ (beginning-of-line)
+ (cond
+ ;; Find the command prefix.
+ ((looking-at (concat "\\s *" comment-start-skip))
+ (setq has-comment t)
+ (setq comment-fill-prefix (buffer-substring (match-beginning 0)
+ (match-end 0))))
+ ;; A line with some code, followed by a comment? Remember that the
+ ;; % which starts the comment shouldn't be part of a string or
+ ;; character.
+ ((progn
+ (while (not (looking-at "%\\|$"))
+ (skip-chars-forward "^%\n\"\\\\")
+ (cond
+ ((eq (char-after (point)) ?\\) (forward-char 2))
+ ((eq (char-after (point)) ?\") (forward-sexp 1))))
+ (looking-at comment-start-skip))
+ (setq has-comment t)
+ (setq comment-fill-prefix
+ (concat (make-string (current-column) ? )
+ (buffer-substring (match-beginning 0) (match-end 0)))))))
+ (if (not has-comment)
+ (fill-paragraph justify)
+ ;; Narrow to include only the comment, and then fill the region.
+ (save-restriction
+ (narrow-to-region
+ ;; Find the first line we should include in the region to fill.
+ (save-excursion
+ (while (and (zerop (forward-line -1))
+ (looking-at "^\\s *%")))
+ ;; We may have gone to far. Go forward again.
+ (or (looking-at "^\\s *%")
+ (forward-line 1))
+ (point))
+ ;; Find the beginning of the first line past the region to fill.
+ (save-excursion
+ (while (progn (forward-line 1)
+ (looking-at "^\\s *%")))
+ (point)))
+ ;; Lines with only % on them can be paragraph boundaries.
+ (let ((paragraph-start (concat paragraph-start "\\|^[ \t%]*$"))
+ (paragraph-separate (concat paragraph-start "\\|^[ \t%]*$"))
+ (fill-prefix comment-fill-prefix))
+ (fill-paragraph justify))))))
+
+
+(defun erlang-uncomment-region (beg end)
+ "Uncomment all commented lines in the region."
+ (interactive "r")
+ (comment-region beg end -1))
+
+
+(defun erlang-generate-new-clause ()
+ "Create additional Erlang clause header.
+
+Parses the source file for the name of the current Erlang function.
+Create the header containing the name, A pair of parentheses,
+and an arrow. The space between the function name and the
+first parenthesis is preserved. The point is placed between
+the parentheses."
+ (interactive)
+ (let ((name (save-excursion
+ (and (erlang-beginning-of-clause)
+ (erlang-get-function-name t))))
+ (arrow (save-excursion
+ (and (erlang-beginning-of-clause)
+ (erlang-get-function-arrow)))))
+ (if (or (null arrow) (null name))
+ (error "Can't find name of current Erlang function."))
+ (if (and (bolp) (eolp))
+ nil
+ (end-of-line)
+ (newline))
+ (insert name)
+ (save-excursion
+ (insert (concat ") " arrow)))
+ (if erlang-new-clause-with-arguments
+ (erlang-clone-arguments))))
+
+
+(defun erlang-clone-arguments ()
+ "Insert, at the point, the argument list of the previous clause.
+
+The mark is set at the beginning of the inserted text, the point
+at the end."
+ (interactive)
+ (let ((args (save-excursion
+ (beginning-of-line)
+ (and (erlang-beginning-of-clause)
+ (erlang-get-function-arguments))))
+ (p (point)))
+ (if (null args)
+ (error "Can't clone argument list."))
+ (insert args)
+ (set-mark p)))
+
+;;; Information retreival functions.
+
+(defun erlang-buffer-substring (beg end)
+ "Like `buffer-substring-no-properties'.
+Although, this function works on all versions of Emacs."
+ (if (fboundp 'buffer-substring-no-properties)
+ (funcall (symbol-function 'buffer-substring-no-properties) beg end)
+ (buffer-substring beg end)))
+
+
+(defun erlang-get-module ()
+ "Return the name of the module as specified by `-module'.
+
+Return nil if file contains no `-module' attribute."
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (let ((md (match-data)))
+ (unwind-protect
+ (if (re-search-forward
+ (concat "^-module\\s *(\\s *\\(\\("
+ erlang-atom-regexp
+ "\\)?\\)\\s *)\\s *\\.")
+ (point-max) t)
+ (erlang-remove-quotes
+ (erlang-buffer-substring (match-beginning 1)
+ (match-end 1)))
+ nil)
+ (store-match-data md))))))
+
+
+(defun erlang-get-module-from-file-name (&optional file)
+ "Extract the module name from a file name.
+
+First, the directory part is removed. Second, the part of the file name
+matching `erlang-file-name-extension-regexp' is removed.
+
+Should the match fail, nil is returned.
+
+By modifying `erlang-file-name-extension-regexp' to match files other
+than Erlang source files, Erlang specific functions could be applied on
+non-Erlang files. Most notably; the support for Erlang modules in the
+tags system could be used by files written in other languages."
+ (or file (setq file buffer-file-name))
+ (if (null file)
+ nil
+ (setq file (file-name-nondirectory file))
+ (if (string-match erlang-file-name-extension-regexp file)
+ (substring file 0 (match-beginning 0))
+ nil)))
+
+
+;; Used by `erlang-get-export' and `erlang-get-import'.
+
+(defun erlang-get-function-arity-list ()
+ "Parses list of `function/arity' as used by `-import' and `-export'.
+
+The point must be placed at before the opening bracket. When the
+function returns the point will be placed after the closing bracket.
+
+The function does not return an error if the list is incorrectly
+formatted.
+
+Return list of (function . arity). The order of the returned list
+corresponds to the order of the parsed Erlang list."
+ (let ((res '()))
+ (erlang-skip-blank)
+ (forward-char 1)
+ (if (not (eq (preceding-char) ?\[))
+ '() ; Not looking at an Erlang list.
+ (while ; Note: `while' has no body.
+ (progn
+ (erlang-skip-blank)
+ (and (looking-at (concat erlang-atom-regexp
+ "/\\([0-9]+\\)\\>"))
+ (progn
+ (setq res (cons
+ (cons
+ (erlang-remove-quotes
+ (erlang-buffer-substring
+ (match-beginning 1) (match-end 1)))
+ (string-to-int
+ (erlang-buffer-substring
+ (match-beginning
+ (+ 1 erlang-atom-regexp-matches))
+ (match-end
+ (+ 1 erlang-atom-regexp-matches)))))
+ res))
+ (goto-char (match-end 0))
+ (erlang-skip-blank)
+ (forward-char 1)
+ ;; Test if there are more exported functions.
+ (eq (preceding-char) ?,))))))
+ (nreverse res)))
+
+
+;;; Note that `-export' and the open parenthesis must be written on
+;;; the same line.
+
+(defun erlang-get-export ()
+ "Return a list of `(function . arity)' as specified by `-export'."
+ (save-excursion
+ (goto-char (point-min))
+ (let ((md (match-data))
+ (res '()))
+ (unwind-protect
+ (progn
+ (while (re-search-forward "^-export\\s *(" (point-max) t)
+ (erlang-skip-blank)
+ (setq res (nconc res (erlang-get-function-arity-list))))
+ res)
+ (store-match-data md)))))
+
+
+(defun erlang-get-import ()
+ "Parse an Erlang source file for imported functions.
+
+Return an alist with module name as car part and list of conses containing
+function and arity as cdr part."
+ (save-excursion
+ (goto-char (point-min))
+ (let ((md (match-data))
+ (res '()))
+ (unwind-protect
+ (progn
+ (while (re-search-forward "^-import\\s *(" (point-max) t)
+ (erlang-skip-blank)
+ (if (looking-at erlang-atom-regexp)
+ (let ((module (erlang-remove-quotes
+ (erlang-buffer-substring
+ (match-beginning 0)
+ (match-end 0)))))
+ (goto-char (match-end 0))
+ (erlang-skip-blank)
+ (if (eq (following-char) ?,)
+ (progn
+ (forward-char 1)
+ (erlang-skip-blank)
+ (let ((funcs (erlang-get-function-arity-list))
+ (pair (assoc module res)))
+ (if pair
+ (setcdr pair (nconc (cdr pair) funcs))
+ (setq res (cons (cons module funcs)
+ res)))))))))
+ (nreverse res))
+ (store-match-data md)))))
+
+
+(defun erlang-get-function-name (&optional arg)
+ "Return name of current function, or nil.
+
+If optional argument is non-nil, everything up to and including
+the first `(' is returned.
+
+Normally used in conjuction with `erlang-beginning-of-clause', e.g.:
+ (save-excursion
+ (if (not (eobp)) (forward-char 1))
+ (and (erlang-beginning-of-clause)
+ (erlang-get-function-name t)))"
+ (let ((n (if arg 0 1)))
+ (and (looking-at (concat "^" erlang-atom-regexp "\\s *("))
+ (erlang-buffer-substring (match-beginning n) (match-end n)))))
+
+
+(defun erlang-get-function-arrow ()
+ "Return arrow of current function, could be \"->\", \":-\" or nil.
+
+The \":-\" arrow is used by mnesia queries.
+
+Normally used in conjuction with `erlang-beginning-of-clause', e.g.:
+ (save-excursion
+ (if (not (eobp)) (forward-char 1))
+ (and (erlang-beginning-of-clause)
+ (erlang-get-function-arrow)))"
+ (and (looking-at (concat "^" erlang-atom-regexp "\\s *\\((\\)"))
+ (condition-case ()
+ (save-excursion
+ (goto-char (match-beginning (+ 1 erlang-atom-regexp-matches)))
+ (forward-sexp 1)
+ (erlang-skip-blank)
+ (and (looking-at "->\\|:-")
+ (erlang-buffer-substring
+ (match-beginning 0) (match-end 0)))))))
+
+
+(defun erlang-get-function-arity ()
+ "Return the number of arguments of function at point, or nil."
+ (and (looking-at (concat "^" erlang-atom-regexp "\\s *("))
+ (save-excursion
+ (goto-char (match-end 0))
+ (condition-case nil
+ (let ((res 0)
+ (cont t))
+ (while cont
+ (cond ((eobp)
+ (setq res nil)
+ (setq cont nil))
+ ((looking-at "\\s *)")
+ (setq cont nil))
+ ((looking-at "\\s *\\($\\|%\\)")
+ (forward-line 1))
+ ((looking-at "\\s *,")
+ (goto-char (match-end 0)))
+ (t
+ (setq res (+ 1 res))
+ (forward-sexp 1))))
+ res)
+ (error nil)))))
+
+
+(defun erlang-get-function-arguments ()
+ "Return arguments of current function, or nil."
+ (if (not (looking-at (concat "^" erlang-atom-regexp "\\s *(")))
+ nil
+ (save-excursion
+ (condition-case nil
+ (let ((start (match-end 0)))
+ (goto-char (- start 1))
+ (forward-sexp)
+ (erlang-buffer-substring start (- (point) 1)))
+ (error nil)))))
+
+
+(defun erlang-get-function-under-point ()
+ "Return the module and function under the point, or nil.
+
+Should no explicit module name be present at the point, the
+list of imported functions is searched.
+
+The following could be retured:
+ (\"module\" \"function\") -- Both module and function name found.
+ (nil \"function\") -- No module name was found.
+ nil -- No function name found
+
+In the future the list may contain more elements."
+ (save-excursion
+ (let ((md (match-data))
+ (res nil))
+ (if (eq (char-syntax (following-char)) ? )
+ (skip-chars-backward " \t"))
+ (skip-chars-backward "a-zA-Z0-9_:'")
+ (cond ((looking-at (concat erlang-atom-regexp ":" erlang-atom-regexp))
+ (setq res (list
+ (erlang-remove-quotes
+ (erlang-buffer-substring
+ (match-beginning 1) (match-end 1)))
+ (erlang-remove-quotes
+ (erlang-buffer-substring
+ (match-beginning (1+ erlang-atom-regexp-matches))
+ (match-end (1+ erlang-atom-regexp-matches)))))))
+ ((looking-at erlang-atom-regexp)
+ (let ((fk (erlang-remove-quotes
+ (erlang-buffer-substring
+ (match-beginning 0) (match-end 0))))
+ (mod nil)
+ (imports (erlang-get-import)))
+ (while (and imports (null mod))
+ (if (assoc fk (cdr (car imports)))
+ (setq mod (car (car imports)))
+ (setq imports (cdr imports))))
+ (setq res (list mod fk)))))
+ (store-match-data md)
+ res)))
+
+
+;; TODO: Escape single quotes inside the string.
+(defun erlang-add-quotes-if-needed (str)
+ "Return STR, possibly with quotes."
+ (if (and (stringp str)
+ (not (string-match (concat "\\`" erlang-atom-regexp "\\'") str)))
+ (concat "'" str "'")
+ str))
+
+
+(defun erlang-remove-quotes (str)
+ "Return STR without quotes, if present."
+ (let ((md (match-data)))
+ (prog1
+ (if (string-match "\\`'\\(.*\\)'\\'" str)
+ (substring str (match-beginning 1) (match-end 1))
+ str)
+ (store-match-data md))))
+
+
+;;; Check module name
+
+;; I don't want to use `advice' since it is not part of Emacs 18.
+;;
+;; The function `write-file', bound to C-x C-w, calls
+;; `set-visited-file-name' which clears the hook. :-(
+;; To make sure that the hook always is present, we add a piece of
+;; code to the function `set-visited-file-name'.
+(defun erlang-check-module-name-init ()
+ "Initialize the functionality to compare file and module names.
+
+We redefines the function `set-visited-file-name' since it clears
+the variable `local-write-file-hooks'. The original function definition
+is stored in `erlang-orig-set-visited-file-name'."
+ (if (fboundp 'erlang-orig-set-visited-file-name)
+ ()
+ (fset 'erlang-orig-set-visited-file-name
+ (symbol-function 'set-visited-file-name))
+ (defun set-visited-file-name (&rest args)
+ "Please see the function `erlang-orig-set-visited-file-name'."
+ (interactive "FSet visited file name: ")
+ (apply (symbol-function 'erlang-orig-set-visited-file-name) args)
+ (if (eq major-mode 'erlang-mode)
+ (add-hook 'local-write-file-hooks 'erlang-check-module-name))))
+ (add-hook 'local-write-file-hooks 'erlang-check-module-name))
+
+
+(defun erlang-check-module-name ()
+ "If the module name doesn't match file name, ask for permission to change.
+
+The variable `erlang-check-module-name' controls the behaviour of this
+function. It it is nil, this function does nothing. If it is t, the
+source is silently changed. If it is set to the atom `ask', the user
+is prompted.
+
+This function is normally placed in the hook `local-write-file-hook'."
+ (if erlang-check-module-name
+ (let ((mn (erlang-get-module))
+ (fn (erlang-get-module-from-file-name (buffer-file-name))))
+ (if (and (stringp mn) (stringp fn))
+ (or (string-equal mn fn)
+ (if (or (eq erlang-check-module-name t)
+ (y-or-n-p
+ "Module does not match file name. Modify source? "))
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (if (re-search-forward
+ (concat "^-module\\s *(\\s *\\(\\("
+ erlang-atom-regexp
+ "\\)?\\)\\s *)\\s *\\.")
+ (point-max) t)
+ (progn
+ (goto-char (match-beginning 1))
+ (delete-region (match-beginning 1)
+ (match-end 1))
+ (insert fn))))))))))
+ ;; Must return nil since it is added to `local-write-file-hook'.
+ nil)
+
+
+;;; Electric functions.
+
+(defun erlang-electric-semicolon (&optional arg)
+ "Insert a semicolon character and possibly a prototype for the next line.
+
+The variable `erlang-electric-semicolon-criteria' states a critera,
+when fulfilled a newline is inserted, the next line is indented and a
+prototype for the next line is inserted. Normally the prototype
+consists of \" ->\". Should the semicolon end the clause a new clause
+header is generated.
+
+The variable `erlang-electric-semicolon-insert-blank-lines' controls
+the number of blank lines inserted between the current line and new
+function header.
+
+Behaves just like the normal semicolon when supplied with a
+numerical arg, point is inside string or comment, or when there are
+non-whitespace characters following the point on the current line."
+ (interactive "P")
+ (self-insert-command (prefix-numeric-value arg))
+ (if (or arg
+ (and (listp erlang-electric-commands)
+ (not (memq 'erlang-electric-semicolon
+ erlang-electric-commands)))
+ (erlang-in-literal)
+ (not (looking-at "\\s *\\(%.*\\)?$"))
+ (null (erlang-test-criteria-list
+ erlang-electric-semicolon-criteria)))
+ (setq erlang-electric-newline-inhibit nil)
+ (setq erlang-electric-newline-inhibit t)
+ (undo-boundary)
+ (end-of-line)
+ (newline)
+ (if (condition-case nil
+ (progn (erlang-indent-line) t)
+ (error (if (bolp) (delete-backward-char 1))))
+ (if (not (bolp))
+ (save-excursion
+ (insert " ->"))
+ (condition-case nil
+ (progn
+ (erlang-generate-new-clause)
+ (if erlang-electric-semicolon-insert-blank-lines
+ (save-excursion
+ (beginning-of-line)
+ (newline
+ erlang-electric-semicolon-insert-blank-lines))))
+ (error (if (bolp) (delete-backward-char 1))))))))
+
+
+(defun erlang-electric-comma (&optional arg)
+ "Insert a comma character and possibly a new indented line.
+The variable `erlang-electric-comma-criteria' states a critera,
+when fulfilled a newline is inserted and the next line is indeted.
+
+Behaves just like the normal comma when supplied with a
+numerical arg, point is inside string or comment, or when there are
+non-whitespace characters following the point on the current line."
+ (interactive "P")
+
+ (self-insert-command (prefix-numeric-value arg))
+
+ (if (or arg
+ (and (listp erlang-electric-commands)
+ (not (memq 'erlang-electric-comma erlang-electric-commands)))
+ (erlang-in-literal)
+ (not (looking-at "\\s *\\(%.*\\)?$"))
+ (null (erlang-test-criteria-list
+ erlang-electric-comma-criteria)))
+ (setq erlang-electric-newline-inhibit nil)
+ (setq erlang-electric-newline-inhibit t)
+ (undo-boundary)
+ (end-of-line)
+ (newline)
+ (condition-case nil
+ (erlang-indent-line)
+ (error (if (bolp) (delete-backward-char 1))))))
+
+(defun erlang-electric-lt (&optional arg)
+ "Insert a less-than sign, and optionally mark it as an open paren."
+
+ (interactive "p")
+
+ (self-insert-command arg)
+
+ ;; Was this the second char in bit-syntax open (`<<')?
+ (unless (< (point) 2)
+ (save-excursion
+ (backward-char 2)
+ (when (and (eq (char-after (point)) ?<)
+ (not (eq (get-text-property (point) 'category)
+ 'bitsyntax-open-inner)))
+ ;; Then mark the two chars...
+ (put-text-property (point) (1+ (point))
+ 'category 'bitsyntax-open-outer)
+ (forward-char 1)
+ (put-text-property (point) (1+ (point))
+ 'category 'bitsyntax-open-inner)
+ ;;...and unmark any subsequent less-than chars.
+ (forward-char 1)
+ (while (eq (char-after (point)) ?<)
+ (remove-text-properties (point) (1+ (point))
+ '(category nil))
+ (forward-char 1))))))
+
+(defun erlang-after-bitsyntax-close ()
+ "Returns true if point is placed immediately after a bit-syntax close parenthesis (`>>')."
+ (and (>= (point) 2)
+ (save-excursion
+ (backward-char 2)
+ (and (eq (char-after (point)) ?>)
+ (not (eq (get-text-property (point) 'category)
+ 'bitsyntax-close-outer))))))
+
+(defun erlang-after-arrow ()
+ "Returns true if point is placed immediately after a function arrow (`->')."
+ (and (>= (point) 2)
+ (and
+ (save-excursion
+ (backward-char)
+ (eq (char-before (point)) ?-))
+ (or (not (listp erlang-electric-commands))
+ (memq 'erlang-electric-gt
+ erlang-electric-commands))
+ (not (erlang-in-literal))
+ (looking-at "\\s *\\(%.*\\)?$")
+ (erlang-test-criteria-list erlang-electric-arrow-criteria))))
+
+
+(defun erlang-electric-gt (&optional arg)
+ "Insert a greater-than sign, and optionally mark it as a close paren."
+
+ (interactive "p")
+
+ (self-insert-command arg)
+
+ (cond
+ ;; Did we just write a bit-syntax close (`>>')?
+ ((erlang-after-bitsyntax-close)
+ (save-excursion
+ ;; Then mark the two chars...
+ (backward-char 2)
+ (put-text-property (point) (1+ (point))
+ 'category 'bitsyntax-close-inner)
+ (forward-char)
+ (put-text-property (point) (1+ (point))
+ 'category 'bitsyntax-close-outer)
+ ;;...and unmark any subsequent greater-than chars.
+ (forward-char)
+ (while (eq (char-after (point)) ?>)
+ (remove-text-properties (point) (1+ (point))
+ '(category nil))
+ (forward-char))))
+
+ ;; Did we just write a function arrow (`->')?
+ ((erlang-after-arrow)
+ (let ((erlang-electric-newline-inhibit t))
+ (undo-boundary)
+ (end-of-line)
+ (newline)
+ (condition-case nil
+ (erlang-indent-line)
+ (error (if (bolp) (delete-backward-char 1))))))
+
+ ;; Then it's just a plain greater-than.
+ (t
+ nil)))
+
+
+(defun erlang-electric-arrow\ off (&optional arg)
+ "Insert a '>'-sign and possible a new indented line.
+
+This command is only `electric' when the `>' is part of an `->' arrow.
+The variable `erlang-electric-arrow-criteria' states a sequence of
+criteria, which decides when a newline should be inserted and the next
+line indented.
+
+It behaves just like the normal greater than sign when supplied with a
+numerical arg, point is inside string or comment, or when there are
+non-whitespace characters following the point on the current line.
+
+After being split/merged into erlang-after-arrow and
+erlang-electric-gt, it is now unused and disabled."
+ (interactive "P")
+ (let ((prec (preceding-char)))
+ (self-insert-command (prefix-numeric-value arg))
+ (if (or arg
+ (and (listp erlang-electric-commands)
+ (not (memq 'erlang-electric-arrow
+ erlang-electric-commands)))
+ (not (eq prec ?-))
+ (erlang-in-literal)
+ (not (looking-at "\\s *\\(%.*\\)?$"))
+ (null (erlang-test-criteria-list
+ erlang-electric-arrow-criteria)))
+ (setq erlang-electric-newline-inhibit nil)
+ (setq erlang-electric-newline-inhibit t)
+ (undo-boundary)
+ (end-of-line)
+ (newline)
+ (condition-case nil
+ (erlang-indent-line)
+ (error (if (bolp) (delete-backward-char 1)))))))
+
+
+(defun erlang-electric-newline (&optional arg)
+ "Break line at point and indent, continuing comment if within one.
+The variable `erlang-electric-newline-criteria' states a critera,
+when fulfilled a newline is inserted and the next line is indeted.
+
+Should the current line begin with a comment, and the variable
+`comment-multi-line' be non-nil, a new comment start is inserted.
+
+Should the previous command be another electric command we assume that
+the user pressed newline out of old habit, hence we will do nothing."
+ (interactive "P")
+ (cond ((and (not arg)
+ erlang-electric-newline-inhibit
+ (memq last-command erlang-electric-newline-inhibit-list))
+ ()) ; Do nothing!
+ ((or arg
+ (and (listp erlang-electric-commands)
+ (not (memq 'erlang-electric-newline
+ erlang-electric-commands)))
+ (null (erlang-test-criteria-list
+ erlang-electric-newline-criteria)))
+ (newline (prefix-numeric-value arg)))
+ (t
+ (if (and comment-multi-line
+ (save-excursion
+ (beginning-of-line)
+ (looking-at (concat "\\s *" comment-start-skip))))
+ (let ((str (buffer-substring
+ (or (match-end 1) (match-beginning 0))
+ (min (match-end 0) (point)))))
+ (newline)
+ (undo-boundary)
+ (insert str))
+ (newline)
+ (undo-boundary)
+ (indent-according-to-mode)))))
+
+
+(defun erlang-test-criteria-list (criteria)
+ "Given a list of criteria functions, test if criteria is fulfilled.
+
+Each element in the criteria list can a function returning nil, t or
+the atom `stop'. t means that the criteria is fulfilled, `stop' means
+that it the criteria isn't fulfilled and that the search should stop,
+and nil means continue searching.
+
+Should the list contain the atom t the criteria is assumed to be
+fulfilled, unless preceded by a function returning `stop', of course.
+
+Should the argument be the atom t instead of a list, the criteria is
+assumed to be trivially true.
+
+Should all function return nil, the criteria is assumed not to be
+fulfilled.
+
+Return t if criteria fulfilled, nil otherwise."
+ (if (eq criteria t)
+ t
+ (save-excursion
+ (let ((answer nil))
+ (while (and criteria (null answer))
+ (if (eq (car criteria) t)
+ (setq answer t)
+ (setq answer (funcall (car criteria))))
+ (setq criteria (cdr criteria)))
+ (if (and answer (not (eq answer 'stop)))
+ t
+ nil)))))
+
+
+(defun erlang-in-literal (&optional lim)
+ "Test if point is in string, quoted atom or comment.
+
+Return one of the three atoms `atom', `string', and `comment'.
+Should the point be inside none of the above mentioned types of
+context, nil is returned."
+ (save-excursion
+ (let* ((lim (or lim (save-excursion
+ (erlang-beginning-of-clause)
+ (point))))
+ (state (parse-partial-sexp lim (point))))
+ (cond
+ ((eq (nth 3 state) ?') 'atom)
+ ((nth 3 state) 'string)
+ ((nth 4 state) 'comment)
+ (t nil)))))
+
+
+(defun erlang-at-end-of-function-p ()
+ "Test if point is at end of an Erlang function.
+
+This function is designed to be a member of a criteria list."
+ (eq (save-excursion (erlang-skip-blank) (point))
+ (save-excursion
+ (erlang-beginning-of-function -1) (point))))
+
+
+(defun erlang-stop-when-inside-argument-list ()
+ "Return `stop' if inside parenthesis list, nil otherwise.
+
+Knows about the list comprehension syntax. When the point is
+after `||', `stop' is not returned.
+
+This function is designed to be a member of a criteria list."
+ (save-excursion
+ (condition-case nil
+ (let ((orig-point (point))
+ (state nil))
+ (up-list -1)
+ (if (not (eq (following-char) ?\[))
+ 'stop
+ ;; Do not return `stop' when inside a list comprehension
+ ;; construnction. (The point must be after `||').
+ (while (< (point) orig-point)
+ (setq state (erlang-partial-parse (point) orig-point state)))
+ (if (and (car state) (eq (car (car (car state))) '||))
+ nil
+ 'stop)))
+ (error
+ nil))))
+
+
+(defun erlang-stop-when-at-guard ()
+ "Return `stop' when at function guards.
+
+This function is designed to be a member of a criteria list."
+ (save-excursion
+ (beginning-of-line)
+ (if (and (looking-at (concat "^" erlang-atom-regexp "\\s *("))
+ (not (looking-at
+ (concat "^" erlang-atom-regexp ".*\\(->\\|:-\\)"))))
+ 'stop
+ nil)))
+
+
+(defun erlang-next-lines-empty-p ()
+ "Return non-nil if next lines are empty.
+
+The variable `erlang-next-lines-empty-threshold' contains the number
+of lines required to be empty.
+
+A line containing only spaces and tabs is considered empty.
+
+This function is designed to be a member of a criteria list."
+ (and erlang-next-lines-empty-threshold
+ (save-excursion
+ (let ((left erlang-next-lines-empty-threshold)
+ (cont t))
+ (while (and cont (> left 0))
+ (forward-line 1)
+ (setq cont (looking-at "\\s *$"))
+ (setq left (- left 1)))
+ cont))))
+
+
+(defun erlang-at-keyword-end-p ()
+ "Test if next readable token is the keyword end.
+
+This function is designed to be a member of a criteria list."
+ (save-excursion
+ (erlang-skip-blank)
+ (looking-at "end[^_a-zA-Z0-9]")))
+
+
+;; Erlang tags support which is aware of erlang modules.
+;;
+;; Not yet implemented under XEmacs. (Hint: The Emacs 19 etags
+;; package work under XEmacs.)
+
+(eval-when-compile
+ (if (or (featurep 'bytecomp)
+ (featurep 'byte-compile))
+ (progn
+ (require 'etags))))
+
+
+;; Variables:
+
+(defvar erlang-tags-function-alist
+ '((find-tag . erlang-find-tag)
+ (find-tag-other-window . erlang-find-tag-other-window)
+ (find-tag-regexp . erlang-find-tag-regexp)
+ (find-tag-other-frame . erlang-find-tag-other-frame))
+ "Alist of old tags commands and the replacement functions.")
+
+(defvar erlang-tags-installed nil
+ "Non-nil when the Erlang tags system is installed.")
+(defvar erlang-tags-file-list '()
+ "List of files in tag list. Used when finding tag on form `module:'.")
+(defvar erlang-tags-completion-table nil
+ "Like `tags-completion-table', this table contains `tag' and `module:tag'.")
+(defvar erlang-tags-buffer-installed-p nil
+ "Non-nil when erlang module recognising functions installed.")
+(defvar erlang-tags-buffer-list '()
+ "Temporary list of buffers.")
+(defvar erlang-tags-orig-completion-table nil
+ "Temporary storage for `tags-completion-table'.")
+(defvar erlang-tags-orig-tag-order nil
+ "Temporary storage for `find-tag-tag-order'.")
+(defvar erlang-tags-orig-regexp-tag-order nil
+ "Temporary storage for `find-tag-regexp-tag-order'.")
+(defvar erlang-tags-orig-search-function nil
+ "Temporary storage for `find-tag-search-function'.")
+(defvar erlang-tags-orig-regexp-search-function nil
+ "Temporary storage for `find-tag-regexp-search-function'.")
+(defvar erlang-tags-orig-format-hooks nil
+ "Temporary storage for `tags-table-format-hooks'.")
+
+(defun erlang-tags-init ()
+ "Install an alternate version of tags, aware of Erlang modules.
+
+After calling this function, the tags functions are aware of
+Erlang modules. Tags can be entered on the for `module:tag' aswell
+as on the old form `tag'.
+
+In the completion list, `module:tag' and `module:' shows up.
+
+Call this function from an appropriate init file, or add it to
+Erlang mode hook with the commands:
+ (add-hook 'erlang-mode-hook 'erlang-tags-init)
+ (add-hook 'erlang-shell-mode-hook 'erlang-tags-init)
+
+This function only works under Emacs 18 and Emacs 19. Currently, It
+is not implemented under XEmacs. (Hint: The Emacs 19 etags module
+works under XEmacs.)"
+ (interactive)
+ (cond ((= erlang-emacs-major-version 18)
+ (require 'tags)
+ (erlang-tags-define-keys (current-local-map))
+ (setq erlang-tags-installed t))
+ (t
+ (require 'etags)
+ ;; Test on a function available in the Emacs 19 version
+ ;; of tags but not in the XEmacs version.
+ (if (not (fboundp 'find-tag-noselect))
+ ()
+ (erlang-tags-define-keys (current-local-map))
+ (setq erlang-tags-installed t)))))
+
+
+;; Set all keys bound to `find-tag' et.al. in the global map and the
+;; menu to `erlang-find-tag' et.al. in `map'.
+;;
+;; The function `substitute-key-definition' does not work properly
+;; in all version of Emacs.
+
+(defun erlang-tags-define-keys (map)
+ "Bind tags commands to keymap MAP aware of Erlang modules."
+ (let ((alist erlang-tags-function-alist))
+ (while alist
+ (let* ((old (car (car alist)))
+ (new (cdr (car alist)))
+ (keys (append (where-is-internal old global-map))))
+ (while keys
+ (define-key map (car keys) new)
+ (setq keys (cdr keys))))
+ (setq alist (cdr alist))))
+ ;; Update the menu.
+ (erlang-menu-substitute erlang-menu-base-items erlang-tags-function-alist)
+ (erlang-menu-init))
+
+
+;; There exists a variable `find-tag-default-function'. It is not used
+;; since `complete-tag' uses it to get current word under point. In that
+;; situation we doesn't want the module to be prepended.
+
+(defun erlang-find-tag-default ()
+ "Return the default tag, searches `-import' list of imported functions.
+Single quotes has been stripped away."
+ (let ((mod-func (erlang-get-function-under-point)))
+ (cond ((null mod-func)
+ nil)
+ ((null (car mod-func))
+ (nth 1 mod-func))
+ (t
+ (concat (car mod-func) ":" (nth 1 mod-func))))))
+
+
+;; Return `t' since it is used inside `tags-loop-form'.
+;;;###autoload
+(defun erlang-find-tag (modtagname &optional next-p regexp-p)
+ "Like `find-tag'. Capable of retreiving Erlang modules.
+
+Tags can be given on the forms `tag', `module:', `module:tag'."
+ (interactive (erlang-tag-interactive "Find `module:tag' or `tag': "))
+ (switch-to-buffer (erlang-find-tag-noselect modtagname next-p regexp-p))
+ t)
+
+
+;; Code mainly from `find-tag-other-window' in `etags.el'.
+;;;###autoload
+(defun erlang-find-tag-other-window (tagname &optional next-p regexp-p)
+ "Like `find-tag-other-window' but aware of Erlang modules."
+ (interactive (erlang-tag-interactive
+ "Find `module:tag' or `tag' other window: "))
+
+ ;; This is to deal with the case where the tag is found in the
+ ;; selected window's buffer; without this, point is moved in both
+ ;; windows. To prevent this, we save the selected window's point
+ ;; before doing find-tag-noselect, and restore it afterwards.
+ (let* ((window-point (window-point (selected-window)))
+ (tagbuf (erlang-find-tag-noselect tagname next-p regexp-p))
+ (tagpoint (progn (set-buffer tagbuf) (point))))
+ (set-window-point (prog1
+ (selected-window)
+ (switch-to-buffer-other-window tagbuf)
+ ;; We have to set this new window's point; it
+ ;; might already have been displaying a
+ ;; different portion of tagbuf, in which case
+ ;; switch-to-buffer-other-window doesn't set
+ ;; the window's point from the buffer.
+ (set-window-point (selected-window) tagpoint))
+ window-point)))
+
+
+(defun erlang-find-tag-other-frame (tagname &optional next-p)
+ "Like `find-tag-other-frame' but aware of Erlang modules."
+ (interactive (erlang-tag-interactive
+ "Find `module:tag' or `tag' other frame: "))
+ (let ((pop-up-frames t))
+ (erlang-find-tag-other-window tagname next-p)))
+
+
+(defun erlang-find-tag-regexp (regexp &optional next-p other-window)
+ "Like `find-tag-regexp' but aware of Erlang modules."
+ (interactive (if (fboundp 'find-tag-regexp)
+ (erlang-tag-interactive
+ "Find `module:regexp' or `regexp': ")
+ (error "This version of Emacs can't find tags by regexps.")))
+ (funcall (if other-window
+ 'erlang-find-tag-other-window
+ 'erlang-find-tag)
+ regexp next-p t))
+
+
+;; Just like C-u M-. This could be added to the menu.
+(defun erlang-find-next-tag ()
+ (interactive)
+ (let ((current-prefix-arg '(4)))
+ (if erlang-tags-installed
+ (call-interactively 'erlang-find-tag)
+ (call-interactively 'find-tag))))
+
+
+;; Mimics `find-tag-noselect' found in `etags.el', but uses `find-tag' to
+;; be compatible with `tags.el'.
+;;
+;; Handles three cases:
+;; * `module:' Loop over all possible filen-ames. Stop if a file-name
+;; without extension and directory matches the module.
+;;
+;; * `module:tag'
+;; Emacs 19: Replace testfunctions with functions aware of
+;; Erlang modules. Tricky because the etags system wasn't
+;; built for these kind of operations...
+;;
+;; Emacs 18: We loop over `find-tag' until we find a file
+;; whose module matches the requested module. The
+;; drawback is that a lot of files could be loaded into
+;; Emacs.
+;;
+;; * `tag' Just give it to `find-tag'.
+
+(defun erlang-find-tag-noselect (modtagname &optional next-p regexp-p)
+ "Like `find-tag-noselect' but aware of Erlang modules."
+ (interactive (erlang-tag-interactive "Find `module:tag' or `tag': "))
+ (or modtagname
+ (setq modtagname (symbol-value 'last-tag)))
+ (funcall (symbol-function 'set) 'last-tag modtagname)
+ ;; `tags.el' uses this variable to record how M-, would
+ ;; know where to restart a tags command.
+ (if (boundp 'tags-loop-form)
+ (funcall (symbol-function 'set)
+ 'tags-loop-form '(erlang-find-tag nil t)))
+ (save-window-excursion
+ (cond
+ ((string-match ":$" modtagname)
+ ;; Only the module name was given. Read all files whose file name
+ ;; match.
+ (let ((modname (substring modtagname 0 (match-beginning 0)))
+ (file nil))
+ (if (not next-p)
+ (save-excursion
+ (visit-tags-table-buffer)
+ (setq erlang-tags-file-list
+ (funcall (symbol-function 'tags-table-files)))))
+ (while (null file)
+ (or erlang-tags-file-list
+ (save-excursion
+ (if (and (featurep 'etags)
+ (funcall
+ (symbol-function 'visit-tags-table-buffer) 'same)
+ (funcall
+ (symbol-function 'visit-tags-table-buffer) t))
+ (setq erlang-tags-file-list
+ (funcall (symbol-function 'tags-table-files)))
+ (error "No %stags containing %s" (if next-p "more " "")
+ modtagname))))
+ (if erlang-tags-file-list
+ (let ((this-module (erlang-get-module-from-file-name
+ (car erlang-tags-file-list))))
+ (if (and (stringp this-module)
+ (string= modname this-module))
+ (setq file (car erlang-tags-file-list)))
+ (setq erlang-tags-file-list (cdr erlang-tags-file-list)))))
+ (set-buffer (or (get-file-buffer file)
+ (find-file-noselect file)))))
+
+ ((string-match ":" modtagname)
+ (if (boundp 'find-tag-tag-order)
+ ;; Method one: Add module-recognising functions to the
+ ;; list of order functions. However, the tags system
+ ;; from Emacs 18, and derives thereof (read: XEmacs)
+ ;; hasn't got this feature.
+ (progn
+ (erlang-tags-install-module-check)
+ (unwind-protect
+ (funcall (symbol-function 'find-tag)
+ modtagname next-p regexp-p)
+ (erlang-tags-remove-module-check)))
+ ;; Method two: Call the tags system until a file matching
+ ;; the module is found. This could result in that many
+ ;; files are read. (e.g. The tag "foo:file" will take a
+ ;; while to process.)
+ (let* ((modname (substring modtagname 0 (match-beginning 0)))
+ (tagname (substring modtagname (match-end 0) nil))
+ (last-tag tagname)
+ file)
+ (while
+ (progn
+ (funcall (symbol-function 'find-tag) tagname next-p regexp-p)
+ (setq next-p t)
+ ;; Determine the module form the file name. (The
+ ;; alternative, to check `-module', would make this
+ ;; code useless for non-Erlang programs.)
+ (setq file (erlang-get-module-from-file-name buffer-file-name))
+ (not (and (stringp file)
+ (string= modname file))))))))
+ (t
+ (funcall (symbol-function 'find-tag) modtagname next-p regexp-p)))
+ (current-buffer))) ; Return the new buffer.
+
+
+;; Process interactive arguments for erlang-find-tag-*.
+;;
+;; Negative arguments work only for `etags', not `tags'. This is not
+;; a problem since negative arguments means step back into the
+;; history list, a feature not implemented in `tags'.
+
+(defun erlang-tag-interactive (prompt)
+ (condition-case nil
+ (require 'etags)
+ (error
+ (require 'tags)))
+ (if current-prefix-arg
+ (list nil (if (< (prefix-numeric-value current-prefix-arg) 0)
+ '-
+ t))
+ (let* ((default (erlang-find-tag-default))
+ (prompt (if default
+ (format "%s(default %s) " prompt default)
+ prompt))
+ (spec (if (featurep 'etags)
+ (completing-read prompt 'erlang-tags-complete-tag)
+ (read-string prompt))))
+ (list (if (equal spec "")
+ (or default (error "There is no default tag"))
+ spec)))))
+
+
+;; Search tag functions which are aware of Erlang modules. The tactic
+;; is to store new search functions into the local variabels of the
+;; TAGS buffers. The variables are restored directly after the
+;; search. The situation is complicated by the fact that new TAGS
+;; files can be loaded during the search.
+;;
+;; This code is Emacs 19 `etags' specific.
+
+(defun erlang-tags-install-module-check ()
+ "Install our own tag search functions."
+ ;; Make sure our functions are installed in TAGS files loaded
+ ;; into Emacs while searching.
+ (setq erlang-tags-orig-format-hooks
+ (symbol-value 'tags-table-format-hooks))
+ (funcall (symbol-function 'set) 'tags-table-format-hooks
+ (cons 'erlang-tags-recognize-tags-table
+ erlang-tags-orig-format-hooks))
+ (setq erlang-tags-buffer-list '())
+ ;; Install our functions in the TAGS files already resident.
+ (save-excursion
+ (let ((files (symbol-value 'tags-table-computed-list)))
+ (while files
+ (if (stringp (car files))
+ (if (get-file-buffer (car files))
+ (progn
+ (set-buffer (get-file-buffer (car files)))
+ (erlang-tags-install-local))))
+ (setq files (cdr files))))))
+
+
+(defun erlang-tags-install-local ()
+ "Install our tag search functions in current buffer."
+ (if erlang-tags-buffer-installed-p
+ ()
+ ;; Mark this buffer as "installed" and record.
+ (set (make-local-variable 'erlang-tags-buffer-installed-p) t)
+ (setq erlang-tags-buffer-list
+ (cons (current-buffer) erlang-tags-buffer-list))
+
+ ;; Save the original values.
+ (set (make-local-variable 'erlang-tags-orig-tag-order)
+ (symbol-value 'find-tag-tag-order))
+ (set (make-local-variable 'erlang-tags-orig-regexp-tag-order)
+ (symbol-value 'find-tag-regexp-tag-order))
+ (set (make-local-variable 'erlang-tags-orig-search-function)
+ (symbol-value 'find-tag-search-function))
+ (set (make-local-variable 'erlang-tags-orig-regexp-search-function)
+ (symbol-value 'find-tag-regexp-search-function))
+
+ ;; Install our own functions.
+ (set (make-local-variable 'find-tag-search-function)
+ 'erlang-tags-search-forward)
+ (set (make-local-variable 'find-tag-regexp-search-function)
+ 'erlang-tags-regexp-search-forward)
+ (set (make-local-variable 'find-tag-tag-order)
+ '(erlang-tag-match-module-p))
+ (set (make-local-variable 'find-tag-regexp-tag-order)
+ '(erlang-tag-match-module-regexp-p))))
+
+
+(defun erlang-tags-remove-module-check ()
+ "Remove our own tags search functions."
+ (funcall (symbol-function 'set)
+ 'tags-table-format-hooks
+ erlang-tags-orig-format-hooks)
+ ;; Remove our functions from the TAGS files. (Note that
+ ;; `tags-table-computed-list' need not be the same list as when
+ ;; the search was started.)
+ (save-excursion
+ (let ((buffers erlang-tags-buffer-list))
+ (while buffers
+ (if (buffer-name (car buffers))
+ (progn
+ (set-buffer (car buffers))
+ (erlang-tags-remove-local)))
+ (setq buffers (cdr buffers))))))
+
+
+(defun erlang-tags-remove-local ()
+ "Remove our tag search functions from current buffer."
+ (if (null erlang-tags-buffer-installed-p)
+ ()
+ (funcall (symbol-function 'set) 'erlang-tags-buffer-installed-p nil)
+ (funcall (symbol-function 'set)
+ 'find-tag-tag-order erlang-tags-orig-tag-order)
+ (funcall (symbol-function 'set)
+ 'find-tag-regexp-tag-order erlang-tags-orig-regexp-tag-order)
+ (funcall (symbol-function 'set)
+ 'find-tag-search-function erlang-tags-orig-search-function)
+ (funcall (symbol-function 'set)
+ 'find-tag-regexp-search-function
+ erlang-tags-orig-regexp-search-function)))
+
+
+(defun erlang-tags-recognize-tags-table ()
+ "Install our functions in all loaded TAGS files.
+
+This function is added to `tags-table-format-hooks' when searching
+for a tag on the form `module:tag'."
+ (if (null (funcall (symbol-function 'etags-recognize-tags-table)))
+ nil
+ (erlang-tags-install-local)
+ t))
+
+
+(defun erlang-tags-search-forward (tag &optional bound noerror count)
+ "Forward search function, aware of Erlang module prefix."
+ (if (string-match ":" tag)
+ (setq tag (substring tag (match-end 0) nil)))
+ ;; Avoid uninteded recursion.
+ (if (eq erlang-tags-orig-search-function 'erlang-tags-search-forward)
+ (search-forward tag bound noerror count)
+ (funcall erlang-tags-orig-search-function tag bound noerror count)))
+
+
+(defun erlang-tags-regexp-search-forward (tag &optional bound noerror count)
+ "Forward regexp search function, aware of Erlang module prefix."
+ (if (string-match ":" tag)
+ (setq tag (substring tag (match-end 0) nil)))
+ (if (eq erlang-tags-orig-regexp-search-function
+ 'erlang-tags-regexp-search-forward)
+ (re-search-forward tag bound noerror count)
+ (funcall erlang-tags-orig-regexp-search-function
+ tag bound noerror count)))
+
+
+;; t if point is at a tag line that matches TAG, containing
+;; module information. Assumes that all other order functions
+;; are stored in `erlang-tags-orig-[regex]-tag-order'.
+
+(defun erlang-tag-match-module-p (tag)
+ (erlang-tag-match-module-common-p tag erlang-tags-orig-tag-order))
+
+(defun erlang-tag-match-module-regexp-p (tag)
+ (erlang-tag-match-module-common-p tag erlang-tags-orig-regexp-tag-order))
+
+(defun erlang-tag-match-module-common-p (tag order)
+ (let ((mod nil)
+ (found nil))
+ (if (string-match ":" tag)
+ (progn
+ (setq mod (substring tag 0 (match-beginning 0)))
+ (setq tag (substring tag (match-end 0) nil))))
+ (while (and order (not found))
+ (setq found
+ (and (not (memq (car order)
+ '(erlang-tag-match-module-p
+ erlang-tag-match-module-regexp-p)))
+ (funcall (car order) tag)))
+ (setq order (cdr order)))
+ (and found
+ (or (null mod)
+ (string= mod (erlang-get-module-from-file-name
+ (file-of-tag)))))))
+
+
+;;; Tags completion, Emacs 19 `etags' specific.
+;;;
+;;; The basic idea is to create a second completion table `erlang-tags-
+;;; completion-table' containing all normal tags plus tags on the form
+;;; `module:tag'.
+
+
+(defun erlang-complete-tag ()
+ "Perform tags completion on the text around point.
+Completes to the set of names listed in the current tags table.
+
+Should the Erlang tags system be installed this command knows
+about Erlang modules."
+ (interactive)
+ (condition-case nil
+ (require 'etags)
+ (error nil))
+ (cond ((and erlang-tags-installed
+ (fboundp 'complete-tag)) ; Emacs 19
+ (let ((orig-tags-complete-tag (symbol-function 'tags-complete-tag)))
+ (fset 'tags-complete-tag
+ (symbol-function 'erlang-tags-complete-tag))
+ (unwind-protect
+ (funcall (symbol-function 'complete-tag))
+ (fset 'tags-complete-tag orig-tags-complete-tag))))
+ ((fboundp 'complete-tag) ; Emacs 19
+ (funcall (symbol-function 'complete-tag)))
+ ((fboundp 'tag-complete-symbol) ; XEmacs
+ (funcall (symbol-function 'tag-complete-symbol)))
+ (t
+ (error "This version of Emacs can't complete tags."))))
+
+
+;; Based on `tags-complete-tag', but this one uses
+;; `erlang-tag-completion-table' instead of `tag-completion-table'.
+;;
+;; This is the entry-point called by system function `completing-read'.
+(defun erlang-tags-complete-tag (string predicate what)
+ (save-excursion
+ ;; If we need to ask for the tag table, allow that.
+ (let ((enable-recursive-minibuffers t))
+ (visit-tags-table-buffer))
+ (if (eq what t)
+ (all-completions string (erlang-tags-completion-table) predicate)
+ (try-completion string (erlang-tags-completion-table) predicate))))
+
+
+;; `tags-completion-table' calls itself recursively, make it
+;; call our own wedge instead. Note that the recursive call
+;; is very rare; it only occurs when a tags-file contains
+;; `include'-statements.
+(defun erlang-tags-completion-table ()
+ "Build completion table. Tags on the form `tag' or `module:tag'."
+ (setq erlang-tags-orig-completion-table
+ (symbol-function 'tags-completion-table))
+ (fset 'tags-completion-table
+ (symbol-function 'erlang-tags-completion-table-1))
+ (unwind-protect
+ (erlang-tags-completion-table-1)
+ (fset 'tags-completion-table
+ erlang-tags-orig-completion-table)))
+
+
+(defun erlang-tags-completion-table-1 ()
+ (make-local-variable 'erlang-tags-completion-table)
+ (or erlang-tags-completion-table
+ (let ((tags-completion-table nil)
+ (tags-completion-table-function
+ 'erlang-etags-tags-completion-table))
+ (funcall erlang-tags-orig-completion-table)
+ (setq erlang-tags-completion-table tags-completion-table))))
+
+
+;; Based on `etags-tags-completion-table'. The difference is that we
+;; adds three symbols to the vector, the tag, module: and module:tag.
+;; The module is extracted from the file name of a tag. (This one
+;; only works if we are looking at an `etags' file. However, this is
+;; the only format supported by Emacs, so far.)
+(defun erlang-etags-tags-completion-table ()
+ (let ((table (make-vector 511 0))
+ (file nil))
+ (save-excursion
+ (goto-char (point-min))
+ ;; This monster regexp matches an etags tag line.
+ ;; \1 is the string to match;
+ ;; \2 is not interesting;
+ ;; \3 is the guessed tag name; XXX guess should be better eg DEFUN
+ ;; \4 is not interesting;
+ ;; \5 is the explicitly-specified tag name.
+ ;; \6 is the line to start searching at;
+ ;; \7 is the char to start searching at.
+ (while (progn
+ (while (and
+ (eq (following-char) ?\f)
+ (looking-at "\f\n\\([^,\n]*\\),.*\n"))
+ (setq file (buffer-substring
+ (match-beginning 1) (match-end 1)))
+ (goto-char (match-end 0)))
+ (re-search-forward
+ "\
+^\\(\\([^\177]+[^-a-zA-Z0-9_$\177]+\\)?\\([-a-zA-Z0-9_$?:]+\\)\
+\[^-a-zA-Z0-9_$?:\177]*\\)\177\\(\\([^\n\001]+\\)\001\\)?\
+\\([0-9]+\\)?,\\([0-9]+\\)?\n"
+ nil t))
+ (let ((tag (if (match-beginning 5)
+ ;; There is an explicit tag name.
+ (buffer-substring (match-beginning 5) (match-end 5))
+ ;; No explicit tag name. Best guess.
+ (buffer-substring (match-beginning 3) (match-end 3))))
+ (module (and file
+ (erlang-get-module-from-file-name file))))
+ (intern tag table)
+ (if (stringp module)
+ (progn
+ (intern (concat module ":" tag) table)
+ ;; Only the first one will be stored in the table.
+ (intern (concat module ":") table))))))
+ table))
+
+;;;
+;;; Prepare for other methods to run an Erlang slave process.
+;;;
+
+(defvar erlang-shell-function 'inferior-erlang
+ "Command to execute start a new Erlang shell.
+
+Change this variable to use your favorite
+Erlang compilation package.")
+
+(defvar erlang-shell-display-function 'inferior-erlang-run-or-select
+ "Command to execute to display Erlang shell.
+
+Change this variable to use your favorite
+Erlang compilation package.")
+
+(defvar erlang-compile-function 'inferior-erlang-compile
+ "Command to execute to compile current buffer.
+
+Change this variable to use your favorite
+Erlang compilation package.")
+
+(defvar erlang-compile-display-function 'inferior-erlang-run-or-select
+ "Command to execute to view last compilation.
+
+Change this variable to use your favorite
+Erlang compilation package.")
+
+(defvar erlang-next-error-function 'inferior-erlang-next-error
+ "Command to execute to go to the next error.
+
+Change this variable to use your favorite
+Erlang compilation package.")
+
+
+;;;###autoload
+(defun erlang-shell ()
+ "Start a new Erlang shell.
+
+The variable `erlang-shell-function' decides which method to use,
+default is to start a new Erlang host. It is possible that, in the
+future, a new shell on an already running host will be started."
+ (interactive)
+ (call-interactively erlang-shell-function))
+
+
+;;;###autoload (autoload 'run-erlang "erlang" "Start a new Erlang shell." t)
+
+;; It is customary for Emacs packages to supply a function on this
+;; form, even though it violates the `erlang-*' name convention.
+(fset 'run-erlang 'erlang-shell)
+
+
+(defun erlang-shell-display ()
+ "Display an Erlang shell, or start a new."
+ (interactive)
+ (call-interactively erlang-shell-display-function))
+
+
+;;;###autoload
+(defun erlang-compile ()
+ "Compile Erlang module in current buffer."
+ (interactive)
+ (call-interactively erlang-compile-function))
+
+
+(defun erlang-compile-display ()
+ "Display compilation output."
+ (interactive)
+ (call-interactively erlang-compile-display-function))
+
+
+(defun erlang-next-error ()
+ "Display next error message from the latest compilation."
+ (interactive)
+ (call-interactively erlang-next-error-function))
+
+
+
+;;;
+;;; Erlang Shell Mode -- Major mode used for Erlang shells.
+;;;
+
+;; This mode is designed to be implementation independent,
+;; e.g. it does not assume that we are running an inferior
+;; Erlang, there exists a lot of other possibilities.
+
+
+(defvar erlang-shell-buffer-name "*erlang*"
+ "*The name of the Erlang link shell buffer.")
+
+
+(defvar erlang-shell-mode-map nil
+ "*Keymap used by Erlang shells.")
+
+
+(defvar erlang-shell-mode-hook nil
+ "*User functions to run when an Erlang shell is started.
+
+This hook is used to change the behaviour of Erlang mode. It is
+normally used by the user to personalise the programming environment.
+When used in a site init file, it could be used to customise Erlang
+mode for all users on the system.
+
+The functioned added to this hook is runed every time a new Erlang
+shell is started.
+
+See also `erlang-load-hook', a hook which is runed once, when Erlang
+mode is loaded, and `erlang-mode-hook' which is runed every time a new
+Erlang source file is loaded into Emacs.")
+
+
+(defvar erlang-input-ring-file-name "~/.erlang_history"
+ "*When non-nil, file name used to store erlang shell history information.")
+
+
+(defun erlang-shell-mode ()
+ "Major mode for interacting with an Erlang shell.
+
+We assume that we already are in comint-mode.
+
+The following special commands are available:
+\\{erlang-shell-mode-map}"
+ (interactive)
+ (setq major-mode 'erlang-shell-mode)
+ (setq mode-name "Erlang Shell")
+ (erlang-mode-variables)
+ (if erlang-shell-mode-map
+ nil
+ (setq erlang-shell-mode-map (copy-keymap comint-mode-map))
+ (erlang-shell-mode-commands erlang-shell-mode-map))
+ (use-local-map erlang-shell-mode-map)
+ (set (make-local-variable 'compilation-parsing-end) 1)
+ (set (make-local-variable 'compilation-error-list) nil)
+ (set (make-local-variable 'compilation-old-error-list) nil)
+ ;; Needed when compiling directly from the Erlang shell.
+ (setq compilation-last-buffer (current-buffer))
+ (erlang-add-compilation-alist erlang-error-regexp-alist)
+ (setq comint-prompt-regexp "^[^>=]*> *")
+ (setq comint-eol-on-send t)
+ (setq comint-input-ignoredups t)
+ (setq comint-scroll-show-maximum-output t)
+ (setq comint-scroll-to-bottom-on-output t)
+ ;; In Emacs 19.30, `add-hook' has got a `local' flag, use it. If
+ ;; the call fails, just call the normal `add-hook'.
+ (condition-case nil
+ (progn
+ (funcall (symbol-function 'add-hook) 'comint-output-filter-functions
+ 'inferior-erlang-strip-delete nil t)
+ (funcall (symbol-function 'add-hook) 'comint-output-filter-functions
+ 'inferior-erlang-strip-ctrl-m nil t))
+ (error
+ (add-hook 'comint-output-filter-functions 'inferior-erlang-strip-delete)
+ (add-hook 'comint-output-filter-functions 'inferior-erlang-strip-ctrl-m)))
+ ;; Some older versions of comint doesn't have an input ring.
+ (if (fboundp 'comint-read-input-ring)
+ (progn
+ (setq comint-input-ring-file-name erlang-input-ring-file-name)
+ (comint-read-input-ring t)
+ (make-local-variable 'kill-buffer-hook)
+ (add-hook 'kill-buffer-hook 'comint-write-input-ring)))
+ (run-hooks 'erlang-shell-mode-hook))
+
+
+(defun erlang-shell-mode-commands (map)
+ (define-key map "\M-\t" 'erlang-complete-tag)
+ (define-key map "\C-a" 'comint-bol) ; Normally the other way around.
+ (define-key map "\C-c\C-a" 'beginning-of-line)
+ (define-key map "\C-d" nil) ; Was `comint-delchar-or-maybe-eof'
+ (define-key map "\C-x`" 'erlang-next-error))
+
+;;;
+;;; Inferior Erlang -- Run an Erlang shell as a subprocess.
+;;;
+
+(defvar inferior-erlang-display-buffer-any-frame nil
+ "*When nil, `inferior-erlang-display-buffer' use only selected frame.
+When t, all frames are searched. When 'raise, the frame is raised.")
+
+(defvar inferior-erlang-shell-type 'newshell
+ "The type of Erlang shell to use.
+
+When this variable is set to the atom `oldshell', the old shell is used.
+When set to `newshell' the new shell is used. Should the variable be
+nil, the default shell is used.
+
+This variable influence the setting of other variables.")
+
+(defvar inferior-erlang-machine "erl"
+ "*The name of the Erlang shell.")
+
+(defvar inferior-erlang-machine-options '()
+ "*The options used when activating the Erlang shell.
+
+This must be a list of strings.")
+
+(defvar inferior-erlang-process-name "inferior-erlang"
+ "*The name of the inferior Erlang process.")
+
+(defvar inferior-erlang-buffer-name erlang-shell-buffer-name
+ "*The name of the inferior erlang buffer.")
+
+(defvar inferior-erlang-prompt-timeout 60
+ "*Number of seconds before `inferior-erlang-wait-prompt' timeouts.
+
+The time specified is waited after every output made by the inferior
+Erlang shell. When this variable is t, we assume that we always have
+a prompt. When nil, we will wait forever, or until C-g.")
+
+(defvar inferior-erlang-process nil
+ "Process of last invoked inferior Erlang, or nil.")
+
+(defvar inferior-erlang-buffer nil
+ "Buffer of last invoked inferior Erlang, or nil.")
+
+;;;###autoload
+(defun inferior-erlang ()
+ "Run an inferior Erlang.
+
+This is just like running Erlang in a normal shell, except that
+an Emacs buffer is used for input and output.
+
+The command line history can be accessed with M-p and M-n.
+The history is saved between sessions.
+
+Entry to this mode calls the functions in the variables
+`comint-mode-hook' and `erlang-shell-mode-hook' with no arguments.
+
+The following commands imitate the usual Unix interrupt and
+editing control characters:
+\\{erlang-shell-mode-map}"
+ (interactive)
+ (require 'comint)
+ (let ((opts inferior-erlang-machine-options))
+ (cond ((eq inferior-erlang-shell-type 'oldshell)
+ (setq opts (cons "-oldshell" opts)))
+ ((eq inferior-erlang-shell-type 'newshell)
+ (setq opts (append '("-newshell" "-env" "TERM" "vt100") opts))))
+ (setq inferior-erlang-buffer
+ (apply 'make-comint
+ inferior-erlang-process-name inferior-erlang-machine
+ nil opts)))
+ (setq inferior-erlang-process
+ (get-buffer-process inferior-erlang-buffer))
+ (process-kill-without-query inferior-erlang-process)
+ (switch-to-buffer inferior-erlang-buffer)
+ (if (and (not (eq system-type 'windows-nt))
+ (eq inferior-erlang-shell-type 'newshell))
+ (setq comint-process-echoes t))
+ ;; `rename-buffer' takes only one argument in Emacs 18.
+ (condition-case nil
+ (rename-buffer inferior-erlang-buffer-name t)
+ (error (rename-buffer inferior-erlang-buffer-name)))
+ (erlang-shell-mode))
+
+
+(defun inferior-erlang-run-or-select ()
+ "Switch to an inferior Erlang buffer, possibly starting new process."
+ (interactive)
+ (if (null (inferior-erlang-running-p))
+ (inferior-erlang)
+ (inferior-erlang-display-buffer t)))
+
+
+(defun inferior-erlang-display-buffer (&optional select)
+ "Make the inferior Erlang process visible.
+The window is returned.
+
+Should `inferior-erlang-display-buffer-any-frame' be nil the buffer is
+displayed in the current frame. Should it be non-nil, and the buffer
+already is visible in any other frame, no new window will be created.
+Should it be the atom 'raise, the frame containing the window will
+be raised.
+
+Should the optional argument SELECT be non-nil, the window is
+selected. Should the window be in another frame, that frame is raised.
+
+Note, should the mouse pointer be places outside the raised frame, that
+frame will become deselected before the next command."
+ (interactive)
+ (or (inferior-erlang-running-p)
+ (error "No inferior Erlang process is running."))
+ (let ((win (inferior-erlang-window
+ inferior-erlang-display-buffer-any-frame))
+ (frames-p (fboundp 'selected-frame)))
+ (if (null win)
+ (let ((old-win (selected-window)))
+ (save-excursion
+ (switch-to-buffer-other-window inferior-erlang-buffer)
+ (setq win (selected-window)))
+ (select-window old-win))
+ (if (and window-system
+ frames-p
+ (or select
+ (eq inferior-erlang-display-buffer-any-frame 'raise))
+ (not (eq (selected-frame) (window-frame win))))
+ (raise-frame (window-frame win))))
+ (if select
+ (select-window win))
+ (sit-for 0)
+ win))
+
+
+(defun inferior-erlang-running-p ()
+ "Non-nil when an inferior Erlang is running."
+ (and inferior-erlang-process
+ (memq (process-status inferior-erlang-process) '(run open))
+ inferior-erlang-buffer
+ (buffer-name inferior-erlang-buffer)))
+
+
+(defun inferior-erlang-window (&optional all-frames)
+ "Return the window containing the inferior Erlang, or nil."
+ (and (inferior-erlang-running-p)
+ (if (and all-frames (>= erlang-emacs-major-version 19))
+ (get-buffer-window inferior-erlang-buffer t)
+ (get-buffer-window inferior-erlang-buffer))))
+
+
+(defun inferior-erlang-wait-prompt ()
+ "Wait until the inferior Erlang shell prompt appear."
+ (if (eq inferior-erlang-prompt-timeout t)
+ ()
+ (or (inferior-erlang-running-p)
+ (error "No inferior Erlang shell is running."))
+ (save-excursion
+ (set-buffer inferior-erlang-buffer)
+ (let ((msg nil))
+ (while (save-excursion
+ (goto-char (process-mark inferior-erlang-process))
+ (forward-line 0)
+ (not (looking-at comint-prompt-regexp)))
+ (if msg
+ ()
+ (setq msg t)
+ (message "Waiting for Erlang shell prompt (press C-g to abort)."))
+ (or (accept-process-output inferior-erlang-process
+ inferior-erlang-prompt-timeout)
+ (error "No Erlang shell prompt before timeout.")))
+ (if msg (message ""))))))
+
+
+(defun inferior-erlang-send-command (cmd &optional hist)
+ "Send command CMD to the inferior Erlang.
+
+The contents of the current command line (if any) will
+be placed at the next prompt.
+
+If optional second argument is non-nil the command is inserted into
+the history list.
+
+Return the position after the newly inserted command."
+ (or (inferior-erlang-running-p)
+ (error "No inferior Erlang process is running."))
+ (let ((old-buffer (current-buffer))
+ (insert-point (marker-position
+ (process-mark inferior-erlang-process)))
+ (insert-length (if comint-process-echoes
+ 0
+ (1+ (length cmd)))))
+ (set-buffer inferior-erlang-buffer)
+ (goto-char insert-point)
+ (insert cmd)
+ ;; Strange things happend if `comint-eol-on-send' is declared
+ ;; in the `let' expression above, but setq:d here. The
+ ;; `set-buffer' statement obviously makes the buffer local
+ ;; instance of `comint-eol-on-send' shadow this one.
+ ;; I'm considering this a bug in Elisp.
+ (let ((comint-eol-on-send nil)
+ (comint-input-filter (if hist comint-input-filter 'ignore)))
+ (comint-send-input))
+ ;; Adjust all windows whose points are incorrect.
+ (if (null comint-process-echoes)
+ (walk-windows
+ (function
+ (lambda (window)
+ (if (and (eq (window-buffer window) inferior-erlang-buffer)
+ (eq (window-point window) insert-point))
+ (set-window-point window
+ (+ insert-point insert-length)))))
+ nil t))
+ (set-buffer old-buffer)
+ (+ insert-point insert-length)))
+
+
+(defun inferior-erlang-strip-delete (&optional s)
+ "Remove `^H' (delete) and the characters it was supposed to remove."
+ (interactive)
+ (if (and (boundp 'comint-last-input-end)
+ (boundp 'comint-last-output-start))
+ (save-excursion
+ (goto-char
+ (if (interactive-p)
+ (symbol-value 'comint-last-input-end)
+ (symbol-value 'comint-last-output-start)))
+ (while (progn (skip-chars-forward "^\C-h")
+ (not (eq (point) (point-max))))
+ (delete-char 1)
+ (or (bolp)
+ (backward-delete-char 1))))))
+
+
+;; Basically `comint-strip-ctrl-m', with a few extra checks.
+(defun inferior-erlang-strip-ctrl-m (&optional string)
+ "Strip trailing `^M' characters from the current output group."
+ (interactive)
+ (if (and (boundp 'comint-last-input-end)
+ (boundp 'comint-last-output-start))
+ (let ((pmark (process-mark (get-buffer-process (current-buffer)))))
+ (save-excursion
+ (goto-char
+ (if (interactive-p)
+ (symbol-value 'comint-last-input-end)
+ (symbol-value 'comint-last-output-start)))
+ (while (re-search-forward "\r+$" pmark t)
+ (replace-match "" t t))))))
+
+
+(defun inferior-erlang-compile ()
+ "Compile the file in the current buffer.
+
+Should Erlang return `{error, nofile}' it could not load the object
+module after completing the compilation. This is due to a bug in the
+compile command `c' when using the option `outdir'.
+
+There exists two workarounds for this bug:
+
+ 1) Place the directory in the Erlang load path.
+
+ 2) Set the Emacs variable `erlang-compile-use-outdir' to nil.
+ To do so, place the following line in your `~/.emacs'-file:
+ (setq erlang-compile-use-outdir nil)"
+ (interactive)
+ (save-some-buffers)
+ (or (inferior-erlang-running-p)
+ (save-excursion
+ (inferior-erlang)))
+ (or (inferior-erlang-running-p)
+ (error "Error starting inferior Erlang shell."))
+ (let ((dir (file-name-directory (buffer-file-name)))
+ ;;; (file (file-name-nondirectory (buffer-file-name)))
+ (noext (substring (buffer-file-name) 0 -4))
+ ;; Hopefully, noone else will ever use these...
+ (tmpvar "Tmp7236")
+ (tmpvar2 "Tmp8742")
+ end)
+ (inferior-erlang-display-buffer)
+ (inferior-erlang-wait-prompt)
+ (setq end (inferior-erlang-send-command
+ (if erlang-compile-use-outdir
+ (format "c(\"%s\", [{outdir, \"%s\"}])." noext dir)
+ (format
+ (concat
+ "f(%s), {ok, %s} = file:get_cwd(), "
+ "file:set_cwd(\"%s\"), "
+ "%s = c(\"%s\"), file:set_cwd(%s), f(%s), %s.")
+ tmpvar2 tmpvar
+ dir
+ tmpvar2 noext tmpvar tmpvar tmpvar2))
+ nil))
+ (save-excursion
+ (set-buffer inferior-erlang-buffer)
+ (setq compilation-error-list nil)
+ (setq compilation-parsing-end end))
+ (setq compilation-last-buffer inferior-erlang-buffer)))
+
+
+;; `next-error' only accepts buffers with major mode `compilation-mode'
+;; or with the minor mode `compilation-minor-mode' activated.
+;; (To activate the minor mode is out of the question, since it will
+;; ruin the inferior Erlang keymap.)
+(defun inferior-erlang-next-error (&optional argp)
+ "Just like `next-error'.
+Capable of finding error messages in an inferior Erlang buffer."
+ (interactive "P")
+ (let ((done nil)
+ (buf (and (boundp 'compilation-last-buffer)
+ compilation-last-buffer)))
+ (if (and (bufferp buf)
+ (save-excursion
+ (set-buffer buf)
+ (and (eq major-mode 'erlang-shell-mode)
+ (setq major-mode 'compilation-mode))))
+ (unwind-protect
+ (progn
+ (setq done t)
+ (next-error argp))
+ (save-excursion
+ (set-buffer buf)
+ (setq major-mode 'erlang-shell-mode))))
+ (or done
+ (next-error argp))))
+
+
+(defun inferior-erlang-change-directory (&optional dir)
+ "Make the inferior erlang change directory.
+The default is to go to the directory of the current buffer."
+ (interactive)
+ (or dir (setq dir (file-name-directory (buffer-file-name))))
+ (or (inferior-erlang-running-p)
+ (error "No inferior Erlang is running."))
+ (inferior-erlang-display-buffer)
+ (inferior-erlang-wait-prompt)
+ (inferior-erlang-send-command (format "cd('%s')." dir) nil))
+
+;; Aliases for backward compatibility with older versions of Erlang Mode.
+;;
+;; Unfortuantely, older versions of Emacs doesn't have `defalias' and
+;; `make-obsolete' so we have to define our own `obsolete' function.
+
+(defun erlang-obsolete (sym newdef)
+ "Make the obsolete function SYM refer to the defined function NEWDEF.
+
+Simplified version of a combination `defalias' and `make-obsolete',
+it assumes that NEWDEF is loaded."
+ (fset sym (symbol-function newdef))
+ (if (fboundp 'make-obsolete)
+ (make-obsolete sym newdef)))
+
+
+(erlang-obsolete 'calculate-erlang-indent 'erlang-calculate-indent)
+(erlang-obsolete 'calculate-erlang-stack-indent
+ 'erlang-calculate-stack-indent)
+(erlang-obsolete 'at-erlang-keyword 'erlang-at-keyword)
+(erlang-obsolete 'at-erlang-operator 'erlang-at-operator)
+(erlang-obsolete 'beginning-of-erlang-clause 'erlang-beginning-of-clause)
+(erlang-obsolete 'end-of-erlang-clause 'erlang-end-of-clause)
+(erlang-obsolete 'mark-erlang-clause 'erlang-mark-clause)
+(erlang-obsolete 'beginning-of-erlang-function 'erlang-beginning-of-function)
+(erlang-obsolete 'end-of-erlang-function 'erlang-end-of-function)
+(erlang-obsolete 'mark-erlang-function 'erlang-mark-function)
+(erlang-obsolete 'pass-over-erlang-clause 'erlang-pass-over-function)
+(erlang-obsolete 'name-of-erlang-function 'erlang-name-of-function)
+
+
+;; The end...
+
+(provide 'erlang)
+
+(run-hooks 'erlang-load-hook)
+
+;;; erlang.el ends here
diff --git a/lib/erl/tools/utilities/appgen b/lib/erl/tools/utilities/appgen
new file mode 100755
index 0000000..b619222
--- /dev/null
+++ b/lib/erl/tools/utilities/appgen
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+
+if [ $# -ne 2 ];then
+ echo ""
+ echo "usage: $0 <appname> <prefix>"
+ echo ""
+ echo "appname is the title of the application to be generated"
+ echo "prefix is the prefix that will be appended to all files in"
+ echo "the application due to erlangs lack of a package structure. The prefix"
+ echo "is typicaly the first letter of each word in the name of the application"
+ echo ""
+ echo "example: $0 chat_server cs"
+ echo ""
+ exit 1
+fi
+
+APP_NAME=$1
+APP_NAME_UPPER_CASE=$(echo $APP_NAME | tr a-z A-Z)
+PREFIX=$2
+
+cd ../.appgen
+echo `pwd`
+
+cp -r blank_app $APP_NAME
+cp -r blank_app_rel "$APP_NAME"_rel
+
+cd "$APP_NAME"_rel
+ls blank_app* | ../rename.sh blank_app $APP_NAME
+cd ..
+
+# The base directory of the release
+./substitute.sh %%APP_NAME%% $APP_NAME "$APP_NAME"_rel/"$APP_NAME"_rel.rel.src
+
+
+cd $APP_NAME/src
+ls ba* | ../../rename.sh ba $PREFIX
+ls blank_app* | ../../rename.sh blank_app $APP_NAME
+cd -
+
+# The base directory of the application
+./substitute.sh %%APP_NAME_UPPER_CASE%% $APP_NAME_UPPER_CASE $APP_NAME/Makefile
+./substitute.sh %%APP_NAME_UPPER_CASE%% $APP_NAME_UPPER_CASE $APP_NAME/vsn.mk
+
+# The src directory of the application
+./substitute.sh %%APP_NAME%% $APP_NAME $APP_NAME/src/Makefile
+./substitute.sh %%APP_NAME_UPPER_CASE%% $APP_NAME_UPPER_CASE $APP_NAME/src/Makefile
+./substitute.sh %%PFX%% $PREFIX $APP_NAME/src/Makefile
+
+./substitute.sh %%APP_NAME%% $APP_NAME $APP_NAME/src/"$APP_NAME".erl
+./substitute.sh %%PFX%% $PREFIX $APP_NAME/src/"$APP_NAME".erl
+./substitute.sh %%PFX%% $PREFIX $APP_NAME/src/"$PREFIX"_sup.erl
+./substitute.sh %%APP_NAME%% $APP_NAME $APP_NAME/src/"$PREFIX"_sup.erl
+./substitute.sh %%PFX%% $PREFIX $APP_NAME/src/"$PREFIX"_server.erl
+./substitute.sh %%APP_NAME%% $APP_NAME $APP_NAME/src/"$PREFIX"_server.erl
+
+# include directory
+mv $APP_NAME/include/blank_app.hrl $APP_NAME/include/"$APP_NAME".hrl
+
+find $APP_NAME -name ".svn" | xargs rm -r
+mv $APP_NAME ../../lib
+mv "$APP_NAME"_rel ../../release
+
+echo ""
+echo "$APP_NAME has been generated and placed under lib/$APP_NAME"
+echo $APP_NAME"_rel has been generated and placed under release/$APP_NAME""_rel"
+echo ""
+
+cd ../utilities
diff --git a/lib/erl/tools/utilities/clean_release b/lib/erl/tools/utilities/clean_release
new file mode 100755
index 0000000..9202690
--- /dev/null
+++ b/lib/erl/tools/utilities/clean_release
@@ -0,0 +1,51 @@
+#!/bin/bash
+
+if [ $# -eq 1 ]; then
+ RELEASE_NAME=$1
+else
+ RELEASE_NAME=$(basename $(dirname $(dirname $(dirname $(which $0)))))
+fi
+
+LOCAL=$(dirname $(which $0))
+
+echo $LOCAL
+echo $RELEASE_NAME
+cd $LOCAL
+
+echo "
+-module(clean_release).
+-export([clean_release/1]).
+
+clean_release([ReleaseName]) ->
+ RelFile = atom_to_list(ReleaseName) ++ \".rel\",
+ case file:consult(RelFile) of
+ {ok, [{release, {RelName, RelVsn}, ErtsSpec, ReleaseSpecs}]} -> do_rest(RelFile, ReleaseSpecs);
+ {error, Reason} -> io:format(\"ERROR - Could not find file ~s~n\", [RelFile]), exit(Reason)
+ end,
+ os:cmd(\"cd ../;rm -rf \" ++ string:strip(os:cmd(\"basename `pwd`\"))).
+
+do_rest(RelFile, ReleaseSpecs) ->
+ io:format(\"Finding Orphans in ~p among current release specs ~p~n\", [RelFile, ReleaseSpecs]),
+ {ok, FileNameList} = file:list_dir(\"../\"),
+ Dirs = [FileName || FileName <- FileNameList, filelib:is_dir(\"../\" ++ FileName)] --
+ [string:strip(os:cmd(\"basename `pwd`\"), right, $\n)],
+ BigListOfReleaseSpecs = lists:foldl(fun(Dir, Acc) ->
+ OtherRelFile = \"../\" ++ Dir ++ \"/\" ++ RelFile,
+ io:format(\"Checking external release file ~p~n\", [OtherRelFile]),
+ case file:consult(OtherRelFile) of
+ {ok, [{release, {RelName, RelVsn}, ErtsSpec, ReleaseSpecs_}]} ->
+ Acc ++ ReleaseSpecs_;
+ _ ->
+ Acc
+ end end, [], Dirs),
+ Orphans = ReleaseSpecs -- BigListOfReleaseSpecs,
+ io:format(\"Removing orphan release specs ~p from ../../lib ~n\", [Orphans]),
+ lists:foreach(fun(Orphan) ->
+ os:cmd(\"rm -rf ../../lib/\" ++ atom_to_list(element(1, Orphan)) ++ \"-\" ++ element(2, Orphan))
+ end, Orphans).
+" > clean_release.erl
+
+erlc clean_release.erl
+
+CMD="erl -s clean_release clean_release $RELEASE_NAME -s erlang halt -noshell"
+$CMD
diff --git a/lib/erl/tools/utilities/edoc b/lib/erl/tools/utilities/edoc
new file mode 100755
index 0000000..632f261
--- /dev/null
+++ b/lib/erl/tools/utilities/edoc
@@ -0,0 +1,16 @@
+#!/bin/sh
+if [ "$#" -ne "1" ]
+then
+ echo $USAGE
+ exit 1
+fi
+
+CURRENT_DIR=`pwd`
+echo $CURRENT_DIR
+
+# Establish the otp base directory.
+MY_CMD=`which $0`
+MY_CMD_DIR=`dirname $MY_CMD`
+OTP_BASE_DIR=$MY_CMD_DIR/../..
+
+erl -noshell -pz $OTP_BASE_DIR/lib/fslib/ebin -s fs_lib s_apply edoc application "$1". "\"../../$1"\". []." " -s init stop | egrep "(EXIT|terminating)"