From df88b47cdafcc2e04452456942ea572a7b72e2f2 Mon Sep 17 00:00:00 2001 From: Lars G Thorsen Date: Tue, 26 Jan 2010 10:13:35 +0000 Subject: OTP-8343 The documentation is now possible to build in an open source environment after a number of bugs are fixed and some features are added in the documentation build process. - The arity calculation is updated. - The module prefix used in the function names for bif's are removed in the generated links so the links will look like http://www.erlang.org/doc/man/erlang.html#append_element-2 instead of http://www.erlang.org/doc/man/erlang.html#erlang:append_element-2 - Enhanced the menu positioning in the html documentation when a new page is loaded. - A number of corrections in the generation of man pages (thanks to Sergei Golovan) - Moved some man pages to more apropriate sections, pages in section 4 moved to 5 and pages in 6 moved to 7. - The legal notice is taken from the xml book file so OTP's build process can be used for non OTP applications. --- system/doc/book.xml | 52 -- system/doc/extensions/Makefile | 142 ----- system/doc/extensions/bit_syntax.xml | 403 -------------- system/doc/extensions/book.xml | 45 -- system/doc/extensions/fun_test.erl | 17 - system/doc/extensions/funparse.erl | 74 --- system/doc/extensions/funs.xml | 486 ----------------- system/doc/extensions/funs1.erl | 125 ----- system/doc/extensions/include.xml | 81 --- system/doc/extensions/list_comprehensions.erl | 118 ----- system/doc/extensions/list_comprehensions.xml | 205 -------- system/doc/extensions/list_comrehensions.erl | 75 --- system/doc/extensions/macros.xml | 177 ------- system/doc/extensions/make.dep | 21 - system/doc/extensions/mexpand.erl | 16 - system/doc/extensions/misc.xml | 310 ----------- system/doc/extensions/part.xml | 57 -- system/doc/extensions/records.xml | 284 ---------- system/doc/extensions/warning.gif | Bin 1498 -> 0 bytes system/doc/images/.gitignore | 0 system/doc/pics/Makefile | 58 -- system/doc/pics/app.gif | Bin 285 -> 0 bytes system/doc/pics/ede.gif | Bin 13644 -> 0 bytes system/doc/pics/ede_logo.gif | Bin 757 -> 0 bytes system/doc/pics/min_head.gif | Bin 2652 -> 0 bytes system/doc/pics/notes.gif | Bin 2005 -> 0 bytes system/doc/pics/otp.gif | Bin 13737 -> 0 bytes system/doc/pics/otp_logo.gif | Bin 1660 -> 0 bytes system/doc/pics/ps.gif | Bin 618 -> 0 bytes system/doc/pics/ref_man.gif | Bin 1530 -> 0 bytes system/doc/pics/user_guide.gif | Bin 1581 -> 0 bytes system/doc/top/bin/otp_man_index | 107 +++- system/doc/top/src/erl_html_tools.erl | 728 +++++++++++++++++++++++++- system/doc/top/src/erlresolvelinks.erl | 145 ++++- system/doc/top/src/permuted_index.erl | 1 - system/doc/top/templates/erlang.gif | Bin 2162 -> 0 bytes system/doc/top/templates/first.html.src | 104 ---- system/doc/top/templates/flip_closed.gif | Bin 82 -> 0 bytes system/doc/top/templates/flip_google.gif | Bin 257 -> 0 bytes system/doc/top/templates/flip_open.gif | Bin 86 -> 0 bytes system/doc/top/templates/flip_static.gif | Bin 109 -> 0 bytes system/doc/top/templates/flipmenu.js | 342 ------------ system/doc/top/templates/index.html.src | 4 +- system/doc/top/templates/otp_top.css | 53 -- system/doc/top/templates/system.html.src | 281 ---------- system/doc/top/templates/toc_.html.src | 105 ---- 46 files changed, 979 insertions(+), 3637 deletions(-) delete mode 100644 system/doc/book.xml delete mode 100644 system/doc/extensions/Makefile delete mode 100644 system/doc/extensions/bit_syntax.xml delete mode 100644 system/doc/extensions/book.xml delete mode 100644 system/doc/extensions/fun_test.erl delete mode 100644 system/doc/extensions/funparse.erl delete mode 100644 system/doc/extensions/funs.xml delete mode 100644 system/doc/extensions/funs1.erl delete mode 100644 system/doc/extensions/include.xml delete mode 100644 system/doc/extensions/list_comprehensions.erl delete mode 100644 system/doc/extensions/list_comprehensions.xml delete mode 100644 system/doc/extensions/list_comrehensions.erl delete mode 100644 system/doc/extensions/macros.xml delete mode 100644 system/doc/extensions/make.dep delete mode 100644 system/doc/extensions/mexpand.erl delete mode 100644 system/doc/extensions/misc.xml delete mode 100644 system/doc/extensions/part.xml delete mode 100644 system/doc/extensions/records.xml delete mode 100644 system/doc/extensions/warning.gif delete mode 100644 system/doc/images/.gitignore delete mode 100644 system/doc/pics/Makefile delete mode 100644 system/doc/pics/app.gif delete mode 100644 system/doc/pics/ede.gif delete mode 100644 system/doc/pics/ede_logo.gif delete mode 100644 system/doc/pics/min_head.gif delete mode 100644 system/doc/pics/notes.gif delete mode 100644 system/doc/pics/otp.gif delete mode 100644 system/doc/pics/otp_logo.gif delete mode 100644 system/doc/pics/ps.gif delete mode 100644 system/doc/pics/ref_man.gif delete mode 100644 system/doc/pics/user_guide.gif mode change 120000 => 100755 system/doc/top/bin/otp_man_index mode change 120000 => 100644 system/doc/top/src/erl_html_tools.erl mode change 120000 => 100644 system/doc/top/src/erlresolvelinks.erl delete mode 120000 system/doc/top/src/permuted_index.erl delete mode 100644 system/doc/top/templates/erlang.gif delete mode 100644 system/doc/top/templates/first.html.src delete mode 100755 system/doc/top/templates/flip_closed.gif delete mode 100755 system/doc/top/templates/flip_google.gif delete mode 100755 system/doc/top/templates/flip_open.gif delete mode 100755 system/doc/top/templates/flip_static.gif delete mode 100755 system/doc/top/templates/flipmenu.js delete mode 100644 system/doc/top/templates/otp_top.css delete mode 100644 system/doc/top/templates/system.html.src delete mode 100644 system/doc/top/templates/toc_.html.src (limited to 'system/doc') diff --git a/system/doc/book.xml b/system/doc/book.xml deleted file mode 100644 index d1ec093019..0000000000 --- a/system/doc/book.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - -
- - 19972009 - Ericsson AB. All Rights Reserved. - - - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - - - Erlang/OTP System Documentation - OTP Team - - 2009-08-21 - A - book.xml -
- - - - - - - - - - - - - - - - - - - - -
- diff --git a/system/doc/extensions/Makefile b/system/doc/extensions/Makefile deleted file mode 100644 index cfc506f7e8..0000000000 --- a/system/doc/extensions/Makefile +++ /dev/null @@ -1,142 +0,0 @@ -# ``The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved via the world wide web at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# The Initial Developer of the Original Code is Ericsson Utvecklings AB. -# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include $(ERL_TOP)/erts/vsn.mk -#VSN=$(SYSTEM_VSN) - -# ---------------------------------------------------- -# Include dependency -# ---------------------------------------------------- - -include make.dep - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/doc/extensions - -# ---------------------------------------------------- -# Target Specs -# ---------------------------------------------------- -XML_PART_FILES = part.xml -XML_CHAPTER_FILES = \ - funs.xml \ - macros.xml \ - misc.xml \ - include.xml \ - records.xml \ - list_comprehensions.xml \ - bit_syntax.xml - -BOOK_FILES = book.xml - -GIF_FILES = note.gif - -PS_FILES = - -# ---------------------------------------------------- - -HTML_FILES = \ - $(XML_PART_FILES:%.xml=%.html) - -HTMLDIR = . -EXTRA_FILES = $(DEFAULT_GIF_FILES) \ - $(DEFAULT_HTML_FILES) \ - $(XML_CHAPTER_FILES:%.xml=%.html) - -TEX_FILES_BOOK = \ - $(BOOK_FILES:%.xml=%.tex) -TEX_FILES_USERS_GUIDE = \ - $(XML_CHAPTER_FILES:%.xml=%.tex) - -TOP_PDF_FILE = extensions-$(VSN).pdf -TOP_PS_FILE = extensions-$(VSN).ps - -$(TOP_PDF_FILE): book.dvi $(ERL_TOP)/erts/vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@ - -$(TOP_PS_FILE): book.dvi $(ERL_TOP)/erts/vsn.mk - $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@ - -# ---------------------------------------------------- -# FLAGS -# ---------------------------------------------------- -XML_FLAGS += -DVIPS_FLAGS += - -# ---------------------------------------------------- -# Targets -# ---------------------------------------------------- - -ifeq ($(DOCTYPE),pdf) -docs: pdf -else -ifeq ($(DOCTYPE),ps) -docs: ps -else -docs: html -endif -endif - -pdf: $(TOP_PDF_FILE) - -ps: $(TOP_PS_FILE) - -html: $(HTML_FILES) $(GIF_FILES) - -debug opt: - -clean_tex: - -rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_BOOK) - -clean: - rm -f *.html $(TEX_FILES_USERS_GUIDE) - rm -f $(TOP_PS_FILES) - rm -f errs core *~ $(LATEX_CLEAN) - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf - $(INSTALL_DIR) $(RELEASE_PATH)/pdf - $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps - $(INSTALL_DIR) $(RELEASE_PATH)/ps - $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR) - $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \ - $(RELSYSDIR) -endif -endif - -release_spec: - - - diff --git a/system/doc/extensions/bit_syntax.xml b/system/doc/extensions/bit_syntax.xml deleted file mode 100644 index d86f73cd9a..0000000000 --- a/system/doc/extensions/bit_syntax.xml +++ /dev/null @@ -1,403 +0,0 @@ - - - - -
- - 20002009 - Ericsson AB. All Rights Reserved. - - - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - - - The Bit Syntax - Björn Gustavsson - Bjarne Däcker - 1 - Bjarne DäKer - - 00-06-21 - PA1 - bit_syntax.sgml -
-

This section describes the "bit syntax" which was added to - the Erlang language in release 5.0 (R7). - Compared to the original bit syntax prototype - by Claes Wikström and Tony Rogvall (presented on the - Erlang User's Conference 1999), this implementation differs - primarily in the following respects, -

- - -

the character pairs '<<' and '>>' are used to delimit - a binary patterns and constructor (not '<' and '>' as in - the prototype), -

-
- -

the tail syntax ('|Variable') has been eliminated, -

-
- -

all size expressions must be bound, -

-
- -

a type unit:U has been added, -

-
- -

lists and tuples cannot be generated -

-
- -

there are no paddings whatsoever. -

-
-
- -
- Introduction -

In Erlang a Bin is used for constructing binaries and - matching binary patterns. A Bin is written with the - following syntax:

- > - ]]> -

A Bin is a low-level sequence of bytes. The purpose of a - Bin is to be able to, from a high level, - construct a binary, -

- > - ]]> -

in which case all elements must be bound, or to - match a binary, -

- > = Bin - ]]> -

where Bin is bound, and where the elements are bound or unbound, - as in any match. -

-

Each element specifies a certain segment of the binary. - A segment is is a set of contiguous bits of the binary (not - necessarily on a byte boundary). The first element specifies - the initial segment, the second element specifies the following - segment etc. -

-

The following examples illustrate how binaries are constructed - or matched, and how elements and tails are specified. -

- -
- Examples -

Example 1: A binary can be constructed from a set of - constants or a string literal:

- >, - Bin12 = <<"abc">> - ]]> -

yields binaries of size 3; binary_to_list(Bin11) - evaluates to [1, 17, 42], and - binary_to_list(Bin12) evaluates to [97, 98, 99]. -

-

Example 2: Similarly, a binary can be constructed - from a set of bound variables:

- > - ]]> -

yields a binary of size 4, and binary_to_list(Bin2) - evaluates to [1, 17, 00, 42] too. Here we used a - size expression for the variable C in order to - specify a 16-bits segment of Bin2. -

-

Example 3: A Bin can also be used for matching: if - D, E, and F are unbound variables, and - Bin2 is bound as in the former example,

- > = Bin2 - ]]> -

yields D = 273, E = 00, and F binds to a binary - of size 1: binary_to_list(F) = [42]. -

-

Example 4: The following is a more elaborate example - of matching, where Dgram is bound to the consecutive - bytes of an IP datagram of IP protocol version 4, and where we - want to extract the header and the data of the datagram:

- > when HLen >= 5, 4*HLen =< DgramSize -> - OptsLen = 4*(HLen - ?IP_MIN_HDR_LEN), - <> = RestDgram, - ... - end. - ]]> -

Here the segment corresponding to the Opts variable - has a type modifier specifying that Opts should - bind to a binary. All other variables have the default type - equal to unsigned integer. -

-

An IP datagram header is of variable length, and its length - - measured in the number of 32-bit words - is given in the segment - corresponding to HLen, the minimum value of which is - 5. It is the segment corresponding to Opts that is - variable: if HLen is equal to 5, Opts will be an - empty binary. -

-

The tail variables RestDgram and Data bind to - binaries, as all tail variables do. Both may bind to empty - binaries. -

-

If the first 4-bits segment of Dgram is not equal to - 4, or if HLen is less than 5, or if the size of - Dgram is less than 4*HLen, the match of - Dgram fails. -

-
-
- -
- A Lexical Note -

Note that ">]]>" will be interpreted as - ">]]>", which is a syntax error. - The correct way to write the expression is ">]]>".

-
- -
- Segments -

Each segment has the following general syntax:

-

Value:Size/TypeSpecifierList

-

Both the Size and the TypeSpecifier or both may be - omitted; thus the following variations are allowed: -

-

Value

-

Value:Size

-

Value/TypeSpecifierList

-

Default values will be used for missing specifications. The default - values are described in the section "Defaults" below. -

-

Used in binary construction, the Value part is any expression. - Used in binary matching, the Value part must be a literal or - variable. You can read more about the Value part in the - sections about constructing binaries and matching binaries. -

-

The Size part of the segment multiplied by the unit in the - TypeSpecifierList (described below) gives the number of bits - for the segment. In construction, Size is any expression that - evaluates to an integer. In matching, Size must be a constant - expression or a variable. -

-

The TypeSpecifierList is a list of type specifiers separated by - hyphens. -

- - Type - The type can be integer, float, or binary. - Signedness - The signedness specification can be either signed - or unsigned. Note that signedness only matters for matching. - Endianness - The endianness specification can be either big, - little, or native. Native-endian means that - the endian will be resolved at load time to be either - big-endian or little-endian, depending on what is "native" - for the CPU that the Erlang machine is run on. - Unit - The unit size is given as unit:IntegerLiteral. - The allowed range is 1-256. It will be multiplied by the Size - specifier to give the effective size of the segment. - -

Example: -

- -X:4/little-signed-integer-unit:8 - -

This element has a total size of 4*8 = 32 bits, and it contains a - signed integer in little-endian order.

-
- -
- Defaults -

The default type for a segment is integer. The default type - does not depend on the value, even if the value is a literal. - For instance, the default type in '>]]>' is integer, - not float. -

-

The default Size depends on the type. - For integer it is 8. For float it is 64. - For binary it is all of the binary. In matching, this default - value is only valid for the very last element. All other binary elements - in matching must have a size specification. -

-

The default unit depends on the the type. - For integer and float it is 1. - For binary it is 8. -

-

The default signedness is unsigned. -

-

The default endianness is big.

-
- -
- Constructing Binaries -

This section describes the rules for constructing binaries using - the bit syntax. Unlike when constructing lists or tuples, the construction - of a binary can fail with a badarg exception. -

-

There can be zero or more segments in a binary to be constructed. - The expression '>]]>' constructs a zero length binary. -

-

Each segment in a binary can consist of zero or more bits. - There are no alignment rules for individual segments, but the total - number of bits in all segments must be evenly divisible by 8, - or in other words, the resulting binary must consist of a whole number - of bytes. An badarg exception will be thrown if the resulting - binary is not byte-aligned. Example: -

- > - ]]> -

The total number of bits is 7, which is not evenly divisible by 8; - thus, there will be badarg exception (and a compiler warning - as well). The following example -

- > - ]]> -

will successfully construct a binary of 8 bits, or one byte. (Provided - that all of X, Y and Z are integers.) -

-

As noted earlier, segments have the following general syntax: -

-

Value:Size/TypeSpecifierList

-

When constructing binaries, Value and Size can be - any Erlang expression. However, for syntactical reasons, - both Value and Size must be enclosed in parenthesis - if the expression consists of anything more than a single literal - or variable. The following gives a compiler syntax error: -

- > - ]]> -

This expression must be rewritten to -

- > - ]]> -

in order to be accepted by the compiler. -

- -
- Including Literal Strings -

As syntactic sugar, an literal string may be written instead of a - element.

- > ]]> -

which is syntactic sugar for

- > ]]> -
-
- -
- Matching Binaries -

This section describes the rules for matching binaries using the - bit syntax. -

-

There can be zero or more segments in a binary binary pattern. - A binary pattern can occur in every place patterns are allowed, also - inside other patterns. Binary patterns cannot be nested. -

-

The pattern '>]]>' matches a zero length binary. -

-

Each segment in a binary can consist of zero or more bits. -

-

A segment of type binary must have a size evenly divisible by 8. -

-

This means that the following head will never match:

- >) -> ]]> -

As noted earlier, segments have the following general syntax: -

-

Value:Size/TypeSpecifierList

-

When matching Value value must be either a variable or an integer - or floating point literal. Expressions are not allowed. -

-

Size must be an integer literal, or a previously bound variable. - Note that the following is not allowed:

- >) -> - {X,T}. ]]> -

The two occurrences of N are not related. The compiler - will complain that the N in the size field is unbound. -

-

The correct way to write this example is like this:

- - <> = Bin, - {X,T}. ]]> - -
- Getting the Rest of the Binary -

To match out the rest of binary, specify a binary field without size:

- >) -> ]]> -

As always, the size of the tail must be evenly divisible by 8. -

-
-
- -
- Traps and Pitfalls -

Assume that we need a function that creates a binary out of a - list of triples of integers. A first (inefficient) version of such - a function could look like this:

- - triples_to_bin(T, <<>>). - -triples_to_bin([{X,Y,Z} | T], Acc) -> - triples_to_bin(T, <>); % inefficient -triples_to_bin([], Acc) -> - Acc. ]]> -

The reason for the inefficiency of this function is that for - each triple, the binary constructed so far (Acc) is copied. - (Note: The original bit syntax prototype avoided the copy operation - by using segmented binaries, which are not implemented in R7.) -

-

The efficient way to write this function in R7 is:

- - triples_to_bin(T, []). - -triples_to_bin([{X,Y,Z} | T], Acc) -> - triples_to_bin(T, [<> | Acc]); -triples_to_bin([], Acc) -> - list_to_binary(lists:reverse(Acc)). ]]> -

Note that list_to_binary/1 handles deep lists of binaries - and small integers. (This fact was previously undocumented.) -

-
-
- diff --git a/system/doc/extensions/book.xml b/system/doc/extensions/book.xml deleted file mode 100644 index ffdbe6cb44..0000000000 --- a/system/doc/extensions/book.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - -
- - 1997 - 2007 - Ericsson AB, All Rights Reserved - - - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - - - Erlang Extensions Since 4.4 - OTP Team - - 1997-05-21 - - book.sgml -
- - - Erlang Extensions Since 4.4 - - - - - - - - -
- diff --git a/system/doc/extensions/fun_test.erl b/system/doc/extensions/fun_test.erl deleted file mode 100644 index 8472fd87f8..0000000000 --- a/system/doc/extensions/fun_test.erl +++ /dev/null @@ -1,17 +0,0 @@ -%1 --module(fun_test). --export([t1/0, t2/0, t3/0, t4/0, double/1]). --import(lists, [map/2]). - -t1() -> map(fun(X) -> 2 * X end, [1,2,3,4,5]). - -t2() -> map(fun double/1, [1,2,3,4,5]). - -t3() -> map({?MODULE, double}, [1,2,3,4,5]). - -double(X) -> X * 2. -%1 - - -t4() -> - "hello world". diff --git a/system/doc/extensions/funparse.erl b/system/doc/extensions/funparse.erl deleted file mode 100644 index 5e23c90df9..0000000000 --- a/system/doc/extensions/funparse.erl +++ /dev/null @@ -1,74 +0,0 @@ --module(funparse). --compile(export_all). --import(lists, [reverse/1]). - -%17 -%% > hof:parse([a,c]). -%% {ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}} -%% > hof:parse([a,d]). -%% {ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}} -%% > hof:parse([b,c]). -%% {ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}} -%% > hof:parse([b,d]). -%% {ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}} -%% > hof:parse([a,b]). -%% fail -%17 - -%% Grammar = (a | b) & (c | d) - -%12 -parse(List) -> - (grammar())(List). -%12 - -%13 -grammar() -> - pand( - por(pconst(a), pconst(b)), - por(pconst(c), pconst(d))). -%13 - -%14 -pconst(X) -> - fun (T) -> - case T of - [X|T1] -> {ok, {const, X}, T1}; - _ -> fail - end - end. -%14 - -%15 -por(P1, P2) -> - fun (T) -> - case P1(T) of - {ok, R, T1} -> - {ok, {'or',1,R}, T1}; - fail -> - case P2(T) of - {ok, R1, T1} -> - {ok, {'or',2,R1}, T1}; - fail -> - fail - end - end - end. -%15 - -%16 -pand(P1, P2) -> - fun (T) -> - case P1(T) of - {ok, R1, T1} -> - case P2(T1) of - {ok, R2, T2} -> - {ok, {'and', R1, R2}}; - fail -> - fail - end; - fail -> - fail - end - end. -%16 diff --git a/system/doc/extensions/funs.xml b/system/doc/extensions/funs.xml deleted file mode 100644 index f9c003c8ee..0000000000 --- a/system/doc/extensions/funs.xml +++ /dev/null @@ -1,486 +0,0 @@ - - - - -
- - 1997 - 2007 - Ericsson AB, All Rights Reserved - - - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - - - Programming with Funs - Joe Armstrong - Bjarne Däcker - 1 - Bjarne DäKer - - 96-01-16 - PA1 - funs.sgml -
-

This section introduces functional objects (Funs). That is a new data type introduced in Erlang 4.4. Functions which takes Funs as arguments, or which return Funs are called higher order functions.

- - Funs can be passed as arguments to other functions, just like lists or tuples - functions can be written which return Funs, just like any other data object. - - -
- Higher Order Functions -

Funs encourages us to encapsulate common patterns of design into functional forms called higher order functions. These functions not only shortens programs, but also produce clearer programs because the intended meaning of the program is explicitly rather than implicitly stated.

-

The concepts of higher order functions and procedural abstraction are introduced with two brief examples.

- -
- Example 1 - map -

If we want to double every element in a list, we could write a function named double:

- - -double([H|T]) -> [2*H|double(T)]; -double([]) -> [] -

This function obviously doubles the argument entered as input as follows:

-
-
-> double([1,2,3,4]).
-[2,4,6,8]      
-

We now add the function add_one, which adds one to every element in a list:

- - -add_one([H|T]) -> [H+1|add_one(T)]; -add_one([]) -> []. -

These functions, double and add_one, have a very similar structure. We can exploit this fact and write a function map which expresses this similarity:

- -

We can now express the functions double and add_one in terms of map as follows:

- - -double(L) -> map(fun(X) -> 2*X end, L). -add_one(L) -> map(fun(X) -> 1 + X end, L). -

map(F, List) is a function which takes a function F and a list L as arguments and - returns the new list which is obtained by applying F to each of the elements in L.

-

The process of abstracting out the common features of a number of different programs is called procedural abstraction. Procedural abstraction can be used in order to write several different functions which have a similar structure, but differ only in some minor detail. This is done as follows:

- - write one function which represents the common features of these functions - parameterize the difference in terms of functions which are passed as arguments to the common function. - -
- -
- Example 2 - foreach -

This example illustrates procedural abstraction. Initially, we show the following two examples written as conventional functions:

- - all elements of a list are printed onto a stream - a message is broadcast to a list of processes. - - - -print_list(Stream, [H|T]) -> - io:format(Stream, "~p~n", [H]), - print_list(Stream, T); -print_on_list(Stream, []) -> - true. - - -broadcast(Msg, [Pid|Pids]) -> - Pid ! Msg, - broadcast(Msg, Pids); -broadcast(_, []) -> - true. -

Both these functions have a very similar structure. They both iterate over a list doing something to each element in the list. The "something" has to be carried round as an extra argument to the function which does this.

-

The function foreach expresses this similarity:

- -

Using foreach, print_on_list becomes:

- - -foreach(fun(H) -> io:format(S, "~p~n~,[H]) end, L) -

broadcast becomes:

- - -foreach(fun(Pid) -> Pid ! M end, L) -

foreach is evaluated for its side-effect and not its value. foreach(Fun ,L) calls Fun(X) for each element X in L and the processing occurs in the order in which the elements were defined in L. map does not define the order in which its elements are processed.

-
-
- -
- Advantages of Higher Order Functions -

Programming with higher order functions, such as map and foreach, has a number of advantages:

- - It is much easier to understand the program and the intention of the programmer is clearly expressed in the code. The statement foreach(fun(X) -> clearly indicates that the intention of this program is to do something to each element in the list L. We also know that the function which is passed as the first argument of foreach takes one argument X, which will be successively bound to each of the elements in L. - Functions which take Funs as arguments are much easier to re-use than other functions. - -
- -
- The Syntax of Funs -

Funs are written with the syntax:

- - -F = fun (Arg1, Arg2, ... ArgN) -> - ... - end -

This creates an anonymous function of N arguments and binds it to the variable F.

-

If we have already written a function in the same module and wish to pass this function as an argument, we can use the following syntax:

- - -F = fun FunctionName/Arity -

With this form of function reference, the function which is referred to does not need to be exported from the module.

-

We can also refer to a function defined in a different module with the following syntax:

- - -F = {Module, FunctionName} -

In this case, the function must be exported from the module in question.

-

The follow program illustrates the different ways of creating Funs:

- -

We can evaluate the fun F with the syntax:

- - -F(Arg1, Arg2, ..., Argn) -

To check whether a term is a Fun, use the test function/1 - in a guard. Example:

- -f(F, Args) when function(F) -> - apply(F, Args); -f(N, _) when integer(N) -> - N. -

Funs are a distinct type. The BIFs erlang:fun_info/1,2 can - be used to retrieve information about a fun, and the BIF - erlang:fun_to_list/1 returns a textual representation of a fun. - The check_process_code/2 BIF returns true if the - process contains funs that depend on the old version of - a module.

- -

In OTP R5 and earlier releases, funs were represented - using tuples.

-
-
- -
- Variable Bindings within a Fun -

The scope rules for variables which occur in Funs are as follows:

- - All variables which occur in the head of a Fun are assumed to be "fresh" variables. - Variables which are defined before the Fun, and which occur in function calls or guard tests within the Fun, have the values they had outside the Fun. - No variables may be exported from a Fun. - -

The following examples illustrate these rules:

- - -print_list(File, List) -> - {ok, Stream} = file:open(File, write), - foreach(fun(X) -> io:format(Stream,"~p~n",[X]) end, List), - file:close(Stream). -

In the above example, the variable X which is defined in the head of the Fun is a new variable. The value of the variable Stream which is used within within the Fun gets its value from the - file:open line.

-

Since any variable which occurs in the head of a Fun is considered a new variable it would be equally valid to write:

- - -print_list(File, List) -> - {ok, Stream} = file:open(File, write), - foreach(fun(File) -> - io:format(Stream,"~p~n",[File]) - end, List), - file:close(Stream). -

In this example, File is used as the new variable instead of X. This is rather silly since code in the body of the Fun cannot refer to the variable File which is defined outside the Fun. Compiling this example will yield the diagnostic:

- - -./FileName.erl:Line: Warning: variable 'File' - shadowed in 'lambda head' -

This reminds us that the variable File which is defined inside the Fun collides with the variable File which is defined outside the Fun.

-

The rules for importing variables into a Fun has the consequence that certain pattern matching operations have to be moved into guard expressions and cannot be written in the head of the Fun. For example, we might write the following code if we intend the first clause of F to be evaluated when the value of its argument is Y:

- - -f(...) -> - Y = ... - map(fun(X) when X == Y -> - ; - (_) -> - ... - end, ...) - ... -

instead of

- - -f(...) -> - Y = ... - map(fun(Y) -> - ; - (_) -> - ... - end, ...) - ... -
- -
- Funs and the Module Lists -

The following examples show a dialogue with the Erlang shell. All the higher order functions discussed are exported from the module lists.

- -
- map - -

map takes a function of one argument and a list of terms. It returns the list obtained by applying the function to every argument in the list.

-
-
-1> Double = fun(X) -> 2 * X end.
-#Fun<erl_eval>
-2>lists:map(Double, [1,2,3,4,5]).
-[2,4,6,8,10]      
-

When a new Fun is defined in the shell, the value of the Fun is printed as ]]>

-
- -
- any - -

any takes a predicate P of one argument and a list of terms. A predicate is a function which returns true or false. any is true if there is a term X in the list such that P(X) is true.

-

We define a predicate Big(X) which is true if its argument is greater that 10.

-
-
-3> Big =  fun(X) -> if X > 10 -> true; true -> false end end.
-#Fun<erl_eval>
-4>lists:any(Big, [1,2,3,4]).
-false.
-5> lists:any(Big, [1,2,3,12,5]).
-true.      
-
- -
- all - -

all has the same arguments as any. It is true if the predicate applied to all elements in the list is true.

-
-
-6>lists:all(Big, [1,2,3,4,12,6]).   
-false
-7>lists:all(Big, [12,13,14,15]).       
-true      
-
- -
- foreach - -

foreach takes a function of one argument and a list of terms. The function is applied to each argument in the list. foreach returns ok. It is used for its side-effect only.

-
-
-8> lists:foreach(fun(X) -> io:format("~w~n",[X]) end, [1,2,3,4]). 
-1
-2
-3
-4
-true      
-
- -
- foldl - -

foldl takes a function of two arguments, an accumulator and a list. The function is called with two arguments. The first argument is the successive elements in the list, the second argument is the accumulator. The function must return a new accumulator which is used the next time the function is called.

-

If we have a list of lists L = ["I","like","Erlang"], then we can sum the lengths of all the strings in L as follows:

-
-
-9> L = ["I","like","Erlang"].
-["I","like","Erlang"]
-10> lists:foldl(fun(X, Sum) -> length(X) + Sum end, 0, L).                    
-11      
-

foldl works like a while loop in an imperative language:

- - - L = ["I","like","Erlang"], - Sum = 0, - while( L != []){ - Sum += length(head(L)), - L = tail(L) - end -
- -
- mapfoldl - -

mapfoldl simultaneously maps and folds over a list. The following example shows how to change all letters in L to upper case and count them.

-

First upcase:

-
-
-11> Upcase =  fun(X) when $a =< X,  X =< $z -> X + $A - $a;
-(X) -> X 
-end.
-#Fun<erl_eval>
-12> Upcase_word = 
-fun(X) -> 
-lists:map(Upcase, X) 
-end.
-#Fun<erl_eval>
-13>Upcase_word("Erlang").
-"ERLANG"
-14>lists:map(Upcase_word, L).
-["I","LIKE","ERLANG"]      
-

Now we can do the fold and the map at the same time:

-
-
-14> lists:mapfoldl(fun(Word, Sum) ->
-14>    {Upcase_word(Word), Sum + length(Word)}
-14>              end, 0, L).
-{["I","LIKE","ERLANG"],11}      
-
- -
- filter - -

filter takes a predicate of one argument and a list and returns all element in the list which satisfy the predicate.

-
-
-15>lists:filter(Big, [500,12,2,45,6,7]).
-[500,12,45]      
-

When we combine maps and filters we can write very succinct and obviously correct code. For example, suppose we want to define a set difference function. We want to define diff(L1, L2) to be the difference between the lists L1 and L2. - This is the list of all elements in L1 which are not contained in L2. This code can be written as follows:

- - -diff(L1, L2) -> - filter(fun(X) -> not member(X, L2) end, L1). -

The AND intersection of the list L1 and L2 is also easily defined:

- - -intersection(L1,L2) -> filter(fun(X) -> member(X,L1) end, L2). -
- -
- takewhile - -

takewhile(P, L) takes elements X from a list L as long as the predicate P(X) is true.

-
-
-16>lists:takewhile(Big, [200,500,45,5,3,45,6]).  
-[200,500,45]      
-
- -
- dropwhile - -

dropwhile is the complement of takewhile.

-
-
-17> lists:dropwhile(Big, [200,500,45,5,3,45,6]).
-[5,3,45,6]      
-
- -
- splitlist - -

splitlist(P, L) splits the list L into the two sub-lists {L1, L2}, where L = takewhile(P, L) and L2 = dropwhile(P, L).

-
-
-18>lists:splitlist(Big, [200,500,45,5,3,45,6]).          
-{[200,500,45],[5,3,45,6]}      
-
- -
- first - -

first returns {true, R}, where R is the first element in a list satisfying a predicate or false:

-
-
-19>lists:first(Big, [1,2,45,6,123]).
-{true,45}
-20>lists:first(Big, [1,2,4,5]).        
-false      
-
-
- -
- Funs which Return Funs -

So far, this section has only described functions which take Funs as arguments. It is also possible to write more powerful functions which themselves return Funs. The following examples illustrate these type of functions.

- -
- Simple Higher Order Functions -

Adder(X) is a function which, given X, returns a new function G such that G(K) returns K + X.

-
-
-21> Adder = fun(X) -> fun(Y) -> X + Y end end.
-#Fun<erl_eval>
-22> Add6 = Adder(6).
-#Fun<erl_eval>
-23>Add6(10).
-16      
-
- -
- Infinite Lists -

The idea is to write something like:

- - --module(lazy). --export([ints_from/1]). -ints_from(N) -> - fun() -> - [N|ints_from(N+1)] - end. -

Then we can proceed as follows:

- XX = lazy:ints_from(1). -#Fun -25> XX(). -[1|#Fun] -26> hd(XX()). -1 -27> Y = tl(XX()). -#Fun -28> hd(Y()). -2 ]]> -

etc. - this is an example of "lazy embedding"

-
- -
- Parsing -

The following examples show parsers of the following type:

-
-Parser(Toks) -> {ok, Tree, Toks1} | fail      
-

Toks is the list of tokens to be parsed. A successful parse returns {ok, Tree, Toks1}, where Tree is a parse tree and Toks1 is a tail of Tree which contains symbols encountered after the structure which was correctly parsed. Otherwise fail is returned.

-

The example which follows illustrates a simple, functional parser which parses the grammar:

-
-(a | b) & (c | d)      
-

The following code defines a function pconst(X) in the module funparse, which returns a Fun which parses a list of tokens.

- -

This function can be used as follows:

-
-29>P1 = funparse:pconst(a).
-#Fun<hof>
-30> P1([a,b,c]).
-{ok,{const,a},[b,c]}
-31> P1([x,y,z]).     
-fail      
-

Next, we define the two higher order functions pand and por which combine primitive parsers to produce more complex parsers. Firstly pand:

- -

Given a parser P1 for grammar G1, and a parser P2 for grammar G2, pand(P1, P2) - returns a parser for the grammar which consists of sequences of tokens which satisfy G1 followed by sequences of tokens which satisfy G2.

-

por(P1, P2) returns a parser for the language described by the grammar G1 or G2.

- -

The original problem was to parse the grammar . The following code addresses this problem:

- -

The following code adds a parser interface to the grammar:

- -

We can test this parser as follows:

-
-
-32> funparse:parse([a,c]).
-{ok,{'and',{'or',1,{const,a}},{'or',1,{const,c}}}}
-33> funparse:parse([a,d]). 
-{ok,{'and',{'or',1,{const,a}},{'or',2,{const,d}}}}
-34> funparse:parse([b,c]).   
-{ok,{'and',{'or',2,{const,b}},{'or',1,{const,c}}}}
-35> funparse:parse([b,d]). 
-{ok,{'and',{'or',2,{const,b}},{'or',2,{const,d}}}}
-36> funparse:parse([a,b]).   
-fail      
-
-
-
- diff --git a/system/doc/extensions/funs1.erl b/system/doc/extensions/funs1.erl deleted file mode 100644 index b1a3e21525..0000000000 --- a/system/doc/extensions/funs1.erl +++ /dev/null @@ -1,125 +0,0 @@ --module(funs1). --compile(export_all). --import(lists, [reverse/1]). - -%1 -map(F, [H|T]) -> [F(H)|map(F, T)]; -map(F, []) -> []. -%1 - -%2 -foreach(F, [H|T]) -> - F(H), - foreach(F, T); -foreach(F, []) -> - ok. -%2 -% -%3 -all(Pred, [H|T]) -> - case Pred(H) of - true -> all(Pred, T); - false -> false - end; -all(Pred, []) -> - true. -%3 -%4 -any(Pred, [H|T]) -> - case Pred(H) of - true -> true; - false -> any(Pred, T) - end; -any(Pred, []) -> - false. -%4 -%5 -takewhile(Pred, [H|T]) -> - case Pred(H) of - true -> [H|takewhile(Pred, T)]; - false -> [] - end; -takewhile(Pred, []) -> - []. -%5 -%6 -dropwhile(Pred, [H|T]) -> - case Pred(H) of - true -> dropwhile(Pred, T); - false -> [H|T] - end; -dropwhile(Pred, []) -> - []. -%6 -%7 -splitlist(Pred, L) -> - splitlist(Pred, L, []). - -splitlist(Pred, [H|T], L) -> - case Pred(H) of - true -> splitlist(Pred, T, [H|L]); - false -> {reverse(L), [H|T]} - end; -splitlist(Pred, [], L) -> - {reverse(L), []}. -%7 - -flatmap(F, [Hd|Tail]) -> - F(Hd) ++ flatmap(F, Tail); -flatmap(F, []) -> []. - -%8 -foldl(F, Accu, [Hd|Tail]) -> - foldl(F, F(Hd, Accu), Tail); -foldl(F, Accu, []) -> Accu. -%8 -% -foldr(F, Accu, [Hd|Tail]) -> - F(Hd, foldr(F, Accu, Tail)); -foldr(F, Accu, []) -> Accu. -%9 -filter(F, [H|T]) -> - case F(H) of - true -> [H|filter(F, T)]; - false -> filter(F, T) - end; -filter(F, []) -> []. -%9 -%10 -mapfoldl(F, Accu0, [Hd|Tail]) -> - {R,Accu1} = F(Hd, Accu0), - {Rs,Accu2} = mapfoldl(F, Accu1, Tail), - {[R|Rs], Accu2}; -mapfoldl(F, Accu, []) -> {[], Accu}. -%10 -mapfoldr(F, Accu0, [Hd|Tail]) -> - {Rs,Accu1} = mapfoldr(F, Accu0, Tail), - {R,Accu2} = F(Hd, Accu1), - {[R|Rs],Accu2}; -mapfoldr(F, Accu, []) -> {[], Accu}. -%11 -first(Pred, [H|T]) -> - case Pred(H) of - true -> - {true, H}; - false -> - first(Pred, T) - end; -first(Pred, []) -> - false. -%11 -% -compose(F, G) -> - fun(X) -> - F(G(X)) - end. - -%20 -iterate(N, F) -> - iterate(N, N+1, F). - -iterate(Stop, Stop, _) -> - []; -iterate(N, Stop, Fun) -> - [Fun(N)|iterate(N+1, Stop, Fun)]. -%20 diff --git a/system/doc/extensions/include.xml b/system/doc/extensions/include.xml deleted file mode 100644 index cd78644b95..0000000000 --- a/system/doc/extensions/include.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - -
- - 19992009 - Ericsson AB. All Rights Reserved. - - - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - - - Includes - Arndt Jonasson - 1 - 99-01-25 - PA1 - include.sgml -
-

There are two directives which can be used in Erlang source - files to cause the compiler to temporarily read input from another - source. They are typically used to provide macro definitions and - record definitions from header files. It is recommended to use the - file name extension ".hrl" for files which are meant to be - included (the 'h' can be read as "header").

-

When locating header files a list of directory names, the - compiler include path, is used. In short the list contains the current - working directory of the file server, the base name of the compiled - file, and the directories given by the include option, in that order. - See erlc(1) and compile(3) for the details of the - compiler include path.

- -
- The -include Directive -

The first action taken by the -include directive is to - check if the format of the first path component of the specified - filename is $VAR, for some string VAR. If that is the - case, the value of the environment variable VAR as returned by - os:getenv(VAR) is substituted for the first path component. If - os:getenv/1 returns false, the first path component is - left as is. If the filename is absolute (possibly after variable - substitution), the header file with that name is included. Otherwise, - the specified header file is searched for in the directories in the - compiler include path, starting with the first directory in the list. - The first file found while traversing the list is included. Examples:

- - -include("my_records.hrl"). - -include("incdir/more_records.hrl"). - -include("/home/users/proj/recs.hrl"). - -include("$PROJ_ROOT/app1/defs.hrl"). -
- -
- The -include_lib Directive -

The -include_lib directive first tries to find the - specified header file using the procedure employed for the - -include directive. If no header file can be found by searching - the compiler include path, the first path component of the specified - filename (possibly after variable substitution) is regarded as the - name of an application, and the directory of the current version of - the application is searched. Example:

- - -include_lib("mnesia/include/mnemosyne.hrl"). -

The compiler is instructed to look for the directory where the - current version of the mnesia application is installed, that is - code:lib_dir(mnesia), and then search the subdirectory - include for the file mnemosyne.hrl.

-
-
- diff --git a/system/doc/extensions/list_comprehensions.erl b/system/doc/extensions/list_comprehensions.erl deleted file mode 100644 index 21ac562aa5..0000000000 --- a/system/doc/extensions/list_comprehensions.erl +++ /dev/null @@ -1,118 +0,0 @@ --module(t). --author('tobbe@erix.ericsson.se'). - -%%-export([test/2]). --compile(export_all). - -%% Odd numbers. - -%%foo(L) -> [ X || X <- L, (X > X-1) == (X /= X-1) ]. - -bar(L) -> [ X || X <- L, integer(X), gt(X, 3) ]. - -bar(L, M) -> [ Y || X <- L, integer(X), gt(X, 3), - Y <- M, float(Y), gt(X, Y) - ]. - -baz(L) -> [ X || X <- L, atom(X) ]. - -buz(L, Min) -> [ X || Min > 3, X <- L, X >= Min ]. - -gt(X, Y) when X > Y -> true; -gt(X, Y) -> false. - -%% Turn a list into a set. -make_set([]) -> []; -make_set([H|T]) -> - [H|[ - Y || Y <- make_set(T), - Y =/= H - ]]. - -%% Return the Pythagorean triangles with sides -%% of total length less than N -pyth(N) -> - [ {A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N), - C <- lists:seq(1,N), - A+B+C =< N, - A*A+B*B == C*C - ]. - -%% Cut the search space a bit.. -pyth2(N) -> - [ {A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N-A+1), - C <- lists:seq(1,N-A-B+2), - A+B+C =< N, - A*A+B*B == C*C ]. - -%% Return the Cartesian product -cp() -> - [ {X,Y} || - X <- a(), - Y <- b() - ]. - -cp(A,B) when list(A),list(B) -> - [ {X,Y} || - X <- A, - Y <- B - ]. - -%a() -> 1/0. -a() -> [a,b]. -b() -> [1,2,3]. - -%% Return all permutations of a list -perms([]) -> [[]]; -perms(L) -> [ [H|T] || H <- L, T <- perms(L--[H]) ]. - -%% Quick sort -sort([X|Xs]) -> - sort([ Y || Y <- Xs, Y < X ]) ++ - [X] ++ - sort([ Y || Y <- Xs, Y >= X ]); -sort([]) -> []. - -%% Vector addition -vecAdd(Xs,Ys) -> - [ X+Y || {X,Y} <- zip(Xs,Ys) ]. - -zip([X|Xs],[Y|Ys]) -> [{X,Y}|zip(Xs,Ys)]; -zip([],[]) -> []. - -qsort([X|Xs]) -> - qsort(lt(X,Xs)) - ++ [X] ++ - qsort(ge(X,Xs)); -qsort([]) -> []. - -lt(X,[H|T]) when X>H -> [H|lt(X,T)]; -lt(X,[_|T]) -> lt(X,T); -lt(_,[]) -> []. - -ge(X,[H|T]) when X= [H|ge(X,T)]; -ge(X,[_|T]) -> ge(X,T); -ge(_,[]) -> []. - -test(1,N) -> statistics(runtime),test1(N),statistics(runtime); -test(2,N) -> statistics(runtime),test2(N),statistics(runtime); -test(3,N) -> statistics(runtime),test3(N),statistics(runtime). - -test1(0) -> true; -test1(N) -> - sort([21,12,45,1,3,87,55,77,11,20,6,99,91,13,14,15,66,62,69,71,67,82,83,84,87,86,85]), - test1(N-1). - -test2(0) -> true; -test2(N) -> - qsort([21,12,45,1,3,87,55,77,11,20,6,99,91,13,14,15,66,62,69,71,67,82,83,84,87,86,85]), - test2(N-1). - -test3(0) -> true; -test3(N) -> - lists:sort([21,12,45,1,3,87,55,77,11,20,6,99,91,13,14,15,66,62,69,71,67,82,83,84,87,86,85]), - test3(N-1). diff --git a/system/doc/extensions/list_comprehensions.xml b/system/doc/extensions/list_comprehensions.xml deleted file mode 100644 index 30e32da79c..0000000000 --- a/system/doc/extensions/list_comprehensions.xml +++ /dev/null @@ -1,205 +0,0 @@ - - - - -
- - 19972009 - Ericsson AB. All Rights Reserved. - - - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - - - List Comprehensions - Joe Armstrong - Bjarne Däcker - 1 - Bjarne DäKer - - 96-09-10 - PA1 - list_comprehensions.sgml -
-

List comprehensions are a feature of many modern functional programming languages. Subject to certain rules, they provide a succinct notation for generating elements in a list.

-

List comprehensions are analogous to set comprehensions - in Zermelo-Frankel set theory and are called ZF expressions in - Miranda. They are analogous to the setof and - findall predicates in Prolog.

-

List comprehensions are written with the following syntax: -

- - -[Expression || Qualifier1, Qualifier2, ...] -

Expression is an arbitrary expression, and each Qualifier is either a generator or a filter.

- - A generator written as . ListExpr must be an expression which evaluates to a list of terms. - A filter is either a predicate or a boolean expression. A predicate is a function which returns true or false. - - -
- Examples of List Comprehensions -

We start with a simple example:

- [X || X <- [1,2,a,3,4,b,5,6], X > 3]. -[a,4,b,5,6] ]]> -

This should be read as follows:

- -

The list of X such that X is taken from the list [1,2,a,...] and X is greater than 3.

-
-

The notation is a generator and the expression X > 3 is a filter.

-

An additional filter can be added in order to restrict the result to integers:

- [X || X <- [1,2,a,3,4,b,5,6], integer(X), X > 3]. -[4,5,6] ]]> -

Generators can be combined. For example, the Cartesian product of two lists can be written as follows:

- [{X, Y} || X <- [1,2,3], Y <- [a,b]]. -[{1,a},{1,b},{2,a},{2,b},{3,a},{3,b}] ]]> - -
- Quick Sort -

The well known quick sort routine can be written as follows:

- - sort([ X || X <- T, X < Pivot]) ++ - [Pivot] ++ - sort([ X || X <- T, X >= Pivot]); -sort([]) -> []. ]]> -

The expression is the list of all elements in T, which are less than Pivot.

-

= Pivot]]]> is the list of all elements in T, which are greater or equal to Pivot.

-

To sort a list, we isolate the first element in the list and split the list into two sub-lists. The first sub-list contains all elements which are smaller than the first element in the list, the second contains all elements which are greater than or equal to the first element in the list. We then sort the sub-lists and combine the results.

-
- -
- Permutations -

The following example generates all permutations of the elements in a list:

- [[]]; -perms(L) -> [[H|T] || H <- L, T <- perms(L--[H])]. ]]> -

We take take H from L in all possible ways. The result is the set of all lists [H|T], where T is the set of all possible permutations of L with H removed.

- - -> perms([b,u,g]). -[[b,u,g],[b,g,u],[u,b,g],[u,g,b],[g,b,u],[g,u,b]] -
- -
- Pythagorean Triplets -

Pythagorean triplets are sets of integers {A,B,C} such that A**2 + B**2 = C**2.

-

The function pyth(N) generates a list of all integers {A,B,C} such that A**2 + B**2 = C**2 and where the sum of the sides is less than N.

- - [ {A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N), - C <- lists:seq(1,N), - A+B+C =< N, - A*A+B*B == C*C - ]. ]]> -
-
-> pyth(3).
-[].
-> pyth(11).
-[].
->pyth(12).
-[{3,4,5},{4,3,5}]
-> pyth(50).
-[{3,4,5},
- {4,3,5},
- {5,12,13},
- {6,8,10},
- {8,6,10},
- {8,15,17},
- {9,12,15},
- {12,5,13},
- {12,9,15},
- {12,16,20},
- {15,8,17},
- {16,12,20}]
-

The following code reduces the search space and is more efficient:

- - [{A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N-A+1), - C <- lists:seq(1,N-A-B+2), - A+B+C =< N, - A*A+B*B == C*C ]. ]]> -
- -
- Simplifications with List Comprehensions -

As an example, list comprehensions can be used to simplify some of the functions in lists.erl:

- [X || L1 <- L, X <- L1]. -map(Fun, L) -> [Fun(X) || X <- L]. -filter(Pred, L) -> [X || X <- L, Pred(X)]. ]]> -
-
- -
- Variable Bindings in List Comprehensions -

The scope rules for variables which occur in list comprehensions are as follows:

- - all variables which occur in a generator pattern are assumed to be "fresh" variables - any variables which are defined before the list comprehension and which are used in filters have the values they had before the list comprehension - no variables may be exported from a list comprehension. - -

As an example of these rules, suppose we want to write the function select, which selects certain elements from a list of tuples. We might write [Y || {X, Y} <- L].]]> with the intention of extracting all tuples from L where the first item is X.

-

Compiling this yields the following diagnostic:

- - -./FileName.erl:Line: Warning: variable 'X' shadowed in generate -

This diagnostic warns us that the variable X in the pattern is not the same variable as the variable X which occurs in the function head.

-

Evaluating select yields the following result:

-
-
-> select(b,[{a,1},{b,2},{c,3},{b,7}]).
-[1,2,3,7]    
-

This result is not what we wanted. To achieve the desired effect we must write select as follows:

- [Y || {X1, Y} <- L, X == X1]. ]]> -

The generator now contains unbound variables and the test has been moved into the filter. This now works as expected:

-
-
-> select(b,[{a,1},{b,2},{c,3},{b,7}]).
-[2,7]    
-

One consequence of the rules for importing variables into a list comprehensions is that certain pattern matching operations have to be moved into the filters and cannot be written directly in the generators. To illustrate this, do not write as follows:

- - Y = ... - [ Expression || PatternInvolving Y <- Expr, ...] - ... ]]> -

Instead, write as follows:

- - Y = ... - [ Expression || PatternInvolving Y1 <- Expr, Y == Y1, ...] - ... - ]]> -
-
- diff --git a/system/doc/extensions/list_comrehensions.erl b/system/doc/extensions/list_comrehensions.erl deleted file mode 100644 index f6a23b5dca..0000000000 --- a/system/doc/extensions/list_comrehensions.erl +++ /dev/null @@ -1,75 +0,0 @@ --module(zf). - --compile(export_all). - - -%% Odd numbers. - -%%foo(L) -> [ X || X <- L, (X > X-1) == (X /= X-1) ]. - -boo() -> [X||X <- [1,2,a,3,4,b,5,6], X > 3]. -boo1() -> [X||X <- [1,2,a,3,4,b,5,6], integer(X),X > 3]. -boo2() -> [{X,Y} || X <- [1,2,3], Y <- [a,b]]. - -bar(L) -> [ X || X <- L, integer(X), gt(X, 3) ]. - -bar(L, M) -> [ Y || X <- L, integer(X), gt(X, 3), - Y <- M, float(Y), gt(X, Y) - ]. - -baz(L) -> [ X || X <- L, atom(X) ]. - -buz(L, Min) -> [ X || Min > 3, X <- L, X >= Min ]. - -gt(X, Y) when X > Y -> true; -gt(X, Y) -> false. - - -%% Return the Pythagorean triangles with sides -%% of total length less than N -pyth(N) -> - [ {A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N), - C <- lists:seq(1,N), - A+B+C =< N, - A*A+B*B == C*C - ]. - -%% Cut the search space a bit.. -pyth2(N) -> - [ {A,B,C} || - A <- lists:seq(1,N), - B <- lists:seq(1,N-A+1), - C <- lists:seq(1,N-A-B+2), - A+B+C =< N, - A*A+B*B == C*C ]. - -%% Return the Cartesian product - -cp(A,B) -> - [ {X,Y} || - X <- A, - Y <- B - ]. - -%% Return all permutations of a list -perms([]) -> [[]]; -perms(L) -> [ [H|T] || H <- L, T <- perms(L--[H]) ]. - -%% Quick sort -sort([X|Xs]) -> - sort([ Y || Y <- Xs, Y < X ]) ++ - [X] ++ - sort([ Y || Y <- Xs, Y >= X ]); -sort([]) -> []. - -%% append - -append(L) -> [X||L1<-L,X<-L1]. - -map(Fun, L) -> [Fun(X)||X<-L]. - -filter(Pred, L) -> [X||X<-L,Pred(X)]. - -select(X, L) -> [Y || {X1,Y} <- L, X == X1]. diff --git a/system/doc/extensions/macros.xml b/system/doc/extensions/macros.xml deleted file mode 100644 index feb3de6102..0000000000 --- a/system/doc/extensions/macros.xml +++ /dev/null @@ -1,177 +0,0 @@ - - - - -
- - 19972009 - Ericsson AB. All Rights Reserved. - - - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - - - Macros - Joe Armstrong - Bjarne Däcker - 1 - Bjarne DäKer - - 96-09-10 - PA1 - macros.sgml -
-

Macros in Erlang are written with the following syntax:

- - --define(Const, Replacement). --define(Fun(Var1, Var2,.., Var), Replacement). -

Macros are expanded when the syntax ?MacroName is encountered.

-

Consider the macro definition:

- - --define(timeout, 200). -

The expression ?timeout, which can occur anywhere in the code which follows the macro definition, will be replaced by 200.

-

Macros with arguments are written as follows:

- - - -define(macro1(X, Y), {a, X, b, Y}). -

This type of macro can be used as follows:

- - -bar(X) -> - ?macro1(a, b), - ?macro1(X, 123) -

This expands to:

- - -bar(X) -> - {a,a,b,b}, - {a,X,b,123}. - -
- Macros and Tokens -

Macro expansion works at a token level. We might define a macro as follows:

- - --define(macro2(X, Y), {a,X,b,Y). -

The replacement value of the macro is not a valid Erlang term because the closing right curly bracket is missing. macro2 expands into a sequence of tokens {, a, X which are then pasted into the place where the macro is used.

-

We might use this macro as follows:

- - -bar() -> - ?macro2(x,y)}. -

This will expand into the valid sequence of tokens {a,x,y,b} before being parsed and compiled.

- -

It is good programming practise to ensure that the replacement text of a macro is a valid Erlang syntactic form.

-
-
- -
- Pre-Defined Macros -

The following macros are pre-defined:

- - ?MODULE. - This macro returns the name of the current module. - - ?MODULE_STRING. - This macro returns the name of the current module, as a string. - ?FILE. - This macro returns the current file name. - ?LINE. - This macro returns the current line number. - ?MACHINE. - This macro returns the current machine name, - 'BEAM', - -
- -
- Stringifying Macro Arguments -

The construction ??Arg for an argument to a macro expands to a - string containing the tokens of the argument, similar to the - #arg stringifying construction in C. This was added in Erlang - 5.0 (OTP R7A).

-

Example:

- --define(TESTCALL(Call), io:format("Call ~s: ~w~n", [??Call, Call])). - -?TESTCALL(myfunction(1,2)), -?TESTCALL(you:function(2,1)). -

results in

- -io:format("Call ~s: ~w~n",["myfunction ( 1 , 2 )",m:myfunction(1,2)]), -io:format("Call ~s: ~w~n",["you : function ( 2 , 1 )",you:function(2,1)]). -
- -
- Flow Control in Macros -

The following macro directives are supplied:

- - -undef(Macro). - Causes the macro to behave as if it had never been defined. - -ifdef(Macro). - Do the following lines if Macro is defined. - -ifndef(Macro). - Do the following lines if Macro is not defined. - -else. - "else" macro - -endif. - "endif" macro. - -

The conditional macros must be properly nested. They are usually grouped as follows:

- - --ifdef(debug) --define(....) --else --define(...) --endif -

The following example illustrates this grouping:

- - --define(debug, true). --ifdef(debug). --define(trace(Str, X), io:format("Mod:~w line:~w ~p ~p~n", - [?MODULE,?LINE, Str, X])). --else. --define(trace(X, Y), true). --endif. -

Given these definitions, the expression ?trace("X=", X). in line 10 of the module foo expands to:

- - -io:format("Mod:~w line:~w ~p ~p~n",[foo,100,"X=",[X]]), -

If we remove the -define(debug, true). line, then the same expression expands to true.

-
- -
- A Macro Expansion Utility -

The following code can be used to expand a macro and display the result:

- - --module(mexpand). --export([file/1]). --import(lists, [foreach/2]). -file(File) -> - case epp:parse_file(File ++ ".erl", [],[]) of - {ok, L} -> - {ok, Stream} = file:open(File ++ ".out", write), - foreach(fun(X) -> - io:format(Stream,"~s~n",[erl_pp:form(X)]) - end, L), - file:close(Stream) - end. -

Alternatively, we can compile the file with the 'P' option. compile:file(File, ['P']) produces a list file File.P, in which the result of any macro expansions can be seen.

-
-
- diff --git a/system/doc/extensions/make.dep b/system/doc/extensions/make.dep deleted file mode 100644 index fdac959667..0000000000 --- a/system/doc/extensions/make.dep +++ /dev/null @@ -1,21 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: bit_syntax.tex book.tex funs.tex include.tex \ - list_comprehensions.tex macros.tex misc.tex \ - part.tex records.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -funs.tex: fun_test.erl funparse.erl funs1.erl - diff --git a/system/doc/extensions/mexpand.erl b/system/doc/extensions/mexpand.erl deleted file mode 100644 index 261f99da46..0000000000 --- a/system/doc/extensions/mexpand.erl +++ /dev/null @@ -1,16 +0,0 @@ --module(mexpand). - --export([file/1]). - --import(lists, [foreach/2]). - -file(File) -> - case epp:parse_file(File ++ ".erl", [],[]) of - {ok, L} -> - {ok, Stream} = file:open(File ++ ".out", write), - foreach(fun(X) -> - io:format(Stream,"~s~n", - [erl_pp:form(X)]) - end, L), - file:close(Stream) - end. diff --git a/system/doc/extensions/misc.xml b/system/doc/extensions/misc.xml deleted file mode 100644 index 576f705278..0000000000 --- a/system/doc/extensions/misc.xml +++ /dev/null @@ -1,310 +0,0 @@ - - - - -
- - 19992009 - Ericsson AB. All Rights Reserved. - - - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - - - Miscellaneous - Arndt Jonasson - 1 - 99-01-25 - PA1 - misc.sgml -
-

In this chapter, a number of miscellaneous features of Erlang - are described.

- -
- Token Syntax -

In Erlang 4.8 (OTP R5A) the syntax of Erlang tokens have been - extended to allow the use of the full ISO-8859-1 (Latin-1) character - set. This is noticeable in the following ways:

- - All the Latin-1 printable characters can be used and are shown without - the escape backslash convention. - Atoms and variables can use all Latin-1 letters. - -

The new characters from Latin-1 have the following - classifications in Erlang:

- - - Octal - Decimal -   - Class - - - 200 - 237 - 128 - 159 -   - Control characters - - - 240 - 277 - 160 - 191 - - ¿ - Punctuation characters - - - 300 - 326 - 192 - 214 - À - Ö - Uppercase letters - - - 327 - 215 - × - Punctuation character - - - 330 - 336 - 216 - 222 - Ø - Þ - Uppercase letters - - - 337 - 366 - 223 - 246 - ß - ö - Lowercase letters - - - 367 - 247 - ÷ - Punctuation character - - - 370 - 377 - 248 - 255 - ø - ÿ - Lowercase letters - - Character classes -
-
- -
- String Concatenation -

Two adjacent string literals are concatenated into one. This is done already - at compile-time, and doesn't incur any runtime overhead. Example:

- - "string" "42" -

is equivalent to

- - "string42" -

This feature is convenient in at least two situations:

- - when one of the - strings is the result of a macro expansion; - when a string is very - long, and would otherwise either have to wrap, making the source code - harder to read, or force the use of some runtime append operation. - -
- -
- The ++ list Concatenation Operator -

Since list concatenation is a very common operation, it is convenient - to have a terse way of expressing it. The ++ operator appends its second - argument to its first. Example: -

- - X = [1,2,3], - Y = [4,5], - X ++ Y. -

results in [1,2,3,4,5].

-

The ++ operator has precedence between the binary '+' operator and - the comparison operators. -

-
- -
- The - - list Subtraction Operator -

The - - operator produces a list which is a copy of the first - argument, subjected to the following procedure: for each element in - the second argument, its first occurrence in the first argument is - removed.

- - X = [1,2,3,2,1,2], - Y = [2,1,2], - X -- Y. -

results in [3,1,2].

-

The - - operator has precedence between the binary '+' operator and - the comparison operators. -

-
- -
- Bitwise Operator bnot -

Apart from the binary bitwise operators band, bor - and bxor, there is a unary operator bnot with the same - precedence as the other unary operators + and -, i.e., higher than - the binary operators. Example:

- - bnot 7. -

returns -8. -

-
- -
- Logical Operators -

The atoms true and false are usually used for representing - Boolean values. With the binary operators and, or and - xor, and the unary operator not, Boolean values can be - combined. Example:

- - - M1 = lists:member(A, List1), - M2 = lists:member(A, List2), - M1 and M2. -

Note that the operators are strict, i.e., they always evaluate both - their arguments.

-

not has the same priority as the other unary operators. The - binary logical operators have precedence between the = operator - and the comparison operators, the and operator having higher - precedence than or and xor. -

-
- -
- Match Operator = In Patterns -

This extension was added in Erlang 4.8 (OTP R5A).

-

The = operator is also called the `match' operator. The match operator - can now be used in a pattern, so that P1 = P2 is a valid pattern, - where both P1 and P2 are patterns. This compound pattern - when matched against a term causes the term to be matched against both - P1 and P2.

-

One use for this construction is to avoid reconstructing a term which - was part of an argument to a function. Example:

- - f({'+',X,Y}=T) -> {X+Y,T}. -

It also makes it possible to rewrite the construction

- - f(X) when X == #rec{x=1, y=a} -> ... -

as

- - f(#rec{x=1, y=a} = X) -> ... -

In the absence of optimization for the former case, the - latter case is more efficient. -

-
- -
- Literal String Prefix in Patterns -

This extension was added in Erlang 4.8 (OTP R5A).

-

A new construction is allowed in patterns, namely a literal - string as the first operand of the ++ operator. Example:

- - f("prefix" ++ L) -> ... -

This is syntactic sugar for the equivalent, but harder to read

- - f([$p,$r,$e,$f,$i,$x | L]) -> ... -
- -
- Disjunctions in Guards -

This extension was added in Erlang 4.9 (OTP R6A).

-

A new construction is allowed in guards, the disjunction operator - ';'. The construction is syntactic sugar which removes the bother of - writing the same body after several guards.

- - f(X) when xxx ; yyy ; zzz -> - pop(X). -

This is syntactic sugar for the equivalent

- - f(X) when xxx -> - pop(X); - f(X) when yyy -> - pop(X); - f(X) when zzz -> - pop(X). -

The abstract format has been changed accordingly to contain a list of - (conjunctive) guards where there was previously only one guard. -

-
- -
- Expressions in Patterns -

This extension was added in Erlang 5.0 (OTP R7A).

-

An arithmetic expression can be used within a pattern, if it uses - only numeric or bitwise operators, and if its value can be evaluated - to a constant at compile-time. This is especially useful when the - expression is defined by a macro. -

-

Example:

- - case X of - {1+2, T} -> T - end. -
- -
- Boolean expresions in guards -

This extension was added in Erlang 5.1 (OTP R8).

-

In guards, the use of and, or and not is - now allowed. Guard expressions can combine these with - parenthesis. This allows for more elaborate guards than what - may be given with , and ;.

- -

The guard expressions written with these operators are boolean - expressions, and the boolean functions is_list, - is_integer etc. should be used, rather than - list, integer etc.

-
-

Example 1:

- - f(X) when not (is_tuple(X) or is_list(X)) -> - ... -

Example 2:

- 0) and (B > 0) and not (A*A < B*B) -> - ... ]]> -
- -
- Short-circuit boolean expressions -

This extension was added in Erlang 5.1 (OTP R8).

-

In a boolean expression it is unnecessary to always evaluate all - terms. If the first term gives a result that determines the - result, the second term is not needed. In Erlang two new - keywords handles boolean expressions without evaluating both - terms, if it's unnecessary. (This is called short-curcuit - boolean evaluation.)

-

The keyword andalso is a short-curcuit version of - and. The keyword orelse is a short-curcuit version - of or. They can be used in boolean expressions (not - guards) instead of and and or.

-

Example 1:

- - case A >= -1.0 andalso math:sqrt(A+1) > B of -

This will work even if A is less than -1.0, since - in that case, the second term (after andalso) is never - evaluated. (Of course, the same effects could have been done - using guards. In guards, evaluation is always short-circuited, - since guard tests are known to be free of side-effects.)

-

Example 2:

- - OnlyOne = is_atom(L) orelse - (is_list(L) andalso length(L) == 1), -
-
- diff --git a/system/doc/extensions/part.xml b/system/doc/extensions/part.xml deleted file mode 100644 index 56fd2c09a6..0000000000 --- a/system/doc/extensions/part.xml +++ /dev/null @@ -1,57 +0,0 @@ - - - - -
- - 1997 - 2007 - Ericsson AB, All Rights Reserved - - - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - - - Erlang Extensions Since 4.4 - OTP Team - - 1997-02-21 - E - part.sgml -
- -

This chapter describes extensions made to the Erlang language - since version 4.4 (where nothing is said to the contrary, an extension - was added in version 4.4). - The chapter contains the following sections: -

- - Records - Functional Objects (Funs) - List Comprehensions - Macros - File inclusion - Bit syntax - Miscellaneous - -
- - - - - - - -
- diff --git a/system/doc/extensions/records.xml b/system/doc/extensions/records.xml deleted file mode 100644 index 21ec73ab77..0000000000 --- a/system/doc/extensions/records.xml +++ /dev/null @@ -1,284 +0,0 @@ - - - - -
- - 1997 - 2007 - Ericsson AB, All Rights Reserved - - - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - The Initial Developer of the Original Code is Ericsson AB. - - - Records - Joe Armstrong - Bjarne Däcker - 1 - Bjarne DäKer - - 96-09-10 - PA1 - records.sgml -
-

A record is a data structure intended for storing a fixed number of related data items. It is - similar to a struct in C, or a record in Pascal.

-

The main advantage of using records instead of tuples is that fields in a record are accessed by name, whereas fields in a tuple are accessed by position. To illustrate these differences, suppose that we want to represent a person with the tuple{Name, Address, Phone}.

-

We must remember that the Name field is the first element of the tuple, the Address field is the second element, and so on, in order to write functions which manipulate this data. For example, to extract data from a variable P which contains such a tuple we might write the following code and then use pattern matching to extract the relevant fields.

- - -Name = element(1, P), -Address = element(2, P), -... -

Code like this is difficult to read and understand and errors occur if we get the numbering of the elements in the tuple wrong. If we change the data representation by re-ordering the fields, or by adding or removing a field, then all references to the person tuple, wherever they occur, must be checked and possibly modified.

-

Records allow us to refer to the fields by name and not position. We use a record instead of a tuple to store the data . If we write a record definition of the type shown below, we can then refer to the fields of the record by name.

- - --record(person, {name, phone, address}). -

For example, if P is now a variable whose value is a person record, we can code as follows in order to access the name and address fields of the records.

- - -Name = P#person.name, -Address = P#person.address, -... -

In the following sections we describe the different operations which can be performed on records:

- -
- Defining a Record -

A record is defined with the following syntax:

- - --record(RecordName, {Field1 [= DefaultValue1], - Field2 [= DefaultValue2], - ..., - FieldN [= DefaultValueN]}). -

The record name and field names must be atoms. The optional default values, which are terms, are used if no value is supplied for a field when a new instance of the record is created. If the default value is not supplied, then the atom undefined is assumed.

-

For example, in the following record definition, the address field is undefined.

-
--record(person, {name = "", phone = [], address}).    
-

This definition of a person will be used in many of the examples which follow.

-
- -
- Including a Record Definition -

If the record is used in several modules, its definition should be placed in a .hrl header file. Each module which uses the record definition should have a -include(FileName). statement. For example:

- - --include("my_data_structures.hrl"). - -

The definition of the record must come before it is used.

-
-
- -
- Creating a Record -

A new record is created with the following syntax:

- - -#RecordName{Field1=Expr1, - ..., - FieldM=ExprM}. -

If any of the fields is omitted, then the default value supplied in the record definition is used. For example:

-
-> #person{phone = [0,8,2,3,4,3,1,2], name = "Robert"}.
-{person, "Robert", [0,8,2,3,4,3,1,2], undefined}.          
-

There is a new feature introduced in Erlang 5.1 (OTP release - R8), with which you can set a value to all fields in a record, - overriding the defaults in the record specification. The special - field _, means "all fields not explicitly specified".

-
-> #person{name = "Jakob", _ = '_'}
-{person, "Jakob", '_', '_'}    
-

It is primarily intended to be used in ets:match/2 and - mnesia:match_object/3, to set record fields to the atom - '_'. (This is a wildcard in ets:match/2.)

-
- -
- Selectors -

The following syntax is used to select an individual field from a record:

- - -Variable#RecordName.Field - -

The values contained in record names and fields must be constants, not variables.

-
- -

For the purposes of illustration, we will demonstrate the use of records using an imaginary dialogue with the Erlang shell. Currently the Erlang evaluator does not support records so you may not be able to reproduce this dialogue.

-
-
-
-> P = #person{name = "Joe", phone = [0,8,2,3,4,3,1,2]}.
-{person, "Joe", [0,8,2,3,4,3,1,2], undefined}
-> P#person.name.
-"Joe"    
- -

Selectors for records are allowed in guards.

-
-
- -
- Updating a Record -

The following syntax is used to create a new copy of the record with some of the fields changed. Only the fields to be changed need to be referred to, all other fields retain their old values.

- - -OldVariable#RecordName{Field1 = NewValue1, - ..., - FieldM = NewValueM} -

For example:

-
-> P1 = #person{name="Joe", phone=[1,2,3], address="A street"}.
-{person, "Joe", [1,2,3], "A street"}
-> P2 = P1#person{name="Robert"}.
-{person, "Robert", [1,2,3], "A street"}    
-
- -
- Type Testing -

The following guard test is used to test the type of a record:

- - -record(Variable, RecordName) -

The following example shows that the guard succeeds if P is record of type person.

-
-foo(P) when record(P, person) -> a_person;
-foo(_) -> not_a_person.    
- -

This test checks that P is a tuple of arity N + 1, where N is the number - of fields in the record, and the first element in the tuple is the atom person.

-
-
- -
- Pattern Matching -

Matching can be used in combination with records as shown in the following example:

-
-> P = #person{name="Joe", phone=[0,0,7], address="A street"}.
-{person, "Joe", [0,0,7], "A street"}
-> #person{name = Name} = P, Name.
-"Joe"    
-

The following function takes a list of person records and searches for the phone number of a person with a particular name:

- - -find_phone([#person{name=Name, phone=Phone} | _], Name) -> - {found, Phone}; -find_phone([_| T], Name) -> - find_phone(T, Name); -find_phone([], Name) -> - not_found. - -

The fields referred to in the pattern can be given in any order.

-
-
- -
- Nested Records -

The value of a field in a record might be an instance of a record. Retrieval of nested data can be done stepwise, or in a single step, as shown in the following example:

-
--record(name, {first = "Robert", last = "Ericsson"}).
--record(person, {name = #name{}, phone}).
-
-demo() ->
-  P = #person{name= #name{first="Robert",last="Virding"}, phone=123},
-  First = (P#person.name)#name.first.    
- -

In this example, demo() evaluates to "Robert".

-
-
- -
- Internal Representation of Records -

It is often desirable to write generic functions which will work on any record, not just a record of a particular type. For this reason, records are represented internally as tuples and the ordering of the fields in the tuple is strictly defined.

-

For example, the record -record(person, {name, phone, address}). is represented internally by the tuple {person, X, Y, Z}.

-

The arity of the tuple is one more than the number of fields in the tuple. The first element of the tuple is the name of the record, and the elements of the tuple are the fields in the record. The variables X, Y and Z will store the data contained in the record fields.

-

The following two functions determine the indices in the tuple which refer to the named fields in the record:

- - record_info(fields, Rec) -> [Names]. This function returns the names of the fields in the record Rec. For example, record_info(fields, person) evaluates to [name, address, phone]. - record_info(size, Rec) -> Size. This function returns the size of the record Rec when represented as a tuple, which is one more than the number of fields. For example, record_info(size, person) returns 4. - -

In addition, #Rec.Name returns the index in the tuple representation of Name of the record Rec.

- -

Name must be an atom.

-
-

For example, the following test function test() might return the result shown:

-
-test() ->
-    {record_info(fields, person),
-     record_info(size, person),
-     #person.name}.    
-
-> Mod:test().
-{[name,address,phone],4,2}    
-

The order in which records map onto tuples is implementation dependent.

- -

record_info is a pseudo-function which cannot be exported from the module where it occurs.

-
-
- -
- Example -
-%% File: person.hrl
-
-%%-----------------------------------------------------------
-%% Data Type: person
-%% where:
-%%    name:  A string (default is undefined).
-%%    age:   An integer (default is undefined).
-%%    phone: A list of integers (default is []).
-%%    dict:  A dictionary containing various information 
-%%           about the person. 
-%%           A {Key, Value} list (default is the empty list).
-%%------------------------------------------------------------
--record(person, {name, age, phone = [], dict = []}).
-    
-
--module(person).
--include("person.hrl").
--compile(export_all). % For test purposes only.
-
-%% This creates an instance of a person.
-%%   Note: The phone number is not supplied so the
-%%         default value [] will be used.
-
-make_hacker_without_phone(Name, Age) ->
-   #person{name = Name, age = Age, 
-           dict = [{computer_knowledge, excellent}, 
-                   {drinks, coke}]}.
-
-%% This demonstrates matching in arguments
-
-print(#person{name = Name, age = Age,
-              phone = Phone, dict = Dict}) ->
-  io:format("Name: ~s, Age: ~w, Phone: ~w ~n" 
-            "Dictionary: ~w.~n", [Name, Age, Phone, Dict]).
-
-%% Demonstrates type testing, selector, updating.
-
-birthday(P) when record(P, person) -> 
-   P#person{age = P#person.age + 1}.
-
-register_two_hackers() ->
-   Hacker1 = make_hacker_without_phone("Joe", 29),
-   OldHacker = birthday(Hacker1),
-   % The central_register_server should have 
-   % an interface function for this.
-   central_register_server ! {register_person, Hacker1},
-   central_register_server ! {register_person, 
-             OldHacker#person{name = "Robert", 
-                              phone = [0,8,3,2,4,5,3,1]}}.    
-
-
- diff --git a/system/doc/extensions/warning.gif b/system/doc/extensions/warning.gif deleted file mode 100644 index 96af52360e..0000000000 Binary files a/system/doc/extensions/warning.gif and /dev/null differ diff --git a/system/doc/images/.gitignore b/system/doc/images/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/system/doc/pics/Makefile b/system/doc/pics/Makefile deleted file mode 100644 index fc5996259d..0000000000 --- a/system/doc/pics/Makefile +++ /dev/null @@ -1,58 +0,0 @@ -# -# Copyright (C) 1996,1997 Ericsson Telecommunications -# Author: Lars Thorsen -# -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -# ---------------------------------------------------- -# Release directory specification -# ---------------------------------------------------- -RELSYSDIR = $(RELEASE_PATH)/doc - -# ---------------------------------------------------- -# Target Specs -# ---------------------------------------------------- -# -# Common macros -# - -GIF_FILES= \ - min_head.gif \ - ps.gif - -# ---------------------------------------------------- -# Target Specs -# ---------------------------------------------------- - -docs: - -pdf: - -ps: - -debug opt: - - - -clean: - @echo "No action" >/dev/null - -# -# Release Targets -# -include $(ERL_TOP)/make/otp_release_targets.mk - -ifeq ($(DOCTYPE),pdf) -release_docs_spec: pdf -else -ifeq ($(DOCTYPE),ps) -release_docs_spec: ps -else -release_docs_spec: docs - $(INSTALL_DIR) $(RELSYSDIR)/pics - $(INSTALL_DATA) $(GIF_FILES) $(RELSYSDIR)/pics -endif -endif - -release_spec: diff --git a/system/doc/pics/app.gif b/system/doc/pics/app.gif deleted file mode 100644 index 345d5795b1..0000000000 Binary files a/system/doc/pics/app.gif and /dev/null differ diff --git a/system/doc/pics/ede.gif b/system/doc/pics/ede.gif deleted file mode 100644 index 7a51766898..0000000000 Binary files a/system/doc/pics/ede.gif and /dev/null differ diff --git a/system/doc/pics/ede_logo.gif b/system/doc/pics/ede_logo.gif deleted file mode 100644 index f7c902791b..0000000000 Binary files a/system/doc/pics/ede_logo.gif and /dev/null differ diff --git a/system/doc/pics/min_head.gif b/system/doc/pics/min_head.gif deleted file mode 100644 index 67948a6378..0000000000 Binary files a/system/doc/pics/min_head.gif and /dev/null differ diff --git a/system/doc/pics/notes.gif b/system/doc/pics/notes.gif deleted file mode 100644 index e000cca26a..0000000000 Binary files a/system/doc/pics/notes.gif and /dev/null differ diff --git a/system/doc/pics/otp.gif b/system/doc/pics/otp.gif deleted file mode 100644 index 48c4ca9c02..0000000000 Binary files a/system/doc/pics/otp.gif and /dev/null differ diff --git a/system/doc/pics/otp_logo.gif b/system/doc/pics/otp_logo.gif deleted file mode 100644 index d1a1f7f72d..0000000000 Binary files a/system/doc/pics/otp_logo.gif and /dev/null differ diff --git a/system/doc/pics/ps.gif b/system/doc/pics/ps.gif deleted file mode 100644 index 186dfc7e24..0000000000 Binary files a/system/doc/pics/ps.gif and /dev/null differ diff --git a/system/doc/pics/ref_man.gif b/system/doc/pics/ref_man.gif deleted file mode 100644 index b13c4efd53..0000000000 Binary files a/system/doc/pics/ref_man.gif and /dev/null differ diff --git a/system/doc/pics/user_guide.gif b/system/doc/pics/user_guide.gif deleted file mode 100644 index e6275a803d..0000000000 Binary files a/system/doc/pics/user_guide.gif and /dev/null differ diff --git a/system/doc/top/bin/otp_man_index b/system/doc/top/bin/otp_man_index deleted file mode 120000 index bb913b25df..0000000000 --- a/system/doc/top/bin/otp_man_index +++ /dev/null @@ -1 +0,0 @@ -../../../../internal_tools/integration/scripts/otp_man_index \ No newline at end of file diff --git a/system/doc/top/bin/otp_man_index b/system/doc/top/bin/otp_man_index new file mode 100755 index 0000000000..57a0f12d32 --- /dev/null +++ b/system/doc/top/bin/otp_man_index @@ -0,0 +1,106 @@ +#!/opt/local/bin/perl + +use File::Find; +use strict; + +######################################### +# Usage: +# $ cd $ERLANG_RELEASE +# otp_man_index > doc/man_index.html +######################################### + +my (@list,$info); + +find(\&wanted,'.'); + +header(); + +foreach $info (sort {lc($a->[0]) cmp lc($b->[0])} @list) { + my ($module,$application,$dir,$path) = @$info; + + my $idx = -f "$dir/index.html" ? "$dir/index.html" : "$dir/../index.html"; + # Remove .html extension from module name, if there is one + if ($module =~ /(\w+).html$/) { + $module = "$1"; + } + print " \n"; + print " $module\n"; + print " $application\n"; + print " \n"; +} + +footer(); + +########################################################################### + +sub wanted { + return unless /\.html$/ and -f $_; + + open(FILE,$_) or die "ERROR: Can't open $File::Find::name: $!\n"; + my $line; + + while (defined ($line = )) { + if ($line =~ //) { + close FILE; + my $path = $File::Find::name; + $path =~ s/\.\///; # Remove './' prefix + my $dir = $File::Find::dir; + $dir =~ s/\.\///; # Remove './' prefix + $dir =~ m&([^/]+)/doc/html$&; + my $application = $1; + push(@list, [$_,$application,$dir,$path]); + return; + } + } + close FILE; +} + + +sub header { + print < + + + + + Erlang/OTP Manual Page Index + + +
+ + +[Up | +Erlang] +
+

Manual Page Index
+

+
+

+ + + + +EOS +} + +sub footer { + my $year = (localtime)[5] + 1900; + print < + +

+

+
+ +Copyright © 1991-$year + +Ericsson AB + +
+ + +EOS +} diff --git a/system/doc/top/src/erl_html_tools.erl b/system/doc/top/src/erl_html_tools.erl deleted file mode 120000 index 35a199b08d..0000000000 --- a/system/doc/top/src/erl_html_tools.erl +++ /dev/null @@ -1 +0,0 @@ -../../../../internal_tools/integration/scripts/make_index/erl_html_tools.erl \ No newline at end of file diff --git a/system/doc/top/src/erl_html_tools.erl b/system/doc/top/src/erl_html_tools.erl new file mode 100644 index 0000000000..d93516768e --- /dev/null +++ b/system/doc/top/src/erl_html_tools.erl @@ -0,0 +1,727 @@ +%% ``The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved via the world wide web at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. +%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings +%% AB. All Rights Reserved.'' +%% +-module(erl_html_tools). + +%% This file contains tools for updating HTML files in an installed system +%% depending on the installed applications. Currently the only use is +%% to update the top index file. + + +%% ------ VERY IMPORTANT ------ +%% +%% Original location for this file: +%% /clearcase/otp/internal_tools/integration/scripts/make_index/ +%% When updating this file, copy the source to +%% /home/otp/patch/share/program/ +%% and place .beam files (compiled with correct release) in all +%% /home/otp/patch/share/program/ +%% for releases >= R9C +%% +%% ---------------------------- + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% This program generate the top index files for the OTP documentation. +% Part of the HTML code is in templates, like "index.html.src" and +% part is written out from this module. So the program and the templates +% has to match. +% +% The templates are searched from the current directory, a directory +% "templates" relative to the current directory or at RootDir. +% +% RootDir is given as an argument or assumed to be code:root_dir(), +% i.e. the root of the system running this program. +% +% The output is put into DestDir or RootDir if not given. +% +% The functions to call are +% +% top_index() +% top_index([RootDir]) +% top_index([RootDir,DestDir,OtpRel]) +% top_index(RootDir) +% top_index(RootDir, DestDir, OtpRel) +% +% where RootDir can be a string or an atom. +% +% +% USING THIS SCRIPT FROM THE UNIX COMMAND LINE +% -------------------------------------------- +% If the Erlang started is the same as the Erlang to create index.html +% for the use +% +% % erl -noshell -s erl_html_tools top_index +% +% If you want to create an index for another Erlang installation or +% documentation located separate from the object code, then use +% +% % erl -noshell -s erl_html_tools top_index /path/to/erlang/root +% +% +% COLLECTING INFORMATION +% ---------------------- +% This script assumes that all applications have an "info" file +% in their top directory. This file should have some keywords with +% values defined. The keys are 'group' and 'short' (for "short +% description). See the OTP applications for examples. +% +% Some HTML code is generated by this program, others are taken from +% the file "index.html.src" that may be located in the patch directory +% or in the "$ERLANG_ROOT/doc/" directory. +% +% The code for creating the top index page assumes all applications +% have a file "info" with some fields filled in +% +% short: Text Short text describing the application +% group: tag [Heading] Group tag optionally followed by a description. +% Only one app need to describe the group but +% more than one can. +% +% FIXME: Check that there is documentation for the application, not just +% an info file. +% FIXME: Use records, it is now unreadable :-( +% FIXME: Use a separate URL and URLIndexFile +% FIXME: Pass the OTP release name as an argument instead of in +% process dictionary (for elegance). + +-export([top_index/0,top_index/1,top_index/3,top_index_silent/3]). + +% This is the order groups are inserted into the file. Groups +% not in this list is inserted in undefined order. + +group_order() -> + [ + basic, + dat, + oam, + orb, + comm, + tools + ]. + +top_index() -> + top_index(code:root_dir()). + +top_index([RootDir]) when atom(RootDir) -> + top_index(atom_to_list(RootDir)); +top_index([RootDir,DestDir,OtpRel]) + when is_atom(RootDir), is_atom(DestDir), is_atom(OtpRel) -> + top_index(atom_to_list(RootDir), atom_to_list(DestDir), atom_to_list(OtpRel)); +top_index(RootDir) -> + {_,RelName} = init:script_id(), + top_index(RootDir, filename:join(RootDir, "doc"), RelName). + +top_index(RootDir, DestDir, OtpRel) -> + report("****\nRootDir: ~p", [RootDir]), + report("****\nDestDir: ~p", [DestDir]), + report("****\nOtpRel: ~p", [OtpRel]), + + put(otp_release, OtpRel), + + Templates = find_templates(["","templates",DestDir]), + report("****\nTemplates: ~p", [Templates]), + Bases = [{"../lib/", filename:join(RootDir,"lib")}, + {"../", RootDir}], + Groups = find_information(Bases), + report("****\nGroups: ~p", [Groups]), + process_templates(Templates, DestDir, Groups). + +top_index_silent(RootDir, DestDir, OtpRel) -> + put(silent,true), + Result = top_index(RootDir, DestDir, OtpRel), + erase(silent), + Result. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Main loop - process templates +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +process_templates([], _DestDir, _Groups) -> + report("\n", []); +process_templates([Template | Templates], DestDir, Groups) -> + report("****\nIN-FILE: ~s", [Template]), + BaseName = filename:basename(Template, ".src"), + case lists:reverse(filename:rootname(BaseName)) of + "_"++_ -> + %% One template expands to several output files. + process_multi_template(BaseName, Template, DestDir, Groups); + _ -> + %% Standard one-to-one template. + OutFile = filename:join(DestDir, BaseName), + subst_file("", OutFile, Template, Groups) + end, + process_templates(Templates, DestDir, Groups). + + +process_multi_template(BaseName0, Template, DestDir, Info) -> + Ext = filename:extension(BaseName0), + BaseName1 = filename:basename(BaseName0, Ext), + [_|BaseName2] = lists:reverse(BaseName1), + BaseName = lists:reverse(BaseName2), + Groups0 = [{[$_|atom_to_list(G)],G} || G <- group_order()], + Groups = [{"",basic}|Groups0], + process_multi_template_1(Groups, BaseName, Ext, Template, DestDir, Info). + +process_multi_template_1([{Suffix,Group}|Gs], BaseName, Ext, Template, DestDir, Info) -> + OutFile = filename:join(DestDir, BaseName++Suffix++Ext), + subst_file(Group, OutFile, Template, Info), + process_multi_template_1(Gs, BaseName, Ext, Template, DestDir, Info); +process_multi_template_1([], _, _, _, _, _) -> ok. + +subst_file(Group, OutFile, Template, Info) -> + report("\nOUTFILE: ~s", [OutFile]), + case subst_template(Group, Template, Info) of + {ok,Text,_NewInfo} -> + case file:open(OutFile, [write]) of + {ok, Stream} -> + file:write(Stream, Text), + file:close(Stream); + Error -> + error("Can't write to file ~s: ~w", [OutFile,Error]) + end; + Error -> + error("Can't write to file ~s: ~w", [OutFile,Error]) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Find the templates +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +find_templates(SearchPaths) -> + find_templates(SearchPaths, SearchPaths). + +find_templates([SearchPath | SearchPaths], AllSearchPaths) -> + case filelib:wildcard(filename:join(SearchPath, "*.html.src")) of + [] -> + find_templates(SearchPaths, AllSearchPaths); + Result -> + Result + end; +find_templates([], AllSearchPaths) -> + error("No templates found in ~p",[AllSearchPaths]). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% This function read all application names and if present all "info" files. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +find_information(Bases) -> + Paths = find_application_paths(Bases), +% report("****\nPaths: ~p", [Paths]), + Apps = find_application_infos(Paths), +% report("****\nApps: ~p", [Apps]), + form_groups(Apps). + +% The input is a list of tuples of the form +% +% IN: [{BaseURL,SearchDir}, ...] +% +% and the output is a list +% +% OUT: [{Appname,AppVersion,AppPath,IndexUTL}, ...] +% +% We know URL ends in a slash. + +find_application_paths([]) -> + []; +find_application_paths([{URL,Dir} | Paths]) -> + Sub1 = "doc/html/index.html", +%% Sub2 = "doc/index.html", + case file:list_dir(Dir) of + {ok, Dirs} -> + AppDirs = + lists:filter( + fun(E) -> + is_match(E, "^[A-Za-z0-9_]+-[0-9\\.]+") + end, Dirs), + AppPaths = + lists:map( + fun(AppDir) -> + {ok,[App,Ver]} = regexp:split(AppDir, "-"), + DirPath = filename:join(Dir,AppDir), + AppURL = URL ++ AppDir, + {App,Ver,DirPath,AppURL ++ "/" ++ Sub1} +%% case file:read_file_info( +%% filename:join(DirPath, Sub1)) of +%% {ok, _} -> +%% {App,Ver,DirPath,AppURL ++ "/" ++ Sub1}; +%% _ -> +%% {App,Ver,DirPath,AppURL ++ "/" ++ Sub2} +%% end + end, AppDirs), + AppPaths ++ find_application_paths(Paths) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Find info for one application. +% Read the "info" file for each application. Look at "group" and "short". +% key words. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% IN: [{Appname,AppVersion,AppPath,IndexUTL}, ...] +% OUT: [{Group,Heading,[{AppName,[{AppVersion,Path,URL,Text} | ...]} +% | ...]}, ...] + +find_application_infos([]) -> + []; +find_application_infos([{App,Ver,AppPath,IndexURL} | Paths]) -> + case read_info(filename:join(AppPath,"info")) of + {error,_Reason} -> + warning("No info for app ~p", [AppPath]), + find_application_infos(Paths); + Db -> + {Group,Heading} = + case lists:keysearch("group", 1, Db) of + {value, {_, G0}} -> + % This value may be in two parts, + % tag and desciption + case string:str(G0," ") of + 0 -> + {list_to_atom(G0),""}; + N -> + {list_to_atom(string:substr(G0,1,N-1)), + string:substr(G0,N+1)} + end; + false -> + error("No group given",[]) + end, + Text = + case lists:keysearch("short", 1, Db) of + {value, {_, G1}} -> + G1; + false -> + "" + end, + [{Group,Heading,{App,{Ver,AppPath,IndexURL,Text}}} + | find_application_infos(Paths)] + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Group into one list element for each group name. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% IN : {Group,Heading,{AppName,{AppVersion,Path,URL,Text}}} +% OUT: {Group,Heading,[{AppName,[{AppVersion,Path,URL,Text} | ...]} | ...]} + +form_groups(Apps) -> + group_apps(lists:sort(Apps)). + +group_apps([{Group,Heading,AppInfo} | Info]) -> + group_apps(Info, Group, Heading, [AppInfo]); +group_apps([]) -> + []. + +% First description +group_apps([{Group,"",AppInfo} | Info], Group, Heading, AppInfos) -> + group_apps(Info, Group, Heading, [AppInfo | AppInfos]); +group_apps([{Group,Heading,AppInfo} | Info], Group, "", AppInfos) -> + group_apps(Info, Group, Heading, [AppInfo | AppInfos]); +% Exact match +group_apps([{Group,Heading,AppInfo} | Info], Group, Heading, AppInfos) -> + group_apps(Info, Group, Heading, [AppInfo | AppInfos]); +% Different descriptions +group_apps([{Group,_OtherHeading,AppInfo} | Info], Group, Heading, AppInfos) -> + warning("Group ~w descriptions differ",[Group]), + group_apps(Info, Group, Heading, [AppInfo | AppInfos]); +group_apps(Info, Group, Heading, AppInfos) -> + [{Group,Heading,combine_apps(AppInfos)} | group_apps(Info)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Group into one list element for each application name. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% IN : {AppName,{AppVersion,Path,URL,Text}} +% OUT: {AppName,[{AppVersion,Path,URL,Text} | ...]} + +combine_apps(Apps) -> + combine_apps(Apps,[],[]). + +combine_apps([{AppName,{Vsn1,Path1,URL1,Text1}}, + {AppName,{Vsn2,Path2,URL2,Text2}} | Apps], AppAcc, Acc) -> + combine_apps([{AppName,{Vsn2,Path2,URL2,Text2}} | Apps], + [{Vsn1,Path1,URL1,Text1} | AppAcc], + Acc); +combine_apps([{AppName,{Vsn1,Path1,URL1,Text1}}, + {NewAppName,{Vsn2,Path2,URL2,Text2}} | Apps], AppAcc, Acc) -> + App = lists:sort(fun vsncmp/2,[{Vsn1,Path1,URL1,Text1}|AppAcc]), + combine_apps([{NewAppName,{Vsn2,Path2,URL2,Text2}} | Apps], + [], + [{AppName,App}|Acc]); +combine_apps([{AppName,{Vsn,Path,URL,Text}}], AppAcc, Acc) -> + App = lists:sort(fun vsncmp/2,[{Vsn,Path,URL,Text}|AppAcc]), + [{AppName,App}|Acc]. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Open a template and fill in the missing parts +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% IN : {Group,Heading,[{AppName,[{AppVersion,Path,URL,Text} | ...]} | ...]} +% OUT: String that is the HTML code + +subst_template(Group, File, Info) -> + case file:open(File, read) of + {ok,Stream} -> + Res = subst_template_1(Group, Stream, Info), + file:close(Stream), + Res; + {error,Reason} -> + {error, Reason} + end. + +subst_template_1(Group, Stream, Info) -> + case file:read(Stream, 100000) of + {ok, Template} -> + Fun = fun(Match, _) -> {subst(Match, Info, Group),Info} end, + gsub(Template, "#[A-Za-z0-9]+#", Fun, Info); + {error, Reason} -> + {error, Reason} + end. + +get_version(Info) -> + case lists:keysearch('runtime', 1, Info) of + {value, {_,_,Apps}} -> + case lists:keysearch("erts", 1, Apps) of + {value, {_,[{Vers,_,_,_} | _]}} -> + Vers; + _ -> + "" + end; + _ -> + "" + end. + +subst("#release#", _Info, _Group) -> + get(otp_release); +subst("#version#", Info, _Group) -> + get_version(Info); +subst("#copyright#", _Info, _Group) -> + "copyright Copyright © 1991-2004"; +subst("#groups#", Info, _Group) -> + [ + "
Manual PageApplication
\n", + subst_groups(Info), + "
\n" + ]; +subst("#applinks#", Info, Group) -> + subst_applinks(Info, Group); +subst(KeyWord, Info, _Group) -> + case search_appname(KeyWord -- "##", Info) of + {ok,URL} -> + URL; + _ -> + warning("Can't substitute keyword ~s~n",[KeyWord]), + "" + end. + +search_appname(App, [{_Group,_,Apps} | Groups]) -> + case lists:keysearch(App, 1, Apps) of + {value, {_,[{_Vers,_Path,URL,_Text} | _]}} -> + {ok,lists:sublist(URL, length(URL) - length("/index.html"))}; + _ -> + search_appname(App, Groups) + end; +search_appname(_App, []) -> + {error,noapp}. + +subst_applinks(Info, Group) -> + subst_applinks_1(group_order(), Info, Group). + +subst_applinks_1([G|Gs], Info0, Group) -> + case lists:keysearch(G, 1, Info0) of + {value,{G,Heading,Apps}} -> + Info = lists:keydelete(G, 1, Info0), + ["\n

  • ",Heading,"\n
      \n", + html_applinks(Apps),"\n
  • \n"| + subst_applinks_1(Gs, Info, Group)]; + false -> + warning("No applications in group ~w\n", [G]), + subst_applinks_1(Gs, Info0, Group) + end; +subst_applinks_1([], [], _) -> []; +subst_applinks_1([], Info, _) -> + error("Info left:\n", [Info]), + []. + +html_applinks([{Name,[{_,_,URL,_}|_]}|AppNames]) -> + ["
  • ",Name, + "
  • \n"|html_applinks(AppNames)]; +html_applinks([]) -> []. + + +% Info: [{Group,Heading,[{AppName,[{AppVersion,Path,URL,Text} | ..]} | ..]} ..] + +subst_groups(Info0) -> + {Html1,Info1} = subst_known_groups(group_order(), Info0, ""), + {Html2,Info} = subst_unknown_groups(Info1, Html1, []), + Fun = fun({_Group,_GText,Applist}, Acc) -> Applist ++ Acc end, + case lists:foldl(Fun, [], Info) of + [] -> + Html2; + Apps -> + [Html2,group_table("Misc Applications",Apps)] + end. + + +subst_known_groups([], Info, Text) -> + {Text,Info}; +subst_known_groups([Group | Groups], Info0, Text0) -> + case lists:keysearch(Group, 1, Info0) of + {value,{_,Heading,Apps}} -> + Text = group_table(Heading,Apps), + Info = lists:keydelete(Group, 1, Info0), + subst_known_groups(Groups, Info, Text0 ++ Text); + false -> + warning("No applications in group ~w~n",[Group]), + subst_known_groups(Groups, Info0, Text0) + end. + + +subst_unknown_groups([], Text0, Left) -> + {Text0,Left}; +subst_unknown_groups([{Group,"",Apps} | Groups], Text0, Left) -> + warning("No text describes ~w",[Group]), + subst_unknown_groups(Groups, Text0, [{Group,"",Apps} | Left]); +subst_unknown_groups([{_Group,Heading,Apps} | Groups], Text0, Left) -> + Text = group_table(Heading,Apps), + subst_unknown_groups(Groups, Text0 ++ Text, Left). + + +group_table(Heading,Apps) -> + [ + " \n", + " \n", + " ",Heading,"\n", + " \n", + " \n", + subst_apps(Apps), + " \n", + "  \n", + " \n" + ]. + +% Count and split the applications in half to get the right sort +% order in the table. + +subst_apps([{App,VersionInfo} | Apps]) -> + [subst_app(App, VersionInfo) | subst_apps(Apps)]; +subst_apps([]) -> + []. + + +subst_app(App, [{VSN,_Path,Link,Text}]) -> + [ + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    \n", + " ",uc(App),"\n", + " ",VSN,"\n", + "
    \n" + " \n", + " \n", + Text,"\n", + " \n", + " \n" + ]; +subst_app(App, [{VSN,_Path,Link,Text} | VerInfos]) -> + [ + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
    \n", + " ",uc(App), + "  
    \n", + " ",VSN,"\n", + "
    \n", + " \n", + " \n", + " \n", + " \n", + "
    \n", + subst_vsn(VerInfos), + "
    \n" + "
    \n" + " \n", + " \n", + Text,"\n", + " \n", + " \n" + ]. + + +subst_vsn([{VSN,_Path,Link,_Text} | VSNs]) -> + [ + " ", + VSN, + "
    \n", + subst_vsn(VSNs) + ]; +subst_vsn([]) -> + "". + + +% Yes, this is very inefficient an is done for every comarision +% in the sort but it doesn't matter in this case. + +vsncmp({Vsn1,_,_,_}, {Vsn2,_,_,_}) -> + L1 = [list_to_integer(N1) || N1 <- string:tokens(Vsn1, ".")], + L2 = [list_to_integer(N2) || N2 <- string:tokens(Vsn2, ".")], + L1 > L2. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% GENERIC FUNCTIONS, NOT SPECIFIC FOR GENERATING INDEX.HTML +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Read the "info" file into a list of Key/Value pairs +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +read_info(File) -> + case file:open(File, read) of + {ok,Stream} -> + Res = + case file:read(Stream,10000) of + {ok, Text} -> + Lines = string:tokens(Text, "\n\r"), + KeyValues0 = lines_to_key_value(Lines), + combine_key_value(KeyValues0); + {error, Reason} -> + {error, Reason} + end, + file:close(Stream), + Res; + {error,Reason} -> + {error,Reason} + end. + +combine_key_value([{Key,Value1},{Key,Value2} | KeyValues]) -> + combine_key_value([{Key,Value1 ++ "\n" ++ Value2} | KeyValues]); +combine_key_value([KeyValue | KeyValues]) -> + [KeyValue | combine_key_value(KeyValues)]; +combine_key_value([]) -> + []. + +lines_to_key_value([]) -> + []; +lines_to_key_value([Line | Lines]) -> + case regexp:first_match(Line, "^[a-zA-Z_\\-]+:") of + nomatch -> + case regexp:first_match(Line, "[\041-\377]") of + nomatch -> + lines_to_key_value(Lines); + _ -> + warning("skipping line \"~s\"",[Line]), + lines_to_key_value(Lines) + end; + {match, _, Length} -> + Value0 = lists:sublist(Line, Length+1, length(Line) - Length), + {ok, Value1, _} = regexp:sub(Value0, "^[ \t]*", ""), + {ok, Value, _} = regexp:sub(Value1, "[ \t]*$", ""), + Key = lists:sublist(Line, Length-1), + [{Key,Value} | lines_to_key_value(Lines)] + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Extensions to the 'regexp' module. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +is_match(Ex, Re) -> + case regexp:first_match(Ex, Re) of + {match, _, _} -> + true; + nomatch -> + false + end. + +%% -type gsub(String, RegExp, Fun, Acc) -> subres(). +%% Substitute every match of the regular expression RegExp with the +%% string returned from the function Fun(Match, Acc). Accept pre-parsed +%% regular expressions. Acc is an argument to the Fun. The Fun should return +%% a tuple {Replacement, NewAcc}. + +gsub(String, RegExp, Fun, Acc) when list(RegExp) -> + case regexp:parse(RegExp) of + {ok,RE} -> gsub(String, RE, Fun, Acc); + {error,E} -> {error,E} + end; +gsub(String, RE, Fun, Acc) -> + {match,Ss} = regexp:matches(String, RE), + {NewString, NewAcc} = sub_repl(Ss, Fun, Acc, String, 1), + {ok,NewString,NewAcc}. + + +% New code that uses fun for finding the replacement. Also uses accumulator +% to pass argument between the calls to the fun. +sub_repl([{St,L}|Ss], Fun, Acc0, S, Pos) -> + Match = string:substr(S, St, L), + {Rep, Acc} = Fun(Match, Acc0), + {Rs, NewAcc} = sub_repl(Ss, Fun, Acc, S, St+L), + {string:substr(S, Pos, St-Pos) ++ Rep ++ Rs, NewAcc}; +sub_repl([], _Fun, Acc, S, Pos) -> {string:substr(S, Pos), Acc}. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Error and warnings +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +error(Format, Args) -> + io:format("ERROR: " ++ Format ++ "\n", Args), + exit(1). + +warning(Format, Args) -> + case get(silent) of + true -> ok; + _ -> io:format("WARNING: " ++ Format ++ "\n", Args) + end. + +report(Format, Args) -> + case get(silent) of + true -> ok; + _ -> io:format(Format ++ "\n", Args) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Extensions to the 'string' module. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +uc(String) -> + lists:reverse(uc(String, [])). + +uc([], Acc) -> + Acc; +uc([H | T], Acc) when is_integer(H), [97] =< H, H =< $z -> + uc(T, [H - 32 | Acc]); +uc([H | T], Acc) -> + uc(T, [H | Acc]). diff --git a/system/doc/top/src/erlresolvelinks.erl b/system/doc/top/src/erlresolvelinks.erl deleted file mode 120000 index 8d277ad17a..0000000000 --- a/system/doc/top/src/erlresolvelinks.erl +++ /dev/null @@ -1 +0,0 @@ -../../../../internal_tools/integration/scripts/resolve_links/erlresolvelinks.erl \ No newline at end of file diff --git a/system/doc/top/src/erlresolvelinks.erl b/system/doc/top/src/erlresolvelinks.erl new file mode 100644 index 0000000000..a891b67421 --- /dev/null +++ b/system/doc/top/src/erlresolvelinks.erl @@ -0,0 +1,144 @@ +-module(erlresolvelinks). + +%% ------ VERY IMPORTANT ------ +%% +%% Original location for this file: +%% /clearcase/otp/internal_tools/integration/scripts/resolve_links/ +%% When updating this file, copy the source to +%% /usr/local/otp/patch/share/program/ +%% and place .beam files (compiled with correct release) in all +%% /usr/local/otp/patch/share/program/ +%% for releases >= R10B +%% +%% ---------------------------- + +-export([make/1, do_make/1, do_make/2, do_make/3]). +-include_lib("kernel/include/file.hrl"). + +-define(JAVASCRIPT_NAME, "erlresolvelinks.js"). + +make([RootDir]) -> + do_make(RootDir); +make([RootDir, DestDir]) -> + do_make(RootDir, DestDir); +make([RootDir, DestDir, Name]) -> + do_make(RootDir, DestDir, Name). + +do_make(RootDir) -> + DestDir = filename:join(RootDir, "doc"), + do_make(RootDir, DestDir). + +do_make(RootDir, DestDir) -> + do_make(RootDir, DestDir, ?JAVASCRIPT_NAME). + +do_make(RootDir, DestDir, Name) -> + %% doc/Dir + %% erts-Vsn + %% lib/App-Vsn + DocDirs0 = get_dirs(filename:join([RootDir, "doc"])), + DocDirs = lists:map(fun(Dir) -> + D = filename:join(["doc", Dir]), + {D, D} end, DocDirs0), + + ErtsDirs = latest_app_dirs(RootDir, ""), + AppDirs = latest_app_dirs(RootDir, "lib"), + + AllAppDirs = + lists:map( + fun({App, AppVsn}) -> {App, filename:join([AppVsn, "doc", "html"])} + end, ErtsDirs ++ AppDirs), + + AllDirs = DocDirs ++ AllAppDirs, + {ok, Fd} = file:open(filename:join([DestDir, Name]), [write]), + UTC = calendar:universal_time(), + io:fwrite(Fd, "/* Generated by ~s at ~w UTC */\n", + [atom_to_list(?MODULE), UTC]), + io:fwrite(Fd, "function erlhref(ups, app, rest) {\n", []), + io:fwrite(Fd, " switch(app) {\n", []), + lists:foreach( + fun({Tag, Dir}) -> + io:fwrite(Fd, " case ~p:\n", [Tag]), + io:fwrite(Fd, " location.href=ups + \"~s/\" + rest;\n", + [Dir]), + io:fwrite(Fd, " break;\n", []) + end, AllDirs), + io:fwrite(Fd, " default:\n", []), + io:fwrite(Fd, " location.href=ups + \"Unresolved\";\n", []), + io:fwrite(Fd, " }\n", []), + io:fwrite(Fd, "}\n", []), + file:close(Fd), + ok. + +get_dirs(Dir) -> + {ok, Files} = file:list_dir(Dir), + AFiles = + lists:map(fun(File) -> {File, filename:join([Dir, File])} end, Files), + lists:zf(fun is_dir/1, AFiles). + +is_dir({File, AFile}) -> + {ok, FileInfo} = file:read_file_info(AFile), + case FileInfo#file_info.type of + directory -> + {true, File}; + _ -> + false + end. + +latest_app_dirs(RootDir, Dir) -> + ADir = filename:join(RootDir, Dir), + RDirs0 = get_dirs(ADir), + RDirs1 = lists:filter(fun is_app_dir/1, RDirs0), + %% Build a list of {{App, VsnNumList}, AppVsn} + SDirs0 = + lists:map(fun(AppVsn) -> + [App, VsnStr] = string:tokens(AppVsn, "-"), + VsnNumList = vsnstr_to_numlist(VsnStr), + {{App, VsnNumList}, AppVsn} end, + RDirs1), + SDirs1 = lists:keysort(1, SDirs0), + App2Dirs = lists:foldr(fun({{App, _VsnNumList}, AppVsn}, Acc) -> + case lists:keymember(App, 1, Acc) of + true -> + Acc; + false -> + [{App, AppVsn}| Acc] + end + end, [], SDirs1), + lists:map(fun({App, AppVsn}) -> {App, filename:join([Dir, AppVsn])} end, + App2Dirs). + +is_app_dir(Dir) -> + case string:tokens(Dir, "-") of + [_Name, Rest] -> + is_vsnstr(Rest); + _ -> + false + end. + +is_vsnstr(Str) -> + case string:tokens(Str, ".") of + [_] -> + false; + Toks -> + lists:all(fun is_numstr/1, Toks) + end. + +is_numstr(Cs) -> + lists:all(fun(C) when $0 =< C, C =< $9 -> + true; + (_) -> + false + end, Cs). + +%% We know: + +vsnstr_to_numlist(VsnStr) -> + lists:map(fun(NumStr) -> list_to_integer(NumStr) end, + string:tokens(VsnStr, ".")). + + + + + + + diff --git a/system/doc/top/src/permuted_index.erl b/system/doc/top/src/permuted_index.erl deleted file mode 120000 index e65338a517..0000000000 --- a/system/doc/top/src/permuted_index.erl +++ /dev/null @@ -1 +0,0 @@ -../../../../internal_tools/integration/scripts/make_index/permuted_index.erl \ No newline at end of file diff --git a/system/doc/top/templates/erlang.gif b/system/doc/top/templates/erlang.gif deleted file mode 100644 index 91fd4b9647..0000000000 Binary files a/system/doc/top/templates/erlang.gif and /dev/null differ diff --git a/system/doc/top/templates/first.html.src b/system/doc/top/templates/first.html.src deleted file mode 100644 index edef1c0e5c..0000000000 --- a/system/doc/top/templates/first.html.src +++ /dev/null @@ -1,104 +0,0 @@ - - - - Erlang/OTP #release# Documentation - - - -
    -

    -Welcome to Erlang/OTP, a complete
    -development environment
    -for concurrent programming.
    -

    -
    -
    -
    -
    -

    - -Some hints that may get you started faster - -

    - -
      - -
    • In addition the the documentation here Erlang is described in the book -"Programming Erlang", ISBN 978-1-934356-00-5 which we really recommend as a start.
      -The complete language is also described in the Erlang Reference Manual. An Erlang tutorial can be found in Getting Started With Erlang. -
    • -
    • Erlang/OTP is divided into a number of OTP applications. An application normally contains -Erlang modules. Some OTP applications, -such as the C interface Erl_Interface, are written in other languages and have no Erlang -modules. - -

      -Note that functions that are not imported or prefixed with a module -name belong to the module -erlang -(in the Kernel application). -

      -

      -

    • On a Unix system you can view the manual pages from the command -line using -
      -    % erl -man <module>
      -
      -

      - -

    • You can of course use any editor you like to write Erlang -programs, but if you use Emacs there exists editing support such as -indentation, syntax highlighting, electric commands, module name -verification, comment support including paragraph filling, skeletons, -tags support and more. See the Tools application for details. -

      -There is also an - -Erlang plugin (ErlIde) for Eclipse if you prefer a more graphical -environment. ErlIde is under development and should at the time -of writing this be quite stable and useful. -

    • When developing with Erlang/OTP you usually test your programs -from the interactive shell (see Getting Started With Erlang) where you can call individual -functions. There is also a number of tools available, such as the graphical Debugger, the process -manager Pman and table -viewer TV. -

      Also note that there are some shell features like history list -(control-p and control-n), inline editing (emacs key bindings) and -module and function name completion (tab) if the module is loaded. -

      - -

    • OpenSource users can ask questions -and share experiences on the Erlang questions mailing list.

      - -

    • Before asking a question you can browse the mailing list archive and read the Frequently -Asked Questions.

      - -

    • Additional information and links of interest for Erlang programmers can be found on the Erlang Open Source site -http://www.erlang.org. -

      - -

    - - - diff --git a/system/doc/top/templates/flip_closed.gif b/system/doc/top/templates/flip_closed.gif deleted file mode 100755 index 9a27c7c25d..0000000000 Binary files a/system/doc/top/templates/flip_closed.gif and /dev/null differ diff --git a/system/doc/top/templates/flip_google.gif b/system/doc/top/templates/flip_google.gif deleted file mode 100755 index 3f0543c2bb..0000000000 Binary files a/system/doc/top/templates/flip_google.gif and /dev/null differ diff --git a/system/doc/top/templates/flip_open.gif b/system/doc/top/templates/flip_open.gif deleted file mode 100755 index 9dda60e73a..0000000000 Binary files a/system/doc/top/templates/flip_open.gif and /dev/null differ diff --git a/system/doc/top/templates/flip_static.gif b/system/doc/top/templates/flip_static.gif deleted file mode 100755 index 2b3ddb5382..0000000000 Binary files a/system/doc/top/templates/flip_static.gif and /dev/null differ diff --git a/system/doc/top/templates/flipmenu.js b/system/doc/top/templates/flipmenu.js deleted file mode 100755 index 92a5a58a06..0000000000 --- a/system/doc/top/templates/flipmenu.js +++ /dev/null @@ -1,342 +0,0 @@ -// ###################################################################### - -// ## flipMenu 5.0.0 (c) J. Reijers -// ## Last modifications: 23 March 2007 - -// ###################################################################### - -// ## Degree of indentation from the left. - flipIndentation = "5px"; - -// ## Padding inbetween menu items. - flipVerticalPadding = "4px"; - -// ## Margin between the left of the browser and the menu. - flipLeftMargin = "16px"; - -// ## Margin between the top of the browser and the menu. - flipTopMargin = "10px"; - -// ## Allow multiple menus to fold out without closing all the other open ones. - flipOpenMultipleMenus = false; - -// ## Preserve the current state of the menu (requires cookies). - flipSaveMenuState = true; - -// ## Use custom images for bullets - flipImages = true; - -// ## Images to use (specify full path) - flipImg_open = "flip_open.gif"; - flipImg_closed = "flip_closed.gif"; - flipImg_static = "flip_static.gif"; - -// ## Initialise all flipMenus onload - flipInitOnLoad = true; - -// ## Message to display in status bar while loading - flipLoadingMessage = "Loading..."; - -// ###################################################################### - -function alterSize(someSize, alterAmount) { - someSize = String(someSize); - var tmpNr = parseFloat(someSize.replace(/\D/g, "")); - var tmpChar = someSize.replace(/\d/g, ""); - return isNaN(tmpNr) ? someSize : ((tmpNr + alterAmount) + tmpChar); -} - -isIE = (String(navigator.appVersion).indexOf("MSIE") > -1); -if (!isIE) flipIndentation = alterSize(flipIndentation, -16); -if (!isIE) flipLeftMargin = alterSize(flipLeftMargin, -16); - -document.write( - "" -); - -if (flipImages) { - aFlipPreloads = []; - aFlipPreloads[0] = new Image; - aFlipPreloads[0].src = flipImg_open; - aFlipPreloads[1] = new Image; - aFlipPreloads[1].src = flipImg_closed; - aFlipPreloads[2] = new Image; - aFlipPreloads[2].src = flipImg_static; -} - -function addEvent(someObj, someEvent, someFunction) { - if (someObj.addEventListener) { someObj.addEventListener(someEvent, someFunction, true); return true; } else if (someObj.attachEvent) return someObj.attachEvent("on" + someEvent, someFunction); else return false; -} - -function openCloseFlip(theItem, newSetting, openParents) { - if (theItem.flipID) { - if (openParents) { - var tmpItem = theItem; - while (tmpItem.parentElement || tmpItem.parentNode) { - tmpItem = (tmpItem.parentElement) ? tmpItem.parentElement : tmpItem.parentNode; - openCloseFlip(tmpItem, newSetting); - } - } - if ((theItem.className == "flipFolderOpen" && newSetting == "closed") || (theItem.className == "flipFolderClosed" && newSetting == "open")) { - if (!theItem.childrenInitialised) { - for (var j = 0; j < theItem.childNodes.length; j++) if (theItem.childNodes[j].nodeName == "UL" && !theItem.childNodes[j].initialised) initFlip(theItem.childNodes[j]); - theItem.childrenInitialised = true; - } - theItem.getElementsByTagName("UL")[0].style.display = (newSetting == "open") ? "" : "none"; - theItem.className = newSetting == "open" ? "flipFolderOpen" : "flipFolderClosed"; - } - } -} - -function openFlip(theItem, openParents) { - openCloseFlip(theItem, "open", openParents); -} - -function closeFlip(theItem, closeParents) { - openCloseFlip(theItem, "closed", closeParents); -} - -function toggleFlip(theElement) { - if (theElement.flipID) { - var theItem = theElement; - var isContained = true; - } else { - if (theElement && theElement.button > 0) return false; - var theItem = (isIE) ? event.srcElement : theElement.target; - - var isContained = false; - if (theItem.className == "flipFolderOpen" || theItem.className == "flipFolderClosed") isContained = true; else while (theItem.parentElement || theItem.parentNode) { - if (theItem.className == "flipStatic" || theItem.className == "flipFolderOpen" || theItem.className == "flipFolderClosed") { - isContained = (theItem.className == "flipFolderOpen" || theItem.className == "flipFolderClosed"); - break; - } - theItem = (theItem.parentElement) ? theItem.parentElement : theItem.parentNode; - } - } - - var toOpenFlip = (isContained && theItem.className == "flipFolderClosed"); - - if (!flipOpenMultipleMenus && (toOpenFlip || theItem.className == "flipStatic")) { - if (theItem.parentElement || theItem.parentNode) { - var parentUL = (theItem.parentElement) ? theItem.parentElement : theItem.parentNode; - for (var i = 0; i < parentUL.childNodes.length; i++) closeFlip(parentUL.childNodes[i]); - } - } - - if (isContained) { - if (toOpenFlip) openFlip(theItem); else closeFlip(theItem); - } -} - -function setAllFlips(startElement, newSetting) { - if (typeof startElement == "undefined") var startElement = document; - if (typeof newSetting == "undefined") var newSetting = "closed"; - - var aUL = startElement.getElementsByTagName("UL"); - for (var i = 0; i < aUL.length; i++) { - var parentFlip = aUL[i].parentElement ? aUL[i].parentElement : aUL[i].parentNode; - openCloseFlip(parentFlip, newSetting); - } -} - -function openAllFlips(startElement) { - setAllFlips(startElement, "open"); -} - -function closeAllFlips(startElement) { - setAllFlips(startElement, "closed"); -} - -function initFlip(startElement) { - if (!document.createElement) return false; - - if (!startElement || !startElement.nodeName) { - var aUL = document.getElementsByTagName("UL"); - for (var i = 0; i < aUL.length; i++) { - if (flipLoadingMessage != "") window.status = flipLoadingMessage + " " + parseInt((i / (aUL.length - 1)) * 100, 10) + "%"; - var curUL = aUL[i]; - if (curUL.className == "flipMenu") { - initFlip(curUL); - - // ## Fix text selecting problem in Mozilla - curUL.onselectstart = new Function("return false"); - curUL.onmousedown = new Function("return false"); - curUL.onclick = new Function("return true"); - } - } - - if (flipSaveMenuState) loadMenuState(); - - if (flipLoadingMessage != "") window.status = ""; - return true; - } - - if (startElement.className == "flipMenu") startElement.style.display = ""; - - if (!startElement.childNodes || startElement.childNodes.length == 0) return false; - - if (typeof flipIDCur == "undefined") flipIDCur = 0; - if (!startElement.initialised) { - var aUL = startElement.getElementsByTagName("UL"); - for (var i = 0; i < aUL.length; i++) aUL[i].style.display = "none"; - } - - for (var i = 0; i < startElement.childNodes.length; i++) { - var curNode = startElement.childNodes[i]; - if (curNode.nodeName == "LI") { - flipIDCur++; - curNode.flipID = flipIDCur; - - var nodeHasChildren = curNode.getElementsByTagName("UL").length > 0; - if (nodeHasChildren) { - if (flipImages && curNode.flipClosed) curNode.style.listStyleImage = "url(" + curNode.flipClosed + ")"; - - if (curNode.className == null || curNode.className == "") curNode.className = "flipFolderClosed"; - } else { - curNode.className = "flipStatic"; - if (flipImages && !curNode.style.listStyleImage) { - if (!curNode.flipStatic) curNode.flipStatic = flipImg_static; - curNode.style.listStyleImage = "url(" + curNode.flipStatic + ")"; - } - } - - if (!curNode.flipOpen) curNode.flipOpen = flipImg_open; - if (!curNode.flipClosed) curNode.flipClosed = flipImg_closed; - - if (curNode.flipIsOpen) openFlip(curNode); - } - } - - startElement.initialised = true; -} - -function rootOfFlip(flipID, startElement) { - - function containsFlip(startElement, flipID) { - var flipFound = false; - var i = 0; - while (i < startElement.childNodes.length && !flipFound) { - var curNode = startElement.childNodes[i]; - flipFound = (curNode.flipID == flipID) ? true : containsFlip(curNode, flipID); - i++; - } - return flipFound; - } - - var rootFlip = null; - - if (!startElement || !startElement.nodeName) { - var aUL = document.getElementsByTagName("UL"); - var i = 0; - while (rootFlip == null && i < aUL.length) { - var curUL = aUL[i]; - if (curUL.nodeName == "UL" && curUL.className == "flipMenu") rootFlip = rootOfFlip(flipID, curUL); - i++; - } - return rootFlip; - } - - if (startElement.childNodes) for (var i = 0; i < startElement.childNodes.length; i++) { - var curNode = startElement.childNodes[i]; - if (curNode.flipID == flipID || containsFlip(curNode, flipID)) rootFlip = curNode; - } - - return rootFlip; -} - -function getCookie(cookieName) { - var allCookies = document.cookie; - var indexStr = allCookies.indexOf(cookieName + "="); - if (indexStr == -1) return ""; - indexStr = allCookies.indexOf("=", indexStr) + 1; - var endStr = allCookies.indexOf(";", indexStr); - if (endStr == -1) endStr = allCookies.length; - return unescape(allCookies.substring(indexStr, endStr)); -} - -function inArray(someID, someArray) { - for (var i = 0; i < someArray.length; i++) if (someArray[i] == someID) return true; - return false; -} - -function getMenuState(startElement) { - if (!startElement.childNodes || startElement.childNodes.length == 0) return ""; - - var openItems = ""; - var aUL = startElement.getElementsByTagName("UL"); - for (var i = 0; i < aUL.length; i++) { - var curNode = aUL[i]; - var parentFlip = (curNode.parentElement) ? curNode.parentElement : curNode.parentNode; - if (curNode.style.display == "" && parentFlip.flipID) openItems += " " + parentFlip.flipID; - } - return openItems; -} - -function putMenuState(startElement) { - if (!startElement.childNodes || startElement.childNodes.length == 0) return false; - - var aUL = startElement.getElementsByTagName("UL"); - for (var i = 0; i < aUL.length; i++) { - var curNode = aUL[i]; - var parentFlip = (curNode.parentElement) ? curNode.parentElement : curNode.parentNode; - if (inArray(parentFlip.flipID, aOpenItems)) { - openFlip(parentFlip); - if (typeof prevFlipRoot == "undefined") { - var testRoot = rootOfFlip(parentFlip.flipID); - if (testRoot.flipID == parentFlip.flipID) prevFlipRoot = testRoot; - } - } - } -} - -function saveMenuState() { - if (flipSaveMenuState) { - var aUL = document.getElementsByTagName("UL"); - for (var i = 0; i < aUL.length; i++) { - var curUL = aUL[i]; - var curID = curUL.id ? curUL.id : i; - if (curUL.className == "flipMenu") document.cookie = cookiePrefix + curID + "=" + getMenuState(curUL) + ";"; - } - } -} - -function loadMenuState() { - var aUL = document.getElementsByTagName("UL"); - for (var i = 0; i < aUL.length; i++) { - var curUL = aUL[i]; - var curID = curUL.id ? curUL.id : i; - if (curUL.className == "flipMenu") { - var savedState = String(getCookie(cookiePrefix + curID)); - if (savedState != "") { - aOpenItems = savedState.split(" "); - putMenuState(curUL); - } - } - } - - addEvent(window, "unload", saveMenuState); -} - -function clearMenuState(flipMenuID) { - if (typeof flipMenuID == "undefined") { - var aUL = document.getElementsByTagName("UL"); - for (var i = 0; i < aUL.length; i++) { - var curUL = aUL[i]; - var curID = curUL.id ? curUL.id : i; - if (curUL.className == "flipMenu") document.cookie = cookiePrefix + curID + "=;"; - } - } else document.cookie = cookiePrefix + flipMenuID + "=;"; -} - -cookiePrefix = document.location.pathname + "_"; - -addEvent(document, "click", toggleFlip); -if (flipInitOnLoad) addEvent(window, "load", initFlip); diff --git a/system/doc/top/templates/index.html.src b/system/doc/top/templates/index.html.src index 935bb11c80..257a656316 100644 --- a/system/doc/top/templates/index.html.src +++ b/system/doc/top/templates/index.html.src @@ -2,7 +2,7 @@ - - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - General -
    - - - - - -
    - - Introduction - - -
    -
    -About Erlang, OTP, Erlang/OTP and this documentation -
    - - - - - -
    - - Installation Guide - - -
    -
    -The Erlang/OTP Installation Guide -
    - - - - - -
    - - System Principles - - -
    -
    -Starting, stopping and configuring the Erlang runtime system -
    - - - - - -
    - - Embedded System - - -
    -
    -Erlang in an Embedded System -
     
    - Programming in Erlang -
    - - - - - -
    - - Erlang Reference Manual - - -
    -
    -Description of data types, language constructs and more -
    - - - - - -
    - - Getting Started - - -
    -
    -Getting started with Erlang -
    - - - - - -
    - - Programming Examples - - -
    -
    -Examples of using records, funs, list comprehensions and the bit syntax -
    - - - - - -
    - Efficiency Guide - -
    -
    -Learn how to write efficient programs in Erlang -
    - - - - - -
    - Interoperability Tutorial - -
    -
    -About interoperating with programs written in other programming languages -
     
    - Working with OTP -
    - - - - - -
    - - Design Principles - - -
    -
    -Structure your programs with applications, supervisors and generic behaviors (gen_server, gen_event and gen_fsm). -Also use the built in error logger. -
    - - - - - -
    - OAM Principles - -
    -
    -OTP Operation and Management Principles -
     
    - -
    - - - - diff --git a/system/doc/top/templates/toc_.html.src b/system/doc/top/templates/toc_.html.src deleted file mode 100644 index 5e79bc0ac8..0000000000 --- a/system/doc/top/templates/toc_.html.src +++ /dev/null @@ -1,105 +0,0 @@ - - - - Erlang/OTP #release# - - - - -
    -Erlang/OTP #release#
    -
    - - - -

    -

    -Erlang/OTP -
    Installation Guide - -
    System Principles - -
    Embedded System - -
    - -

    -

    - -

    -

    -Working with OTP -
    Design Principles - - -
    OAM Principles - -
    - -

    -

    -Applications -#applinks# -
    - -

    -http://www.erlang.se - - - -- cgit v1.2.3