diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/stdlib/doc/src | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/stdlib/doc/src')
79 files changed, 35695 insertions, 0 deletions
diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile new file mode 100644 index 0000000000..13b9b2ff18 --- /dev/null +++ b/lib/stdlib/doc/src/Makefile @@ -0,0 +1,176 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. 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. +# +# %CopyrightEnd% +# +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(STDLIB_VSN) +APPLICATION=stdlib + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +XML_APPLICATION_FILES = ref_man.xml + +XML_REF3_FILES = \ + array.xml \ + base64.xml \ + beam_lib.xml \ + c.xml \ + calendar.xml \ + dets.xml \ + dict.xml \ + digraph.xml \ + digraph_utils.xml \ + epp.xml \ + erl_eval.xml \ + erl_expand_records.xml \ + erl_id_trans.xml \ + erl_internal.xml \ + erl_lint.xml \ + erl_parse.xml \ + erl_pp.xml \ + erl_scan.xml \ + erl_tar.xml \ + ets.xml \ + file_sorter.xml \ + filelib.xml \ + filename.xml \ + gb_sets.xml \ + gb_trees.xml \ + gen_event.xml \ + gen_fsm.xml \ + gen_server.xml \ + io.xml \ + io_lib.xml \ + lib.xml \ + lists.xml \ + log_mf_h.xml \ + math.xml \ + ms_transform.xml \ + orddict.xml \ + ordsets.xml \ + pg.xml \ + pool.xml \ + proc_lib.xml \ + proplists.xml \ + qlc.xml \ + queue.xml \ + random.xml \ + re.xml \ + regexp.xml \ + sets.xml \ + shell.xml \ + shell_default.xml \ + slave.xml \ + sofs.xml \ + string.xml \ + supervisor.xml \ + supervisor_bridge.xml \ + sys.xml \ + timer.xml \ + unicode.xml \ + win32reg.xml \ + zip.xml + +XML_REF6_FILES = stdlib_app.xml + +XML_PART_FILES = part.xml part_notes.xml part_notes_history.xml +XML_CHAPTER_FILES = io_protocol.xml unicode_usage.xml notes.xml notes_history.xml +GIF_FILES = ushell1.gif ushell2.gif ushell3.gif + +BOOK_FILES = book.xml + +XML_FILES = \ + $(BOOK_FILES) $(XML_CHAPTER_FILES) \ + $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_REF6_FILES) $(XML_APPLICATION_FILES) + +# ---------------------------------------------------- + +HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(GIF_FILES:%.gif=$(HTMLDIR)/%.gif) + +INFO_FILE = ../../info + +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) +MAN6_FILES = $(XML_REF6_FILES:%_app.xml=$(MAN6DIR)/%.6) + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- +XML_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +docs: pdf html man + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +man: $(MAN3_FILES) $(MAN6_FILES) + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +debug opt: + +clean clean_docs: + rm -rf $(HTMLDIR)/* + rm -f $(MAN3DIR)/* + rm -f $(MAN6DIR)/* + rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f errs core *~ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_docs_spec: docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(HTMLDIR)/* \ + $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3 + $(INSTALL_DIR) $(RELEASE_PATH)/man/man6 + $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6 + +release_spec: diff --git a/lib/stdlib/doc/src/array.xml b/lib/stdlib/doc/src/array.xml new file mode 100644 index 0000000000..5c3ac6a2a9 --- /dev/null +++ b/lib/stdlib/doc/src/array.xml @@ -0,0 +1,482 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> +<erlref> +<header> + <copyright> + <year>2007</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + +<title>array</title> +<prepared></prepared> +<responsible></responsible> +<docno>1</docno> +<approved></approved> +<checked></checked> +<date></date> +<rev>A</rev> +<file>array.xml</file></header> +<module>array</module> +<modulesummary>Functional, extendible arrays.</modulesummary> +<description> +<p>Functional, extendible arrays. Arrays can have fixed size, or +can grow automatically as needed. A default value is used for entries +that have not been explicitly set.</p> + + <p>Arrays uses <em>zero</em> based indexing. This is a deliberate design +choice and differs from other erlang datastructures, e.g. tuples.</p> + + <p>Unless specified by the user when the array is created, the default + value is the atom <c>undefined</c>. There is no difference between an + unset entry and an entry which has been explicitly set to the same + value as the default one (cf. <seealso marker="#reset-2">reset/2</seealso>). If you need to +differentiate between unset and set entries, you must make sure that +the default value cannot be confused with the values of set entries.</p> + + <p>The array never shrinks automatically; if an index <c>I</c> has been used + successfully to set an entry, all indices in the range [0,<c>I</c>] will + stay accessible unless the array size is explicitly changed by + calling <seealso marker="#resize-2">resize/2</seealso>.</p> + + <p>Examples: + </p><pre> %% Create a fixed-size array with entries 0-9 set to 'undefined' + A0 = array:new(10). + 10 = array:size(A0). + + %% Create an extendible array and set entry 17 to 'true', + %% causing the array to grow automatically + A1 = array:set(17, true, array:new()). + 18 = array:size(A1). + + %% Read back a stored value + true = array:get(17, A1). + + %% Accessing an unset entry returns the default value + undefined = array:get(3, A1). + + %% Accessing an entry beyond the last set entry also returns the + %% default value, if the array does not have fixed size + undefined = array:get(18, A1). + + %% "sparse" functions ignore default-valued entries + A2 = array:set(4, false, A1). + [{4, false}, {17, true}] = array:sparse_to_orddict(A2). + + %% An extendible array can be made fixed-size later + A3 = array:fix(A2). + + %% A fixed-size array does not grow automatically and does not + %% allow accesses beyond the last set entry + {'EXIT',{badarg,_}} = (catch array:set(18, true, A3)). + {'EXIT',{badarg,_}} = (catch array:get(18, A3)).</pre></description> +<section><title>DATA TYPES</title><marker id="types"/> + +<taglist> +<tag><c>array()</c></tag> +<item><marker id="type-array"/> +<p>A functional, extendible array. The representation is + not documented and is subject to change without notice. Note that + arrays cannot be directly compared for equality.</p> +</item> +</taglist></section> +<funcs> +<func> +<name>default(Array::array()) -> term()</name> +<fsummary>Get the value used for uninitialized entries.</fsummary> + +<desc><marker id="default-1"/> + +<p>Get the value used for uninitialized entries. + </p> +<p><em>See also:</em> <seealso marker="#new-2">new/2</seealso>.</p> +</desc></func> +<func> +<name>fix(Array::array()) -> array()</name> +<fsummary>Fix the size of the array.</fsummary> + +<desc><marker id="fix-1"/> + +<p>Fix the size of the array. This prevents it from growing + automatically upon insertion; see also <seealso marker="#set-3">set/3</seealso>.</p> +<p><em>See also:</em> <seealso marker="#relax-1">relax/1</seealso>.</p> +</desc></func> +<func> +<name>foldl(Function, InitialAcc::term(), Array::array()) -> term()</name> +<fsummary>Fold the elements of the array using the given function and + initial accumulator value.</fsummary> +<type> +<v>Function = (Index::integer(), Value::term(), Acc::term()) -> term()</v></type> +<desc><marker id="foldl-3"/> + +<p>Fold the elements of the array using the given function and + initial accumulator value. The elements are visited in order from the + lowest index to the highest. If <c>Function</c> is not a function, the + call fails with reason <c>badarg</c>. + </p> +<p><em>See also:</em> <seealso marker="#foldr-3">foldr/3</seealso>, <seealso marker="#map-2">map/2</seealso>, <seealso marker="#sparse_foldl-3">sparse_foldl/3</seealso>.</p> +</desc></func> +<func> +<name>foldr(Function, InitialAcc::term(), Array::array()) -> term()</name> +<fsummary>Fold the elements of the array right-to-left using the given + function and initial accumulator value.</fsummary> +<type> +<v>Function = (Index::integer(), Value::term(), Acc::term()) -> term()</v></type> +<desc><marker id="foldr-3"/> + +<p>Fold the elements of the array right-to-left using the given + function and initial accumulator value. The elements are visited in + order from the highest index to the lowest. If <c>Function</c> is not a + function, the call fails with reason <c>badarg</c>. + </p> +<p><em>See also:</em> <seealso marker="#foldl-3">foldl/3</seealso>, <seealso marker="#map-2">map/2</seealso>.</p> +</desc></func> +<func> +<name>from_list(List::list()) -> array()</name> +<fsummary>Equivalent to from_list(List, undefined). +</fsummary> + +<desc><marker id="from_list-1"/> +<p>Equivalent to <seealso marker="#from_list-2">from_list(List, undefined)</seealso>.</p> +</desc></func> +<func> +<name>from_list(List::list(), Default::term()) -> array()</name> +<fsummary>Convert a list to an extendible array.</fsummary> + +<desc><marker id="from_list-2"/> + +<p>Convert a list to an extendible array. <c>Default</c> is used as the value + for uninitialized entries of the array. If <c>List</c> is not a proper list, + the call fails with reason <c>badarg</c>. + </p> +<p><em>See also:</em> <seealso marker="#new-2">new/2</seealso>, <seealso marker="#to_list-1">to_list/1</seealso>.</p> +</desc></func> +<func> +<name>from_orddict(Orddict::list()) -> array()</name> +<fsummary>Equivalent to from_orddict(Orddict, undefined). +</fsummary> + +<desc><marker id="from_orddict-1"/> +<p>Equivalent to <seealso marker="#from_orddict-2">from_orddict(Orddict, undefined)</seealso>.</p> +</desc></func> +<func> +<name>from_orddict(List::list(), Default::term()) -> array()</name> +<fsummary>Convert an ordered list of pairs {Index, Value} to a + corresponding extendible array.</fsummary> + +<desc><marker id="from_orddict-2"/> + +<p>Convert an ordered list of pairs <c>{Index, Value}</c> to a + corresponding extendible array. <c>Default</c> is used as the value for + uninitialized entries of the array. If <c>List</c> is not a proper, + ordered list of pairs whose first elements are nonnegative + integers, the call fails with reason <c>badarg</c>. + </p> +<p><em>See also:</em> <seealso marker="#new-2">new/2</seealso>, <seealso marker="#to_orddict-1">to_orddict/1</seealso>.</p> +</desc></func> +<func> +<name>get(I::integer(), Array::array()) -> term()</name> +<fsummary>Get the value of entry I.</fsummary> + +<desc><marker id="get-2"/> + +<p>Get the value of entry <c>I</c>. If <c>I</c> is not a nonnegative + integer, or if the array has fixed size and <c>I</c> is larger than the + maximum index, the call fails with reason <c>badarg</c>.</p> + + <p>If the array does not have fixed size, this function will return the + default value for any index <c>I</c> greater than <c>size(Array)-1</c>.</p> +<p><em>See also:</em> <seealso marker="#set-3">set/3</seealso>.</p> +</desc></func> +<func> +<name>is_array(X::term()) -> bool()</name> +<fsummary>Returns true if X appears to be an array, otherwise false.</fsummary> + +<desc><marker id="is_array-1"/> + +<p>Returns <c>true</c> if <c>X</c> appears to be an array, otherwise <c>false</c>. + Note that the check is only shallow; there is no guarantee that <c>X</c> + is a well-formed array representation even if this function returns + <c>true</c>.</p> +</desc></func> +<func> +<name>is_fix(Array::array()) -> bool()</name> +<fsummary>Check if the array has fixed size.</fsummary> + +<desc><marker id="is_fix-1"/> + +<p>Check if the array has fixed size. + Returns <c>true</c> if the array is fixed, otherwise <c>false</c>.</p> +<p><em>See also:</em> <seealso marker="#fix-1">fix/1</seealso>.</p> +</desc></func> +<func> +<name>map(Function, Array::array()) -> array()</name> +<fsummary>Map the given function onto each element of the array.</fsummary> +<type> +<v>Function = (Index::integer(), Value::term()) -> term()</v></type> +<desc><marker id="map-2"/> + +<p>Map the given function onto each element of the array. The + elements are visited in order from the lowest index to the highest. + If <c>Function</c> is not a function, the call fails with reason <c>badarg</c>. + </p> +<p><em>See also:</em> <seealso marker="#foldl-3">foldl/3</seealso>, <seealso marker="#foldr-3">foldr/3</seealso>, <seealso marker="#sparse_map-2">sparse_map/2</seealso>.</p> +</desc></func> +<func> +<name>new() -> array()</name> +<fsummary>Create a new, extendible array with initial size zero.</fsummary> + +<desc><marker id="new-0"/> + +<p>Create a new, extendible array with initial size zero.</p> +<p><em>See also:</em> <seealso marker="#new-1">new/1</seealso>, <seealso marker="#new-2">new/2</seealso>.</p> +</desc></func> +<func> +<name>new(Options::term()) -> array()</name> +<fsummary>Create a new array according to the given options.</fsummary> + +<desc><marker id="new-1"/> + +<p>Create a new array according to the given options. By default, +the array is extendible and has initial size zero. Array indices +start at 0.</p> + + <p><c>Options</c> is a single term or a list of terms, selected from the + following: + </p><taglist> + <tag><c>N::integer()</c> or <c>{size, N::integer()}</c></tag> + <item><p>Specifies the initial size of the array; this also implies + <c>{fixed, true}</c>. If <c>N</c> is not a nonnegative integer, the call + fails with reason <c>badarg</c>.</p></item> + <tag><c>fixed</c> or <c>{fixed, true}</c></tag> + <item><p>Creates a fixed-size array; see also <seealso marker="#fix-1">fix/1</seealso>.</p></item> + <tag><c>{fixed, false}</c></tag> + <item><p>Creates an extendible (non fixed-size) array.</p></item> + <tag><c>{default, Value}</c></tag> + <item><p>Sets the default value for the array to <c>Value</c>.</p></item> + </taglist><p> +Options are processed in the order they occur in the list, i.e., +later options have higher precedence.</p> + + <p>The default value is used as the value of uninitialized entries, and +cannot be changed once the array has been created.</p> + + <p>Examples: + </p><pre> array:new(100)</pre><p> creates a fixed-size array of size 100. + </p><pre> array:new({default,0})</pre><p> creates an empty, extendible array + whose default value is 0. + </p><pre> array:new([{size,10},{fixed,false},{default,-1}])</pre><p> creates an + extendible array with initial size 10 whose default value is -1. + </p> +<p><em>See also:</em> <seealso marker="#fix-1">fix/1</seealso>, <seealso marker="#from_list-2">from_list/2</seealso>, <seealso marker="#get-2">get/2</seealso>, <seealso marker="#new-0">new/0</seealso>, <seealso marker="#new-2">new/2</seealso>, <seealso marker="#set-3">set/3</seealso>.</p> +</desc></func> +<func> +<name>new(Size::integer(), Options::term()) -> array()</name> +<fsummary>Create a new array according to the given size and options.</fsummary> + +<desc><marker id="new-2"/> + +<p>Create a new array according to the given size and options. If + <c>Size</c> is not a nonnegative integer, the call fails with reason + <c>badarg</c>. By default, the array has fixed size. Note that any size + specifications in <c>Options</c> will override the <c>Size</c> parameter.</p> + + <p>If <c>Options</c> is a list, this is simply equivalent to <c>new([{size, + Size} | Options]</c>, otherwise it is equivalent to <c>new([{size, Size} | + [Options]]</c>. However, using this function directly is more efficient.</p> + + <p>Example: + </p><pre> array:new(100, {default,0})</pre><p> creates a fixed-size array of size + 100, whose default value is 0. + </p> +<p><em>See also:</em> <seealso marker="#new-1">new/1</seealso>.</p> +</desc></func> +<func> +<name>relax(Array::array()) -> array()</name> +<fsummary>Make the array resizable.</fsummary> + +<desc><marker id="relax-1"/> + +<p>Make the array resizable. (Reverses the effects of <seealso marker="#fix-1">fix/1</seealso>.)</p> +<p><em>See also:</em> <seealso marker="#fix-1">fix/1</seealso>.</p> +</desc></func> +<func> +<name>reset(I::integer(), Array::array()) -> array()</name> +<fsummary>Reset entry I to the default value for the array.</fsummary> + +<desc><marker id="reset-2"/> + +<p>Reset entry <c>I</c> to the default value for the array. + If the value of entry <c>I</c> is the default value the array will be + returned unchanged. Reset will never change size of the array. + Shrinking can be done explicitly by calling <seealso marker="#resize-2">resize/2</seealso>.</p> + + <p>If <c>I</c> is not a nonnegative integer, or if the array has fixed size + and <c>I</c> is larger than the maximum index, the call fails with reason + <c>badarg</c>; cf. <seealso marker="#set-3">set/3</seealso> + </p> +<p><em>See also:</em> <seealso marker="#new-2">new/2</seealso>, <seealso marker="#set-3">set/3</seealso>.</p> +</desc></func> +<func> +<name>resize(Array::array()) -> array()</name> +<fsummary>Change the size of the array to that reported by sparse_size/1.</fsummary> + +<desc><marker id="resize-1"/> + +<p>Change the size of the array to that reported by <seealso marker="#sparse_size-1">sparse_size/1</seealso>. If the given array has fixed size, the resulting + array will also have fixed size.</p> +<p><em>See also:</em> <seealso marker="#resize-2">resize/2</seealso>, <seealso marker="#sparse_size-1">sparse_size/1</seealso>.</p> +</desc></func> +<func> +<name>resize(Size::integer(), Array::array()) -> array()</name> +<fsummary>Change the size of the array.</fsummary> + +<desc><marker id="resize-2"/> + +<p>Change the size of the array. If <c>Size</c> is not a nonnegative + integer, the call fails with reason <c>badarg</c>. If the given array has + fixed size, the resulting array will also have fixed size.</p> +</desc></func> +<func> +<name>set(I::integer(), Value::term(), Array::array()) -> array()</name> +<fsummary>Set entry I of the array to Value.</fsummary> + +<desc><marker id="set-3"/> + +<p>Set entry <c>I</c> of the array to <c>Value</c>. If <c>I</c> is not a + nonnegative integer, or if the array has fixed size and <c>I</c> is larger + than the maximum index, the call fails with reason <c>badarg</c>.</p> + + <p>If the array does not have fixed size, and <c>I</c> is greater than + <c>size(Array)-1</c>, the array will grow to size <c>I+1</c>. + </p> +<p><em>See also:</em> <seealso marker="#get-2">get/2</seealso>, <seealso marker="#reset-2">reset/2</seealso>.</p> +</desc></func> +<func> +<name>size(Array::array()) -> integer()</name> +<fsummary>Get the number of entries in the array.</fsummary> + +<desc><marker id="size-1"/> + +<p>Get the number of entries in the array. Entries are numbered + from 0 to <c>size(Array)-1</c>; hence, this is also the index of the first + entry that is guaranteed to not have been previously set.</p> +<p><em>See also:</em> <seealso marker="#set-3">set/3</seealso>, <seealso marker="#sparse_size-1">sparse_size/1</seealso>.</p> +</desc></func> +<func> +<name>sparse_foldl(Function, InitialAcc::term(), Array::array()) -> term()</name> +<fsummary>Fold the elements of the array using the given function and + initial accumulator value, skipping default-valued entries.</fsummary> +<type> +<v>Function = (Index::integer(), Value::term(), Acc::term()) -> term()</v></type> +<desc><marker id="sparse_foldl-3"/> + +<p>Fold the elements of the array using the given function and + initial accumulator value, skipping default-valued entries. The + elements are visited in order from the lowest index to the highest. + If <c>Function</c> is not a function, the call fails with reason <c>badarg</c>. + </p> +<p><em>See also:</em> <seealso marker="#foldl-3">foldl/3</seealso>, <seealso marker="#sparse_foldr-3">sparse_foldr/3</seealso>.</p> +</desc></func> +<func> +<name>sparse_foldr(Function, InitialAcc::term(), Array::array()) -> term()</name> +<fsummary>Fold the elements of the array right-to-left using the given + function and initial accumulator value, skipping default-valued + entries.</fsummary> +<type> +<v>Function = (Index::integer(), Value::term(), Acc::term()) -> term()</v></type> +<desc><marker id="sparse_foldr-3"/> + +<p>Fold the elements of the array right-to-left using the given + function and initial accumulator value, skipping default-valued + entries. The elements are visited in order from the highest index to + the lowest. If <c>Function</c> is not a function, the call fails with + reason <c>badarg</c>. + </p> +<p><em>See also:</em> <seealso marker="#foldr-3">foldr/3</seealso>, <seealso marker="#sparse_foldl-3">sparse_foldl/3</seealso>.</p> +</desc></func> +<func> +<name>sparse_map(Function, Array::array()) -> array()</name> +<fsummary>Map the given function onto each element of the array, skipping + default-valued entries.</fsummary> +<type> +<v>Function = (Index::integer(), Value::term()) -> term()</v></type> +<desc><marker id="sparse_map-2"/> + +<p>Map the given function onto each element of the array, skipping + default-valued entries. The elements are visited in order from the + lowest index to the highest. If <c>Function</c> is not a function, the + call fails with reason <c>badarg</c>. + </p> +<p><em>See also:</em> <seealso marker="#map-2">map/2</seealso>.</p> +</desc></func> +<func> +<name>sparse_size(A::array()) -> integer()</name> +<fsummary>Get the number of entries in the array up until the last + non-default valued entry.</fsummary> + +<desc><marker id="sparse_size-1"/> + +<p>Get the number of entries in the array up until the last + non-default valued entry. In other words, returns <c>I+1</c> if <c>I</c> is the + last non-default valued entry in the array, or zero if no such entry + exists.</p> +<p><em>See also:</em> <seealso marker="#resize-1">resize/1</seealso>, <seealso marker="#size-1">size/1</seealso>.</p> +</desc></func> +<func> +<name>sparse_to_list(Array::array()) -> list()</name> +<fsummary>Converts the array to a list, skipping default-valued entries.</fsummary> + +<desc><marker id="sparse_to_list-1"/> + +<p>Converts the array to a list, skipping default-valued entries. + </p> +<p><em>See also:</em> <seealso marker="#to_list-1">to_list/1</seealso>.</p> +</desc></func> +<func> +<name>sparse_to_orddict(Array::array()) -> [{Index::integer(), Value::term()}]</name> +<fsummary>Convert the array to an ordered list of pairs {Index, Value}, + skipping default-valued entries.</fsummary> + +<desc><marker id="sparse_to_orddict-1"/> + +<p>Convert the array to an ordered list of pairs <c>{Index, Value}</c>, + skipping default-valued entries. + </p> +<p><em>See also:</em> <seealso marker="#to_orddict-1">to_orddict/1</seealso>.</p> +</desc></func> +<func> +<name>to_list(Array::array()) -> list()</name> +<fsummary>Converts the array to a list.</fsummary> + +<desc><marker id="to_list-1"/> + +<p>Converts the array to a list. + </p> +<p><em>See also:</em> <seealso marker="#from_list-2">from_list/2</seealso>, <seealso marker="#sparse_to_list-1">sparse_to_list/1</seealso>.</p> +</desc></func> +<func> +<name>to_orddict(Array::array()) -> [{Index::integer(), Value::term()}]</name> +<fsummary>Convert the array to an ordered list of pairs {Index, Value}.</fsummary> + +<desc><marker id="to_orddict-1"/> + +<p>Convert the array to an ordered list of pairs <c>{Index, Value}</c>. + </p> +<p><em>See also:</em> <seealso marker="#from_orddict-2">from_orddict/2</seealso>, <seealso marker="#sparse_to_orddict-1">sparse_to_orddict/1</seealso>.</p> +</desc></func></funcs> + +</erlref> + diff --git a/lib/stdlib/doc/src/base64.xml b/lib/stdlib/doc/src/base64.xml new file mode 100644 index 0000000000..d3fd7a843b --- /dev/null +++ b/lib/stdlib/doc/src/base64.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2007</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>base64</title> + <prepared>Ingela Anderton Andin</prepared> + <docno></docno> + <date>2007-02-22</date> + <rev></rev> + <file>base64.sgml</file> + </header> + <module>base64</module> + <modulesummary>Implements base 64 encode and decode, see RFC2045.</modulesummary> + <description> + <p>Implements base 64 encode and decode, see RFC2045. </p> + </description> + <funcs> + <func> + <name>encode(Data) -> Base64 </name> + <name>encode_to_string(Data) -> Base64String</name> + <fsummary>Encodes data into base64. </fsummary> + <type> + <v>Data = string() | binary()</v> + <v>Base64 = binary()</v> + <v>Base64String = string()</v> + </type> + <desc> + <p>Encodes a plain ASCII string into base64. The result will + be 33% larger than the data.</p> + </desc> + </func> + <func> + <name>decode(Base64) -> Data</name> + <name>decode_to_string(Base64) -> DataString</name> + <name>mime_decode(Base64) -> Data</name> + <name>mime_decode_to_string(Base64) -> DataString</name> + <fsummary>Decodes a base64 encoded string to data. </fsummary> + <type> + <v>Base64 = string() | binary()</v> + <v>Data = binary()</v> + <v>DataString = string()</v> + </type> + <desc> + <p>Decodes a base64 encoded string to plain ASCII. See RFC4648. + <c>mime_decode/1</c> and <c>mime_decode_to_string/1</c> + strips away illegal characters, while <c>decode/1</c> and + <c>decode_to_string/1</c> only strips away whitespace characters.</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/beam_lib.xml b/lib/stdlib/doc/src/beam_lib.xml new file mode 100644 index 0000000000..f2a9c2a671 --- /dev/null +++ b/lib/stdlib/doc/src/beam_lib.xml @@ -0,0 +1,507 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>beam_lib</title> + <prepared>Hans Bolinder</prepared> + <docno></docno> + <date>1999-10-30</date> + <rev>PA1</rev> + </header> + <module>beam_lib</module> + <modulesummary>An Interface To the BEAM File Format</modulesummary> + <description> + <p><c>beam_lib</c> provides an interface to files created by + the BEAM compiler ("BEAM files"). The format used, a variant of + "EA IFF 1985" Standard for Interchange Format Files, divides data + into chunks.</p> + <p>Chunk data can be returned as binaries or as compound terms. + Compound terms are returned when chunks are referenced by names + (atoms) rather than identifiers (strings). The names recognized + and the corresponding identifiers are:</p> + <list type="bulleted"> + <item><c>abstract_code ("Abst")</c></item> + <item><c>attributes ("Attr")</c></item> + <item><c>compile_info ("CInf")</c></item> + <item><c>exports ("ExpT")</c></item> + <item><c>labeled_exports ("ExpT")</c></item> + <item><c>imports ("ImpT")</c></item> + <item><c>indexed_imports ("ImpT")</c></item> + <item><c>locals ("LocT")</c></item> + <item><c>labeled_locals ("LocT")</c></item> + <item><c>atoms ("Atom")</c></item> + </list> + </description> + + <section> + <marker id="debug_info"></marker> + <title>Debug Information/Abstract Code</title> + <p>The option <c>debug_info</c> can be given to the compiler (see + <seealso marker="compiler:compile#debug_info">compile(3)</seealso>) + in order to have debug information in the form of abstract code + (see <seealso marker="erts:absform">The Abstract Format</seealso> + in ERTS User's Guide) stored in the <c>abstract_code</c> chunk. + Tools such as Debugger and Xref require the debug information to + be included.</p> + <warning> + <p>Source code can be reconstructed from the debug information. + Use encrypted debug information (see below) to prevent this.</p> + </warning> + <p>The debug information can also be removed from BEAM files + using <seealso marker="#strip/1">strip/1</seealso>, + <seealso marker="#strip_files/1">strip_files/1</seealso> and/or + <seealso marker="#strip_release/1">strip_release/1</seealso>.</p> + <p><em>Reconstructing source code</em></p> + <p>Here is an example of how to reconstruct source code from + the debug information in a BEAM file <c>Beam</c>:</p> + <code type="none"> + {ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(Beam,[abstract_code]). + io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code> + <p><em>Encrypted debug information</em></p> + <p>The debug information can be encrypted in order to keep + the source code secret, but still being able to use tools such as + Xref or Debugger. </p> + <p>To use encrypted debug information, a key must be provided to + the compiler and <c>beam_lib</c>. The key is given as a string and + it is recommended that it contains at least 32 characters and + that both upper and lower case letters as well as digits and + special characters are used.</p> + <p></p> + <p>The default type -- and currently the only type -- of crypto + algorithm is <c>des3_cbc</c>, three rounds of DES. The key string + will be scrambled using <c>erlang:md5/1</c> to generate + the actual keys used for <c>des3_cbc</c>.</p> + <note> + <p>As far as we know by the time of writing, it is + infeasible to break <c>des3_cbc</c> encryption without any + knowledge of the key. Therefore, as long as the key is kept + safe and is unguessable, the encrypted debug information + <em>should</em> be safe from intruders.</p> + </note> + <p>There are two ways to provide the key:</p> + <list type="ordered"> + <item> + <p>Use the compiler option <c>{debug_info,Key}</c>, see + <seealso marker="compiler:compile#debug_info_key">compile(3)</seealso>, + and the function + <seealso marker="#crypto_key_fun/1">crypto_key_fun/1</seealso> + to register a fun which returns the key whenever + <c>beam_lib</c> needs to decrypt the debug information.</p> + <p>If no such fun is registered, <c>beam_lib</c> will instead + search for a <c>.erlang.crypt</c> file, see below.</p> + </item> + <item> + <p>Store the key in a text file named <c>.erlang.crypt</c>.</p> + <p>In this case, the compiler option <c>encrypt_debug_info</c> + can be used, see + <seealso marker="compiler:compile#encrypt_debug_info">compile(3)</seealso>.</p> + </item> + </list> + <p><em>.erlang.crypt</em></p> + <p><c>beam_lib</c> searches for <c>.erlang.crypt</c> in the current + directory and then the home directory for the current user. If + the file is found and contains a key, <c>beam_lib</c> will + implicitly create a crypto key fun and register it.</p> + <p>The <c>.erlang.crypt</c> file should contain a single list of + tuples:</p> + <code type="none"> + {debug_info, Mode, Module, Key}</code> + <p><c>Mode</c> is the type of crypto algorithm; currently, the only + allowed value thus is <c>des3_cbc</c>. <c>Module</c> is either an + atom, in which case <c>Key</c> will only be used for the module + <c>Module</c>, or <c>[]</c>, in which case <c>Key</c> will be + used for all modules. <c>Key</c> is the non-empty key string.</p> + <p>The <c>Key</c> in the first tuple where both <c>Mode</c> and + <c>Module</c> matches will be used.</p> + <p>Here is an example of an <c>.erlang.crypt</c> file that returns + the same key for all modules:</p> + <code type="none"><![CDATA[ +[{debug_info, des3_cbc, [], "%>7}|pc/DM6Cga*68$Mw]L#&_Gejr]G^"}].]]></code> + <p>And here is a slightly more complicated example of an + <c>.erlang.crypt</c> which provides one key for the module + <c>t</c>, and another key for all other modules:</p> + <code type="none"><![CDATA[ +[{debug_info, des3_cbc, t, "My KEY"}, + {debug_info, des3_cbc, [], "%>7}|pc/DM6Cga*68$Mw]L#&_Gejr]G^"}].]]></code> + <note> + <p>Do not use any of the keys in these examples. Use your own + keys.</p> + </note> + </section> + + <section> + <title>DATA TYPES</title> + <code type="none"> +beam() -> Module | Filename | binary() + Module = atom() + Filename = string() | atom()</code> + <p>Each of the functions described below accept either the module + name, the filename, or a binary containing the beam module.</p> + <code type="none"> +chunkdata() = {ChunkId, DataB} | {ChunkName, DataT} + ChunkId = chunkid() + DataB = binary() + {ChunkName, DataT} = + {abstract_code, AbstractCode} + | {attributes, [{Attribute, [AttributeValue]}]} + | {compile_info, [{InfoKey, [InfoValue]}]} + | {exports, [{Function, Arity}]} + | {labeled_exports, [{Function, Arity, Label}]} + | {imports, [{Module, Function, Arity}]} + | {indexed_imports, [{Index, Module, Function, Arity}]} + | {locals, [{Function, Arity}]}]} + | {labeled_locals, [{Function, Arity, Label}]}]} + | {atoms, [{integer(), atom()}]} + AbstractCode = {AbstVersion, Forms} | no_abstract_code + AbstVersion = atom() + Attribute = atom() + AttributeValue = term() + Module = Function = atom() + Arity = int() + Label = int()</code> + <p>It is not checked that the forms conform to the abstract format + indicated by <c>AbstVersion</c>. <c>no_abstract_code</c> means + that the <c>"Abst"</c> chunk is present, but empty.</p> + <p>The list of attributes is sorted on <c>Attribute</c>, and each + attribute name occurs once in the list. The attribute values + occur in the same order as in the file. The lists of functions + are also sorted.</p> + <code type="none"> +chunkid() = "Abst" | "Attr" | "CInf" + | "ExpT" | "ImpT" | "LocT" + | "Atom" + +chunkname() = abstract_code | attributes | compile_info + | exports | labeled_exports + | imports | indexed_imports + | locals | labeled_locals + | atoms + +chunkref() = chunkname() | chunkid()</code> + </section> + <funcs> + <func> + <name>chunks(Beam, [ChunkRef]) -> {ok, {Module, [ChunkData]}} | {error, beam_lib, Reason}</name> + <fsummary>Read selected chunks from a BEAM file or binary</fsummary> + <type> + <v>Beam = beam()</v> + <v>ChunkRef = chunkref()</v> + <v>Module = atom()</v> + <v>ChunkData = chunkdata()</v> + <v>Reason = {unknown_chunk, Filename, atom()}</v> + <v> | {key_missing_or_invalid, Filename, abstract_code}</v> + <v> | Reason1 -- see info/1</v> + <v> Filename = string()</v> + </type> + <desc> + <p>Reads chunk data for selected chunks refs. The order of + the returned list of chunk data is determined by the order + of the list of chunks references.</p> + </desc> + </func> + <func> + <name>chunks(Beam, [ChunkRef], [Option]) -> {ok, {Module, [ChunkResult]}} | {error, beam_lib, Reason}</name> + <fsummary>Read selected chunks from a BEAM file or binary</fsummary> + <type> + <v>Beam = beam()</v> + <v>ChunkRef = chunkref()</v> + <v>Module = atom()</v> + <v>Option = allow_missing_chunks</v> + <v>ChunkResult = {chunkref(), ChunkContents} | {chunkref(), missing_chunk}</v> + <v>Reason = {missing_chunk, Filename, atom()}</v> + <v> | {key_missing_or_invalid, Filename, abstract_code}</v> + <v> | Reason1 -- see info/1</v> + <v> Filename = string()</v> + </type> + <desc> + <p>Reads chunk data for selected chunks refs. The order of + the returned list of chunk data is determined by the order + of the list of chunks references.</p> + <p>By default, if any requested chunk is missing in <c>Beam</c>, + an <c>error</c> tuple is returned. + However, if the option <c>allow_missing_chunks</c> has been given, + a result will be returned even if chunks are missing. + In the result list, any missing chunks will be represented as + <c>{ChunkRef,missing_chunk}</c>. + Note, however, that if the <c>"Atom"</c> chunk if missing, that is + considered a fatal error and the return value will be an <c>error</c> + tuple.</p> + </desc> + </func> + <func> + <name>version(Beam) -> {ok, {Module, [Version]}} | {error, beam_lib, Reason}</name> + <fsummary>Read the BEAM file's module version</fsummary> + <type> + <v>Beam = beam()</v> + <v>Module = atom()</v> + <v>Version = term()</v> + <v>Reason -- see chunks/2</v> + </type> + <desc> + <p>Returns the module version(s). A version is defined by + the module attribute <c>-vsn(Vsn)</c>. If this attribute is + not specified, the version defaults to the checksum of + the module. Note that if the version <c>Vsn</c> is not a list, + it is made into one, that is <c>{ok,{Module,[Vsn]}}</c> is + returned. If there are several <c>-vsn</c> module attributes, + the result is the concatenated list of versions. Examples:</p> + <pre> +1> <input>beam_lib:version(a).</input> % -vsn(1). +{ok,{a,[1]}} +2> <input>beam_lib:version(b).</input> % -vsn([1]). +{ok,{b,[1]}} +3> <input>beam_lib:version(c).</input> % -vsn([1]). -vsn(2). +{ok,{c,[1,2]}} +4> <input>beam_lib:version(d).</input> % no -vsn attribute +{ok,{d,[275613208176997377698094100858909383631]}}</pre> + </desc> + </func> + <func> + <name>md5(Beam) -> {ok, {Module, MD5}} | {error, beam_lib, Reason}</name> + <fsummary>Read the BEAM file's module version</fsummary> + <type> + <v>Beam = beam()</v> + <v>Module = atom()</v> + <v>MD5 = binary()</v> + <v>Reason -- see chunks/2</v> + </type> + <desc> + <p>Calculates an MD5 redundancy check for the code of the module + (compilation date and other attributes are not included).</p> + </desc> + </func> + <func> + <name>info(Beam) -> [{Item, Info}] | {error, beam_lib, Reason1}</name> + <fsummary>Information about a BEAM file</fsummary> + <type> + <v>Beam = beam()</v> + <v>Item, Info -- see below</v> + <v>Reason1 = {chunk_too_big, Filename, ChunkId, ChunkSize, FileSize}</v> + <v> | {invalid_beam_file, Filename, Pos}</v> + <v> | {invalid_chunk, Filename, ChunkId}</v> + <v> | {missing_chunk, Filename, ChunkId}</v> + <v> | {not_a_beam_file, Filename}</v> + <v> | {file_error, Filename, Posix}</v> + <v> Filename = string()</v> + <v> ChunkId = chunkid()</v> + <v> ChunkSize = FileSize = int()</v> + <v> Pos = int()</v> + <v> Posix = posix() -- see file(3)</v> + </type> + <desc> + <p>Returns a list containing some information about a BEAM file + as tuples <c>{Item, Info}</c>:</p> + <taglist> + <tag><c>{file, Filename} | {binary, Binary}</c></tag> + <item> + <p>The name (string) of the BEAM file, or the binary from + which the information was extracted.</p> + </item> + <tag><c>{module, Module}</c></tag> + <item> + <p>The name (atom) of the module.</p> + </item> + <tag><c>{chunks, [{ChunkId, Pos, Size}]}</c></tag> + <item> + <p>For each chunk, the identifier (string) and the position + and size of the chunk data, in bytes.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>cmp(Beam1, Beam2) -> ok | {error, beam_lib, Reason}</name> + <fsummary>Compare two BEAM files</fsummary> + <type> + <v>Beam1 = Beam2 = beam()</v> + <v>Reason = {modules_different, Module1, Module2}</v> + <v> | {chunks_different, ChunkId}</v> + <v> | Reason1 -- see info/1</v> + <v> Module1 = Module2 = atom()</v> + <v> ChunkId = chunkid()</v> + </type> + <desc> + <p>Compares the contents of two BEAM files. If the module names + are the same, and the chunks with the identifiers + <c>"Code"</c>, <c>"ExpT"</c>, <c>"ImpT"</c>, <c>"StrT"</c>, + and <c>"Atom"</c> have the same contents in both files, + <c>ok</c> is returned. Otherwise an error message is returned.</p> + </desc> + </func> + <func> + <name>cmp_dirs(Dir1, Dir2) -> {Only1, Only2, Different} | {error, beam_lib, Reason1}</name> + <fsummary>Compare the BEAM files in two directories</fsummary> + <type> + <v>Dir1 = Dir2 = string() | atom()</v> + <v>Different = [{Filename1, Filename2}]</v> + <v>Only1 = Only2 = [Filename]</v> + <v>Filename = Filename1 = Filename2 = string()</v> + <v>Reason1 = {not_a_directory, term()} | -- see info/1</v> + </type> + <desc> + <p>The <c>cmp_dirs/2</c> function compares the BEAM files in + two directories. Only files with extension <c>".beam"</c> are + compared. BEAM files that exist in directory <c>Dir1</c> + (<c>Dir2</c>) only are returned in <c>Only1</c> + (<c>Only2</c>). BEAM files that exist on both directories but + are considered different by <c>cmp/2</c> are returned as + pairs {<c>Filename1</c>, <c>Filename2</c>} where + <c>Filename1</c> (<c>Filename2</c>) exists in directory + <c>Dir1</c> (<c>Dir2</c>).</p> + </desc> + </func> + <func> + <name>diff_dirs(Dir1, Dir2) -> ok | {error, beam_lib, Reason1}</name> + <fsummary>Compare the BEAM files in two directories</fsummary> + <type> + <v>Dir1 = Dir2 = string() | atom()</v> + <v>Reason1 = {not_a_directory, term()} | -- see info/1</v> + </type> + <desc> + <p>The <c>diff_dirs/2</c> function compares the BEAM files in + two directories the way <c>cmp_dirs/2</c> does, but names of + files that exist in only one directory or are different are + presented on standard output.</p> + </desc> + </func> + <func> + <name>strip(Beam1) -> {ok, {Module, Beam2}} | {error, beam_lib, Reason1}</name> + <fsummary>Removes chunks not needed by the loader from a BEAM file</fsummary> + <type> + <v>Beam1 = Beam2 = beam()</v> + <v>Module = atom()</v> + <v>Reason1 -- see info/1</v> + </type> + <desc> + <p>The <c>strip/1</c> function removes all chunks from a BEAM + file except those needed by the loader. In particular, + the debug information (<c>abstract_code</c> chunk) is removed.</p> + </desc> + </func> + <func> + <name>strip_files(Files) -> {ok, [{Module, Beam2}]} | {error, beam_lib, Reason1}</name> + <fsummary>Removes chunks not needed by the loader from BEAM files</fsummary> + <type> + <v>Files = [Beam1]</v> + <v> Beam1 = beam()</v> + <v>Module = atom()</v> + <v>Beam2 = beam()</v> + <v>Reason1 -- see info/1</v> + </type> + <desc> + <p>The <c>strip_files/1</c> function removes all chunks except + those needed by the loader from BEAM files. In particular, + the debug information (<c>abstract_code</c> chunk) is removed. + The returned list contains one element for each given file + name, in the same order as in <c>Files</c>.</p> + </desc> + </func> + <func> + <name>strip_release(Dir) -> {ok, [{Module, Filename]}} | {error, beam_lib, Reason1}</name> + <fsummary>Removes chunks not needed by the loader from all BEAM files of a release</fsummary> + <type> + <v>Dir = string() | atom()</v> + <v>Module = atom()</v> + <v>Filename = string()</v> + <v>Reason1 = {not_a_directory, term()} | -- see info/1</v> + </type> + <desc> + <p>The <c>strip_release/1</c> function removes all chunks + except those needed by the loader from the BEAM files of a + release. <c>Dir</c> should be the installation root + directory. For example, the current OTP release can be + stripped with the call + <c>beam_lib:strip_release(code:root_dir())</c>.</p> + </desc> + </func> + <func> + <name>format_error(Reason) -> Chars</name> + <fsummary>Return an English description of a BEAM read error reply</fsummary> + <type> + <v>Reason -- see other functions</v> + <v>Chars = [char() | Chars]</v> + </type> + <desc> + <p>Given the error returned by any function in this module, + the function <c>format_error</c> returns a descriptive string + of the error in English. For file errors, the function + <c>file:format_error(Posix)</c> should be called.</p> + </desc> + </func> + <func> + <name>crypto_key_fun(CryptoKeyFun) -> ok | {error, Reason}</name> + <fsummary>Register a fun that provides a crypto key</fsummary> + <type> + <v>CryptoKeyFun = fun() -- see below</v> + <v>Reason = badfun | exists | term()</v> + </type> + <desc> + <p>The <c>crypto_key_fun/1</c> function registers a unary fun + that will be called if <c>beam_lib</c> needs to read an + <c>abstract_code</c> chunk that has been encrypted. The fun + is held in a process that is started by the function.</p> + <p>If there already is a fun registered when attempting to + register a fun, <c>{error, exists}</c> is returned.</p> + <p>The fun must handle the following arguments:</p> + <code type="none"> + CryptoKeyFun(init) -> ok | {ok, NewCryptoKeyFun} | {error, Term}</code> + <p>Called when the fun is registered, in the process that holds + the fun. Here the crypto key fun can do any necessary + initializations. If <c>{ok, NewCryptoKeyFun}</c> is returned + then <c>NewCryptoKeyFun</c> will be registered instead of + <c>CryptoKeyFun</c>. If <c>{error, Term}</c> is returned, + the registration is aborted and <c>crypto_key_fun/1</c> + returns <c>{error, Term}</c> as well.</p> + <code type="none"> + CryptoKeyFun({debug_info, Mode, Module, Filename}) -> Key</code> + <p>Called when the key is needed for the module <c>Module</c> + in the file named <c>Filename</c>. <c>Mode</c> is the type of + crypto algorithm; currently, the only possible value thus is + <c>des3_cbc</c>. The call should fail (raise an exception) if + there is no key available.</p> + <code type="none"> + CryptoKeyFun(clear) -> term()</code> + <p>Called before the fun is unregistered. Here any cleaning up + can be done. The return value is not important, but is passed + back to the caller of <c>clear_crypto_key_fun/0</c> as part + of its return value.</p> + </desc> + </func> + <func> + <name>clear_crypto_key_fun() -> {ok, Result}</name> + <fsummary>Unregister the current crypto key fun</fsummary> + <type> + <v>Result = undefined | term()</v> + </type> + <desc> + <p>Unregisters the crypto key fun and terminates the process + holding it, started by <c>crypto_key_fun/1</c>.</p> + <p>The <c>clear_crypto_key_fun/1</c> either returns + <c>{ok, undefined}</c> if there was no crypto key fun + registered, or <c>{ok, Term}</c>, where <c>Term</c> is + the return value from <c>CryptoKeyFun(clear)</c>, see + <c>crypto_key_fun/1</c>.</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/book.xml b/lib/stdlib/doc/src/book.xml new file mode 100644 index 0000000000..10ee6f3855 --- /dev/null +++ b/lib/stdlib/doc/src/book.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + <header titlestyle="normal"> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>STDLIB</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>1997-05-02</date> + <rev>1.3</rev> + <file>book.sgml</file> + </header> + <insidecover> + </insidecover> + <pagetext>STDLIB</pagetext> + <preamble> + <contents level="2"></contents> + </preamble> + <parts> + <xi:include href="part.xml"/> + </parts> + <applications> + <xi:include href="ref_man.xml"/> + </applications> + <releasenotes> + <xi:include href="notes.xml"/> + </releasenotes> + <listofterms></listofterms> + <index></index> +</book> + diff --git a/lib/stdlib/doc/src/c.xml b/lib/stdlib/doc/src/c.xml new file mode 100644 index 0000000000..19e3ac1f08 --- /dev/null +++ b/lib/stdlib/doc/src/c.xml @@ -0,0 +1,320 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>c</title> + <prepared>Joe Armstrong</prepared> + <docno>1</docno> + <date>96-10-30</date> + <rev>B</rev> + </header> + <module>c</module> + <modulesummary>Command Interface Module</modulesummary> + <description> + <p>The <c>c</c> module enables users to enter the short form of + some commonly used commands.</p> + <note> + <p>These functions are are intended for interactive use in + the Erlang shell only. The module prefix may be omitted.</p> + </note> + </description> + <funcs> + <func> + <name>bt(Pid) -> void()</name> + <fsummary>Stack backtrace for a process</fsummary> + <type> + <v>Pid = pid()</v> + </type> + <desc> + <p>Stack backtrace for a process. Equivalent to + <c>erlang:process_display(Pid, backtrace)</c>.</p> + </desc> + </func> + <func> + <name>c(File) -> {ok, Module} | error</name> + <name>c(File, Options) -> {ok, Module} | error</name> + <fsummary>Compile and load code in a file</fsummary> + <type> + <v>File = name() -- see filename(3)</v> + <v>Options = [Opt] -- see compile:file/2</v> + </type> + <desc> + <p><c>c/1,2</c> compiles and then purges and loads the code for + a file. <c>Options</c> defaults to []. Compilation is + equivalent to:</p> + <code type="none"> +compile:file(File, Options ++ [report_errors, report_warnings])</code> + <p>Note that purging the code means that any processes + lingering in old code for the module are killed without + warning. See <c>code/3</c> for more information.</p> + </desc> + </func> + <func> + <name>cd(Dir) -> void()</name> + <fsummary>Change working directory</fsummary> + <type> + <v>Dir = name() -- see filename(3)</v> + </type> + <desc> + <p>Changes working directory to <c>Dir</c>, which may be a + relative name, and then prints the name of the new working + directory.</p> + <pre> +2> <input>cd("../erlang").</input> +/home/ron/erlang</pre> + </desc> + </func> + <func> + <name>flush() -> void()</name> + <fsummary>Flush any messages sent to the shell</fsummary> + <desc> + <p>Flushes any messages sent to the shell.</p> + </desc> + </func> + <func> + <name>help() -> void()</name> + <fsummary>Help information</fsummary> + <desc> + <p>Displays help information: all valid shell internal commands, + and commands in this module.</p> + </desc> + </func> + <func> + <name>i() -> void()</name> + <name>ni() -> void()</name> + <fsummary>Information about the system</fsummary> + <desc> + <p><c>i/0</c> displays information about the system, listing + information about all processes. <c>ni/0</c> does the same, + but for all nodes the network.</p> + </desc> + </func> + <func> + <name>i(X, Y, Z) -> void()</name> + <fsummary>Information about pid <X.Y.Z></fsummary> + <type> + <v>X = Y = Z = int()</v> + </type> + <desc> + <p>Displays information about a process, Equivalent to + <c>process_info(pid(X, Y, Z))</c>, but location transparent.</p> + </desc> + </func> + <func> + <name>l(Module) -> void()</name> + <fsummary>Load or reload module</fsummary> + <type> + <v>Module = atom()</v> + </type> + <desc> + <p>Purges and loads, or reloads, a module by calling + <c>code:purge(Module)</c> followed by + <c>code:load_file(Module)</c>.</p> + <p>Note that purging the code means that any processes + lingering in old code for the module are killed without + warning. See <c>code/3</c> for more information.</p> + </desc> + </func> + <func> + <name>lc(Files) -> ok</name> + <fsummary>Compile a list of files</fsummary> + <type> + <v>Files = [File]</v> + <v> File = name() -- see filename(3)</v> + </type> + <desc> + <p>Compiles a list of files by calling <c>compile:file(File, [report_errors, report_warnings])</c> for each <c>File</c> + in <c>Files</c>.</p> + </desc> + </func> + <func> + <name>ls() -> void()</name> + <fsummary>List files in the current directory</fsummary> + <desc> + <p>Lists files in the current directory.</p> + </desc> + </func> + <func> + <name>ls(Dir) -> void()</name> + <fsummary>List files in a directory</fsummary> + <type> + <v>Dir = name() -- see filename(3)</v> + </type> + <desc> + <p>Lists files in directory <c>Dir</c>.</p> + </desc> + </func> + <func> + <name>m() -> void()</name> + <fsummary>Which modules are loaded</fsummary> + <desc> + <p>Displays information about the loaded modules, including + the files from which they have been loaded.</p> + </desc> + </func> + <func> + <name>m(Module) -> void()</name> + <fsummary>Information about a module</fsummary> + <type> + <v>Module = atom()</v> + </type> + <desc> + <p>Displays information about <c>Module</c>.</p> + </desc> + </func> + <func> + <name>memory() -> [{Type, Size}]</name> + <fsummary>Memory allocation information</fsummary> + <type> + <v>Type, Size -- see erlang:memory/0</v> + </type> + <desc> + <p>Memory allocation information. Equivalent to + <c>erlang:memory/0</c>.</p> + </desc> + </func> + <func> + <name>memory(Type) -> Size</name> + <name>memory([Type]) -> [{Type, Size}]</name> + <fsummary>Memory allocation information</fsummary> + <type> + <v>Type, Size -- see erlang:memory/0</v> + </type> + <desc> + <p>Memory allocation information. Equivalent to + <c>erlang:memory/1</c>.</p> + </desc> + </func> + <func> + <name>nc(File) -> {ok, Module} | error</name> + <name>nc(File, Options) -> {ok, Module} | error</name> + <fsummary>Compile and load code in a file on all nodes</fsummary> + <type> + <v>File = name() -- see filename(3)</v> + <v>Options = [Opt] -- see compile:file/2</v> + </type> + <desc> + <p>Compiles and then loads the code for a file on all nodes. + <c>Options</c> defaults to []. Compilation is equivalent to:</p> + <code type="none"> +compile:file(File, Opts ++ [report_errors, report_warnings])</code> + </desc> + </func> + <func> + <name>nl(Module) -> void()</name> + <fsummary>Load module on all nodes</fsummary> + <type> + <v>Module = atom()</v> + </type> + <desc> + <p>Loads <c>Module</c> on all nodes.</p> + </desc> + </func> + <func> + <name>pid(X, Y, Z) -> pid()</name> + <fsummary>Convert X,Y,Z to a pid</fsummary> + <type> + <v>X = Y = Z = int()</v> + </type> + <desc> + <p>Converts <c>X</c>, <c>Y</c>, <c>Z</c> to the pid + <c><![CDATA[<X.Y.Z>]]></c>. This function should only be used when + debugging.</p> + </desc> + </func> + <func> + <name>pwd() -> void()</name> + <fsummary>Print working directory</fsummary> + <desc> + <p>Prints the name of the working directory.</p> + </desc> + </func> + <func> + <name>q() -> void()</name> + <fsummary>Quit - shorthand for <c>init:stop()</c></fsummary> + <desc> + <p>This function is shorthand for <c>init:stop()</c>, that is, + it causes the node to stop in a controlled fashion.</p> + </desc> + </func> + <func> + <name>regs() -> void()</name> + <name>nregs() -> void()</name> + <fsummary>Information about registered processes</fsummary> + <desc> + <p><c>regs/0</c> displays information about all registered + processes. <c>nregs/0</c> does the same, but for all nodes + in the network.</p> + </desc> + </func> + <func> + <name>xm(ModSpec) -> void()</name> + <fsummary>Cross reference check a module</fsummary> + <type> + <v>ModSpec = Module | Filename</v> + <v> Module = atom()</v> + <v> Filename = string()</v> + </type> + <desc> + <p>This function finds undefined functions, unused functions, + and calls to deprecated functions in a module by calling + <c>xref:m/1</c>.</p> + </desc> + </func> + <func> + <name>y(File) -> YeccRet</name> + <fsummary>Generate an LALR-1 parser</fsummary> + <type> + <v>File = name() -- see filename(3)</v> + <v>YeccRet = -- see yecc:file/2</v> + </type> + <desc> + <p>Generates an LALR-1 parser. Equivalent to:</p> + <code type="none"> +yecc:file(File)</code> + </desc> + </func> + <func> + <name>y(File, Options) -> YeccRet</name> + <fsummary>Generate an LALR-1 parser</fsummary> + <type> + <v>File = name() -- see filename(3)</v> + <v>Options, YeccRet = -- see yecc:file/2</v> + </type> + <desc> + <p>Generates an LALR-1 parser. Equivalent to:</p> + <code type="none"> +yecc:file(File, Options)</code> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p><seealso marker="compiler:compile">compile(3)</seealso>, + <seealso marker="filename">filename(3)</seealso>, + <seealso marker="erts:erlang">erlang(3)</seealso>, + <seealso marker="parsetools:yecc">yecc(3)</seealso>, + <seealso marker="tools:xref">xref(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/calendar.xml b/lib/stdlib/doc/src/calendar.xml new file mode 100644 index 0000000000..36f0c03162 --- /dev/null +++ b/lib/stdlib/doc/src/calendar.xml @@ -0,0 +1,377 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>calendar</title> + <prepared>Peter Högfeldt</prepared> + <docno></docno> + <date>1996-11-05</date> + <rev>B</rev> + </header> + <module>calendar</module> + <modulesummary>Local and universal time, day-of-the-week, date and time conversions</modulesummary> + <description> + <p>This module provides computation of local and universal time, + day-of-the-week, and several time conversion functions.</p> + <p>Time is local when it is adjusted in accordance with the current + time zone and daylight saving. Time is universal when it reflects + the time at longitude zero, without any adjustment for daylight + saving. Universal Coordinated Time (UTC) time is also called + Greenwich Mean Time (GMT).</p> + <p>The time functions <c>local_time/0</c> and + <c>universal_time/0</c> provided in this module both return date + and time. The reason for this is that separate functions for date + and time may result in a date/time combination which is displaced + by 24 hours. This happens if one of the functions is called + before midnight, and the other after midnight. This problem also + applies to the Erlang BIFs <c>date/0</c> and <c>time/0</c>, and + their use is strongly discouraged if a reliable date/time stamp + is required.</p> + <p>All dates conform to the Gregorian calendar. This calendar was + introduced by Pope Gregory XIII in 1582 and was used in all + Catholic countries from this year. Protestant parts of Germany + and the Netherlands adopted it in 1698, England followed in 1752, + and Russia in 1918 (the October revolution of 1917 took place in + November according to the Gregorian calendar).</p> + <p>The Gregorian calendar in this module is extended back to year 0. + For a given date, the <em>gregorian days</em> is the number of + days up to and including the date specified. Similarly, + the <em>gregorian seconds</em> for a given date and time, is + the the number of seconds up to and including the specified date + and time.</p> + <p>For computing differences between epochs in time, use + the functions counting gregorian days or seconds. If epochs are + given as local time, they must be converted to universal time, in + order to get the correct value of the elapsed time between epochs. + Use of the function <c>time_difference/2</c> is discouraged.</p> + </description> + + <section> + <title>DATA TYPES</title> + <code type="none"> +date() = {Year, Month, Day} + Year = int() + Month = 1..12 + Day = 1..31 +Year cannot be abbreviated. Example: 93 denotes year 93, not 1993. +Valid range depends on the underlying OS. +The date tuple must denote a valid date. + +time() = {Hour, Minute, Second} + Hour = 0..23 + Minute = Second = 0..59</code> + </section> + <funcs> + <func> + <name>date_to_gregorian_days(Date) -> Days</name> + <name>date_to_gregorian_days(Year, Month, Day) -> Days</name> + <fsummary>Compute the number of days from year 0 up to the given date</fsummary> + <type> + <v>Date = date()</v> + <v>Days = int()</v> + </type> + <desc> + <p>This function computes the number of gregorian days starting + with year 0 and ending at the given date.</p> + </desc> + </func> + <func> + <name>datetime_to_gregorian_seconds({Date, Time}) -> Seconds</name> + <fsummary>Compute the number of seconds from year 0 up to the given date and time</fsummary> + <type> + <v>Date = date()</v> + <v>Time = time()</v> + <v>Seconds = int()</v> + </type> + <desc> + <p>This function computes the number of gregorian seconds + starting with year 0 and ending at the given date and time.</p> + </desc> + </func> + <func> + <name>day_of_the_week(Date) -> DayNumber</name> + <name>day_of_the_week(Year, Month, Day) -> DayNumber</name> + <fsummary>Compute the day of the week</fsummary> + <type> + <v>Date = date()</v> + <v>DayNumber = 1..7</v> + </type> + <desc> + <p>This function computes the day of the week given <c>Year</c>, + <c>Month</c> and <c>Day</c>. The return value denotes the day + of the week as <c>1</c>: Monday, <c>2</c>: Tuesday, and so on.</p> + </desc> + </func> + <func> + <name>gregorian_days_to_date(Days) -> Date</name> + <fsummary>Compute the date given the number of gregorian days</fsummary> + <type> + <v>Days = int()</v> + <v>Date = date()</v> + </type> + <desc> + <p>This function computes the date given the number of + gregorian days.</p> + </desc> + </func> + <func> + <name>gregorian_seconds_to_datetime(Seconds) -> {Date, Time}</name> + <fsummary>Compute the date given the number of gregorian days</fsummary> + <type> + <v>Seconds = int()</v> + <v>Date = date()</v> + <v>Time = time()</v> + </type> + <desc> + <p>This function computes the date and time from the given + number of gregorian seconds.</p> + </desc> + </func> + <func> + <name>is_leap_year(Year) -> bool()</name> + <fsummary>Check if a year is a leap year</fsummary> + <desc> + <p>This function checks if a year is a leap year.</p> + </desc> + </func> + <func> + <name>last_day_of_the_month(Year, Month) -> int()</name> + <fsummary>Compute the number of days in a month</fsummary> + <desc> + <p>This function computes the number of days in a month.</p> + </desc> + </func> + <func> + <name>local_time() -> {Date, Time}</name> + <fsummary>Compute local time</fsummary> + <type> + <v>Date = date()</v> + <v>Time = time()</v> + </type> + <desc> + <p>This function returns the local time reported by + the underlying operating system.</p> + </desc> + </func> + <func> + <name>local_time_to_universal_time({Date1, Time1}) -> {Date2, Time2}</name> + <fsummary>Convert from local time to universal time (deprecated)</fsummary> + <desc> + <p>This function converts from local time to Universal + Coordinated Time (UTC). <c>Date1</c> must refer to a local + date after Jan 1, 1970.</p> + <warning> + <p>This function is deprecated. Use + <c>local_time_to_universal_time_dst/1</c> instead, as it + gives a more correct and complete result. Especially for + the period that does not exist since it gets skipped during + the switch <em>to</em> daylight saving time, this function + still returns a result.</p> + </warning> + </desc> + </func> + <func> + <name>local_time_to_universal_time_dst({Date1, Time1}) -> [{Date, Time}]</name> + <fsummary>Convert from local time to universal time(s)</fsummary> + <type> + <v>Date1 = Date = date()</v> + <v>Time1 = Time = time()</v> + </type> + <desc> + <p>This function converts from local time to Universal + Coordinated Time (UTC). <c>Date1</c> must refer to a local + date after Jan 1, 1970.</p> + <p>The return value is a list of 0, 1 or 2 possible UTC times:</p> + <taglist> + <tag><c>[]</c></tag> + <item> + <p>For a local <c>{Date1, Time1}</c> during the period that + is skipped when switching <em>to</em> daylight saving + time, there is no corresponding UTC since the local time + is illegal - it has never happened.</p> + </item> + <tag><c>[DstDateTimeUTC, DateTimeUTC]</c></tag> + <item> + <p>For a local <c>{Date1, Time1}</c> during the period that + is repeated when switching <em>from</em> daylight saving + time, there are two corresponding UTCs. One for the first + instance of the period when daylight saving time is still + active, and one for the second instance.</p> + </item> + <tag><c>[DateTimeUTC]</c></tag> + <item> + <p>For all other local times there is only one + corresponding UTC.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>now_to_local_time(Now) -> {Date, Time}</name> + <fsummary>Convert now to local date and time</fsummary> + <type> + <v>Now -- see erlang:now/0</v> + <v>Date = date()</v> + <v>Time = time()</v> + </type> + <desc> + <p>This function returns local date and time converted from + the return value from <c>erlang:now()</c>.</p> + </desc> + </func> + <func> + <name>now_to_universal_time(Now) -> {Date, Time}</name> + <name>now_to_datetime(Now) -> {Date, Time}</name> + <fsummary>Convert now to date and time</fsummary> + <type> + <v>Now -- see erlang:now/0</v> + <v>Date = date()</v> + <v>Time = time()</v> + </type> + <desc> + <p>This function returns Universal Coordinated Time (UTC) + converted from the return value from <c>erlang:now()</c>.</p> + </desc> + </func> + <func> + <name>seconds_to_daystime(Seconds) -> {Days, Time}</name> + <fsummary>Compute days and time from seconds</fsummary> + <type> + <v>Seconds = Days = int()</v> + <v>Time = time()</v> + </type> + <desc> + <p>This function transforms a given number of seconds into days, + hours, minutes, and seconds. The <c>Time</c> part is always + non-negative, but <c>Days</c> is negative if the argument + <c>Seconds</c> is.</p> + </desc> + </func> + <func> + <name>seconds_to_time(Seconds) -> Time</name> + <fsummary>Compute time from seconds</fsummary> + <type> + <v>Seconds = int() < 86400</v> + <v>Time = time()</v> + </type> + <desc> + <p>This function computes the time from the given number of + seconds. <c>Seconds</c> must be less than the number of + seconds per day (86400).</p> + </desc> + </func> + <func> + <name>time_difference(T1, T2) -> {Days, Time}</name> + <fsummary>Compute the difference between two times (deprecated)</fsummary> + <desc> + <p>This function returns the difference between two <c>{Date, Time}</c> tuples. <c>T2</c> should refer to an epoch later + than <c>T1</c>.</p> + <warning> + <p>This function is obsolete. Use the conversion functions for + gregorian days and seconds instead.</p> + </warning> + </desc> + </func> + <func> + <name>time_to_seconds(Time) -> Seconds</name> + <fsummary>Compute the number of seconds since midnight up to the given time</fsummary> + <type> + <v>Time = time()</v> + <v>Seconds = int()</v> + </type> + <desc> + <p>This function computes the number of seconds since midnight + up to the specified time.</p> + </desc> + </func> + <func> + <name>universal_time() -> {Date, Time}</name> + <fsummary>Compute universal time</fsummary> + <type> + <v>Date = date()</v> + <v>Time = time()</v> + </type> + <desc> + <p>This function returns the Universal Coordinated Time (UTC) + reported by the underlying operating system. Local time is + returned if universal time is not available.</p> + </desc> + </func> + <func> + <name>universal_time_to_local_time({Date1, Time1}) -> {Date2, Time2}</name> + <fsummary>Convert from universal time to local time</fsummary> + <type> + <v>Date1 = Date2 = date()</v> + <v>Time1 = Time2 = time()</v> + </type> + <desc> + <p>This function converts from Universal Coordinated Time (UTC) + to local time. <c>Date1</c> must refer to a date after Jan 1, + 1970.</p> + </desc> + </func> + <func> + <name>valid_date(Date) -> bool()</name> + <name>valid_date(Year, Month, Day) -> bool()</name> + <fsummary>Check if a date is valid</fsummary> + <type> + <v>Date = date()</v> + </type> + <desc> + <p>This function checks if a date is a valid.</p> + </desc> + </func> + </funcs> + + <section> + <title>Leap Years</title> + <p>The notion that every fourth year is a leap year is not + completely true. By the Gregorian rule, a year Y is a leap year if + either of the following rules is valid:</p> + <list type="bulleted"> + <item> + <p>Y is divisible by 4, but not by 100; or</p> + </item> + <item> + <p>Y is divisible by 400.</p> + </item> + </list> + <p>Accordingly, 1996 is a leap year, 1900 is not, but 2000 is.</p> + </section> + + <section> + <title>Date and Time Source</title> + <p>Local time is obtained from the Erlang BIF <c>localtime/0</c>. + Universal time is computed from the BIF <c>universaltime/0</c>.</p> + <p>The following facts apply:</p> + <list type="bulleted"> + <item>there are 86400 seconds in a day</item> + <item>there are 365 days in an ordinary year</item> + <item>there are 366 days in a leap year</item> + <item>there are 1461 days in a 4 year period</item> + <item>there are 36524 days in a 100 year period</item> + <item>there are 146097 days in a 400 year period</item> + <item>there are 719528 days between Jan 1, 0 and Jan 1, 1970.</item> + </list> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/dets.xml b/lib/stdlib/doc/src/dets.xml new file mode 100644 index 0000000000..8d1398d3b7 --- /dev/null +++ b/lib/stdlib/doc/src/dets.xml @@ -0,0 +1,1255 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>dets</title> + <prepared>Claes Wikström</prepared> + <responsible>Claes Wikström</responsible> + <docno></docno> + <approved>nobody</approved> + <checked>no</checked> + <date>2001-06-06</date> + <rev>B</rev> + <file>dets.sgml</file> + </header> + <module>dets</module> + <modulesummary>A Disk Based Term Storage</modulesummary> + <description> + <p>The module <c>dets</c> provides a term storage on file. The + stored terms, in this module called <em>objects</em>, are tuples + such that one element is defined to be the key. A Dets + <em>table</em> is a collection of objects with the key at the same + position stored on a file.</p> + <p>Dets is used by the Mnesia application, and is provided as is + for users who are interested in an efficient storage of Erlang + terms on disk only. Many applications just need to store some + terms in a file. Mnesia adds transactions, queries, and + distribution. The size of Dets files cannot exceed 2 GB. If larger + tables are needed, Mnesia's table fragmentation can be used.</p> + <p>There are three types of Dets tables: set, bag and + duplicate_bag. A table of type <em>set</em> has at most one object + with a given key. If an object with a key already present in the + table is inserted, the existing object is overwritten by the new + object. A table of type <em>bag</em> has zero or more different + objects with a given key. A table of type <em>duplicate_bag</em> + has zero or more possibly matching objects with a given key.</p> + <p>Dets tables must be opened before they can be updated or read, + and when finished they must be properly closed. If a table has not + been properly closed, Dets will automatically repair the table. + This can take a substantial time if the table is large. A Dets + table is closed when the process which opened the table + terminates. If several Erlang processes (users) open the same Dets + table, they will share the table. The table is properly closed + when all users have either terminated or closed the table. Dets + tables are not properly closed if the Erlang runtime system is + terminated abnormally.</p> + <note> + <p>A ^C command abnormally terminates an Erlang runtime + system in a Unix environment with a break-handler.</p> + </note> + <p>Since all operations performed by Dets are disk operations, it + is important to realize that a single look-up operation involves a + series of disk seek and read operations. For this reason, the Dets + functions are much slower than the corresponding Ets functions, + although Dets exports a similar interface.</p> + <p>Dets organizes data as a linear hash list and the hash list + grows gracefully as more data is inserted into the table. Space + management on the file is performed by what is called a buddy + system. The current implementation keeps the entire buddy system + in RAM, which implies that if the table gets heavily fragmented, + quite some memory can be used up. The only way to defragment a + table is to close it and then open it again with the <c>repair</c> + option set to <c>force</c>.</p> + <p>It is worth noting that the ordered_set type present in Ets is + not yet implemented by Dets, neither is the limited support for + concurrent updates which makes a sequence of <c>first</c> and + <c>next</c> calls safe to use on fixed Ets tables. Both these + features will be implemented by Dets in a future release of + Erlang/OTP. Until then, the Mnesia application (or some user + implemented method for locking) has to be used to implement safe + concurrency. Currently, no library of Erlang/OTP has support for + ordered disk based term storage.</p> + <p>Two versions of the format used for storing objects on file are + supported by Dets. The first version, 8, is the format always used + for tables created by OTP R7 and earlier. The second version, 9, + is the default version of tables created by OTP R8 (and later OTP + releases). OTP R8 can create version 8 tables, and convert version + 8 tables to version 9, and vice versa, upon request. + </p> + <p>All Dets functions return <c>{error, Reason}</c> if an error + occurs (<c>first/1</c> and <c>next/2</c> are exceptions, they exit + the process with the error tuple). If given badly formed + arguments, all functions exit the process with a <c>badarg</c> + message.</p> + <p><em>Types</em></p> + <pre> +access() = read | read_write +auto_save() = infinity | int() +bindings_cont() = tuple() +bool() = true | false +file() = string() +int() = integer() >= 0 +keypos() = integer() >= 1 +name() = atom() | ref() +no_slots() = integer() >= 0 | default +object() = tuple() +object_cont() = tuple() +select_cont() = tuple() +type() = bag | duplicate_bag | set +version() = 8 | 9 | default </pre> + </description> + <funcs> + <func> + <name>all() -> [Name]</name> + <fsummary>Return a list of the names of all open Dets tables on this node.</fsummary> + <type> + <v>Name = name()</v> + </type> + <desc> + <p>Returns a list of the names of all open tables on this + node.</p> + </desc> + </func> + <func> + <name>bchunk(Name, Continuation) -> {Continuation2, Data} | '$end_of_table' | {error, Reason}</name> + <fsummary>Return a chunk of objects stored in a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>Continuation = start | cont()</v> + <v>Continuation2 = cont()</v> + <v>Data = binary() | tuple()</v> + </type> + <desc> + <p>Returns a list of objects stored in a table. The exact + representation of the returned objects is not public. The + lists of data can be used for initializing a table by giving + the value <c>bchunk</c> to the <c>format</c> option of the + <c>init_table/3</c> function. The Mnesia application uses this + function for copying open tables.</p> + <p>Unless the table is protected using <c>safe_fixtable/2</c>, + calls to <c>bchunk/2</c> may not work as expected if + concurrent updates are made to the table.</p> + <p>The first time <c>bchunk/2</c> is called, an initial + continuation, the atom <c>start</c>, must be provided.</p> + <p>The <c>bchunk/2</c> function returns a tuple + <c>{Continuation2, Data}</c>, where <c>Data</c> is a list of + objects. <c>Continuation2</c> is another continuation which is + to be passed on to a subsequent call to <c>bchunk/2</c>. With + a series of calls to <c>bchunk/2</c> it is possible to extract + all objects of the table. + </p> + <p><c>bchunk/2</c> returns <c>'$end_of_table'</c> when all + objects have been returned, or <c>{error, Reason}</c> if an + error occurs. + </p> + </desc> + </func> + <func> + <name>close(Name) -> ok | {error, Reason} </name> + <fsummary>Close a Dets table.</fsummary> + <type> + <v>Name = name()</v> + </type> + <desc> + <p>Closes a table. Only processes that have opened a table are + allowed to close it. + </p> + <p>All open tables must be closed before the system is + stopped. If an attempt is made to open a table which has not + been properly closed, Dets automatically tries to repair the + table.</p> + </desc> + </func> + <func> + <name>delete(Name, Key) -> ok | {error, Reason}</name> + <fsummary>Delete all objects with a given key from a Dets table.</fsummary> + <type> + <v>Name = name()</v> + </type> + <desc> + <p>Deletes all objects with the key <c>Key</c> from the table + <c>Name</c>.</p> + </desc> + </func> + <func> + <name>delete_all_objects(Name) -> ok | {error, Reason}</name> + <fsummary>Delete all objects from a Dets table.</fsummary> + <type> + <v>Name = name()</v> + </type> + <desc> + <p>Deletes all objects from a table in almost constant time. + However, if the table if fixed, <c>delete_all_objects(T)</c> + is equivalent to <c>match_delete(T, '_')</c>.</p> + </desc> + </func> + <func> + <name>delete_object(Name, Object) -> ok | {error, Reason}</name> + <fsummary>Delete a given object from a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>Object = object()</v> + </type> + <desc> + <p>Deletes all instances of a given object from a table. If a + table is of type <c>bag</c> or <c>duplicate_bag</c>, the + <c>delete/2</c> function cannot be used to delete only some of + the objects with a given key. This function makes this + possible.</p> + </desc> + </func> + <func> + <name>first(Name) -> Key | '$end_of_table'</name> + <fsummary>Return the first key stored in a Dets table.</fsummary> + <type> + <v>Key = term()</v> + <v>Name = name()</v> + </type> + <desc> + <p>Returns the first key stored in the table <c>Name</c> + according to the table's internal order, or + <c>'$end_of_table'</c> if the table is empty.</p> + <p>Unless the table is protected using <c>safe_fixtable/2</c>, + subsequent calls to <c>next/2</c> may not work as expected if + concurrent updates are made to the table.</p> + <p>Should an error occur, the process is exited with an error + tuple <c>{error, Reason}</c>. The reason for not returning the + error tuple is that it cannot be distinguished from a key.</p> + <p>There are two reasons why <c>first/1</c> and <c>next/2</c> + should not be used: they are not very efficient, and they + prevent the use of the key <c>'$end_of_table'</c> since this + atom is used to indicate the end of the table. If possible, + the <c>match</c>, <c>match_object</c>, and <c>select</c> + functions should be used for traversing tables.</p> + </desc> + </func> + <func> + <name>foldl(Function, Acc0, Name) -> Acc1 | {error, Reason}</name> + <fsummary>Fold a function over a Dets table.</fsummary> + <type> + <v>Function = fun(Object, AccIn) -> AccOut</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v>Name = name()</v> + <v>Object = object()</v> + </type> + <desc> + <p>Calls <c>Function</c> on successive elements of the table + <c>Name</c> together with an extra argument <c>AccIn</c>. The + order in which the elements of the table are traversed is + unspecified. <c>Function</c> must return a new accumulator + which is passed to the next call. <c>Acc0</c> is returned if + the table is empty.</p> + </desc> + </func> + <func> + <name>foldr(Function, Acc0, Name) -> Acc1 | {error, Reason}</name> + <fsummary>Fold a function over a Dets table.</fsummary> + <type> + <v>Function = fun(Object, AccIn) -> AccOut</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v>Name = name()</v> + <v>Object = object()</v> + </type> + <desc> + <p>Calls <c>Function</c> on successive elements of the table + <c>Name</c> together with an extra argument <c>AccIn</c>. The + order in which the elements of the table are traversed is + unspecified. <c>Function</c> must return a new accumulator + which is passed to the next call. <c>Acc0</c> is returned if + the table is empty.</p> + </desc> + </func> + <func> + <name>from_ets(Name, EtsTab) -> ok | {error, Reason}</name> + <fsummary>Replace the objects of a Dets table with the objects of an Ets table.</fsummary> + <type> + <v>Name = name()</v> + <v>EtsTab = - see ets(3) -</v> + </type> + <desc> + <p>Deletes all objects of the table <c>Name</c> and then + inserts all the objects of the Ets table <c>EtsTab</c>. The + order in which the objects are inserted is not specified. + Since <c>ets:safe_fixtable/2</c> is called the Ets table must + be public or owned by the calling process.</p> + </desc> + </func> + <func> + <name>info(Name) -> InfoList | undefined</name> + <fsummary>Return information about a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>InfoList = [{Item, Value}]</v> + </type> + <desc> + <p>Returns information about the table <c>Name</c> as a list of + <c>{Item, Value}</c> tuples:</p> + <list type="bulleted"> + <item> + <p><c>{file_size, int()}</c>, the size of the file in + bytes.</p> + </item> + <item> + <p><c>{filename, file()}</c>, the name of the file + where objects are stored.</p> + </item> + <item> + <p><c>{keypos, keypos()}</c>, the position of the + key.</p> + </item> + <item> + <p><c>{size, int()}</c>, the number of objects stored + in the table.</p> + </item> + <item> + <p><c>{type, type()}</c>, the type of the table.</p> + </item> + </list> + </desc> + </func> + <func> + <name>info(Name, Item) -> Value | undefined</name> + <fsummary>Return the information associated with a given item for a Dets table.</fsummary> + <type> + <v>Name = name()</v> + </type> + <desc> + <p>Returns the information associated with <c>Item</c> for the + table <c>Name</c>. In addition to the <c>{Item, Value}</c> + pairs defined for <c>info/1</c>, the following items are + allowed:</p> + <list type="bulleted"> + <item> + <p><c>{access, access()}</c>, the access mode.</p> + </item> + <item> + <p><c>{auto_save, auto_save()}</c>, the auto save + interval.</p> + </item> + <item> + <p><c>{bchunk_format, binary()}</c>, an opaque binary + describing the format of the objects returned by + <c>bchunk/2</c>. The binary can be used as argument to + <c>is_compatible_chunk_format/2</c>. Only available for + version 9 tables.</p> + </item> + <item> + <p><c>{hash,</c> Hash<c>}</c>. Describes which BIF is + used to calculate the hash values of the objects stored in + the Dets table. Possible values of Hash are <c>hash</c>, + which implies that the <c>erlang:hash/2</c> BIF is used, + <c>phash</c>, which implies that the <c>erlang:phash/2</c> + BIF is used, and <c>phash2</c>, which implies that the + <c>erlang:phash2/1</c> BIF is used.</p> + </item> + <item> + <p><c>{memory, int()}</c>, the size of the file in + bytes. The same value is associated with the item + <c>file_size</c>.</p> + </item> + <item> + <p><c>{no_keys, int()}</c>, the number of different + keys stored in the table. Only available for version 9 + tables.</p> + </item> + <item> + <p><c>{no_objects, int()}</c>, the number of objects + stored in the table.</p> + </item> + <item> + <p><c>{no_slots, {Min, Used, Max}}</c>, the number of + slots of the table. <c>Min</c> is the minimum number of + slots, <c>Used</c> is the number of currently used slots, + and <c>Max</c> is the maximum number of slots. Only + available for version 9 tables.</p> + </item> + <item> + <p><c>{owner, pid()}</c>, the pid of the process that + handles requests to the Dets table.</p> + </item> + <item> + <p><c>{ram_file, bool()}</c>, whether the table is + kept in RAM.</p> + </item> + <item> + <p><c>{safe_fixed,</c> SafeFixed<c>}</c>. If the table + is fixed, SafeFixed is a tuple <c>{FixedAtTime, [{Pid,RefCount}]}</c>. <c>FixedAtTime</c> is the time when + the table was first fixed, and <c>Pid</c> is the pid of + the process that fixes the table <c>RefCount</c> times. + There may be any number of processes in the list. If the + table is not fixed, SafeFixed is the atom <c>false</c>.</p> + </item> + <item> + <p><c>{version, int()}</c>, the version of the format + of the table.</p> + </item> + </list> + </desc> + </func> + <func> + <name>init_table(Name, InitFun [, Options]) -> ok | {error, Reason}</name> + <fsummary>Replace all objects of a Dets table.</fsummary> + <type> + <v>Name = atom()</v> + <v>InitFun = fun(Arg) -> Res</v> + <v>Arg = read | close</v> + <v>Res = end_of_input | {[object()], InitFun} | {Data, InitFun} | term()</v> + <v>Data = binary() | tuple()</v> + </type> + <desc> + <p>Replaces the existing objects of the table <c>Name</c> with + objects created by calling the input function <c>InitFun</c>, + see below. The reason for using this function rather than + calling <c>insert/2</c> is that of efficiency. It should be + noted that the input functions are called by the process that + handles requests to the Dets table, not by the calling + process.</p> + <p>When called with the argument <c>read</c> the function + <c>InitFun</c> is assumed to return <c>end_of_input</c> when + there is no more input, or <c>{Objects, Fun}</c>, where + <c>Objects</c> is a list of objects and <c>Fun</c> is a new + input function. Any other value Value is returned as an error + <c>{error, {init_fun, Value}}</c>. Each input function will be + called exactly once, and should an error occur, the last + function is called with the argument <c>close</c>, the reply + of which is ignored.</p> + <p>If the type of the table is <c>set</c> and there is more + than one object with a given key, one of the objects is + chosen. This is not necessarily the last object with the given + key in the sequence of objects returned by the input + functions. Duplicate keys should be avoided, or the file + will be unnecessarily fragmented. This holds also for duplicated + objects stored in tables of type <c>bag</c>.</p> + <p>It is important that the table has a sufficient number of + slots for the objects. If not, the hash list will start to + grow when <c>init_table/2</c> returns which will significantly + slow down access to the table for a period of time. The + minimum number of slots is set by the <c>open_file/2</c> + option <c>min_no_slots</c> and returned by the <c>info/2</c> + item <c>no_slots</c>. See also the <c>min_no_slots</c> option + below. + </p> + <p>The <c>Options</c> argument is a list of <c>{Key, Val}</c> + tuples where the following values are allowed:</p> + <list type="bulleted"> + <item> + <p><c>{min_no_slots, no_slots()}</c>. Specifies the + estimated number of different keys that will be stored + in the table. The <c>open_file</c> option with the same + name is ignored unless the table is created, and in that + case performance can be enhanced by supplying an + estimate when initializing the table.</p> + </item> + <item> + <p><c>{format, Format}</c>. Specifies the format of the + objects returned by the function <c>InitFun</c>. If + <c>Format</c> is <c>term</c> (the default), + <c>InitFun</c> is assumed to return a list of tuples. If + <c>Format</c> is <c>bchunk</c>, <c>InitFun</c> is + assumed to return <c>Data</c> as returned by + <c>bchunk/2</c>. This option overrides the + <c>min_no_slots</c> option.</p> + </item> + </list> + </desc> + </func> + <func> + <name>insert(Name, Objects) -> ok | {error, Reason}</name> + <fsummary>Insert one or more objects into a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>Objects = object() | [object()]</v> + </type> + <desc> + <p>Inserts one or more objects into the table <c>Name</c>. If + there already exists an object with a key matching the key of + some of the given objects and the table type is <c>set</c>, + the old object will be replaced.</p> + </desc> + </func> + <func> + <name>insert_new(Name, Objects) -> Bool</name> + <fsummary>Insert one or more objects into a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>Objects = object() | [object()]</v> + <v>Bool = bool()</v> + </type> + <desc> + <p>Inserts one or more objects into the table <c>Name</c>. If + there already exists some object with a key matching the key + of any of the given objects the table is not updated and + <c>false</c> is returned, otherwise the objects are inserted + and <c>true</c> returned.</p> + </desc> + </func> + <func> + <name>is_compatible_bchunk_format(Name, BchunkFormat) -> Bool</name> + <fsummary>Test compatibility of a table's chunk data.</fsummary> + <type> + <v>Name = name()</v> + <v>BchunkFormat = binary()</v> + <v>Bool = bool()</v> + </type> + <desc> + <p>Returns <c>true</c> if it would be possible to initialize + the table <c>Name</c>, using <c>init_table/3</c> with the + option <c>{format, bchunk}</c>, with objects read with + <c>bchunk/2</c> from some table <c>T</c> such that calling + <c>info(T, bchunk_format)</c> returns + <c>BchunkFormat</c>.</p> + </desc> + </func> + <func> + <name>is_dets_file(FileName) -> Bool | {error, Reason}</name> + <fsummary>Test for a Dets table.</fsummary> + <type> + <v>FileName = file()</v> + <v>Bool = bool()</v> + </type> + <desc> + <p>Returns <c>true</c> if the file <c>FileName</c> is a Dets + table, <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>lookup(Name, Key) -> [Object] | {error, Reason}</name> + <fsummary>Return all objects with a given key stored in a Dets table.</fsummary> + <type> + <v>Key = term()</v> + <v>Name = name()</v> + <v>Object = object()</v> + </type> + <desc> + <p>Returns a list of all objects with the key <c>Key</c> + stored in the table <c>Name</c>. For example:</p> + <pre> +2> <input>dets:open_file(abc, [{type, bag}]).</input> +{ok,abc} +3> <input>dets:insert(abc, {1,2,3}).</input> +ok +4> <input>dets:insert(abc, {1,3,4}).</input> +ok +5> <input>dets:lookup(abc, 1).</input> +[{1,2,3},{1,3,4}] </pre> + <p>If the table is of type <c>set</c>, the function returns + either the empty list or a list with one object, as there + cannot be more than one object with a given key. If the table + is of type <c>bag</c> or <c>duplicate_bag</c>, the function + returns a list of arbitrary length.</p> + <p>Note that the order of objects returned is unspecified. In + particular, the order in which objects were inserted is not + reflected.</p> + </desc> + </func> + <func> + <name>match(Continuation) -> {[Match], Continuation2} | '$end_of_table' | {error, Reason}</name> + <fsummary>Match a chunk of objects stored in a Dets table and return a list of variable bindings.</fsummary> + <type> + <v>Continuation = Continuation2 = bindings_cont()</v> + <v>Match = [term()]</v> + </type> + <desc> + <p>Matches some objects stored in a table and returns a + non-empty list of the bindings that match a given pattern in + some unspecified order. The table, the pattern, and the number + of objects that are matched are all defined by + <c>Continuation</c>, which has been returned by a prior call + to <c>match/1</c> or <c>match/3</c>.</p> + <p>When all objects of the table have been matched, + <c>'$end_of_table'</c> is returned.</p> + </desc> + </func> + <func> + <name>match(Name, Pattern) -> [Match] | {error, Reason}</name> + <fsummary>Match the objects stored in a Dets table and return a list of variable bindings.</fsummary> + <type> + <v>Name = name()</v> + <v>Pattern = tuple()</v> + <v>Match = [term()]</v> + </type> + <desc> + <p>Returns for each object of the table <c>Name</c> that + matches <c>Pattern</c> a list of bindings in some unspecified + order. See <seealso marker="ets">ets(3)</seealso> for a + description of patterns. If the keypos'th element of + <c>Pattern</c> is unbound, all objects of the table are + matched. If the keypos'th element is bound, only the + objects with the right key are matched.</p> + </desc> + </func> + <func> + <name>match(Name, Pattern, N) -> {[Match], Continuation} | '$end_of_table' | {error, Reason}</name> + <fsummary>Match the first chunk of objects stored in a Dets table and return a list of variable bindings.</fsummary> + <type> + <v>Name = name()</v> + <v>Pattern = tuple()</v> + <v>N = default | int()</v> + <v>Match = [term()]</v> + <v>Continuation = bindings_cont()</v> + </type> + <desc> + <p>Matches some or all objects of the table <c>Name</c> and + returns a non-empty list of the bindings that match + <c>Pattern</c> in some unspecified order. See <seealso marker="ets">ets(3)</seealso> for a description of + patterns.</p> + <p>A tuple of the bindings and a continuation is returned, + unless the table is empty, in which case + <c>'$end_of_table'</c> is returned. The continuation is to be + used when matching further objects by calling + <c>match/1</c>.</p> + <p>If the keypos'th element of <c>Pattern</c> is bound, all + objects of the table are matched. If the keypos'th element is + unbound, all objects of the table are matched, <c>N</c> + objects at a time, until at least one object matches or the + end of the table has been reached. The default, indicated by + giving <c>N</c> the value <c>default</c>, is to let the number + of objects vary depending on the sizes of the objects. If + <c>Name</c> is a version 9 table, all objects with the same + key are always matched at the same time which implies that + more than N objects may sometimes be matched. + </p> + <p>The table should always be protected using + <c>safe_fixtable/2</c> before calling <c>match/3</c>, or + errors may occur when calling <c>match/1</c>.</p> + </desc> + </func> + <func> + <name>match_delete(Name, Pattern) -> ok | {error, Reason}</name> + <fsummary>Delete all objects that match a given pattern from a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>Pattern = tuple()</v> + </type> + <desc> + <p>Deletes all objects that match <c>Pattern</c> from the + table <c>Name</c>. + See <seealso marker="ets#match/2">ets:match/2</seealso> for a + description of patterns.</p> + <p>If the keypos'th element of <c>Pattern</c> is bound, + only the objects with the right key are matched.</p> + </desc> + </func> + <func> + <name>match_object(Continuation) -> {[Object], Continuation2} | '$end_of_table' | {error, Reason}</name> + <fsummary>Match a chunk of objects stored in a Dets table and return a list of objects.</fsummary> + <type> + <v>Continuation = Continuation2 = object_cont()</v> + <v>Object = object()</v> + </type> + <desc> + <p>Returns a non-empty list of some objects stored in a table + that match a given pattern in some unspecified order. The + table, the pattern, and the number of objects that are matched + are all defined by <c>Continuation</c>, which has been + returned by a prior call to <c>match_object/1</c> or + <c>match_object/3</c>.</p> + <p>When all objects of the table have been matched, + <c>'$end_of_table'</c> is returned.</p> + </desc> + </func> + <func> + <name>match_object(Name, Pattern) -> [Object] | {error, Reason}</name> + <fsummary>Match the objects stored in a Dets table and return a list of objects.</fsummary> + <type> + <v>Name = name()</v> + <v>Pattern = tuple()</v> + <v>Object = object()</v> + </type> + <desc> + <p>Returns a list of all objects of the table <c>Name</c> that + match <c>Pattern</c> in some unspecified order. See <seealso marker="ets">ets(3)</seealso> for a description of patterns. + </p> + <p>If the keypos'th element of <c>Pattern</c> is + unbound, all objects of the table are matched. If the + keypos'th element of <c>Pattern</c> is bound, only the + objects with the right key are matched.</p> + <p>Using the <c>match_object</c> functions for traversing all + objects of a table is more efficient than calling + <c>first/1</c> and <c>next/2</c> or <c>slot/2</c>.</p> + </desc> + </func> + <func> + <name>match_object(Name, Pattern, N) -> {[Object], Continuation} | '$end_of_table' | {error, Reason}</name> + <fsummary>Match the first chunk of objects stored in a Dets table and return a list of objects.</fsummary> + <type> + <v>Name = name()</v> + <v>Pattern = tuple()</v> + <v>N = default | int()</v> + <v>Object = object()</v> + <v>Continuation = object_cont()</v> + </type> + <desc> + <p>Matches some or all objects stored in the table <c>Name</c> + and returns a non-empty list of the objects that match + <c>Pattern</c> in some unspecified order. See <seealso marker="ets">ets(3)</seealso> for a description of + patterns.</p> + <p>A list of objects and a continuation is returned, unless + the table is empty, in which case <c>'$end_of_table'</c> + is returned. The continuation is to be used when matching + further objects by calling <c>match_object/1</c>.</p> + <p>If the keypos'th element of <c>Pattern</c> is bound, all + objects of the table are matched. If the keypos'th element is + unbound, all objects of the table are matched, <c>N</c> + objects at a time, until at least one object matches or the + end of the table has been reached. The default, indicated by + giving <c>N</c> the value <c>default</c>, is to let the number + of objects vary depending on the sizes of the objects. If + <c>Name</c> is a version 9 table, all matching objects with + the same key are always returned in the same reply which + implies that more than N objects may sometimes be returned. + </p> + <p>The table should always be protected using + <c>safe_fixtable/2</c> before calling <c>match_object/3</c>, + or errors may occur when calling <c>match_object/1</c>.</p> + </desc> + </func> + <func> + <name>member(Name, Key) -> Bool | {error, Reason}</name> + <fsummary>Test for occurrence of a key in a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>Key = term()</v> + <v>Bool = bool()</v> + </type> + <desc> + <p>Works like <c>lookup/2</c>, but does not return the + objects. The function returns <c>true</c> if one or more + elements of the table has the key <c>Key</c>, <c>false</c> + otherwise.</p> + </desc> + </func> + <func> + <name>next(Name, Key1) -> Key2 | '$end_of_table'</name> + <fsummary>Return the next key in a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>Key1 = Key2 = term()</v> + </type> + <desc> + <p>Returns the key following <c>Key1</c> in the table + <c>Name</c> according to the table's internal order, or + <c>'$end_of_table'</c> if there is no next key.</p> + <p>Should an error occur, the process is exited with an error + tuple <c>{error, Reason}</c>.</p> + <p>Use <c>first/1</c> to find the first key in the table.</p> + </desc> + </func> + <func> + <name>open_file(Filename) -> {ok, Reference} | {error, Reason}</name> + <fsummary>Open an existing Dets table.</fsummary> + <type> + <v>FileName = file()</v> + <v>Reference = ref()</v> + </type> + <desc> + <p>Opens an existing table. If the table has not been properly + closed, it will be repaired. The returned reference is to be + used as the name of the table. This function is most useful + for debugging purposes.</p> + </desc> + </func> + <func> + <name>open_file(Name, Args) -> {ok, Name} | {error, Reason}</name> + <fsummary>Open a Dets table.</fsummary> + <type> + <v>Name = atom()</v> + </type> + <desc> + <p>Opens a table. An empty Dets table is created if no file + exists.</p> + <p>The atom <c>Name</c> is the name of the table. The table + name must be provided in all subsequent operations on the + table. The name can be used by other processes as well, and + several process can share one table. + </p> + <p>If two processes open the same table by giving the same + name and arguments, then the table will have two users. If one + user closes the table, it still remains open until the second + user closes the table.</p> + <p>The <c>Args</c> argument is a list of <c>{Key, Val}</c> + tuples where the following values are allowed:</p> + <list type="bulleted"> + <item> + <p><c>{access, access()}</c>. It is possible to open + existing tables in read-only mode. A table which is opened + in read-only mode is not subjected to the automatic file + reparation algorithm if it is later opened after a crash. + The default value is <c>read_write</c>.</p> + </item> + <item> + <p><c>{auto_save, auto_save()}</c>, the auto save + interval. If the interval is an integer <c>Time</c>, the + table is flushed to disk whenever it is not accessed for + <c>Time</c> milliseconds. A table that has been flushed + will require no reparation when reopened after an + uncontrolled emulator halt. If the interval is the atom + <c>infinity</c>, auto save is disabled. The default value + is 180000 (3 minutes).</p> + </item> + <item> + <p><c>{estimated_no_objects, int()}</c>. Equivalent to the + <c>min_no_slots</c> option.</p> + </item> + <item> + <p><c>{file, file()}</c>, the name of the file to be + opened. The default value is the name of the table.</p> + </item> + <item> + <p><c>{max_no_slots, no_slots()}</c>, the maximum number + of slots that will be used. The default value is 2 M, and + the maximal value is 32 M. Note that a higher value may + increase the fragmentation of the table, and conversely, + that a smaller value may decrease the fragmentation, at + the expense of execution time. Only available for version + 9 tables.</p> + </item> + <item> + <p><c>{min_no_slots, no_slots()}</c>. Application + performance can be enhanced with this flag by specifying, + when the table is created, the estimated number of + different keys that will be stored in the table. The + default value as well as the minimum value is 256.</p> + </item> + <item> + <p><c>{keypos, keypos()}</c>, the position of the + element of each object to be used as key. The default + value is 1. The ability to explicitly state the key + position is most convenient when we want to store Erlang + records in which the first position of the record is the + name of the record type.</p> + </item> + <item> + <p><c>{ram_file, bool()}</c>, whether the table is to + be kept in RAM. Keeping the table in RAM may sound like an + anomaly, but can enhance the performance of applications + which open a table, insert a set of objects, and then + close the table. When the table is closed, its contents + are written to the disk file. The default value is + <c>false</c>.</p> + </item> + <item> + <p><c>{repair, Value}</c>. <c>Value</c> can be either + a <c>bool()</c> or the atom <c>force</c>. The flag + specifies whether the Dets server should invoke the + automatic file reparation algorithm. The default is + <c>true</c>. If <c>false</c> is specified, there is no + attempt to repair the file and <c>{error, {needs_repair, + FileName}}</c> is returned if the table needs to be + repaired.</p> + <p>The value <c>force</c> means that a reparation will + take place even if the table has been properly closed. + This is how to convert tables created by older versions of + STDLIB. An example is tables hashed with the deprecated + <c>erlang:hash/2</c> BIF. Tables created with Dets from a + STDLIB version of 1.8.2 and later use the + <c>erlang:phash/2</c> function or the + <c>erlang:phash2/1</c> function, which is preferred.</p> + <p>The <c>repair</c> option is ignored if the table is + already open.</p> + </item> + <item> + <p><c>{type, type()}</c>, the type of the table. The + default value is <c>set</c>.</p> + </item> + <item> + <p><c>{version, version()}</c>, the version of the format + used for the table. The default value is <c>9</c>. Tables + on the format used before OTP R8 can be created by giving + the value <c>8</c>. A version 8 table can be converted to + a version 9 table by giving the options <c>{version,9}</c> + and <c>{repair,force}</c>.</p> + </item> + </list> + </desc> + </func> + <func> + <name>pid2name(Pid) -> {ok, Name} | undefined</name> + <fsummary>Return the name of the Dets table handled by a pid.</fsummary> + <type> + <v>Name = name()</v> + <v>Pid = pid()</v> + </type> + <desc> + <p>Returns the name of the table given the pid of a process + that handles requests to a table, or <c>undefined</c> if + there is no such table.</p> + <p>This function is meant to be used for debugging only.</p> + </desc> + </func> + <func> + <name>repair_continuation(Continuation, MatchSpec) -> Continuation2</name> + <fsummary>Repair a continuation from select/1 or select/3.</fsummary> + <type> + <v>Continuation = Continuation2 = select_cont()</v> + <v>MatchSpec = match_spec()</v> + </type> + <desc> + <p>This function can be used to restore an opaque continuation + returned by <c>select/3</c> or <c>select/1</c> if the + continuation has passed through external term format (been + sent between nodes or stored on disk).</p> + <p>The reason for this function is that continuation terms + contain compiled match specifications and therefore will be + invalidated if converted to external term format. Given that + the original match specification is kept intact, the + continuation can be restored, meaning it can once again be + used in subsequent <c>select/1</c> calls even though it has + been stored on disk or on another node.</p> + <p>See also <c>ets(3)</c> for further explanations and + examples. + </p> + <note> + <p>This function is very rarely needed in application code. It + is used by Mnesia to implement distributed <c>select/3</c> + and <c>select/1</c> sequences. A normal application would + either use Mnesia or keep the continuation from being + converted to external format.</p> + <p>The reason for not having an external representation of + compiled match specifications is performance. It may be + subject to change in future releases, while this interface + will remain for backward compatibility.</p> + </note> + </desc> + </func> + <func> + <name>safe_fixtable(Name, Fix)</name> + <fsummary>Fix a Dets table for safe traversal.</fsummary> + <type> + <v>Name = name()</v> + <v>Fix = bool()</v> + </type> + <desc> + <p>If <c>Fix</c> is <c>true</c>, the table <c>Name</c> is + fixed (once more) by the calling process, otherwise the table + is released. The table is also released when a fixing process + terminates. + </p> + <p>If several processes fix a table, the table will remain + fixed until all processes have released it or terminated. A + reference counter is kept on a per process basis, and N + consecutive fixes require N releases to release the table.</p> + <p>It is not guaranteed that calls to <c>first/1</c>, + <c>next/2</c>, select and match functions work as expected + even if the table has been fixed; the limited support for + concurrency implemented in Ets has not yet been implemented + in Dets. Fixing a table currently only disables resizing of + the hash list of the table.</p> + <p>If objects have been added while the table was fixed, the + hash list will start to grow when the table is released which + will significantly slow down access to the table for a period + of time.</p> + </desc> + </func> + <func> + <name>select(Continuation) -> {Selection, Continuation2} | '$end_of_table' | {error, Reason}</name> + <fsummary>Apply a match specification to some objects stored in a Dets table.</fsummary> + <type> + <v>Continuation = Continuation2 = select_cont()</v> + <v>Selection = [term()]</v> + </type> + <desc> + <p>Applies a match specification to some objects stored in a + table and returns a non-empty list of the results. The + table, the match specification, and the number of objects + that are matched are all defined by <c>Continuation</c>, + which has been returned by a prior call to <c>select/1</c> + or <c>select/3</c>.</p> + <p>When all objects of the table have been matched, + <c>'$end_of_table'</c> is returned.</p> + </desc> + </func> + <func> + <name>select(Name, MatchSpec) -> Selection | {error, Reason}</name> + <fsummary>Apply a match specification to all objects stored in a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>MatchSpec = match_spec()</v> + <v>Selection = [term()]</v> + </type> + <desc> + <p>Returns the results of applying the match specification + <c>MatchSpec</c> to all or some objects stored in the table + <c>Name</c>. The order of the objects is not specified. See + the ERTS User's Guide for a description of match + specifications.</p> + <p>If the keypos'th element of <c>MatchSpec</c> is + unbound, the match specification is applied to all objects of + the table. If the keypos'th element is bound, the match + specification is applied to the objects with the right key(s) + only.</p> + <p>Using the <c>select</c> functions for traversing all + objects of a table is more efficient than calling + <c>first/1</c> and <c>next/2</c> or <c>slot/2</c>. + </p> + </desc> + </func> + <func> + <name>select(Name, MatchSpec, N) -> {Selection, Continuation} | '$end_of_table' | {error, Reason}</name> + <fsummary>Apply a match specification to the first chunk of objects stored in a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>MatchSpec = match_spec()</v> + <v>N = default | int()</v> + <v>Selection = [term()]</v> + <v>Continuation = select_cont()</v> + </type> + <desc> + <p>Returns the results of applying the match specification + <c>MatchSpec</c> to some or all objects stored in the table + <c>Name</c>. The order of the objects is not specified. See + the ERTS User's Guide for a description of match + specifications.</p> + <p>A tuple of the results of applying the match specification + and a continuation is returned, unless the table is empty, + in which case <c>'$end_of_table'</c> is returned. The + continuation is to be used when matching further objects by + calling <c>select/1</c>.</p> + <p>If the keypos'th element of <c>MatchSpec</c> is bound, the + match specification is applied to all objects of the table + with the right key(s). If the keypos'th element of + <c>MatchSpec</c> is unbound, the match specification is + applied to all objects of the table, <c>N</c> objects at a + time, until at least one object matches or the end of the + table has been reached. The default, indicated by giving + <c>N</c> the value <c>default</c>, is to let the number of + objects vary depending on the sizes of the objects. If + <c>Name</c> is a version 9 table, all objects with the same + key are always handled at the same time which implies that the + match specification may be applied to more than N objects. + </p> + <p>The table should always be protected using + <c>safe_fixtable/2</c> before calling <c>select/3</c>, or + errors may occur when calling <c>select/1</c>.</p> + </desc> + </func> + <func> + <name>select_delete(Name, MatchSpec) -> N | {error, Reason}</name> + <fsummary>Delete all objects that match a given pattern from a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>MatchSpec = match_spec()</v> + <v>N = int()</v> + </type> + <desc> + <p>Deletes each object from the table <c>Name</c> such that + applying the match specification <c>MatchSpec</c> to the + object returns the value <c>true</c>. See the ERTS + User's Guide for a description of match + specifications. Returns the number of deleted objects.</p> + <p>If the keypos'th element of <c>MatchSpec</c> is + bound, the match specification is applied to the objects + with the right key(s) only.</p> + </desc> + </func> + <func> + <name>slot(Name, I) -> '$end_of_table' | [Object] | {error, Reason}</name> + <fsummary>Return the list of objects associated with a slot of a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>I = int()</v> + <v>Object = object()</v> + </type> + <desc> + <p>The objects of a table are distributed among slots, + starting with slot <c>0</c> and ending with slot n. This + function returns the list of objects associated with slot + <c>I</c>. If <c>I</c> is greater than n <c>'$end_of_table'</c> + is returned.</p> + </desc> + </func> + <func> + <name>sync(Name) -> ok | {error, Reason}</name> + <fsummary>Ensure that all updates made to a Dets table are written to disk.</fsummary> + <type> + <v>Name = name()</v> + </type> + <desc> + <p>Ensures that all updates made to the table <c>Name</c> are + written to disk. This also applies to tables which have been + opened with the <c>ram_file</c> flag set to <c>true</c>. In + this case, the contents of the RAM file are flushed to + disk.</p> + <p>Note that the space management data structures kept in RAM, + the buddy system, is also written to the disk. This may take + some time if the table is fragmented.</p> + </desc> + </func> + <func> + <name>table(Name [, Options]) -> QueryHandle</name> + <fsummary>Return a QLC query handle.</fsummary> + <type> + <v>Name = name()</v> + <v>QueryHandle = - a query handle, see qlc(3) -</v> + <v>Options = [Option] | Option</v> + <v>Option = {n_objects, Limit} | {traverse, TraverseMethod}</v> + <v>Limit = default | integer() >= 1</v> + <v>TraverseMethod = first_next | select | {select, MatchSpec}</v> + <v>MatchSpec = match_spec()</v> + </type> + <desc> + <p> <marker id="qlc_table"></marker> +Returns a QLC (Query List + Comprehension) query handle. The module <c>qlc</c> + implements a query language aimed mainly at Mnesia but Ets + tables, Dets tables, and lists are also recognized by <c>qlc</c> + as sources of data. Calling <c>dets:table/1,2</c> is the + means to make the Dets table <c>Name</c> usable to <c>qlc</c>.</p> + <p>When there are only simple restrictions on the key position + <c>qlc</c> uses <c>dets:lookup/2</c> to look up the keys, but when + that is not possible the whole table is traversed. The + option <c>traverse</c> determines how this is done:</p> + <list type="bulleted"> + <item> + <p><c>first_next</c>. The table is traversed one key at + a time by calling <c>dets:first/1</c> and + <c>dets:next/2</c>.</p> + </item> + <item> + <p><c>select</c>. The table is traversed by calling + <c>dets:select/3</c> and <c>dets:select/1</c>. The option + <c>n_objects</c> determines the number of objects + returned (the third argument of <c>select/3</c>). The + match specification (the second argument of + <c>select/3</c>) is assembled by <c>qlc</c>: simple filters are + translated into equivalent match specifications while + more complicated filters have to be applied to all + objects returned by <c>select/3</c> given a match + specification that matches all objects.</p> + </item> + <item> + <p><c>{select, MatchSpec}</c>. As for <c>select</c> + the table is traversed by calling <c>dets:select/3</c> + and <c>dets:select/1</c>. The difference is that the + match specification is explicitly given. This is how to + state match specifications that cannot easily be + expressed within the syntax provided by <c>qlc</c>.</p> + </item> + </list> + <p>The following example uses an explicit match specification + to traverse the table:</p> + <pre> +1> <input>dets:open_file(t, []),</input> +<input>ok = dets:insert(t, [{1,a},{2,b},{3,c},{4,d}]),</input> +<input>MS = ets:fun2ms(fun({X,Y}) when (X > 1) or (X < 5) -> {Y} end),</input> +<input>QH1 = dets:table(t, [{traverse, {select, MS}}]).</input> </pre> + <p>An example with implicit match specification:</p> + <pre> +2> <input>QH2 = qlc:q([{Y} || {X,Y} <- dets:table(t), (X > 1) or (X < 5)]).</input> </pre> + <p>The latter example is in fact equivalent to the former which + can be verified using the function <c>qlc:info/1</c>:</p> + <pre> +3> <input>qlc:info(QH1) =:= qlc:info(QH2).</input> +true </pre> + <p><c>qlc:info/1</c> returns information about a query handle, + and in this case identical information is returned for the + two query handles.</p> + </desc> + </func> + <func> + <name>to_ets(Name, EtsTab) -> EtsTab | {error, Reason}</name> + <fsummary>Insert all objects of a Dets table into an Ets table.</fsummary> + <type> + <v>Name = name()</v> + <v>EtsTab = - see ets(3) -</v> + </type> + <desc> + <p>Inserts the objects of the Dets table <c>Name</c> into the + Ets table <c>EtsTab</c>. The order in which the objects are + inserted is not specified. The existing objects of the Ets + table are kept unless overwritten.</p> + </desc> + </func> + <func> + <name>traverse(Name, Fun) -> Return | {error, Reason}</name> + <fsummary>Apply a function to all or some objects stored in a Dets table.</fsummary> + <type> + <v>Fun = fun(Object) -> FunReturn</v> + <v>FunReturn = continue | {continue, Val} | {done, Value}</v> + <v>Val = Value = term()</v> + <v>Name = name()</v> + <v>Object = object()</v> + <v>Return = [term()]</v> + </type> + <desc> + <p>Applies <c>Fun</c> to each object stored in the table + <c>Name</c> in some unspecified order. Different actions are + taken depending on the return value of <c>Fun</c>. The + following <c>Fun</c> return values are allowed:</p> + <taglist> + <tag><c>continue</c></tag> + <item> + <p>Continue to perform the traversal. For example, the + following function can be used to print out the contents + of a table:</p> + <pre> +fun(X) -> io:format("~p~n", [X]), continue end. </pre> + </item> + <tag><c>{continue, Val}</c></tag> + <item> + <p>Continue the traversal and accumulate <c>Val</c>. The + following function is supplied in order to collect all + objects of a table in a list: </p> + <pre> +fun(X) -> {continue, X} end. </pre> + </item> + <tag><c>{done, Value}</c></tag> + <item> + <p>Terminate the traversal and return <c>[Value | Acc]</c>.</p> + </item> + </taglist> + <p>Any other value returned by <c>Fun</c> terminates the + traversal and is immediately returned. + </p> + </desc> + </func> + <func> + <name>update_counter(Name, Key, Increment) -> Result</name> + <fsummary>Update a counter object stored in a Dets table.</fsummary> + <type> + <v>Name = name()</v> + <v>Key = term()</v> + <v>Increment = {Pos, Incr} | Incr</v> + <v>Pos = Incr = Result = integer()</v> + </type> + <desc> + <p>Updates the object with key <c>Key</c> stored in the table + <c>Name</c> of type <c>set</c> by adding <c>Incr</c> to the + element at the <c>Pos</c>:th position. The new counter value + is returned. If no position is specified, the element directly + following the key is updated.</p> + <p>This functions provides a way of updating a counter, + without having to look up an object, update the object by + incrementing an element and insert the resulting object into + the table again.</p> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p><seealso marker="ets">ets(3)</seealso>, + mnesia(3), + <seealso marker="qlc">qlc(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/dict.xml b/lib/stdlib/doc/src/dict.xml new file mode 100644 index 0000000000..ebcd2eed09 --- /dev/null +++ b/lib/stdlib/doc/src/dict.xml @@ -0,0 +1,347 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>dict</title> + <prepared>Robert Virding</prepared> + <docno></docno> + <date>1997-01-15</date> + <rev>B</rev> + </header> + <module>dict</module> + <modulesummary>Key-Value Dictionary</modulesummary> + <description> + <p><c>Dict</c> implements a <c>Key</c> - <c>Value</c> dictionary. + The representation of a dictionary is not defined.</p> + <p>This module provides exactly the same interface as the module + <c>orddict</c>. One difference is that while this module + considers two keys as different if they do not match (<c>=:=</c>), + <c>orddict</c> considers two keys as different if and only if + they do not compare equal (<c>==</c>).</p> + </description> + + <section> + <title>DATA TYPES</title> + <code type="none"> +dictionary() + as returned by new/0</code> + </section> + <funcs> + <func> + <name>append(Key, Value, Dict1) -> Dict2</name> + <fsummary>Append a value to keys in a dictionary</fsummary> + <type> + <v>Key = Value = term()</v> + <v>Dict1 = Dict2 = dictionary()</v> + </type> + <desc> + <p>This function appends a new <c>Value</c> to the current list + of values associated with <c>Key</c>. An exception is + generated if the initial value associated with <c>Key</c> is + not a list of values.</p> + </desc> + </func> + <func> + <name>append_list(Key, ValList, Dict1) -> Dict2</name> + <fsummary>Append new values to keys in a dictionary</fsummary> + <type> + <v>ValList = [Value]</v> + <v>Key = Value = term()</v> + <v>Dict1 = Dict2 = dictionary()</v> + </type> + <desc> + <p>This function appends a list of values <c>ValList</c> to + the current list of values associated with <c>Key</c>. An + exception is generated if the initial value associated with + <c>Key</c> is not a list of values.</p> + </desc> + </func> + <func> + <name>erase(Key, Dict1) -> Dict2</name> + <fsummary>Erase a key from a dictionary</fsummary> + <type> + <v>Key = term()</v> + <v>Dict1 = Dict2 = dictionary()</v> + </type> + <desc> + <p>This function erases all items with a given key from a + dictionary.</p> + </desc> + </func> + <func> + <name>fetch(Key, Dict) -> Value</name> + <fsummary>Look-up values in a dictionary</fsummary> + <type> + <v>Key = Value = term()</v> + <v>Dict = dictionary()</v> + </type> + <desc> + <p>This function returns the value associated with <c>Key</c> + in the dictionary <c>Dict</c>. <c>fetch</c> assumes that + the <c>Key</c> is present in the dictionary and an exception + is generated if <c>Key</c> is not in the dictionary.</p> + </desc> + </func> + <func> + <name>fetch_keys(Dict) -> Keys</name> + <fsummary>Return all keys in a dictionary</fsummary> + <type> + <v>Dict = dictionary()</v> + <v>Keys = [term()]</v> + </type> + <desc> + <p>This function returns a list of all keys in the dictionary.</p> + </desc> + </func> + <func> + <name>filter(Pred, Dict1) -> Dict2</name> + <fsummary>Choose elements which satisfy a predicate</fsummary> + <type> + <v>Pred = fun(Key, Value) -> bool()</v> + <v> Key = Value = term()</v> + <v>Dict1 = Dict2 = dictionary()</v> + </type> + <desc> + <p><c>Dict2</c> is a dictionary of all keys and values in + <c>Dict1</c> for which <c>Pred(Key, Value)</c> is <c>true</c>.</p> + </desc> + </func> + <func> + <name>find(Key, Dict) -> {ok, Value} | error</name> + <fsummary>Search for a key in a dictionary</fsummary> + <type> + <v>Key = Value = term()</v> + <v>Dict = dictionary()</v> + </type> + <desc> + <p>This function searches for a key in a dictionary. Returns + <c>{ok, Value}</c> where <c>Value</c> is the value associated + with <c>Key</c>, or <c>error</c> if the key is not present in + the dictionary.</p> + </desc> + </func> + <func> + <name>fold(Fun, Acc0, Dict) -> Acc1</name> + <fsummary>Fold a function over a dictionary</fsummary> + <type> + <v>Fun = fun(Key, Value, AccIn) -> AccOut</v> + <v>Key = Value = term()</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v>Dict = dictionary()</v> + </type> + <desc> + <p>Calls <c>Fun</c> on successive keys and values of + <c>Dict</c> together with an extra argument <c>Acc</c> + (short for accumulator). <c>Fun</c> must return a new + accumulator which is passed to the next call. <c>Acc0</c> is + returned if the list is empty. The evaluation order is + undefined.</p> + </desc> + </func> + <func> + <name>from_list(List) -> Dict</name> + <fsummary>Convert a list of pairs to a dictionary</fsummary> + <type> + <v>List = [{Key, Value}]</v> + <v>Dict = dictionary()</v> + </type> + <desc> + <p>This function converts the key/value list <c>List</c> to a + dictionary.</p> + </desc> + </func> + <func> + <name>is_key(Key, Dict) -> bool()</name> + <fsummary>Test if a key is in a dictionary</fsummary> + <type> + <v>Key = term()</v> + <v>Dict = dictionary()</v> + </type> + <desc> + <p>This function tests if <c>Key</c> is contained in + the dictionary <c>Dict</c>.</p> + </desc> + </func> + <func> + <name>map(Fun, Dict1) -> Dict2</name> + <fsummary>Map a function over a dictionary</fsummary> + <type> + <v>Fun = fun(Key, Value1) -> Value2</v> + <v> Key = Value1 = Value2 = term()</v> + <v>Dict1 = Dict2 = dictionary()</v> + </type> + <desc> + <p><c>map</c> calls <c>Func</c> on successive keys and values + of <c>Dict</c> to return a new value for each key. + The evaluation order is undefined.</p> + </desc> + </func> + <func> + <name>merge(Fun, Dict1, Dict2) -> Dict3</name> + <fsummary>Merge two dictionaries</fsummary> + <type> + <v>Fun = fun(Key, Value1, Value2) -> Value</v> + <v> Key = Value1 = Value2 = Value3 = term()</v> + <v>Dict1 = Dict2 = Dict3 = dictionary()</v> + </type> + <desc> + <p><c>merge</c> merges two dictionaries, <c>Dict1</c> and + <c>Dict2</c>, to create a new dictionary. All the <c>Key</c> + - <c>Value</c> pairs from both dictionaries are included in + the new dictionary. If a key occurs in both dictionaries then + <c>Fun</c> is called with the key and both values to return a + new value. <c>merge</c> could be defined as:</p> + <code type="none"> +merge(Fun, D1, D2) -> + fold(fun (K, V1, D) -> + update(K, fun (V2) -> Fun(K, V1, V2) end, V1, D) + end, D2, D1).</code> + <p>but is faster.</p> + </desc> + </func> + <func> + <name>new() -> dictionary()</name> + <fsummary>Create a dictionary</fsummary> + <desc> + <p>This function creates a new dictionary.</p> + </desc> + </func> + <func> + <name>size(Dict) -> int()</name> + <fsummary>Return the number of elements in a dictionary</fsummary> + <type> + <v>Dict = dictionary()</v> + </type> + <desc> + <p>Returns the number of elements in a <c>Dict</c>.</p> + </desc> + </func> + <func> + <name>store(Key, Value, Dict1) -> Dict2</name> + <fsummary>Store a value in a dictionary</fsummary> + <type> + <v>Key = Value = term()</v> + <v>Dict1 = Dict2 = dictionary()</v> + </type> + <desc> + <p>This function stores a <c>Key</c> - <c>Value</c> pair in a + dictionary. If the <c>Key</c> already exists in <c>Dict1</c>, + the associated value is replaced by <c>Value</c>.</p> + </desc> + </func> + <func> + <name>to_list(Dict) -> List</name> + <fsummary>Convert a dictionary to a list of pairs</fsummary> + <type> + <v>Dict = dictionary()</v> + <v>List = [{Key, Value}]</v> + </type> + <desc> + <p>This function converts the dictionary to a list + representation.</p> + </desc> + </func> + <func> + <name>update(Key, Fun, Dict1) -> Dict2</name> + <fsummary>Update a value in a dictionary</fsummary> + <type> + <v>Key = term()</v> + <v>Fun = fun(Value1) -> Value2</v> + <v> Value1 = Value2 = term()</v> + <v>Dict1 = Dict2 = dictionary()</v> + </type> + <desc> + <p>Update the a value in a dictionary by calling <c>Fun</c> on + the value to get a new value. An exception is generated if + <c>Key</c> is not present in the dictionary.</p> + </desc> + </func> + <func> + <name>update(Key, Fun, Initial, Dict1) -> Dict2</name> + <fsummary>Update a value in a dictionary</fsummary> + <type> + <v>Key = Initial = term()</v> + <v>Fun = fun(Value1) -> Value2</v> + <v> Value1 = Value2 = term()</v> + <v>Dict1 = Dict2 = dictionary()</v> + </type> + <desc> + <p>Update the a value in a dictionary by calling <c>Fun</c> on + the value to get a new value. If <c>Key</c> is not present + in the dictionary then <c>Initial</c> will be stored as + the first value. For example <c>append/3</c> could be defined + as:</p> + <code type="none"> +append(Key, Val, D) -> + update(Key, fun (Old) -> Old ++ [Val] end, [Val], D).</code> + </desc> + </func> + <func> + <name>update_counter(Key, Increment, Dict1) -> Dict2</name> + <fsummary>Increment a value in a dictionary</fsummary> + <type> + <v>Key = term()</v> + <v>Increment = number()</v> + <v>Dict1 = Dict2 = dictionary()</v> + </type> + <desc> + <p>Add <c>Increment</c> to the value associated with <c>Key</c> + and store this value. If <c>Key</c> is not present in + the dictionary then <c>Increment</c> will be stored as + the first value.</p> + <p>This could be defined as:</p> + <code type="none"> +update_counter(Key, Incr, D) -> + update(Key, fun (Old) -> Old + Incr end, Incr, D).</code> + <p>but is faster.</p> + </desc> + </func> + </funcs> + + <section> + <title>Notes</title> + <p>The functions <c>append</c> and <c>append_list</c> are included + so we can store keyed values in a list <em>accumulator</em>. For + example:</p> + <pre> +> D0 = dict:new(), + D1 = dict:store(files, [], D0), + D2 = dict:append(files, f1, D1), + D3 = dict:append(files, f2, D2), + D4 = dict:append(files, f3, D3), + dict:fetch(files, D4). +[f1,f2,f3] </pre> + <p>This saves the trouble of first fetching a keyed value, + appending a new value to the list of stored values, and storing + the result. + </p> + <p>The function <c>fetch</c> should be used if the key is known to + be in the dictionary, otherwise <c>find</c>.</p> + </section> + + <section> + <title>See Also</title> + <p><seealso marker="gb_trees">gb_trees(3)</seealso>, + <seealso marker="orddict">orddict(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/digraph.xml b/lib/stdlib/doc/src/digraph.xml new file mode 100644 index 0000000000..ad256e671f --- /dev/null +++ b/lib/stdlib/doc/src/digraph.xml @@ -0,0 +1,601 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>digraph</title> + <prepared>Tony</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>2001-08-27</date> + <rev>C</rev> + <file>digraph.sgml</file> + </header> + <module>digraph</module> + <modulesummary>Directed Graphs</modulesummary> + <description> + <p>The <c>digraph</c> module implements a version of labeled + directed graphs. What makes the graphs implemented here + non-proper directed graphs is that multiple edges between + vertices are allowed. However, the customary definition of + directed graphs will be used in the text that follows. + </p> + <p>A <marker id="digraph"></marker><em>directed graph</em> (or just + "digraph") is a pair (V, E) of a finite set V of + <marker id="vertex"></marker><em>vertices</em> and a finite set E of + <marker id="edge"></marker><em>directed edges</em> (or just "edges"). + The set of + edges E is a subset of V × V (the Cartesian + product of V with itself). In this module, V is allowed to be + empty; the so obtained unique digraph is called the + <marker id="empty_digraph"></marker><em>empty digraph</em>. + Both vertices and edges are represented by unique Erlang terms. + </p> + <p>Digraphs can be annotated with additional information. Such + information may be attached to the vertices and to the edges of + the digraph. A digraph which has been annotated is called a + <em>labeled digraph</em>, and the information attached to a + vertex or an edge is called a <marker id="label"></marker> + <em>label</em>. Labels are Erlang terms. + </p> + <p>An edge e = (v, w) is said to + <marker id="emanate"></marker><em>emanate</em> from vertex v and + to be <marker id="incident"></marker><em>incident</em> on vertex w. + The <marker id="out_degree"></marker><em>out-degree</em> of a vertex + is the number of edges emanating from that vertex. + The <marker id="in_degree"></marker><em>in-degree</em> of a vertex + is the number of edges incident on that vertex. + If there is an edge emanating from v and incident on w, then w is + said to be an <marker id="out_neighbour"></marker> + <em>out-neighbour</em> of v, and v is said to be an + <marker id="in_neighbour"></marker><em>in-neighbour</em> of w. + A <marker id="path"></marker><em>path</em> P from v[1] to v[k] + in a digraph (V, E) is a non-empty sequence + v[1], v[2], ..., v[k] of vertices in V such that + there is an edge (v[i],v[i+1]) in E for + 1 <= i < k. + The <marker id="length"></marker><em>length</em> of the path P is k-1. + P is <marker id="simple_path"></marker><em>simple</em> if all + vertices are distinct, except that the first and the last vertices + may be the same. + P is a <marker id="cycle"></marker><em>cycle</em> if the length + of P is not zero and v[1] = v[k]. + A <marker id="loop"></marker><em>loop</em> is a cycle of length one. + A <marker id="simple_cycle"></marker><em>simple cycle</em> is a path + that is both a cycle and simple. + An <marker id="acyclic_digraph"></marker><em>acyclic digraph</em> + is a digraph that has no cycles. + </p> + </description> + <funcs> + <func> + <name>add_edge(G, E, V1, V2, Label) -> edge() | {error, Reason}</name> + <name>add_edge(G, V1, V2, Label) -> edge() | {error, Reason}</name> + <name>add_edge(G, V1, V2) -> edge() | {error, Reason}</name> + <fsummary>Add an edge to a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>E = edge()</v> + <v>V1 = V2 = vertex()</v> + <v>Label = label()</v> + <v>Reason = {bad_edge, Path} | {bad_vertex, V}</v> + <v>Path = [vertex()]</v> + </type> + <desc> + <p><c>add_edge/5</c> creates (or modifies) the edge <c>E</c> + of the digraph <c>G</c>, using <c>Label</c> as the (new) + <seealso marker="#label">label</seealso> of the edge. The + edge is <seealso marker="#emanate">emanating</seealso> from + <c>V1</c> and <seealso marker="#incident">incident</seealso> + on <c>V2</c>. Returns <c>E</c>. + </p> + <p><c>add_edge(G, V1, V2, Label)</c> is + equivalent to + <c>add_edge(G, E, V1, V2, Label)</c>, + where <c>E</c> is a created edge. The created edge is + represented by the term <c>['$e' | N]</c>, where N + is an integer >= 0. + </p> + <p><c>add_edge(G, V1, V2)</c> is equivalent to + <c>add_edge(G, V1, V2, [])</c>. + </p> + <p>If the edge would create a cycle in + an <seealso marker="#acyclic_digraph">acyclic digraph</seealso>, + then <c>{error, {bad_edge, Path}}</c> is returned. If + either of <c>V1</c> or <c>V2</c> is not a vertex of the + digraph <c>G</c>, then + <c>{error, {bad_vertex, </c>V<c>}}</c> is + returned, V = <c>V1</c> or + V = <c>V2</c>. + </p> + </desc> + </func> + <func> + <name>add_vertex(G, V, Label) -> vertex()</name> + <name>add_vertex(G, V) -> vertex()</name> + <name>add_vertex(G) -> vertex()</name> + <fsummary>Add or modify a vertex of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V = vertex()</v> + <v>Label = label()</v> + </type> + <desc> + <p><c>add_vertex/3</c> creates (or modifies) the vertex <c>V</c> + of the digraph <c>G</c>, using <c>Label</c> as the (new) + <seealso marker="#label">label</seealso> of the + vertex. Returns <c>V</c>. + </p> + <p><c>add_vertex(G, V)</c> is equivalent to + <c>add_vertex(G, V, [])</c>. + </p> + <p><c>add_vertex/1</c> creates a vertex using the empty list + as label, and returns the created vertex. The created vertex + is represented by the term <c>['$v' | N]</c>, + where N is an integer >= 0. + </p> + </desc> + </func> + <func> + <name>del_edge(G, E) -> true</name> + <fsummary>Delete an edge from a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>E = edge()</v> + </type> + <desc> + <p>Deletes the edge <c>E</c> from the digraph <c>G</c>. + </p> + </desc> + </func> + <func> + <name>del_edges(G, Edges) -> true</name> + <fsummary>Delete edges from a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>Edges = [edge()]</v> + </type> + <desc> + <p>Deletes the edges in the list <c>Edges</c> from the digraph + <c>G</c>. + </p> + </desc> + </func> + <func> + <name>del_path(G, V1, V2) -> true</name> + <fsummary>Delete paths from a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V1 = V2 = vertex()</v> + </type> + <desc> + <p>Deletes edges from the digraph <c>G</c> until there are no + <seealso marker="#path">paths</seealso> from the vertex + <c>V1</c> to the vertex <c>V2</c>. + </p> + <p>A sketch of the procedure employed: Find an arbitrary + <seealso marker="#simple_path">simple path</seealso> + v[1], v[2], ..., v[k] from <c>V1</c> to + <c>V2</c> in <c>G</c>. Remove all edges of + <c>G</c> <seealso marker="#emanate">emanating</seealso> from v[i] + and <seealso marker="#incident">incident</seealso> to v[i+1] for + 1 <= i < k (including multiple + edges). Repeat until there is no path between <c>V1</c> and + <c>V2</c>. + </p> + </desc> + </func> + <func> + <name>del_vertex(G, V) -> true</name> + <fsummary>Delete a vertex from a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V = vertex()</v> + </type> + <desc> + <p>Deletes the vertex <c>V</c> from the digraph <c>G</c>. Any + edges <seealso marker="#emanate">emanating</seealso> from + <c>V</c> or <seealso marker="#incident">incident</seealso> + on <c>V</c> are also deleted. + </p> + </desc> + </func> + <func> + <name>del_vertices(G, Vertices) -> true</name> + <fsummary>Delete vertices from a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Deletes the vertices in the list <c>Vertices</c> from the + digraph <c>G</c>. + </p> + </desc> + </func> + <func> + <name>delete(G) -> true</name> + <fsummary>Delete a digraph.</fsummary> + <type> + <v>G = digraph()</v> + </type> + <desc> + <p>Deletes the digraph <c>G</c>. This call is important + because digraphs are implemented with <c>Ets</c>. There is + no garbage collection of <c>Ets</c> tables. The digraph + will, however, be deleted if the process that created the + digraph terminates. + </p> + </desc> + </func> + <func> + <name>edge(G, E) -> {E, V1, V2, Label} | false</name> + <fsummary>Return the vertices and the label of an edge of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>E = edge()</v> + <v>V1 = V2 = vertex()</v> + <v>Label = label()</v> + </type> + <desc> + <p>Returns <c>{E, V1, V2, Label}</c> where + <c>Label</c> is the <seealso marker="#label">label</seealso> + of the edge + <c>E</c> <seealso marker="#emanate">emanating</seealso> from + <c>V1</c> and <seealso marker="#incident">incident</seealso> on + <c>V2</c> of the digraph <c>G</c>. + If there is no edge <c>E</c> of the + digraph <c>G</c>, then <c>false</c> is returned. + </p> + </desc> + </func> + <func> + <name>edges(G) -> Edges</name> + <fsummary>Return all edges of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>Edges = [edge()]</v> + </type> + <desc> + <p>Returns a list of all edges of the digraph <c>G</c>, in + some unspecified order. + </p> + </desc> + </func> + <func> + <name>edges(G, V) -> Edges</name> + <fsummary>Return the edges emanating from or incident on a vertex of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V = vertex()</v> + <v>Edges = [edge()]</v> + </type> + <desc> + <p>Returns a list of all + edges <seealso marker="#emanate">emanating</seealso> from + or <seealso marker="#incident">incident</seealso> on <c>V</c> + of the digraph <c>G</c>, in some unspecified order.</p> + </desc> + </func> + <func> + <name>get_cycle(G, V) -> Vertices | false</name> + <fsummary>Find one cycle in a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V1 = V2 = vertex()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>If there is + a <seealso marker="#simple_cycle">simple cycle</seealso> of + length two or more through the vertex + <c>V</c>, then the cycle is returned as a list + <c>[V, ..., V]</c> of vertices, otherwise if there + is a <seealso marker="#loop">loop</seealso> through + <c>V</c>, then the loop is returned as a list <c>[V]</c>. If + there are no cycles through <c>V</c>, then <c>false</c> is + returned. + </p> + <p><c>get_path/3</c> is used for finding a simple cycle + through <c>V</c>. + </p> + </desc> + </func> + <func> + <name>get_path(G, V1, V2) -> Vertices | false</name> + <fsummary>Find one path in a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V1 = V2 = vertex()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Tries to find + a <seealso marker="#simple_path">simple path</seealso> from + the vertex <c>V1</c> to the vertex + <c>V2</c> of the digraph <c>G</c>. Returns the path as a + list <c>[V1, ..., V2]</c> of vertices, or + <c>false</c> if no simple path from <c>V1</c> to <c>V2</c> + of length one or more exists. + </p> + <p>The digraph <c>G</c> is traversed in a depth-first manner, + and the first path found is returned. + </p> + </desc> + </func> + <func> + <name>get_short_cycle(G, V) -> Vertices | false</name> + <fsummary>Find one short cycle in a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V1 = V2 = vertex()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Tries to find an as short as + possible <seealso marker="#simple_cycle">simple cycle</seealso> through + the vertex <c>V</c> of the digraph <c>G</c>. Returns the cycle + as a list <c>[V, ..., V]</c> of vertices, or + <c>false</c> if no simple cycle through <c>V</c> exists. + Note that a <seealso marker="#loop">loop</seealso> through + <c>V</c> is returned as the list <c>[V, V]</c>. + </p> + <p><c>get_short_path/3</c> is used for finding a simple cycle + through <c>V</c>. + </p> + </desc> + </func> + <func> + <name>get_short_path(G, V1, V2) -> Vertices | false</name> + <fsummary>Find one short path in a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V1 = V2 = vertex()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Tries to find an as short as + possible <seealso marker="#simple_path">simple path</seealso> from + the vertex <c>V1</c> to the vertex <c>V2</c> of the digraph <c>G</c>. + Returns the path as a list <c>[V1, ..., V2]</c> of + vertices, or <c>false</c> if no simple path from <c>V1</c> + to <c>V2</c> of length one or more exists. + </p> + <p>The digraph <c>G</c> is traversed in a breadth-first + manner, and the first path found is returned. + </p> + </desc> + </func> + <func> + <name>in_degree(G, V) -> integer()</name> + <fsummary>Return the in-degree of a vertex of a digraph.</fsummary> + <type> + <v>G= digraph()</v> + <v>V = vertex()</v> + </type> + <desc> + <p>Returns the <seealso marker="#in_degree">in-degree</seealso> of the vertex + <c>V</c> of the digraph <c>G</c>. + </p> + </desc> + </func> + <func> + <name>in_edges(G, V) -> Edges</name> + <fsummary>Return all edges incident on a vertex of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V = vertex()</v> + <v>Edges = [edge()]</v> + </type> + <desc> + <p>Returns a list of all + edges <seealso marker="#incident">incident</seealso> on + <c>V</c> of the digraph <c>G</c>, in some unspecified order. + </p> + </desc> + </func> + <func> + <name>in_neighbours(G, V) -> Vertices</name> + <fsummary>Return all in-neighbours of a vertex of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V = vertex()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Returns a list of + all <seealso marker="#in_neighbour">in-neighbours</seealso> of + <c>V</c> of the digraph <c>G</c>, in some unspecified order. + </p> + </desc> + </func> + <func> + <name>info(G) -> InfoList</name> + <fsummary>Return information about a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>InfoList = [{cyclicity, Cyclicity}, {memory, NoWords}, {protection, Protection}]</v> + <v>Cyclicity = cyclic | acyclic</v> + <v>Protection = protected | private</v> + <v>NoWords = integer() >= 0</v> + </type> + <desc> + <p>Returns a list of <c>{Tag, Value}</c> pairs describing the + digraph <c>G</c>. The following pairs are returned: + </p> + <list type="bulleted"> + <item> + <p><c>{cyclicity, Cyclicity}</c>, where <c>Cyclicity</c> + is <c>cyclic</c> or <c>acyclic</c>, according to the + options given to <c>new</c>.</p> + </item> + <item> + <p><c>{memory, NoWords}</c>, where <c>NoWords</c> is + the number of words allocated to the <c>ets</c> tables.</p> + </item> + <item> + <p><c>{protection, Protection}</c>, where <c>Protection</c> + is <c>protected</c> or <c>private</c>, according + to the options given to <c>new</c>.</p> + </item> + </list> + </desc> + </func> + <func> + <name>new() -> digraph()</name> + <fsummary>Return a protected empty digraph, where cycles are allowed.</fsummary> + <desc> + <p>Equivalent to <c>new([])</c>. + </p> + </desc> + </func> + <func> + <name>new(Type) -> digraph()</name> + <fsummary>Create a new empty digraph.</fsummary> + <type> + <v>Type = [cyclic | acyclic | private | protected]</v> + </type> + <desc> + <p>Returns + an <seealso marker="#empty_digraph">empty digraph</seealso> with + properties according to the options in <c>Type</c>:</p> + <taglist> + <tag><c>cyclic</c></tag> + <item>Allow <seealso marker="#cycle">cycles</seealso> in the + digraph (default).</item> + <tag><c>acyclic</c></tag> + <item>The digraph is to be kept <seealso marker="#acyclic_digraph">acyclic</seealso>.</item> + <tag><c>protected</c></tag> + <item>Other processes can read the digraph (default).</item> + <tag><c>private</c></tag> + <item>The digraph can be read and modified by the creating + process only.</item> + </taglist> + <p>If an unrecognized type option <c>T</c> is given or <c>Type</c> + is not a proper list, there will be a <c>badarg</c> exception. + </p> + </desc> + </func> + <func> + <name>no_edges(G) -> integer() >= 0</name> + <fsummary>Return the number of edges of the a digraph.</fsummary> + <type> + <v>G = digraph()</v> + </type> + <desc> + <p>Returns the number of edges of the digraph <c>G</c>. + </p> + </desc> + </func> + <func> + <name>no_vertices(G) -> integer() >= 0</name> + <fsummary>Return the number of vertices of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + </type> + <desc> + <p>Returns the number of vertices of the digraph <c>G</c>. + </p> + </desc> + </func> + <func> + <name>out_degree(G, V) -> integer()</name> + <fsummary>Return the out-degree of a vertex of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V = vertex()</v> + </type> + <desc> + <p>Returns the <seealso marker="#out_degree">out-degree</seealso> of the vertex + <c>V</c> of the digraph <c>G</c>. + </p> + </desc> + </func> + <func> + <name>out_edges(G, V) -> Edges</name> + <fsummary>Return all edges emanating from a vertex of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V = vertex()</v> + <v>Edges = [edge()]</v> + </type> + <desc> + <p>Returns a list of all + edges <seealso marker="#emanate">emanating</seealso> from + <c>V</c> of the digraph <c>G</c>, in some unspecified order. + </p> + </desc> + </func> + <func> + <name>out_neighbours(G, V) -> Vertices</name> + <fsummary>Return all out-neighbours of a vertex of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V = vertex()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Returns a list of + all <seealso marker="#out_neighbour">out-neighbours</seealso> of + <c>V</c> of the digraph <c>G</c>, in some unspecified order. + </p> + </desc> + </func> + <func> + <name>vertex(G, V) -> {V, Label} | false</name> + <fsummary>Return the label of a vertex of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>V = vertex()</v> + <v>Label = label()</v> + </type> + <desc> + <p>Returns <c>{V, Label}</c> where <c>Label</c> is the + <seealso marker="#label">label</seealso> of the vertex + <c>V</c> of the digraph <c>G</c>, or <c>false</c> if there + is no vertex <c>V</c> of the digraph <c>G</c>. + </p> + </desc> + </func> + <func> + <name>vertices(G) -> Vertices</name> + <fsummary>Return all vertices of a digraph.</fsummary> + <type> + <v>G = digraph()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Returns a list of all vertices of the digraph <c>G</c>, in + some unspecified order. + </p> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p><seealso marker="digraph_utils">digraph_utils(3)</seealso>, + <seealso marker="ets">ets(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/digraph_utils.xml b/lib/stdlib/doc/src/digraph_utils.xml new file mode 100644 index 0000000000..4b137456b3 --- /dev/null +++ b/lib/stdlib/doc/src/digraph_utils.xml @@ -0,0 +1,426 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>digraph_utils</title> + <prepared>Hans Bolinder</prepared> + <responsible>nobody</responsible> + <docno></docno> + <approved>nobody</approved> + <checked>no</checked> + <date>2001-08-27</date> + <rev>PA1</rev> + <file>digraph_utils.sgml</file> + </header> + <module>digraph_utils</module> + <modulesummary>Algorithms for Directed Graphs</modulesummary> + <description> + <p>The <c>digraph_utils</c> module implements some algorithms + based on depth-first traversal of directed graphs. See the + <c>digraph</c> module for basic functions on directed graphs. + </p> + <p>A <marker id="digraph"></marker><em>directed graph</em> (or + just "digraph") is a pair (V, E) of a finite set V of + <marker id="vertex"></marker><em>vertices</em> and a finite set E + of <marker id="edge"></marker><em>directed edges</em> (or just + "edges"). The set of edges E is a subset of V × V + (the Cartesian product of V with itself). + </p> + <p>Digraphs can be annotated with additional information. Such + information may be attached to the vertices and to the edges of + the digraph. A digraph which has been annotated is called a + <em>labeled digraph</em>, and the information attached to a + vertex or an edge is called a <marker id="label"></marker> + <em>label</em>.</p> + <p>An edge e = (v, w) is said + to <marker id="emanate"></marker><em>emanate</em> from vertex v and + to be <marker id="incident"></marker><em>incident</em> on vertex w. + If there is an edge emanating from v and incident on w, then w is + said to be + an <marker id="out_neighbour"></marker><em>out-neighbour</em> of v, + and v is said to be + an <marker id="in_neighbour"></marker><em>in-neighbour</em> of w. + A <marker id="path"></marker><em>path</em> P from v[1] to v[k] in a + digraph (V, E) is a non-empty sequence + v[1], v[2], ..., v[k] of vertices in V such that + there is an edge (v[i],v[i+1]) in E for + 1 <= i < k. + The <marker id="length"></marker><em>length</em> of the path P is k-1. + P is a <marker id="cycle"></marker><em>cycle</em> if the length of P + is not zero and v[1] = v[k]. + A <marker id="loop"></marker><em>loop</em> is a cycle of length one. + An <marker id="acyclic_digraph"></marker><em>acyclic digraph</em> is + a digraph that has no cycles. + </p> + + <p>A <marker id="depth_first_traversal"></marker> <em>depth-first + traversal</em> of a directed digraph can be viewed as a process + that visits all vertices of the digraph. Initially, all vertices + are marked as unvisited. The traversal starts with an + arbitrarily chosen vertex, which is marked as visited, and + follows an edge to an unmarked vertex, marking that vertex. The + search then proceeds from that vertex in the same fashion, until + there is no edge leading to an unvisited vertex. At that point + the process backtracks, and the traversal continues as long as + there are unexamined edges. If there remain unvisited vertices + when all edges from the first vertex have been examined, some + hitherto unvisited vertex is chosen, and the process is + repeated. + </p> + <p>A <marker id="partial_ordering"></marker><em>partial ordering</em> of + a set S is a transitive, antisymmetric and reflexive relation + between the objects of S. The problem + of <marker id="topsort"></marker><em>topological sorting</em> is to + find a total + ordering of S that is a superset of the partial ordering. A + digraph G = (V, E) is equivalent to a relation E + on V (we neglect the fact that the version of directed graphs + implemented in the <c>digraph</c> module allows multiple edges + between vertices). If the digraph has no cycles of length two or + more, then the reflexive and transitive closure of E is a + partial ordering. + </p> + <p>A <marker id="subgraph"></marker><em>subgraph</em> G' of G is a + digraph whose vertices and edges form subsets of the vertices + and edges of G. G' is <em>maximal</em> with respect to a + property P if all other subgraphs that include the vertices of + G' do not have the property P. A <marker + id="strong_components"></marker> <em>strongly connected + component</em> is a maximal subgraph such that there is a path + between each pair of vertices. A <marker + id="components"></marker><em>connected component</em> is a + maximal subgraph such that there is a path between each pair of + vertices, considering all edges undirected. An <marker + id="arborescence"></marker><em>arborescence</em> is an acyclic + digraph with a vertex V, the <marker + id="root"></marker><em>root</em>, such that there is a unique + path from V to every other vertex of G. A <marker + id="tree"></marker><em>tree</em> is an acyclic non-empty digraph + such that there is a unique path between every pair of vertices, + considering all edges undirected.</p> + </description> + + <funcs> + <func> + <name>arborescence_root(Digraph) -> no | {yes, Root}</name> + <fsummary>Check if a digraph is an arborescence.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>Root = vertex()</v> + </type> + <desc> + + <p>Returns <c>{yes, Root}</c> if <c>Root</c> is + the <seealso marker="#root">root</seealso> of the arborescence + <c>Digraph</c>, <c>no</c> otherwise. + </p> + </desc> + </func> + <func> + <name>components(Digraph) -> [Component]</name> + <fsummary>Return the components of a digraph.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>Component = [vertex()]</v> + </type> + <desc> + <p>Returns a list + of <seealso marker="#components">connected components</seealso>. + Each component is represented by its + vertices. The order of the vertices and the order of the + components are arbitrary. Each vertex of the digraph + <c>Digraph</c> occurs in exactly one component. + </p> + </desc> + </func> + <func> + <name>condensation(Digraph) -> CondensedDigraph</name> + <fsummary>Return a condensed graph of a digraph.</fsummary> + <type> + <v>Digraph = CondensedDigraph = digraph()</v> + </type> + <desc> + <p>Creates a digraph where the vertices are + the <seealso marker="#strong_components">strongly connected + components</seealso> of <c>Digraph</c> as returned by + <c>strong_components/1</c>. If X and Y are strongly + connected components, and there exist vertices x and y in X + and Y respectively such that there is an + edge <seealso marker="#emanate">emanating</seealso> from x + and <seealso marker="#incident">incident</seealso> on y, then + an edge emanating from X and incident on Y is created. + </p> + <p>The created digraph has the same type as <c>Digraph</c>. + All vertices and edges have the + default <seealso marker="#label">label</seealso> <c>[]</c>. + </p> + <p>Each and every <seealso marker="#cycle">cycle</seealso> is + included in some strongly connected component, which implies + that there always exists + a <seealso marker="#topsort">topological ordering</seealso> of the + created digraph.</p> + </desc> + </func> + <func> + <name>cyclic_strong_components(Digraph) -> [StrongComponent]</name> + <fsummary>Return the cyclic strong components of a digraph.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>StrongComponent = [vertex()]</v> + </type> + <desc> + <p>Returns a list of <seealso marker="#strong_components">strongly + connected components</seealso>. + Each strongly component is represented + by its vertices. The order of the vertices and the order of + the components are arbitrary. Only vertices that are + included in some <seealso marker="#cycle">cycle</seealso> in + <c>Digraph</c> are returned, otherwise the returned list is + equal to that returned by <c>strong_components/1</c>. + </p> + </desc> + </func> + <func> + <name>is_acyclic(Digraph) -> bool()</name> + <fsummary>Check if a digraph is acyclic.</fsummary> + <type> + <v>Digraph = digraph()</v> + </type> + <desc> + <p>Returns <c>true</c> if and only if the digraph + <c>Digraph</c> is <seealso marker="#acyclic_digraph">acyclic</seealso>.</p> + </desc> + </func> + <func> + <name>is_arborescence(Digraph) -> bool()</name> + <fsummary>Check if a digraph is an arborescence.</fsummary> + <type> + <v>Digraph = digraph()</v> + </type> + <desc> + <p>Returns <c>true</c> if and only if the digraph + <c>Digraph</c> is + an <seealso marker="#arborescence">arborescence</seealso>.</p> + </desc> + </func> + <func> + <name>is_tree(Digraph) -> bool()</name> + <fsummary>Check if a digraph is a tree.</fsummary> + <type> + <v>Digraph = digraph()</v> + </type> + <desc> + <p>Returns <c>true</c> if and only if the digraph + <c>Digraph</c> is + a <seealso marker="#tree">tree</seealso>.</p> + </desc> + </func> + <func> + <name>loop_vertices(Digraph) -> Vertices</name> + <fsummary>Return the vertices of a digraph included in some loop.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Returns a list of all vertices of <c>Digraph</c> that are + included in some <seealso marker="#loop">loop</seealso>.</p> + </desc> + </func> + <func> + <name>postorder(Digraph) -> Vertices</name> + <fsummary>Return the vertices of a digraph in post-order.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Returns all vertices of the digraph <c>Digraph</c>. The + order is given by + a <seealso marker="#depth_first_traversal">depth-first + traversal</seealso> of the digraph, collecting visited + vertices in postorder. More precisely, the vertices visited + while searching from an arbitrarily chosen vertex are + collected in postorder, and all those collected vertices are + placed before the subsequently visited vertices. + </p> + </desc> + </func> + <func> + <name>preorder(Digraph) -> Vertices</name> + <fsummary>Return the vertices of a digraph in pre-order.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Returns all vertices of the digraph <c>Digraph</c>. The + order is given by + a <seealso marker="#depth_first_traversal">depth-first + traversal</seealso> of the digraph, collecting visited + vertices in pre-order.</p> + </desc> + </func> + <func> + <name>reachable(Vertices, Digraph) -> Vertices</name> + <fsummary>Return the vertices reachable from some vertices of a digraph.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Returns an unsorted list of digraph vertices such that for + each vertex in the list, there is + a <seealso marker="#path">path</seealso> in <c>Digraph</c> from some + vertex of <c>Vertices</c> to the vertex. In particular, + since paths may have length zero, the vertices of + <c>Vertices</c> are included in the returned list. + </p> + </desc> + </func> + <func> + <name>reachable_neighbours(Vertices, Digraph) -> Vertices</name> + <fsummary>Return the neighbours reachable from some vertices of a digraph.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Returns an unsorted list of digraph vertices such that for + each vertex in the list, there is + a <seealso marker="#path">path</seealso> in <c>Digraph</c> of length + one or more from some vertex of <c>Vertices</c> to the + vertex. As a consequence, only those vertices + of <c>Vertices</c> that are included in + some <seealso marker="#cycle">cycle</seealso> are returned. + </p> + </desc> + </func> + <func> + <name>reaching(Vertices, Digraph) -> Vertices</name> + <fsummary>Return the vertices that reach some vertices of a digraph.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Returns an unsorted list of digraph vertices such that for + each vertex in the list, there is + a <seealso marker="#path">path</seealso> from the vertex to some + vertex of <c>Vertices</c>. In particular, since paths may have + length zero, the vertices of <c>Vertices</c> are included in + the returned list. + </p> + </desc> + </func> + <func> + <name>reaching_neighbours(Vertices, Digraph) -> Vertices</name> + <fsummary>Return the neighbours that reach some vertices of a digraph.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Returns an unsorted list of digraph vertices such that for + each vertex in the list, there is + a <seealso marker="#path">path</seealso> of length one or more + from the vertex to some vertex of <c>Vertices</c>. As a consequence, + only those vertices of <c>Vertices</c> that are included in + some <seealso marker="#cycle">cycle</seealso> are returned. + </p> + </desc> + </func> + <func> + <name>strong_components(Digraph) -> [StrongComponent]</name> + <fsummary>Return the strong components of a digraph.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>StrongComponent = [vertex()]</v> + </type> + <desc> + <p>Returns a list of <seealso marker="#strong_components">strongly + connected components</seealso>. + Each strongly component is represented + by its vertices. The order of the vertices and the order of + the components are arbitrary. Each vertex of the digraph + <c>Digraph</c> occurs in exactly one strong component. + </p> + </desc> + </func> + <func> + <name>subgraph(Digraph, Vertices [, Options]) -> Subgraph</name> + <fsummary>Return a subgraph of a digraph.</fsummary> + <type> + <v>Digraph = Subgraph = digraph()</v> + <v>Options = [{type, SubgraphType}, {keep_labels, bool()}]</v> + <v>SubgraphType = inherit | type()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Creates a maximal <seealso marker="#subgraph">subgraph</seealso> of <c>Digraph</c> having + as vertices those vertices of <c>Digraph</c> that are + mentioned in <c>Vertices</c>. + </p> + <p>If the value of the option <c>type</c> is <c>inherit</c>, + which is the default, then the type of <c>Digraph</c> is used + for the subgraph as well. Otherwise the option value of <c>type</c> + is used as argument to <c>digraph:new/1</c>. + </p> + <p>If the value of the option <c>keep_labels</c> is <c>true</c>, + which is the default, then + the <seealso marker="#label">labels</seealso> of vertices and edges + of <c>Digraph</c> are used for the subgraph as well. If the value + is <c>false</c>, then the default label, <c>[]</c>, is used + for the subgraph's vertices and edges. + </p> + <p><c>subgraph(Digraph, Vertices)</c> is equivalent to + <c>subgraph(Digraph, Vertices, [])</c>. + </p> + <p>There will be a <c>badarg</c> exception if any of the arguments + are invalid. + </p> + </desc> + </func> + <func> + <name>topsort(Digraph) -> Vertices | false</name> + <fsummary>Return a topological sorting of the vertices of a digraph.</fsummary> + <type> + <v>Digraph = digraph()</v> + <v>Vertices = [vertex()]</v> + </type> + <desc> + <p>Returns a <seealso marker="#topsort">topological + ordering</seealso> of the vertices of the digraph + <c>Digraph</c> if such an ordering exists, <c>false</c> + otherwise. For each vertex in the returned list, there are + no <seealso marker="#out_neighbour">out-neighbours</seealso> + that occur earlier in the list.</p> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p><seealso marker="digraph">digraph(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/epp.xml b/lib/stdlib/doc/src/epp.xml new file mode 100644 index 0000000000..455d9dc124 --- /dev/null +++ b/lib/stdlib/doc/src/epp.xml @@ -0,0 +1,123 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>epp</title> + <prepared>Kenneth Lundin</prepared> + <responsible>Kenneth Lundin</responsible> + <docno>1</docno> + <approved>Kenneth Lundin</approved> + <checked></checked> + <date>97-01-31</date> + <rev>B</rev> + <file>epp.sgml</file> + </header> + <module>epp</module> + <modulesummary>An Erlang Code Preprocessor</modulesummary> + <description> + <p>The Erlang code preprocessor includes functions which are used + by <c>compile</c> to preprocess macros and include files before + the actual parsing takes place.</p> + </description> + <funcs> + <func> + <name>open(FileName, IncludePath) -> {ok,Epp} | {error, ErrorDescriptor}</name> + <name>open(FileName, IncludePath, PredefMacros) -> {ok,Epp} | {error, ErrorDescriptor}</name> + <fsummary>Open a file for preprocessing</fsummary> + <type> + <v>FileName = atom() | string()</v> + <v>IncludePath = [DirectoryName]</v> + <v>DirectoryName = atom() | string()</v> + <v>PredefMacros = [{atom(),term()}]</v> + <v>Epp = pid() -- handle to the epp server</v> + <v>ErrorDescriptor = term()</v> + </type> + <desc> + <p>Opens a file for preprocessing.</p> + </desc> + </func> + <func> + <name>close(Epp) -> ok</name> + <fsummary>Close the preprocessing of the file associated with <c>Epp</c></fsummary> + <type> + <v>Epp = pid() -- handle to the epp server</v> + </type> + <desc> + <p>Closes the preprocessing of a file.</p> + </desc> + </func> + <func> + <name>parse_erl_form(Epp) -> {ok, AbsForm} | {eof, Line} | {error, ErrorInfo}</name> + <fsummary>Return the next Erlang form from the opened Erlang source file</fsummary> + <type> + <v>Epp = pid()</v> + <v>AbsForm = term()</v> + <v>Line = integer()</v> + <v>ErrorInfo = see separate description below.</v> + </type> + <desc> + <p>Returns the next Erlang form from the opened Erlang source file. + The tuple <c>{eof, Line}</c> is returned at end-of-file. The first + form corresponds to an implicit attribute <c>-file(File,1).</c>, where + <c>File</c> is the name of the file.</p> + </desc> + </func> + <func> + <name>parse_file(FileName,IncludePath,PredefMacro) -> {ok,[Form]} | {error,OpenError}</name> + <fsummary>Preprocesse and parse an Erlang source file</fsummary> + <type> + <v>FileName = atom() | string()</v> + <v>IncludePath = [DirectoryName]</v> + <v>DirectoryName = atom() | string()</v> + <v>PredefMacros = [{atom(),term()}]</v> + <v>Form = term() -- same as returned by erl_parse:parse_form</v> + </type> + <desc> + <p>Preprocesses and parses an Erlang source file. + Note that the tuple <c>{eof, Line}</c> returned at end-of-file is + included as a "form".</p> + </desc> + </func> + </funcs> + + <section> + <title>Error Information</title> + <p>The <c>ErrorInfo</c> mentioned above is the standard + <c>ErrorInfo</c> structure which is returned from all IO + modules. It has the following format: + </p> + <code type="none"> + {ErrorLine, Module, ErrorDescriptor} </code> + <p>A string which describes the error is obtained with the following call: + </p> + <code type="none"> +apply(Module, format_error, ErrorDescriptor) </code> + </section> + + <section> + <title>See Also</title> + <p><seealso marker="erl_parse">erl_parse(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/erl_eval.xml b/lib/stdlib/doc/src/erl_eval.xml new file mode 100644 index 0000000000..62af23c5eb --- /dev/null +++ b/lib/stdlib/doc/src/erl_eval.xml @@ -0,0 +1,246 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>erl_eval</title> + <prepared>Robert Virding</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>97-01-21</date> + <rev>B</rev> + <file>erl_eval.sgml</file> + </header> + <module>erl_eval</module> + <modulesummary>The Erlang Meta Interpreter</modulesummary> + <description> + <p>This module provides an interpreter for Erlang expressions. The + expressions are in the abstract syntax as returned by + <c>erl_parse</c>, the Erlang parser, or a call to + <c>io:parse_erl_exprs/2</c>.</p> + </description> + <funcs> + <func> + <name>exprs(Expressions, Bindings) -> {value, Value, NewBindings}</name> + <name>exprs(Expressions, Bindings, LocalFunctionHandler) -> {value, Value, NewBindings}</name> + <name>exprs(Expressions, Bindings, LocalFunctionHandler, NonlocalFunctionHandler) -> {value, Value, NewBindings}</name> + <fsummary>Evaluate expressions</fsummary> + <type> + <v>Expressions = as returned by erl_parse or io:parse_erl_exprs/2</v> + <v>Bindings = as returned by bindings/1</v> + <v>LocalFunctionHandler = {value, Func} | {eval, Func} | none</v> + <v>NonlocalFunctionHandler = {value, Func} | none</v> + </type> + <desc> + <p>Evaluates <c>Expressions</c> with the set of bindings + <c>Bindings</c>, where <c>Expressions</c> is a sequence of + expressions (in abstract syntax) of a type which may be + returned by <c>io:parse_erl_exprs/2</c>. See below for an + explanation of how and when to use the arguments + <c>LocalFunctionHandler</c> and <c>NonlocalFunctionHandler</c>. + </p> + <p>Returns <c>{value, Value, NewBindings}</c></p> + </desc> + </func> + <func> + <name>expr(Expression, Bindings) -> { value, Value, NewBindings }</name> + <name>expr(Expression, Bindings, LocalFunctionHandler) -> { value, Value, NewBindings }</name> + <name>expr(Expression, Bindings, LocalFunctionHandler, NonlocalFunctionHandler) -> { value, Value, NewBindings }</name> + <name>expr(Expression, Bindings, LocalFunctionHandler, NonlocalFunctionHandler, ReturnFormat) -> { value, Value, NewBindings } | Value</name> + <fsummary>Evaluate expression</fsummary> + <type> + <v>Expression = as returned by io:parse_erl_form/2, for example</v> + <v>Bindings = as returned by bindings/1</v> + <v>LocalFunctionHandler = {value, Func} | {eval, Func} | none</v> + <v>NonlocalFunctionHandler = {value, Func} | none</v> + <v>ReturnFormat = value | none</v> + </type> + <desc> + <p>Evaluates <c>Expression</c> with the set of bindings + <c>Bindings</c>. <c>Expression</c> is an expression (in + abstract syntax) of a type which may be returned by + <c>io:parse_erl_form/2</c>. See below for an explanation of + how and when to use the arguments + <c>LocalFunctionHandler</c> and + <c>NonlocalFunctionHandler</c>. + </p> + <p>Returns <c>{value, Value, NewBindings}</c> by default. But + if the <c>ReturnFormat</c> is <c>value</c> only the <c>Value</c> + is returned.</p> + </desc> + </func> + <func> + <name>expr_list(ExpressionList, Bindings) -> {ValueList, NewBindings}</name> + <name>expr_list(ExpressionList, Bindings, LocalFunctionHandler) -> {ValueList, NewBindings}</name> + <name>expr_list(ExpressionList, Bindings, LocalFunctionHandler, NonlocalFunctionHandler) -> {ValueList, NewBindings}</name> + <fsummary>Evaluate a list of expressions</fsummary> + <desc> + <p>Evaluates a list of expressions in parallel, using the same + initial bindings for each expression. Attempts are made to + merge the bindings returned from each evaluation. This + function is useful in the <c>LocalFunctionHandler</c>. See below. + </p> + <p>Returns <c>{ValueList, NewBindings}</c>.</p> + </desc> + </func> + <func> + <name>new_bindings() -> BindingStruct</name> + <fsummary>Return a bindings structure</fsummary> + <desc> + <p>Returns an empty binding structure.</p> + </desc> + </func> + <func> + <name>bindings(BindingStruct) -> Bindings</name> + <fsummary>Return bindings</fsummary> + <desc> + <p>Returns the list of bindings contained in the binding + structure.</p> + </desc> + </func> + <func> + <name>binding(Name, BindingStruct) -> Binding</name> + <fsummary>Return bindings</fsummary> + <desc> + <p>Returns the binding of <c>Name</c> in <c>BindingStruct</c>.</p> + </desc> + </func> + <func> + <name>add_binding(Name, Value, Bindings) -> BindingStruct</name> + <fsummary>Add a binding</fsummary> + <desc> + <p>Adds the binding <c>Name = Value</c> to <c>Bindings</c>. + Returns an updated binding structure.</p> + </desc> + </func> + <func> + <name>del_binding(Name, Bindings) -> BindingStruct</name> + <fsummary>Delete a binding</fsummary> + <desc> + <p>Removes the binding of <c>Name</c> in <c>Bindings</c>. + Returns an updated binding structure.</p> + </desc> + </func> + </funcs> + + <section> + <title>Local Function Handler</title> + <p>During evaluation of a function, no calls can be made to local + functions. An undefined function error would be + generated. However, the optional argument + <c>LocalFunctionHandler</c> may be used to define a function + which is called when there is a call to a local function. The + argument can have the following formats:</p> + <taglist> + <tag><c>{value,Func}</c></tag> + <item> + <p>This defines a local function handler which is called with:</p> + <code type="none"> +Func(Name, Arguments) </code> + <p><c>Name</c> is the name of the local function (an atom) and + <c>Arguments</c> is a list of the <em>evaluated</em> + arguments. The function handler returns the value of the + local function. In this case, it is not possible to access + the current bindings. To signal an error, the function + handler just calls <c>exit/1</c> with a suitable exit value.</p> + </item> + <tag><c>{eval,Func}</c></tag> + <item> + <p>This defines a local function handler which is called with:</p> + <code type="none"> +Func(Name, Arguments, Bindings) </code> + <p><c>Name</c> is the name of the local function (an atom), + <c>Arguments</c> is a list of the <em>unevaluated</em> + arguments, and <c>Bindings</c> are the current variable + bindings. The function handler returns:</p> + <code type="none"> +{value,Value,NewBindings} </code> + <p><c>Value</c> is the value of the local function and + <c>NewBindings</c> are the updated variable bindings. In + this case, the function handler must itself evaluate all the + function arguments and manage the bindings. To signal an + error, the function handler just calls <c>exit/1</c> with a + suitable exit value.</p> + </item> + <tag><c>none</c></tag> + <item> + <p>There is no local function handler.</p> + </item> + </taglist> + </section> + + <section> + <title>Non-local Function Handler</title> + <p>The optional argument <c>NonlocalFunctionHandler</c> may be + used to define a function which is called in the following + cases: a functional object (fun) is called; a built-in function + is called; a function is called using the M:F syntax, where M + and F are atoms or expressions; an operator Op/A is called + (this is handled as a call to the function <c>erlang:Op/A</c>). + Exceptions are calls to <c>erlang:apply/2,3</c>; neither of the + function handlers will be called for such calls. + The argument can have the following formats:</p> + <taglist> + <tag><c>{value,Func}</c></tag> + <item> + <p>This defines an nonlocal function handler which is called with:</p> + <code type="none"> +Func(FuncSpec, Arguments) </code> + <p><c>FuncSpec</c> is the name of the function on the form + <c>{Module,Function}</c> or a fun, and <c>Arguments</c> is a + list of the <em>evaluated</em> arguments. The function + handler returns the value of the function. To + signal an error, the function handler just calls + <c>exit/1</c> with a suitable exit value.</p> + </item> + <tag><c>none</c></tag> + <item> + <p>There is no nonlocal function handler.</p> + </item> + </taglist> + <note> + <p>For calls such as <c>erlang:apply(Fun, Args)</c> or + <c>erlang:apply(Module, Function, Args)</c> the call of the + non-local function handler corresponding to the call to + <c>erlang:apply/2,3</c> itself--<c>Func({erlang, apply}, [Fun, Args])</c> or <c>Func({erlang, apply}, [Module, Function, Args])</c>--will never take place. The non-local function + handler <em>will</em> however be called with the evaluated + arguments of the call to <c>erlang:apply/2,3</c>: <c>Func(Fun, Args)</c> or <c>Func({Module, Function}, Args)</c> (assuming + that <c>{Module, Function}</c> is not <c>{erlang, apply}</c>).</p> + <p>Calls to functions defined by evaluating fun expressions + <c>"fun ... end"</c> are also hidden from non-local function + handlers.</p> </note> + <p>The nonlocal function handler argument is probably not used as + frequently as the local function handler argument. A possible + use is to call <c>exit/1</c> on calls to functions that for some + reason are not allowed to be called.</p> + </section> + + <section> + <title>Bugs</title> + <p>The evaluator is not complete. <c>receive</c> cannot be + handled properly. + </p> + <p>Any undocumented functions in <c>erl_eval</c> should not be used.</p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/erl_expand_records.xml b/lib/stdlib/doc/src/erl_expand_records.xml new file mode 100644 index 0000000000..7fb03e7c50 --- /dev/null +++ b/lib/stdlib/doc/src/erl_expand_records.xml @@ -0,0 +1,61 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2005</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>erl_expand_records</title> + <prepared>Hans Bolinder</prepared> + <responsible>nobody</responsible> + <docno></docno> + <approved>nobody</approved> + <checked>no</checked> + <date>2005-12-23</date> + <rev>PA1</rev> + <file>erl_expand_records.sgml</file> + </header> + <module>erl_expand_records</module> + <modulesummary>Expands Records in a Module</modulesummary> + <description> + </description> + <funcs> + <func> + <name>module(AbsForms, CompileOptions) -> AbsForms</name> + <fsummary>Expand all records in a module</fsummary> + <type> + <v>AbsForms = [term()]</v> + <v>CompileOptions = [term()]</v> + </type> + <desc> + <p>Expands all records in a module. The returned module has no + references to records, neither attributes nor code.</p> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p>The <seealso marker="erts:absform">abstract format</seealso> + documentation in ERTS User's Guide</p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/erl_id_trans.xml b/lib/stdlib/doc/src/erl_id_trans.xml new file mode 100644 index 0000000000..7c821d2efc --- /dev/null +++ b/lib/stdlib/doc/src/erl_id_trans.xml @@ -0,0 +1,76 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>erl_id_trans</title> + <prepared>Robert Virding</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>97-01-21</date> + <rev>B</rev> + <file>erl_id_trans.sgml</file> + </header> + <module>erl_id_trans</module> + <modulesummary>An Identity Parse Transform</modulesummary> + <description> + <p>This module performs an identity parse transformation of Erlang code. + It is included as an example for users who may wish to write their own + parse transformers. If the option <c>{parse_transform,Module}</c> is passed + to the compiler, a user written function <c>parse_transform/2</c> + is called by the compiler before the code is checked for + errors.</p> + </description> + <funcs> + <func> + <name>parse_transform(Forms, Options) -> Forms</name> + <fsummary>Transform Erlang forms</fsummary> + <type> + <v>Forms = [erlang_form()]</v> + <v>Options = [compiler_options()]</v> + </type> + <desc> + <p>Performs an identity transformation on Erlang forms, as an example.</p> + </desc> + </func> + </funcs> + + <section> + <title>Parse Transformations</title> + <p>Parse transformations are used if a programmer wants to use + Erlang syntax, but with different semantics. The original Erlang + code is then transformed into other Erlang code. + </p> + <note> + <p>Programmers are strongly advised not to engage in parse transformations and no support is offered for problems encountered.</p> + </note> + </section> + + <section> + <title>See Also</title> + <p><seealso marker="erl_parse">erl_parse(3)</seealso>, compile(3).</p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/erl_internal.xml b/lib/stdlib/doc/src/erl_internal.xml new file mode 100644 index 0000000000..906b95deb7 --- /dev/null +++ b/lib/stdlib/doc/src/erl_internal.xml @@ -0,0 +1,158 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>erl_internal</title> + <prepared>Robert Virding</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>97-01-21</date> + <rev>B</rev> + <file>erl_internal.sgml</file> + </header> + <module>erl_internal</module> + <modulesummary>Internal Erlang Definitions</modulesummary> + <description> + <p>This module defines Erlang BIFs, guard tests and operators. + This module is only of interest to programmers who + manipulate Erlang code.</p> + </description> + <funcs> + <func> + <name>bif(Name, Arity) -> bool()</name> + <fsummary>Test for an Erlang BIF</fsummary> + <type> + <v>Name = atom()</v> + <v>Arity = integer()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Name/Arity</c> is an Erlang BIF + which is automatically recognized by the compiler, otherwise + <c>false</c>.</p> + </desc> + </func> + <func> + <name>guard_bif(Name, Arity) -> bool()</name> + <fsummary>Test for an Erlang BIF allowed in guards</fsummary> + <type> + <v>Name = atom()</v> + <v>Arity = integer()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Name/Arity</c> is an Erlang BIF + which is allowed in guards, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>type_test(Name, Arity) -> bool()</name> + <fsummary>Test for a valid type test</fsummary> + <type> + <v>Name = atom()</v> + <v>Arity = integer()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Name/Arity</c> is a valid Erlang + type test, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>arith_op(OpName, Arity) -> bool()</name> + <fsummary>Test for an arithmetic operator</fsummary> + <type> + <v>OpName = atom()</v> + <v>Arity = integer()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>OpName/Arity</c> is an arithmetic + operator, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>bool_op(OpName, Arity) -> bool()</name> + <fsummary>Test for a Boolean operator</fsummary> + <type> + <v>OpName = atom()</v> + <v>Arity = integer()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>OpName/Arity</c> is a Boolean + operator, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>comp_op(OpName, Arity) -> bool()</name> + <fsummary>Test for a comparison operator</fsummary> + <type> + <v>OpName = atom()</v> + <v>Arity = integer()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>OpName/Arity</c> is a comparison + operator, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>list_op(OpName, Arity) -> bool()</name> + <fsummary>Test for a list operator</fsummary> + <type> + <v>OpName = atom()</v> + <v>Arity = integer()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>OpName/Arity</c> is a list + operator, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>send_op(OpName, Arity) -> bool()</name> + <fsummary>Test for a send operator</fsummary> + <type> + <v>OpName = atom()</v> + <v>Arity = integer()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>OpName/Arity</c> is a send + operator, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>op_type(OpName, Arity) -> Type</name> + <fsummary>Return operator type</fsummary> + <type> + <v>OpName = atom()</v> + <v>Arity = integer()</v> + <v>Type = arith | bool | comp | list | send</v> + </type> + <desc> + <p>Returns the <c>Type</c> of operator that <c>OpName/Arity</c> + belongs to, + or generates a <c>function_clause</c> error if it is not an + operator at all.</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/erl_lint.xml b/lib/stdlib/doc/src/erl_lint.xml new file mode 100644 index 0000000000..e339f484cc --- /dev/null +++ b/lib/stdlib/doc/src/erl_lint.xml @@ -0,0 +1,159 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>erl_lint</title> + <prepared>Robert Virding</prepared> + <responsible>Bjarne Dacker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>97-01-27</date> + <rev>B</rev> + <file>erl_lint.sgml</file> + </header> + <module>erl_lint</module> + <modulesummary>The Erlang Code Linter</modulesummary> + <description> + <p>This module is used to check Erlang code for illegal syntax and + other bugs. It also warns against coding practices which are + not recommended. </p> + <p>The errors detected include:</p> + <list type="bulleted"> + <item>redefined and undefined functions</item> + <item>unbound and unsafe variables</item> + <item>illegal record usage.</item> + </list> + <p>Warnings include:</p> + <list type="bulleted"> + <item>unused functions and imports</item> + <item>unused variables</item> + <item>variables imported into matches</item> + <item>variables exported from + <c>if</c>/<c>case</c>/<c>receive</c></item> + <item>variables shadowed in lambdas and list + comprehensions.</item> + </list> + <p>Some of the warnings are optional, and can be turned on by + giving the appropriate option, described below.</p> + <p>The functions in this module are invoked automatically by the + Erlang compiler and there is no reason to invoke these + functions separately unless you have written your own Erlang + compiler.</p> + </description> + <funcs> + <func> + <name>module(AbsForms) -> {ok,Warnings} | {error,Errors,Warnings}</name> + <name>module(AbsForms, FileName) -> {ok,Warnings} | {error,Errors,Warnings}</name> + <name>module(AbsForms, FileName, CompileOptions) -> {ok,Warnings} | {error,Errors,Warnings}</name> + <fsummary>Check a module for errors</fsummary> + <type> + <v>AbsForms = [term()]</v> + <v>FileName = FileName2 = atom() | string()</v> + <v>Warnings = Errors = [{Filename2,[ErrorInfo]}]</v> + <v>ErrorInfo = see separate description below.</v> + <v>CompileOptions = [term()]</v> + </type> + <desc> + <p>This function checks all the forms in a module for errors. + It returns: + </p> + <taglist> + <tag><c>{ok,Warnings}</c></tag> + <item> + <p>There were no errors in the module.</p> + </item> + <tag><c>{error,Errors,Warnings}</c></tag> + <item> + <p>There were errors in the module.</p> + </item> + </taglist> + <p>Since this module is of interest only to the maintainers of + the compiler, and to avoid having the same description in + two places to avoid the usual maintenance nightmare, the + elements of <c>Options</c> that control the warnings are + only described in <seealso marker="compiler:compile#erl_lint_options">compile(3)</seealso>. + </p> + <p>The <c>AbsForms</c> of a module which comes from a file + that is read through <c>epp</c>, the Erlang pre-processor, + can come from many files. This means that any references to + errors must include the file name (see <seealso marker="epp">epp(3)</seealso>, or parser <seealso marker="erl_parse">erl_parse(3)</seealso> The warnings and + errors returned have the following format: + </p> + <code type="none"> + [{FileName2,[ErrorInfo]}] </code> + <p>The errors and warnings are listed in the order in which + they are encountered in the forms. This means that the + errors from one file may be split into different entries in + the list of errors.</p> + </desc> + </func> + <func> + <name>is_guard_test(Expr) -> bool()</name> + <fsummary>Test for a guard test</fsummary> + <type> + <v>Expr = term()</v> + </type> + <desc> + <p>This function tests if <c>Expr</c> is a legal guard test. + <c>Expr</c> is an Erlang term representing the abstract form + for the expression. <c>erl_parse:parse_exprs(Tokens)</c> can + be used to generate a list of <c>Expr</c>.</p> + </desc> + </func> + <func> + <name>format_error(ErrorDescriptor) -> Chars</name> + <fsummary>Format an error descriptor</fsummary> + <type> + <v>ErrorDescriptor = errordesc()</v> + <v>Chars = [char() | Chars]</v> + </type> + <desc> + <p>Takes an <c>ErrorDescriptor</c> and returns a string which + describes the error or warning. This function is usually + called implicitly when processing an <c>ErrorInfo</c> + structure (see below).</p> + </desc> + </func> + </funcs> + + <section> + <title>Error Information</title> + <p>The <c>ErrorInfo</c> mentioned above is the standard + <c>ErrorInfo</c> structure which is returned from all IO + modules. It has the following format: + </p> + <code type="none"> + {ErrorLine, Module, ErrorDescriptor} </code> + <p>A string which describes the error is obtained with the following call: + </p> + <code type="none"> +apply(Module, format_error, ErrorDescriptor) </code> + </section> + + <section> + <title>See Also</title> + <p><seealso marker="erl_parse">erl_parse(3)</seealso>, + <seealso marker="epp">epp(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml new file mode 100644 index 0000000000..739fde7a40 --- /dev/null +++ b/lib/stdlib/doc/src/erl_parse.xml @@ -0,0 +1,201 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>erl_parse</title> + <prepared>Robert</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>97-01-24</date> + <rev>B</rev> + <file>erl_parse.sgml</file> + </header> + <module>erl_parse</module> + <modulesummary>The Erlang Parser</modulesummary> + <description> + <p>This module is the basic Erlang parser which converts tokens into + the abstract form of either forms (i.e., top-level constructs), + expressions, or terms. The Abstract Format is described in the ERTS + User's Guide. + Note that a token list must end with the <em>dot</em> token in order + to be acceptable to the parse functions (see erl_scan).</p> + </description> + <funcs> + <func> + <name>parse_form(Tokens) -> {ok, AbsForm} | {error, ErrorInfo}</name> + <fsummary>Parse an Erlang form</fsummary> + <type> + <v>Tokens = [Token]</v> + <v>Token = {Tag,Line} | {Tag,Line,term()}</v> + <v>Tag = atom()</v> + <v>AbsForm = term()</v> + <v>ErrorInfo = see section Error Information below.</v> + </type> + <desc> + <p>This function parses <c>Tokens</c> as if it were a form. It returns:</p> + <taglist> + <tag><c>{ok, AbsForm}</c></tag> + <item> + <p>The parsing was successful. <c>AbsForm</c> is the + abstract form of the parsed form.</p> + </item> + <tag><c>{error, ErrorInfo}</c></tag> + <item> + <p>An error occurred.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>parse_exprs(Tokens) -> {ok, Expr_list} | {error, ErrorInfo}</name> + <fsummary>Parse Erlang expressions</fsummary> + <type> + <v>Tokens = [Token]</v> + <v>Token = {Tag,Line} | {Tag,Line,term()}</v> + <v>Tag = atom()</v> + <v>Expr_list = [AbsExpr]</v> + <v>AbsExpr = term()</v> + <v>ErrorInfo = see section Error Information below.</v> + </type> + <desc> + <p>This function parses <c>Tokens</c> as if it were a list of expressions. It returns:</p> + <taglist> + <tag><c>{ok, Expr_list}</c></tag> + <item> + <p>The parsing was successful. <c>Expr_list</c> is a + list of the abstract forms of the parsed expressions.</p> + </item> + <tag><c>{error, ErrorInfo}</c></tag> + <item> + <p>An error occurred.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>parse_term(Tokens) -> {ok, Term} | {error, ErrorInfo}</name> + <fsummary>Parse an Erlang term</fsummary> + <type> + <v>Tokens = [Token]</v> + <v>Token = {Tag,Line} | {Tag,Line,term()}</v> + <v>Tag = atom()</v> + <v>Term = term()</v> + <v>ErrorInfo = see section Error Information below.</v> + </type> + <desc> + <p>This function parses <c>Tokens</c> as if it were a term. It returns:</p> + <taglist> + <tag><c>{ok, Term}</c></tag> + <item> + <p>The parsing was successful. <c>Term</c> is + the Erlang term corresponding to the token list.</p> + </item> + <tag><c>{error, ErrorInfo}</c></tag> + <item> + <p>An error occurred.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>format_error(ErrorDescriptor) -> Chars</name> + <fsummary>Format an error descriptor</fsummary> + <type> + <v>ErrorDescriptor = errordesc()</v> + <v>Chars = [char() | Chars]</v> + </type> + <desc> + <p>Uses an <c>ErrorDescriptor</c> and returns a string + which describes the error. This function is usually called + implicitly when an <c>ErrorInfo</c> structure is processed + (see below).</p> + </desc> + </func> + <func> + <name>tokens(AbsTerm) -> Tokens</name> + <name>tokens(AbsTerm, MoreTokens) -> Tokens</name> + <fsummary>Generate a list of tokens for an expression</fsummary> + <type> + <v>Tokens = MoreTokens = [Token]</v> + <v>Token = {Tag,Line} | {Tag,Line,term()}</v> + <v>Tag = atom()</v> + <v>AbsTerm = term()</v> + <v>ErrorInfo = see section Error Information below.</v> + </type> + <desc> + <p>This function generates a list of tokens representing the abstract + form <c>AbsTerm</c> of an expression. Optionally, it appends + <c>Moretokens</c>.</p> + </desc> + </func> + <func> + <name>normalise(AbsTerm) -> Data</name> + <fsummary>Convert abstract form to an Erlang term</fsummary> + <type> + <v>AbsTerm = Data = term()</v> + </type> + <desc> + <p>Converts the abstract form <c>AbsTerm</c> of a term into a + conventional Erlang data structure (i.e., the term itself). + This is the inverse of <c>abstract/1</c>.</p> + </desc> + </func> + <func> + <name>abstract(Data) -> AbsTerm</name> + <fsummary>Convert an Erlang term into an abstract form</fsummary> + <type> + <v>Data = AbsTerm = term()</v> + </type> + <desc> + <p>Converts the Erlang data structure <c>Data</c> into an + abstract form of type <c>AbsTerm</c>. This is the inverse of + <c>normalise/1</c>.</p> + </desc> + </func> + </funcs> + + <section> + <title>Error Information</title> + <p>The <c>ErrorInfo</c> mentioned above is the standard + <c>ErrorInfo</c> structure which is returned from all IO + modules. It has the format: + </p> + <code type="none"> + {ErrorLine, Module, ErrorDescriptor} </code> + <p>A string which describes the error is obtained with the following call: + </p> + <code type="none"> +apply(Module, format_error, ErrorDescriptor) </code> + </section> + + <section> + <title>See Also</title> + <p><seealso marker="io">io(3)</seealso>, + <seealso marker="erl_scan">erl_scan(3)</seealso>, + ERTS User's Guide</p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/erl_pp.xml b/lib/stdlib/doc/src/erl_pp.xml new file mode 100644 index 0000000000..6b15c5afd3 --- /dev/null +++ b/lib/stdlib/doc/src/erl_pp.xml @@ -0,0 +1,178 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>erl_pp</title> + <prepared>Robert Virding</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>97-01-24</date> + <rev>B</rev> + <file>erl_pp.sgml</file> + </header> + <module>erl_pp</module> + <modulesummary>The Erlang Pretty Printer</modulesummary> + <description> + <p>The functions in this module are used to generate + aesthetically attractive representations of abstract + forms, which are suitable for printing. All functions return (possibly deep) + lists of characters and generate an error if the form is wrong.</p> + <p>All functions can have an optional argument which specifies a hook + that is called if an attempt is made to print an unknown form.</p> + </description> + <funcs> + <func> + <name>form(Form) -> DeepCharList</name> + <name>form(Form, HookFunction) -> DeepCharList</name> + <fsummary>Pretty print a form</fsummary> + <type> + <v>Form = term()</v> + <v>HookFunction = see separate description below.</v> + <v>DeepCharList = [char()|DeepCharList]</v> + </type> + <desc> + <p>Pretty prints a + <c>Form</c> which is an abstract form of a type which is + returned by <c>erl_parse:parse_form</c>.</p> + </desc> + </func> + <func> + <name>attribute(Attribute) -> DeepCharList</name> + <name>attribute(Attribute, HookFunction) -> DeepCharList</name> + <fsummary>Pretty print an attribute</fsummary> + <type> + <v>Attribute = term()</v> + <v>HookFunction = see separate description below.</v> + <v>DeepCharList = [char()|DeepCharList]</v> + </type> + <desc> + <p>The same as <c>form</c>, but only for the attribute + <c>Attribute</c>.</p> + </desc> + </func> + <func> + <name>function(Function) -> DeepCharList</name> + <name>function(Function, HookFunction) -> DeepCharList</name> + <fsummary>Pretty print a function</fsummary> + <type> + <v>Function = term()</v> + <v>HookFunction = see separate description below.</v> + <v>DeepCharList = [char()|DeepCharList]</v> + </type> + <desc> + <p>The same as <c>form</c>, but only for the function + <c>Function</c>.</p> + </desc> + </func> + <func> + <name>guard(Guard) -> DeepCharList</name> + <name>guard(Guard, HookFunction) -> DeepCharList</name> + <fsummary>Pretty print a guard</fsummary> + <type> + <v>Form = term()</v> + <v>HookFunction = see separate description below.</v> + <v>DeepCharList = [char()|DeepCharList]</v> + </type> + <desc> + <p>The same as <c>form</c>, but only for the guard test + <c>Guard</c>.</p> + </desc> + </func> + <func> + <name>exprs(Expressions) -> DeepCharList</name> + <name>exprs(Expressions, HookFunction) -> DeepCharList</name> + <name>exprs(Expressions, Indent, HookFunction) -> DeepCharList</name> + <fsummary>Pretty print <c>Expressions</c></fsummary> + <type> + <v>Expressions = term()</v> + <v>HookFunction = see separate description below.</v> + <v>Indent = integer()</v> + <v>DeepCharList = [char()|DeepCharList]</v> + </type> + <desc> + <p>The same as <c>form</c>, but only for the sequence of + expressions in <c>Expressions</c>.</p> + </desc> + </func> + <func> + <name>expr(Expression) -> DeepCharList</name> + <name>expr(Expression, HookFunction) -> DeepCharList</name> + <name>expr(Expression, Indent, HookFunction) -> DeepCharList</name> + <name>expr(Expression, Indent, Precedence, HookFunction) ->-> DeepCharList</name> + <fsummary>Pretty print one <c>Expression</c></fsummary> + <type> + <v>Expression = term()</v> + <v>HookFunction = see separate description below.</v> + <v>Indent = integer()</v> + <v>Precedence = </v> + <v>DeepCharList = [char()|DeepCharList]</v> + </type> + <desc> + <p>This function prints one expression. It is useful for implementing hooks (see below).</p> + </desc> + </func> + </funcs> + + <section> + <title>Unknown Expression Hooks</title> + <p>The optional argument <c>HookFunction</c>, shown in the functions described above, defines a function which is called when an unknown form occurs where there + should be a valid expression. It can have the following formats:</p> + <taglist> + <tag><c>Function</c></tag> + <item> + <p>The hook function is called by:</p> + <code type="none"> +Function(Expr, + CurrentIndentation, + CurrentPrecedence, + HookFunction) </code> + </item> + <tag><c>none</c></tag> + <item> + <p>There is no hook function</p> + </item> + </taglist> + <p>The called hook function should return a (possibly deep) list + of characters. <c>expr/4</c> is useful in a hook. + </p> + <p>If <c>CurrentIndentation</c> is negative, there will be no line + breaks and only a space is used as a separator.</p> + </section> + + <section> + <title>Bugs</title> + <p>It should be possible to have hook functions for unknown forms + at places other than expressions.</p> + </section> + + <section> + <title>See Also</title> + <p><seealso marker="io">io(3)</seealso>, + <seealso marker="erl_parse">erl_parse(3)</seealso>, + <seealso marker="erl_eval">erl_eval(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/erl_scan.xml b/lib/stdlib/doc/src/erl_scan.xml new file mode 100644 index 0000000000..4175146c3c --- /dev/null +++ b/lib/stdlib/doc/src/erl_scan.xml @@ -0,0 +1,417 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>erl_scan</title> + <prepared>Robert Virding</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>97-01-24</date> + <rev>B</rev> + <file>erl_scan.sgml</file> + </header> + <module>erl_scan</module> + <modulesummary>The Erlang Token Scanner</modulesummary> + <description> + <p>This module contains functions for tokenizing characters into + Erlang tokens.</p> + </description> + <section> + <title>DATA TYPES</title> + <code type="none"> +category() = atom() +column() = integer() > 0 +line() = integer() +location() = line() | {line(), column()} +reserved_word_fun() -> fun(atom()) -> bool() +set_attribute_fun() -> fun(term()) -> term() +symbol() = atom() | float() | integer() | string() +token() = {category(), attributes()} | {category(), attributes(), symbol()} +attributes() = line() | list() | tuple()</code> + </section> + <funcs> + <func> + <name>string(String) -> Return</name> + <name>string(String, StartLocation) -> Return</name> + <name>string(String, StartLocation, Options) -> Return</name> + <fsummary>Scan a string and return the Erlang tokens</fsummary> + <type> + <v>String = string()</v> + <v>Return = {ok, Tokens, EndLocation} | Error</v> + <v>Tokens = [token()]</v> + <v>Error = {error, ErrorInfo, EndLocation}</v> + <v>StartLocation = EndLocation = location()</v> + <v>Options = Option | [Option]</v> + <v>Option = {reserved_word_fun,reserved_word_fun()} + | return_comments | return_white_spaces | return + | text</v> + </type> + <desc> + <p>Takes the list of characters <c>String</c> and tries to + scan (tokenize) them. Returns <c>{ok, Tokens, EndLocation}</c>, + where <c>Tokens</c> are the Erlang tokens from + <c>String</c>. <c>EndLocation</c> is the first location + after the last token.</p> + <p><c>{error, ErrorInfo, EndLocation}</c> is returned if an + error occurs. <c>EndLocation</c> is the first location after + the erroneous token.</p> + <p><c>string(String)</c> is equivalent to + <c>string(String, 1)</c>, and <c>string(String, + StartLocation)</c> is equivalent to <c>string(String, + StartLocation, [])</c>.</p> + <p><c>StartLocation</c> indicates the initial location when + scanning starts. If <c>StartLocation</c> is a line + <c>attributes()</c> as well as <c>EndLocation</c> and + <c>ErrorLocation</c> will be lines. If + <c>StartLocation</c> is a pair of a line and a column + <c>attributes()</c> takes the form of an opaque compound + data type, and <c>EndLocation</c> and <c>ErrorLocation</c> + will be pairs of a line and a column. The <em>token + attributes</em> contain information about the column and the + line where the token begins, as well as the text of the + token (if the <c>text</c> option is given), all of which can + be accessed by calling <seealso + marker="#token_info/1">token_info/1,2</seealso> or <seealso + marker="#attributes_info/1">attributes_info/1,2</seealso>.</p> + <p>A <em>token</em> is a tuple containing information about + syntactic category, the token attributes, and the actual + terminal symbol. For punctuation characters (e.g. <c>;</c>, + <c>|</c>) and reserved words, the category and the symbol + coincide, and the token is represented by a two-tuple. + Three-tuples have one of the following forms: <c>{atom, + Info, atom()}</c>, + <c>{char, Info, integer()}</c>, <c>{comment, Info, + string()}</c>, <c>{float, Info, float()}</c>, <c>{integer, + Info, integer()}</c>, <c>{var, Info, atom()}</c>, + and <c>{white_space, Info, string()}</c>.</p> + <p>The valid options are:</p> + <taglist> + <tag><c>{reserved_word_fun, reserved_word_fun()}</c></tag> + <item><p>A callback function that is called when the scanner + has found an unquoted atom. If the function returns + <c>true</c>, the unquoted atom itself will be the category + of the token; if the function returns <c>false</c>, + <c>atom</c> will be the category of the unquoted atom.</p> + </item> + <tag><c>return_comments</c></tag> + <item><p>Return comment tokens.</p> + </item> + <tag><c>return_white_spaces</c></tag> + <item><p>Return white space tokens. By convention, if there is + a newline character, it is always the first character of the + text (there cannot be more than one newline in a white space + token).</p> + </item> + <tag><c>return</c></tag> + <item><p>Short for <c>[return_comments, return_white_spaces]</c>.</p> + </item> + <tag><c>text</c></tag> + <item><p>Include the token's text in the token attributes. The + text is the part of the input corresponding to the token.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>tokens(Continuation, CharSpec, StartLocation) -> Return</name> + <name>tokens(Continuation, CharSpec, StartLocation, Options) -> Return</name> + <fsummary>Re-entrant scanner</fsummary> + <type> + <v>Continuation = [] | Continuation1</v> + <v>Return = {done, Result, LeftOverChars} | {more, Continuation1}</v> + <v>LeftOverChars = CharSpec</v> + <v>CharSpec = string() | eof</v> + <v>Continuation1 = tuple()</v> + <v>Result = {ok, Tokens, EndLocation} | {eof, EndLocation} | Error</v> + <v>Tokens = [token()]</v> + <v>Error = {error, ErrorInfo, EndLocation}</v> + <v>StartLocation = EndLocation = location()</v> + <v>Options = Option | [Option]</v> + <v>Option = {reserved_word_fun,reserved_word_fun()} + | return_comments | return_white_spaces | return</v> + </type> + <desc> + <p>This is the re-entrant scanner which scans characters until + a <em>dot</em> ('.' followed by a white space) or + <c>eof</c> has been reached. It returns:</p> + <taglist> + <tag><c>{done, Result, LeftOverChars}</c></tag> + <item> + <p>This return indicates that there is sufficient input + data to get a result. <c>Result</c> is:</p> + <taglist> + <tag><c>{ok, Tokens, EndLocation}</c></tag> + <item> + <p>The scanning was successful. <c>Tokens</c> is the + list of tokens including <em>dot</em>.</p> + </item> + <tag><c>{eof, EndLocation}</c></tag> + <item> + <p>End of file was encountered before any more tokens.</p> + </item> + <tag><c>{error, ErrorInfo, EndLocation}</c></tag> + <item> + <p>An error occurred. <c>LeftOverChars</c> is the remaining + characters of the input data, + starting from <c>EndLocation</c>.</p> + </item> + </taglist> + </item> + <tag><c>{more, Continuation1}</c></tag> + <item> + <p>More data is required for building a term. + <c>Continuation1</c> must be passed in a new call to + <c>tokens/3,4</c> when more data is available.</p> + </item> + </taglist> + <p>The <c>CharSpec</c> <c>eof</c> signals end of file. + <c>LeftOverChars</c> will then take the value <c>eof</c> as + well.</p> + <p><c>tokens(Continuation, CharSpec, StartLocation)</c> is + equivalent to <c>tokens(Continuation, CharSpec, + StartLocation, [])</c>.</p> + <p>See <seealso marker="#string/3">string/3</seealso> for a + description of the various options.</p> + </desc> + </func> + <func> + <name>reserved_word(Atom) -> bool()</name> + <fsummary>Test for a reserved word</fsummary> + <type> + <v>Atom = atom()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Atom</c> is an Erlang reserved + word, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>token_info(Token) -> TokenInfo</name> + <fsummary>Return information about a token</fsummary> + <type> + <v>Token = token()</v> + <v>TokenInfo = [TokenInfoTuple]</v> + <v>TokenInfoTuple = {TokenItem, Info}</v> + <v>TokenItem = atom()</v> + <v>Info = term()</v> + </type> + <desc> + <p>Returns a list containing information about the token + <c>Token</c>. The order of the <c>TokenInfoTuple</c>s is not + defined. The following <c>TokenItem</c>s are returned: + <c>category</c>, <c>column</c>, <c>length</c>, + <c>line</c>, <c>symbol</c>, and <c>text</c>. See <seealso + marker="#token_info/2">token_info/2</seealso> for + information about specific + <c>TokenInfoTuple</c>s.</p> + <p>Note that if <c>token_info(Token, TokenItem)</c> returns + <c>undefined</c> for some <c>TokenItem</c> in the list above, the + item is not included in <c>TokenInfo</c>.</p> + </desc> + </func> + <func> + <name>token_info(Token, TokenItemSpec) -> TokenInfo</name> + <fsummary>Return information about a token</fsummary> + <type> + <v>Token = token()</v> + <v>TokenItemSpec = TokenItem | [TokenItem]</v> + <v>TokenInfo = TokenInfoTuple | undefined | [TokenInfoTuple]</v> + <v>TokenInfoTuple = {TokenItem, Info}</v> + <v>TokenItem = atom()</v> + <v>Info = term()</v> + </type> + <desc> + <p>Returns a list containing information about the token + <c>Token</c>. If <c>TokenItemSpec</c> is a single + <c>TokenItem</c>, the returned value is the corresponding + <c>TokenInfoTuple</c>, or <c>undefined</c> if the + <c>TokenItem</c> has no value. If <c>TokenItemSpec</c> is a + list of + <c>TokenItem</c>, the result is a list of + <c>TokenInfoTuple</c>. The <c>TokenInfoTuple</c>s will + appear with the corresponding + <c>TokenItem</c>s in the same order as the <c>TokenItem</c>s + appeared in the list of <c>TokenItem</c>s. <c>TokenItem</c>s + with no value are not included in the list of + <c>TokenInfoTuple</c>.</p> + <p>The following <c>TokenInfoTuple</c>s with corresponding + <c>TokenItem</c>s are valid:</p> + <taglist> + <tag><c>{category, category()}</c></tag> + <item><p>The category of the token.</p> + </item> + <tag><c>{column, column()}</c></tag> + <item><p>The column where the token begins.</p> + </item> + <tag><c>{length, integer() > 0}</c></tag> + <item><p>The length of the token's text.</p> + </item> + <tag><c>{line, line()}</c></tag> + <item><p>The line where the token begins.</p> + </item> + <tag><c>{location, location()}</c></tag> + <item><p>The line and column where the token begins, or + just the line if the column unknown.</p> + </item> + <tag><c>{symbol, symbol()}</c></tag> + <item><p>The token's symbol.</p> + </item> + <tag><c>{text, string()}</c></tag> + <item><p>The token's text..</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>attributes_info(Attributes) -> AttributesInfo</name> + <fsummary>Return information about token attributes</fsummary> + <type> + <v>Attributes = attributes()</v> + <v>AttributesInfo = [AttributeInfoTuple]</v> + <v>AttributeInfoTuple = {AttributeItem, Info}</v> + <v>AttributeItem = atom()</v> + <v>Info = term()</v> + </type> + <desc> + <p>Returns a list containing information about the token + attributes <c>Attributes</c>. The order of the + <c>AttributeInfoTuple</c>s is not defined. The following + <c>AttributeItem</c>s are returned: + <c>column</c>, <c>length</c>, <c>line</c>, and <c>text</c>. + See <seealso + marker="#attributes_info/2">attributes_info/2</seealso> for + information about specific + <c>AttributeInfoTuple</c>s.</p> + <p>Note that if <c>attributes_info(Token, AttributeItem)</c> + returns <c>undefined</c> for some <c>AttributeItem</c> in + the list above, the item is not included in + <c>AttributesInfo</c>.</p> + </desc> + </func> + <func> + <name>attributes_info(Attributes, AttributeItemSpec) -> AttributesInfo</name> + <fsummary>Return information about a token attributes</fsummary> + <type> + <v>Attributes = attributes()</v> + <v>AttributeItemSpec = AttributeItem | [AttributeItem]</v> + <v>AttributesInfo = AttributeInfoTuple | undefined + | [AttributeInfoTuple]</v> + <v>AttributeInfoTuple = {AttributeItem, Info}</v> + <v>AttributeItem = atom()</v> + <v>Info = term()</v> + </type> + <desc> + <p>Returns a list containing information about the token + attributes <c>Attributes</c>. If <c>AttributeItemSpec</c> is + a single <c>AttributeItem</c>, the returned value is the + corresponding <c>AttributeInfoTuple</c>, or <c>undefined</c> + if the <c>AttributeItem</c> has no value. If + <c>AttributeItemSpec</c> is a list of + <c>AttributeItem</c>, the result is a list of + <c>AttributeInfoTuple</c>. The <c>AttributeInfoTuple</c>s + will appear with the corresponding <c>AttributeItem</c>s in + the same order as the <c>AttributeItem</c>s appeared in the + list of <c>AttributeItem</c>s. <c>AttributeItem</c>s with no + value are not included in the list of + <c>AttributeInfoTuple</c>.</p> + <p>The following <c>AttributeInfoTuple</c>s with corresponding + <c>AttributeItem</c>s are valid:</p> + <taglist> + <tag><c>{column, column()}</c></tag> + <item><p>The column where the token begins.</p> + </item> + <tag><c>{length, integer() > 0}</c></tag> + <item><p>The length of the token's text.</p> + </item> + <tag><c>{line, line()}</c></tag> + <item><p>The line where the token begins.</p> + </item> + <tag><c>{location, location()}</c></tag> + <item><p>The line and column where the token begins, or + just the line if the column unknown.</p> + </item> + <tag><c>{text, string()}</c></tag> + <item><p>The token's text..</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>set_attribute(AttributeItem, Attributes, SetAttributeFun) -> AttributesInfo</name> + <fsummary>Set a token attribute value</fsummary> + <type> + <v>AttributeItem = line</v> + <v>Attributes = attributes()</v> + <v>SetAttributeFun = set_attribute_fun()</v> + </type> + <desc> + <p>Sets the value of the <c>line</c> attribute of the token + attributes <c>Attributes</c>.</p> + <p>The <c>SetAttributeFun</c> is called with the value of + the <c>line</c> attribute, and is to return the new value of + the <c>line</c> attribute.</p> + </desc> + </func> + <func> + <name>format_error(ErrorDescriptor) -> string()</name> + <fsummary>Format an error descriptor</fsummary> + <type> + <v>ErrorDescriptor = errordesc()</v> + </type> + <desc> + <p>Takes an <c>ErrorDescriptor</c> and returns a string which + describes the error or warning. This function is usually + called implicitly when processing an <c>ErrorInfo</c> + structure (see below).</p> + </desc> + </func> + </funcs> + + <section> + <title>Error Information</title> + <p>The <c>ErrorInfo</c> mentioned above is the standard + <c>ErrorInfo</c> structure which is returned from all IO + modules. It has the following format:</p> + <code type="none"> +{ErrorLocation, Module, ErrorDescriptor}</code> + <p>A string which describes the error is obtained with the + following call:</p> + <code type="none"> +Module:format_error(ErrorDescriptor)</code> + </section> + + <section> + <title>Notes</title> + <p>The continuation of the first call to the re-entrant input + functions must be <c>[]</c>. Refer to Armstrong, Virding and + Williams, 'Concurrent Programming in Erlang', Chapter 13, for a + complete description of how the re-entrant input scheme works.</p> + </section> + + <section> + <title>See Also</title> + <p><seealso marker="io">io(3)</seealso>, + <seealso marker="erl_parse">erl_parse(3)</seealso></p> + </section> +</erlref> diff --git a/lib/stdlib/doc/src/erl_tar.xml b/lib/stdlib/doc/src/erl_tar.xml new file mode 100644 index 0000000000..929620bb88 --- /dev/null +++ b/lib/stdlib/doc/src/erl_tar.xml @@ -0,0 +1,434 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>erl_tar</title> + <prepared>Bjorn Gustavsson</prepared> + <responsible>Bjorn Gustavsson</responsible> + <docno>1</docno> + <approved>Kenneth Lundin</approved> + <checked></checked> + <date>03-01-21</date> + <rev>A</rev> + <file>erl_tar.sgml</file> + </header> + <module>erl_tar</module> + <modulesummary>Unix 'tar' utility for reading and writing tar archives</modulesummary> + <description> + <p>The <c>erl_tar</c> module archives and extract files to and from + a tar file. The tar file format is the POSIX extended tar file format + specified in IEEE Std 1003.1 and ISO/IEC 9945-1. That is the same + format as used by <c>tar</c> program on Solaris, but is not the same + as used by the GNU tar program.</p> + <p>By convention, the name of a tar file should end in "<c>.tar</c>". + To abide to the convention, you'll need to add "<c>.tar</c>" yourself + to the name.</p> + <p>Tar files can be created in one operation using the + <seealso marker="#create_2">create/2</seealso> or + <seealso marker="#create_3">create/3</seealso> function.</p> + <p>Alternatively, for more control, the + <seealso marker="#open">open</seealso>, + <seealso marker="#add">add/3,4</seealso>, and + <seealso marker="#close">close/1</seealso> functions can be used.</p> + <p>To extract all files from a tar file, use the + <seealso marker="#extract_1">extract/1</seealso> function. + To extract only some files or to be able to specify some more options, + use the <seealso marker="#extract_2">extract/2</seealso> function.</p> + <p>To return a list of the files in a tar file, + use either the <seealso marker="#table_1">table/1</seealso> or + <seealso marker="#table_2">table/2</seealso> function. + To print a list of files to the Erlang shell, + use either the <seealso marker="#t_1">t/1</seealso> or + <seealso marker="#tt_1">tt/1</seealso> function.</p> + <p>To convert an error term returned from one of the functions + above to a readable message, use the + <seealso marker="#format_error_1">format_error/1</seealso> function.</p> + </description> + + <section> + <title>LIMITATIONS</title> + <p>For maximum compatibility, it is safe to archive files with names + up to 100 characters in length. Such tar files can generally be + extracted by any <c>tar</c> program.</p> + <p>If filenames exceed 100 characters in length, the resulting tar + file can only be correctly extracted by a POSIX-compatible <c>tar</c> + program (such as Solaris <c>tar</c>), not by GNU tar.</p> + <p>File have longer names than 256 bytes cannot be stored at all.</p> + <p>The filename of the file a symbolic link points is always limited + to 100 characters.</p> + </section> + <funcs> + <func> + <name>add(TarDescriptor, Filename, Options) -> RetValue</name> + <fsummary>Add a file to an open tar file</fsummary> + <type> + <v>TarDescriptor = term()</v> + <v>Filename = filename()</v> + <v>Options = [Option]</v> + <v>Option = dereference|verbose</v> + <v>RetValue = ok|{error,{Filename,Reason}}</v> + <v>Reason = term()</v> + </type> + <desc> + <p>The <marker id="add"></marker> +<c>add/3</c> function adds a file to a tar file + that has been opened for writing by + <seealso marker="#open">open/1</seealso>.</p> + <taglist> + <tag><c>dereference</c></tag> + <item> + <p>By default, symbolic links will be stored as symbolic links + in the tar file. Use the <c>dereference</c> option to override the + default and store the file that the symbolic link points to into + the tar file.</p> + </item> + <tag><c>verbose</c></tag> + <item> + <p>Print an informational message about the file being added.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>add(TarDescriptor, FilenameOrBin, NameInArchive, Options) -> RetValue </name> + <fsummary>Add a file to an open tar file</fsummary> + <type> + <v>TarDescriptor = term()</v> + <v>FilenameOrBin = Filename()|binary()</v> + <v>Filename = filename()()</v> + <v>NameInArchive = filename()</v> + <v>Options = [Option]</v> + <v>Option = dereference|verbose</v> + <v>RetValue = ok|{error,{Filename,Reason}}</v> + <v>Reason = term()</v> + </type> + <desc> + <p>The <c>add/4</c> function adds a file to a tar file + that has been opened for writing by + <seealso marker="#open">open/1</seealso>. It accepts the same + options as <seealso marker="#add">add/3</seealso>.</p> + <p><c>NameInArchive</c> is the name under which the file will + be stored in the tar file. That is the name that the file will + get when it will be extracted from the tar file.</p> + </desc> + </func> + <func> + <name>close(TarDescriptor)</name> + <fsummary>Close an open tar file</fsummary> + <type> + <v>TarDescriptor = term()</v> + </type> + <desc> + <p>The <marker id="close"></marker> +<c>close/1</c> function closes a tar file + opened by <seealso marker="#open">open/1</seealso>.</p> + </desc> + </func> + <func> + <name>create(Name, FileList) ->RetValue </name> + <fsummary>Create a tar archive</fsummary> + <type> + <v>Name = filename()</v> + <v>FileList = [Filename|{NameInArchive, binary()},{NameInArchive, Filename}]</v> + <v>Filename = filename()</v> + <v>NameInArchive = filename()</v> + <v>RetValue = ok|{error,{Name,Reason}} <V>Reason = term()</v> + </type> + <desc> + <p>The <marker id="create_2"></marker> +<c>create/2</c> function creates a tar file and + archives the files whose names are given in <c>FileList</c> into it. + The files may either be read from disk or given as + binaries.</p> + </desc> + </func> + <func> + <name>create(Name, FileList, OptionList)</name> + <fsummary>Create a tar archive with options</fsummary> + <type> + <v>Name = filename()</v> + <v>FileList = [Filename|{NameInArchive, binary()},{NameInArchive, Filename}]</v> + <v>Filename = filename()</v> + <v>NameInArchive = filename()</v> + <v>OptionList = [Option]</v> + <v>Option = compressed|cooked|dereference|verbose</v> + <v>RetValue = ok|{error,{Name,Reason}} <V>Reason = term()</v> + </type> + <desc> + <p>The <marker id="create_3"></marker> +<c>create/3</c> function + creates a tar file and archives the files whose names are given + in <c>FileList</c> into it. The files may either be read from + disk or given as binaries.</p> + <p>The options in <c>OptionList</c> modify the defaults as follows. + </p> + <taglist> + <tag><c>compressed</c></tag> + <item> + <p>The entire tar file will be compressed, as if it has + been run through the <c>gzip</c> program. To abide to the + convention that a compressed tar file should end in "<c>.tar.gz</c>" or + "<c>.tgz</c>", you'll need to add the appropriate extension yourself.</p> + </item> + <tag><c>cooked</c></tag> + <item> + <p>By default, the <c>open/2</c> function will open the tar file + in <c>raw</c> mode, which is faster but does not allow a remote (erlang) + file server to be used. Adding <c>cooked</c> to the mode list will + override the default and open the tar file without the <c>raw</c> + option.</p> + </item> + <tag><c>dereference</c></tag> + <item> + <p>By default, symbolic links will be stored as symbolic links + in the tar file. Use the <c>dereference</c> option to override the + default and store the file that the symbolic link points to into + the tar file.</p> + </item> + <tag><c>verbose</c></tag> + <item> + <p>Print an informational message about each file being added.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>extract(Name) -> RetValue</name> + <fsummary>Extract all files from a tar file</fsummary> + <type> + <v>Name = filename()</v> + <v>RetValue = ok|{error,{Name,Reason}}</v> + <v>Reason = term()</v> + </type> + <desc> + <p>The <marker id="extract_1"></marker> +<c>extract/1</c> function extracts + all files from a tar archive.</p> + <p>If the <c>Name</c> argument is given as "<c>{binary,Binary}</c>", + the contents of the binary is assumed to be a tar archive. + </p> + <p>If the <c>Name</c> argument is given as "<c>{file,Fd}</c>", + <c>Fd</c> is assumed to be a file descriptor returned from + the <c>file:open/2</c> function. + </p> + <p>Otherwise, <c>Name</c> should be a filename.</p> + </desc> + </func> + <func> + <name>extract(Name, OptionList)</name> + <fsummary>Extract files from a tar file</fsummary> + <type> + <v>Name = filename() | {binary,Binary} | {file,Fd} </v> + <v>Binary = binary()</v> + <v>Fd = file_descriptor()</v> + <v>OptionList = [Option]</v> + <v>Option = {cwd,Cwd}|{files,FileList}|keep_old_files|verbose|memory</v> + <v>Cwd = [dirname()]</v> + <v>FileList = [filename()]</v> + <v>RetValue = ok|MemoryRetValue|{error,{Name,Reason}}</v> + <v>MemoryRetValue = {ok, [{NameInArchive,binary()}]}</v> + <v>NameInArchive = filename()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>The <marker id="extract_2"></marker> +<c>extract/2</c> function extracts + files from a tar archive.</p> + <p>If the <c>Name</c> argument is given as "<c>{binary,Binary}</c>", + the contents of the binary is assumed to be a tar archive. + </p> + <p>If the <c>Name</c> argument is given as "<c>{file,Fd}</c>", + <c>Fd</c> is assumed to be a file descriptor returned from + the <c>file:open/2</c> function. + </p> + <p>Otherwise, <c>Name</c> should be a filename. + </p> + <p>The following options modify the defaults for the extraction as + follows.</p> + <taglist> + <tag><c>{cwd,Cwd}</c></tag> + <item> + <p>Files with relative filenames will by default be extracted + to the current working directory. + Given the <c>{cwd,Cwd}</c> option, the <c>extract/2</c> function + will extract into the directory <c>Cwd</c> instead of to the current + working directory.</p> + </item> + <tag><c>{files,FileList}</c></tag> + <item> + <p>By default, all files will be extracted from the tar file. + Given the <c>{files,Files}</c> option, the <c>extract/2</c> function + will only extract the files whose names are included in <c>FileList</c>.</p> + </item> + <tag><c>compressed</c></tag> + <item> + <p>Given the <c>compressed</c> option, the <c>extract/2</c> + function will uncompress the file while extracting + If the tar file is not actually compressed, the <c>compressed</c> + will effectively be ignored.</p> + </item> + <tag><c>cooked</c></tag> + <item> + <p>By default, the <c>open/2</c> function will open the tar file + in <c>raw</c> mode, which is faster but does not allow a remote (erlang) + file server to be used. Adding <c>cooked</c> to the mode list will + override the default and open the tar file without the <c>raw</c> + option.</p> + </item> + <tag><c>memory</c></tag> + <item> + <p>Instead of extracting to a directory, the memory option will + give the result as a list of tuples {Filename, Binary}, where + Binary is a binary containing the extracted data of the file named + Filename in the tar file.</p> + </item> + <tag><c>keep_old_files</c></tag> + <item> + <p>By default, all existing files with the same name as file in + the tar file will be overwritten + Given the <c>keep_old_files</c> option, the <c>extract/2</c> function + will not overwrite any existing files.</p> + </item> + <tag><c>verbose</c></tag> + <item> + <p>Print an informational message as each file is being extracted.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>format_error(Reason) -> string()</name> + <fsummary>Convert error term to a readable string</fsummary> + <type> + <v>Reason = term()</v> + </type> + <desc> + <p>The <marker id="format_error_1"></marker> +<c>format_error/1</c> converts + an error reason term to a human-readable error message string.</p> + </desc> + </func> + <func> + <name>open(Name, OpenModeList) -> RetValue</name> + <fsummary>Open a tar file for writing.</fsummary> + <type> + <v>Name = filename()</v> + <v>OpenModeList = [OpenMode]</v> + <v>Mode = write|compressed|cooked</v> + <v>RetValue = {ok,TarDescriptor}|{error,{Name,Reason}}</v> + <v>TarDescriptor = term()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>The <marker id="open"></marker> +<c>open/2</c> function creates a tar file for writing. + (Any existing file with the same name will be truncated.)</p> + <p>By convention, the name of a tar file should end in "<c>.tar</c>". + To abide to the convention, you'll need to add "<c>.tar</c>" yourself + to the name.</p> + <p>Except for the <c>write</c> atom the following atoms + may be added to <c>OpenModeList</c>:</p> + <taglist> + <tag><c>compressed</c></tag> + <item> + <p>The entire tar file will be compressed, as if it has + been run through the <c>gzip</c> program. To abide to the + convention that a compressed tar file should end in "<c>.tar.gz</c>" or + "<c>.tgz</c>", you'll need to add the appropriate extension yourself.</p> + </item> + <tag><c>cooked</c></tag> + <item> + <p>By default, the <c>open/2</c> function will open the tar file + in <c>raw</c> mode, which is faster but does not allow a remote (erlang) + file server to be used. Adding <c>cooked</c> to the mode list will + override the default and open the tar file without the <c>raw</c> + option.</p> + </item> + </taglist> + <p>Use the <seealso marker="#add">add/3,4</seealso> functions + to add one file at the time into an opened tar file. When you are + finished adding files, use the <seealso marker="#close">close</seealso> + function to close the tar file.</p> + <warning> + <p>The <c>TarDescriptor</c> term is not a file descriptor. + You should not rely on the specific contents of the <c>TarDescriptor</c> + term, as it may change in future versions as more features are added + to the <c>erl_tar</c> module.</p> + <p></p> + </warning> + </desc> + </func> + <func> + <name>table(Name) -> RetValue</name> + <fsummary>Retrieve the name of all files in a tar file</fsummary> + <type> + <v>Name = filename()</v> + <v>RetValue = {ok,[string()]}|{error,{Name,Reason}}</v> + <v>Reason = term()</v> + </type> + <desc> + <p>The <marker id="table_1"></marker> +<c>table/1</c> function retrieves + the names of all files in the tar file <c>Name</c>.</p> + </desc> + </func> + <func> + <name>table(Name, Options)</name> + <fsummary>Retrieve name and information of all files in a tar file</fsummary> + <type> + <v>Name = filename()</v> + </type> + <desc> + <p>The <marker id="table_2"></marker> +<c>table/2</c> function retrieves + the names of all files in the tar file <c>Name</c>.</p> + </desc> + </func> + <func> + <name>t(Name)</name> + <fsummary>Print the name of each file in a tar file</fsummary> + <type> + <v>Name = filename()</v> + </type> + <desc> + <p>The <marker id="t_1"></marker> +<c>t/1</c> function prints the names + of all files in the tar file <c>Name</c> to the Erlang shell. + (Similar to "<c>tar t</c>".)</p> + </desc> + </func> + <func> + <name>tt(Name)</name> + <fsummary>Print name and information for each file in a tar file</fsummary> + <type> + <v>Name = filename()</v> + </type> + <desc> + <p>The <marker id="tt_1"></marker> +<c>tt/1</c> function prints names and + information about all files in the tar file <c>Name</c> to + the Erlang shell. (Similar to "<c>tar tv</c>".)</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml new file mode 100644 index 0000000000..7b9f0e7772 --- /dev/null +++ b/lib/stdlib/doc/src/ets.xml @@ -0,0 +1,1811 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>ets</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>ets</module> + <modulesummary>Built-In Term Storage</modulesummary> + <description> + <p>This module is an interface to the Erlang built-in term storage + BIFs. These provide the ability to store very large quantities of + data in an Erlang runtime system, and to have constant access + time to the data. (In the case of <c>ordered_set</c>, see below, + access time is proportional to the logarithm of the number of + objects stored).</p> + <p>Data is organized as a set of dynamic tables, which can store + tuples. Each table is created by a process. When the process + terminates, the table is automatically destroyed. Every table has + access rights set at creation.</p> + <p>Tables are divided into four different types, <c>set</c>, + <c>ordered_set</c>, <c>bag</c> and <c>duplicate_bag</c>. + A <c>set</c> or <c>ordered_set</c> table can only have one object + associated with each key. A <c>bag</c> or <c>duplicate_bag</c> can + have many objects associated with each key.</p> + <p>The number of tables stored at one Erlang node is limited. + The current default limit is approximately 1400 tables. The upper + limit can be increased by setting the environment variable + <c>ERL_MAX_ETS_TABLES</c> before starting the Erlang runtime + system (i.e. with the <c>-env</c> option to + <c>erl</c>/<c>werl</c>). The actual limit may be slightly higher + than the one specified, but never lower.</p> + <p>Note that there is no automatic garbage collection for tables. + Even if there are no references to a table from any process, it + will not automatically be destroyed unless the owner process + terminates. It can be destroyed explicitly by using + <c>delete/1</c>.</p> + <p>Since R13B01, table ownership can be transferred at process termination + by using the <seealso marker="#heir">heir</seealso> option or explicitly + by calling <seealso marker="#give_away/3">give_away/3</seealso>.</p> + <p>Some implementation details:</p> + <list type="bulleted"> + <item>In the current implementation, every object insert and + look-up operation results in a copy of the object.</item> + <item><c>'$end_of_table'</c> should not be used as a key since + this atom is used to mark the end of the table when using + <c>first</c>/<c>next</c>.</item> + </list> + <p>Also worth noting is the subtle difference between + <em>matching</em> and <em>comparing equal</em>, which is + demonstrated by the different table types <c>set</c> and + <c>ordered_set</c>. Two Erlang terms <c>match</c> if they are of + the same type and have the same value, so that <c>1</c> matches + <c>1</c>, but not <c>1.0</c> (as <c>1.0</c> is a <c>float()</c> + and not an <c>integer()</c>). Two Erlang terms <em>compare equal</em> if they either are of the same type and value, or if + both are numeric types and extend to the same value, so that + <c>1</c> compares equal to both <c>1</c> and <c>1.0</c>. The + <c>ordered_set</c> works on the <em>Erlang term order</em> and + there is no defined order between an <c>integer()</c> and a + <c>float()</c> that extends to the same value, hence the key + <c>1</c> and the key <c>1.0</c> are regarded as equal in an + <c>ordered_set</c> table.</p> + <p>In general, the functions below will exit with reason + <c>badarg</c> if any argument is of the wrong format, or if the + table identifier is invalid.</p> + </description> + + <section><marker id="concurrency"></marker> + <title>Concurrency</title> + <p>This module provides some limited support for concurrent access. + All updates to single objects are guaranteed to be both <em>atomic</em> + and <em>isolated</em>. This means that an updating operation towards + a single object will either succeed or fail completely without any + effect at all (atomicy). + Nor can any intermediate results of the update be seen by other + processes (isolation). Some functions that update several objects + state that they even guarantee atomicy and isolation for the entire + operation. In database terms the isolation level can be seen as + "serializable", as if all isolated operations were carried out serially, + one after the other in a strict order.</p> + <p>No other support is available within ETS that would guarantee + consistency between objects. However, the <c>safe_fixtable/2</c> + function can be used to guarantee that a sequence of + <c>first/1</c> and <c>next/2</c> calls will traverse the table + without errors and that each existing object in the table is visited + exactly once, even if another process (or the same process) + simultaneously deletes or inserts objects into the table. + Nothing more is guaranteed; in particular objects that are inserted + or deleted during such a traversal may be visited once or not at all. + Functions that internally traverse over a table, like <c>select</c> + and <c>match</c>, will give the same guarantee as <c>safe_fixtable</c>.</p> + </section> + <section> + <marker id="match_spec"></marker> + <title>Match Specifications</title> + <p>Some of the functions uses a <em>match specification</em>, + match_spec. A brief explanation is given in + <seealso marker="#select/2">select/2</seealso>. For a detailed + description, see the chapter "Match specifications in Erlang" in + <em>ERTS User's Guide</em>.</p> + </section> + + <section> + <title>DATA TYPES</title> + <code type="none"> +match_spec() + a match specification, see above + +tid() + a table identifier, as returned by new/2</code> + </section> + <funcs> + <func> + <name>all() -> [Tab]</name> + <fsummary>Return a list of all ETS tables.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + </type> + <desc> + <p>Returns a list of all tables at the node. Named tables are + given by their names, unnamed tables are given by their + table identifiers.</p> + </desc> + </func> + <func> + <name>delete(Tab) -> true</name> + <fsummary>Delete an entire ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + </type> + <desc> + <p>Deletes the entire table <c>Tab</c>.</p> + </desc> + </func> + <func> + <name>delete(Tab, Key) -> true</name> + <fsummary>Delete all objects with a given key from an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Key = term()</v> + </type> + <desc> + <p>Deletes all objects with the key <c>Key</c> from the table + <c>Tab</c>.</p> + </desc> + </func> + <func> + <name>delete_all_objects(Tab) -> true</name> + <fsummary>Delete all objects in an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + </type> + <desc> + <p>Delete all objects in the ETS table <c>Tab</c>. + The operation is guaranteed to be + <seealso marker="#concurrency">atomic and isolated</seealso>.</p> + </desc> + </func> + <func> + <name>delete_object(Tab,Object) -> true</name> + <fsummary>Deletes a specific from an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Object = tuple()</v> + </type> + <desc> + <p>Delete the exact object <c>Object</c> from the ETS table, + leaving objects with the same key but other differences + (useful for type <c>bag</c>). In a <c>duplicate_bag</c>, all + instances of the object will be deleted.</p> + </desc> + </func> + <func> + <name>file2tab(Filename) -> {ok,Tab} | {error,Reason}</name> + <fsummary>Read an ETS table from a file.</fsummary> + <type> + <v>Filename = string() | atom()</v> + <v>Tab = tid() | atom()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Reads a file produced by <seealso + marker="#tab2file/2">tab2file/2</seealso> or + <seealso marker="#tab2file/3">tab2file/3</seealso> and creates the + corresponding table <c>Tab</c>.</p> + <p>Equivalent to <c>file2tab(Filename,[])</c>.</p> + </desc> + </func> + <func> + <name>file2tab(Filename,Options) -> {ok,Tab} | {error,Reason}</name> + <fsummary>Read an ETS table from a file.</fsummary> + <type> + <v>Filename = string() | atom()</v> + <v>Tab = tid() | atom()</v> + <v>Options = [Option]</v> + <v>Option = {verify, bool()}</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Reads a file produced by <seealso + marker="#tab2file/2">tab2file/2</seealso> or + <seealso marker="#tab2file/3">tab2file/3</seealso> and creates the + corresponding table <c>Tab</c>.</p> + <p>The currently only supported option is <c>{verify,bool()}</c>. If + verification is turned on (by means of specifying + <c>{verify,true}</c>), the function utilizes whatever + information is present in the file to assert that the + information is not damaged. How this is done depends on which + <c>extended_info</c> was written using + <seealso marker="#tab2file/3">tab2file/3</seealso>.</p> + <p>If no <c>extended_info</c> is present in the file and + <c>{verify,true}</c> is specified, the number of objects + written is compared to the size of the original table when the + dump was started. This might make verification fail if the + table was + <c>public</c> and objects were added or removed while the + table was dumped to file. To avoid this type of problems, + either do not verify files dumped while updated simultaneously + or use the <c>{extended_info, [object_count]}</c> option to + <seealso marker="#tab2file/3">tab2file/3</seealso>, which + extends the information in the file with the number of objects + actually written.</p> + <p>If verification is turned on and the file was written with + the option <c>{extended_info, [md5sum]}</c>, reading the file + is slower and consumes radically more CPU time than + otherwise.</p> + <p><c>{verify,false}</c> is the default.</p> + </desc> + </func> + <func> + <name>first(Tab) -> Key | '$end_of_table'</name> + <fsummary>Return the first key in an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Key = term()</v> + </type> + <desc> + <p>Returns the first key <c>Key</c> in the table <c>Tab</c>. + If the table is of the <c>ordered_set</c> type, the first key + in Erlang term order will be returned. If the table is of any + other type, the first key according to the table's internal + order will be returned. If the table is empty, + <c>'$end_of_table'</c> will be returned.</p> + <p>Use <c>next/2</c> to find subsequent keys in the table.</p> + </desc> + </func> + <func> + <name>foldl(Function, Acc0, Tab) -> Acc1</name> + <fsummary>Fold a function over an ETS table</fsummary> + <type> + <v>Function = fun(A, AccIn) -> AccOut</v> + <v>Tab = tid() | atom()</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + </type> + <desc> + <p><c>Acc0</c> is returned if the table is empty. + This function is similar to <c>lists:foldl/3</c>. The order in + which the elements of the table are traversed is unspecified, + except for tables of type <c>ordered_set</c>, for which they + are traversed first to last.</p> + + <p>If <c>Function</c> inserts objects into the table, or another + process inserts objects into the table, those objects <em>may</em> + (depending on key ordering) be included in the traversal.</p> + </desc> + </func> + <func> + <name>foldr(Function, Acc0, Tab) -> Acc1</name> + <fsummary>Fold a function over an ETS table</fsummary> + <type> + <v>Function = fun(A, AccIn) -> AccOut</v> + <v>Tab = tid() | atom()</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + </type> + <desc> + <p><c>Acc0</c> is returned if the table is empty. + This function is similar to <c>lists:foldr/3</c>. The order in + which the elements of the table are traversed is unspecified, + except for tables of type <c>ordered_set</c>, for which they + are traversed last to first.</p> + + <p>If <c>Function</c> inserts objects into the table, or another + process inserts objects into the table, those objects <em>may</em> + (depending on key ordering) be included in the traversal.</p> + </desc> + </func> + <func> + <name>from_dets(Tab, DetsTab) -> true</name> + <fsummary>Fill an ETS table with objects from a Dets table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>DetsTab = atom()</v> + </type> + <desc> + <p>Fills an already created ETS table with the objects in the + already opened Dets table named <c>DetsTab</c>. The existing + objects of the ETS table are kept unless overwritten.</p> + <p>Throws a badarg error if any of the tables does not exist or the + dets table is not open.</p> + </desc> + </func> + <func> + <name>fun2ms(LiteralFun) -> MatchSpec</name> + <fsummary>Pseudo function that transforms fun syntax to a match_spec.</fsummary> + <type> + <v>LiteralFun -- see below</v> + <v>MatchSpec = match_spec()</v> + </type> + <desc> + <p>Pseudo function that by means of a <c>parse_transform</c> + translates <c>LiteralFun</c> typed as parameter in the + function call to a + <seealso marker="#match_spec">match_spec</seealso>. With + "literal" is meant that the fun needs to textually be written + as the parameter of the function, it cannot be held in a + variable which in turn is passed to the function).</p> + <p>The parse transform is implemented in the module + <c>ms_transform</c> and the source <em>must</em> include the + file <c>ms_transform.hrl</c> in <c>stdlib</c> for this + pseudo function to work. Failing to include the hrl file in + the source will result in a runtime error, not a compile + time ditto. The include file is easiest included by adding + the line + <c>-include_lib("stdlib/include/ms_transform.hrl").</c> to + the source file.</p> + <p>The fun is very restricted, it can take only a single + parameter (the object to match): a sole variable or a + tuple. It needs to use the <c>is_</c>XXX guard tests. + Language constructs that have no representation + in a match_spec (like <c>if</c>, <c>case</c>, <c>receive</c> + etc) are not allowed.</p> + <p>The return value is the resulting match_spec.</p> + <p>Example:</p> + <pre> +1> <input>ets:fun2ms(fun({M,N}) when N > 3 -> M end).</input> +[{{'$1','$2'},[{'>','$2',3}],['$1']}]</pre> + <p>Variables from the environment can be imported, so that this + works:</p> + <pre> +2> <input>X=3.</input> +3 +3> <input>ets:fun2ms(fun({M,N}) when N > X -> M end).</input> +[{{'$1','$2'},[{'>','$2',{const,3}}],['$1']}]</pre> + <p>The imported variables will be replaced by match_spec + <c>const</c> expressions, which is consistent with the + static scoping for Erlang funs. Local or global function + calls can not be in the guard or body of the fun however. + Calls to builtin match_spec functions of course is allowed:</p> + <pre> +4> <input>ets:fun2ms(fun({M,N}) when N > X, is_atomm(M) -> M end).</input> +Error: fun containing local Erlang function calls +('is_atomm' called in guard) cannot be translated into match_spec +{error,transform_error} +5> <input>ets:fun2ms(fun({M,N}) when N > X, is_atom(M) -> M end).</input> +[{{'$1','$2'},[{'>','$2',{const,3}},{is_atom,'$1'}],['$1']}]</pre> + <p>As can be seen by the example, the function can be called + from the shell too. The fun needs to be literally in the call + when used from the shell as well. Other means than the + parse_transform are used in the shell case, but more or less + the same restrictions apply (the exception being records, + as they are not handled by the shell).</p> + <warning> + <p>If the parse_transform is not applied to a module which + calls this pseudo function, the call will fail in runtime + (with a <c>badarg</c>). The module <c>ets</c> actually + exports a function with this name, but it should never + really be called except for when using the function in the + shell. If the <c>parse_transform</c> is properly applied by + including the <c>ms_transform.hrl</c> header file, compiled + code will never call the function, but the function call is + replaced by a literal match_spec.</p> + </warning> + <p>For more information, see + <seealso marker="ms_transform#top">ms_transform(3)</seealso>.</p> + </desc> + </func> + <func> + <name>give_away(Tab, Pid, GiftData) -> true</name> + <fsummary>Change owner of a table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Pid = pid()</v> + <v>GiftData = term()</v> + </type> + <desc> + <p>Make process <c>Pid</c> the new owner of table <c>Tab</c>. + If successful, the message + <c>{'ETS-TRANSFER',Tab,FromPid,GiftData}</c> will be sent + to the new owner.</p> + <p>The process <c>Pid</c> must be alive, local and not already the + owner of the table. The calling process must be the table owner.</p> + <p>Note that <c>give_away</c> does not at all affect the + <seealso marker="#heir">heir</seealso> option of the table. A table + owner can for example set the <c>heir</c> to itself, give the table + away and then get it back in case the receiver terminates.</p> + </desc> + </func> + <func> + <name>i() -> ok</name> + <fsummary>Display information about all ETS tables on tty.</fsummary> + <desc> + <p>Displays information about all ETS tables on tty.</p> + </desc> + </func> + <func> + <name>i(Tab) -> ok</name> + <fsummary>Browse an ETS table on tty.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + </type> + <desc> + <p>Browses the table <c>Tab</c> on tty.</p> + </desc> + </func> + <func> + <name>info(Tab) -> [{Item, Value}] | undefined</name> + <fsummary>Return information about an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Item = atom(), see below</v> + <v>Value = term(), see below</v> + </type> + <desc> + <p>Returns information about the table <c>Tab</c> as a list of + <c>{Item, Value}</c> tuples. If <c>Tab</c> has the correct type + for a table identifier, but does not refer to an existing ETS + table, <c>undefined</c> is returned. If <c>Tab</c> is not of the + correct type, this function fails with reason <c>badarg</c>.</p> + + <list type="bulleted"> + <item><c>Item=memory, Value=int()</c> <br></br> + + The number of words allocated to the table.</item> + <item><c>Item=owner, Value=pid()</c> <br></br> + + The pid of the owner of the table.</item> + <item><c>Item=heir, Value=pid()|none</c> <br></br> + + The pid of the heir of the table, or <c>none</c> if no heir is set.</item> + <item><c>Item=name, Value=atom()</c> <br></br> + + The name of the table.</item> + <item><c>Item=size, Value=int()</c> <br></br> + + The number of objects inserted in the table.</item> + <item><c>Item=node, Value=atom()</c> <br></br> + + The node where the table is stored. This field is no longer + meaningful as tables cannot be accessed from other nodes.</item> + <item><c>Item=named_table, Value=true|false</c> <br></br> + + Indicates if the table is named or not.</item> + <item><c>Item=type, Value=set|ordered_set|bag|duplicate_bag</c> <br></br> + + The table type.</item> + <item><c>Item=keypos, Value=int()</c> <br></br> + + The key position.</item> + <item><c>Item=protection, Value=public|protected|private</c> <br></br> + + The table access rights.</item> + </list> + </desc> + </func> + <func> + <name>info(Tab, Item) -> Value | undefined</name> + <fsummary>Return the information associated with given item for an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Item, Value - see below</v> + </type> + <desc> + <p>Returns the information associated with <c>Item</c> for + the table <c>Tab</c>, or returns <c>undefined</c> if <c>Tab</c> + does not refer an existing ETS table. + If <c>Tab</c> is not of the correct type, or if <c>Item</c> is not + one of the allowed values, this function fails with reason <c>badarg</c>.</p> + + <warning><p>In R11B and earlier, this function would not fail but return + <c>undefined</c> for invalid values for <c>Item</c>.</p> + </warning> + + <p>In addition to the <c>{Item,Value}</c> + pairs defined for <c>info/1</c>, the following items are + allowed:</p> + <list type="bulleted"> + <item><c>Item=fixed, Value=true|false</c> <br></br> + + Indicates if the table is fixed by any process or not.</item> + <item> + <p><c>Item=safe_fixed, Value={FirstFixed,Info}|false</c> <br></br> +</p> + <p>If the table has been fixed using <c>safe_fixtable/2</c>, + the call returns a tuple where <c>FirstFixed</c> is the + time when the table was first fixed by a process, which + may or may not be one of the processes it is fixed by + right now.</p> + <p><c>Info</c> is a possibly empty lists of tuples + <c>{Pid,RefCount}</c>, one tuple for every process the + table is fixed by right now. <c>RefCount</c> is the value + of the reference counter, keeping track of how many times + the table has been fixed by the process.</p> + <p>If the table never has been fixed, the call returns + <c>false</c>.</p> + </item> + </list> + </desc> + </func> + <func> + <name>init_table(Name, InitFun) -> true</name> + <fsummary>Replace all objects of an ETS table.</fsummary> + <type> + <v>Name = atom()</v> + <v>InitFun = fun(Arg) -> Res</v> + <v>Arg = read | close</v> + <v>Res = end_of_input | {[object()], InitFun} | term()</v> + </type> + <desc> + <p>Replaces the existing objects of the table <c>Tab</c> with + objects created by calling the input function <c>InitFun</c>, + see below. This function is provided for compatibility with + the <c>dets</c> module, it is not more efficient than filling + a table by using <c>ets:insert/2</c>. + </p> + <p>When called with the argument <c>read</c> the function + <c>InitFun</c> is assumed to return <c>end_of_input</c> when + there is no more input, or <c>{Objects, Fun}</c>, where + <c>Objects</c> is a list of objects and <c>Fun</c> is a new + input function. Any other value Value is returned as an error + <c>{error, {init_fun, Value}}</c>. Each input function will be + called exactly once, and should an error occur, the last + function is called with the argument <c>close</c>, the reply + of which is ignored.</p> + <p>If the type of the table is <c>set</c> and there is more + than one object with a given key, one of the objects is + chosen. This is not necessarily the last object with the given + key in the sequence of objects returned by the input + functions. This holds also for duplicated + objects stored in tables of type <c>bag</c>.</p> + </desc> + </func> + <func> + <name>insert(Tab, ObjectOrObjects) -> true</name> + <fsummary>Insert an object into an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>ObjectOrObjects = tuple() | [tuple()]</v> + </type> + <desc> + <p>Inserts the object or all of the objects in the list + <c>ObjectOrObjects</c> into the table <c>Tab</c>. + If the table is a <c>set</c> and the key of the inserted + objects <em>matches</em> the key of any object in the table, + the old object will be replaced. If the table is an + <c>ordered_set</c> and the key of the inserted object + <em>compares equal</em> to the key of any object in the + table, the old object is also replaced. If the list contains + more than one object with <em>matching</em> keys and the table is a + <c>set</c>, one will be inserted, which one is + not defined. The same thing holds for <c>ordered_set</c>, but + will also happen if the keys <em>compare equal</em>.</p> + <p>The entire operation is guaranteed to be + <seealso marker="#concurrency">atomic and isolated</seealso>, + even when a list of objects is inserted.</p> + </desc> + </func> + <func> + <name>insert_new(Tab, ObjectOrObjects) -> bool()</name> + <fsummary>Insert an object into an ETS table if the key is not already present.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>ObjectOrObjects = tuple() | [tuple()]</v> + </type> + <desc> + <p>This function works exactly like <c>insert/2</c>, with the + exception that instead of overwriting objects with the same + key (in the case of <c>set</c> or <c>ordered_set</c>) or + adding more objects with keys already existing in the table + (in the case of <c>bag</c> and <c>duplicate_bag</c>), it + simply returns <c>false</c>. If <c>ObjectOrObjects</c> is a + list, the function checks <em>every</em> key prior to + inserting anything. Nothing will be inserted if not + <em>all</em> keys present in the list are absent from the + table. Like <c>insert/2</c>, the entire operation is guaranteed to be + <seealso marker="#concurrency">atomic and isolated</seealso>.</p> + </desc> + </func> + <func> + <name>is_compiled_ms(Term) -> bool()</name> + <fsummary>Checks if an Erlang term is the result of ets:match_spec_compile</fsummary> + <type> + <v>Term = term()</v> + </type> + <desc> + <p>This function is used to check if a term is a valid + compiled <seealso marker="#match_spec">match_spec</seealso>. + The compiled match_spec is an opaque datatype which can + <em>not</em> be sent between Erlang nodes nor be stored on + disk. Any attempt to create an external representation of a + compiled match_spec will result in an empty binary + (<c><![CDATA[<<>>]]></c>). As an example, the following + expression:</p> + <code type="none"> +ets:is_compiled_ms(ets:match_spec_compile([{'_',[],[true]}])).</code> + <p>will yield <c>true</c>, while the following expressions:</p> + <code type="none"> +MS = ets:match_spec_compile([{'_',[],[true]}]), +Broken = binary_to_term(term_to_binary(MS)), +ets:is_compiled_ms(Broken).</code> + <p>will yield false, as the variable <c>Broken</c> will contain + a compiled match_spec that has passed through external + representation.</p> + <note> + <p>The fact that compiled match_specs has no external + representation is for performance reasons. It may be subject + to change in future releases, while this interface will + still remain for backward compatibility reasons.</p> + </note> + </desc> + </func> + <func> + <name>last(Tab) -> Key | '$end_of_table'</name> + <fsummary>Return the last key in an ETS table of type<c>ordered_set</c>.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Key = term()</v> + </type> + <desc> + <p>Returns the last key <c>Key</c> according to Erlang term + order in the table <c>Tab</c> of the <c>ordered_set</c> type. + If the table is of any other type, the function is synonymous + to <c>first/2</c>. If the table is empty, + <c>'$end_of_table'</c> is returned.</p> + <p>Use <c>prev/2</c> to find preceding keys in the table.</p> + </desc> + </func> + <func> + <name>lookup(Tab, Key) -> [Object]</name> + <fsummary>Return all objects with a given key in an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Key = term()</v> + <v>Object = tuple()</v> + </type> + <desc> + <p>Returns a list of all objects with the key <c>Key</c> in + the table <c>Tab</c>.</p> + <p>In the case of <c>set, bag and duplicate_bag</c>, an object + is returned only if the given key <em>matches</em> the key + of the object in the table. If the table is an + <c>ordered_set</c> however, an object is returned if the key + given <em>compares equal</em> to the key of an object in the + table. The difference being the same as between <c>=:=</c> + and <c>==</c>. As an example, one might insert an object + with the + <c>integer()</c><c>1</c> as a key in an <c>ordered_set</c> + and get the object returned as a result of doing a + <c>lookup/2</c> with the <c>float()</c><c>1.0</c> as the + key to search for.</p> + <p>If the table is of type <c>set</c> or <c>ordered_set</c>, + the function returns either the empty list or a list with one + element, as there cannot be more than one object with the same + key. If the table is of type <c>bag</c> or + <c>duplicate_bag</c>, the function returns a list of + arbitrary length.</p> + <p>Note that the time order of object insertions is preserved; + The first object inserted with the given key will be first + in the resulting list, and so on.</p> + <p>Insert and look-up times in tables of type <c>set</c>, + <c>bag</c> and <c>duplicate_bag</c> are constant, regardless + of the size of the table. For the <c>ordered_set</c> + data-type, time is proportional to the (binary) logarithm of + the number of objects.</p> + </desc> + </func> + <func> + <name>lookup_element(Tab, Key, Pos) -> Elem</name> + <fsummary>Return the <c>Pos</c>:th element of all objects with a given key in an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Key = term()</v> + <v>Pos = int()</v> + <v>Elem = term() | [term()]</v> + </type> + <desc> + <p>If the table <c>Tab</c> is of type <c>set</c> or + <c>ordered_set</c>, the function returns the <c>Pos</c>:th + element of the object with the key <c>Key</c>.</p> + <p>If the table is of type <c>bag</c> or <c>duplicate_bag</c>, + the functions returns a list with the <c>Pos</c>:th element of + every object with the key <c>Key</c>.</p> + <p>If no object with the key <c>Key</c> exists, the function + will exit with reason <c>badarg</c>.</p> + <p>The difference between <c>set</c>, <c>bag</c> and + <c>duplicate_bag</c> on one hand, and <c>ordered_set</c> on + the other, regarding the fact that <c>ordered_set</c>'s + view keys as equal when they <em>compare equal</em> + whereas the other table types only regard them equal when + they <em>match</em>, naturally holds for + <c>lookup_element</c> as well as for <c>lookup</c>.</p> + </desc> + </func> + <func> + <name>match(Tab, Pattern) -> [Match]</name> + <fsummary>Match the objects in an ETS table against a pattern.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Pattern = tuple()</v> + <v>Match = [term()]</v> + </type> + <desc> + <p>Matches the objects in the table <c>Tab</c> against the + pattern <c>Pattern</c>.</p> + <p>A pattern is a term that may contain:</p> + <list type="bulleted"> + <item>bound parts (Erlang terms),</item> + <item><c>'_'</c> which matches any Erlang term, and</item> + <item>pattern variables: <c>'$N'</c> where + <c>N</c>=0,1,...</item> + </list> + <p>The function returns a list with one element for each + matching object, where each element is an ordered list of + pattern variable bindings. An example:</p> + <pre> +6> <input>ets:match(T, '$1').</input> % Matches every object in the table +[[{rufsen,dog,7}],[{brunte,horse,5}],[{ludde,dog,5}]] +7> <input>ets:match(T, {'_',dog,'$1'}).</input> +[[7],[5]] +8> <input>ets:match(T, {'_',cow,'$1'}).</input> +[]</pre> + <p>If the key is specified in the pattern, the match is very + efficient. If the key is not specified, i.e. if it is a + variable or an underscore, the entire table must be searched. + The search time can be substantial if the table is very large.</p> + <p>On tables of the <c>ordered_set</c> type, the result is in + the same order as in a <c>first/next</c> traversal.</p> + </desc> + </func> + <func> + <name>match(Tab, Pattern, Limit) -> {[Match],Continuation} | '$end_of_table'</name> + <fsummary>Match the objects in an ETS table against a pattern and returns part of the answers.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Pattern = tuple()</v> + <v>Match = [term()]</v> + <v>Continuation = term()</v> + </type> + <desc> + <p>Works like <c>ets:match/2</c> but only returns a limited + (<c>Limit</c>) number of matching objects. The + <c>Continuation</c> term can then be used in subsequent calls + to <c>ets:match/1</c> to get the next chunk of matching + objects. This is a space efficient way to work on objects in a + table which is still faster than traversing the table object + by object using <c>ets:first/1</c> and <c>ets:next/1</c>.</p> + <p><c>'$end_of_table'</c> is returned if the table is empty.</p> + </desc> + </func> + <func> + <name>match(Continuation) -> {[Match],Continuation} | '$end_of_table'</name> + <fsummary>Continues matching objects in an ETS table.</fsummary> + <type> + <v>Match = [term()]</v> + <v>Continuation = term()</v> + </type> + <desc> + <p>Continues a match started with <c>ets:match/3</c>. The next + chunk of the size given in the initial <c>ets:match/3</c> + call is returned together with a new <c>Continuation</c> + that can be used in subsequent calls to this function.</p> + <p><c>'$end_of_table'</c> is returned when there are no more + objects in the table.</p> + </desc> + </func> + <func> + <name>match_delete(Tab, Pattern) -> true</name> + <fsummary>Delete all objects which match a given pattern from an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Pattern = tuple()</v> + </type> + <desc> + <p>Deletes all objects which match the pattern <c>Pattern</c> + from the table <c>Tab</c>. See <c>match/2</c> for a + description of patterns.</p> + </desc> + </func> + <func> + <name>match_object(Tab, Pattern) -> [Object]</name> + <fsummary>Match the objects in an ETS table against a pattern.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Pattern = Object = tuple()</v> + </type> + <desc> + <p>Matches the objects in the table <c>Tab</c> against the + pattern <c>Pattern</c>. See <c>match/2</c> for a description + of patterns. The function returns a list of all objects which + match the pattern.</p> + <p>If the key is specified in the pattern, the match is very + efficient. If the key is not specified, i.e. if it is a + variable or an underscore, the entire table must be searched. + The search time can be substantial if the table is very large.</p> + <p>On tables of the <c>ordered_set</c> type, the result is in + the same order as in a <c>first/next</c> traversal.</p> + </desc> + </func> + <func> + <name>match_object(Tab, Pattern, Limit) -> {[Match],Continuation} | '$end_of_table'</name> + <fsummary>Match the objects in an ETS table against a pattern and returns part of the answers.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Pattern = tuple()</v> + <v>Match = [term()]</v> + <v>Continuation = term()</v> + </type> + <desc> + <p>Works like <c>ets:match_object/2</c> but only returns a + limited (<c>Limit</c>) number of matching objects. The + <c>Continuation</c> term can then be used in subsequent calls + to <c>ets:match_object/1</c> to get the next chunk of matching + objects. This is a space efficient way to work on objects in a + table which is still faster than traversing the table object + by object using <c>ets:first/1</c> and <c>ets:next/1</c>.</p> + <p><c>'$end_of_table'</c> is returned if the table is empty.</p> + </desc> + </func> + <func> + <name>match_object(Continuation) -> {[Match],Continuation} | '$end_of_table'</name> + <fsummary>Continues matching objects in an ETS table.</fsummary> + <type> + <v>Match = [term()]</v> + <v>Continuation = term()</v> + </type> + <desc> + <p>Continues a match started with <c>ets:match_object/3</c>. + The next chunk of the size given in the initial + <c>ets:match_object/3</c> call is returned together with a + new <c>Continuation</c> that can be used in subsequent calls + to this function.</p> + <p><c>'$end_of_table'</c> is returned when there are no more + objects in the table.</p> + </desc> + </func> + <func> + <name>match_spec_compile(MatchSpec) -> CompiledMatchSpec</name> + <fsummary>Compiles a match specification into its internal representation</fsummary> + <type> + <v>MatchSpec = match_spec()</v> + <v>CompiledMatchSpec = comp_match_spec()</v> + </type> + <desc> + <p>This function transforms a + <seealso marker="#match_spec">match_spec</seealso> into an + internal representation that can be used in subsequent calls + to <c>ets:match_spec_run/2</c>. The internal representation is + opaque and can not be converted to external term format and + then back again without losing its properties (meaning it can + not be sent to a process on another node and still remain a + valid compiled match_spec, nor can it be stored on disk). + The validity of a compiled match_spec can be checked using + <c>ets:is_compiled_ms/1</c>.</p> + <p>If the term <c>MatchSpec</c> can not be compiled (does not + represent a valid match_spec), a <c>badarg</c> fault is + thrown.</p> + <note> + <p>This function has limited use in normal code, it is used by + Dets to perform the <c>dets:select</c> operations.</p> + </note> + </desc> + </func> + <func> + <name>match_spec_run(List,CompiledMatchSpec) -> list()</name> + <fsummary>Performs matching, using a compiled match_spec, on a list of tuples</fsummary> + <type> + <v>List = [ tuple() ]</v> + <v>CompiledMatchSpec = comp_match_spec()</v> + </type> + <desc> + <p>This function executes the matching specified in a + compiled <seealso marker="#match_spec">match_spec</seealso> on + a list of tuples. The <c>CompiledMatchSpec</c> term should be + the result of a call to <c>ets:match_spec_compile/1</c> and + is hence the internal representation of the match_spec one + wants to use.</p> + <p>The matching will be executed on each element in <c>List</c> + and the function returns a list containing all results. If an + element in <c>List</c> does not match, nothing is returned + for that element. The length of the result list is therefore + equal or less than the the length of the parameter + <c>List</c>. The two calls in the following example will give + the same result (but certainly not the same execution + time...):</p> + <code type="none"> +Table = ets:new... +MatchSpec = .... +% The following call... +ets:match_spec_run(ets:tab2list(Table), +ets:match_spec_compile(MatchSpec)), +% ...will give the same result as the more common (and more efficient) +ets:select(Table,MatchSpec),</code> + <note> + <p>This function has limited use in normal code, it is used by + Dets to perform the <c>dets:select</c> operations and by + Mnesia during transactions.</p> + </note> + </desc> + </func> + <func> + <name>member(Tab, Key) -> true | false</name> + <fsummary>Tests for occurrence of a key in an ETS table</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Key = term()</v> + </type> + <desc> + <p>Works like <c>lookup/2</c>, but does not return the objects. + The function returns <c>true</c> if one or more elements in + the table has the key <c>Key</c>, <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>new(Name, Options) -> tid() | atom()</name> + <fsummary>Create a new ETS table.</fsummary> + <type> + <v>Name = atom()</v> + <v>Options = [Option]</v> + <v> Option = Type | Access | named_table | {keypos,Pos} | {heir,pid(),HeirData} | {heir,none} | {write_concurrency,bool()}</v> + <v> Type = set | ordered_set | bag | duplicate_bag</v> + <v> Access = public | protected | private</v> + <v> Pos = int()</v> + <v> HeirData = term()</v> + </type> + <desc> + <p>Creates a new table and returns a table identifier which can + be used in subsequent operations. The table identifier can be + sent to other processes so that a table can be shared between + different processes within a node.</p> + <p>The parameter <c>Options</c> is a list of atoms which + specifies table type, access rights, key position and if the + table is named or not. If one or more options are left out, + the default values are used. This means that not specifying + any options (<c>[]</c>) is the same as specifying + <c>[set,protected,{keypos,1},{heir,none},{write_concurrency,false}]</c>.</p> + <list type="bulleted"> + <item> + <p><c>set</c> + The table is a <c>set</c> table - one key, one object, + no order among objects. This is the default table type.</p> + </item> + <item> + <p><c>ordered_set</c> + The table is a <c>ordered_set</c> table - one key, one + object, ordered in Erlang term order, which is the order + implied by the < and > operators. Tables of this type + have a somewhat different behavior in some situations + than tables of the other types. Most notably the + <c>ordered_set</c> tables regard keys as equal when they + <em>compare equal</em>, not only when they match. This + means that to an <c>ordered_set</c>, the + <c>integer()</c><c>1</c> and the <c>float()</c><c>1.0</c> are regarded as equal. This also means that the + key used to lookup an element not necessarily + <em>matches</em> the key in the elements returned, if + <c>float()</c>'s and <c>integer()</c>'s are mixed in + keys of a table.</p> + </item> + <item> + <p><c>bag</c> + The table is a <c>bag</c> table which can have many + objects, but only one instance of each object, per key.</p> + </item> + <item> + <p><c>duplicate_bag</c> + The table is a <c>duplicate_bag</c> table which can have + many objects, including multiple copies of the same + object, per key.</p> + </item> + <item> + <p><c>public</c> + Any process may read or write to the table.</p> + </item> + <item> + <p><c>protected</c> + The owner process can read and write to the table. Other + processes can only read the table. This is the default + setting for the access rights.</p> + </item> + <item> + <p><c>private</c> + Only the owner process can read or write to the table.</p> + </item> + <item> + <p><c>named_table</c> + If this option is present, the name <c>Name</c> is + associated with the table identifier. The name can then + be used instead of the table identifier in subsequent + operations.</p> + </item> + <item> + <p><c>{keypos,Pos}</c> + Specfies which element in the stored tuples should be + used as key. By default, it is the first element, i.e. + <c>Pos=1</c>. However, this is not always appropriate. In + particular, we do not want the first element to be the + key if we want to store Erlang records in a table.</p> + <p>Note that any tuple stored in the table must have at + least <c>Pos</c> number of elements.</p> + </item> + <item> + <marker id="heir"></marker> + <p><c>{heir,Pid,HeirData} | {heir,none}</c><br></br> + Set a process as heir. The heir will inherit the table if + the owner terminates. The message + <c>{'ETS-TRANSFER',tid(),FromPid,HeirData}</c> will be sent to + the heir when that happens. The heir must be a local process. + Default heir is <c>none</c>, which will destroy the table when + the owner terminates.</p> + </item> + <item> + <p><c>{write_concurrency,bool()}</c> + Performance tuning. Default is <c>false</c>, which means that the table + is optimized towards concurrent read access. An operation that + mutates (writes to) the table will obtain exclusive access, + blocking any concurrent access of the same table until finished. + If set to <c>true</c>, the table is optimized towards concurrent + write access. Different objects of the same table can be mutated + (and read) by concurrent processes. This is achieved to some degree + at the expense of single access and concurrent reader performance. + Note that this option does not change any guarantees about + <seealso marker="#concurrency">atomicy and isolation</seealso>. + Functions that makes such promises over several objects (like + <c>insert/2</c>) will gain less (or nothing) from this option.</p> + <p>Table type <c>ordered_set</c> is not affected by this option in current + implementation.</p> + </item> + </list> + </desc> + </func> + <func> + <name>next(Tab, Key1) -> Key2 | '$end_of_table'</name> + <fsummary>Return the next key in an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Key1 = Key2 = term()</v> + </type> + <desc> + <p>Returns the next key <c>Key2</c>, following the key + <c>Key1</c> in the table <c>Tab</c>. If the table is of the + <c>ordered_set</c> type, the next key in Erlang term order is + returned. If the table is of any other type, the next key + according to the table's internal order is returned. If there + is no next key, <c>'$end_of_table'</c> is returned.</p> + <p>Use <c>first/1</c> to find the first key in the table.</p> + <p>Unless a table of type <c>set</c>, <c>bag</c> or + <c>duplicate_bag</c> is protected using + <c>safe_fixtable/2</c>, see below, a traversal may fail if + concurrent updates are made to the table. If the table is of + type <c>ordered_set</c>, the function returns the next key in + order, even if the object does no longer exist.</p> + </desc> + </func> + <func> + <name>prev(Tab, Key1) -> Key2 | '$end_of_table'</name> + <fsummary>Return the previous key in an ETS table of type<c>ordered_set</c>.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Key1 = Key2 = term()</v> + </type> + <desc> + <p>Returns the previous key <c>Key2</c>, preceding the key + <c>Key1</c> according the Erlang term order in the table + <c>Tab</c> of the <c>ordered_set</c> type. If the table is of + any other type, the function is synonymous to <c>next/2</c>. + If there is no previous key, <c>'$end_of_table'</c> is + returned.</p> + <p>Use <c>last/1</c> to find the last key in the table.</p> + </desc> + </func> + <func> + <name>rename(Tab, Name) -> Name</name> + <fsummary>Rename a named ETS table.</fsummary> + <type> + <v>Tab = Name = atom()</v> + </type> + <desc> + <p>Renames the named table <c>Tab</c> to the new name + <c>Name</c>. Afterwards, the old name can not be used to + access the table. Renaming an unnamed table has no effect.</p> + </desc> + </func> + <func> + <name>repair_continuation(Continuation, MatchSpec) -> Continuation</name> + <fsummary>Repair a continuation from ets:select/1 or ets:select/3 that has passed through external representation</fsummary> + <type> + <v>Continuation = term()</v> + <v>MatchSpec = match_spec()</v> + </type> + <desc> + <p>This function can be used to restore an opaque continuation + returned by <c>ets:select/3</c> or <c>ets:select/1</c> if the + continuation has passed through external term format (been + sent between nodes or stored on disk).</p> + <p>The reason for this function is that continuation terms + contain compiled match_specs and therefore will be + invalidated if converted to external term format. Given that + the original match_spec is kept intact, the continuation can + be restored, meaning it can once again be used in subsequent + <c>ets:select/1</c> calls even though it has been stored on + disk or on another node.</p> + <p>As an example, the following sequence of calls will fail:</p> + <code type="none"> +T=ets:new(x,[]), +... +{_,C} = ets:select(T,ets:fun2ms(fun({N,_}=A) +when (N rem 10) =:= 0 -> +A +end),10), +Broken = binary_to_term(term_to_binary(C)), +ets:select(Broken).</code> + <p>...while the following sequence will work:</p> + <code type="none"> +T=ets:new(x,[]), +... +MS = ets:fun2ms(fun({N,_}=A) +when (N rem 10) =:= 0 -> +A +end), +{_,C} = ets:select(T,MS,10), +Broken = binary_to_term(term_to_binary(C)), +ets:select(ets:repair_continuation(Broken,MS)).</code> + <p>...as the call to <c>ets:repair_continuation/2</c> will + reestablish the (deliberately) invalidated continuation + <c>Broken</c>.</p> + <note> + <p>This function is very rarely needed in application code. It + is used by Mnesia to implement distributed <c>select/3</c> + and <c>select/1</c> sequences. A normal application would + either use Mnesia or keep the continuation from being + converted to external format.</p> + <p>The reason for not having an external representation of a + compiled match_spec is performance. It may be subject to + change in future releases, while this interface will remain + for backward compatibility.</p> + </note> + </desc> + </func> + <func> + <name>safe_fixtable(Tab, true|false) -> true</name> + <fsummary>Fix an ETS table for safe traversal.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + </type> + <desc> + <p>Fixes a table of the <c>set</c>, <c>bag</c> or + <c>duplicate_bag</c> table type for safe traversal.</p> + <p>A process fixes a table by calling + <c>safe_fixtable(Tab,true)</c>. The table remains fixed until + the process releases it by calling + <c>safe_fixtable(Tab,false)</c>, or until the process + terminates.</p> + <p>If several processes fix a table, the table will remain fixed + until all processes have released it (or terminated). + A reference counter is kept on a per process basis, and N + consecutive fixes requires N releases to actually release + the table.</p> + <p>When a table is fixed, a sequence of <c>first/1</c> and + <c>next/2</c> calls are guaranteed to succeed and each object in + the table will only be returned once, even if objects + are removed or inserted during the traversal. + The keys for new objects inserted during the traversal <em>may</em> + be returned by <seealso marker="#next/2">next/2</seealso> + (it depends on the internal ordering of the keys). An example:</p> + <code type="none"> +clean_all_with_value(Tab,X) -> + safe_fixtable(Tab,true), + clean_all_with_value(Tab,X,ets:first(Tab)), + safe_fixtable(Tab,false). + +clean_all_with_value(Tab,X,'$end_of_table') -> + true; +clean_all_with_value(Tab,X,Key) -> + case ets:lookup(Tab,Key) of + [{Key,X}] -> + ets:delete(Tab,Key); + _ -> + true + end, + clean_all_with_value(Tab,X,ets:next(Tab,Key)).</code> + <p>Note that no deleted objects are actually removed from a + fixed table until it has been released. If a process fixes a + table but never releases it, the memory used by the deleted + objects will never be freed. The performance of operations on + the table will also degrade significantly.</p> + <p>Use <c>info/2</c> to retrieve information about which + processes have fixed which tables. A system with a lot of + processes fixing tables may need a monitor which sends alarms + when tables have been fixed for too long.</p> + <p>Note that for tables of the <c>ordered_set</c> type, + <c>safe_fixtable/2</c> is not necessary as calls to + <c>first/1</c> and <c>next/2</c> will always succeed.</p> + </desc> + </func> + <func> + <name>select(Tab, MatchSpec) -> [Match]</name> + <fsummary>Match the objects in an ETS table against a match_spec.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Match = term()</v> + <v>MatchSpec = match_spec()</v> + </type> + <desc> + <p>Matches the objects in the table <c>Tab</c> using a + <seealso marker="#match_spec">match_spec</seealso>. This is a + more general call than the <c>ets:match/2</c> and + <c>ets:match_object/2</c> calls. In its simplest forms the + match_specs look like this:</p> + <list type="bulleted"> + <item>MatchSpec = [MatchFunction]</item> + <item>MatchFunction = {MatchHead, [Guard], [Result]}</item> + <item>MatchHead = "Pattern as in ets:match"</item> + <item>Guard = {"Guardtest name", ...}</item> + <item>Result = "Term construct"</item> + </list> + <p>This means that the match_spec is always a list of one or + more tuples (of arity 3). The tuples first element should be + a pattern as described in the documentation of + <c>ets:match/2</c>. The second element of the tuple should + be a list of 0 or more guard tests (described below). The + third element of the tuple should be a list containing a + description of the value to actually return. In almost all + normal cases the list contains exactly one term which fully + describes the value to return for each object.</p> + <p>The return value is constructed using the "match variables" + bound in the MatchHead or using the special match variables + <c>'$_'</c> (the whole matching object) and <c>'$$'</c> (all + match variables in a list), so that the following + <c>ets:match/2</c> expression:</p> + <code type="none"> +ets:match(Tab,{'$1','$2','$3'})</code> + <p>is exactly equivalent to:</p> + <code type="none"> +ets:select(Tab,[{{'$1','$2','$3'},[],['$$']}])</code> + <p>- and the following <c>ets:match_object/2</c> call:</p> + <code type="none"> +ets:match_object(Tab,{'$1','$2','$1'})</code> + <p>is exactly equivalent to</p> + <code type="none"> +ets:select(Tab,[{{'$1','$2','$1'},[],['$_']}])</code> + <p>Composite terms can be constructed in the <c>Result</c> part + either by simply writing a list, so that this code:</p> + <code type="none"> +ets:select(Tab,[{{'$1','$2','$3'},[],['$$']}])</code> + <p>gives the same output as:</p> + <code type="none"> +ets:select(Tab,[{{'$1','$2','$3'},[],[['$1','$2','$3']]}])</code> + <p>i.e. all the bound variables in the match head as a list. If + tuples are to be constructed, one has to write a tuple of + arity 1 with the single element in the tuple being the tuple + one wants to construct (as an ordinary tuple could be mistaken + for a <c>Guard</c>). Therefore the following call:</p> + <code type="none"> +ets:select(Tab,[{{'$1','$2','$1'},[],['$_']}])</code> + <p>gives the same output as:</p> + <code type="none"> +ets:select(Tab,[{{'$1','$2','$1'},[],[{{'$1','$2','$3'}}]}])</code> + <p>- this syntax is equivalent to the syntax used in the trace + patterns (see + <seealso marker="runtime_tools:dbg">dbg(3)</seealso>).</p> + <p>The <c>Guard</c>s are constructed as tuples where the first + element is the name of the test and the rest of the elements + are the parameters of the test. To check for a specific type + (say a list) of the element bound to the match variable + <c>'$1'</c>, one would write the test as + <c>{is_list, '$1'}</c>. If the test fails, the object in the + table will not match and the next <c>MatchFunction</c> (if + any) will be tried. Most guard tests present in Erlang can be + used, but only the new versions prefixed <c>is_</c> are + allowed (like <c>is_float</c>, <c>is_atom</c> etc).</p> + <p>The <c>Guard</c> section can also contain logic and + arithmetic operations, which are written with the same syntax + as the guard tests (prefix notation), so that a guard test + written in Erlang looking like this:</p> + <code type="none"><![CDATA[ +is_integer(X), is_integer(Y), X + Y < 4711]]></code> + <p>is expressed like this (X replaced with '$1' and Y with + '$2'):</p> + <code type="none"><![CDATA[ +[{is_integer, '$1'}, {is_integer, '$2'}, {'<', {'+', '$1', '$2'}, 4711}]]]></code> + <p>On tables of the <c>ordered_set</c> type, objects are visited + in the same order as in a <c>first/next</c> + traversal. This means that the match specification will be + executed against objects with keys in the <c>first/next</c> + order and the corresponding result list will be in the order of that + execution.</p> + + </desc> + </func> + <func> + <name>select(Tab, MatchSpec, Limit) -> {[Match],Continuation} | '$end_of_table'</name> + <fsummary>Match the objects in an ETS table against a match_spec and returns part of the answers.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Match = term()</v> + <v>MatchSpec = match_spec()</v> + <v>Continuation = term()</v> + </type> + <desc> + <p>Works like <c>ets:select/2</c> but only returns a limited + (<c>Limit</c>) number of matching objects. The + <c>Continuation</c> term can then be used in subsequent calls + to <c>ets:select/1</c> to get the next chunk of matching + objects. This is a space efficient way to work on objects in a + table which is still faster than traversing the table object + by object using <c>ets:first/1</c> and <c>ets:next/1</c>.</p> + <p><c>'$end_of_table'</c> is returned if the table is empty.</p> + </desc> + </func> + <func> + <name>select(Continuation) -> {[Match],Continuation} | '$end_of_table'</name> + <fsummary>Continue matching objects in an ETS table.</fsummary> + <type> + <v>Match = term()</v> + <v>Continuation = term()</v> + </type> + <desc> + <p>Continues a match started with + <c>ets:select/3</c>. The next + chunk of the size given in the initial <c>ets:select/3</c> + call is returned together with a new <c>Continuation</c> + that can be used in subsequent calls to this function.</p> + <p><c>'$end_of_table'</c> is returned when there are no more + objects in the table.</p> + </desc> + </func> + <func> + <name>select_delete(Tab, MatchSpec) -> NumDeleted</name> + <fsummary>Match the objects in an ETS table against a match_spec and deletes objects where the match_spec returns 'true'</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Object = tuple()</v> + <v>MatchSpec = match_spec()</v> + <v>NumDeleted = integer()</v> + </type> + <desc> + <p>Matches the objects in the table <c>Tab</c> using a + <seealso marker="#match_spec">match_spec</seealso>. If the + match_spec returns <c>true</c> for an object, that object is + removed from the table. For any other result from the + match_spec the object is retained. This is a more general + call than the <c>ets:match_delete/2</c> call.</p> + <p>The function returns the number of objects actually + deleted from the table.</p> + <note> + <p>The <c>match_spec</c> has to return the atom <c>true</c> if + the object is to be deleted. No other return value will get the + object deleted, why one can not use the same match specification for + looking up elements as for deleting them.</p> + </note> + </desc> + </func> + <func> + <name>select_count(Tab, MatchSpec) -> NumMatched</name> + <fsummary>Match the objects in an ETS table against a match_spec and returns the number of objects for which the match_spec returned 'true'</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Object = tuple()</v> + <v>MatchSpec = match_spec()</v> + <v>NumMatched = integer()</v> + </type> + <desc> + <p>Matches the objects in the table <c>Tab</c> using a + <seealso marker="#match_spec">match_spec</seealso>. If the + match_spec returns <c>true</c> for an object, that object + considered a match and is counted. For any other result from + the match_spec the object is not considered a match and is + therefore not counted.</p> + <p>The function could be described as a <c>match_delete/2</c> + that does not actually delete any elements, but only counts + them.</p> + <p>The function returns the number of objects matched.</p> + </desc> + </func> + <func> + <name>setopts(Tab, Opts) -> true</name> + <fsummary>Set table options.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Opts = Opt | [Opt]</v> + <v>Opt = {heir,pid(),HeirData} | {heir,none}</v> + <v>HeirData = term()</v> + </type> + <desc> + <p>Set table options. The only option that currently is allowed to be + set after the table has been created is + <seealso marker="#heir">heir</seealso>. The calling process must be + the table owner.</p> + </desc> + </func> + <func> + <name>slot(Tab, I) -> [Object] | '$end_of_table'</name> + <fsummary>Return all objects in a given slot of an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>I = int()</v> + <v>Object = tuple()</v> + </type> + <desc> + <p>This function is mostly for debugging purposes, Normally + one should use <c>first/next</c> or <c>last/prev</c> instead.</p> + <p>Returns all objects in the <c>I</c>:th slot of the table + <c>Tab</c>. A table can be traversed by repeatedly calling + the function, starting with the first slot <c>I=0</c> and + ending when <c>'$end_of_table'</c> is returned. + The function will fail with reason <c>badarg</c> if the + <c>I</c> argument is out of range.</p> + <p>Unless a table of type <c>set</c>, <c>bag</c> or + <c>duplicate_bag</c> is protected using + <c>safe_fixtable/2</c>, see above, a traversal may fail if + concurrent updates are made to the table. If the table is of + type <c>ordered_set</c>, the function returns a list + containing the <c>I</c>:th object in Erlang term order.</p> + </desc> + </func> + <func> + <name>tab2file(Tab, Filename) -> ok | {error,Reason}</name> + <fsummary>Dump an ETS table to a file.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Filename = string() | atom()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Dumps the table <c>Tab</c> to the file <c>Filename</c>.</p> + <p>Equivalent to <c>tab2file(Tab, Filename,[])</c></p> + + </desc> + </func> + <func> + <name>tab2file(Tab, Filename, Options) -> ok | {error,Reason}</name> + <fsummary>Dump an ETS table to a file.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Filename = string() | atom()</v> + <v>Options = [Option]</v> + <v>Option = {extended_info, [ExtInfo]}</v> + <v>ExtInfo = object_count | md5sum</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Dumps the table <c>Tab</c> to the file <c>Filename</c>.</p> + <p>When dumping the table, certain information about the table + is dumped to a header at the beginning of the dump. This + information contains data about the table type, + name, protection, size, version and if it's a named table. It + also contains notes about what extended information is added + to the file, which can be a count of the objects in the file + or a MD5 sum of the header and records in the file.</p> + <p>The size field in the header might not correspond to the + actual number of records in the file if the table is public + and records are added or removed from the table during + dumping. Public tables updated during dump, and that one wants + to verify when reading, needs at least one field of extended + information for the read verification process to be reliable + later.</p> + <p>The <c>extended_info</c> option specifies what extra + information is written to the table dump:</p> + <taglist> + <tag><c>object_count</c></tag> + <item><p>The number of objects actually written to the file is + noted in the file footer, why verification of file truncation + is possible even if the file was updated during + dump.</p></item> + <tag><c>md5sum</c></tag> + <item><p>The header and objects in the file are checksummed using + the built in MD5 functions. The MD5 sum of all objects is + written in the file footer, so that verification while reading + will detect the slightest bitflip in the file data. Using this + costs a fair amount of CPU time.</p></item> + </taglist> + <p>Whenever the <c>extended_info</c> option is used, it + results in a file not readable by versions of ets prior to + that in stdlib-1.15.1</p> + + </desc> + </func> + <func> + <name>tab2list(Tab) -> [Object]</name> + <fsummary>Return a list of all objects in an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Object = tuple()</v> + </type> + <desc> + <p>Returns a list of all objects in the table <c>Tab</c>.</p> + </desc> + </func> + <func> + <name>tabfile_info(Filename) -> {ok, TableInfo} | {error, Reason}</name> + <fsummary>Return a list of all objects in an ETS table.</fsummary> + <type> + <v>Filename = string() | atom()</v> + <v>TableInfo = [InfoItem]</v> + <v>InfoItem = {InfoTag, term()}</v> + <v>InfoTag = name | type | protection | named_table | keypos | size | extended_info | version</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Returns information about the table dumped to file by + <seealso marker="#tab2file/2">tab2file/2</seealso> or + <seealso marker="#tab2file/3">tab2file/3</seealso></p> + <p>The following items are returned:</p> + <taglist> + <tag>name</tag> + <item><p>The name of the dumped table. If the table was a + named table, a table with the same name cannot exist when the + table is loaded from file with + <seealso marker="#file2tab/2">file2tab/2</seealso>. If the table is + not saved as a named table, this field has no significance + at all when loading the table from file.</p></item> + <tag>type</tag> + <item>The ets type of the dumped table (i.e. <c>set</c>, <c>bag</c>, + <c>duplicate_bag</c> or <c>ordered_set</c>). This type will be used + when loading the table again.</item> + <tag>protection</tag> + <item>The protection of the dumped table (i.e. <c>private</c>, + <c>protected</c> or <c>public</c>). A table loaded from the file + will get the same protection.</item> + <tag>named_table</tag> + <item><c>true</c> if the table was a named table when dumped + to file, otherwise <c>false</c>. Note that when a named table + is loaded from a file, there cannot exist a table in the + system with the same name.</item> + <tag>keypos</tag> + <item>The <c>keypos</c> of the table dumped to file, which + will be used when loading the table again.</item> + <tag>size</tag> + <item>The number of objects in the table when the table dump + to file started, which in case of a <c>public</c> table need + not correspond to the number of objects actually saved to the + file, as objects might have been added or deleted by another + process during table dump.</item> + <tag>extended_info</tag> + <item>The extended information written in the file footer to + allow stronger verification during table loading from file, as + specified to <seealso + marker="#tab2file/3">tab2file/3</seealso>. Note that this + function only tells <em>which</em> information is present, not + the values in the file footer. The value is a list containing + one or more of the atoms <c>object_count</c> and + <c>md5sum</c>.</item> + <tag>version</tag> + <item>A tuple <c>{Major,Minor}</c> containing the major and + minor version of the file format for ets table dumps. This + version field was added beginning with stdlib-1.5.1, files + dumped with older versions will return <c>{0,0}</c> in this + field.</item> + </taglist> + <p>An error is returned if the file is inaccessible, + badly damaged or not an file produced with <seealso + marker="#tab2file/2">tab2file/2</seealso> or <seealso + marker="#tab2file/3">tab2file/3</seealso>.</p> + </desc> + </func> + <func> + <name>table(Tab [, Options]) -> QueryHandle</name> + <fsummary>Return a QLC query handle.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>QueryHandle = - a query handle, see qlc(3) -</v> + <v>Options = [Option] | Option</v> + <v>Option = {n_objects, NObjects} | {traverse, TraverseMethod}</v> + <v>NObjects = default | integer() > 0</v> + <v>TraverseMethod = first_next | last_prev | select | {select, MatchSpec}</v> + <v>MatchSpec = match_spec()</v> + </type> + <desc> + <p> <marker id="qlc_table"></marker> +Returns a QLC (Query List + Comprehension) query handle. The module <c>qlc</c> implements + a query language aimed mainly at Mnesia but ETS tables, Dets + tables, and lists are also recognized by QLC as sources of + data. Calling <c>ets:table/1,2</c> is the means to make the + ETS table <c>Tab</c> usable to QLC.</p> + <p>When there are only simple restrictions on the key position + QLC uses <c>ets:lookup/2</c> to look up the keys, but when + that is not possible the whole table is traversed. The + option <c>traverse</c> determines how this is done:</p> + <list type="bulleted"> + <item> + <p><c>first_next</c>. The table is traversed one key at + a time by calling <c>ets:first/1</c> and + <c>ets:next/2</c>.</p> + </item> + <item> + <p><c>last_prev</c>. The table is traversed one key at + a time by calling <c>ets:last/1</c> and + <c>ets:prev/2</c>.</p> + </item> + <item> + <p><c>select</c>. The table is traversed by calling + <c>ets:select/3</c> and <c>ets:select/1</c>. The option + <c>n_objects</c> determines the number of objects + returned (the third argument of <c>select/3</c>); the + default is to return <c>100</c> objects at a time. The + <seealso marker="#match_spec">match_spec</seealso> (the + second argument of <c>select/3</c>) is assembled by QLC: + simple filters are translated into equivalent match_specs + while more complicated filters have to be applied to all + objects returned by <c>select/3</c> given a match_spec + that matches all objects.</p> + </item> + <item> + <p><c>{select, MatchSpec}</c>. As for <c>select</c> + the table is traversed by calling <c>ets:select/3</c> and + <c>ets:select/1</c>. The difference is that the + match_spec is explicitly given. This is how to state + match_specs that cannot easily be expressed within the + syntax provided by QLC.</p> + </item> + </list> + <p>The following example uses an explicit match_spec to + traverse the table:</p> + <pre> +9> <input>true = ets:insert(Tab = ets:new(t, []), [{1,a},{2,b},{3,c},{4,d}]),</input> +<input>MS = ets:fun2ms(fun({X,Y}) when (X > 1) or (X < 5) -> {Y} end),</input> +<input>QH1 = ets:table(Tab, [{traverse, {select, MS}}]).</input></pre> + <p>An example with implicit match_spec:</p> + <pre> +10> <input>QH2 = qlc:q([{Y} || {X,Y} <- ets:table(Tab), (X > 1) or (X < 5)]).</input></pre> + <p>The latter example is in fact equivalent to the former which + can be verified using the function <c>qlc:info/1</c>:</p> + <pre> +11> <input>qlc:info(QH1) =:= qlc:info(QH2).</input> +true</pre> + <p><c>qlc:info/1</c> returns information about a query handle, + and in this case identical information is returned for the + two query handles.</p> + </desc> + </func> + <func> + <name>test_ms(Tuple, MatchSpec) -> {ok, Result} | {error, Errors}</name> + <fsummary>Test a match_spec for use in ets:select/2.</fsummary> + <type> + <v>Tuple = tuple()</v> + <v>MatchSpec = match_spec()</v> + <v>Result = term()</v> + <v>Errors = [{warning|error, string()}]</v> + </type> + <desc> + <p>This function is a utility to test a + <seealso marker="#match_spec">match_spec</seealso> used in + calls to <c>ets:select/2</c>. The function both tests + <c>MatchSpec</c> for "syntactic" correctness and runs the + match_spec against the object <c>Tuple</c>. If the match_spec + contains errors, the tuple <c>{error, Errors}</c> is returned + where <c>Errors</c> is a list of natural language + descriptions of what was wrong with the match_spec. If the + match_spec is syntactically OK, the function returns + <c>{ok,Term}</c> where <c>Term</c> is what would have been + the result in a real <c>ets:select/2</c> call or <c>false</c> + if the match_spec does not match the object <c>Tuple</c>.</p> + <p>This is a useful debugging and test tool, especially when + writing complicated <c>ets:select/2</c> calls.</p> + </desc> + </func> + <func> + <name>to_dets(Tab, DetsTab) -> Tab</name> + <fsummary>Fill a Dets table with objects from an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>DetsTab = atom()</v> + </type> + <desc> + <p>Fills an already created/opened Dets table with the objects + in the already opened ETS table named <c>Tab</c>. The Dets + table is emptied before the objects are inserted.</p> + </desc> + </func> + <func> + <name>update_counter(Tab, Key, UpdateOp) -> Result</name> + <name>update_counter(Tab, Key, [UpdateOp]) -> [Result]</name> + <name>update_counter(Tab, Key, Incr) -> Result</name> + <fsummary>Update a counter object in an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Key = term()</v> + <v>UpdateOp = {Pos,Incr} | {Pos,Incr,Threshold,SetValue}</v> + <v>Pos = Incr = Threshold = SetValue = Result = int()</v> + </type> + <desc> + <p>This function provides an efficient way to update one or more + counters, without the hassle of having to look up an object, update + the object by incrementing an element and insert the resulting object + into the table again. (The update is done atomically; i.e. no process + can access the ets table in the middle of the operation.) + </p> + <p>It will destructively update the object with key <c>Key</c> + in the table <c>Tab</c> by adding <c>Incr</c> to the element + at the <c>Pos</c>:th position. The new counter value is + returned. If no position is specified, the element directly + following the key (<c><![CDATA[<keypos>+1]]></c>) is updated.</p> + <p>If a <c>Threshold</c> is specified, the counter will be + reset to the value <c>SetValue</c> if the following + conditions occur:</p> + <list type="bulleted"> + <item>The <c>Incr</c> is not negative (<c>>= 0</c>) and the + result would be greater than (<c>></c>) <c>Threshold</c></item> + <item>The <c>Incr</c> is negative (<c><![CDATA[< 0]]></c>) and the + result would be less than (<c><![CDATA[<]]></c>) + <c>Threshold</c></item> + </list> + <p>A list of <c>UpdateOp</c> can be supplied to do several update + operations within the object. The operations are carried out in the + order specified in the list. If the same counter position occurs + more than one time in the list, the corresponding counter will thus + be updated several times, each time based on the previous result. + The return value is a list of the new counter values from each + update operation in the same order as in the operation list. If an + empty list is specified, nothing is updated and an empty list is + returned. If the function should fail, no updates will be done at + all. + </p> + <p>The given Key is used to identify the object by either + <em>matching</em> the key of an object in a <c>set</c> table, + or <em>compare equal</em> to the key of an object in an + <c>ordered_set</c> table (see + <seealso marker="#lookup/2">lookup/2</seealso> and + <seealso marker="#new/2">new/2</seealso> + for details on the difference).</p> + <p>The function will fail with reason <c>badarg</c> if:</p> + <list type="bulleted"> + <item>the table is not of type <c>set</c> or + <c>ordered_set</c>,</item> + <item>no object with the right key exists,</item> + <item>the object has the wrong arity,</item> + <item>the element to update is not an integer,</item> + <item>the element to update is also the key, or,</item> + <item>any of <c>Pos</c>, <c>Incr</c>, <c>Threshold</c> or + <c>SetValue</c> is not an integer</item> + </list> + </desc> + </func> + <func> + <name>update_element(Tab, Key, {Pos,Value}) -> true | false</name> + <name>update_element(Tab, Key, [{Pos,Value}]) -> true | false</name> + <fsummary>Updates the <c>Pos</c>:th element of the object with a given key in an ETS table.</fsummary> + <type> + <v>Tab = tid() | atom()</v> + <v>Key = Value = term()</v> + <v>Pos = int()</v> + </type> + <desc> + <p>This function provides an efficient way to update one or more + elements within an object, without the hassle of having to look up, + update and write back the entire object. + </p> + <p>It will destructively update the object with key <c>Key</c> + in the table <c>Tab</c>. The element at the <c>Pos</c>:th position + will be given the value <c>Value</c>. </p> + <p>A list of <c>{Pos,Value}</c> can be supplied to update several + elements within the same object. If the same position occurs more + than one in the list, the last value in the list will be written. If + the list is empty or the function fails, no updates will be done at + all. The function is also atomic in the sense that other processes + can never see any intermediate results. + </p> + <p>The function returns <c>true</c> if an object with the key + <c>Key</c> was found, <c>false</c> otherwise. + </p> + <p>The given Key is used to identify the object by either + <em>matching</em> the key of an object in a <c>set</c> table, + or <em>compare equal</em> to the key of an object in an + <c>ordered_set</c> table (see + <seealso marker="#lookup/2">lookup/2</seealso> and + <seealso marker="#new/2">new/2</seealso> + for details on the difference).</p> + <p>The function will fail with reason <c>badarg</c> if:</p> + <list type="bulleted"> + <item>the table is not of type <c>set</c> or + <c>ordered_set</c>,</item> + <item><c>Pos</c> is less than 1 or greater than the object + arity, or,</item> + <item>the element to update is also the key</item> + </list> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/fascicules.xml b/lib/stdlib/doc/src/fascicules.xml new file mode 100644 index 0000000000..b30d34186e --- /dev/null +++ b/lib/stdlib/doc/src/fascicules.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE fascicules SYSTEM "fascicules.dtd"> + +<fascicules> + <fascicule file="part" href="part_frame.html" entry="no"> + STDLIB User's Guide + </fascicule> + <fascicule file="ref_man" href="ref_man_frame.html" entry="yes"> + Reference Manual + </fascicule> + <fascicule file="part_notes" href="part_notes_frame.html" entry="no"> + Release Notes + </fascicule> + <fascicule file="" href="../../../../doc/print.html" entry="no"> + Off-Print + </fascicule> +</fascicules> + diff --git a/lib/stdlib/doc/src/file_sorter.xml b/lib/stdlib/doc/src/file_sorter.xml new file mode 100644 index 0000000000..b3f4da294c --- /dev/null +++ b/lib/stdlib/doc/src/file_sorter.xml @@ -0,0 +1,390 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>file_sorter</title> + <prepared>Hans Bolinder</prepared> + <responsible>nobody</responsible> + <docno></docno> + <approved>nobody</approved> + <checked>no</checked> + <date>2001-03-13</date> + <rev>PA1</rev> + <file>file_sorter.sgml</file> + </header> + <module>file_sorter</module> + <modulesummary>File Sorter</modulesummary> + <description> + <p>The functions of this module sort terms on files, merge already + sorted files, and check files for sortedness. Chunks containing + binary terms are read from a sequence of files, sorted + internally in memory and written on temporary files, which are + merged producing one sorted file as output. Merging is provided + as an optimization; it is faster when the files are already + sorted, but it always works to sort instead of merge. + </p> + <p>On a file, a term is represented by a header and a binary. Two + options define the format of terms on files: + </p> + <list type="bulleted"> + <item><c>{header, HeaderLength}</c>. HeaderLength determines the + number of bytes preceding each binary and containing the + length of the binary in bytes. Default is 4. The order of the + header bytes is defined as follows: if <c>B</c> is a binary + containing a header only, the size <c>Size</c> of the binary + is calculated as + <c><![CDATA[<<Size:HeaderLength/unit:8>> = B]]></c>. + </item> + <item><c>{format, Format}</c>. The format determines the + function that is applied to binaries in order to create the + terms that will be sorted. The default value is + <c>binary_term</c>, which is equivalent to + <c>fun binary_to_term/1</c>. The value <c>binary</c> is + equivalent to <c>fun(X) -> X end</c>, which means that the + binaries will be sorted as they are. This is the fastest + format. If <c>Format</c> is <c>term</c>, <c>io:read/2</c> is + called to read terms. In that case only the default value of + the <c>header</c> option is allowed. The <c>format</c> option + also determines what is written to the sorted output file: if + <c>Format</c> is <c>term</c> then <c>io:format/3</c> is called + to write each term, otherwise the binary prefixed by a header + is written. Note that the binary written is the same binary + that was read; the results of applying the <c>Format</c> + function are thrown away as soon as the terms have been + sorted. Reading and writing terms using the <c>io</c> module + is very much slower than reading and writing binaries. + </item> + </list> + <p>Other options are: + </p> + <list type="bulleted"> + <item><c>{order, Order}</c>. The default is to sort terms in + ascending order, but that can be changed by the value + <c>descending</c> or by giving an ordering function <c>Fun</c>. + An ordering function is antisymmetric, transitive and total. + <c>Fun(A, B)</c> should return <c>true</c> if <c>A</c> + comes before <c>B</c> in the ordering, <c>false</c> otherwise. + Using an ordering function will slow down the sort + considerably. The <c>keysort</c>, <c>keymerge</c> and + <c>keycheck</c> functions do not accept ordering functions. + </item> + <item><c>{unique, bool()}</c>. When sorting or merging files, + only the first of a sequence of terms that compare equal is + output if this option is set to <c>true</c>. The default + value is <c>false</c> which implies that all terms that + compare equal are output. When checking files for + sortedness, a check that no pair of consecutive terms + compares equal is done if this option is set to <c>true</c>. + </item> + <item><c>{tmpdir, TempDirectory}</c>. The directory where + temporary files are put can be chosen explicitly. The + default, implied by the value <c>""</c>, is to put temporary + files on the same directory as the sorted output file. If + output is a function (see below), the directory returned by + <c>file:get_cwd()</c> is used instead. The names of + temporary files are derived from the Erlang nodename + (<c>node()</c>), the process identifier of the current Erlang + emulator (<c>os:getpid()</c>), and a timestamp + (<c>erlang:now()</c>); a typical name would be + <c>fs_mynode@myhost_1763_1043_337000_266005.17</c>, where + <c>17</c> is a sequence number. Existing files will be + overwritten. Temporary files are deleted unless some + uncaught EXIT signal occurs. + </item> + <item><c>{compressed, bool()}</c>. Temporary files and the + output file may be compressed. The default value + <c>false</c> implies that written files are not + compressed. Regardless of the value of the <c>compressed</c> + option, compressed files can always be read. Note that + reading and writing compressed files is significantly slower + than reading and writing uncompressed files. + </item> + <item><c>{size, Size}</c>. By default approximately 512*1024 + bytes read from files are sorted internally. This option + should rarely be needed. + </item> + <item><c>{no_files, NoFiles}</c>. By default 16 files are + merged at a time. This option should rarely be needed. + </item> + </list> + <p>To summarize, here is the syntax of the options:</p> + <list type="bulleted"> + <item> + <p><c>Options = [Option] | Option</c></p> + </item> + <item> + <p><c>Option = {header, HeaderLength} | {format, Format} | {order, Order} | {unique, bool()} | {tmpdir, TempDirectory} | {compressed, bool()} | {size, Size} | {no_files, NoFiles}</c></p> + </item> + <item> + <p><c>HeaderLength = int() > 0</c></p> + </item> + <item> + <p><c>Format = binary_term | term | binary | FormatFun</c></p> + </item> + <item> + <p><c>FormatFun = fun(Binary) -> Term</c></p> + </item> + <item> + <p><c>Order = ascending | descending | OrderFun</c></p> + </item> + <item> + <p><c>OrderFun = fun(Term, Term) -> bool()</c></p> + </item> + <item> + <p><c>TempDirectory = "" | file_name()</c></p> + </item> + <item> + <p><c>Size = int() >= 0</c></p> + </item> + <item> + <p><c>NoFiles = int() > 1</c></p> + </item> + </list> + <p>As an alternative to sorting files, a function of one argument + can be given as input. When called with the argument <c>read</c> + the function is assumed to return <c>end_of_input</c> or + <c>{end_of_input, Value}}</c> when there is no more input + (<c>Value</c> is explained below), or <c>{Objects, Fun}</c>, + where <c>Objects</c> is a list of binaries or terms depending on + the format and <c>Fun</c> is a new input function. Any other + value is immediately returned as value of the current call to + <c>sort</c> or <c>keysort</c>. Each input function will be + called exactly once, and should an error occur, the last + function is called with the argument <c>close</c>, the reply of + which is ignored. + </p> + <p>A function of one argument can be given as output. The results + of sorting or merging the input is collected in a non-empty + sequence of variable length lists of binaries or terms depending + on the format. The output function is called with one list at a + time, and is assumed to return a new output function. Any other + return value is immediately returned as value of the current + call to the sort or merge function. Each output function is + called exactly once. When some output function has been applied + to all of the results or an error occurs, the last function is + called with the argument <c>close</c>, and the reply is returned + as value of the current call to the sort or merge function. If a + function is given as input and the last input function returns + <c>{end_of_input, Value}</c>, the function given as output will + be called with the argument <c>{value, Value}</c>. This makes it + easy to initiate the sequence of output functions with a value + calculated by the input functions. + </p> + <p>As an example, consider sorting the terms on a disk log file. + A function that reads chunks from the disk log and returns a + list of binaries is used as input. The results are collected in + a list of terms.</p> + <pre> +sort(Log) -> + {ok, _} = disk_log:open([{name,Log}, {mode,read_only}]), + Input = input(Log, start), + Output = output([]), + Reply = file_sorter:sort(Input, Output, {format,term}), + ok = disk_log:close(Log), + Reply. + +input(Log, Cont) -> + fun(close) -> + ok; + (read) -> + case disk_log:chunk(Log, Cont) of + {error, Reason} -> + {error, Reason}; + {Cont2, Terms} -> + {Terms, input(Log, Cont2)}; + {Cont2, Terms, _Badbytes} -> + {Terms, input(Log, Cont2)}; + eof -> + end_of_input + end + end. + +output(L) -> + fun(close) -> + lists:append(lists:reverse(L)); + (Terms) -> + output([Terms | L]) + end. </pre> + <p>Further examples of functions as input and output can be found + at the end of the <c>file_sorter</c> module; the <c>term</c> + format is implemented with functions. + </p> + <p>The possible values of <c>Reason</c> returned when an error + occurs are:</p> + <list type="bulleted"> + <item> + <p><c>bad_object</c>, <c>{bad_object, FileName}</c>. + Applying the format function failed for some binary, + or the key(s) could not be extracted from some term.</p> + </item> + <item> + <p><c>{bad_term, FileName}</c>. <c>io:read/2</c> failed + to read some term.</p> + </item> + <item> + <p><c>{file_error, FileName, Reason2}</c>. See + <c>file(3)</c> for an explanation of <c>Reason2</c>.</p> + </item> + <item> + <p><c>{premature_eof, FileName}</c>. End-of-file was + encountered inside some binary term.</p> + </item> + </list> + <p><em>Types</em></p> + <pre> +Binary = binary() +FileName = file_name() +FileNames = [FileName] +ICommand = read | close +IReply = end_of_input | {end_of_input, Value} | {[Object], Infun} | InputReply +Infun = fun(ICommand) -> IReply +Input = FileNames | Infun +InputReply = Term +KeyPos = int() > 0 | [int() > 0] +OCommand = {value, Value} | [Object] | close +OReply = Outfun | OutputReply +Object = Term | Binary +Outfun = fun(OCommand) -> OReply +Output = FileName | Outfun +OutputReply = Term +Term = term() +Value = Term</pre> + </description> + <funcs> + <func> + <name>sort(FileName) -> Reply</name> + <name>sort(Input, Output) -> Reply</name> + <name>sort(Input, Output, Options) -> Reply</name> + <fsummary>Sort terms on files.</fsummary> + <type> + <v>Reply = ok | {error, Reason} | InputReply | OutputReply</v> + </type> + <desc> + <p>Sorts terms on files. + </p> + <p><c>sort(FileName)</c> is equivalent to + <c>sort([FileName], FileName)</c>. + </p> + <p><c>sort(Input, Output)</c> is equivalent to + <c>sort(Input, Output, [])</c>. + </p> + <p></p> + </desc> + </func> + <func> + <name>keysort(KeyPos, FileName) -> Reply</name> + <name>keysort(KeyPos, Input, Output) -> Reply</name> + <name>keysort(KeyPos, Input, Output, Options) -> Reply</name> + <fsummary>Sort terms on files by key.</fsummary> + <type> + <v>Reply = ok | {error, Reason} | InputReply | OutputReply</v> + </type> + <desc> + <p>Sorts tuples on files. The sort is performed on the + element(s) mentioned in <c>KeyPos</c>. If two tuples + compare equal on one element, next element according to + <c>KeyPos</c> is compared. The sort is stable. + </p> + <p><c>keysort(N, FileName)</c> is equivalent to + <c>keysort(N, [FileName], FileName)</c>. + </p> + <p><c>keysort(N, Input, Output)</c> is equivalent to + <c>keysort(N, Input, Output, [])</c>. + </p> + <p></p> + </desc> + </func> + <func> + <name>merge(FileNames, Output) -> Reply</name> + <name>merge(FileNames, Output, Options) -> Reply</name> + <fsummary>Merge terms on files.</fsummary> + <type> + <v>Reply = ok | {error, Reason} | OutputReply</v> + </type> + <desc> + <p>Merges terms on files. Each input file is assumed to be + sorted. + </p> + <p><c>merge(FileNames, Output)</c> is equivalent to + <c>merge(FileNames, Output, [])</c>. + </p> + </desc> + </func> + <func> + <name>keymerge(KeyPos, FileNames, Output) -> Reply</name> + <name>keymerge(KeyPos, FileNames, Output, Options) -> Reply</name> + <fsummary>Merge terms on files by key.</fsummary> + <type> + <v>Reply = ok | {error, Reason} | OutputReply</v> + </type> + <desc> + <p>Merges tuples on files. Each input file is assumed to be + sorted on key(s). + </p> + <p><c>keymerge(KeyPos, FileNames, Output)</c> is equivalent + to <c>keymerge(KeyPos, FileNames, Output, [])</c>. + </p> + <p></p> + </desc> + </func> + <func> + <name>check(FileName) -> Reply</name> + <name>check(FileNames, Options) -> Reply</name> + <fsummary>Check whether terms on files are sorted.</fsummary> + <type> + <v>Reply = {ok, [Result]} | {error, Reason}</v> + <v>Result = {FileName, TermPosition, Term}</v> + <v>TermPosition = int() > 1</v> + </type> + <desc> + <p>Checks files for sortedness. If a file is not sorted, the + first out-of-order element is returned. The first term on a + file has position 1. + </p> + <p><c>check(FileName)</c> is equivalent to + <c>check([FileName], [])</c>. + </p> + </desc> + </func> + <func> + <name>keycheck(KeyPos, FileName) -> CheckReply</name> + <name>keycheck(KeyPos, FileNames, Options) -> Reply</name> + <fsummary>Check whether terms on files are sorted by key.</fsummary> + <type> + <v>Reply = {ok, [Result]} | {error, Reason}</v> + <v>Result = {FileName, TermPosition, Term}</v> + <v>TermPosition = int() > 1</v> + </type> + <desc> + <p>Checks files for sortedness. If a file is not sorted, the + first out-of-order element is returned. The first term on a + file has position 1. + </p> + <p><c>keycheck(KeyPos, FileName)</c> is equivalent + to <c>keycheck(KeyPos, [FileName], [])</c>. + </p> + <p></p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/filelib.xml b/lib/stdlib/doc/src/filelib.xml new file mode 100644 index 0000000000..c1c4ca9350 --- /dev/null +++ b/lib/stdlib/doc/src/filelib.xml @@ -0,0 +1,217 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2003</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>filelib</title> + <prepared>Bjorn Gustavsson</prepared> + <responsible>Bjorn Gustavsson</responsible> + <docno>1</docno> + <approved>Kenneth Lundin</approved> + <checked></checked> + <date>03-01-21</date> + <rev>A</rev> + <file>filelib.sgml</file> + </header> + <module>filelib</module> + <modulesummary>File utilities, such as wildcard matching of filenames</modulesummary> + <description> + <p>This module contains utilities on a higher level than the <c>file</c> + module.</p> + </description> + + <section> + <title>DATA TYPES</title> + <code type="none"> +filename() = string() | atom() | DeepList +dirname() = filename() +DeepList = [char() | atom() | DeepList]</code> + </section> + + <funcs> + <func> + <name>ensure_dir(Name) -> ok | {error, Reason}</name> + <fsummary>Ensure that all parent directories for a file or directory exist.</fsummary> + <type> + <v>Name = filename() | dirname()</v> + <v>Reason = posix() -- see file(3)</v> + </type> + <desc> + <p>The <c>ensure_dir/1</c> function ensures that all parent + directories for the given file or directory name <c>Name</c> + exist, trying to create them if necessary.</p> + <p>Returns <c>ok</c> if all parent directories already exist + or could be created, or <c>{error, Reason}</c> if some parent + directory does not exist and could not be created for some + reason.</p> + </desc> + </func> + <func> + <name>file_size(Filename) -> integer()</name> + <fsummary>Return the size in bytes of the file.</fsummary> + <desc> + <p>The <c>file_size</c> function returns the size of the given file.</p> + </desc> + </func> + <func> + <name>fold_files(Dir, RegExp, Recursive, Fun, AccIn) -> AccOut </name> + <fsummary>Fold over all files matching a regular expression.</fsummary> + <type> + <v>Dir = dirname()</v> + <v>RegExp = regular_expression_string()</v> + <v>Recursive = true|false</v> + <v>Fun = fun(F, AccIn) -> AccOut</v> + <v>AccIn = AccOut = term()</v> + </type> + <desc> + <p>The <c>fold_files/5</c> function folds the function + <c>Fun</c> over all (regular) files <c>F</c> in the + directory <c>Dir</c> that match the regular expression <c>RegExp</c> + (see the <seealso marker="re">re</seealso> module for a description + of the allowed regular expressions). + If <c>Recursive</c> is true all sub-directories to <c>Dir</c> + are processed. The regular expression matching is done on just + the filename without the directory part.</p> + </desc> + </func> + <func> + <name>is_dir(Name) -> true | false</name> + <fsummary>Test whether Name refer to a directory or not</fsummary> + <type> + <v>Name = filename() | dirname()</v> + </type> + <desc> + <p>The <c>is_dir/1</c> function returns <c>true</c> if <c>Name</c> + refers to a directory, and <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>is_file(Name) -> true | false</name> + <fsummary>Test whether Name refer to a file or directory.</fsummary> + <type> + <v>Name = filename() | dirname()</v> + </type> + <desc> + <p>The <c>is_file/1</c> function returns <c>true</c> if <c>Name</c> + refers to a file or a directory, and <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>is_regular(Name) -> true | false</name> + <fsummary>Test whether Name refer to a (regular) file.</fsummary> + <type> + <v>Name = filename()</v> + </type> + <desc> + <p>The <c>is_regular/1</c> function returns <c>true</c> if <c>Name</c> + refers to a file (regular file), and <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>last_modified(Name) -> {{Year,Month,Day},{Hour,Min,Sec}} | 0</name> + <fsummary>Return the local date and time when a file was last modified.</fsummary> + <type> + <v>Name = filename() | dirname()</v> + </type> + <desc> + <p>The <c>last_modified/1</c> function returns the date and time the + given file or directory was last modified, or 0 if the file + does not exist.</p> + </desc> + </func> + <func> + <name>wildcard(Wildcard) -> list()</name> + <fsummary>Match filenames using Unix-style wildcards.</fsummary> + <type> + <v>Wildcard = filename() | dirname()</v> + </type> + <desc> + <p>The <c>wildcard/1</c> function returns a list of all files + that match Unix-style wildcard-string <c>Wildcard</c>.</p> + <p>The wildcard string looks like an ordinary filename, except + that certain "wildcard characters" are interpreted in a special + way. The following characters are special: + </p> + <taglist> + <tag>?</tag> + <item> + <p>Matches one character.</p> + </item> + <tag>*</tag> + <item> + <p>Matches any number of characters up to the end of + the filename, the next dot, or the next slash.</p> + </item> + <tag>{Item,...}</tag> + <item> + <p>Alternation. Matches one of the alternatives.</p> + </item> + </taglist> + <p>Other characters represent themselves. Only filenames that + have exactly the same character in the same position will match. + (Matching is case-sensitive; i.e. "a" will not match "A"). + </p> + <p>Note that multiple "*" characters are allowed + (as in Unix wildcards, but opposed to Windows/DOS wildcards). + </p> + <p>Examples:</p> + <p>The following examples assume that the current directory is the + top of an Erlang/OTP installation. + </p> + <p>To find all <c>.beam</c> files in all applications, the following + line can be used:</p> + <code type="none"> + filelib:wildcard("lib/*/ebin/*.beam"). </code> + <p>To find either <c>.erl</c> or <c>.hrl</c> in all applications + <c>src</c> directories, the following</p> + <code type="none"> + filelib:wildcard("lib/*/src/*.?rl") </code> + <p>or the following line</p> + <code type="none"> + filelib:wildcard("lib/*/src/*.{erl,hrl}") </code> + <p>can be used.</p> + <p>To find all <c>.hrl</c> files in either <c>src</c> or <c>include</c> + directories, use:</p> + <code type="none"> + filelib:wildcard("lib/*/{src,include}/*.hrl"). </code> + <p>To find all <c>.erl</c> or <c>.hrl</c> files in either + <c>src</c> or <c>include</c> directories, use:</p> + <code type="none"> + filelib:wildcard("lib/*/{src,include}/*.{erl,hrl}") </code> + </desc> + </func> + <func> + <name>wildcard(Wildcard, Cwd) -> list()</name> + <fsummary>Match filenames using Unix-style wildcards starting at a specified directory.</fsummary> + <type> + <v>Wildcard = filename() | dirname()</v> + <v>Cwd = dirname()</v> + </type> + <desc> + <p>The <c>wildcard/2</c> function works like <c>wildcard/1</c>, + except that instead of the actual working directory, <c>Cwd</c> + will be used.</p> + </desc> + </func> + </funcs> +</erlref> + + diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml new file mode 100644 index 0000000000..3a6c5e0b60 --- /dev/null +++ b/lib/stdlib/doc/src/filename.xml @@ -0,0 +1,385 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1997</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>filename</title> + <prepared>Kenneth Lundin</prepared> + <docno>1</docno> + <date>97-11-13</date> + <rev>B</rev> + </header> + <module>filename</module> + <modulesummary>Filename Manipulation Functions</modulesummary> + <description> + <p>The module <c>filename</c> provides a number of useful functions + for analyzing and manipulating file names. These functions are + designed so that the Erlang code can work on many different + platforms with different formats for file names. With file name + is meant all strings that can be used to denote a file. They can + be short relative names like <c>foo.erl</c>, very long absolute + name which include a drive designator and directory names like + <c>D:\\usr/local\\bin\\erl/lib\\tools\\foo.erl</c>, or any variations + in between.</p> + <p>In Windows, all functions return file names with forward slashes + only, even if the arguments contain back slashes. Use + <c>join/1</c> to normalize a file name by removing redundant + directory separators.</p> + </description> + + <section> + <title>DATA TYPES</title> + <code type="none"> +name() = string() | atom() | DeepList + DeepList = [char() | atom() | DeepList]</code> + </section> + <funcs> + <func> + <name>absname(Filename) -> string()</name> + <fsummary>Convert a filename to an absolute name, relative the working directory</fsummary> + <type> + <v>Filename = name()</v> + </type> + <desc> + <p>Converts a relative <c>Filename</c> and returns an absolute + name. No attempt is made to create the shortest absolute name, + because this can give incorrect results on file systems which + allow links.</p> + <p>Unix examples:</p> + <pre> +1> <input>pwd().</input> +"/usr/local" +2> <input>filename:absname("foo").</input> +"/usr/local/foo" +3> <input>filename:absname("../x").</input> +"/usr/local/../x" +4> <input>filename:absname("/").</input> +"/"</pre> + <p>Windows examples:</p> + <pre> +1> <input>pwd().</input> +"D:/usr/local" +2> <input>filename:absname("foo").</input> +"D:/usr/local/foo" +3> <input>filename:absname("../x").</input> +"D:/usr/local/../x" +4> <input>filename:absname("/").</input> +"D:/"</pre> + </desc> + </func> + <func> + <name>absname(Filename, Dir) -> string()</name> + <fsummary>Convert a filename to an absolute name, relative a specified directory</fsummary> + <type> + <v>Filename = name()</v> + <v>Dir = string()</v> + </type> + <desc> + <p>This function works like <c>absname/1</c>, except that + the directory to which the file name should be made relative + is given explicitly in the <c>Dir</c> argument.</p> + </desc> + </func> + <func> + <name>absname_join(Dir, Filename) -> string()</name> + <fsummary>Join an absolute directory with a relative filename</fsummary> + <type> + <v>Dir = string()</v> + <v>Filename = name()</v> + </type> + <desc> + <p>Joins an absolute directory with a relative filename. + Similar to <c>join/2</c>, but on platforms with tight + restrictions on raw filename length and no support for + symbolic links (read: VxWorks), leading parent directory + components in <c>Filename</c> are matched against trailing + directory components in <c>Dir</c> so they can be removed + from the result - minimizing its length.</p> + </desc> + </func> + <func> + <name>basename(Filename) -> string()</name> + <fsummary>Return the last component of a filename</fsummary> + <type> + <v>Filename = name()</v> + </type> + <desc> + <p>Returns the last component of <c>Filename</c>, or + <c>Filename</c> itself if it does not contain any directory + separators.</p> + <pre> +5> <input>filename:basename("foo").</input> +"foo" +6> <input>filename:basename("/usr/foo").</input> +"foo" +7> <input>filename:basename("/").</input> +[]</pre> + </desc> + </func> + <func> + <name>basename(Filename, Ext) -> string()</name> + <fsummary>Return the last component of a filename, stripped of the specified extension</fsummary> + <type> + <v>Filename = Ext = name()</v> + </type> + <desc> + <p>Returns the last component of <c>Filename</c> with the + extension <c>Ext</c> stripped. This function should be used + to remove a specific extension which might, or might not, be + there. Use <c>rootname(basename(Filename))</c> to remove an + extension that exists, but you are not sure which one it is.</p> + <pre> +8> <input>filename:basename("~/src/kalle.erl", ".erl").</input> +"kalle" +9> <input>filename:basename("~/src/kalle.beam", ".erl").</input> +"kalle.beam" +10> <input>filename:basename("~/src/kalle.old.erl", ".erl").</input> +"kalle.old" +11> <input>filename:rootname(filename:basename("~/src/kalle.erl")).</input> +"kalle" +12> <input>filename:rootname(filename:basename("~/src/kalle.beam")).</input> +"kalle"</pre> + </desc> + </func> + <func> + <name>dirname(Filename) -> string()</name> + <fsummary>Return the directory part of a path name</fsummary> + <type> + <v>Filename = name()</v> + </type> + <desc> + <p>Returns the directory part of <c>Filename</c>.</p> + <pre> +13> <input>filename:dirname("/usr/src/kalle.erl").</input> +"/usr/src" +14> <input>filename:dirname("kalle.erl").</input> +"." + +5> <input>filename:dirname("\\\\usr\\\\src/kalle.erl").</input> % Windows +"/usr/src"</pre> + </desc> + </func> + <func> + <name>extension(Filename) -> string()</name> + <fsummary>Return the file extension</fsummary> + <type> + <v>Filename = name()</v> + </type> + <desc> + <p>Returns the file extension of <c>Filename</c>, including + the period. Returns an empty string if there is no extension.</p> + <pre> +15> <input>filename:extension("foo.erl").</input> +".erl" +16> <input>filename:extension("beam.src/kalle").</input> +[]</pre> + </desc> + </func> + <func> + <name>flatten(Filename) -> string()</name> + <fsummary>Convert a filename to a flat string</fsummary> + <type> + <v>Filename = name()</v> + </type> + <desc> + <p>Converts a possibly deep list filename consisting of + characters and atoms into the corresponding flat string + filename.</p> + </desc> + </func> + <func> + <name>join(Components) -> string()</name> + <fsummary>Join a list of filename components with directory separators</fsummary> + <type> + <v>Components = [string()]</v> + </type> + <desc> + <p>Joins a list of file name <c>Components</c> with directory + separators. If one of the elements of <c>Components</c> + includes an absolute path, for example <c>"/xxx"</c>, + the preceding elements, if any, are removed from the result.</p> + <p>The result is "normalized":</p> + <list type="bulleted"> + <item>Redundant directory separators are removed.</item> + <item>In Windows, all directory separators are forward + slashes and the drive letter is in lower case.</item> + </list> + <pre> +17> <input>filename:join(["/usr", "local", "bin"]).</input> +"/usr/local/bin" +18> <input>filename:join(["a/b///c/"]).</input> +"a/b/c" + +6> <input>filename:join(["B:a\\\\b///c/"]).</input> % Windows +"b:a/b/c"</pre> + </desc> + </func> + <func> + <name>join(Name1, Name2) -> string()</name> + <fsummary>Join two filename components with directory separators</fsummary> + <type> + <v>Name1 = Name2 = string()</v> + </type> + <desc> + <p>Joins two file name components with directory separators. + Equivalent to <c>join([Name1, Name2])</c>.</p> + </desc> + </func> + <func> + <name>nativename(Path) -> string()</name> + <fsummary>Return the native form of a file path</fsummary> + <type> + <v>Path = string()</v> + </type> + <desc> + <p>Converts <c>Path</c> to a form accepted by the command shell + and native applications on the current platform. On Windows, + forward slashes is converted to backward slashes. On all + platforms, the name is normalized as done by <c>join/1</c>.</p> + <pre> +19> <input>filename:nativename("/usr/local/bin/").</input> % Unix +"/usr/local/bin" + +7> <input>filename:nativename("/usr/local/bin/").</input> % Windows +"\\\\usr\\\\local\\\\bin"</pre> + </desc> + </func> + <func> + <name>pathtype(Path) -> absolute | relative | volumerelative</name> + <fsummary>Return the type of a path</fsummary> + <desc> + <p>Returns the type of path, one of <c>absolute</c>, + <c>relative</c>, or <c>volumerelative</c>.</p> + <taglist> + <tag><c>absolute</c></tag> + <item> + <p>The path name refers to a specific file on a specific + volume.</p> + <p>Unix example: <c>/usr/local/bin</c></p> + <p>Windows example: <c>D:/usr/local/bin</c></p> + </item> + <tag><c>relative</c></tag> + <item> + <p>The path name is relative to the current working + directory on the current volume.</p> + <p>Example: <c>foo/bar, ../src</c></p> + </item> + <tag><c>volumerelative</c></tag> + <item> + <p>The path name is relative to the current working + directory on a specified volume, or it is a specific file + on the current working volume.</p> + <p>Windows example: <c>D:bar.erl, /bar/foo.erl</c></p> + </item> + </taglist> + </desc> + </func> + <func> + <name>rootname(Filename) -> string()</name> + <name>rootname(Filename, Ext) -> string()</name> + <fsummary>Remove a filename extension</fsummary> + <type> + <v>Filename = Ext = name()</v> + </type> + <desc> + <p>Remove a filename extension. <c>rootname/2</c> works as + <c>rootname/1</c>, except that the extension is removed only + if it is <c>Ext</c>.</p> + <pre> +20> <input>filename:rootname("/beam.src/kalle").</input> +/beam.src/kalle" +21> <input>filename:rootname("/beam.src/foo.erl").</input> +"/beam.src/foo" +22> <input>filename:rootname("/beam.src/foo.erl", ".erl").</input> +"/beam.src/foo" +23> <input>filename:rootname("/beam.src/foo.beam", ".erl").</input> +"/beam.src/foo.beam"</pre> + </desc> + </func> + <func> + <name>split(Filename) -> Components</name> + <fsummary>Split a filename into its path components</fsummary> + <type> + <v>Filename = name()</v> + <v>Components = [string()]</v> + </type> + <desc> + <p>Returns a list whose elements are the path components of + <c>Filename</c>.</p> + <pre> +24> <input>filename:split("/usr/local/bin").</input> +["/","usr","local","bin"] +25> <input>filename:split("foo/bar").</input> +["foo","bar"] +26> <input>filename:split("a:\\\\msdev\\\\include").</input> +["a:/","msdev","include"]</pre> + </desc> + </func> + <func> + <name>find_src(Beam) -> {SourceFile, Options} | {error,{ErrorReason,Module}}</name> + <name>find_src(Beam, Rules) -> {SourceFile, Options} | {error,{ErrorReason,Module}}</name> + <fsummary>Find the filename and compiler options for a module</fsummary> + <type> + <v>Beam = Module | Filename</v> + <v> Module = atom()</v> + <v> Filename = string() | atom()</v> + <v>SourceFile = string()</v> + <v>Options = [Opt]</v> + <v> Opt = {i, string()} | {outdir, string()} | {d, atom()}</v> + <v>ErrorReason = non_existing | preloaded | interpreted</v> + </type> + <desc> + <p>Finds the source filename and compiler options for a module. + The result can be fed to <c>compile:file/2</c> in order to + compile the file again.</p> + <p>The <c>Beam</c> argument, which can be a string or an atom, + specifies either the module name or the path to the source + code, with or without the <c>".erl"</c> extension. In either + case, the module must be known by the code server, i.e. + <c>code:which(Module)</c> must succeed.</p> + <p><c>Rules</c> describes how the source directory can be found, + when the object code directory is known. It is a list of + tuples <c>{BinSuffix, SourceSuffix}</c> and is interpreted + as follows: If the end of the directory name where the object + is located matches <c>BinSuffix</c>, then the source code + directory has the same name, but with <c>BinSuffix</c> + replaced by <c>SourceSuffix</c>. <c>Rules</c> defaults to:</p> + <code type="none"> +[{"", ""}, {"ebin", "src"}, {"ebin", "esrc"}]</code> + <p>If the source file is found in the resulting directory, then + the function returns that location together with + <c>Options</c>. Otherwise, the next rule is tried, and so on.</p> + + <p>The function returns <c>{SourceFile, Options}</c> if it succeeds. + <c>SourceFile</c> is the absolute path to the source file + without the <c>".erl"</c> extension. <c>Options</c> include + the options which are necessary to recompile the file with + <c>compile:file/2</c>, but excludes options such as + <c>report</c> or <c>verbose</c> which do not change the way + code is generated. The paths in the <c>{outdir, Path}</c> + and <c>{i, Path}</c> options are guaranteed to be + absolute.</p> + + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/gb_sets.xml b/lib/stdlib/doc/src/gb_sets.xml new file mode 100644 index 0000000000..accec623b9 --- /dev/null +++ b/lib/stdlib/doc/src/gb_sets.xml @@ -0,0 +1,487 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>gb_sets</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>gb_sets</module> + <modulesummary>General Balanced Trees</modulesummary> + <description> + <p>An implementation of ordered sets using Prof. Arne Andersson's + General Balanced Trees. This can be much more efficient than + using ordered lists, for larger sets, but depends on the + application.</p> + </description> + + <section> + <title>Complexity note</title> + <p>The complexity on set operations is bounded by either O(|S|) or + O(|T| * log(|S|)), where S is the largest given set, depending + on which is fastest for any particular function call. For + operating on sets of almost equal size, this implementation is + about 3 times slower than using ordered-list sets directly. For + sets of very different sizes, however, this solution can be + arbitrarily much faster; in practical cases, often between 10 + and 100 times. This implementation is particularly suited for + accumulating elements a few at a time, building up a large set + (more than 100-200 elements), and repeatedly testing for + membership in the current set.</p> + <p>As with normal tree structures, lookup (membership testing), + insertion and deletion have logarithmic complexity.</p> + </section> + + <section> + <title>Compatibility</title> + <p>All of the following functions in this module also exist + and do the same thing in the <c>sets</c> and <c>ordsets</c> + modules. That is, by only changing the module name for each call, + you can try out different set representations.</p> + <p></p> + <list type="bulleted"> + <item> + <p><c>add_element/2</c></p> + </item> + <item> + <p><c>del_element/2</c></p> + </item> + <item> + <p><c>filter/2</c></p> + </item> + <item> + <p><c>fold/3</c></p> + </item> + <item> + <p><c>from_list/1</c></p> + </item> + <item> + <p><c>intersection/1</c></p> + </item> + <item> + <p><c>intersection/2</c></p> + </item> + <item> + <p><c>is_element/2</c></p> + </item> + <item> + <p><c>is_set/1</c></p> + </item> + <item> + <p><c>is_subset/2</c></p> + </item> + <item> + <p><c>new/0</c></p> + </item> + <item> + <p><c>size/1</c></p> + </item> + <item> + <p><c>subtract/2</c></p> + </item> + <item> + <p><c>to_list/1</c></p> + </item> + <item> + <p><c>union/1</c></p> + </item> + <item> + <p><c>union/2</c></p> + </item> + </list> + </section> + + <section> + <title>DATA TYPES</title> + <code type="none"> +gb_set() = a GB set</code> + </section> + <funcs> + <func> + <name>add(Element, Set1) -> Set2</name> + <name>add_element(Element, Set1) -> Set2</name> + <fsummary>Add a (possibly existing) element to a gb_set</fsummary> + <type> + <v>Element = term()</v> + <v>Set1 = Set2 = gb_set()</v> + </type> + <desc> + <p>Returns a new gb_set formed from <c>Set1</c> with + <c>Element</c> inserted. If <c>Element</c> is already an + element in <c>Set1</c>, nothing is changed.</p> + </desc> + </func> + <func> + <name>balance(Set1) -> Set2</name> + <fsummary>Rebalance tree representation of a gb_set</fsummary> + <type> + <v>Set1 = Set2 = gb_set()</v> + </type> + <desc> + <p>Rebalances the tree representation of <c>Set1</c>. Note that + this is rarely necessary, but may be motivated when a large + number of elements have been deleted from the tree without + further insertions. Rebalancing could then be forced in order + to minimise lookup times, since deletion only does not + rebalance the tree.</p> + </desc> + </func> + <func> + <name>delete(Element, Set1) -> Set2</name> + <fsummary>Remove an element from a gb_set</fsummary> + <type> + <v>Element = term()</v> + <v>Set1 = Set2 = gb_set()</v> + </type> + <desc> + <p>Returns a new gb_set formed from <c>Set1</c> with + <c>Element</c> removed. Assumes that <c>Element</c> is present + in <c>Set1</c>.</p> + </desc> + </func> + <func> + <name>delete_any(Element, Set1) -> Set2</name> + <name>del_element(Element, Set1) -> Set2</name> + <fsummary>Remove a (possibly non-existing) element from a gb_set</fsummary> + <type> + <v>Element = term()</v> + <v>Set1 = Set2 = gb_set()</v> + </type> + <desc> + <p>Returns a new gb_set formed from <c>Set1</c> with + <c>Element</c> removed. If <c>Element</c> is not an element + in <c>Set1</c>, nothing is changed.</p> + </desc> + </func> + <func> + <name>difference(Set1, Set2) -> Set3</name> + <name>subtract(Set1, Set2) -> Set3</name> + <fsummary>Return the difference of two gb_sets</fsummary> + <type> + <v>Set1 = Set2 = Set3 = gb_set()</v> + </type> + <desc> + <p>Returns only the elements of <c>Set1</c> which are not also + elements of <c>Set2</c>.</p> + </desc> + </func> + <func> + <name>empty() -> Set</name> + <name>new() -> Set</name> + <fsummary>Return an empty gb_set</fsummary> + <type> + <v>Set = gb_set()</v> + </type> + <desc> + <p>Returns a new empty gb_set.</p> + </desc> + </func> + <func> + <name>filter(Pred, Set1) -> Set2</name> + <fsummary>Filter gb_set elements</fsummary> + <type> + <v>Pred = fun (E) -> bool()</v> + <v> E = term()</v> + <v>Set1 = Set2 = gb_set()</v> + </type> + <desc> + <p>Filters elements in <c>Set1</c> using predicate function + <c>Pred</c>.</p> + </desc> + </func> + <func> + <name>fold(Function, Acc0, Set) -> Acc1</name> + <fsummary>Fold over gb_set elements</fsummary> + <type> + <v>Function = fun (E, AccIn) -> AccOut</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v> E = term()</v> + <v>Set = gb_set()</v> + </type> + <desc> + <p>Folds <c>Function</c> over every element in <c>Set</c> + returning the final value of the accumulator.</p> + </desc> + </func> + <func> + <name>from_list(List) -> Set</name> + <fsummary>Convert a list into a gb_set</fsummary> + <type> + <v>List = [term()]</v> + <v>Set = gb_set()</v> + </type> + <desc> + <p>Returns a gb_set of the elements in <c>List</c>, where + <c>List</c> may be unordered and contain duplicates.</p> + </desc> + </func> + <func> + <name>from_ordset(List) -> Set</name> + <fsummary>Make a gb_set from an ordset list</fsummary> + <type> + <v>List = [term()]</v> + <v>Set = gb_set()</v> + </type> + <desc> + <p>Turns an ordered-set list <c>List</c> into a gb_set. The list + must not contain duplicates.</p> + </desc> + </func> + <func> + <name>insert(Element, Set1) -> Set2</name> + <fsummary>Add a new element to a gb_set</fsummary> + <type> + <v>Element = term()</v> + <v>Set1 = Set2 = gb_set()</v> + </type> + <desc> + <p>Returns a new gb_set formed from <c>Set1</c> with + <c>Element</c> inserted. Assumes that <c>Element</c> is not + present in <c>Set1</c>.</p> + </desc> + </func> + <func> + <name>intersection(Set1, Set2) -> Set3</name> + <fsummary>Return the intersection of two gb_sets</fsummary> + <type> + <v>Set1 = Set2 = Set3 = gb_set()</v> + </type> + <desc> + <p>Returns the intersection of <c>Set1</c> and <c>Set2</c>.</p> + </desc> + </func> + <func> + <name>intersection(SetList) -> Set</name> + <fsummary>Return the intersection of a list of gb_sets</fsummary> + <type> + <v>SetList = [gb_set()]</v> + <v>Set = gb_set()</v> + </type> + <desc> + <p>Returns the intersection of the non-empty list of gb_sets.</p> + </desc> + </func> + <func> + <name>is_disjoint(Set1, Set2) -> bool()</name> + <fsummary>Check whether two gb_sets are disjoint</fsummary> + <type> + <v>Set1 = Set2 = gb_set()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Set1</c> and + <c>Set2</c> are disjoint (have no elements in common), + and <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>is_empty(Set) -> bool()</name> + <fsummary>Test for empty gb_set</fsummary> + <type> + <v>Set = gb_set()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Set</c> is an empty set, and + <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>is_member(Element, Set) -> bool()</name> + <name>is_element(Element, Set) -> bool()</name> + <fsummary>Test for membership of a gb_set</fsummary> + <type> + <v>Element = term()</v> + <v>Set = gb_set()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Element</c> is an element of + <c>Set</c>, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>is_set(Term) -> bool()</name> + <fsummary>Test for a gb_set</fsummary> + <type> + <v>Term = term()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Set</c> appears to be a gb_set, + otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>is_subset(Set1, Set2) -> bool()</name> + <fsummary>Test for subset</fsummary> + <type> + <v>Set1 = Set2 = gb_set()</v> + </type> + <desc> + <p>Returns <c>true</c> when every element of <c>Set1</c> is + also a member of <c>Set2</c>, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>iterator(Set) -> Iter</name> + <fsummary>Return an iterator for a gb_set</fsummary> + <type> + <v>Set = gb_set()</v> + <v>Iter = term()</v> + </type> + <desc> + <p>Returns an iterator that can be used for traversing the + entries of <c>Set</c>; see <c>next/1</c>. The implementation + of this is very efficient; traversing the whole set using + <c>next/1</c> is only slightly slower than getting the list + of all elements using <c>to_list/1</c> and traversing that. + The main advantage of the iterator approach is that it does + not require the complete list of all elements to be built in + memory at one time.</p> + </desc> + </func> + <func> + <name>largest(Set) -> term()</name> + <fsummary>Return largest element</fsummary> + <type> + <v>Set = gb_set()</v> + </type> + <desc> + <p>Returns the largest element in <c>Set</c>. Assumes that + <c>Set</c> is nonempty.</p> + </desc> + </func> + <func> + <name>next(Iter1) -> {Element, Iter2} | none</name> + <fsummary>Traverse a gb_set with an iterator</fsummary> + <type> + <v>Iter1 = Iter2 = Element = term()</v> + </type> + <desc> + <p>Returns <c>{Element, Iter2}</c> where <c>Element</c> is the + smallest element referred to by the iterator <c>Iter1</c>, + and <c>Iter2</c> is the new iterator to be used for + traversing the remaining elements, or the atom <c>none</c> if + no elements remain.</p> + </desc> + </func> + <func> + <name>singleton(Element) -> gb_set()</name> + <fsummary>Return a gb_set with one element</fsummary> + <type> + <v>Element = term()</v> + </type> + <desc> + <p>Returns a gb_set containing only the element <c>Element</c>.</p> + </desc> + </func> + <func> + <name>size(Set) -> int()</name> + <fsummary>Return the number of elements in a gb_set</fsummary> + <type> + <v>Set = gb_set()</v> + </type> + <desc> + <p>Returns the number of elements in <c>Set</c>.</p> + </desc> + </func> + <func> + <name>smallest(Set) -> term()</name> + <fsummary>Return smallest element</fsummary> + <type> + <v>Set = gb_set()</v> + </type> + <desc> + <p>Returns the smallest element in <c>Set</c>. Assumes that + <c>Set</c> is nonempty.</p> + </desc> + </func> + <func> + <name>take_largest(Set1) -> {Element, Set2}</name> + <fsummary>Extract largest element</fsummary> + <type> + <v>Set1 = Set2 = gb_set()</v> + <v>Element = term()</v> + </type> + <desc> + <p>Returns <c>{Element, Set2}</c>, where <c>Element</c> is the + largest element in <c>Set1</c>, and <c>Set2</c> is this set + with <c>Element</c> deleted. Assumes that <c>Set1</c> is + nonempty.</p> + </desc> + </func> + <func> + <name>take_smallest(Set1) -> {Element, Set2}</name> + <fsummary>Extract smallest element</fsummary> + <type> + <v>Set1 = Set2 = gb_set()</v> + <v>Element = term()</v> + </type> + <desc> + <p>Returns <c>{Element, Set2}</c>, where <c>Element</c> is the + smallest element in <c>Set1</c>, and <c>Set2</c> is this set + with <c>Element</c> deleted. Assumes that <c>Set1</c> is + nonempty.</p> + </desc> + </func> + <func> + <name>to_list(Set) -> List</name> + <fsummary>Convert a gb_set into a list</fsummary> + <type> + <v>Set = gb_set()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns the elements of <c>Set</c> as a list.</p> + </desc> + </func> + <func> + <name>union(Set1, Set2) -> Set3</name> + <fsummary>Return the union of two gb_sets</fsummary> + <type> + <v>Set1 = Set2 = Set3 = gb_set()</v> + </type> + <desc> + <p>Returns the merged (union) gb_set of <c>Set1</c> and + <c>Set2</c>.</p> + </desc> + </func> + <func> + <name>union(SetList) -> Set</name> + <fsummary>Return the union of a list of gb_sets</fsummary> + <type> + <v>SetList = [gb_set()]</v> + <v>Set = gb_set()</v> + </type> + <desc> + <p>Returns the merged (union) gb_set of the list of gb_sets.</p> + </desc> + </func> + </funcs> + + <section> + <title>SEE ALSO</title> + <p><seealso marker="gb_trees">gb_trees(3)</seealso>, + <seealso marker="ordsets">ordsets(3)</seealso>, + <seealso marker="sets">sets(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/gb_trees.xml b/lib/stdlib/doc/src/gb_trees.xml new file mode 100644 index 0000000000..2bf18138c0 --- /dev/null +++ b/lib/stdlib/doc/src/gb_trees.xml @@ -0,0 +1,367 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>gb_trees</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>gb_trees</module> + <modulesummary>General Balanced Trees</modulesummary> + <description> + <p>An efficient implementation of Prof. Arne Andersson's General + Balanced Trees. These have no storage overhead compared to + unbalanced binary trees, and their performance is in general + better than AVL trees.</p> + </description> + + <section> + <title>Data structure</title> + <p>Data structure:</p> + <code type="none"> + +- {Size, Tree}, where `Tree' is composed of nodes of the form: + - {Key, Value, Smaller, Bigger}, and the "empty tree" node: + - nil.</code> + <p>There is no attempt to balance trees after deletions. Since + deletions do not increase the height of a tree, this should be OK.</p> + <p>Original balance condition <em>h(T) <= ceil(c * log(|T|))</em> + has been changed to the similar (but not quite equivalent) + condition <em>2 ^ h(T) <= |T| ^ c</em>. This should also be OK.</p> + <p>Performance is comparable to the AVL trees in the Erlang book + (and faster in general due to less overhead); the difference is + that deletion works for these trees, but not for the book's + trees. Behaviour is logarithmic (as it should be).</p> + </section> + + <section> + <title>DATA TYPES</title> + <code type="none"> +gb_tree() = a GB tree</code> + </section> + <funcs> + <func> + <name>balance(Tree1) -> Tree2</name> + <fsummary>Rebalance a tree</fsummary> + <type> + <v>Tree1 = Tree2 = gb_tree()</v> + </type> + <desc> + <p>Rebalances <c>Tree1</c>. Note that this is rarely necessary, + but may be motivated when a large number of nodes have been + deleted from the tree without further insertions. Rebalancing + could then be forced in order to minimise lookup times, since + deletion only does not rebalance the tree.</p> + </desc> + </func> + <func> + <name>delete(Key, Tree1) -> Tree2</name> + <fsummary>Remove a node from a tree</fsummary> + <type> + <v>Key = term()</v> + <v>Tree1 = Tree2 = gb_tree()</v> + </type> + <desc> + <p>Removes the node with key <c>Key</c> from <c>Tree1</c>; + returns new tree. Assumes that the key is present in the tree, + crashes otherwise.</p> + </desc> + </func> + <func> + <name>delete_any(Key, Tree1) -> Tree2</name> + <fsummary>Remove a (possibly non-existing) node from a tree</fsummary> + <type> + <v>Key = term()</v> + <v>Tree1 = Tree2 = gb_tree()</v> + </type> + <desc> + <p>Removes the node with key <c>Key</c> from <c>Tree1</c> if + the key is present in the tree, otherwise does nothing; + returns new tree.</p> + </desc> + </func> + <func> + <name>empty() -> Tree</name> + <fsummary>Return an empty tree</fsummary> + <type> + <v>Tree = gb_tree()</v> + </type> + <desc> + <p>Returns a new empty tree</p> + </desc> + </func> + <func> + <name>enter(Key, Val, Tree1) -> Tree2</name> + <fsummary>Insert or update key with value in a tree</fsummary> + <type> + <v>Key = Val = term()</v> + <v>Tree1 = Tree2 = gb_tree()</v> + </type> + <desc> + <p>Inserts <c>Key</c> with value <c>Val</c> into <c>Tree1</c> if + the key is not present in the tree, otherwise updates + <c>Key</c> to value <c>Val</c> in <c>Tree1</c>. Returns the + new tree.</p> + </desc> + </func> + <func> + <name>from_orddict(List) -> Tree</name> + <fsummary>Make a tree from an orddict</fsummary> + <type> + <v>List = [{Key, Val}]</v> + <v> Key = Val = term()</v> + <v>Tree = gb_tree()</v> + </type> + <desc> + <p>Turns an ordered list <c>List</c> of key-value tuples into a + tree. The list must not contain duplicate keys.</p> + </desc> + </func> + <func> + <name>get(Key, Tree) -> Val</name> + <fsummary>Look up a key in a tree, if present</fsummary> + <type> + <v>Key = Val = term()</v> + <v>Tree = gb_tree()</v> + </type> + <desc> + <p>Retrieves the value stored with <c>Key</c> in <c>Tree</c>. + Assumes that the key is present in the tree, crashes + otherwise.</p> + </desc> + </func> + <func> + <name>lookup(Key, Tree) -> {value, Val} | none</name> + <fsummary>Look up a key in a tree</fsummary> + <type> + <v>Key = Val = term()</v> + <v>Tree = gb_tree()</v> + </type> + <desc> + <p>Looks up <c>Key</c> in <c>Tree</c>; returns + <c>{value, Val}</c>, or <c>none</c> if <c>Key</c> is not + present.</p> + </desc> + </func> + <func> + <name>insert(Key, Val, Tree1) -> Tree2</name> + <fsummary>Insert a new key and value in a tree</fsummary> + <type> + <v>Key = Val = term()</v> + <v>Tree1 = Tree2 = gb_tree()</v> + </type> + <desc> + <p>Inserts <c>Key</c> with value <c>Val</c> into <c>Tree1</c>; + returns the new tree. Assumes that the key is not present in + the tree, crashes otherwise.</p> + </desc> + </func> + <func> + <name>is_defined(Key, Tree) -> bool()</name> + <fsummary>Test for membership of a tree</fsummary> + <type> + <v>Tree = gb_tree()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Key</c> is present in <c>Tree</c>, + otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>is_empty(Tree) -> bool()</name> + <fsummary>Test for empty tree</fsummary> + <type> + <v>Tree = gb_tree()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Tree</c> is an empty tree, and + <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>iterator(Tree) -> Iter</name> + <fsummary>Return an iterator for a tree</fsummary> + <type> + <v>Tree = gb_tree()</v> + <v>Iter = term()</v> + </type> + <desc> + <p>Returns an iterator that can be used for traversing the + entries of <c>Tree</c>; see <c>next/1</c>. The implementation + of this is very efficient; traversing the whole tree using + <c>next/1</c> is only slightly slower than getting the list + of all elements using <c>to_list/1</c> and traversing that. + The main advantage of the iterator approach is that it does + not require the complete list of all elements to be built in + memory at one time.</p> + </desc> + </func> + <func> + <name>keys(Tree) -> [Key]</name> + <fsummary>Return a list of the keys in a tree</fsummary> + <type> + <v>Tree = gb_tree()</v> + <v>Key = term()</v> + </type> + <desc> + <p>Returns the keys in <c>Tree</c> as an ordered list.</p> + </desc> + </func> + <func> + <name>largest(Tree) -> {Key, Val}</name> + <fsummary>Return largest key and value</fsummary> + <type> + <v>Tree = gb_tree()</v> + <v>Key = Val = term()</v> + </type> + <desc> + <p>Returns <c>{Key, Val}</c>, where <c>Key</c> is the largest + key in <c>Tree</c>, and <c>Val</c> is the value associated + with this key. Assumes that the tree is nonempty.</p> + </desc> + </func> + <func> + <name>map(Function, Tree1) -> Tree2</name> + <fsummary>Return largest key and value</fsummary> + <type> + <v>Function = fun(K, V1) -> V2</v> + <v>Tree1 = Tree2 = gb_tree()</v> + </type> + <desc><p>maps the function F(K, V1) -> V2 to all key-value pairs + of the tree Tree1 and returns a new tree Tree2 with the same set of keys + as Tree1 and the new set of values V2.</p> + </desc> + </func> + <func> + <name>next(Iter1) -> {Key, Val, Iter2} | none</name> + <fsummary>Traverse a tree with an iterator</fsummary> + <type> + <v>Iter1 = Iter2 = Key = Val = term()</v> + </type> + <desc> + <p>Returns <c>{Key, Val, Iter2}</c> where <c>Key</c> is the + smallest key referred to by the iterator <c>Iter1</c>, and + <c>Iter2</c> is the new iterator to be used for + traversing the remaining nodes, or the atom <c>none</c> if no + nodes remain.</p> + </desc> + </func> + <func> + <name>size(Tree) -> int()</name> + <fsummary>Return the number of nodes in a tree</fsummary> + <type> + <v>Tree = gb_tree()</v> + </type> + <desc> + <p>Returns the number of nodes in <c>Tree</c>.</p> + </desc> + </func> + <func> + <name>smallest(Tree) -> {Key, Val}</name> + <fsummary>Return smallest key and value</fsummary> + <type> + <v>Tree = gb_tree()</v> + <v>Key = Val = term()</v> + </type> + <desc> + <p>Returns <c>{Key, Val}</c>, where <c>Key</c> is the smallest + key in <c>Tree</c>, and <c>Val</c> is the value associated + with this key. Assumes that the tree is nonempty.</p> + </desc> + </func> + <func> + <name>take_largest(Tree1) -> {Key, Val, Tree2}</name> + <fsummary>Extract largest key and value</fsummary> + <type> + <v>Tree1 = Tree2 = gb_tree()</v> + <v>Key = Val = term()</v> + </type> + <desc> + <p>Returns <c>{Key, Val, Tree2}</c>, where <c>Key</c> is the + largest key in <c>Tree1</c>, <c>Val</c> is the value + associated with this key, and <c>Tree2</c> is this tree with + the corresponding node deleted. Assumes that the tree is + nonempty.</p> + </desc> + </func> + <func> + <name>take_smallest(Tree1) -> {Key, Val, Tree2}</name> + <fsummary>Extract smallest key and value</fsummary> + <type> + <v>Tree1 = Tree2 = gb_tree()</v> + <v>Key = Val = term()</v> + </type> + <desc> + <p>Returns <c>{Key, Val, Tree2}</c>, where <c>Key</c> is the + smallest key in <c>Tree1</c>, <c>Val</c> is the value + associated with this key, and <c>Tree2</c> is this tree with + the corresponding node deleted. Assumes that the tree is + nonempty.</p> + </desc> + </func> + <func> + <name>to_list(Tree) -> [{Key, Val}]</name> + <fsummary>Convert a tree into a list</fsummary> + <type> + <v>Tree = gb_tree()</v> + <v>Key = Val = term()</v> + </type> + <desc> + <p>Converts a tree into an ordered list of key-value tuples.</p> + </desc> + </func> + <func> + <name>update(Key, Val, Tree1) -> Tree2</name> + <fsummary>Update a key to new value in a tree</fsummary> + <type> + <v>Key = Val = term()</v> + <v>Tree1 = Tree2 = gb_tree()</v> + </type> + <desc> + <p>Updates <c>Key</c> to value <c>Val</c> in <c>Tree1</c>; + returns the new tree. Assumes that the key is present in the + tree.</p> + </desc> + </func> + <func> + <name>values(Tree) -> [Val]</name> + <fsummary>Return a list of the values in a tree</fsummary> + <type> + <v>Tree = gb_tree()</v> + <v>Val = term()</v> + </type> + <desc> + <p>Returns the values in <c>Tree</c> as an ordered list, sorted + by their corresponding keys. Duplicates are not removed.</p> + </desc> + </func> + </funcs> + + <section> + <title>SEE ALSO</title> + <p><seealso marker="gb_sets">gb_sets(3)</seealso>, + <seealso marker="dict">dict(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml new file mode 100644 index 0000000000..df09294de6 --- /dev/null +++ b/lib/stdlib/doc/src/gen_event.xml @@ -0,0 +1,641 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>gen_event</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>gen_event</module> + <modulesummary>Generic Event Handling Behaviour</modulesummary> + <description> + <p>A behaviour module for implementing event handling functionality. + The OTP event handling model consists of a generic event manager + process with an arbitrary number of event handlers which are added and + deleted dynamically.</p> + <p>An event manager implemented using this module will have a standard + set of interface functions and include functionality for tracing and + error reporting. It will also fit into an OTP supervision tree. + Refer to <em>OTP Design Principles</em> for more information.</p> + <p>Each event handler is implemented as a callback module exporting + a pre-defined set of functions. The relationship between the behaviour + functions and the callback functions can be illustrated as follows:</p> + <pre> +gen_event module Callback module +---------------- --------------- +gen_event:start_link -----> - + +gen_event:add_handler +gen_event:add_sup_handler -----> Module:init/1 + +gen_event:notify +gen_event:sync_notify -----> Module:handle_event/2 + +gen_event:call -----> Module:handle_call/2 + +- -----> Module:handle_info/2 + +gen_event:delete_handler -----> Module:terminate/2 + +gen_event:swap_handler +gen_event:swap_sup_handler -----> Module1:terminate/2 + Module2:init/1 + +gen_event:which_handlers -----> - + +gen_event:stop -----> Module:terminate/2 + +- -----> Module:code_change/3</pre> + <p>Since each event handler is one callback module, an event manager + will have several callback modules which are added and deleted + dynamically. Therefore <c>gen_event</c> is more tolerant of callback + module errors than the other behaviours. If a callback function for + an installed event handler fails with <c>Reason</c>, or returns a + bad value <c>Term</c>, the event manager will not fail. It will delete + the event handler by calling the callback function + <c>Module:terminate/2</c> (see below), giving as argument + <c>{error,{'EXIT',Reason}}</c> or <c>{error,Term}</c>, respectively. + No other event handler will be affected.</p> + <p>A gen_event process handles system messages as documented in + <seealso marker="sys">sys(3)</seealso>. The <c>sys</c> module + can be used for debugging an event manager.</p> + <p>Note that an event manager <em>does</em> trap exit signals + automatically.</p> + <p>The gen_event process can go into hibernation + (see <seealso marker="erts:erlang#erlang:hibernate/3">erlang(3)</seealso>) if a callback + function in a handler module specifies <c>'hibernate'</c> in its return value. + This might be useful if the server is expected to be idle for a long + time. However this feature should be used with care as hibernation + implies at least two garbage collections (when hibernating and + shortly after waking up) and is not something you'd want to do + between each event handled by a busy event manager.</p> + + <p>It's also worth noting that when multiple event handlers are + invoked, it's sufficient that one single event handler returns a + <c>'hibernate'</c> request for the whole event manager to go into + hibernation.</p> + + <p>Unless otherwise stated, all functions in this module fail if + the specified event manager does not exist or if bad arguments are + given.</p> + </description> + <funcs> + <func> + <name>start_link() -> Result</name> + <name>start_link(EventMgrName) -> Result</name> + <fsummary>Create a generic event manager process in a supervision tree.</fsummary> + <type> + <v>EventMgrName = {local,Name} | {global,Name}</v> + <v> Name = atom()</v> + <v>Result = {ok,Pid} | {error,{already_started,Pid}}</v> + <v> Pid = pid()</v> + </type> + <desc> + <p>Creates an event manager process as part of a supervision + tree. The function should be called, directly or indirectly, + by the supervisor. It will, among other things, ensure that + the event manager is linked to the supervisor.</p> + <p>If <c>EventMgrName={local,Name}</c>, the event manager is + registered locally as <c>Name</c> using <c>register/2</c>. + If <c>EventMgrName={global,Name}</c>, the event manager is + registered globally as <c>Name</c> using + <c>global:register_name/2</c>. If no name is provided, + the event manager is not registered.</p> + <p>If the event manager is successfully created the function + returns <c>{ok,Pid}</c>, where <c>Pid</c> is the pid of + the event manager. If there already exists a process with + the specified <c>EventMgrName</c> the function returns + <c>{error,{already_started,Pid}}</c>, where <c>Pid</c> is + the pid of that process.</p> + </desc> + </func> + <func> + <name>start() -> Result</name> + <name>start(EventMgrName) -> Result</name> + <fsummary>Create a stand-alone event manager process.</fsummary> + <type> + <v>EventMgrName = {local,Name} | {global,Name}</v> + <v> Name = atom()</v> + <v>Result = {ok,Pid} | {error,{already_started,Pid}}</v> + <v> Pid = pid()</v> + </type> + <desc> + <p>Creates a stand-alone event manager process, i.e. an event + manager which is not part of a supervision tree and thus has + no supervisor.</p> + <p>See <c>start_link/0,1</c> for a description of arguments and + return values.</p> + </desc> + </func> + <func> + <name>add_handler(EventMgrRef, Handler, Args) -> Result</name> + <fsummary>Add an event handler to a generic event manager.</fsummary> + <type> + <v>EventMgr = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Handler = Module | {Module,Id}</v> + <v> Module = atom()</v> + <v> Id = term()</v> + <v>Args = term()</v> + <v>Result = ok | {'EXIT',Reason} | term()</v> + <v> Reason = term()</v> + </type> + <desc> + <p>Adds a new event handler to the event manager <c>EventMgrRef</c>. + The event manager will call <c>Module:init/1</c> to initiate + the event handler and its internal state.</p> + <p><c>EventMgrRef</c> can be:</p> + <list type="bulleted"> + <item>the pid,</item> + <item><c>Name</c>, if the event manager is locally registered,</item> + <item><c>{Name,Node}</c>, if the event manager is locally + registered at another node, or</item> + <item><c>{global,Name}</c>, if the event manager is globally + registered.</item> + </list> + <p><c>Handler</c> is the name of the callback module <c>Module</c> or + a tuple <c>{Module,Id}</c>, where <c>Id</c> is any term. + The <c>{Module,Id}</c> representation makes it possible to + identify a specific event handler when there are several event + handlers using the same callback module.</p> + <p><c>Args</c> is an arbitrary term which is passed as the argument + to <c>Module:init/1</c>.</p> + <p>If <c>Module:init/1</c> returns a correct value, the event + manager adds the event handler and this function returns + <c>ok</c>. If <c>Module:init/1</c> fails with <c>Reason</c> or + returns an unexpected value <c>Term</c>, the event handler is + ignored and this function returns <c>{'EXIT',Reason}</c> or + <c>Term</c>, respectively.</p> + </desc> + </func> + <func> + <name>add_sup_handler(EventMgrRef, Handler, Args) -> Result</name> + <fsummary>Add a supervised event handler to a generic event manager.</fsummary> + <type> + <v>EventMgr = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Handler = Module | {Module,Id}</v> + <v> Module = atom()</v> + <v> Id = term()</v> + <v>Args = term()</v> + <v>Result = ok | {'EXIT',Reason} | term()</v> + <v> Reason = term()</v> + </type> + <desc> + <p>Adds a new event handler in the same way as <c>add_handler/3</c> + but will also supervise the connection between the event handler + and the calling process.</p> + <list type="bulleted"> + <item>If the calling process later terminates with <c>Reason</c>, + the event manager will delete the event handler by calling + <c>Module:terminate/2</c> with <c>{stop,Reason}</c> as argument.</item> + <item> + <p>If the event handler later is deleted, the event manager + sends a message<c>{gen_event_EXIT,Handler,Reason}</c> to + the calling process. <c>Reason</c> is one of the following:</p> + <list type="bulleted"> + <item><c>normal</c>, if the event handler has been removed due to a + call to <c>delete_handler/3</c>, or <c>remove_handler</c> + has been returned by a callback function (see below).</item> + <item><c>shutdown</c>, if the event handler has been removed + because the event manager is terminating.</item> + <item><c>{swapped,NewHandler,Pid}</c>, if the process <c>Pid</c> + has replaced the event handler with another event handler + <c>NewHandler</c> using a call to <c>swap_handler/3</c> or + <c>swap_sup_handler/3</c>.</item> + <item>a term, if the event handler is removed due to an error. + Which term depends on the error.</item> + </list> + </item> + </list> + <p>See <c>add_handler/3</c> for a description of the arguments + and return values.</p> + </desc> + </func> + <func> + <name>notify(EventMgrRef, Event) -> ok</name> + <name>sync_notify(EventMgrRef, Event) -> ok</name> + <fsummary>Notify an event manager about an event.</fsummary> + <type> + <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Event = term()</v> + </type> + <desc> + <p>Sends an event notification to the event manager + <c>EventMgrRef</c>. The event manager will call + <c>Module:handle_event/2</c> for each installed event handler to + handle the event.</p> + <p><c>notify</c> is asynchronous and will return immediately after + the event notification has been sent. <c>sync_notify</c> is + synchronous in the sense that it will return <c>ok</c> after + the event has been handled by all event handlers.</p> + <p>See <c>add_handler/3</c> for a description of <c>EventMgrRef</c>.</p> + <p><c>Event</c> is an arbitrary term which is passed as one of + the arguments to <c>Module:handle_event/2</c>.</p> + <p><c>notify</c> will not fail even if the specified event manager + does not exist, unless it is specified as <c>Name</c>.</p> + </desc> + </func> + <func> + <name>call(EventMgrRef, Handler, Request) -> Result</name> + <name>call(EventMgrRef, Handler, Request, Timeout) -> Result</name> + <fsummary>Make a synchronous call to a generic event manager.</fsummary> + <type> + <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Handler = Module | {Module,Id}</v> + <v> Module = atom()</v> + <v> Id = term()</v> + <v>Request = term()</v> + <v>Timeout = int()>0 | infinity</v> + <v>Result = Reply | {error,Error}</v> + <v> Reply = term()</v> + <v> Error = bad_module | {'EXIT',Reason} | term()</v> + <v> Reason = term()</v> + </type> + <desc> + <p>Makes a synchronous call to the event handler <c>Handler</c> + installed in the event manager <c>EventMgrRef</c> by sending a + request and waiting until a reply arrives or a timeout occurs. + The event manager will call <c>Module:handle_call/2</c> to handle + the request.</p> + <p>See <c>add_handler/3</c> for a description of <c>EventMgrRef</c> + and <c>Handler</c>.</p> + <p><c>Request</c> is an arbitrary term which is passed as one of + the arguments to <c>Module:handle_call/2</c>.</p> + <p><c>Timeout</c> is an integer greater than zero which specifies + how many milliseconds to wait for a reply, or the atom + <c>infinity</c> to wait indefinitely. Default value is 5000. + If no reply is received within the specified time, the function + call fails.</p> + <p>The return value <c>Reply</c> is defined in the return value of + <c>Module:handle_call/2</c>. If the specified event handler is not + installed, the function returns <c>{error,bad_module}</c>. If + the callback function fails with <c>Reason</c> or returns an + unexpected value <c>Term</c>, this function returns + <c>{error,{'EXIT',Reason}}</c> or <c>{error,Term}</c>, + respectively.</p> + </desc> + </func> + <func> + <name>delete_handler(EventMgrRef, Handler, Args) -> Result</name> + <fsummary>Delete an event handler from a generic event manager.</fsummary> + <type> + <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Handler = Module | {Module,Id}</v> + <v> Module = atom()</v> + <v> Id = term()</v> + <v>Args = term()</v> + <v>Result = term() | {error,module_not_found} | {'EXIT',Reason}</v> + <v> Reason = term()</v> + </type> + <desc> + <p>Deletes an event handler from the event manager + <c>EventMgrRef</c>. The event manager will call + <c>Module:terminate/2</c> to terminate the event handler.</p> + <p>See <c>add_handler/3</c> for a description of <c>EventMgrRef</c> + and <c>Handler</c>.</p> + <p><c>Args</c> is an arbitrary term which is passed as one of + the arguments to <c>Module:terminate/2</c>.</p> + <p>The return value is the return value of <c>Module:terminate/2</c>. + If the specified event handler is not installed, the function + returns <c>{error,module_not_found}</c>. If the callback function + fails with <c>Reason</c>, the function returns + <c>{'EXIT',Reason}</c>.</p> + </desc> + </func> + <func> + <name>swap_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name> + <fsummary>Replace an event handler in a generic event manager.</fsummary> + <type> + <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Handler1 = Handler2 = Module | {Module,Id}</v> + <v> Module = atom()</v> + <v> Id = term()</v> + <v>Args1 = Args2 = term()</v> + <v>Result = ok | {error,Error}</v> + <v> Error = {'EXIT',Reason} | term()</v> + <v> Reason = term()</v> + </type> + <desc> + <p>Replaces an old event handler with a new event handler in + the event manager <c>EventMgrRef</c>.</p> + <p>See <c>add_handler/3</c> for a description of the arguments.</p> + <p>First the old event handler <c>Handler1</c> is deleted. + The event manager calls <c>Module1:terminate(Args1, ...)</c>, + where <c>Module1</c> is the callback module of <c>Handler1</c>, + and collects the return value.</p> + <p>Then the new event handler <c>Handler2</c> is added and initiated + by calling <c>Module2:init({Args2,Term})</c>, where <c>Module2</c> + is the callback module of <c>Handler2</c> and <c>Term</c> + the return value of <c>Module1:terminate/2</c>. This makes it + possible to transfer information from <c>Handler1</c> to + <c>Handler2</c>.</p> + <p>The new handler will be added even if the the specified old event + handler is not installed in which case <c>Term=error</c>, or if + <c>Module1:terminate/2</c> fails with <c>Reason</c> in which case + <c>Term={'EXIT',Reason}</c>. + The old handler will be deleted even if <c>Module2:init/1</c> + fails.</p> + <p>If there was a supervised connection between <c>Handler1</c> and + a process <c>Pid</c>, there will be a supervised connection + between <c>Handler2</c> and <c>Pid</c> instead.</p> + <p>If <c>Module2:init/1</c> returns a correct value, this function + returns <c>ok</c>. If <c>Module2:init/1</c> fails with + <c>Reason</c> or returns an unexpected value <c>Term</c>, this + this function returns <c>{error,{'EXIT',Reason}}</c> or + <c>{error,Term}</c>, respectively.</p> + </desc> + </func> + <func> + <name>swap_sup_handler(EventMgrRef, {Handler1,Args1}, {Handler2,Args2}) -> Result</name> + <fsummary>Replace an event handler in a generic event manager.</fsummary> + <type> + <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Handler1 = Handler 2 = Module | {Module,Id}</v> + <v> Module = atom()</v> + <v> Id = term()</v> + <v>Args1 = Args2 = term()</v> + <v>Result = ok | {error,Error}</v> + <v> Error = {'EXIT',Reason} | term()</v> + <v> Reason = term()</v> + </type> + <desc> + <p>Replaces an event handler in the event manager <c>EventMgrRef</c> + in the same way as <c>swap_handler/3</c> but will also supervise + the connection between <c>Handler2</c> and the calling process.</p> + <p>See <c>swap_handler/3</c> for a description of the arguments + and return values.</p> + </desc> + </func> + <func> + <name>which_handlers(EventMgrRef) -> [Handler]</name> + <fsummary>Return all event handlers installed in a generic event manager.</fsummary> + <type> + <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Handler = Module | {Module,Id}</v> + <v> Module = atom()</v> + <v> Id = term()</v> + </type> + <desc> + <p>Returns a list of all event handlers installed in the event + manager <c>EventMgrRef</c>.</p> + <p>See <c>add_handler/3</c> for a description of <c>EventMgrRef</c> + and <c>Handler</c>.</p> + </desc> + </func> + <func> + <name>stop(EventMgrRef) -> ok</name> + <fsummary>Terminate a generic event manager.</fsummary> + <type> + <v>EventMgrRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v>Name = Node = atom()</v> + </type> + <desc> + <p>Terminates the event manager <c>EventMgrRef</c>. Before + terminating, the event manager will call + <c>Module:terminate(stop,...)</c> for each installed event + handler.</p> + <p>See <c>add_handler/3</c> for a description of the argument.</p> + </desc> + </func> + </funcs> + + <section> + <title>CALLBACK FUNCTIONS</title> + <p>The following functions should be exported from a <c>gen_event</c> + callback module.</p> + </section> + <funcs> + <func> + <name>Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate}</name> + <fsummary>Initialize an event handler.</fsummary> + <type> + <v>InitArgs = Args | {Args,Term}</v> + <v> Args = Term = term()</v> + <v>State = term()</v> + </type> + <desc> + <p>Whenever a new event handler is added to an event manager, + this function is called to initialize the event handler.</p> + <p>If the event handler is added due to a call to + <c>gen_event:add_handler/3</c> or + <c>gen_event:add_sup_handler/3</c>, <c>InitArgs</c> is + the <c>Args</c> argument of these functions.</p> + <p>If the event handler is replacing another event handler due to + a call to <c>gen_event:swap_handler/3</c> or + <c>gen_event:swap_sup_handler/3</c>, or due to a <c>swap</c> + return tuple from one of the other callback functions, + <c>InitArgs</c> is a tuple <c>{Args,Term}</c> where <c>Args</c> is + the argument provided in the function call/return tuple and + <c>Term</c> is the result of terminating the old event handler, + see <c>gen_event:swap_handler/3</c>.</p> + <p>The function should return <c>{ok,State}</c> or <c>{ok,State, hibernate}</c> + where <c>State</c> is the initial internal state of the event handler.</p> + <p>If <c>{ok,State,hibernate}</c> is returned, the event + manager will go into hibernation (by calling <seealso + marker="proc_lib#hibernate/3">proc_lib:hibernate/3</seealso>), + waiting for the next event to occur.</p> + </desc> + </func> + <func> + <name>Module:handle_event(Event, State) -> Result</name> + <fsummary>Handle an event.</fsummary> + <type> + <v>Event = term()</v> + <v>State = term()</v> + <v>Result = {ok,NewState} | {ok,NewState,hibernate} </v> + <v> | {swap_handler,Args1,NewState,Handler2,Args2} | remove_handler</v> + <v> NewState = term()</v> + <v> Args1 = Args2 = term()</v> + <v> Handler2 = Module2 | {Module2,Id}</v> + <v> Module2 = atom()</v> + <v> Id = term()</v> + </type> + <desc> + <p>Whenever an event manager receives an event sent using + <c>gen_event:notify/2</c> or <c>gen_event:sync_notify/2</c>, this + function is called for each installed event handler to handle + the event.</p> + <p><c>Event</c> is the <c>Event</c> argument of + <c>notify</c>/<c>sync_notify</c>.</p> + <p><c>State</c> is the internal state of the event handler.</p> + <p>If the function returns <c>{ok,NewState}</c> or <c>{ok,NewState,hibernate}</c> + the event handler + will remain in the event manager with the possible updated + internal state <c>NewState</c>.</p> + <p>If <c>{ok,NewState,hibernate}</c> is returned, the event + manager will also go into hibernation (by calling <seealso + marker="proc_lib#hibernate/3">proc_lib:hibernate/3</seealso>), + waiting for the next event to occur. It is sufficient that one of the event + handlers return <c>{ok,NewState,hibernate}</c> for the whole event manager + process to hibernate.</p> + <p>If the function returns + <c>{swap_handler,Args1,NewState,Handler2,Args2}</c> the event + handler will be replaced by <c>Handler2</c> by first calling + <c>Module:terminate(Args1,NewState)</c> and then + <c>Module2:init({Args2,Term})</c> where <c>Term</c> is the return + value of <c>Module:terminate/2</c>. + See <c>gen_event:swap_handler/3</c> for more information.</p> + <p>If the function returns <c>remove_handler</c> the event handler + will be deleted by calling + <c>Module:terminate(remove_handler,State)</c>.</p> + </desc> + </func> + <func> + <name>Module:handle_call(Request, State) -> Result</name> + <fsummary>Handle a synchronous request.</fsummary> + <type> + <v>Request = term()</v> + <v>State = term()</v> + <v>Result = {ok,Reply,NewState} | {ok,Reply,NewState,hibernate}</v> + <v> | {swap_handler,Reply,Args1,NewState,Handler2,Args2}</v> + <v> | {remove_handler, Reply}</v> + <v> Reply = term()</v> + <v> NewState = term()</v> + <v> Args1 = Args2 = term()</v> + <v> Handler2 = Module2 | {Module2,Id}</v> + <v> Module2 = atom()</v> + <v> Id = term()</v> + </type> + <desc> + <p>Whenever an event manager receives a request sent using + <c>gen_event:call/3,4</c>, this function is called for + the specified event handler to handle the request.</p> + <p><c>Request</c> is the <c>Request</c> argument of <c>call</c>.</p> + <p><c>State</c> is the internal state of the event handler.</p> + <p>The return values are the same as for <c>handle_event/2</c> + except they also contain a term <c>Reply</c> which is the reply + given back to the client as the return value of <c>call</c>.</p> + </desc> + </func> + <func> + <name>Module:handle_info(Info, State) -> Result</name> + <fsummary>Handle an incoming message.</fsummary> + <type> + <v>Info = term()</v> + <v>State = term()</v> + <v>Result = {ok,NewState} | {ok,NewState,hibernate}</v> + <v> | {swap_handler,Args1,NewState,Handler2,Args2} | remove_handler</v> + <v> NewState = term()</v> + <v> Args1 = Args2 = term()</v> + <v> Handler2 = Module2 | {Module2,Id}</v> + <v> Module2 = atom()</v> + <v> Id = term()</v> + </type> + <desc> + <p>This function is called for each installed event handler when + an event manager receives any other message than an event or + a synchronous request (or a system message).</p> + <p><c>Info</c> is the received message.</p> + <p>See <c>Module:handle_event/2</c> for a description of State + and possible return values.</p> + </desc> + </func> + <func> + <name>Module:terminate(Arg, State) -> term()</name> + <fsummary>Clean up before deletion.</fsummary> + <type> + <v>Arg = Args | {stop,Reason} | stop | remove_handler</v> + <v> | {error,{'EXIT',Reason}} | {error,Term}</v> + <v> Args = Reason = Term = term()</v> + </type> + <desc> + <p>Whenever an event handler is deleted from an event manager, + this function is called. It should be the opposite of + <c>Module:init/1</c> and do any necessary cleaning up.</p> + <p>If the event handler is deleted due to a call to + <c>gen_event:delete_handler</c>, <c>gen_event:swap_handler/3</c> + or <c>gen_event:swap_sup_handler/3</c>, <c>Arg</c> is + the <c>Args</c> argument of this function call.</p> + <p><c>Arg={stop,Reason}</c> if the event handler has a supervised + connection to a process which has terminated with reason + <c>Reason</c>.</p> + <p><c>Arg=stop</c> if the event handler is deleted because + the event manager is terminating.</p> + <p>The event manager will terminate if it is part of a supervision + tree and it is ordered by its supervisor to terminate. + Even if it is <em>not</em> part of a supervision tree, it will + terminate if it receives an <c>'EXIT'</c> message from + its parent.</p> + <p><c>Arg=remove_handler</c> if the event handler is deleted because + another callback function has returned <c>remove_handler</c> or + <c>{remove_handler,Reply}</c>.</p> + <p><c>Arg={error,Term}</c> if the event handler is deleted because + a callback function returned an unexpected value <c>Term</c>, + or <c>Arg={error,{'EXIT',Reason}}</c> if a callback function + failed.</p> + <p><c>State</c> is the internal state of the event handler.</p> + <p>The function may return any term. If the event handler is + deleted due to a call to <c>gen_event:delete_handler</c>, + the return value of that function will be the return value of this + function. If the event handler is to be replaced with another event + handler due to a swap, the return value will be passed to + the <c>init</c> function of the new event handler. Otherwise + the return value is ignored.</p> + </desc> + </func> + <func> + <name>Module:code_change(OldVsn, State, Extra) -> {ok, NewState}</name> + <fsummary>Update the internal state during upgrade/downgrade.</fsummary> + <type> + <v>OldVsn = Vsn | {down, Vsn}</v> + <v> Vsn = term()</v> + <v>State = NewState = term()</v> + <v>Extra = term()</v> + </type> + <desc> + <p>This function is called for an installed event handler which + should update its internal state during a release + upgrade/downgrade, i.e. when the instruction + <c>{update,Module,Change,...}</c> where + <c>Change={advanced,Extra}</c> is given in the <c>.appup</c> + file. See <em>OTP Design Principles</em> for more + information.</p> + <p>In the case of an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and + in the case of a downgrade, <c>OldVsn</c> is + <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the <c>vsn</c> + attribute(s) of the old version of the callback module + <c>Module</c>. If no such attribute is defined, the version + is the checksum of the BEAM file.</p> + <p><c>State</c> is the internal state of the event handler.</p> + <p><c>Extra</c> is passed as-is from the <c>{advanced,Extra}</c> + part of the update instruction.</p> + <p>The function should return the updated internal state.</p> + </desc> + </func> + </funcs> + + <section> + <title>SEE ALSO</title> + <p><seealso marker="supervisor">supervisor(3)</seealso>, + <seealso marker="sys">sys(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/gen_fsm.xml b/lib/stdlib/doc/src/gen_fsm.xml new file mode 100644 index 0000000000..f5d8b9bb48 --- /dev/null +++ b/lib/stdlib/doc/src/gen_fsm.xml @@ -0,0 +1,743 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>gen_fsm</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>gen_fsm</module> + <modulesummary>Generic Finite State Machine Behaviour</modulesummary> + <description> + <p>A behaviour module for implementing a finite state machine. + A generic finite state machine process (gen_fsm) implemented + using this module will have a standard set of interface functions + and include functionality for tracing and error reporting. It will + also fit into an OTP supervision tree. Refer to + <seealso marker="doc/design_principles:fsm">OTP Design Principles</seealso> for more information.</p> + <p>A gen_fsm assumes all specific parts to be located in a callback + module exporting a pre-defined set of functions. The relationship + between the behaviour functions and the callback functions can be + illustrated as follows:</p> + <pre> +gen_fsm module Callback module +-------------- --------------- +gen_fsm:start_link -----> Module:init/1 + +gen_fsm:send_event -----> Module:StateName/2 + +gen_fsm:send_all_state_event -----> Module:handle_event/3 + +gen_fsm:sync_send_event -----> Module:StateName/3 + +gen_fsm:sync_send_all_state_event -----> Module:handle_sync_event/4 + +- -----> Module:handle_info/3 + +- -----> Module:terminate/3 + +- -----> Module:code_change/4</pre> + <p>If a callback function fails or returns a bad value, the gen_fsm + will terminate.</p> + <p>A gen_fsm handles system messages as documented in + <seealso marker="sys">sys(3)</seealso>. The <c>sys</c> module + can be used for debugging a gen_fsm.</p> + <p>Note that a gen_fsm does not trap exit signals automatically, + this must be explicitly initiated in the callback module.</p> + <p>Unless otherwise stated, all functions in this module fail if + the specified gen_fsm does not exist or if bad arguments are + given.</p> + <p>The gen_fsm process can go into hibernation + (see <seealso marker="erts:erlang#erlang:hibernate/3">erlang(3)</seealso>) if a callback + function specifies <c>'hibernate'</c> instead of a timeout value. This + might be useful if the server is expected to be idle for a long + time. However this feature should be used with care as hibernation + implies at least two garbage collections (when hibernating and + shortly after waking up) and is not something you'd want to do + between each call to a busy state machine.</p> + + </description> + <funcs> + <func> + <name>start_link(Module, Args, Options) -> Result</name> + <name>start_link(FsmName, Module, Args, Options) -> Result</name> + <fsummary>Create a gen_fsm process in a supervision tree.</fsummary> + <type> + <v>FsmName = {local,Name} | {global,GlobalName}</v> + <v> Name = atom()</v> + <v> GlobalName = term()</v> + <v>Module = atom()</v> + <v>Args = term()</v> + <v>Options = [Option]</v> + <v> Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}</v> + <v> Dbgs = [Dbg]</v> + <v> Dbg = trace | log | statistics</v> + <v> | {log_to_file,FileName} | {install,{Func,FuncState}}</v> + <v> SOpts = [SOpt]</v> + <v> SOpt - see erlang:spawn_opt/2,3,4,5</v> + <v>Result = {ok,Pid} | ignore | {error,Error}</v> + <v> Pid = pid()</v> + <v> Error = {already_started,Pid} | term()</v> + </type> + <desc> + <p>Creates a gen_fsm process as part of a supervision tree. + The function should be called, directly or indirectly, by + the supervisor. It will, among other things, ensure that + the gen_fsm is linked to the supervisor.</p> + <p>The gen_fsm process calls <c>Module:init/1</c> to + initialize. To ensure a synchronized start-up procedure, + <c>start_link/3,4</c> does not return until + <c>Module:init/1</c> has returned.</p> + <p>If <c>FsmName={local,Name}</c>, the gen_fsm is registered + locally as <c>Name</c> using <c>register/2</c>. + If <c>FsmName={global,GlobalName}</c>, the gen_fsm is + registered globally as <c>GlobalName</c> using + <c>global:register_name/2</c>. If no name is provided, + the gen_fsm is not registered.</p> + <p><c>Module</c> is the name of the callback module.</p> + <p><c>Args</c> is an arbitrary term which is passed as + the argument to <c>Module:init/1</c>.</p> + <p>If the option <c>{timeout,Time}</c> is present, the gen_fsm + is allowed to spend <c>Time</c> milliseconds initializing + or it will be terminated and the start function will return + <c>{error,timeout}</c>.</p> + <p>If the option <c>{debug,Dbgs}</c> is present, + the corresponding <c>sys</c> function will be called for each + item in <c>Dbgs</c>. See + <seealso marker="sys">sys(3)</seealso>.</p> + <p>If the option <c>{spawn_opt,SOpts}</c> is present, + <c>SOpts</c> will be passed as option list to + the <c>spawn_opt</c> BIF which is used to spawn the gen_fsm + process. See + <seealso marker="erts:erlang#spawn_opt/2">erlang(3)</seealso>.</p> + <note> + <p>Using the spawn option <c>monitor</c> is currently not + allowed, but will cause the function to fail with reason + <c>badarg</c>.</p> + </note> + <p>If the gen_fsm is successfully created and initialized + the function returns <c>{ok,Pid}</c>, where <c>Pid</c> is + the pid of the gen_fsm. If there already exists a process with + the specified <c>FsmName</c>, the function returns + <c>{error,{already_started,Pid}}</c> where <c>Pid</c> is + the pid of that process.</p> + <p>If <c>Module:init/1</c> fails with <c>Reason</c>, + the function returns <c>{error,Reason}</c>. If + <c>Module:init/1</c> returns <c>{stop,Reason}</c> or + <c>ignore</c>, the process is terminated and the function + returns <c>{error,Reason}</c> or <c>ignore</c>, respectively.</p> + </desc> + </func> + <func> + <name>start(Module, Args, Options) -> Result</name> + <name>start(FsmName, Module, Args, Options) -> Result</name> + <fsummary>Create a stand-alone gen_fsm process.</fsummary> + <type> + <v>FsmName = {local,Name} | {global,GlobalName}</v> + <v> Name = atom()</v> + <v> GlobalName = term()</v> + <v>Module = atom()</v> + <v>Args = term()</v> + <v>Options = [Option]</v> + <v> Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}</v> + <v> Dbgs = [Dbg]</v> + <v> Dbg = trace | log | statistics</v> + <v> | {log_to_file,FileName} | {install,{Func,FuncState}}</v> + <v> SOpts = [term()]</v> + <v>Result = {ok,Pid} | ignore | {error,Error}</v> + <v> Pid = pid()</v> + <v> Error = {already_started,Pid} | term()</v> + </type> + <desc> + <p>Creates a stand-alone gen_fsm process, i.e. a gen_fsm which + is not part of a supervision tree and thus has no supervisor.</p> + <p>See <seealso marker="#start_link/3">start_link/3,4</seealso> + for a description of arguments and return values.</p> + </desc> + </func> + <func> + <name>send_event(FsmRef, Event) -> ok</name> + <fsummary>Send an event asynchronously to a generic FSM.</fsummary> + <type> + <v>FsmRef = Name | {Name,Node} | {global,GlobalName} | pid()</v> + <v> Name = Node = atom()</v> + <v> GlobalName = term()</v> + <v>Event = term()</v> + </type> + <desc> + <p>Sends an event asynchronously to the gen_fsm <c>FsmRef</c> + and returns <c>ok</c> immediately. The gen_fsm will call + <c>Module:StateName/2</c> to handle the event, where + <c>StateName</c> is the name of the current state of + the gen_fsm.</p> + <p><c>FsmRef</c> can be:</p> + <list type="bulleted"> + <item>the pid,</item> + <item><c>Name</c>, if the gen_fsm is locally registered,</item> + <item><c>{Name,Node}</c>, if the gen_fsm is locally + registered at another node, or</item> + <item><c>{global,GlobalName}</c>, if the gen_fsm is globally + registered.</item> + </list> + <p><c>Event</c> is an arbitrary term which is passed as one of + the arguments to <c>Module:StateName/2</c>.</p> + </desc> + </func> + <func> + <name>send_all_state_event(FsmRef, Event) -> ok</name> + <fsummary>Send an event asynchronously to a generic FSM.</fsummary> + <type> + <v>FsmRef = Name | {Name,Node} | {global,GlobalName} | pid()</v> + <v> Name = Node = atom()</v> + <v> GlobalName = term()</v> + <v>Event = term()</v> + </type> + <desc> + <p>Sends an event asynchronously to the gen_fsm <c>FsmRef</c> + and returns <c>ok</c> immediately. The gen_fsm will call + <c>Module:handle_event/3</c> to handle the event.</p> + <p>See <seealso marker="#send_event/2">send_event/2</seealso> + for a description of the arguments.</p> + <p>The difference between <c>send_event</c> and + <c>send_all_state_event</c> is which callback function is + used to handle the event. This function is useful when + sending events that are handled the same way in every state, + as only one <c>handle_event</c> clause is needed to handle + the event instead of one clause in each state name function.</p> + </desc> + </func> + <func> + <name>sync_send_event(FsmRef, Event) -> Reply</name> + <name>sync_send_event(FsmRef, Event, Timeout) -> Reply</name> + <fsummary>Send an event synchronously to a generic FSM.</fsummary> + <type> + <v>FsmRef = Name | {Name,Node} | {global,GlobalName} | pid()</v> + <v> Name = Node = atom()</v> + <v> GlobalName = term()</v> + <v>Event = term()</v> + <v>Timeout = int()>0 | infinity</v> + <v>Reply = term()</v> + </type> + <desc> + <p>Sends an event to the gen_fsm <c>FsmRef</c> and waits until a + reply arrives or a timeout occurs. The gen_fsm will call + <c>Module:StateName/3</c> to handle the event, where + <c>StateName</c> is the name of the current state of + the gen_fsm.</p> + <p>See <seealso marker="#send_event/2">send_event/2</seealso> + for a description of <c>FsmRef</c> and <c>Event</c>.</p> + <p><c>Timeout</c> is an integer greater than zero which + specifies how many milliseconds to wait for a reply, or + the atom <c>infinity</c> to wait indefinitely. Default value + is 5000. If no reply is received within the specified time, + the function call fails.</p> + <p>The return value <c>Reply</c> is defined in the return value + of <c>Module:StateName/3</c>.</p> + <p>The ancient behaviour of sometimes consuming the server + exit message if the server died during the call while + linked to the client has been removed in OTP R12B/Erlang 5.6.</p> + </desc> + </func> + <func> + <name>sync_send_all_state_event(FsmRef, Event) -> Reply</name> + <name>sync_send_all_state_event(FsmRef, Event, Timeout) -> Reply</name> + <fsummary>Send an event synchronously to a generic FSM.</fsummary> + <type> + <v>FsmRef = Name | {Name,Node} | {global,GlobalName} | pid()</v> + <v> Name = Node = atom()</v> + <v> GlobalName = term()</v> + <v>Event = term()</v> + <v>Timeout = int()>0 | infinity</v> + <v>Reply = term()</v> + </type> + <desc> + <p>Sends an event to the gen_fsm <c>FsmRef</c> and waits until a + reply arrives or a timeout occurs. The gen_fsm will call + <c>Module:handle_sync_event/4</c> to handle the event.</p> + <p>See <seealso marker="#send_event/2">send_event/2</seealso> + for a description of <c>FsmRef</c> and <c>Event</c>. See + <seealso marker="#sync_send_event/3">sync_send_event/3</seealso> + for a description of <c>Timeout</c> and <c>Reply</c>.</p> + <p>See + <seealso marker="#send_all_state_event/2">send_all_state_event/2</seealso> + for a discussion about the difference between + <c>sync_send_event</c> and <c>sync_send_all_state_event</c>.</p> + </desc> + </func> + <func> + <name>reply(Caller, Reply) -> true</name> + <fsummary>Send a reply to a caller.</fsummary> + <type> + <v>Caller - see below</v> + <v>Reply = term()</v> + </type> + <desc> + <p>This function can be used by a gen_fsm to explicitly send a + reply to a client process that called + <seealso marker="#sync_send_event/2">sync_send_event/2,3</seealso> + or + <seealso marker="#sync_send_all_state_event/2">sync_send_all_state_event/2,3</seealso>, + when the reply cannot be defined in the return value of + <c>Module:State/3</c> or <c>Module:handle_sync_event/4</c>.</p> + <p><c>Caller</c> must be the <c>From</c> argument provided to + the callback function. <c>Reply</c> is an arbitrary term, + which will be given back to the client as the return value of + <c>sync_send_event/2,3</c> or + <c>sync_send_all_state_event/2,3</c>.</p> + </desc> + </func> + <func> + <name>send_event_after(Time, Event) -> Ref</name> + <fsummary>Send a delayed event internally in a generic FSM.</fsummary> + <type> + <v>Time = integer()</v> + <v>Event = term()</v> + <v>Ref = reference()</v> + </type> + <desc> + <p>Sends a delayed event internally in the gen_fsm that calls + this function after <c>Time</c> ms. Returns immediately a + reference that can be used to cancel the delayed send using + <seealso marker="#cancel_timer/1">cancel_timer/1</seealso>.</p> + <p>The gen_fsm will call <c>Module:StateName/2</c> to handle + the event, where <c>StateName</c> is the name of the current + state of the gen_fsm at the time the delayed event is + delivered.</p> + <p><c>Event</c> is an arbitrary term which is passed as one of + the arguments to <c>Module:StateName/2</c>.</p> + </desc> + </func> + <func> + <name>start_timer(Time, Msg) -> Ref</name> + <fsummary>Send a timeout event internally in a generic FSM.</fsummary> + <type> + <v>Time = integer()</v> + <v>Msg = term()</v> + <v>Ref = reference()</v> + </type> + <desc> + <p>Sends a timeout event internally in the gen_fsm that calls + this function after <c>Time</c> ms. Returns immediately a + reference that can be used to cancel the timer using + <seealso marker="#cancel_timer/1">cancel_timer/1</seealso>.</p> + <p>The gen_fsm will call <c>Module:StateName/2</c> to handle + the event, where <c>StateName</c> is the name of the current + state of the gen_fsm at the time the timeout message is + delivered.</p> + <p><c>Msg</c> is an arbitrary term which is passed in the + timeout message, <c>{timeout, Ref, Msg}</c>, as one of + the arguments to <c>Module:StateName/2</c>.</p> + </desc> + </func> + <func> + <name>cancel_timer(Ref) -> RemainingTime | false</name> + <fsummary>Cancel an internal timer in a generic FSM.</fsummary> + <type> + <v>Ref = reference()</v> + <v>RemainingTime = integer()</v> + </type> + <desc> + <p>Cancels an internal timer referred by <c>Ref</c> in the + gen_fsm that calls this function.</p> + <p><c>Ref</c> is a reference returned from + <seealso marker="#send_event_after/2">send_event_after/2</seealso> + or + <seealso marker="#start_timer/2">start_timer/2</seealso>.</p> + <p>If the timer has already timed out, but the event not yet + been delivered, it is cancelled as if it had <em>not</em> + timed out, so there will be no false timer event after + returning from this function.</p> + <p>Returns the remaining time in ms until the timer would + have expired if <c>Ref</c> referred to an active timer, + <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>enter_loop(Module, Options, StateName, StateData)</name> + <name>enter_loop(Module, Options, StateName, StateData, FsmName)</name> + <name>enter_loop(Module, Options, StateName, StateData, Timeout)</name> + <name>enter_loop(Module, Options, StateName, StateData, FsmName, Timeout)</name> + <fsummary>Enter the gen_fsm receive loop</fsummary> + <type> + <v>Module = atom()</v> + <v>Options = [Option]</v> + <v> Option = {debug,Dbgs}</v> + <v> Dbgs = [Dbg]</v> + <v> Dbg = trace | log | statistics</v> + <v> | {log_to_file,FileName} | {install,{Func,FuncState}}</v> + <v>StateName = atom()</v> + <v>StateData = term()</v> + <v>FsmName = {local,Name} | {global,GlobalName}</v> + <v> Name = atom()</v> + <v> GlobalName = term()</v> + <v>Timeout = int() | infinity</v> + </type> + <desc> + <p>Makes an existing process into a gen_fsm. Does not return, + instead the calling process will enter the gen_fsm receive + loop and become a gen_fsm process. The process <em>must</em> + have been started using one of the start functions in + <c>proc_lib</c>, see + <seealso marker="proc_lib">proc_lib(3)</seealso>. The user is + responsible for any initialization of the process, including + registering a name for it.</p> + <p>This function is useful when a more complex initialization + procedure is needed than the gen_fsm behaviour provides.</p> + <p><c>Module</c>, <c>Options</c> and <c>FsmName</c> have + the same meanings as when calling + <seealso marker="#start_link/3">start[_link]/3,4</seealso>. + However, if <c>FsmName</c> is specified, the process must have + been registered accordingly <em>before</em> this function is + called.</p> + <p><c>StateName</c>, <c>StateData</c> and <c>Timeout</c> have + the same meanings as in the return value of + <seealso marker="#Moduleinit">Module:init/1</seealso>. + Also, the callback module <c>Module</c> does not need to + export an <c>init/1</c> function.</p> + <p>Failure: If the calling process was not started by a + <c>proc_lib</c> start function, or if it is not registered + according to <c>FsmName</c>.</p> + </desc> + </func> + </funcs> + + <section> + <title>CALLBACK FUNCTIONS</title> + <p>The following functions should be exported from a <c>gen_fsm</c> + callback module.</p> + <p>In the description, the expression <em>state name</em> is used to + denote a state of the state machine. <em>state data</em> is used + to denote the internal state of the Erlang process which + implements the state machine.</p> + <p></p> + </section> + <funcs> + <func> + <name>Module:init(Args) -> Result</name> + <fsummary>Initialize process and internal state name and state data.</fsummary> + <type> + <v>Args = term()</v> + <v>Return = {ok,StateName,StateData} | {ok,StateName,StateData,Timeout}</v> + <v> | {ok,StateName,StateData,hibernate}</v> + <v> | {stop,Reason} | ignore</v> + <v> StateName = atom()</v> + <v> StateData = term()</v> + <v> Timeout = int()>0 | infinity</v> + <v> Reason = term()</v> + </type> + <desc> + <marker id="Moduleinit"></marker> + <p>Whenever a gen_fsm is started using + <seealso marker="#start/3">gen_fsm:start/3,4</seealso> or + <seealso marker="#start_link/3">gen_fsm:start_link/3,4</seealso>, + this function is called by the new process to initialize.</p> + <p><c>Args</c> is the <c>Args</c> argument provided to the start + function.</p> + <p>If initialization is successful, the function should return + <c>{ok,StateName,StateData}</c>, + <c>{ok,StateName,StateData,Timeout}</c> or <c>{ok,StateName,StateData,hibernate}</c>, + where <c>StateName</c> + is the initial state name and <c>StateData</c> the initial + state data of the gen_fsm.</p> + <p>If an integer timeout value is provided, a timeout will occur + unless an event or a message is received within <c>Timeout</c> + milliseconds. A timeout is represented by the atom + <c>timeout</c> and should be handled by + the <c>Module:StateName/2</c> callback functions. The atom + <c>infinity</c> can be used to wait indefinitely, this is + the default value.</p> + <p>If <c>hibernate</c> is specified instead of a timeout value, the process will go + into hibernation when waiting for the next message to arrive (by calling + <seealso marker="proc_lib#hibernate/3">proc_lib:hibernate/3</seealso>).</p> + <p>If something goes wrong during the initialization + the function should return <c>{stop,Reason}</c>, where + <c>Reason</c> is any term, or <c>ignore</c>.</p> + </desc> + </func> + <func> + <name>Module:StateName(Event, StateData) -> Result</name> + <fsummary>Handle an asynchronous event.</fsummary> + <type> + <v>Event = timeout | term()</v> + <v>StateData = term()</v> + <v>Result = {next_state,NextStateName,NewStateData} </v> + <v> | {next_state,NextStateName,NewStateData,Timeout}</v> + <v> | {next_state,NextStateName,NewStateData,hibernate}</v> + <v> | {stop,Reason,NewStateData}</v> + <v> NextStateName = atom()</v> + <v> NewStateData = term()</v> + <v> Timeout = int()>0 | infinity</v> + <v> Reason = term()</v> + </type> + <desc> + <p>There should be one instance of this function for each + possible state name. Whenever a gen_fsm receives an event + sent using + <seealso marker="#send_event/2">gen_fsm:send_event/2</seealso>, + the instance of this function with the same name as + the current state name <c>StateName</c> is called to handle + the event. It is also called if a timeout occurs.</p> + <p><c>Event</c> is either the atom <c>timeout</c>, if a timeout + has occurred, or the <c>Event</c> argument provided to + <c>send_event/2</c>.</p> + <p><c>StateData</c> is the state data of the gen_fsm.</p> + <p>If the function returns + <c>{next_state,NextStateName,NewStateData}</c>, + <c>{next_state,NextStateName,NewStateData,Timeout}</c> or + <c>{next_state,NextStateName,NewStateData,hibernate}</c>, + the gen_fsm will continue executing with the current state + name set to <c>NextStateName</c> and with the possibly + updated state data <c>NewStateData</c>. See + <c>Module:init/1</c> for a description of <c>Timeout</c> and <c>hibernate</c>.</p> + <p>If the function returns <c>{stop,Reason,NewStateData}</c>, + the gen_fsm will call + <c>Module:terminate(Reason,NewStateData)</c> and terminate.</p> + </desc> + </func> + <func> + <name>Module:handle_event(Event, StateName, StateData) -> Result</name> + <fsummary>Handle an asynchronous event.</fsummary> + <type> + <v>Event = term()</v> + <v>StateName = atom()</v> + <v>StateData = term()</v> + <v>Result = {next_state,NextStateName,NewStateData} </v> + <v> | {next_state,NextStateName,NewStateData,Timeout}</v> + <v> | {next_state,NextStateName,NewStateData,hibernate}</v> + <v> | {stop,Reason,NewStateData}</v> + <v> NextStateName = atom()</v> + <v> NewStateData = term()</v> + <v> Timeout = int()>0 | infinity</v> + <v> Reason = term()</v> + </type> + <desc> + <p>Whenever a gen_fsm receives an event sent using + <seealso marker="#send_all_state_event/2">gen_fsm:send_all_state_event/2</seealso>, + this function is called to handle the event.</p> + <p><c>StateName</c> is the current state name of the gen_fsm.</p> + <p>See <c>Module:StateName/2</c> for a description of the other + arguments and possible return values.</p> + </desc> + </func> + <func> + <name>Module:StateName(Event, From, StateData) -> Result</name> + <fsummary>Handle a synchronous event.</fsummary> + <type> + <v>Event = term()</v> + <v>From = {pid(),Tag}</v> + <v>StateData = term()</v> + <v>Result = {reply,Reply,NextStateName,NewStateData}</v> + <v> | {reply,Reply,NextStateName,NewStateData,Timeout}</v> + <v> | {reply,Reply,NextStateName,NewStateData,hibernate}</v> + <v> | {next_state,NextStateName,NewStateData}</v> + <v> | {next_state,NextStateName,NewStateData,Timeout}</v> + <v> | {next_state,NextStateName,NewStateData,hibernate}</v> + <v> | {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData}</v> + <v> Reply = term()</v> + <v> NextStateName = atom()</v> + <v> NewStateData = term()</v> + <v> Timeout = int()>0 | infinity</v> + <v> Reason = normal | term()</v> + </type> + <desc> + <p>There should be one instance of this function for each + possible state name. Whenever a gen_fsm receives an event + sent using + <seealso marker="#sync_send_event/2">gen_fsm:sync_send_event/2,3</seealso>, + the instance of this function with the same name as + the current state name <c>StateName</c> is called to handle + the event.</p> + <p><c>Event</c> is the <c>Event</c> argument provided to + <c>sync_send_event</c>.</p> + <p><c>From</c> is a tuple <c>{Pid,Tag}</c> where <c>Pid</c> is + the pid of the process which called <c>sync_send_event/2,3</c> + and <c>Tag</c> is a unique tag.</p> + <p><c>StateData</c> is the state data of the gen_fsm.</p> + <p>If the function returns + <c>{reply,Reply,NextStateName,NewStateData}</c>, + <c>{reply,Reply,NextStateName,NewStateData,Timeout}</c> or + <c>{reply,Reply,NextStateName,NewStateData,hibernate}</c>, + <c>Reply</c> will be given back to <c>From</c> as the return + value of <c>sync_send_event/2,3</c>. The gen_fsm then + continues executing with the current state name set to + <c>NextStateName</c> and with the possibly updated state data + <c>NewStateData</c>. See <c>Module:init/1</c> for a + description of <c>Timeout</c> and <c>hibernate</c>.</p> + <p>If the function returns + <c>{next_state,NextStateName,NewStateData}</c>, + <c>{next_state,NextStateName,NewStateData,Timeout}</c> or + <c>{next_state,NextStateName,NewStateData,hibernate}</c>, + the gen_fsm will continue executing in <c>NextStateName</c> + with <c>NewStateData</c>. Any reply to <c>From</c> must be + given explicitly using + <seealso marker="#reply/2">gen_fsm:reply/2</seealso>.</p> + <p>If the function returns + <c>{stop,Reason,Reply,NewStateData}</c>, <c>Reply</c> will be + given back to <c>From</c>. If the function returns + <c>{stop,Reason,NewStateData}</c>, any reply to <c>From</c> + must be given explicitly using <c>gen_fsm:reply/2</c>. + The gen_fsm will then call + <c>Module:terminate(Reason,NewStateData)</c> and terminate.</p> + </desc> + </func> + <func> + <name>Module:handle_sync_event(Event, From, StateName, StateData) -> Result</name> + <fsummary>Handle a synchronous event.</fsummary> + <type> + <v>Event = term()</v> + <v>From = {pid(),Tag}</v> + <v>StateName = atom()</v> + <v>StateData = term()</v> + <v>Result = {reply,Reply,NextStateName,NewStateData}</v> + <v> | {reply,Reply,NextStateName,NewStateData,Timeout}</v> + <v> | {reply,Reply,NextStateName,NewStateData,hibernate}</v> + <v> | {next_state,NextStateName,NewStateData}</v> + <v> | {next_state,NextStateName,NewStateData,Timeout}</v> + <v> | {next_state,NextStateName,NewStateData,hibernate}</v> + <v> | {stop,Reason,Reply,NewStateData} | {stop,Reason,NewStateData}</v> + <v> Reply = term()</v> + <v> NextStateName = atom()</v> + <v> NewStateData = term()</v> + <v> Timeout = int()>0 | infinity</v> + <v> Reason = term()</v> + </type> + <desc> + <p>Whenever a gen_fsm receives an event sent using + <seealso marker="#sync_send_all_state_event/2">gen_fsm:sync_send_all_state_event/2,3</seealso>, + this function is called to handle the event.</p> + <p><c>StateName</c> is the current state name of the gen_fsm.</p> + <p>See <c>Module:StateName/3</c> for a description of the other + arguments and possible return values.</p> + </desc> + </func> + <func> + <name>Module:handle_info(Info, StateName, StateData) -> Result</name> + <fsummary>Handle an incoming message.</fsummary> + <type> + <v>Info = term()</v> + <v>StateName = atom()</v> + <v>StateData = term()</v> + <v>Result = {next_state,NextStateName,NewStateData}</v> + <v> > | {next_state,NextStateName,NewStateData,Timeout}</v> + <v> > | {next_state,NextStateName,NewStateData,hibernate}</v> + <v> > | {stop,Reason,NewStateData}</v> + <v> NextStateName = atom()</v> + <v> NewStateData = term()</v> + <v> Timeout = int()>0 | infinity</v> + <v> Reason = normal | term()</v> + </type> + <desc> + <p>This function is called by a gen_fsm when it receives any + other message than a synchronous or asynchronous event (or a + system message).</p> + <p><c>Info</c> is the received message.</p> + <p>See <c>Module:StateName/2</c> for a description of the other + arguments and possible return values.</p> + </desc> + </func> + <func> + <name>Module:terminate(Reason, StateName, StateData)</name> + <fsummary>Clean up before termination.</fsummary> + <type> + <v>Reason = normal | shutdown | {shutdown,term()} | term()</v> + <v>StateName = atom()</v> + <v>StateData = term()</v> + </type> + <desc> + <p>This function is called by a gen_fsm when it is about to + terminate. It should be the opposite of <c>Module:init/1</c> + and do any necessary cleaning up. When it returns, the gen_fsm + terminates with <c>Reason</c>. The return value is ignored.</p> + <p><c>Reason</c> is a term denoting the stop reason, + <c>StateName</c> is the current state name, and + <c>StateData</c> is the state data of the gen_fsm.</p> + <p><c>Reason</c> depends on why the gen_fsm is terminating. If + it is because another callback function has returned a stop + tuple <c>{stop,..}</c>, <c>Reason</c> will have the value + specified in that tuple. If it is due to a failure, + <c>Reason</c> is the error reason.</p> + <p>If the gen_fsm is part of a supervision tree and is ordered + by its supervisor to terminate, this function will be called + with <c>Reason=shutdown</c> if the following conditions apply:</p> + <list type="bulleted"> + <item>the gen_fsm has been set to trap exit signals, and</item> + <item>the shutdown strategy as defined in the supervisor's + child specification is an integer timeout value, not + <c>brutal_kill</c>.</item> + </list> + <p>Even if the gen_fsm is <em>not</em> part of a supervision tree, + this function will be called if it receives an <c>'EXIT'</c> + message from its parent. <c>Reason</c> will be the same as in + the <c>'EXIT'</c> message.</p> + <p>Otherwise, the gen_fsm will be immediately terminated.</p> + <p>Note that for any other reason than <c>normal</c>, + <c>shutdown</c>, or <c>{shutdown,Term}</c> the gen_fsm is + assumed to terminate due to an error and + an error report is issued using + <seealso marker="kernel:error_logger#format/2">error_logger:format/2</seealso>.</p> + </desc> + </func> + <func> + <name>Module:code_change(OldVsn, StateName, StateData, Extra) -> {ok, NextStateName, NewStateData}</name> + <fsummary>Update the internal state data during upgrade/downgrade.</fsummary> + <type> + <v>OldVsn = Vsn | {down, Vsn}</v> + <v> Vsn = term()</v> + <v>StateName = NextStateName = atom()</v> + <v>StateData = NewStateData = term()</v> + <v>Extra = term()</v> + </type> + <desc> + <p>This function is called by a gen_fsm when it should update + its internal state data during a release upgrade/downgrade, + i.e. when the instruction <c>{update,Module,Change,...}</c> + where <c>Change={advanced,Extra}</c> is given in + the <c>appup</c> file. See + <seealso marker="doc/design_principles:release_handling#instr">OTP Design Principles</seealso>.</p> + <p>In the case of an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and + in the case of a downgrade, <c>OldVsn</c> is + <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the <c>vsn</c> + attribute(s) of the old version of the callback module + <c>Module</c>. If no such attribute is defined, the version is + the checksum of the BEAM file.</p> + <p><c>StateName</c> is the current state name and + <c>StateData</c> the internal state data of the gen_fsm.</p> + <p><c>Extra</c> is passed as-is from the <c>{advanced,Extra}</c> + part of the update instruction.</p> + <p>The function should return the new current state name and + updated internal data.</p> + </desc> + </func> + </funcs> + + <section> + <title>SEE ALSO</title> + <p><seealso marker="gen_event">gen_event(3)</seealso>, + <seealso marker="gen_server">gen_server(3)</seealso>, + <seealso marker="supervisor">supervisor(3)</seealso>, + <seealso marker="proc_lib">proc_lib(3)</seealso>, + <seealso marker="sys">sys(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml new file mode 100644 index 0000000000..8496802259 --- /dev/null +++ b/lib/stdlib/doc/src/gen_server.xml @@ -0,0 +1,612 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>gen_server</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>gen_server</module> + <modulesummary>Generic Server Behaviour</modulesummary> + <description> + <p>A behaviour module for implementing the server of a client-server + relation. A generic server process (gen_server) implemented using + this module will have a standard set of interface functions and + include functionality for tracing and error reporting. It will + also fit into an OTP supervision tree. Refer to + <seealso marker="doc/design_principles:gen_server_concepts">OTP Design Principles</seealso> for more information.</p> + <p>A gen_server assumes all specific parts to be located in a + callback module exporting a pre-defined set of functions. + The relationship between the behaviour functions and the callback + functions can be illustrated as follows:</p> + <pre> +gen_server module Callback module +----------------- --------------- +gen_server:start_link -----> Module:init/1 + +gen_server:call +gen_server:multi_call -----> Module:handle_call/3 + +gen_server:cast +gen_server:abcast -----> Module:handle_cast/2 + +- -----> Module:handle_info/2 + +- -----> Module:terminate/2 + +- -----> Module:code_change/3 </pre> + <p>If a callback function fails or returns a bad value, + the gen_server will terminate.</p> + <p>A gen_server handles system messages as documented in + <seealso marker="sys">sys(3)</seealso>. The <c>sys</c> module + can be used for debugging a gen_server.</p> + <p>Note that a gen_server does not trap exit signals automatically, + this must be explicitly initiated in the callback module.</p> + <p>Unless otherwise stated, all functions in this module fail if + the specified gen_server does not exist or if bad arguments are + given.</p> + + <p>The gen_server process can go into hibernation + (see <seealso marker="erts:erlang#erlang:hibernate/3">erlang(3)</seealso>) if a callback + function specifies <c>'hibernate'</c> instead of a timeout value. This + might be useful if the server is expected to be idle for a long + time. However this feature should be used with care as hibernation + implies at least two garbage collections (when hibernating and + shortly after waking up) and is not something you'd want to do + between each call to a busy server.</p> + + </description> + <funcs> + <func> + <name>start_link(Module, Args, Options) -> Result</name> + <name>start_link(ServerName, Module, Args, Options) -> Result</name> + <fsummary>Create a gen_server process in a supervision tree.</fsummary> + <type> + <v>ServerName = {local,Name} | {global,GlobalName}</v> + <v> Name = atom()</v> + <v> GlobalName = term()</v> + <v>Module = atom()</v> + <v>Args = term()</v> + <v>Options = [Option]</v> + <v> Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}</v> + <v> Dbgs = [Dbg]</v> + <v> Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}</v> + <v> SOpts = [term()]</v> + <v>Result = {ok,Pid} | ignore | {error,Error}</v> + <v> Pid = pid()</v> + <v> Error = {already_started,Pid} | term()</v> + </type> + <desc> + <p>Creates a gen_server process as part of a supervision tree. + The function should be called, directly or indirectly, by + the supervisor. It will, among other things, ensure that + the gen_server is linked to the supervisor.</p> + <p>The gen_server process calls <c>Module:init/1</c> to + initialize. To ensure a synchronized start-up procedure, + <c>start_link/3,4</c> does not return until + <c>Module:init/1</c> has returned.</p> + <p>If <c>ServerName={local,Name}</c> the gen_server is + registered locally as <c>Name</c> using <c>register/2</c>. + If <c>ServerName={global,GlobalName}</c> the gen_server is + registered globally as <c>GlobalName</c> using + <c>global:register_name/2</c>. If no name is provided, + the gen_server is not registered.</p> + <p><c>Module</c> is the name of the callback module.</p> + <p><c>Args</c> is an arbitrary term which is passed as + the argument to <c>Module:init/1</c>.</p> + <p>If the option <c>{timeout,Time}</c> is present, + the gen_server is allowed to spend <c>Time</c> milliseconds + initializing or it will be terminated and the start function + will return <c>{error,timeout}</c>.</p> + <p>If the option <c>{debug,Dbgs}</c> is present, + the corresponding <c>sys</c> function will be called for each + item in <c>Dbgs</c>. See + <seealso marker="sys">sys(3)</seealso>.</p> + <p>If the option <c>{spawn_opt,SOpts}</c> is present, + <c>SOpts</c> will be passed as option list to + the <c>spawn_opt</c> BIF which is used to spawn + the gen_server. See + <seealso marker="erts:erlang#spawn_opt/2">erlang(3)</seealso>.</p> + <note> + <p>Using the spawn option <c>monitor</c> is currently not + allowed, but will cause the function to fail with reason + <c>badarg</c>.</p> + </note> + <p>If the gen_server is successfully created and initialized + the function returns <c>{ok,Pid}</c>, where <c>Pid</c> is + the pid of the gen_server. If there already exists a process + with the specified <c>ServerName</c> the function returns + <c>{error,{already_started,Pid}}</c>, where <c>Pid</c> is + the pid of that process.</p> + <p>If <c>Module:init/1</c> fails with <c>Reason</c>, + the function returns <c>{error,Reason}</c>. If + <c>Module:init/1</c> returns <c>{stop,Reason}</c> or + <c>ignore</c>, the process is terminated and the function + returns <c>{error,Reason}</c> or <c>ignore</c>, respectively.</p> + </desc> + </func> + <func> + <name>start(Module, Args, Options) -> Result</name> + <name>start(ServerName, Module, Args, Options) -> Result</name> + <fsummary>Create a stand-alone gen_server process.</fsummary> + <type> + <v>ServerName = {local,Name} | {global,GlobalName}</v> + <v> Name = atom()</v> + <v> GlobalName = term()</v> + <v>Module = atom()</v> + <v>Args = term()</v> + <v>Options = [Option]</v> + <v> Option = {debug,Dbgs} | {timeout,Time} | {spawn_opt,SOpts}</v> + <v> Dbgs = [Dbg]</v> + <v> Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}</v> + <v> SOpts = [term()]</v> + <v>Result = {ok,Pid} | ignore | {error,Error}</v> + <v> Pid = pid()</v> + <v> Error = {already_started,Pid} | term()</v> + </type> + <desc> + <p>Creates a stand-alone gen_server process, i.e. a gen_server + which is not part of a supervision tree and thus has no + supervisor.</p> + <p>See <seealso marker="#start_link/3">start_link/3,4</seealso> + for a description of arguments and return values.</p> + </desc> + </func> + <func> + <name>call(ServerRef, Request) -> Reply</name> + <name>call(ServerRef, Request, Timeout) -> Reply</name> + <fsummary>Make a synchronous call to a generic server.</fsummary> + <type> + <v>ServerRef = Name | {Name,Node} | {global,GlobalName} | pid()</v> + <v> Node = atom()</v> + <v> GlobalName = term()</v> + <v>Request = term()</v> + <v>Timeout = int()>0 | infinity</v> + <v>Reply = term()</v> + </type> + <desc> + <p>Makes a synchronous call to the gen_server <c>ServerRef</c> + by sending a request and waiting until a reply arrives or a + timeout occurs. The gen_server will call + <c>Module:handle_call/3</c> to handle the request.</p> + <p><c>ServerRef</c> can be:</p> + <list type="bulleted"> + <item>the pid,</item> + <item><c>Name</c>, if the gen_server is locally registered,</item> + <item><c>{Name,Node}</c>, if the gen_server is locally + registered at another node, or</item> + <item><c>{global,GlobalName}</c>, if the gen_server is + globally registered.</item> + </list> + <p><c>Request</c> is an arbitrary term which is passed as one of + the arguments to <c>Module:handle_call/3</c>.</p> + <p><c>Timeout</c> is an integer greater than zero which + specifies how many milliseconds to wait for a reply, or + the atom <c>infinity</c> to wait indefinitely. Default value + is 5000. If no reply is received within the specified time, + the function call fails. If the caller catches the failure + and continues running, and the server is just late with the reply, + it may arrive at any time later into the caller's message queue. + The caller must in this case be prepared for this + and discard any such garbage messages that are two element + tuples with a reference as the first element.</p> + <p>The return value <c>Reply</c> is defined in the return value + of <c>Module:handle_call/3</c>.</p> + <p>The call may fail for several reasons, including timeout and + the called gen_server dying before or during the call.</p> + <p>The ancient behaviour of sometimes consuming the server + exit message if the server died during the call while + linked to the client has been removed in OTP R12B/Erlang 5.6.</p> + </desc> + </func> + <func> + <name>multi_call(Name, Request) -> Result</name> + <name>multi_call(Nodes, Name, Request) -> Result</name> + <name>multi_call(Nodes, Name, Request, Timeout) -> Result</name> + <fsummary>Make a synchronous call to several generic servers.</fsummary> + <type> + <v>Nodes = [Node]</v> + <v> Node = atom()</v> + <v>Name = atom()</v> + <v>Request = term()</v> + <v>Timeout = int()>=0 | infinity</v> + <v>Result = {Replies,BadNodes}</v> + <v> Replies = [{Node,Reply}]</v> + <v> Reply = term()</v> + <v>BadNodes = [Node]</v> + </type> + <desc> + <p>Makes a synchronous call to all gen_servers locally + registered as <c>Name</c> at the specified nodes by first + sending a request to every node and then waiting for + the replies. The gen_servers will call + <c>Module:handle_call/3</c> to handle the request.</p> + <p>The function returns a tuple <c>{Replies,BadNodes}</c> where + <c>Replies</c> is a list of <c>{Node,Reply}</c> and + <c>BadNodes</c> is a list of node that either did not exist, + or where the gen_server <c>Name</c> did not exist or did not + reply.</p> + <p><c>Nodes</c> is a list of node names to which the request + should be sent. Default value is the list of all known nodes + <c>[node()|nodes()]</c>.</p> + <p><c>Name</c> is the locally registered name of each + gen_server.</p> + <p><c>Request</c> is an arbitrary term which is passed as one of + the arguments to <c>Module:handle_call/3</c>.</p> + <p><c>Timeout</c> is an integer greater than zero which + specifies how many milliseconds to wait for each reply, or + the atom <c>infinity</c> to wait indefinitely. Default value + is <c>infinity</c>. If no reply is received from a node within + the specified time, the node is added to <c>BadNodes</c>.</p> + <p>When a reply <c>Reply</c> is received from the gen_server at + a node <c>Node</c>, <c>{Node,Reply}</c> is added to + <c>Replies</c>. <c>Reply</c> is defined in the return value of + <c>Module:handle_call/3</c>.</p> + <warning> + <p>If one of the nodes is not capable of process monitors, + for example C or Java nodes, and the gen_server is not started + when the requests are sent, but starts within 2 seconds, + this function waits the whole <c>Timeout</c>, + which may be infinity.</p> + <p>This problem does not exist if all nodes are Erlang nodes.</p> + </warning> + <p>To avoid that late answers (after the timeout) pollutes + the caller's message queue, a middleman process is used to + do the actual calls. Late answers will then be discarded + when they arrive to a terminated process.</p> + </desc> + </func> + <func> + <name>cast(ServerRef, Request) -> ok</name> + <fsummary>Send an asynchronous request to a generic server.</fsummary> + <type> + <v>ServerRef = Name | {Name,Node} | {global,GlobalName} | pid()</v> + <v> Node = atom()</v> + <v> GlobalName = term()</v> + <v>Request = term()</v> + </type> + <desc> + <p>Sends an asynchronous request to the gen_server + <c>ServerRef</c> and returns <c>ok</c> immediately, ignoring + if the destination node or gen_server does not exist. + The gen_server will call <c>Module:handle_cast/2</c> to + handle the request.</p> + <p>See <seealso marker="#call/2">call/2,3</seealso> for a + description of <c>ServerRef</c>.</p> + <p><c>Request</c> is an arbitrary term which is passed as one + of the arguments to <c>Module:handle_cast/2</c>.</p> + </desc> + </func> + <func> + <name>abcast(Name, Request) -> abcast</name> + <name>abcast(Nodes, Name, Request) -> abcast</name> + <fsummary>Send an asynchronous request to several generic servers.</fsummary> + <type> + <v>Nodes = [Node]</v> + <v> Node = atom()</v> + <v>Name = atom()</v> + <v>Request = term()</v> + </type> + <desc> + <p>Sends an asynchronous request to the gen_servers locally + registered as <c>Name</c> at the specified nodes. The function + returns immediately and ignores nodes that do not exist, or + where the gen_server <c>Name</c> does not exist. + The gen_servers will call <c>Module:handle_cast/2</c> to + handle the request.</p> + <p>See + <seealso marker="#multi_call/2">multi_call/2,3,4</seealso> + for a description of the arguments.</p> + </desc> + </func> + <func> + <name>reply(Client, Reply) -> Result</name> + <fsummary>Send a reply to a client.</fsummary> + <type> + <v>Client - see below</v> + <v>Reply = term()</v> + <v>Result = term()</v> + </type> + <desc> + <p>This function can be used by a gen_server to explicitly send + a reply to a client that called <c>call/2,3</c> or + <c>multi_call/2,3,4</c>, when the reply cannot be defined in + the return value of <c>Module:handle_call/3</c>.</p> + <p><c>Client</c> must be the <c>From</c> argument provided to + the callback function. <c>Reply</c> is an arbitrary term, + which will be given back to the client as the return value of + <c>call/2,3</c> or <c>multi_call/2,3,4</c>.</p> + <p>The return value <c>Result</c> is not further defined, and + should always be ignored.</p> + </desc> + </func> + <func> + <name>enter_loop(Module, Options, State)</name> + <name>enter_loop(Module, Options, State, ServerName)</name> + <name>enter_loop(Module, Options, State, Timeout)</name> + <name>enter_loop(Module, Options, State, ServerName, Timeout)</name> + <fsummary>Enter the gen_server receive loop</fsummary> + <type> + <v>Module = atom()</v> + <v>Options = [Option]</v> + <v> Option = {debug,Dbgs}</v> + <v> Dbgs = [Dbg]</v> + <v> Dbg = trace | log | statistics</v> + <v> | {log_to_file,FileName} | {install,{Func,FuncState}}</v> + <v>State = term()</v> + <v>ServerName = {local,Name} | {global,GlobalName}</v> + <v> Name = atom()</v> + <v> GlobalName = term()</v> + <v>Timeout = int() | infinity</v> + </type> + <desc> + <p>Makes an existing process into a gen_server. Does not return, + instead the calling process will enter the gen_server receive + loop and become a gen_server process. The process + <em>must</em> have been started using one of the start + functions in <c>proc_lib</c>, see + <seealso marker="proc_lib">proc_lib(3)</seealso>. The user is + responsible for any initialization of the process, including + registering a name for it.</p> + <p>This function is useful when a more complex initialization + procedure is needed than the gen_server behaviour provides.</p> + <p><c>Module</c>, <c>Options</c> and <c>ServerName</c> have + the same meanings as when calling + <seealso marker="#start_link/3">gen_server:start[_link]/3,4</seealso>. + However, if <c>ServerName</c> is specified, the process must + have been registered accordingly <em>before</em> this function + is called.</p> + <p><c>State</c> and <c>Timeout</c> have the same meanings as in + the return value of + <seealso marker="#Moduleinit">Module:init/1</seealso>. + Also, the callback module <c>Module</c> does not need to + export an <c>init/1</c> function. </p> + <p>Failure: If the calling process was not started by a + <c>proc_lib</c> start function, or if it is not registered + according to <c>ServerName</c>.</p> + </desc> + </func> + </funcs> + + <section> + <title>CALLBACK FUNCTIONS</title> + <p>The following functions + should be exported from a <c>gen_server</c> callback module.</p> + </section> + <funcs> + <func> + <name>Module:init(Args) -> Result</name> + <fsummary>Initialize process and internal state.</fsummary> + <type> + <v>Args = term()</v> + <v>Result = {ok,State} | {ok,State,Timeout} | {ok,State,hibernate}</v> + <v> | {stop,Reason} | ignore</v> + <v> State = term()</v> + <v> Timeout = int()>=0 | infinity</v> + <v> Reason = term()</v> + </type> + <desc> + <marker id="Moduleinit"></marker> + <p>Whenever a gen_server is started using + <seealso marker="#start/3">gen_server:start/3,4</seealso> or + <seealso marker="#start_link/3">gen_server:start_link/3,4</seealso>, + this function is called by the new process to initialize.</p> + <p><c>Args</c> is the <c>Args</c> argument provided to the start + function.</p> + <p>If the initialization is successful, the function should + return <c>{ok,State}</c>, <c>{ok,State,Timeout}</c> or <c>{ok,State,hibernate}</c>, where + <c>State</c> is the internal state of the gen_server.</p> + <p>If an integer timeout value is provided, a timeout will occur + unless a request or a message is received within + <c>Timeout</c> milliseconds. A timeout is represented by + the atom <c>timeout</c> which should be handled by + the <c>handle_info/2</c> callback function. The atom + <c>infinity</c> can be used to wait indefinitely, this is + the default value.</p> + <p>If <c>hibernate</c> is specified instead of a timeout value, the process will go + into hibernation when waiting for the next message to arrive (by calling + <seealso marker="proc_lib#hibernate/3">proc_lib:hibernate/3</seealso>).</p> + <p>If something goes wrong during the initialization + the function should return <c>{stop,Reason}</c> where + <c>Reason</c> is any term, or <c>ignore</c>.</p> + </desc> + </func> + <func> + <name>Module:handle_call(Request, From, State) -> Result</name> + <fsummary>Handle a synchronous request.</fsummary> + <type> + <v>Request = term()</v> + <v>From = {pid(),Tag}</v> + <v>State = term()</v> + <v>Result = {reply,Reply,NewState} | {reply,Reply,NewState,Timeout}</v> + <v> | {reply,Reply,NewState,hibernate}</v> + <v> | {noreply,NewState} | {noreply,NewState,Timeout}</v> + <v> | {noreply,NewState,hibernate}</v> + <v> | {stop,Reason,Reply,NewState} | {stop,Reason,NewState}</v> + <v> Reply = term()</v> + <v> NewState = term()</v> + <v> Timeout = int()>=0 | infinity</v> + <v> Reason = term()</v> + </type> + <desc> + <p>Whenever a gen_server receives a request sent using + <seealso marker="#call/2">gen_server:call/2,3</seealso> or + <seealso marker="#multi_call/2">gen_server:multi_call/2,3,4</seealso>, + this function is called to handle the request.</p> + <p><c>Request</c> is the <c>Request</c> argument provided + to <c>call</c> or <c>multi_call</c>.</p> + <p><c>From</c> is a tuple <c>{Pid,Tag}</c> where <c>Pid</c> is + the pid of the client and <c>Tag</c> is a unique tag.</p> + <p><c>State</c> is the internal state of the gen_server.</p> + <p>If the function returns <c>{reply,Reply,NewState}</c>, + <c>{reply,Reply,NewState,Timeout}</c> or + <c>{reply,Reply,NewState,hibernate}</c>, <c>Reply</c> will be + given back to <c>From</c> as the return value of + <c>call/2,3</c> or included in the return value of + <c>multi_call/2,3,4</c>. The gen_server then continues + executing with the possibly updated internal state + <c>NewState</c>. See <c>Module:init/1</c> for a description + of <c>Timeout</c> and <c>hibernate</c>.</p> + <p>If the functions returns <c>{noreply,NewState}</c>, + <c>{noreply,NewState,Timeout}</c> or <c>{noreply,NewState,hibernate}</c>, + the gen_server will + continue executing with <c>NewState</c>. Any reply to + <c>From</c> must be given explicitly using + <seealso marker="#reply/2">gen_server:reply/2</seealso>.</p> + <p>If the function returns <c>{stop,Reason,Reply,NewState}</c>, + <c>Reply</c> will be given back to <c>From</c>. If + the function returns <c>{stop,Reason,NewState}</c>, any reply + to <c>From</c> must be given explicitly using + <c>gen_server:reply/2</c>. The gen_server will then call + <c>Module:terminate(Reason,NewState)</c> and terminate.</p> + </desc> + </func> + <func> + <name>Module:handle_cast(Request, State) -> Result</name> + <fsummary>Handle an asynchronous request.</fsummary> + <type> + <v>Request = term()</v> + <v>State = term()</v> + <v>Result = {noreply,NewState} | {noreply,NewState,Timeout}</v> + <v> | {noreply,NewState,hibernate}</v> + <v> | {stop,Reason,NewState}</v> + <v> NewState = term()</v> + <v> Timeout = int()>=0 | infinity</v> + <v> Reason = term()</v> + </type> + <desc> + <p>Whenever a gen_server receives a request sent using + <seealso marker="#cast/2">gen_server:cast/2</seealso> or + <seealso marker="#abcast/2">gen_server:abcast/2,3</seealso>, + this function is called to handle the request.</p> + <p>See <c>Module:handle_call/3</c> for a description of + the arguments and possible return values.</p> + </desc> + </func> + <func> + <name>Module:handle_info(Info, State) -> Result</name> + <fsummary>Handle an incoming message.</fsummary> + <type> + <v>Info = timeout | term()</v> + <v>State = term()</v> + <v>Result = {noreply,NewState} | {noreply,NewState,Timeout} </v> + <v> | {noreply,NewState,hibernate}</v> + <v> | {stop,Reason,NewState}</v> + <v> NewState = term()</v> + <v> Timeout = int()>=0 | infinity</v> + <v> Reason = normal | term()</v> + </type> + <desc> + <p>This function is called by a gen_server when a timeout + occurs or when it receives any other message than a + synchronous or asynchronous request (or a system message).</p> + <p><c>Info</c> is either the atom <c>timeout</c>, if a timeout + has occurred, or the received message.</p> + <p>See <c>Module:handle_call/3</c> for a description of + the other arguments and possible return values.</p> + </desc> + </func> + <func> + <name>Module:terminate(Reason, State)</name> + <fsummary>Clean up before termination.</fsummary> + <type> + <v>Reason = normal | shutdown | {shutdown,term()} | term()</v> + <v>State = term()</v> + </type> + <desc> + <p>This function is called by a gen_server when it is about to + terminate. It should be the opposite of <c>Module:init/1</c> + and do any necessary cleaning up. When it returns, + the gen_server terminates with <c>Reason</c>. The return + value is ignored.</p> + <p><c>Reason</c> is a term denoting the stop reason and + <c>State</c> is the internal state of the gen_server.</p> + <p><c>Reason</c> depends on why the gen_server is terminating. + If it is because another callback function has returned a + stop tuple <c>{stop,..}</c>, <c>Reason</c> will have + the value specified in that tuple. If it is due to a failure, + <c>Reason</c> is the error reason.</p> + <p>If the gen_server is part of a supervision tree and is + ordered by its supervisor to terminate, this function will be + called with <c>Reason=shutdown</c> if the following + conditions apply:</p> + <list type="bulleted"> + <item>the gen_server has been set to trap exit signals, and</item> + <item>the shutdown strategy as defined in the supervisor's + child specification is an integer timeout value, not + <c>brutal_kill</c>.</item> + </list> + <p>Even if the gen_server is <em>not</em> part of a supervision tree, + this function will be called if it receives an <c>'EXIT'</c> + message from its parent. <c>Reason</c> will be the same as in + the <c>'EXIT'</c> message.</p> + <p>Otherwise, the gen_server will be immediately terminated.</p> + <p>Note that for any other reason than <c>normal</c>, + <c>shutdown</c>, or <c>{shutdown,Term}</c> the gen_server is + assumed to terminate due to an error and + an error report is issued using + <seealso marker="kernel:error_logger#format/2">error_logger:format/2</seealso>.</p> + </desc> + </func> + <func> + <name>Module:code_change(OldVsn, State, Extra) -> {ok, NewState}</name> + <fsummary>Update the internal state during upgrade/downgrade.</fsummary> + <type> + <v>OldVsn = Vsn | {down, Vsn}</v> + <v> Vsn = term()</v> + <v>State = NewState = term()</v> + <v>Extra = term()</v> + </type> + <desc> + <p>This function is called by a gen_server when it should + update its internal state during a release upgrade/downgrade, + i.e. when the instruction <c>{update,Module,Change,...}</c> + where <c>Change={advanced,Extra}</c> is given in + the <c>appup</c> file. See + <seealso marker="doc/design_principles:release_handling#instr">OTP Design Principles</seealso> + for more information.</p> + <p>In the case of an upgrade, <c>OldVsn</c> is <c>Vsn</c>, and + in the case of a downgrade, <c>OldVsn</c> is + <c>{down,Vsn}</c>. <c>Vsn</c> is defined by the <c>vsn</c> + attribute(s) of the old version of the callback module + <c>Module</c>. If no such attribute is defined, the version + is the checksum of the BEAM file.</p> + <p><c>State</c> is the internal state of the gen_server.</p> + <p><c>Extra</c> is passed as-is from the <c>{advanced,Extra}</c> + part of the update instruction.</p> + <p>The function should return the updated internal state.</p> + </desc> + </func> + </funcs> + + <section> + <title>SEE ALSO</title> + <p><seealso marker="gen_event">gen_event(3)</seealso>, + <seealso marker="gen_fsm">gen_fsm(3)</seealso>, + <seealso marker="supervisor">supervisor(3)</seealso>, + <seealso marker="proc_lib">proc_lib(3)</seealso>, + <seealso marker="sys">sys(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml new file mode 100644 index 0000000000..c075f11792 --- /dev/null +++ b/lib/stdlib/doc/src/io.xml @@ -0,0 +1,1026 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>io</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>io</module> + <modulesummary>Standard IO Server Interface Functions</modulesummary> + <description> + <p>This module provides an interface to standard Erlang IO servers. + The output functions all return <c>ok</c> if they are successful, + or exit if they are not.</p> + <p>In the following description, all functions have an optional + parameter <c>IoDevice</c>. If included, it must be the pid of a + process which handles the IO protocols. Normally, it is the + <c>IoDevice</c> returned by + <seealso marker="kernel:file#open/2">file:open/2</seealso>.</p> + <p>For a description of the IO protocols refer to the STDLIB Users Guide.</p> + <warning> + + <p>As of R13A, data supplied to the <seealso + marker="#put_chars/2">put_chars</seealso> function should be in the + <c>chardata()</c> format described below. This means that programs + supplying binaries to this function need to convert them to UTF-8 + before trying to output the data on an + <c>io_device()</c>.</p> + + <p>If an io_device() is set in binary mode, the functions <seealso + marker="#get_chars/3">get_chars</seealso> and <seealso + marker="#get_line/2">get_line</seealso> may return binaries + instead of lists. The binaries will, as of R13A, be encoded in + UTF-8.</p> + + <p>To work with binaries in ISO-latin-1 encoding, use the <seealso + marker="kernel:file">file</seealso> module instead.</p> + + <p>For conversion functions between character encodings, see the <seealso + marker="stdlib:unicode">unicode</seealso> module.</p> + + </warning> + + </description> + + <section> + <title>DATA TYPES</title> + <code type="none"> +io_device() + as returned by file:open/2, a process handling IO protocols</code> + + <code type="none"> +unicode_binary() = binary() with characters encoded in UTF-8 coding standard +unicode_char() = integer() representing valid unicode codepoint + +chardata() = charlist() | unicode_binary() + +charlist() = [unicode_char() | unicode_binary() | charlist()] + a unicode_binary is allowed as the tail of the list</code> + </section> + <funcs> + <func> + <name>columns([IoDevice]) -> {ok,int()} | {error, enotsup}</name> + <fsummary>Get the number of columns of a device</fsummary> + <type> + <v>IoDevice = io_device()</v> + </type> + <desc> + <p>Retrieves the number of columns of the + <c>IoDevice</c> (i.e. the width of a terminal). The function + only succeeds for terminal devices, for all other devices + the function returns <c>{error, enotsup}</c></p> + </desc> + </func> + <func> + <name>put_chars([IoDevice,] IoData) -> ok</name> + <fsummary>Write a list of characters</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>IoData = chardata()</v> + </type> + <desc> + <p>Writes the characters of <c>IoData</c> to the io_server() + (<c>IoDevice</c>).</p> + </desc> + </func> + <func> + <name>nl([IoDevice]) -> ok</name> + <fsummary>Write a newline</fsummary> + <type> + <v>IoDevice = io_device()</v> + </type> + <desc> + <p>Writes new line to the standard output (<c>IoDevice</c>).</p> + </desc> + </func> + <func> + <name>get_chars([IoDevice,] Prompt, Count) -> Data | eof</name> + <fsummary>Read a specified number of characters</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Prompt = atom() | string()</v> + <v>Count = int()</v> + <v>Data = [ unicode_char() ] | unicode_binary()</v> + </type> + <desc> + <p>Reads <c>Count</c> characters from standard input + (<c>IoDevice</c>), prompting it with <c>Prompt</c>. It + returns:</p> + <taglist> + <tag><c>Data</c></tag> + <item> + <p>The input characters. If the device supports Unicode, + the data may represent codepoints larger than 255 (the + latin1 range). If the io_server() is set to deliver + binaries, they will be encoded in UTF-8 (regardless of if + the device actually supports Unicode or not).</p> + </item> + <tag><c>eof</c></tag> + <item> + <p>End of file was encountered.</p> + </item> + <tag><c>{error,Reason}</c></tag> + <item> + <p>Other (rare) error condition, for instance <c>{error,estale}</c> + if reading from an NFS file system.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>get_line([IoDevice,] Prompt) -> Data | eof | {error,Reason}</name> + <fsummary>Read a line</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Prompt = atom() | string()</v> + <v>Data = [ unicode_char() ] | unicode_binary()</v> + </type> + <desc> + <p>Reads a line from the standard input (<c>IoDevice</c>), + prompting it with <c>Prompt</c>. It returns:</p> + <taglist> + <tag><c>Data</c></tag> + <item> + <p>The characters in the line terminated by a LF (or end of + file). If the device supports Unicode, + the data may represent codepoints larger than 255 (the + latin1 range). If the io_server() is set to deliver + binaries, they will be encoded in UTF-8 (regardless of if + the device actually supports Unicode or not).</p> + </item> + <tag><c>eof</c></tag> + <item> + <p>End of file was encountered.</p> + </item> + <tag><c>{error,Reason}</c></tag> + <item> + <p>Other (rare) error condition, for instance <c>{error,estale}</c> + if reading from an NFS file system.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>getopts([IoDevice]) -> Opts</name> + <fsummary>Get the supported options and values from an I/O-server</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Opts = [Opt]</v> + <v> Opt = {atom(),Value}</v> + <v> Value = term()</v> + </type> + <desc> + <p>This function requests all available options and their current values for a specific io_device(). Example:</p> +<pre> +1> <input>{ok,F} = file:open("/dev/null",[read]).</input> +{ok,<0.42.0>} +2> <input>io:getopts(F).</input> +[{binary,false},{encoding,latin1}]</pre> + <p>Here the file I/O-server returns all available options for a file, + which are the expected ones, <c>encoding</c> and <c>binary</c>. The standard shell however has some more options:</p> +<pre> +3> io:getopts(). +[{expand_fun,#Fun<group.0.120017273>}, + {echo,true}, + {binary,false}, + {encoding,unicode}]</pre> + <p>This example is, as can be seen, run in an environment where the terminal supports Unicode input and output.</p> + </desc> + </func> + <func> + <name>setopts([IoDevice,] Opts) -> ok | {error, Reason}</name> + <fsummary>Set options</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Opts = [Opt]</v> + <v> Opt = atom() | {atom(),Value}</v> + <v> Value = term()</v> + <v>Reason = term()</v> + </type> + <desc> + <p>Set options for the io_device() (<c>IoDevice</c>).</p> + + <p>Possible options and values vary depending on the actual + io_device(). For a list of supported options and their current values + on a specific device, use the <seealso + marker="#getopts/1">getopts/1</seealso> function.</p> + + <p>The options and values supported by the current OTP io_devices are:</p> + <taglist> + <tag><c>binary, list or {binary, bool()}</c></tag> + <item> + <p>If set in binary mode (binary or {binary,true}), the io_server() sends binary data (encoded in UTF-8) as answers to the get_line, get_chars and, if possible, get_until requests (see the I/O protocol description in STDLIB User's Guide for details). The immediate effect is that <c>get_chars/2,3</c> and <c>get_line/1,2</c> return UTF-8 binaries instead of lists of chars for the affected device.</p> + <p>By default, all io_devices in OTP are set in list mode, but the io functions can handle any of these modes and so should other, user written, modules behaving as clients to I/O-servers.</p> + <p>This option is supported by the standard shell (group.erl), the 'oldshell' (user.erl) and the file I/O servers.</p> + </item> + <tag><c>{echo, bool()}</c></tag> + <item> + <p>Denotes if the terminal should echo input. Only supported for the standard shell I/O-server (group.erl)</p> + </item> + <tag><c>{expand_fun, fun()}</c></tag> + <item> + <p>Provide a function for tab-completion (expansion) + like the erlang shell. This function is called + when the user presses the Tab key. The expansion is + active when calling line-reading functions such as + <c>get_line/1,2</c>.</p> + <p>The function is called with the current line, upto + the cursor, as a reversed string. It should return a + three-tuple: <c>{yes|no, string(), [string(), ...]}</c>. The + first element gives a beep if <c>no</c>, otherwise the + expansion is silent, the second is a string that will be + entered at the cursor position, and the third is a list of + possible expansions. If this list is non-empty, the list + will be printed and the current input line will be written + once again.</p> + <p>Trivial example (beep on anything except empty line, which + is expanded to "quit"):</p> + <code type="none"> + fun("") -> {yes, "quit", []}; + (_) -> {no, "", ["quit"]} end</code> + <p>This option is supported by the standard shell only (group.erl).</p> + </item> + <tag><c>{encoding, latin1 | unicode}</c></tag> + <item> + <p>Specifies how characters are input or output from or to the actual device, implying that i.e. a terminal is set to handle Unicode input and output or a file is set to handle UTF-8 data encoding.</p> + <p>The option <em>does not</em> affect how data is returned from the io-functions or how it is sent in the I/O-protocol, it only affects how the io_device() is to handle Unicode characters towards the "physical" device.</p> + <p>The standard shell will be set for either unicode or latin1 encoding when the system is started. The actual encoding is set with the help of the "LANG" or "LC_CTYPE" environment variables on Unix-like system or by other means on other systems. The bottom line is that the user can input Unicode characters and the device will be in {encoding, unicode} mode if the device supports it. The mode can be changed, if the assumption of the runtime system is wrong, by setting this option.</p> + <p>The io_device() used when Erlang is started with the "-oldshell" or "-noshell" flags is by default set to latin1 encoding, meaning that any characters beyond codepoint 255 will be escaped and that input is expected to be plain 8-bit ISO-latin-1. If the encoding is changed to Unicode, input and output from the standard file descriptors will be in UTF-8 (regardless of operating system).</p> + <p>Files can also be set in {encoding, unicode}, meaning that data is written and read as UTF-8. More encodings are possible for files, see below.</p> + <p>{encoding, unicode | latin1} is supported by both the standard shell (group.erl including werl on windows), the 'oldshell' (user.erl) and the file I/O servers.</p> + </item> + <tag><c>{encoding, utf8 | utf16 | utf32 | {utf16,big} | {utf16,little} | {utf32,big} | {utf32,little}}</c></tag> + <item> + <p>For disk files, the encoding can be set to various UTF variants. This will have the effect that data is expected to be read as the specified encoding from the file and the data will be written in the specified encoding to the disk file.</p> + <p>{encoding, utf8} will have the same effect as {encoding,unicode} on files.</p> + <p>The extended encodings are only supported on disk files (opened by the <seealso marker="kernel:file#open/2">file:open/2</seealso> function)</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>write([IoDevice,] Term) -> ok</name> + <fsummary>Write a term</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Term = term()</v> + </type> + <desc> + <p>Writes the term <c>Term</c> to the standard output + (<c>IoDevice</c>).</p> + </desc> + </func> + <func> + <name>read([IoDevice,] Prompt) -> Result</name> + <fsummary>Read a term</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Prompt = atom() | string()</v> + <v>Result = {ok, Term} | eof | {error, ErrorInfo}</v> + <v> Term = term()</v> + <v> ErrorInfo -- see section Error Information below</v> + </type> + <desc> + <p>Reads a term <c>Term</c> from the standard input + (<c>IoDevice</c>), prompting it with <c>Prompt</c>. It + returns:</p> + <taglist> + <tag><c>{ok, Term}</c></tag> + <item> + <p>The parsing was successful.</p> + </item> + <tag><c>eof</c></tag> + <item> + <p>End of file was encountered.</p> + </item> + <tag><c>{error, ErrorInfo}</c></tag> + <item> + <p>The parsing failed.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>read(IoDevice, Prompt, StartLine) -> Result</name> + <fsummary>Read a term</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Prompt = atom() | string()</v> + <v>StartLine = int()</v> + <v>Result = {ok, Term, EndLine} | {eof, EndLine} | {error, ErrorInfo, EndLine}</v> + <v> Term = term()</v> + <v> EndLine = int()</v> + <v> ErrorInfo -- see section Error Information below</v> + </type> + <desc> + <p>Reads a term <c>Term</c> from <c>IoDevice</c>, prompting it + with <c>Prompt</c>. Reading starts at line number + <c>StartLine</c>. It returns:</p> + <taglist> + <tag><c>{ok, Term, EndLine}</c></tag> + <item> + <p>The parsing was successful.</p> + </item> + <tag><c>{eof, EndLine}</c></tag> + <item> + <p>End of file was encountered.</p> + </item> + <tag><c>{error, ErrorInfo, EndLine}</c></tag> + <item> + <p>The parsing failed.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>fwrite(Format) -></name> + <name>fwrite([IoDevice,] Format, Data) -> ok</name> + <name>format(Format) -></name> + <name>format([IoDevice,] Format, Data) -> ok</name> + <fsummary>Write formatted output</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Format = atom() | string() | binary()</v> + <v>Data = [term()]</v> + </type> + <desc> + <p>Writes the items in <c>Data</c> (<c>[]</c>) on the standard + output (<c>IoDevice</c>) in accordance with <c>Format</c>. + <c>Format</c> contains plain characters which are copied to + the output device, and control sequences for formatting, see + below. If <c>Format</c> is an atom or a binary, it is first + converted to a list with the aid of <c>atom_to_list/1</c> + or <c>binary_to_list/1</c>.</p> + <pre> +1> <input>io:fwrite("Hello world!~n", []).</input> +Hello world! +ok</pre> + <p>The general format of a control sequence is <c>~F.P.PadModC</c>. + The character <c>C</c> determines the type of control sequence + to be used, <c>F</c> and <c>P</c> are optional numeric + arguments. If <c>F</c>, <c>P</c>, or <c>Pad</c> is <c>*</c>, + the next argument in <c>Data</c> is used as the numeric value + of <c>F</c> or <c>P</c>.</p> + <p><c>F</c> is the <c>field width</c> of the printed argument. A + negative value means that the argument will be left justified + within the field, otherwise it will be right justified. If no + field width is specified, the required print width will be + used. If the field width specified is too small, then the + whole field will be filled with <c>*</c> characters.</p> + <p><c>P</c> is the <c>precision</c> of the printed argument. A + default value is used if no precision is specified. The + interpretation of precision depends on the control sequences. + Unless otherwise specified, the argument <c>within</c> is used + to determine print width.</p> + <p><c>Pad</c> is the padding character. This is the character + used to pad the printed representation of the argument so that + it conforms to the specified field width and precision. Only + one padding character can be specified and, whenever + applicable, it is used for both the field width and precision. + The default padding character is <c>' '</c> (space).</p> + <p><c>Mod</c> is the control sequence modifier. It is either a + single character (currently only 't', for unicode translation, + is supported) that changes the interpretation of Data.</p> + + <p>The following control sequences are available:</p> + <taglist> + <tag><c>~</c></tag> + <item> + <p>The character <c>~</c> is written.</p> + </item> + <tag><c>c</c></tag> + <item> + <p>The argument is a number that will be interpreted as an + ASCII code. The precision is the number of times the + character is printed and it defaults to the field width, + which in turn defaults to 1. The following example + illustrates:</p> + <pre> +2> <input>io:fwrite("|~10.5c|~-10.5c|~5c|~n", [$a, $b, $c]).</input> +| aaaaa|bbbbb |ccccc| +ok</pre> + <p>If the Unicode translation modifier ('t') is in effect, + the integer argument can be any number representing a + valid unicode codepoint, otherwise it should be an integer + less than or equal to 255, otherwise it is masked with 16#FF:</p> +<pre> +1> <input>io:fwrite("~tc~n",[1024]).</input> +\x{400} +ok +2> <input>io:fwrite("~c~n",[1024]).</input> +^@ +ok</pre> + + </item> + <tag><c>f</c></tag> + <item> + <p>The argument is a float which is written as + <c>[-]ddd.ddd</c>, where the precision is the number of + digits after the decimal point. The default precision is 6 + and it cannot be less than 1.</p> + </item> + <tag><c>e</c></tag> + <item> + <p>The argument is a float which is written as + <c>[-]d.ddde+-ddd</c>, where the precision is the number + of digits written. The default precision is 6 and it + cannot be less than 2.</p> + </item> + <tag><c>g</c></tag> + <item> + <p>The argument is a float which is written as <c>f</c>, if + it is >= 0.1 and < 10000.0. Otherwise, it is written + in the <c>e</c> format. The precision is the number of + significant digits. It defaults to 6 and should not be + less than 2. If the absolute value of the float does not + allow it to be written in the <c>f</c> format with the + desired number of significant digits, it is also written + in the <c>e</c> format.</p> + </item> + <tag><c>s</c></tag> + <item> + <p>Prints the argument with the <c>string</c> syntax. The + argument is, if no Unicode translation modifier is present, an + <seealso marker="erts:erlang#iolist_definition">I/O list</seealso>, a binary, or an atom. If the Unicode translation modifier ('t') is in effect, the argument is chardata(), meaning that binaries are in UTF-8. The characters + are printed without quotes. In this format, the printed + argument is truncated to the given precision and field + width.</p> + <p>This format can be used for printing any object and + truncating the output so it fits a specified field:</p> + <pre> +3> <input>io:fwrite("|~10w|~n", [{hey, hey, hey}]).</input> +|**********| +ok +4> <input>io:fwrite("|~10s|~n", [io_lib:write({hey, hey, hey})]).</input> +|{hey,hey,h| +ok</pre> + <p>A list with integers larger than 255 is considered an error if the Unicode translation modifier is not given:</p> +<pre> +1> <input>io:fwrite("~ts~n",[[1024]]).</input> +\x{400} +ok +2> io:fwrite("~s~n",[[1024]]). +** exception exit: {badarg,[{io,format,[<0.26.0>,"~s~n",[[1024]]]}, + ...</pre> + </item> + <tag><c>w</c></tag> + <item> + <p>Writes data with the standard syntax. This is used to + output Erlang terms. Atoms are printed within quotes if + they contain embedded non-printable characters, and + floats are printed accurately as the shortest, correctly + rounded string.</p> + </item> + <tag><c>p</c></tag> + <item> + <p>Writes the data with standard syntax in the same way as + <c>~w</c>, but breaks terms whose printed representation + is longer than one line into many lines and indents each + line sensibly. It also tries to detect lists of printable + characters and to output these as strings. For example:</p> + <pre> +5> <input>T = [{attributes,[[{id,age,1.50000},{mode,explicit},</input> +<input>{typename,"INTEGER"}], [{id,cho},{mode,explicit},{typename,'Cho'}]]},</input> +<input>{typename,'Person'},{tag,{'PRIVATE',3}},{mode,implicit}].</input> +... +6> <input>io:fwrite("~w~n", [T]).</input> +[{attributes,[[{id,age,1.5},{mode,explicit},{typename, +[73,78,84,69,71,69,82]}],[{id,cho},{mode,explicit},{typena +me,'Cho'}]]},{typename,'Person'},{tag,{'PRIVATE',3}},{mode +,implicit}] +ok +7> <input>io:fwrite("~62p~n", [T]).</input> +[{attributes,[[{id,age,1.5}, + {mode,explicit}, + {typename,"INTEGER"}], + [{id,cho},{mode,explicit},{typename,'Cho'}]]}, + {typename,'Person'}, + {tag,{'PRIVATE',3}}, + {mode,implicit}] +ok</pre> + <p>The field width specifies the maximum line length. It + defaults to 80. The precision specifies the initial + indentation of the term. It defaults to the number of + characters printed on this line in the <c>same</c> call to + <c>io:fwrite</c> or <c>io:format</c>. For example, using + <c>T</c> above:</p> + <pre> +8> <input>io:fwrite("Here T = ~62p~n", [T]).</input> +Here T = [{attributes,[[{id,age,1.5}, + {mode,explicit}, + {typename,"INTEGER"}], + [{id,cho}, + {mode,explicit}, + {typename,'Cho'}]]}, + {typename,'Person'}, + {tag,{'PRIVATE',3}}, + {mode,implicit}] +ok</pre> + </item> + <tag><c>W</c></tag> + <item> + <p>Writes data in the same way as <c>~w</c>, but takes an + extra argument which is the maximum depth to which terms + are printed. Anything below this depth is replaced with + <c>...</c>. For example, using <c>T</c> above:</p> + <pre> +9> <input>io:fwrite("~W~n", [T,9]).</input> +[{attributes,[[{id,age,1.5},{mode,explicit},{typename,...}], +[{id,cho},{mode,...},{...}]]},{typename,'Person'}, +{tag,{'PRIVATE',3}},{mode,implicit}] +ok</pre> + <p>If the maximum depth has been reached, then it is + impossible to read in the resultant output. Also, the + <c>,...</c> form in a tuple denotes that there are more + elements in the tuple but these are below the print depth.</p> + </item> + <tag><c>P</c></tag> + <item> + <p>Writes data in the same way as <c>~p</c>, but takes an + extra argument which is the maximum depth to which terms + are printed. Anything below this depth is replaced with + <c>...</c>. For example:</p> + <pre> +10> <input>io:fwrite("~62P~n", [T,9]).</input> +[{attributes,[[{id,age,1.5},{mode,explicit},{typename,...}], + [{id,cho},{mode,...},{...}]]}, + {typename,'Person'}, + {tag,{'PRIVATE',3}}, + {mode,implicit}] +ok</pre> + </item> + <tag><c>B</c></tag> + <item> + <p>Writes an integer in base 2..36, the default base is + 10. A leading dash is printed for negative integers.</p> + <p>The precision field selects base. For example:</p> + <pre> +11> <input>io:fwrite("~.16B~n", [31]).</input> +1F +ok +12> <input>io:fwrite("~.2B~n", [-19]).</input> +-10011 +ok +13> <input>io:fwrite("~.36B~n", [5*36+35]).</input> +5Z +ok</pre> + </item> + <tag><c>X</c></tag> + <item> + <p>Like <c>B</c>, but takes an extra argument that is a + prefix to insert before the number, but after the leading + dash, if any.</p> + <p>The prefix can be a possibly deep list of characters or + an atom.</p> + <pre> +14> <input>io:fwrite("~X~n", [31,"10#"]).</input> +10#31 +ok +15> <input>io:fwrite("~.16X~n", [-31,"0x"]).</input> +-0x1F +ok</pre> + </item> + <tag><c>#</c></tag> + <item> + <p>Like <c>B</c>, but prints the number with an Erlang style + '#'-separated base prefix.</p> + <pre> +16> <input>io:fwrite("~.10#~n", [31]).</input> +10#31 +ok +17> <input>io:fwrite("~.16#~n", [-31]).</input> +-16#1F +ok</pre> + </item> + <tag><c>b</c></tag> + <item> + <p>Like <c>B</c>, but prints lowercase letters.</p> + </item> + <tag><c>x</c></tag> + <item> + <p>Like <c>X</c>, but prints lowercase letters.</p> + </item> + <tag><c>+</c></tag> + <item> + <p>Like <c>#</c>, but prints lowercase letters.</p> + </item> + <tag><c>n</c></tag> + <item> + <p>Writes a new line.</p> + </item> + <tag><c>i</c></tag> + <item> + <p>Ignores the next term.</p> + </item> + </taglist> + <p>Returns:</p> + <taglist> + <tag><c>ok</c></tag> + <item> + <p>The formatting succeeded.</p> + </item> + </taglist> + <p>If an error occurs, there is no output. For example:</p> + <pre> +18> <input>io:fwrite("~s ~w ~i ~w ~c ~n",['abc def', 'abc def', {foo, 1},{foo, 1}, 65]).</input> +abc def 'abc def' {foo,1} A +ok +19> <input>io:fwrite("~s", [65]).</input> +** exception exit: {badarg,[{io,format,[<0.22.0>,"~s","A"]}, + {erl_eval,do_apply,5}, + {shell,exprs,6}, + {shell,eval_exprs,6}, + {shell,eval_loop,3}]} + in function io:o_request/2</pre> + <p>In this example, an attempt was made to output the single + character '65' with the aid of the string formatting directive + "~s".</p> + </desc> + </func> + <func> + <name>fread([IoDevice,] Prompt, Format) -> Result</name> + <fsummary>Read formatted input</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Prompt = atom() | string()</v> + <v>Format = string()</v> + <v>Result = {ok, Terms} | eof | {error, What}</v> + <v> Terms = [term()]</v> + <v> What = term()</v> + </type> + <desc> + <p>Reads characters from the standard input (<c>IoDevice</c>), + prompting it with <c>Prompt</c>. Interprets the characters in + accordance with <c>Format</c>. <c>Format</c> contains control + sequences which directs the interpretation of the input.</p> + <p><c>Format</c> may contain:</p> + <list type="bulleted"> + <item> + <p>White space characters (SPACE, TAB and NEWLINE) which + cause input to be read to the next non-white space + character.</p> + </item> + <item> + <p>Ordinary characters which must match the next input + character.</p> + </item> + <item> + + <p>Control sequences, which have the general format + <c>~*FMC</c>. The character <c>*</c> is an optional + return suppression character. It provides a method to + specify a field which is to be omitted. <c>F</c> is the + <c>field width</c> of the input field, <c>M</c> is an optional + translation modifier (of which 't' is the only currently + supported, meaning Unicode translation) and <c>C</c> + determines the type of control sequence.</p> + + <p>Unless otherwise specified, leading white-space is + ignored for all control sequences. An input field cannot + be more than one line wide. The following control + sequences are available:</p> + <taglist> + <tag><c>~</c></tag> + <item> + <p>A single <c>~</c> is expected in the input.</p> + </item> + <tag><c>d</c></tag> + <item> + <p>A decimal integer is expected.</p> + </item> + <tag><c>u</c></tag> + <item> + <p>An unsigned integer in base 2..36 is expected. The + field width parameter is used to specify base. Leading + white-space characters are not skipped.</p> + </item> + <tag><c>-</c></tag> + <item> + <p>An optional sign character is expected. A sign + character '-' gives the return value <c>-1</c>. Sign + character '+' or none gives <c>1</c>. The field width + parameter is ignored. Leading white-space characters + are not skipped.</p> + </item> + <tag><c>#</c></tag> + <item> + <p>An integer in base 2..36 with Erlang-style base + prefix (for example <c>"16#ffff"</c>) is expected.</p> + </item> + <tag><c>f</c></tag> + <item> + <p>A floating point number is expected. It must follow + the Erlang floating point number syntax.</p> + </item> + <tag><c>s</c></tag> + <item> + <p>A string of non-white-space characters is read. If a + field width has been specified, this number of + characters are read and all trailing white-space + characters are stripped. An Erlang string (list of + characters) is returned.</p> + + <p>If Unicode translation is in effect (~ts), + characters larger than 255 are accepted, otherwise + not. With the translation modifier, the list + returned may as a consequence also contain + integers larger than 255:</p> + +<pre> +1> <input>io:fread("Prompt> ","~s").</input> +Prompt> <input><Characters beyond latin1 range not printable in this medium></input> +{error,{fread,string}} +2> <input>io:fread("Prompt> ","~ts").</input> +Prompt> <input><Characters beyond latin1 range not printable in this medium></input> +{ok,[[1091,1085,1080,1094,1086,1076,1077]]}</pre> + + </item> + <tag><c>a</c></tag> + <item> + <p>Similar to <c>s</c>, but the resulting string is + converted into an atom.</p> + <p>The Unicode translation modifier is not allowed (atoms can not contain characters beyond the latin1 range).</p> + </item> + <tag><c>c</c></tag> + <item> + <p>The number of characters equal to the field width are + read (default is 1) and returned as an Erlang string. + However, leading and trailing white-space characters + are not omitted as they are with <c>s</c>. All + characters are returned.</p> + <p>The Unicode translation modifier works as with <c>s</c>:</p> +<pre> +1> <input>io:fread("Prompt> ","~c").</input> +Prompt> <input><Character beyond latin1 range not printable in this medium></input> +{error,{fread,string}} +2> <input>io:fread("Prompt> ","~tc").</input> +Prompt> <input><Character beyond latin1 range not printable in this medium></input> +{ok,[[1091]]}</pre> + + </item> + <tag><c>l</c></tag> + <item> + <p>Returns the number of characters which have been + scanned up to that point, including white-space + characters.</p> + </item> + </taglist> + <p>It returns:</p> + <taglist> + <tag><c>{ok, Terms}</c></tag> + <item> + <p>The read was successful and <c>Terms</c> is the list + of successfully matched and read items.</p> + </item> + <tag><c>eof</c></tag> + <item> + <p>End of file was encountered.</p> + </item> + <tag><c>{error, What}</c></tag> + <item> + <p>The read operation failed and the parameter + <c>What</c> gives a hint about the error.</p> + </item> + </taglist> + </item> + </list> + <p>Examples:</p> + <pre> +20> <input>io:fread('enter>', "~f~f~f").</input> +enter><input>1.9 35.5e3 15.0</input> +{ok,[1.9,3.55e4,15.0]} +21> <input>io:fread('enter>', "~10f~d").</input> +enter> <input>5.67899</input> +{ok,[5.678,99]} +22> <input>io:fread('enter>', ":~10s:~10c:").</input> +enter><input>:</input> <input>alan</input> <input>:</input> <input>joe</input> <input>:</input> +{ok, ["alan", " joe "]}</pre> + </desc> + </func> + <func> + <name>rows([IoDevice]) -> {ok,int()} | {error, enotsup}</name> + <fsummary>Get the number of rows of a device</fsummary> + <type> + <v>IoDevice = io_device()</v> + </type> + <desc> + <p>Retrieves the number of rows of the + <c>IoDevice</c> (i.e. the height of a terminal). The function + only succeeds for terminal devices, for all other devices + the function returns <c>{error, enotsup}</c></p> + </desc> + </func> + <func> + <name>scan_erl_exprs(Prompt) -></name> + <name>scan_erl_exprs([IoDevice,] Prompt, StartLine) -> Result</name> + <fsummary>Read and tokenize Erlang expressions</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Prompt = atom() | string()</v> + <v>StartLine = int()</v> + <v>Result = {ok, Tokens, EndLine} | {eof, EndLine} | {error, ErrorInfo, EndLine}</v> + <v> Tokens -- see erl_scan(3)</v> + <v> EndLine = int()</v> + <v> ErrorInfo -- see section Error Information below</v> + </type> + <desc> + <p>Reads data from the standard input (<c>IoDevice</c>), + prompting it with <c>Prompt</c>. Reading starts at line number + <c>StartLine</c> (1). The data is tokenized as if it were a + sequence of Erlang expressions until a final <c>'.'</c> is + reached. This token is also returned. It returns:</p> + <taglist> + <tag><c>{ok, Tokens, EndLine}</c></tag> + <item> + <p>The tokenization succeeded.</p> + </item> + <tag><c>{eof, EndLine}</c></tag> + <item> + <p>End of file was encountered.</p> + </item> + <tag><c>{error, ErrorInfo, EndLine}</c></tag> + <item> + <p>An error occurred.</p> + </item> + </taglist> + <p>Example:</p> + <pre> +23> <input>io:scan_erl_exprs('enter>').</input> +enter><input>abc(), "hey".</input> +{ok,[{atom,1,abc},{'(',1},{')',1},{',',1},{string,1,"hey"},{dot,1}],2} +24> <input>io:scan_erl_exprs('enter>').</input> +enter><input>1.0er.</input> +{error,{1,erl_scan,{illegal,float}},2}</pre> + </desc> + </func> + <func> + <name>scan_erl_form(Prompt) -></name> + <name>scan_erl_form([IoDevice,] Prompt, StartLine) -> Result</name> + <fsummary>Read and tokenize an Erlang form</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Prompt = atom() | string()</v> + <v>StartLine = int()</v> + <v>Result = {ok, Tokens, EndLine} | {eof, EndLine} | {error, ErrorInfo, EndLine}</v> + <v> Tokens -- see erl_scan(3)</v> + <v> EndLine = int()</v> + <v> ErrorInfo -- see section Error Information below</v> + </type> + <desc> + <p>Reads data from the standard input (<c>IoDevice</c>), + prompting it with <c>Prompt</c>. Starts reading at line number + <c>StartLine</c> (1). The data is tokenized as if it were an + Erlang form - one of the valid Erlang expressions in an + Erlang source file - until a final <c>'.'</c> is reached. + This last token is also returned. The return values are the + same as for <c>scan_erl_exprs/1,2,3</c> above.</p> + </desc> + </func> + <func> + <name>parse_erl_exprs(Prompt) -></name> + <name>parse_erl_exprs([IoDevice,] Prompt, StartLine) -> Result</name> + <fsummary>Read, tokenize and parse Erlang expressions</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Prompt = atom() | string()</v> + <v>StartLine = int()</v> + <v>Result = {ok, Expr_list, EndLine} | {eof, EndLine} | {error, ErrorInfo, EndLine}</v> + <v> Expr_list -- see erl_parse(3)</v> + <v> EndLine = int()</v> + <v> ErrorInfo -- see section Error Information below</v> + </type> + <desc> + <p>Reads data from the standard input (<c>IoDevice</c>), + prompting it with <c>Prompt</c>. Starts reading at line number + <c>StartLine</c> (1). The data is tokenized and parsed as if + it were a sequence of Erlang expressions until a final '.' is + reached. It returns:</p> + <taglist> + <tag><c>{ok, Expr_list, EndLine}</c></tag> + <item> + <p>The parsing was successful.</p> + </item> + <tag><c>{eof, EndLine}</c></tag> + <item> + <p>End of file was encountered.</p> + </item> + <tag><c>{error, ErrorInfo, EndLine}</c></tag> + <item> + <p>An error occurred.</p> + </item> + </taglist> + <p>Example:</p> + <pre> +25> <input>io:parse_erl_exprs('enter>').</input> +enter><input>abc(), "hey".</input> +{ok, [{call,1,{atom,1,abc},[]},{string,1,"hey"}],2} +26> <input>io:parse_erl_exprs ('enter>').</input> +enter><input>abc("hey".</input> +{error,{1,erl_parse,["syntax error before: ",["'.'"]]},2}</pre> + </desc> + </func> + <func> + <name>parse_erl_form(Prompt) -></name> + <name>parse_erl_form([IoDevice,] Prompt, StartLine) -> Result</name> + <fsummary>Read, tokenize and parse an Erlang form</fsummary> + <type> + <v>IoDevice = io_device()</v> + <v>Prompt = atom() | string()</v> + <v>StartLine = int()</v> + <v>Result = {ok, AbsForm, EndLine} | {eof, EndLine} | {error, ErrorInfo, EndLine}</v> + <v> AbsForm -- see erl_parse(3)</v> + <v> EndLine = int()</v> + <v> ErrorInfo -- see section Error Information below</v> + </type> + <desc> + <p>Reads data from the standard input (<c>IoDevice</c>), + prompting it with <c>Prompt</c>. Starts reading at line number + <c>StartLine</c> (1). The data is tokenized and parsed as if + it were an Erlang form - one of the valid Erlang expressions + in an Erlang source file - until a final '.' is reached. It + returns:</p> + <taglist> + <tag><c>{ok, AbsForm, EndLine}</c></tag> + <item> + <p>The parsing was successful.</p> + </item> + <tag><c>{eof, EndLine}</c></tag> + <item> + <p>End of file was encountered.</p> + </item> + <tag><c>{error, ErrorInfo, EndLine}</c></tag> + <item> + <p>An error occurred.</p> + </item> + </taglist> + </desc> + </func> + </funcs> + + <section> + <title>Standard Input/Output</title> + <p>All Erlang processes have a default standard IO device. This + device is used when no <c>IoDevice</c> argument is specified in + the above function calls. However, it is sometimes desirable to + use an explicit <c>IoDevice</c> argument which refers to the + default IO device. This is the case with functions that can + access either a file or the default IO device. The atom + <c>standard_io</c> has this special meaning. The following example + illustrates this:</p> + <pre> +27> <input>io:read('enter>').</input> +enter><input>foo.</input> +{ok,foo} +28> <input>io:read(standard_io, 'enter>').</input> +enter><input>bar.</input> +{ok,bar}</pre> + <p>There is always a process registered under the name of + <c>user</c>. This can be used for sending output to the user.</p> + </section> + <section> + <title>Standard Error</title> + <p>In certain situations, especially when the standard output is redirected, access to an io_server() specific for error messages might be convenient. The io_device 'standard_error' can be used to direct output to whatever the current operating system considers a suitable device for error output. Example on a Unix-like operating system:</p> +<pre> +$ <input>erl -noshell -noinput -eval 'io:format(standard_error,"Error: ~s~n",["error 11"]),init:stop().' > /dev/null</input> +Error: error 11</pre> + + + + </section> + + <section> + <title>Error Information</title> + <p>The <c>ErrorInfo</c> mentioned above is the standard + <c>ErrorInfo</c> structure which is returned from all IO modules. + It has the format:</p> + <code type="none"> +{ErrorLine, Module, ErrorDescriptor}</code> + <p>A string which describes the error is obtained with the following + call:</p> + <code type="none"> +apply(Module, format_error, ErrorDescriptor)</code> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/io_lib.xml b/lib/stdlib/doc/src/io_lib.xml new file mode 100644 index 0000000000..399f968c5f --- /dev/null +++ b/lib/stdlib/doc/src/io_lib.xml @@ -0,0 +1,300 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>io_lib</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>io_lib</module> + <modulesummary>IO Library Functions</modulesummary> + <description> + <p>This module contains functions for converting to and from + strings (lists of characters). They are used for implementing the + functions in the <c>io</c> module. There is no guarantee that the + character lists returned from some of the functions are flat, + they can be deep lists. <c>lists:flatten/1</c> can be used for + flattening deep lists.</p> + </description> + + <section> + <title>DATA TYPES</title> + <code type="none"> +chars() = [char() | chars()]</code> + </section> + <funcs> + <func> + <name>nl() -> chars()</name> + <fsummary>Write a newline</fsummary> + <desc> + <p>Returns a character list which represents a new line + character.</p> + </desc> + </func> + <func> + <name>write(Term) -></name> + <name>write(Term, Depth) -> chars()</name> + <fsummary>Write a term</fsummary> + <type> + <v>Term = term()</v> + <v>Depth = int()</v> + </type> + <desc> + <p>Returns a character list which represents <c>Term</c>. The + <c>Depth</c> (-1) argument controls the depth of the + structures written. When the specified depth is reached, + everything below this level is replaced by "...". For + example:</p> + <pre> +1> <input>lists:flatten(io_lib:write({1,[2],[3],[4,5],6,7,8,9})).</input> +"{1,[2],[3],[4,5],6,7,8,9}" +2> <input>lists:flatten(io_lib:write({1,[2],[3],[4,5],6,7,8,9}, 5)).</input> +"{1,[2],[3],[...],...}"</pre> + </desc> + </func> + <func> + <name>print(Term) -></name> + <name>print(Term, Column, LineLength, Depth) -> chars()</name> + <fsummary>Pretty print a term</fsummary> + <type> + <v>Term = term()</v> + <v>Column = LineLenght = Depth = int()</v> + </type> + <desc> + <p>Also returns a list of characters which represents + <c>Term</c>, but breaks representations which are longer than + one line into many lines and indents each line sensibly. It + also tries to detect and output lists of printable characters + as strings. <c>Column</c> is the starting column (1), + <c>LineLength</c> the maximum line length (80), and + <c>Depth</c> (-1) the maximum print depth.</p> + </desc> + </func> + <func> + <name>fwrite(Format, Data) -></name> + <name>format(Format, Data) -> chars() | UnicodeList</name> + <fsummary>Write formatted output</fsummary> + <type> + <v>Format = atom() | string() | binary()</v> + <v>Data = [term()]</v> + <v>UnicodeList = [Unicode]</v> + <v>Unicode = int() representing valid unicode codepoint</v> + </type> + <desc> + <p>Returns a character list which represents <c>Data</c> + formatted in accordance with <c>Format</c>. See + <seealso marker="io#fwrite/1">io:fwrite/1,2,3</seealso> for a detailed + description of the available formatting options. A fault is + generated if there is an error in the format string or + argument list.</p> + + <p>If (and only if) the Unicode translation modifier is used + in the format string (i.e. ~ts or ~tc), the resulting list + may contain characters beyond the ISO-latin-1 character + range (in other words, numbers larger than 255). If so, the + result is not an ordinary Erlang string(), but can well be + used in any context where Unicode data is allowed.</p> + + </desc> + </func> + <func> + <name>fread(Format, String) -> Result</name> + <fsummary>Read formatted input</fsummary> + <type> + <v>Format = String = string()</v> + <v>Result = {ok, InputList, LeftOverChars} | {more, RestFormat, Nchars, InputStack} | {error, What}</v> + <v> InputList = chars()</v> + <v> LeftOverChars = string()</v> + <v> RestFormat = string()</v> + <v> Nchars = int()</v> + <v> InputStack = chars()</v> + <v> What = term()</v> + </type> + <desc> + <p>Tries to read <c>String</c> in accordance with the control + sequences in <c>Format</c>. See + <seealso marker="io#fread/3">io:fread/3</seealso> for a detailed + description of the available formatting options. It is + assumed that <c>String</c> contains whole lines. It returns:</p> + <taglist> + <tag><c>{ok, InputList, LeftOverChars}</c></tag> + <item> + <p>The string was read. <c>InputList</c> is the list of + successfully matched and read items, and + <c>LeftOverChars</c> are the input characters not used.</p> + </item> + <tag><c>{more, RestFormat, Nchars, InputStack}</c></tag> + <item> + <p>The string was read, but more input is needed in order + to complete the original format string. <c>RestFormat</c> + is the remaining format string, <c>NChars</c> the number + of characters scanned, and <c>InputStack</c> is the + reversed list of inputs matched up to that point.</p> + </item> + <tag><c>{error, What}</c></tag> + <item> + <p>The read operation failed and the parameter <c>What</c> + gives a hint about the error.</p> + </item> + </taglist> + <p>Example:</p> + <pre> +3> <input>io_lib:fread("~f~f~f", "15.6 17.3e-6 24.5").</input> +{ok,[15.6,1.73e-5,24.5],[]}</pre> + </desc> + </func> + <func> + <name>fread(Continuation, String, Format) -> Return</name> + <fsummary>Re-entrant formatted reader</fsummary> + <type> + <v>Continuation = see below</v> + <v>String = Format = string()</v> + <v>Return = {done, Result, LeftOverChars} | {more, Continuation}</v> + <v> Result = {ok, InputList} | eof | {error, What}</v> + <v> InputList = chars()</v> + <v> What = term()()</v> + <v> LeftOverChars = string()</v> + </type> + <desc> + <p>This is the re-entrant formatted reader. The continuation of + the first call to the functions must be <c>[]</c>. Refer to + Armstrong, Virding, Williams, 'Concurrent Programming in + Erlang', Chapter 13 for a complete description of how the + re-entrant input scheme works.</p> + <p>The function returns:</p> + <taglist> + <tag><c>{done, Result, LeftOverChars}</c></tag> + <item> + <p>The input is complete. The result is one of the + following:</p> + <taglist> + <tag><c>{ok, InputList}</c></tag> + <item> + <p>The string was read. <c>InputList</c> is the list of + successfully matched and read items, and + <c>LeftOverChars</c> are the remaining characters.</p> + </item> + <tag><c>eof</c></tag> + <item> + <p>End of file has been encountered. + <c>LeftOverChars</c> are the input characters not + used.</p> + </item> + <tag><c>{error, What}</c></tag> + <item> + <p>An error occurred and the parameter <c>What</c> gives + a hint about the error.</p> + </item> + </taglist> + </item> + <tag><c>{more, Continuation}</c></tag> + <item> + <p>More data is required to build a term. + <c>Continuation</c> must be passed to <c>fread/3</c>, + when more data becomes available.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>write_atom(Atom) -> chars()</name> + <fsummary>Write an atom</fsummary> + <type> + <v>Atom = atom()</v> + </type> + <desc> + <p>Returns the list of characters needed to print the atom + <c>Atom</c>.</p> + </desc> + </func> + <func> + <name>write_string(String) -> chars()</name> + <fsummary>Write a string</fsummary> + <type> + <v>String = string()</v> + </type> + <desc> + <p>Returns the list of characters needed to print <c>String</c> + as a string.</p> + </desc> + </func> + <func> + <name>write_char(Integer) -> chars()</name> + <fsummary>Write a character</fsummary> + <type> + <v>Integer = int()</v> + </type> + <desc> + <p>Returns the list of characters needed to print a character + constant in the ISO-latin-1 character set.</p> + </desc> + </func> + <func> + <name>indentation(String, StartIndent) -> int()</name> + <fsummary>Indentation after printing string</fsummary> + <type> + <v>String = string()</v> + <v>StartIndent = int()</v> + </type> + <desc> + <p>Returns the indentation if <c>String</c> has been printed, + starting at <c>StartIndent</c>.</p> + </desc> + </func> + <func> + <name>char_list(Term) -> bool()</name> + <fsummary>Test for a list of characters</fsummary> + <type> + <v>Term = term()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Term</c> is a flat list of + characters in the ISO-latin-1 range, otherwise it returns <c>false</c>.</p> + </desc> + </func> + <func> + <name>deep_char_list(Term) -> bool()</name> + <fsummary>Test for a deep list of characters</fsummary> + <type> + <v>Term = term()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Term</c> is a, possibly deep, list + of characters in the ISO-latin-1 range, otherwise it returns <c>false</c>.</p> + </desc> + </func> + <func> + <name>printable_list(Term) -> bool()</name> + <fsummary>Test for a list of printable ISO-latin-1 characters</fsummary> + <type> + <v>Term = term()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Term</c> is a flat list of + printable ISO-latin-1 characters, otherwise it returns <c>false</c>.</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/io_protocol.xml b/lib/stdlib/doc/src/io_protocol.xml new file mode 100644 index 0000000000..1b75114031 --- /dev/null +++ b/lib/stdlib/doc/src/io_protocol.xml @@ -0,0 +1,861 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1999</year> + <year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>The Erlang I/O-protocol</title> + <prepared>Patrik Nyblom</prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date>2009-02-25</date> + <rev>PA1</rev> + <file>io_protocol.xml</file> + </header> + + +<p>The I/O-protocol in Erlang specifies a way for a client to communicate +with an io_server and vice versa. The io_server is a process handling the +requests and that performs the requested task on i.e. a device. The +client is any Erlang process wishing to read or write data from/to the +device.</p> + +<p>The common I/O-protocol has been present in OTP since the +beginning, but has been fairly undocumented and has also somewhat +evolved over the years. In an addendum to Robert Virdings rationale +the original I/O-protocol is described. This document describes the +current I/O-protocol.</p> + +<p>The original I/O-protocol was simple and flexible. Demands for spacial +and execution time efficiency has triggered extensions to the protocol +over the years, making the protocol larger and somewhat less easy to +implement than the original. It can certainly be argumented that the +current protocol is to complex, but this text describes how it looks +today, not how it should have looked.</p> + +<p>The basic ideas from the original protocol still holds. The io_server +and client communicate with one single, rather simplistic protocol and +no server state is ever present in the client. Any io_server can be +used together with any client code and client code need not be aware +of the actual device the io_server communicates with.</p> + +<section> +<title>Protocol basics</title> + +<p>As described in Roberts paper, servers and clients communicate using +io_request/io_reply tuples as follows:</p> + +<p><em>{io_request, From, ReplyAs, Request}</em><br/> +<em>{io_reply, ReplyAs, Reply}</em></p> + +<p>The client sends an io_request to the io_server and the server +eventually sends a corresponding reply.</p> + +<list type="bulleted"> +<item>From is the pid() of the client, the process which the io_server +sends the reply to.</item> + +<item>ReplyAs can be any datum and is simply returned in the corresponding +io_reply. The io-module in the Erlang standard library simply uses the pid() +of the io_server as the ReplyAs datum, but a more complicated client +could have several outstanding io-requests to the same server and +would then use i.e. a ref() or something else to differentiate among +the incoming io_reply's. The ReplyAs element should be considered +opaque by the io_server. Note that the pid() of the server is not +explicitly present in the io_reply. The reply can be sent from any +process, not necessarily the actual io_server. The ReplyAs element is +the only thing that connects one io_request with an io_reply.</item> + +<item>Request and Reply are described below.</item> +</list> + +<p>When an io_server receives an io_request, it acts upon the actual +Request part and eventually sends an io_reply with the corresponding +Reply part.</p> +</section> +<section> +<title>Output requests</title> + +<p>To output characters on a device, the following Requests exist:</p> + +<p> +<em>{put_chars, Encoding, Characters}</em><br/> +<em>{put_chars, Encoding, Module, Function, Args}</em> +</p> +<list type="bulleted"> +<item>Encoding is either 'latin1' or 'unicode', meaning that the + characters are (in case of binaries) encoded as either UTF-8 or + iso-latin-1 (pure bytes). A well behaved io_server should also + return error if list elements contain integers > 255 when the + Encoding is set to latin1. Note that this does not in any way tell + how characters should be put on the actual device or how the + io_server should handle them. Different io_servers may handle the + characters however they want, this simply tells the io_server which + format the data is expected to have. In the Module/Function/argument + case, the Encoding tells which format the designated function + produces. Note that byte-oriented data is simplest sent using latin1 + Encoding</item> + +<item>Characters are the data to be put on the device. If encoding is + latin1, this is an iolist(). If encoding is unicode, this is an + Erlang standard mixed unicode list (one integer in a list per + character, characters in binaries represented as UTF-8).</item> + +<item>Module, Function, Args denotes a function which will be called to + produce the data (like io_lib:format), Args is a list of arguments + to the function. The function should produce data in the given + Encoding. The io_server should call the function as apply(Mod, Func, + Args) and will put the returned data on the device as if it was sent + in a {put_chars, Encoding, Characters} request. If the function + returns anything else than a binary or list or throws an exception, + an error should be sent back to the client.</item> +</list> + +<p>The server replies to the client with an io_reply where the Reply +element is one of:</p> +<p> +<em>ok</em><br/> +<em>{error, Error}</em> +</p> + +<list type="bulleted"> +<item>Error describes the error to the client, which may do whatever it + wants with it. The Erlang io-module typically returns it as is.</item> +</list> + +<p>For backward compatibility the following Requests should also be +handled by an io_server (these messages should not be present after +R15B of OTP):</p> +<p> +<em>{put_chars, Characters}</em><br/> +<em>{put_chars, Module, Function, Args}</em> +</p> + +<p>These should behave as {put_chars, latin1, Characters} and {put_chars, +latin1, Module, Function, Args} respectively. </p> +</section> +<section> +<title>Input Requests</title> + +<p>To read characters from a device, the following Requests exist:</p> + +<p><em>{get_until, Encoding, Prompt, Module, Function, ExtraArgs}</em></p> + +<list type="bulleted"> +<item>Encoding denotes how data is to be sent back to the client and + what data is sent to the function denoted by + Module/Function/Arity. If the function supplied returns data as a + list, the data is converted to this encoding. If however the + function supplied returns data in some other format, no conversion + can be done and it's up to the client supplied function to return + data in a proper way. If Encoding is latin1, lists of integers + 0..255 or binaries containing plain bytes are sent back to the + client when possible, if Encoding is unicode, lists with integers in + the whole unicode range or binaries encoded in UTF-8 are sent to the + client. The user supplied function will always see lists of integers, never + binaries, but the list may contain numbers > 255 if the Encoding is + 'unicode'.</item> + +<item>Prompt is a list of characters (not mixed, no binaries) or an atom() + to be output as a prompt for input on the device. The Prompt is + often ignored by the io_server and a Prompt set to '' should always + be ignored (and result in nothing being written to the device). </item> + +<item><p>Module, Function, ExtraArgs denotes a function and arguments to + determine when enough data is written. The function should take two + additional arguments, the last state, and a list of characters. The + function should return one of:</p> +<p> +<em>{done, Result, RestChars}</em><br/> +<em>{more, Continuation}</em> +</p> + <p>The Result can be any Erlang term, but if it is a list(), the + io_server may convert it to a binary() of appropriate format before + returning it to the client, if the server is set in binary mode (see + below).</p> + + <p>The function will be called with the data the io_server finds on + it's device, returning {done, Result, RestChars} when enough data is + read (in which case Result is sent to the client and RestChars are + kept in the io_server as a buffer for subsequent input) or {more, + Continuation}, indicating that more characters are needed to + complete the request. The Continuation will be sent as the state in + subsequent calls to the function when more characters are + available. When no more characters are available, the function + shall return {done,eof,Rest}. + The initial state is the empty list and the data when an + end of file is reached on the device is the atom 'eof'. An emulation + of the get_line request could be (inefficiently) implemented using + the following functions:</p> +<code> +-module(demo). +-export([until_newline/3, get_line/1]). + +until_newline(_ThisFar,eof,_MyStopCharacter) -> + {done,eof,[]}; +until_newline(ThisFar,CharList,MyStopCharacter) -> + case lists:splitwith(fun(X) -> X =/= MyStopCharacter end, CharList) of + {L,[]} -> + {more,ThisFar++L}; + {L2,[MyStopCharacter|Rest]} -> + {done,ThisFar++L2++[MyStopCharacter],Rest} + end. + +get_line(IoServer) -> + IoServer ! {io_request, self(), IoServer, {get_until, unicode, '', + ?MODULE, until_newline, [$\n]}}, + receive + {io_reply, IoServer, Data} -> + Data + end. +</code> + <p>Note especially that the last element in the Request tuple ([$\n]) + is appended to the argument list when the function is called. The + function should be called like + apply(Module, Function, [ State, Data | ExtraArgs ]) by the io_server</p> +</item> +</list> + +<p>A defined number of characters is requested using this Request:</p> +<p> +<em>{get_chars, Encoding, Prompt, N}</em> +</p> + +<list type="bulleted"> +<item>Encoding and Prompt as for get_until.</item> + +<item>N is the number of characters to be read from the device.</item> +</list> + +<p>A single line (like in the example above) is requested with this Request:</p> +<p> +<em>{get_line, Encoding, Prompt}</em> +</p> + +<list type="bulleted"> +<item>Encoding and prompt as above.</item> +</list> + +<p>Obviously, get_chars and get_line could be implemented with the +get_until request (and indeed was originally), but demands for +efficiency has made these additions necessary.</p> + +<p>The server replies to the client with an io_reply where the Reply +element is one of:</p> +<p> +<em>Data</em><br/> +<em>eof</em><br/> +<em>{error, Error}</em> +</p> + +<list type="bulleted"> +<item>Data is the characters read, in either list or binary form + (depending on the io_server mode, see below).</item> +<item>Error describes the error to the client, which may do whatever it + wants with it. The Erlang io-module typically returns it as is.</item> +<item>eof is returned when input end is reached and no more data is +available to the client process.</item> +</list> + +<p>For backward compatibility the following Requests should also be +handled by an io_server (these messages should not be present after +R15B of OTP):</p> + +<p> +<em>{get_until, Prompt, Module, Function, ExtraArgs}</em><br/> +<em>{get_chars, Prompt, N}</em><br/> +<em>{get_line, Prompt}</em><br/> +</p> + +<p>These should behave as {get_until, latin1, Prompt, Module, Function, +ExtraArgs}, {get_chars, latin1, Prompt, N} and {get_line, latin1, +Prompt} respectively.</p> +</section> +<section> +<title>I/O-server modes</title> + +<p>Demands for efficiency when reading data from an io_server has not +only lead to the addition of the get_line and get_chars requests, but +has also added the concept of io_server options. No options are +mandatory to implement, but all io_servers in the Erlang standard +libraries honor the 'binary' option, which allows the Data in the +io_reply to be binary instead of in list form <em>when possible</em>. +If the data is sent as a binary, Unicode data will be sent in the +standard Erlang unicode +format, i.e. UTF-8 (note that the function in get_until still gets +list data regardless of the io_server mode).</p> + +<p>Note that i.e. the <c>get_until</c> request allows for a function with the data specified as always being a list. Also the return value data from such a function can be of any type (as is indeed the case when an io:fread request is sent to an io_server). The client has to be prepared for data received as answers to those requests to be in a variety of forms, but the server should convert the results to binaries whenever possible (i.e. when the function supplied to get_until actually returns a list). The example shown later in this text does just that.</p> + +<p>An I/O-server in binary mode will affect the data sent to the client, +so that it has to be able to handle binary data. For convenience, it +is possible to set and retrieve the modes of an io_server using the +following I/O-requests:</p> + +<p> +<em>{setopts, Opts}</em> +</p> + + +<list type="bulleted"> +<item>Opts is a list of options in the format recognized by proplists (and + of course by the io_server itself).</item> +</list> +<p>As an example, the io_server for the interactive shell (in group.erl) +understands the following options:</p> +<p> +<em>{binary, bool()} (or 'binary'/'list')</em><br/> +<em>{echo, bool()}</em><br/> +<em>{expand_fun, fun()}</em><br/> +<em>{encoding, 'unicode'/'latin1'} (or 'unicode'/'latin1')</em> +</p> + +<p>- of which the 'binary' and 'encoding' options are common for all +io_servers in OTP, while 'echo' and 'expand' is valid only for this +io_server. It's worth noting that the 'unicode' option notifies how +characters are actually put on the physical device, i.e. if the +terminal per se is unicode aware, it does not affect how characters +are sent in the I/O-protocol, where each request contains encoding +information for the provided or returned data.</p> + +<p>The server should send one of the following as Reply:</p> +<p> +<em>ok</em><br/> +<em>{error, Error}</em> +</p> + +<p>An error (preferably enotsup) is to be expected if the option is +not supported by the io_server (like if an 'echo' option is sent in a +setopt Request to a plain file).</p> + +<p>To retrieve options, this message is used:</p> +<p> +<em>getopts</em> +</p> + +<p>The 'getopts' message requests a complete list of all options +supported by the io_server as well as their current values.</p> + +<p>The server replies:</p> +<p> +<em>OptList</em><br/> +<em>{error,Error}</em> +</p> + +<list type="bulleted"> +<item>OptList is a list of tuples {Option, Value} where Option is always + an atom.</item> +</list> +</section> +<section> +<title>Multiple I/O requests</title> + +<p>The Request element can in itself contain several Requests by using +the following format:</p> +<p> +<em>{requests, Requests}</em> +</p> +<list type="bulleted"> +<item>Requests is a list of valid Request tuples for the protocol, they + shall be executed in the order in which they appear in the list and + the execution should continue until one of the requests result in an + error or the list is consumed. The result of the last request is + sent back to the client.</item> +</list> + +<p>The server can for a list of requests send any of the valid results in +the reply:</p> + +<p> +<em>ok</em><br/> +<em>{ok, Data}</em><br/> +<em>{ok, Options}</em><br/> +<em>{error, Error}</em> +</p> +<p>- depending on the actual requests in the list.</p> +</section> +<section> +<title>Optional I/O-requests</title> + +<p>The following I/O request is optional to implement and a client +should be prepared for an error return:</p> +<p> +<em>{get_geometry, Geometry}</em> +</p> +<list type="bulleted"> +<item>Geometry is either the atom 'rows' or the atom 'columns'.</item> +</list> +<p>The server should send the Reply as:</p> +<p> +<em>{ok, N}</em><br/> +<em>{error, Error}</em> +</p> + +<list type="bulleted"> +<item>N is the number of character rows or columns the device has, if + applicable to the device the io_server handles, otherwise {error, + enotsup} is a good answer.</item> +</list> +</section> +<section> +<title>Unimplemented request types:</title> + +<p>If an io_server encounters a request it does not recognize (i.e. the +io_request tuple is in the expected format, but the actual Request is +unknown), the server should send a valid reply with the error tuple:</p> +<p> +<em>{error, request}</em> +</p> + +<p>This makes it possible to extend the protocol with optional messages +and for the clients to be somewhat backwards compatible.</p> +</section> +<section> +<title>An annotated and working example io_server:</title> + +<p>An io_server is any process capable of handling the protocol. There is +no generic io_server behavior, but could well be. The framework is +simple enough, a process handling incoming requests, usually both +io_requests and other device-specific requests (for i.e. positioning , +closing etc.).</p> + +<p>Our example io_server stores characters in an ets table, making up a +fairly crude ram-file (it is probably not useful, but working).</p> + +<p>The module begins with the usual directives, a function to start the +server and a main loop handling the requests:</p> + +<code> +-module(ets_io_server). + +-export([start_link/0, init/0, loop/1, until_newline/3, until_enough/3]). + +-define(CHARS_PER_REC, 10). + +-record(state, { + table, + position, % absolute + mode % binary | list + }). + +start_link() -> + spawn_link(?MODULE,init,[]). + +init() -> + Table = ets:new(noname,[ordered_set]), + ?MODULE:loop(#state{table = Table, position = 0, mode=list}). + +loop(State) -> + receive + {io_request, From, ReplyAs, Request} -> + case request(Request,State) of + {Tag, Reply, NewState} when Tag =:= ok; Tag =:= error -> + reply(From, ReplyAs, Reply), + ?MODULE:loop(NewState); + {stop, Reply, _NewState} -> + reply(From, ReplyAs, Reply), + exit(Reply) + end; + %% Private message + {From, rewind} -> + From ! {self(), ok}, + ?MODULE:loop(State#state{position = 0}); + _Unknown -> + ?MODULE:loop(State) + end. +</code> + +<p>The main loop receives messages from the client (which might be using +the io-module to send requests). For each request the function +request/2 is called and a reply is eventually sent using the reply/3 +function.</p> + +<p>The "private" message {From, rewind} results in the +current position in the pseudo-file to be reset to 0 (the beginning of +the "file"). This is a typical example of device-specific +messages not being part of the I/O-protocol. It is usually a bad idea +to embed such private messages in io_request tuples, as that might be +confusing to the reader.</p> + +<p>Let's look at the reply function first...</p> + +<code> + +reply(From, ReplyAs, Reply) -> + From ! {io_reply, ReplyAs, Reply}. + +</code> + +<p>Simple enough, it sends the io_reply tuple back to the client, +providing the ReplyAs element received in the request along with the +result of the request, as described above.</p> + +<p>Now look at the different requests we need to handle. First the +requests for writing characters:</p> + +<code> +request({put_chars, Encoding, Chars}, State) -> + put_chars(unicode:characters_to_list(Chars,Encoding),State); +request({put_chars, Encoding, Module, Function, Args}, State) -> + try + request({put_chars, Encoding, apply(Module, Function, Args)}, State) + catch + _:_ -> + {error, {error,Function}, State} + end; +</code> + +<p>The Encoding tells us how the characters in the message are +represented. We want to store the characters as lists in the +ets-table, so we convert them to lists using the +unicode:characters_to_list/2 function. The conversion function +conveniently accepts the encoding types unicode or latin1, so we can +use the Encoding parameter directly.</p> + +<p>When Module, Function and Arguments are provided, we simply apply it +and do the same thing with the result as if the data was provided +directly.</p> + +<p>Let's handle the requests for retrieving data too:</p> + +<code> +request({get_until, Encoding, _Prompt, M, F, As}, State) -> + get_until(Encoding, M, F, As, State); +request({get_chars, Encoding, _Prompt, N}, State) -> + %% To simplify the code, get_chars is implemented using get_until + get_until(Encoding, ?MODULE, until_enough, [N], State); +request({get_line, Encoding, _Prompt}, State) -> + %% To simplify the code, get_line is implemented using get_until + get_until(Encoding, ?MODULE, until_newline, [$\\n], State); +</code> + +<p>Here we have cheated a little by more or less only implementing +get_until and using internal helpers to implement get__chars and +get_line. In production code, this might be to inefficient, but that +of course depends on the frequency of the different requests. Before +we start actually implementing the functions put_chars/2 and +get_until/5, lets look into the few remaining requests:</p> + +<code> +request({get_geometry,_}, State) -> + {error, {error,enotsup}, State}; +request({setopts, Opts}, State) -> + setopts(Opts, State); +request(getopts, State) -> + getopts(State); +request({requests, Reqs}, State) -> + multi_request(Reqs, {ok, ok, State}); +</code> + +<p>The get_geometry request has no meaning for this io_server, so the +reply will be {error, enotsup}. The only option we handle is the +binary/list option, which is done in separate functions.</p> + +<p>The multi-request tag (requests) is handled in a separate loop +function applying the requests in the list one after another, +returning the last result.</p> + +<p>What's left is to handle backward compatibility and the file-module +(which uses the old requests until backward compatibility with pre-R13 +nodes is no longer needed). Note that the io_server will not work with +a simple file:write if these are not added:</p> + +<code> +request({put_chars,Chars}, State) -> + request({put_chars,latin1,Chars}, State); +request({put_chars,M,F,As}, State) -> + request({put_chars,latin1,M,F,As}, State); +request({get_chars,Prompt,N}, State) -> + request({get_chars,latin1,Prompt,N}, State); +request({get_line,Prompt}, State) -> + request({get_line,latin1,Prompt}, State); +request({get_until, Prompt,M,F,As}, State) -> + request({get_until,latin1,Prompt,M,F,As}, State); +</code> + +<p>Ok, what's left now is to return {error, request} if the request is +not recognized:</p> + +<code> +request(_Other, State) -> + {error, {error, request}, State}. +</code> + +<p>Let's move further and actually handle the different requests, first +the fairly generic multi-request type:</p> + +<code> +multi_request([R|Rs], {ok, _Res, State}) -> + multi_request(Rs, request(R, State)); +multi_request([_|_], Error) -> + Error; +multi_request([], Result) -> + Result. +</code> + +<p>We loop through the requests one at the time, stopping when we either +encounter an error or the list is exhausted. The last return value is +sent back to the client (it's first returned to the main loop and then +sent back by the function io_reply).</p> + +<p>The getopt and setopt requests is also simple to handle, we just +change or read our state record:</p> + +<code> +setopts(Opts0,State) -> + Opts = proplists:unfold( + proplists:substitute_negations( + [{list,binary}], + Opts0)), + case check_valid_opts(Opts) of + true -> + case proplists:get_value(binary, Opts) of + true -> + {ok,ok,State#state{mode=binary}}; + false -> + {ok,ok,State#state{mode=binary}}; + _ -> + {ok,ok,State} + end; + false -> + {error,{error,enotsup},State} + end. +check_valid_opts([]) -> + true; +check_valid_opts([{binary,Bool}|T]) when is_boolean(Bool) -> + check_valid_opts(T); +check_valid_opts(_) -> + false. + +getopts(#state{mode=M} = S) -> + {ok,[{binary, case M of + binary -> + true; + _ -> + false + end}],S}. +</code> + +<p>As a convention, all io_servers handle both {setopts, [binary]}, +{setopts, [list]} and {setopts,[{binary, bool()}]}, hence the trick +with proplists:substitute_negations/2 and proplists:unfold/1. If +invalid options are sent to us, we send {error,enotsup} back to the +client.</p> + +<p>The getopts request should return a list of {Option, Value} tuples, +which has the twofold function of providing both the current values +and the available options of this io_server. We have only one option, +and hence return that.</p> + +<p>So far our io_server has been fairly generic (except for the rewind +request handled in the main loop and the creation of an ets table). +Most io_servers contain code similar to what's above.</p> + +<p>To make the example runnable, we now start implementing the actual +reading and writing of the data to/from the ets-table. First the +put_chars function:</p> + +<code> +put_chars(Chars, #state{table = T, position = P} = State) -> + R = P div ?CHARS_PER_REC, + C = P rem ?CHARS_PER_REC, + [ apply_update(T,U) || U <- split_data(Chars, R, C) ], + {ok, ok, State#state{position = (P + length(Chars))}}. +</code> + +<p>We already have the data as (Unicode) lists and therefore just split +the list in runs of a predefined size and put each run in the +table at the current position (and forward). The functions +split_data/3 and apply_update/2 are implemented below.</p> + +<p>Now we want to read data from the table. The get_until function reads +data and applies the function until it says it's done. The result is +sent back to the client:</p> + +<code> +get_until(Encoding, Mod, Func, As, + #state{position = P, mode = M, table = T} = State) -> + case get_loop(Mod,Func,As,T,P,[]) of + {done,Data,_,NewP} when is_binary(Data); is_list(Data) -> + if + M =:= binary -> + {ok, + unicode:characters_to_binary(Data,unicode,Encoding), + State#state{position = NewP}}; + true -> + case check(Encoding, + unicode:characters_to_list(Data, unicode)) of + {error, _} = E -> + {error, E, State}; + List -> + {ok, List, + State#state{position = NewP}} + end + end; + {done,Data,_,NewP} -> + {ok, Data, State#state{position = NewP}}; + Error -> + {error, Error, State} + end. + +get_loop(M,F,A,T,P,C) -> + {NewP,L} = get(P,T), + case catch apply(M,F,[C,L|A]) of + {done, List, Rest} -> + {done, List, [], NewP - length(Rest)}; + {more, NewC} -> + get_loop(M,F,A,T,NewP,NewC); + _ -> + {error,F} + end. +</code> + +<p>Here we also handle the mode (binary or list) that can be set by +the setopts request. By default, all OTP io_servers send data back to +the client as lists, but switching mode to binary might increase +efficiency if the server handles it in an appropriate way. The +implementation of get_until is hard to get efficient as the supplied +function is defined to take lists as arguments, but get_chars and +get_line can be optimized for binary mode. This example does not +optimize anything however. It is important though that the returned +data is of the right type depending on the options set, so we convert +the lists to binaries in the correct encoding <em>if possible</em> +before returning. The function supplied in the get_until request may, +as it's final result return anything, so only functions actually +returning lists can get them converted to binaries. If the request +contained the encoding tag unicode, the lists can contain all unicode +codepoints and the binaries should be in UTF-8, if the encoding tag +was latin1, the client should only get characters in the range +0..255. The function check/2 takes care of not returning arbitrary +unicode codepoints in lists if the encoding was given as latin1. If +the function did not return a list, the check cannot be performed and +the result will be that of the supplied function untouched.</p> + +<p>Now we are more or less done. We implement the utility functions below +to actually manipulate the table:</p> + +<code> +check(unicode, List) -> + List; +check(latin1, List) -> + try + [ throw(not_unicode) || X <- List, + X > 255 ], + List + catch + throw:_ -> + {error,{cannot_convert, unicode, latin1}} + end. +</code> + +<p>The function check takes care of providing an error tuple if unicode +codepoints above 255 is to be returned if the client requested +latin1.</p> + +<p>The two functions until_newline/3 and until_enough/3 are helpers used +together with the get_until function to implement get_chars and +get_line (inefficiently):</p> + +<code> +until_newline([],eof,_MyStopCharacter) -> + {done,eof,[]}; +until_newline(ThisFar,eof,_MyStopCharacter) -> + {done,ThisFar,[]}; +until_newline(ThisFar,CharList,MyStopCharacter) -> + case lists:splitwith(fun(X) -> X =/= MyStopCharacter end, CharList) of + {L,[]} -> + {more,ThisFar++L}; + {L2,[MyStopCharacter|Rest]} -> + {done,ThisFar++L2++[MyStopCharacter],Rest} + end. + +until_enough([],eof,_N) -> + {done,eof,[]}; +until_enough(ThisFar,eof,_N) -> + {done,ThisFar,[]}; +until_enough(ThisFar,CharList,N) + when length(ThisFar) + length(CharList) >= N -> + {Res,Rest} = my_split(N,ThisFar ++ CharList, []), + {done,Res,Rest}; +until_enough(ThisFar,CharList,_N) -> + {more,ThisFar++CharList}. +</code> + +<p>As can be seen, the functions above are just the type of functions +that should be provided in get_until requests.</p> + +<p>Now we only need to read and write the table in an appropriate way to +complete the server:</p> + +<code> +get(P,Tab) -> + R = P div ?CHARS_PER_REC, + C = P rem ?CHARS_PER_REC, + case ets:lookup(Tab,R) of + [] -> + {P,eof}; + [{R,List}] -> + case my_split(C,List,[]) of + {_,[]} -> + {P+length(List),eof}; + {_,Data} -> + {P+length(Data),Data} + end + end. + +my_split(0,Left,Acc) -> + {lists:reverse(Acc),Left}; +my_split(_,[],Acc) -> + {lists:reverse(Acc),[]}; +my_split(N,[H|T],Acc) -> + my_split(N-1,T,[H|Acc]). + +split_data([],_,_) -> + []; +split_data(Chars, Row, Col) -> + {This,Left} = my_split(?CHARS_PER_REC - Col, Chars, []), + [ {Row, Col, This} | split_data(Left, Row + 1, 0) ]. + +apply_update(Table, {Row, Col, List}) -> + case ets:lookup(Table,Row) of + [] -> + ets:insert(Table,{Row, lists:duplicate(Col,0) ++ List}); + [{Row, OldData}] -> + {Part1,_} = my_split(Col,OldData,[]), + {_,Part2} = my_split(Col+length(List),OldData,[]), + ets:insert(Table,{Row, Part1 ++ List ++ Part2}) + end. +</code> + +<p>The table is read or written in chunks of ?CHARS_PER_REC, overwriting +when necessary. The implementation is obviously not efficient, it is +just working.</p> + +<p>This concludes the example. It is fully runnable and you can read or +write to the io_server by using i.e. the io_module or even the file +module. It's as simple as that to implement a fully fledged io_server +in Erlang.</p> +</section> +</chapter> + + diff --git a/lib/stdlib/doc/src/lib.xml b/lib/stdlib/doc/src/lib.xml new file mode 100644 index 0000000000..046add48e8 --- /dev/null +++ b/lib/stdlib/doc/src/lib.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>lib</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>lib</module> + <modulesummary>A number of useful library functions</modulesummary> + <description> + <warning> + <p>This module is retained for compatibility. It may disappear + without warning in a future release.</p> + </warning> + </description> + <funcs> + <func> + <name>flush_receive() -> void()</name> + <fsummary>Flush messages</fsummary> + <desc> + <p>Flushes the message buffer of the current process.</p> + </desc> + </func> + <func> + <name>error_message(Format, Args) -> ok</name> + <fsummary>Print error message</fsummary> + <type> + <v>Format = atom() | string() | binary()</v> + <v>Args = [term()]</v> + </type> + <desc> + <p>Prints error message <c>Args</c> in accordance with + <c>Format</c>. Similar to <c>io:format/2</c>, see + <seealso marker="io#fwrite/1">io(3)</seealso>.</p> + </desc> + </func> + <func> + <name>progname() -> atom()</name> + <fsummary>Return name of Erlang start script</fsummary> + <desc> + <p>Returns the name of the script that started the current + Erlang session.</p> + </desc> + </func> + <func> + <name>nonl(String1) -> String2</name> + <fsummary>Remove last newline</fsummary> + <type> + <v>String1 = String2 = string()</v> + </type> + <desc> + <p>Removes the last newline character, if any, in + <c>String1</c>.</p> + </desc> + </func> + <func> + <name>send(To, Msg)</name> + <fsummary>Send a message</fsummary> + <type> + <v>To = pid() | Name | {Name,Node}</v> + <v> Name = Node = atom()</v> + <v>Msg = term()</v> + </type> + <desc> + <p>This function to makes it possible to send a message using + the <c>apply/3</c> BIF.</p> + </desc> + </func> + <func> + <name>sendw(To, Msg)</name> + <fsummary>Send a message and wait for an answer</fsummary> + <type> + <v>To = pid() | Name | {Name,Node}</v> + <v> Name = Node = atom()</v> + <v>Msg = term()</v> + </type> + <desc> + <p>As <c>send/2</c>, but waits for an answer. It is implemented + as follows:</p> + <code type="none"> +sendw(To, Msg) -> + To ! {self(),Msg}, + receive + Reply -> Reply + end.</code> + <p>The message returned is not necessarily a reply to the + message sent.</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml new file mode 100644 index 0000000000..39fc05420d --- /dev/null +++ b/lib/stdlib/doc/src/lists.xml @@ -0,0 +1,1196 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>lists</title> + <prepared>Robert Virding</prepared> + <docno>1</docno> + <date>96-09-28</date> + <rev>A</rev> + </header> + <module>lists</module> + <modulesummary>List Processing Functions</modulesummary> + <description> + <p>This module contains functions for list processing. The functions + are organized in two groups: those in the first group perform a + particular operation on one or more lists, whereas those in the + second group are higher-order functions, using a fun as argument + to perform an operation on one list.</p> + <p>Unless otherwise stated, all functions assume that position + numbering starts at 1. That is, the first element of a list is at + position 1.</p> + + <p>Whenever an <marker + id="ordering_function"></marker><em>ordering function</em> + <c>F</c> is expected as argument, it is assumed that the + following properties hold of <c>F</c> for all x, y and z:</p> + <list type="bulleted"> + <item><p>if x <c>F</c> y and y <c>F</c> x then x = y (<c>F</c> + is antisymmetric);</p> + </item> + <item><p>if x <c>F</c> y and and y <c>F</c> z then x <c>F</c> z + (<c>F</c> is transitive);</p> + </item> + <item><p>x <c>F</c> y or y <c>F</c> x (<c>F</c> is total).</p> + </item> + </list> + <p>An example of a typical ordering function is less than or equal + to, <c>=</2</c>.</p> + + </description> + <funcs> + <func> + <name>all(Pred, List) -> bool()</name> + <fsummary>Return true if all elements in the list satisfy<c>Pred</c></fsummary> + <type> + <v>Pred = fun(Elem) -> bool()</v> + <v> Elem = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Pred(Elem)</c> returns + <c>true</c> for all elements <c>Elem</c> in <c>List</c>, + otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>any(Pred, List) -> bool()</name> + <fsummary>Return true if any of the elements in the list satisfies<c>Pred</c></fsummary> + <type> + <v>Pred = fun(Elem) -> bool()</v> + <v> Elem = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Pred(Elem)</c> returns + <c>true</c> for at least one element <c>Elem</c> in + <c>List</c>.</p> + </desc> + </func> + <func> + <name>append(ListOfLists) -> List1</name> + <fsummary>Append a list of lists</fsummary> + <type> + <v>ListOfLists = [List]</v> + <v>List = List1 = [term()]</v> + </type> + <desc> + <p>Returns a list in which all the sub-lists of + <c>ListOfLists</c> have been appended. For example:</p> + <pre> +> <input>lists:append([[1, 2, 3], [a, b], [4, 5, 6]]).</input> +[1,2,3,a,b,4,5,6]</pre> + </desc> + </func> + <func> + <name>append(List1, List2) -> List3</name> + <fsummary>Append two lists</fsummary> + <type> + <v>List1 = List2 = List3 = [term()]</v> + </type> + <desc> + <p>Returns a new list <c>List3</c> which is made from + the elements of <c>List1</c> followed by the elements of + <c>List2</c>. For example:</p> + <pre> +> <input>lists:append("abc", "def").</input> +"abcdef"</pre> + <p><c>lists:append(A, B)</c> is equivalent to <c>A ++ B</c>.</p> + </desc> + </func> + <func> + <name>concat(Things) -> string()</name> + <fsummary>Concatenate a list of atoms</fsummary> + <type> + <v>Things = [Thing]</v> + <v> Thing = atom() | integer() | float() | string()</v> + </type> + <desc> + <p>Concatenates the text representation of the elements + of <c>Things</c>. The elements of <c>Things</c> can be atoms, + integers, floats or strings.</p> + <pre> +> <input>lists:concat([doc, '/', file, '.', 3]).</input> +"doc/file.3"</pre> + </desc> + </func> + <func> + <name>delete(Elem, List1) -> List2</name> + <fsummary>Delete an element from a list</fsummary> + <type> + <v>Elem = term()</v> + <v>List1 = List2 = [term()]</v> + </type> + <desc> + <p>Returns a copy of <c>List1</c> where the first element + matching <c>Elem</c> is deleted, if there is such an + element.</p> + </desc> + </func> + <func> + <name>dropwhile(Pred, List1) -> List2</name> + <fsummary>Drop elements from a list while a predicate is true</fsummary> + <type> + <v>Pred = fun(Elem) -> bool()</v> + <v> Elem = term()</v> + <v>List1 = List2 = [term()]</v> + </type> + <desc> + <p>Drops elements <c>Elem</c> from <c>List1</c> while + <c>Pred(Elem)</c> returns <c>true</c> and returns + the remaining list.</p> + </desc> + </func> + <func> + <name>duplicate(N, Elem) -> List</name> + <fsummary>Make N copies of element</fsummary> + <type> + <v>N = int()</v> + <v>Elem = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns a list which contains N copies of the term + <c>Elem</c>. For example:</p> + <pre> +> <input>lists:duplicate(5, xx).</input> +[xx,xx,xx,xx,xx]</pre> + </desc> + </func> + <func> + <name>filter(Pred, List1) -> List2</name> + <fsummary>Choose elements which satisfy a predicate</fsummary> + <type> + <v>Pred = fun(Elem) -> bool()</v> + <v> Elem = term()</v> + <v>List1 = List2 = [term()]</v> + </type> + <desc> + <p><c>List2</c> is a list of all elements <c>Elem</c> in + <c>List1</c> for which <c>Pred(Elem)</c> returns + <c>true</c>.</p> + </desc> + </func> + <func> + <name>flatlength(DeepList) -> int()</name> + <fsummary>Length of flattened deep list</fsummary> + <type> + <v>DeepList = [term() | DeepList]</v> + </type> + <desc> + <p>Equivalent to <c>length(flatten(DeepList))</c>, but more + efficient.</p> + </desc> + </func> + <func> + <name>flatmap(Fun, List1) -> List2</name> + <fsummary>Map and flatten in one pass</fsummary> + <type> + <v>Fun = fun(A) -> [B]</v> + <v>List1 = [A]</v> + <v>List2 = [B]</v> + <v> A = B = term()</v> + </type> + <desc> + <p>Takes a function from <c>A</c>s to lists of <c>B</c>s, and a + list of <c>A</c>s (<c>List1</c>) and produces a list of + <c>B</c>s by applying the function to every element in + <c>List1</c> and appending the resulting lists.</p> + <p>That is, <c>flatmap</c> behaves as if it had been defined as + follows:</p> + <code type="none"> +flatmap(Fun, List1) -> + append(map(Fun, List1))</code> + <p>Example:</p> + <pre> +> <input>lists:flatmap(fun(X)->[X,X] end, [a,b,c]).</input> +[a,a,b,b,c,c]</pre> + </desc> + </func> + <func> + <name>flatten(DeepList) -> List</name> + <fsummary>Flatten a deep list</fsummary> + <type> + <v>DeepList = [term() | DeepList]</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns a flattened version of <c>DeepList</c>.</p> + </desc> + </func> + <func> + <name>flatten(DeepList, Tail) -> List</name> + <fsummary>Flatten a deep list</fsummary> + <type> + <v>DeepList = [term() | DeepList]</v> + <v>Tail = List = [term()]</v> + </type> + <desc> + <p>Returns a flattened version of <c>DeepList</c> with the tail + <c>Tail</c> appended.</p> + </desc> + </func> + <func> + <name>foldl(Fun, Acc0, List) -> Acc1</name> + <fsummary>Fold a function over a list</fsummary> + <type> + <v>Fun = fun(Elem, AccIn) -> AccOut</v> + <v> Elem = term()</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Calls <c>Fun(Elem, AccIn)</c> on successive elements <c>A</c> + of <c>List</c>, starting with <c>AccIn == Acc0</c>. + <c>Fun/2</c> must return a new accumulator which is passed to + the next call. The function returns the final value of + the accumulator. <c>Acc0</c> is returned if the list is empty. + For example:</p> + <pre> +> <input>lists:foldl(fun(X, Sum) -> X + Sum end, 0, [1,2,3,4,5]).</input> +15 +> <input>lists:foldl(fun(X, Prod) -> X * Prod end, 1, [1,2,3,4,5]).</input> +120</pre> + </desc> + </func> + <func> + <name>foldr(Fun, Acc0, List) -> Acc1</name> + <fsummary>Fold a function over a list</fsummary> + <type> + <v>Fun = fun(Elem, AccIn) -> AccOut</v> + <v> Elem = term()</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Like <c>foldl/3</c>, but the list is traversed from right to + left. For example:</p> + <pre> +> <input>P = fun(A, AccIn) -> io:format("~p ", [A]), AccIn end.</input> +#Fun<erl_eval.12.2225172> +> <input>lists:foldl(P, void, [1,2,3]).</input> +1 2 3 void +> <input>lists:foldr(P, void, [1,2,3]).</input> +3 2 1 void</pre> + <p><c>foldl/3</c> is tail recursive and would usually be + preferred to <c>foldr/3</c>.</p> + </desc> + </func> + <func> + <name>foreach(Fun, List) -> void()</name> + <fsummary>Apply a function to each element of a list</fsummary> + <type> + <v>Fun = fun(Elem) -> void()</v> + <v> Elem = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Calls <c>Fun(Elem)</c> for each element <c>Elem</c> in + <c>List</c>. This function is used for its side effects and + the evaluation order is defined to be the same as the order + of the elements in the list.</p> + </desc> + </func> + <func> + <name>keydelete(Key, N, TupleList1) -> TupleList2</name> + <fsummary>Delete an element from a list of tuples</fsummary> + <type> + <v>Key = term()</v> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList1 = TupleList2 = [Tuple]</v> + <v> Tuple = tuple()</v> + </type> + <desc> + <p>Returns a copy of <c>TupleList1</c> where the first + occurrence of a tuple whose <c>N</c>th element compares equal to + <c>Key</c> is deleted, if there is such a tuple.</p> + </desc> + </func> + <func> + <name>keyfind(Key, N, TupleList) -> Tuple | false</name> + <fsummary>Search for an element in a list of tuples</fsummary> + <type> + <v>Key = term()</v> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList = [Tuple]</v> + <v>Tuple = tuple()</v> + </type> + <desc> + <p>Searches the list of tuples <c>TupleList</c> for a + tuple whose <c>N</c>th element compares equal to <c>Key</c>. + Returns <c>Tuple</c> if such a tuple is found, + otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>keymap(Fun, N, TupleList1) -> TupleList2</name> + <fsummary>Map a function over a list of tuples</fsummary> + <type> + <v>Fun = fun(Term1) -> Term2</v> + <v> Term1 = Term2 = term()</v> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList1 = TupleList2 = [tuple()]</v> + </type> + <desc> + <p>Returns a list of tuples where, for each tuple in + <c>TupleList1</c>, the <c>N</c>th element <c>Term1</c> of the tuple + has been replaced with the result of calling + <c>Fun(Term1)</c>.</p> + <p>Examples:</p> + <pre> +> <input>Fun = fun(Atom) -> atom_to_list(Atom) end.</input> +#Fun<erl_eval.6.10732646> +2> <input>lists:keymap(Fun, 2, [{name,jane,22},{name,lizzie,20},{name,lydia,15}]).</input> +[{name,"jane",22},{name,"lizzie",20},{name,"lydia",15}]</pre> + </desc> + </func> + <func> + <name>keymember(Key, N, TupleList) -> bool()</name> + <fsummary>Test for membership of a list of tuples</fsummary> + <type> + <v>Key = term()</v> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList = [Tuple]</v> + <v> Tuple = tuple()</v> + </type> + <desc> + <p>Returns <c>true</c> if there is a tuple in <c>TupleList</c> + whose <c>N</c>th element compares equal to <c>Key</c>, otherwise + <c>false</c>.</p> + </desc> + </func> + <func> + <name>keymerge(N, TupleList1, TupleList2) -> TupleList3</name> + <fsummary>Merge two key-sorted lists of tuples</fsummary> + <type> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList1 = TupleList2 = TupleList3 = [Tuple]</v> + <v> Tuple = tuple()</v> + </type> + <desc> + <p>Returns the sorted list formed by merging <c>TupleList1</c> + and <c>TupleList2</c>. The merge is performed on + the <c>N</c>th element of each tuple. Both <c>TupleList1</c> and + <c>TupleList2</c> must be key-sorted prior to evaluating this + function. When two tuples compare equal, the tuple from + <c>TupleList1</c> is picked before the tuple from + <c>TupleList2</c>.</p> + </desc> + </func> + <func> + <name>keyreplace(Key, N, TupleList1, NewTuple) -> TupleList2</name> + <fsummary>Replace an element in a list of tuples</fsummary> + <type> + <v>Key = term()</v> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList1 = TupleList2 = [Tuple]</v> + <v>NewTuple = Tuple = tuple()</v> + </type> + <desc> + <p>Returns a copy of <c>TupleList1</c> where the first + occurrence of a <c>T</c> tuple whose <c>N</c>th element + compares equal to <c>Key</c> is replaced with + <c>NewTuple</c>, if there is such a tuple <c>T</c>.</p> + </desc> + </func> + <func> + <name>keysearch(Key, N, TupleList) -> {value, Tuple} | false</name> + <fsummary>Search for an element in a list of tuples</fsummary> + <type> + <v>Key = term()</v> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList = [Tuple]</v> + <v>Tuple = tuple()</v> + </type> + <desc> + <p>Searches the list of tuples <c>TupleList</c> for a + tuple whose <c>N</c>th element compares equal to <c>Key</c>. + Returns <c>{value, Tuple}</c> if such a tuple is found, + otherwise <c>false</c>.</p> + <note><p>This function is retained for backward compatibility. + The function <c>lists:keyfind/3</c> (introduced in R13A) + is in most cases more convenient.</p></note> + </desc> + </func> + <func> + <name>keysort(N, TupleList1) -> TupleList2</name> + <fsummary>Sort a list of tuples</fsummary> + <type> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList1 = TupleList2 = [Tuple]</v> + <v> Tuple = tuple()</v> + </type> + <desc> + <p>Returns a list containing the sorted elements of the list + <c>TupleList1</c>. Sorting is performed on the <c>N</c>th + element of the tuples.</p> + </desc> + </func> + <func> + <name>keystore(Key, N, TupleList1, NewTuple) -> TupleList2</name> + <fsummary>Store an element in a list of tuples</fsummary> + <type> + <v>Key = term()</v> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList1 = TupleList2 = [Tuple]</v> + <v>NewTuple = Tuple = tuple()</v> + </type> + <desc> + <p>Returns a copy of <c>TupleList1</c> where the first + occurrence of a tuple <c>T</c> whose <c>N</c>th element + compares equal to <c>Key</c> is replaced with + <c>NewTuple</c>, if there is such a tuple <c>T</c>. If there + is no such tuple <c>T</c> a copy of <c>TupleList1</c> where + [<c>NewTuple</c>] has been appended to the end is + returned.</p> + </desc> + </func> + <func> + <name>keytake(Key, N, TupleList1) -> {value, Tuple, TupleList2} + | false</name> + <fsummary>Extract an element from a list of tuples</fsummary> + <type> + <v>Key = term()</v> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList1 = TupleList2 = [Tuple]</v> + <v>Tuple = tuple()</v> + </type> + <desc> + <p>Searches the list of tuples <c>TupleList1</c> for a tuple + whose <c>N</c>th element compares equal to <c>Key</c>. + Returns <c>{value, Tuple, TupleList2}</c> if such a tuple is + found, otherwise <c>false</c>. <c>TupleList2</c> is a copy + of <c>TupleList1</c> where the first occurrence of + <c>Tuple</c> has been removed.</p> + </desc> + </func> + <func> + <name>last(List) -> Last</name> + <fsummary>Return last element in a list</fsummary> + <type> + <v>List = [term()], length(List) > 0</v> + <v>Last = term()</v> + </type> + <desc> + <p>Returns the last element in <c>List</c>.</p> + </desc> + </func> + <func> + <name>map(Fun, List1) -> List2</name> + <fsummary>Map a function over a list</fsummary> + <type> + <v>Fun = fun(A) -> B</v> + <v>List1 = [A]</v> + <v>List2 = [B]</v> + <v> A = B = term()</v> + </type> + <desc> + <p>Takes a function from <c>A</c>s to <c>B</c>s, and a list of + <c>A</c>s and produces a list of <c>B</c>s by applying + the function to every element in the list. This function is + used to obtain the return values. The evaluation order is + implementation dependent.</p> + </desc> + </func> + <func> + <name>mapfoldl(Fun, Acc0, List1) -> {List2, Acc1}</name> + <fsummary>Map and fold in one pass</fsummary> + <type> + <v>Fun = fun(A, AccIn) -> {B, AccOut}</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v>List1 = [A]</v> + <v>List2 = [B]</v> + <v> A = B = term()</v> + </type> + <desc> + <p><c>mapfold</c> combines the operations of <c>map/2</c> and + <c>foldl/3</c> into one pass. An example, summing + the elements in a list and double them at the same time:</p> + <pre> +> <input>lists:mapfoldl(fun(X, Sum) -> {2*X, X+Sum} end,</input> +<input>0, [1,2,3,4,5]).</input> +{[2,4,6,8,10],15}</pre> + </desc> + </func> + <func> + <name>mapfoldr(Fun, Acc0, List1) -> {List2, Acc1}</name> + <fsummary>Map and fold in one pass</fsummary> + <type> + <v>Fun = fun(A, AccIn) -> {B, AccOut}</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v>List1 = [A]</v> + <v>List2 = [B]</v> + <v> A = B = term()</v> + </type> + <desc> + <p><c>mapfold</c> combines the operations of <c>map/2</c> and + <c>foldr/3</c> into one pass.</p> + </desc> + </func> + <func> + <name>max(List) -> Max</name> + <fsummary>Return maximum element of a list</fsummary> + <type> + <v>List = [term()], length(List) > 0</v> + <v>Max = term()</v> + </type> + <desc> + <p>Returns the first element of <c>List</c> that compares + greater than or equal to all other elements of + <c>List</c>.</p> + </desc> + </func> + <func> + <name>member(Elem, List) -> bool()</name> + <fsummary>Test for membership of a list</fsummary> + <type> + <v>Elem = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Elem</c> matches some element of + <c>List</c>, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>merge(ListOfLists) -> List1</name> + <fsummary>Merge a list of sorted lists</fsummary> + <type> + <v>ListOfLists = [List]</v> + <v>List = List1 = [term()]</v> + </type> + <desc> + <p>Returns the sorted list formed by merging all the sub-lists + of <c>ListOfLists</c>. All sub-lists must be sorted prior to + evaluating this function. When two elements compare equal, + the element from the sub-list with the lowest position in + <c>ListOfLists</c> is picked before the other element.</p> + </desc> + </func> + <func> + <name>merge(List1, List2) -> List3</name> + <fsummary>Merge two sorted lists</fsummary> + <type> + <v>List1 = List2 = List3 = [term()]</v> + </type> + <desc> + <p>Returns the sorted list formed by merging <c>List1</c> and + <c>List2</c>. Both <c>List1</c> and <c>List2</c> must be + sorted prior to evaluating this function. When two elements + compare equal, the element from <c>List1</c> is picked + before the element from <c>List2</c>.</p> + </desc> + </func> + <func> + <name>merge(Fun, List1, List2) -> List3</name> + <fsummary>Merge two sorted list</fsummary> + <type> + <v>Fun = fun(A, B) -> bool()</v> + <v>List1 = [A]</v> + <v>List2 = [B]</v> + <v>List3 = [A | B]</v> + <v> A = B = term()</v> + </type> + <desc> + <p>Returns the sorted list formed by merging <c>List1</c> and + <c>List2</c>. Both <c>List1</c> and <c>List2</c> must be + sorted according to the <seealso + marker="#ordering_function">ordering function</seealso> + <c>Fun</c> prior to evaluating this function. <c>Fun(A, + B)</c> should return <c>true</c> if <c>A</c> compares less + than or equal to <c>B</c> in the ordering, <c>false</c> + otherwise. When two elements compare equal, the element from + <c>List1</c> is picked before the element from + <c>List2</c>.</p> + </desc> + </func> + <func> + <name>merge3(List1, List2, List3) -> List4</name> + <fsummary>Merge three sorted lists</fsummary> + <type> + <v>List1 = List2 = List3 = List4 = [term()]</v> + </type> + <desc> + <p>Returns the sorted list formed by merging <c>List1</c>, + <c>List2</c> and <c>List3</c>. All of <c>List1</c>, + <c>List2</c> and <c>List3</c> must be sorted prior to + evaluating this function. When two elements compare equal, + the element from <c>List1</c>, if there is such an element, + is picked before the other element, otherwise the element + from <c>List2</c> is picked before the element from + <c>List3</c>.</p> + </desc> + </func> + <func> + <name>min(List) -> Min</name> + <fsummary>Return minimum element of a list</fsummary> + <type> + <v>List = [term()], length(List) > 0</v> + <v>Min = term()</v> + </type> + <desc> + <p>Returns the first element of <c>List</c> that compares + less than or equal to all other elements of + <c>List</c>.</p> + </desc> + </func> + <func> + <name>nth(N, List) -> Elem</name> + <fsummary>Return the Nth element of a list</fsummary> + <type> + <v>N = 1..length(List)</v> + <v>List = [term()]</v> + <v>Elem = term()</v> + </type> + <desc> + <p>Returns the <c>N</c>th element of <c>List</c>. For example:</p> + <pre> +> <input>lists:nth(3, [a, b, c, d, e]).</input> +c</pre> + </desc> + </func> + <func> + <name>nthtail(N, List1) -> Tail</name> + <fsummary>Return the Nth tail of a list</fsummary> + <type> + <v>N = 0..length(List1)</v> + <v>List1 = Tail = [term()]</v> + </type> + <desc> + <p>Returns the <c>N</c>th tail of <c>List</c>, that is, the sublist of + <c>List</c> starting at <c>N+1</c> and continuing up to + the end of the list. For example:</p> + <pre> +> <input>lists:nthtail(3, [a, b, c, d, e]).</input> +[d,e] +> <input>tl(tl(tl([a, b, c, d, e]))).</input> +[d,e] +> <input>lists:nthtail(0, [a, b, c, d, e]).</input> +[a,b,c,d,e] +> <input>lists:nthtail(5, [a, b, c, d, e]).</input> +[]</pre> + </desc> + </func> + <func> + <name>partition(Pred, List) -> {Satisfying, NonSatisfying}</name> + <fsummary>Partition a list into two lists based on a predicate</fsummary> + <type> + <v>Pred = fun(Elem) -> bool()</v> + <v> Elem = term()</v> + <v>List = Satisfying = NonSatisfying = [term()]</v> + </type> + <desc> + <p>Partitions <c>List</c> into two lists, where the first list + contains all elements for which <c>Pred(Elem)</c> returns + <c>true</c>, and the second list contains all elements for + which <c>Pred(Elem)</c> returns <c>false</c>.</p> + <p>Examples:</p> + <pre> +> <input>lists:partition(fun(A) -> A rem 2 == 1 end, [1,2,3,4,5,6,7]).</input> +{[1,3,5,7],[2,4,6]} +> <input>lists:partition(fun(A) -> is_atom(A) end, [a,b,1,c,d,2,3,4,e]).</input> +{[a,b,c,d,e],[1,2,3,4]}</pre> + <p>See also <c>splitwith/2</c> for a different way to partition + a list.</p> + </desc> + </func> + <func> + <name>prefix(List1, List2) -> bool()</name> + <fsummary>Test for list prefix</fsummary> + <type> + <v>List1 = List2 = [term()]</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>List1</c> is a prefix of + <c>List2</c>, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>reverse(List1) -> List2</name> + <fsummary>Reverse a list</fsummary> + <type> + <v>List1 = List2 = [term()]</v> + </type> + <desc> + <p>Returns a list with the top level elements in <c>List1</c> + in reverse order.</p> + </desc> + </func> + <func> + <name>reverse(List1, Tail) -> List2</name> + <fsummary>Reverse a list appending a tail</fsummary> + <type> + <v>List1 = Tail = List2 = [term()]</v> + </type> + <desc> + <p>Returns a list with the top level elements in <c>List1</c> + in reverse order, with the tail <c>Tail</c> appended. For + example:</p> + <pre> +> <input>lists:reverse([1, 2, 3, 4], [a, b, c]).</input> +[4,3,2,1,a,b,c]</pre> + </desc> + </func> + <func> + <name>seq(From, To) -> Seq</name> + <name>seq(From, To, Incr) -> Seq</name> + <fsummary>Generate a sequence of integers</fsummary> + <type> + <v>From = To = Incr = int()</v> + <v>Seq = [int()]</v> + </type> + <desc> + <p>Returns a sequence of integers which starts with <c>From</c> + and contains the successive results of adding <c>Incr</c> to + the previous element, until <c>To</c> has been reached or + passed (in the latter case, <c>To</c> is not an element of + the sequence). <c>Incr</c> defaults to 1.</p> + <p>Failure: If <c><![CDATA[To<From-Incr]]></c> and <c>Incr</c> + is positive, or if <c>To>From-Incr</c> and <c>Incr</c> is + negative, or if <c>Incr==0</c> and <c>From/=To</c>.</p> + <p>The following equalities hold for all sequences:</p> + <code type="none"> +length(lists:seq(From, To)) == To-From+1 +length(lists:seq(From, To, Incr)) == (To-From+Incr) div Incr</code> + <p>Examples:</p> + <pre> +> <input>lists:seq(1, 10).</input> +[1,2,3,4,5,6,7,8,9,10] +> <input>lists:seq(1, 20, 3).</input> +[1,4,7,10,13,16,19] +> <input>lists:seq(1, 0, 1).</input> +[] +> <input>lists:seq(10, 6, 4).</input> +[] +> <input>lists:seq(1, 1, 0).</input> +[1]</pre> + </desc> + </func> + <func> + <name>sort(List1) -> List2</name> + <fsummary>Sort a list</fsummary> + <type> + <v>List1 = List2 = [term()]</v> + </type> + <desc> + <p>Returns a list containing the sorted elements of + <c>List1</c>.</p> + </desc> + </func> + <func> + <name>sort(Fun, List1) -> List2</name> + <fsummary>Sort a list</fsummary> + <type> + <v>Fun = fun(Elem1, Elem2) -> bool()</v> + <v> Elem1 = Elem2 = term()</v> + <v>List1 = List2 = [term()]</v> + </type> + <desc> + <p>Returns a list containing the sorted elements of + <c>List1</c>, according to the <seealso + marker="#ordering_function">ordering function</seealso> + <c>Fun</c>. <c>Fun(A, B)</c> should return <c>true</c> if + <c>A</c> compares less than or equal to <c>B</c> in the + ordering, <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>split(N, List1) -> {List2, List3}</name> + <fsummary>Split a list into two lists</fsummary> + <type> + <v>N = 0..length(List1)</v> + <v>List1 = List2 = List3 = [term()]</v> + </type> + <desc> + <p>Splits <c>List1</c> into <c>List2</c> and <c>List3</c>. + <c>List2</c> contains the first <c>N</c> elements and + <c>List3</c> the rest of the elements (the <c>N</c>th tail).</p> + </desc> + </func> + <func> + <name>splitwith(Pred, List) -> {List1, List2}</name> + <fsummary>Split a list into two lists based on a predicate</fsummary> + <type> + <v>Pred = fun(Elem) -> bool()</v> + <v> Elem = term()</v> + <v>List = List1 = List2 = [term()]</v> + </type> + <desc> + <p>Partitions <c>List</c> into two lists according to + <c>Pred</c>. <c>splitwith/2</c> behaves as if it is defined + as follows:</p> + <code type="none"> +splitwith(Pred, List) -> + {takewhile(Pred, List), dropwhile(Pred, List)}.</code> + <p>Examples:</p> + <pre> +> <input>lists:splitwith(fun(A) -> A rem 2 == 1 end, [1,2,3,4,5,6,7]).</input> +{[1],[2,3,4,5,6,7]} +> <input>lists:splitwith(fun(A) -> is_atom(A) end, [a,b,1,c,d,2,3,4,e]).</input> +{[a,b],[1,c,d,2,3,4,e]}</pre> + <p>See also <c>partition/2</c> for a different way to partition + a list.</p> + </desc> + </func> + <func> + <name>sublist(List1, Len) -> List2</name> + <fsummary>Return a sub-list of a certain length, starting at the first position</fsummary> + <type> + <v>List1 = List2 = [term()]</v> + <v>Len = int()</v> + </type> + <desc> + <p>Returns the sub-list of <c>List1</c> starting at position 1 + and with (max) <c>Len</c> elements. It is not an error for + <c>Len</c> to exceed the length of the list -- in that case + the whole list is returned.</p> + </desc> + </func> + <func> + <name>sublist(List1, Start, Len) -> List2</name> + <fsummary>Return a sub-list starting at a given position and with a given number of elements</fsummary> + <type> + <v>List1 = List2 = [term()]</v> + <v>Start = 1..(length(List1)+1)</v> + <v>Len = int()</v> + </type> + <desc> + <p>Returns the sub-list of <c>List1</c> starting at <c>Start</c> + and with (max) <c>Len</c> elements. It is not an error for + <c>Start+Len</c> to exceed the length of the list.</p> + <pre> +> <input>lists:sublist([1,2,3,4], 2, 2).</input> +[2,3] +> <input>lists:sublist([1,2,3,4], 2, 5).</input> +[2,3,4] +> <input>lists:sublist([1,2,3,4], 5, 2).</input> +[]</pre> + </desc> + </func> + <func> + <name>subtract(List1, List2) -> List3</name> + <fsummary>Subtract the element in one list from another list</fsummary> + <type> + <v>List1 = List2 = List3 = [term()]</v> + </type> + <desc> + <p>Returns a new list <c>List3</c> which is a copy of + <c>List1</c>, subjected to the following procedure: for each + element in <c>List2</c>, its first occurrence in <c>List1</c> + is deleted. For example:</p> + <pre> +> <input>lists:subtract("123212", "212").</input> +"312".</pre> + <p><c>lists:subtract(A, B)</c> is equivalent to <c>A -- B</c>.</p> + <warning><p>The complexity of <c>lists:subtract(A, B)</c> is proportional + to <c>length(A)*length(B)</c>, meaning that it will be very slow if + both <c>A</c> and <c>B</c> are long lists. + (Using ordered lists and + <seealso marker="ordsets#subtract/2">ordsets:subtract/2</seealso> + is a much better choice if both lists are long.)</p></warning> + </desc> + </func> + <func> + <name>suffix(List1, List2) -> bool()</name> + <fsummary>Test for list suffix</fsummary> + <desc> + <p>Returns <c>true</c> if <c>List1</c> is a suffix of + <c>List2</c>, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>sum(List) -> number()</name> + <fsummary>Return sum of elements in a list</fsummary> + <type> + <v>List = [number()]</v> + </type> + <desc> + <p>Returns the sum of the elements in <c>List</c>.</p> + </desc> + </func> + <func> + <name>takewhile(Pred, List1) -> List2</name> + <fsummary>Take elements from a list while a predicate is true</fsummary> + <type> + <v>Pred = fun(Elem) -> bool()</v> + <v> Elem = term()</v> + <v>List1 = List2 = [term()]</v> + </type> + <desc> + <p>Takes elements <c>Elem</c> from <c>List1</c> while + <c>Pred(Elem)</c> returns <c>true</c>, that is, + the function returns the longest prefix of the list for which + all elements satisfy the predicate.</p> + </desc> + </func> + <func> + <name>ukeymerge(N, TupleList1, TupleList2) -> TupleList3</name> + <fsummary>Merge two key-sorted lists of tuples, removing duplicates</fsummary> + <type> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList1 = TupleList2 = TupleList3 = [Tuple]</v> + <v> Tuple = tuple()</v> + </type> + <desc> + <p>Returns the sorted list formed by merging <c>TupleList1</c> + and <c>TupleList2</c>. The merge is performed on the + <c>N</c>th element of each tuple. Both <c>TupleList1</c> and + <c>TupleList2</c> must be key-sorted without duplicates + prior to evaluating this function. When two tuples compare + equal, the tuple from <c>TupleList1</c> is picked and the + one from <c>TupleList2</c> deleted.</p> + </desc> + </func> + <func> + <name>ukeysort(N, TupleList1) -> TupleList2</name> + <fsummary>Sort a list of tuples, removing duplicates</fsummary> + <type> + <v>N = 1..tuple_size(Tuple)</v> + <v>TupleList1 = TupleList2 = [Tuple]</v> + <v> Tuple = tuple()</v> + </type> + <desc> + <p>Returns a list containing the sorted elements of the list + <c>TupleList1</c> where all but the first tuple of the + tuples comparing equal have been deleted. Sorting is + performed on the <c>N</c>th element of the tuples.</p> + </desc> + </func> + <func> + <name>umerge(ListOfLists) -> List1</name> + <fsummary>Merge a list of sorted lists, removing duplicates</fsummary> + <type> + <v>ListOfLists = [List]</v> + <v>List = List1 = [term()]</v> + </type> + <desc> + <p>Returns the sorted list formed by merging all the sub-lists + of <c>ListOfLists</c>. All sub-lists must be sorted and + contain no duplicates prior to evaluating this function. + When two elements compare equal, the element from the + sub-list with the lowest position in <c>ListOfLists</c> is + picked and the other one deleted.</p> + </desc> + </func> + <func> + <name>umerge(List1, List2) -> List3</name> + <fsummary>Merge two sorted lists, removing duplicates</fsummary> + <type> + <v>List1 = List2 = List3 = [term()]</v> + </type> + <desc> + <p>Returns the sorted list formed by merging <c>List1</c> and + <c>List2</c>. Both <c>List1</c> and <c>List2</c> must be + sorted and contain no duplicates prior to evaluating this + function. When two elements compare equal, the element from + <c>List1</c> is picked and the one from <c>List2</c> + deleted.</p> + </desc> + </func> + <func> + <name>umerge(Fun, List1, List2) -> List3</name> + <fsummary>Merge two sorted lists, removing duplicates</fsummary> + <type> + <v>Fun = fun(A, B) -> bool()</v> + <v>List1 = [A]</v> + <v>List2 = [B]</v> + <v>List3 = [A | B]</v> + <v> A = B = term()</v> + </type> + <desc> + <p>Returns the sorted list formed by merging <c>List1</c> and + <c>List2</c>. Both <c>List1</c> and <c>List2</c> must be + sorted according to the <seealso + marker="#ordering_function">ordering function</seealso> + <c>Fun</c> and contain no duplicates prior to evaluating + this function. <c>Fun(A, B)</c> should return <c>true</c> if + <c>A</c> compares less than or equal to <c>B</c> in the + ordering, <c>false</c> otherwise. When two elements compare + equal, the element from + <c>List1</c> is picked and the one from <c>List2</c> + deleted.</p> + </desc> + </func> + <func> + <name>umerge3(List1, List2, List3) -> List4</name> + <fsummary>Merge three sorted lists, removing duplicates</fsummary> + <type> + <v>List1 = List2 = List3 = List4 = [term()]</v> + </type> + <desc> + <p>Returns the sorted list formed by merging <c>List1</c>, + <c>List2</c> and <c>List3</c>. All of <c>List1</c>, + <c>List2</c> and <c>List3</c> must be sorted and contain no + duplicates prior to evaluating this function. When two + elements compare equal, the element from <c>List1</c> is + picked if there is such an element, otherwise the element + from <c>List2</c> is picked, and the other one deleted.</p> + </desc> + </func> + <func> + <name>unzip(List1) -> {List2, List3}</name> + <fsummary>Unzip a list of two-tuples into two lists</fsummary> + <type> + <v>List1 = [{X, Y}]</v> + <v>List2 = [X]</v> + <v>List3 = [Y]</v> + <v> X = Y = term()</v> + </type> + <desc> + <p>"Unzips" a list of two-tuples into two lists, where the first + list contains the first element of each tuple, and the second + list contains the second element of each tuple.</p> + </desc> + </func> + <func> + <name>unzip3(List1) -> {List2, List3, List4}</name> + <fsummary>Unzip a list of three-tuples into three lists</fsummary> + <type> + <v>List1 = [{X, Y, Z}]</v> + <v>List2 = [X]</v> + <v>List3 = [Y]</v> + <v>List4 = [Z]</v> + <v> X = Y = Z = term()</v> + </type> + <desc> + <p>"Unzips" a list of three-tuples into three lists, where + the first list contains the first element of each tuple, + the second list contains the second element of each tuple, and + the third list contains the third element of each tuple.</p> + </desc> + </func> + <func> + <name>usort(List1) -> List2</name> + <fsummary>Sort a list, removing duplicates</fsummary> + <type> + <v>List1 = List2 = [term()]</v> + </type> + <desc> + <p>Returns a list containing the sorted elements of + <c>List1</c> where all but the first element of the elements + comparing equal have been deleted.</p> + </desc> + </func> + <func> + <name>usort(Fun, List1) -> List2</name> + <fsummary>Sort a list, removing duplicates</fsummary> + <type> + <v>Fun = fun(Elem1, Elem2) -> bool()</v> + <v> Elem1 = Elem2 = term()</v> + <v>List1 = List2 = [term()]</v> + </type> + <desc> + <p>Returns a list which contains the sorted elements of + <c>List1</c> where all but the first element of the elements + comparing equal according to the <seealso + marker="#ordering_function">ordering function</seealso> + <c>Fun</c> have been deleted. <c>Fun(A, B)</c> should return + <c>true</c> if <c>A</c> compares less than or equal to + <c>B</c> in the ordering, <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>zip(List1, List2) -> List3</name> + <fsummary>Zip two lists into a list of two-tuples</fsummary> + <type> + <v>List1 = [X]</v> + <v>List2 = [Y]</v> + <v>List3 = [{X, Y}]</v> + <v> X = Y = term()</v> + </type> + <desc> + <p>"Zips" two lists of equal length into one list of two-tuples, + where the first element of each tuple is taken from the first + list and the second element is taken from corresponding + element in the second list.</p> + </desc> + </func> + <func> + <name>zip3(List1, List2, List3) -> List4</name> + <fsummary>Zip three lists into a list of three-tuples</fsummary> + <type> + <v>List1 = [X]</v> + <v>List2 = [Y]</v> + <v>List3 = [Z]</v> + <v>List3 = [{X, Y, Z}]</v> + <v> X = Y = Z = term()</v> + </type> + <desc> + <p>"Zips" three lists of equal length into one list of + three-tuples, where the first element of each tuple is taken + from the first list, the second element is taken from + corresponding element in the second list, and the third + element is taken from the corresponding element in the third + list.</p> + </desc> + </func> + <func> + <name>zipwith(Combine, List1, List2) -> List3</name> + <fsummary>Zip two lists into one list according to a fun</fsummary> + <type> + <v>Combine = fun(X, Y) -> T</v> + <v>List1 = [X]</v> + <v>List2 = [Y]</v> + <v>List3 = [T]</v> + <v> X = Y = T = term()</v> + </type> + <desc> + <p>Combine the elements of two lists of equal length into one + list. For each pair <c>X, Y</c> of list elements from the two + lists, the element in the result list will be + <c>Combine(X, Y)</c>.</p> + <p><c>zipwith(fun(X, Y) -> {X,Y} end, List1, List2)</c> is + equivalent to <c>zip(List1, List2)</c>.</p> + <p>Example:</p> + <pre> +> <input>lists:zipwith(fun(X, Y) -> X+Y end, [1,2,3], [4,5,6]).</input> +[5,7,9]</pre> + </desc> + </func> + <func> + <name>zipwith3(Combine, List1, List2, List3) -> List4</name> + <fsummary>Zip three lists into one list according to a fun</fsummary> + <type> + <v>Combine = fun(X, Y, Z) -> T</v> + <v>List1 = [X]</v> + <v>List2 = [Y]</v> + <v>List3 = [Z]</v> + <v>List4 = [T]</v> + <v> X = Y = Z = T = term()</v> + </type> + <desc> + <p>Combine the elements of three lists of equal length into one + list. For each triple <c>X, Y, Z</c> of list elements from + the three lists, the element in the result list will be + <c>Combine(X, Y, Z)</c>.</p> + <p><c>zipwith3(fun(X, Y, Z) -> {X,Y,Z} end, List1, List2, List3)</c> is equivalent to <c>zip3(List1, List2, List3)</c>.</p> + <p>Examples:</p> + <pre> +> <input>lists:zipwith3(fun(X, Y, Z) -> X+Y+Z end, [1,2,3], [4,5,6], [7,8,9]).</input> +[12,15,18] +> <input>lists:zipwith3(fun(X, Y, Z) -> [X,Y,Z] end, [a,b,c], [x,y,z], [1,2,3]).</input> +[[a,x,1],[b,y,2],[c,z,3]]</pre> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/log_mf_h.xml b/lib/stdlib/doc/src/log_mf_h.xml new file mode 100644 index 0000000000..198a55a63b --- /dev/null +++ b/lib/stdlib/doc/src/log_mf_h.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>log_mf_h</title> + <prepared>Martin Björklund</prepared> + <responsible>Bjarne Dacker</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked>Martin Björklund</checked> + <date>1996-10-31</date> + <rev>A</rev> + <file>log_mf_h.sgml</file> + </header> + <module>log_mf_h</module> + <modulesummary>An Event Handler which Logs Events to Disk</modulesummary> + <description> + <p>The <c>log_mf_h</c> is a <c>gen_event</c> handler module which + can be installed in any <c>gen_event</c> process. It logs onto disk all events + which are sent to an event manager. Each event is written as a + binary which makes the logging very fast. However, a tool such as the <c>Report Browser</c> (<c>rb</c>) must be used in order to read the files. The events are written to multiple files. When all files have been used, the first one is re-used and overwritten. The directory location, the number of files, and the size of each file are configurable. The directory will include one file called <c>index</c>, and + report files <c>1, 2, ....</c>. + </p> + </description> + <funcs> + <func> + <name>init(Dir, MaxBytes, MaxFiles)</name> + <name>init(Dir, MaxBytes, MaxFiles, Pred) -> Args</name> + <fsummary>Initiate the event handler</fsummary> + <type> + <v>Dir = string()</v> + <v>MaxBytes = integer()</v> + <v>MaxFiles = 0 < integer() < 256</v> + <v>Pred = fun(Event) -> boolean()</v> + <v>Event = term()</v> + <v>Args = args()</v> + </type> + <desc> + <p>Initiates the event handler. This function returns + <c>Args</c>, which should be used in a call to + <c>gen_event:add_handler(EventMgr, log_mf_h, Args)</c>. + </p> + <p><c>Dir</c> specifies which directory to use for the log + files. <c>MaxBytes</c> specifies the size of each individual + file. <c>MaxFiles</c> specifies how many files are + used. <c>Pred</c> is a predicate function used to filter the + events. If no predicate function is specified, all events are + logged.</p> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p><seealso marker="gen_event">gen_event(3)</seealso>, rb(3) </p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/make.dep b/lib/stdlib/doc/src/make.dep new file mode 100644 index 0000000000..48ee6209ef --- /dev/null +++ b/lib/stdlib/doc/src/make.dep @@ -0,0 +1,40 @@ +# ---------------------------------------------------- +# >>>> 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: array.tex base64.tex beam_lib.tex book.tex \ + c.tex calendar.tex dets.tex dict.tex digraph.tex \ + digraph_utils.tex epp.tex erl_eval.tex erl_expand_records.tex \ + erl_id_trans.tex erl_internal.tex erl_lint.tex \ + erl_parse.tex erl_pp.tex erl_scan.tex erl_tar.tex \ + ets.tex file_sorter.tex filelib.tex filename.tex \ + gb_sets.tex gb_trees.tex gen_event.tex gen_fsm.tex \ + gen_server.tex io.tex io_lib.tex io_protocol.tex \ + lib.tex lists.tex log_mf_h.tex math.tex ms_transform.tex \ + orddict.tex ordsets.tex part.tex pg.tex pool.tex \ + proc_lib.tex proplists.tex qlc.tex queue.tex \ + random.tex re.tex ref_man.tex regexp.tex sets.tex \ + shell.tex shell_default.tex slave.tex sofs.tex \ + stdlib_app.tex string.tex supervisor.tex supervisor_bridge.tex \ + sys.tex timer.tex unicode.tex unicode_usage.tex \ + win32reg.tex zip.tex + +# ---------------------------------------------------- +# Source inlined when transforming from source to LaTeX +# ---------------------------------------------------- + +book.tex: ref_man.xml + +# ---------------------------------------------------- +# Pictures that the DVI file depend on +# ---------------------------------------------------- + +book.dvi: ushell1.ps + diff --git a/lib/stdlib/doc/src/math.xml b/lib/stdlib/doc/src/math.xml new file mode 100644 index 0000000000..990a6b4024 --- /dev/null +++ b/lib/stdlib/doc/src/math.xml @@ -0,0 +1,112 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>math</title> + <prepared>Joe Armstrong</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>97-01-15</date> + <rev>B</rev> + <file>math.sgml</file> + </header> + <module>math</module> + <modulesummary>Mathematical Functions</modulesummary> + <description> + <p>This module provides an interface to a number of mathematical + functions.</p> + <note> + <p>Not all functions are implemented on all platforms. In particular, + the <c>erf/1</c> and <c>erfc/1</c> functions are not implemented on Windows.</p> + </note> + </description> + <funcs> + <func> + <name>pi() -> float()</name> + <fsummary>A useful number</fsummary> + <desc> + <p>A useful number.</p> + </desc> + </func> + <func> + <name>sin(X)</name> + <name>cos(X)</name> + <name>tan(X)</name> + <name>asin(X)</name> + <name>acos(X)</name> + <name>atan(X)</name> + <name>atan2(Y, X)</name> + <name>sinh(X)</name> + <name>cosh(X)</name> + <name>tanh(X)</name> + <name>asinh(X)</name> + <name>acosh(X)</name> + <name>atanh(X)</name> + <name>exp(X)</name> + <name>log(X)</name> + <name>log10(X)</name> + <name>pow(X, Y)</name> + <name>sqrt(X)</name> + <fsummary>Diverse math functions</fsummary> + <type> + <v>X = Y = number()</v> + </type> + <desc> + <p>A collection of math functions which return floats. Arguments + are numbers. </p> + </desc> + </func> + <func> + <name>erf(X) -> float()</name> + <fsummary>Error function.</fsummary> + <type> + <v>X = number()</v> + </type> + <desc> + <p>Returns the error function of <c>X</c>, where</p> + <pre> +erf(X) = 2/sqrt(pi)*integral from 0 to X of exp(-t*t) dt. </pre> + </desc> + </func> + <func> + <name>erfc(X) -> float()</name> + <fsummary>Another error function</fsummary> + <type> + <v>X = number()</v> + </type> + <desc> + <p><c>erfc(X)</c> returns <c>1.0 - erf(X)</c>, computed by + methods that avoid cancellation for large <c>X</c>. </p> + </desc> + </func> + </funcs> + + <section> + <title>Bugs</title> + <p>As these are the C library, the bugs are the same.</p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/ms_transform.xml b/lib/stdlib/doc/src/ms_transform.xml new file mode 100644 index 0000000000..9f178b426c --- /dev/null +++ b/lib/stdlib/doc/src/ms_transform.xml @@ -0,0 +1,651 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2002</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>ms_transform</title> + <prepared>Patrik Nyblom</prepared> + <responsible>Bjarne Dacker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>99-02-09</date> + <rev>C</rev> + <file>ms_transform.sgml</file> + </header> + <module>ms_transform</module> + <modulesummary>Parse_transform that translates fun syntax into match specifications. </modulesummary> + <description> + <marker id="top"></marker> + <p>This module implements the parse_transform that makes calls to + <c>ets</c> and <c>dbg</c>:<c>fun2ms/1</c> translate into literal + match specifications. It also implements the back end for the same + functions when called from the Erlang shell.</p> + <p>The translations from fun's to match_specs + is accessed through the two "pseudo + functions" <c>ets:fun2ms/1</c> and <c>dbg:fun2ms/1</c>.</p> + <p>Actually this introduction is more or less an introduction to the + whole concept of match specifications. Since everyone trying to use + <c>ets:select</c> or <c>dbg</c> seems to end up reading + this page, it seems in good place to explain a little more than + just what this module does.</p> + <p>There are some caveats one should be aware of, please read through + the whole manual page if it's the first time you're using the + transformations. </p> + <p>Match specifications are used more or less as filters. + They resemble usual Erlang matching in a list comprehension or in + a <c>fun</c> used in conjunction with <c>lists:foldl</c> etc. The + syntax of pure match specifications is somewhat awkward though, as + they are made up purely by Erlang terms and there is no syntax in the + language to make the match specifications more readable.</p> + <p>As the match specifications execution and structure is quite like + that of a fun, it would for most programmers be more straight forward + to simply write it using the familiar fun syntax and having that + translated into a match specification automatically. Of course a real + fun is more powerful than the match specifications allow, but bearing + the match specifications in mind, and what they can do, it's still + more convenient to write it all as a fun. This module contains the + code that simply translates the fun syntax into match_spec terms.</p> + <p>Let's start with an ets example. Using <c>ets:select</c> and + a match specification, one can filter out rows of a table and construct + a list of tuples containing relevant parts of the data in these + rows. Of course one could use <c>ets:foldl</c> instead, but the + select call is far more efficient. Without the translation, one has to + struggle with writing match specifications terms to accommodate this, + or one has to resort to the less powerful + <c>ets:match(_object)</c> calls, or simply give up and use + the more inefficient method of <c>ets:foldl</c>. Using the + <c>ets:fun2ms</c> transformation, a <c>ets:select</c> call + is at least as easy to write as any of the alternatives.</p> + <p>As an example, consider a simple table of employees:</p> + <code type="none"> +-record(emp, {empno, %Employee number as a string, the key + surname, %Surname of the employee + givenname, %Given name of employee + dept, %Department one of {dev,sales,prod,adm} + empyear}). %Year the employee was employed </code> + <p>We create the table using:</p> + <code type="none"> +ets:new(emp_tab,[{keypos,#emp.empno},named_table,ordered_set]). </code> + <p>Let's also fill it with some randomly chosen data for the examples:</p> + <code type="none"> +[{emp,"011103","Black","Alfred",sales,2000}, + {emp,"041231","Doe","John",prod,2001}, + {emp,"052341","Smith","John",dev,1997}, + {emp,"076324","Smith","Ella",sales,1995}, + {emp,"122334","Weston","Anna",prod,2002}, + {emp,"535216","Chalker","Samuel",adm,1998}, + {emp,"789789","Harrysson","Joe",adm,1996}, + {emp,"963721","Scott","Juliana",dev,2003}, + {emp,"989891","Brown","Gabriel",prod,1999}] </code> + <p>Now, the amount of data in the table is of course to small to justify + complicated ets searches, but on real tables, using <c>select</c> to get + exactly the data you want will increase efficiency remarkably.</p> + <p>Lets say for example that we'd want the employee numbers of + everyone in the sales department. One might use <c>ets:match</c> + in such a situation:</p> + <pre> +1> <input>ets:match(emp_tab, {'_', '$1', '_', '_', sales, '_'}).</input> +[["011103"],["076324"]] </pre> + <p>Even though <c>ets:match</c> does not require a full match + specification, but a simpler type, it's still somewhat unreadable, and + one has little control over the returned result, it's always a list of + lists. OK, one might use <c>ets:foldl</c> or + <c>ets:foldr</c> instead:</p> + <code type="none"> +ets:foldr(fun(#emp{empno = E, dept = sales},Acc) -> [E | Acc]; + (_,Acc) -> Acc + end, + [], + emp_tab). </code> + <p>Running that would result in <c>["011103","076324"]</c> + , which at least gets rid of the extra lists. The fun is also quite + straightforward, so the only problem is that all the data from the + table has to be transferred from the table to the calling process for + filtering. That's inefficient compared to the <c>ets:match</c> + call where the filtering can be done "inside" the emulator and only + the result is transferred to the process. Remember that ets tables are + all about efficiency, if it wasn't for efficiency all of ets could be + implemented in Erlang, as a process receiving requests and sending + answers back. One uses ets because one wants performance, and + therefore one wouldn't want all of the table transferred to the + process for filtering. OK, let's look at a pure + <c>ets:select</c> call that does what the <c>ets:foldr</c> + does:</p> + <code type="none"> +ets:select(emp_tab,[{#emp{empno = '$1', dept = sales, _='_'},[],['$1']}]). </code> + <p>Even though the record syntax is used, it's still somewhat hard to + read and even harder to write. The first element of the tuple, + <c>#emp{empno = '$1', dept = sales, _='_'}</c> tells what to + match, elements not matching this will not be returned at all, as in + the <c>ets:match</c> example. The second element, the empty list + is a list of guard expressions, which we need none, and the third + element is the list of expressions constructing the return value (in + ets this almost always is a list containing one single term). In our + case <c>'$1'</c> is bound to the employee number in the head + (first element of tuple), and hence it is the employee number that is + returned. The result is <c>["011103","076324"]</c>, just as in + the <c>ets:foldr</c> example, but the result is retrieved much + more efficiently in terms of execution speed and memory consumption.</p> + <p>We have one efficient but hardly readable way of doing it and one + inefficient but fairly readable (at least to the skilled Erlang + programmer) way of doing it. With the use of <c>ets:fun2ms</c>, + one could have something that is as efficient as possible but still is + written as a filter using the fun syntax:</p> + <code type="none"> +-include_lib("stdlib/include/ms_transform.hrl"). + +% ... + +ets:select(emp_tab, ets:fun2ms( + fun(#emp{empno = E, dept = sales}) -> + E + end)). </code> + <p>This may not be the shortest of the expressions, but it requires no + special knowledge of match specifications to read. The fun's head + should simply match what you want to filter out and the body returns + what you want returned. As long as the fun can be kept within the + limits of the match specifications, there is no need to transfer all + data of the table to the process for filtering as in the + <c>ets:foldr</c> example. In fact it's even easier to read then + the <c>ets:foldr</c> example, as the select call in itself + discards anything that doesn't match, while the fun of the + <c>foldr</c> call needs to handle both the elements matching and + the ones not matching.</p> + <p>It's worth noting in the above <c>ets:fun2ms</c> example that one + needs to include <c>ms_transform.hrl</c> in the source code, as this is + what triggers the parse transformation of the <c>ets:fun2ms</c> call + to a valid match specification. This also implies that the + transformation is done at compile time (except when called from the + shell of course) and therefore will take no resources at all in + runtime. So although you use the more intuitive fun syntax, it gets as + efficient in runtime as writing match specifications by hand.</p> + <p>Let's look at some more <c>ets</c> examples. Let's say one + wants to get all the employee numbers of any employee hired before the + year 2000. Using <c>ets:match</c> isn't an alternative here as + relational operators cannot be expressed there. Once again, an + <c>ets:foldr</c> could do it (slowly, but correct):</p> + <code type="none"><![CDATA[ +ets:foldr(fun(#emp{empno = E, empyear = Y},Acc) when Y < 2000 -> [E | Acc]; + (_,Acc) -> Acc + end, + [], + emp_tab). ]]></code> + <p>The result will be + <c>["052341","076324","535216","789789","989891"]</c>, as + expected. Now the equivalent expression using a handwritten match + specification would look something like this:</p> + <code type="none"><![CDATA[ +ets:select(emp_tab,[{#emp{empno = '$1', empyear = '$2', _='_'}, + [{'<', '$2', 2000}], + ['$1']}]). ]]></code> + <p>This gives the same result, the <c><![CDATA[[{'<', '$2', 2000}]]]></c> is in + the guard part and therefore discards anything that does not have a + empyear (bound to '$2' in the head) less than 2000, just as the guard + in the <c>foldl</c> example. Lets jump on to writing it using + <c>ets:fun2ms</c></p> + <code type="none"><![CDATA[ +-include_lib("stdlib/include/ms_transform.hrl"). + +% ... + +ets:select(emp_tab, ets:fun2ms( + fun(#emp{empno = E, empyear = Y}) when Y < 2000 -> + E + end)). ]]></code> + <p>Obviously readability is gained by using the parse transformation.</p> + <p>I'll show some more examples without the tiresome + comparing-to-alternatives stuff. Let's say we'd want the whole object + matching instead of only one element. We could of course assign a + variable to every part of the record and build it up once again in the + body of the <c>fun</c>, but it's easier to do like this:</p> + <code type="none"><![CDATA[ +ets:select(emp_tab, ets:fun2ms( + fun(Obj = #emp{empno = E, empyear = Y}) + when Y < 2000 -> + Obj + end)). ]]></code> + <p>Just as in ordinary Erlang matching, you can bind a variable to the + whole matched object using a "match in then match", i.e. a + <c>=</c>. Unfortunately this is not general in <c>fun's</c> translated + to match specifications, only on the "top level", i.e. matching the + <em>whole</em> object arriving to be matched into a separate variable, + is it allowed. For the one's used to writing match specifications by + hand, I'll have to mention that the variable A will simply be + translated into '$_'. It's not general, but it has very common usage, + why it is handled as a special, but useful, case. If this bothers you, + the pseudo function <c>object</c> also returns the whole matched + object, see the part about caveats and limitations below.</p> + <p>Let's do something in the <c>fun</c>'s body too: Let's say + that someone realizes that there are a few people having an employee + number beginning with a zero (<c>0</c>), which shouldn't be + allowed. All those should have their numbers changed to begin with a + one (<c>1</c>) instead and one wants the + list <c><![CDATA[[{<Old empno>,<New empno>}]]]></c> created:</p> + <code type="none"> +ets:select(emp_tab, ets:fun2ms( + fun(#emp{empno = [$0 | Rest] }) -> + {[$0|Rest],[$1|Rest]} + end)). </code> + <p>As a matter of fact, this query hit's the feature of partially bound + keys in the table type <c>ordered_set</c>, so that not the whole + table need be searched, only the part of the table containing keys + beginning with <c>0</c> is in fact looked into. </p> + <p>The fun of course can have several clauses, so that if one could do + the following: For each employee, if he or she is hired prior to 1997, + return the tuple <c><![CDATA[{inventory, <employee number>}]]></c>, for each hired 1997 + or later, but before 2001, return <c><![CDATA[{rookie, <employee number>}]]></c>, for all others return <c><![CDATA[{newbie, <employee number>}]]></c>. All except for the ones named <c>Smith</c> as + they would be affronted by anything other than the tag + <c>guru</c> and that is also what's returned for their numbers; + <c><![CDATA[{guru, <employee number>}]]></c>:</p> + <code type="none"><![CDATA[ +ets:select(emp_tab, ets:fun2ms( + fun(#emp{empno = E, surname = "Smith" }) -> + {guru,E}; + (#emp{empno = E, empyear = Y}) when Y < 1997 -> + {inventory, E}; + (#emp{empno = E, empyear = Y}) when Y > 2001 -> + {newbie, E}; + (#emp{empno = E, empyear = Y}) -> % 1997 -- 2001 + {rookie, E} + end)). ]]></code> + <p>The result will be:</p> + <code type="none"> +[{rookie,"011103"}, + {rookie,"041231"}, + {guru,"052341"}, + {guru,"076324"}, + {newbie,"122334"}, + {rookie,"535216"}, + {inventory,"789789"}, + {newbie,"963721"}, + {rookie,"989891"}] </code> + <p>and so the Smith's will be happy...</p> + <p>So, what more can you do? Well, the simple answer would be; look + in the documentation of match specifications in ERTS users + guide. However let's briefly go through the most useful "built in + functions" that you can use when the <c>fun</c> is to be + translated into a match specification by <c>ets:fun2ms</c> (it's + worth mentioning, although it might be obvious to some, that calling + other functions than the one's allowed in match specifications cannot + be done. No "usual" Erlang code can be executed by the <c>fun</c> being + translated by <c>fun2ms</c>, the <c>fun</c> is after all limited + exactly to the power of the match specifications, which is + unfortunate, but the price one has to pay for the execution speed of + an <c>ets:select</c> compared to <c>ets:foldl/foldr</c>).</p> + <p>The head of the <c>fun</c> is obviously a head matching (or mismatching) + <em>one</em> parameter, one object of the table we <c>select</c> + from. The object is always a single variable (can be <c>_</c>) or + a tuple, as that's what's in <c>ets, dets</c> and + <c>mnesia</c> tables (the match specification returned by + <c>ets:fun2ms</c> can of course be used with + <c>dets:select</c> and <c>mnesia:select</c> as well as + with <c>ets:select</c>). The use of <c>=</c> in the head + is allowed (and encouraged) on the top level.</p> + <p>The guard section can contain any guard expression of Erlang. + Even the "old" type test are allowed on the toplevel of the guard + (<c>integer(X)</c> instead of <c>is_integer(X)</c>). As the new type tests (the + <c>is_</c> tests) are in practice just guard bif's they can also + be called from within the body of the fun, but so they can in ordinary + Erlang code. Also arithmetics is allowed, as well as ordinary guard + bif's. Here's a list of bif's and expressions:</p> + <list type="bulleted"> + <item>The type tests: is_atom, is_constant, is_float, is_integer, + is_list, is_number, is_pid, is_port, is_reference, is_tuple, + is_binary, is_function, is_record</item> + <item>The boolean operators: not, and, or, andalso, orelse </item> + <item>The relational operators: >, >=, <, =<, =:=, ==, =/=, /=</item> + <item>Arithmetics: +, -, *, div, rem</item> + <item>Bitwise operators: band, bor, bxor, bnot, bsl, bsr</item> + <item>The guard bif's: abs, element, hd, length, node, round, size, tl, + trunc, self</item> + <item>The obsolete type test (only in guards): + atom, constant, float, integer, + list, number, pid, port, reference, tuple, + binary, function, record</item> + </list> + <p>Contrary to the fact with "handwritten" match specifications, the + <c>is_record</c> guard works as in ordinary Erlang code.</p> + <p>Semicolons (<c>;</c>) in guards are allowed, the result will be (as + expected) one "match_spec-clause" for each semicolon-separated + part of the guard. The semantics being identical to the Erlang + semantics.</p> + <p>The body of the <c>fun</c> is used to construct the + resulting value. When selecting from tables one usually just construct + a suiting term here, using ordinary Erlang term construction, like + tuple parentheses, list brackets and variables matched out in the + head, possibly in conjunction with the occasional constant. Whatever + expressions are allowed in guards are also allowed here, but there are + no special functions except <c>object</c> and + <c>bindings</c> (see further down), which returns the whole + matched object and all known variable bindings respectively.</p> + <p>The <c>dbg</c> variants of match specifications have an + imperative approach to the match specification body, the ets dialect + hasn't. The fun body for <c>ets:fun2ms</c> returns the result + without side effects, and as matching (<c>=</c>) in the body of + the match specifications is not allowed (for performance reasons) the + only thing left, more or less, is term construction...</p> + <p>Let's move on to the <c>dbg</c> dialect, the slightly + different match specifications translated by <c>dbg:fun2ms</c>. </p> + <p>The same reasons for using the parse transformation applies to + <c>dbg</c>, maybe even more so as filtering using Erlang code is + simply not a good idea when tracing (except afterwards, if you trace + to file). The concept is similar to that of <c>ets:fun2ms</c> + except that you usually use it directly from the shell (which can also + be done with <c>ets:fun2ms</c>). </p> + <p>Let's manufacture a toy module to trace on </p> + <code type="none"> +-module(toy). + +-export([start/1, store/2, retrieve/1]). + +start(Args) -> + toy_table = ets:new(toy_table,Args). + +store(Key, Value) -> + ets:insert(toy_table,{Key,Value}). + +retrieve(Key) -> + [{Key, Value}] = ets:lookup(toy_table,Key), + Value. </code> + <p>During model testing, the first test bails out with a + <c>{badmatch,16}</c> in <c>{toy,start,1}</c>, why?</p> + <p>We suspect the ets call, as we match hard on the return value, but + want only the particular <c>new</c> call with + <c>toy_table</c> as first parameter. + So we start a default tracer on the node:</p> + <pre> +1> <input>dbg:tracer().</input> +{ok,<0.88.0>}</pre> + <p>And so we turn on call tracing for all processes, we are going to + make a pretty restrictive trace pattern, so there's no need to call + trace only a few processes (it usually isn't):</p> + <pre> +2> <input>dbg:p(all,call).</input> +{ok,[{matched,nonode@nohost,25}]} </pre> + <p>It's time to specify the filter. We want to view calls that resemble + <c><![CDATA[ets:new(toy_table,<something>)]]></c>:</p> + <pre> +3> <input>dbg:tp(ets,new,dbg:fun2ms(fun([toy_table,_]) -> true end)).</input> +{ok,[{matched,nonode@nohost,1},{saved,1}]} </pre> + <p>As can be seen, the <c>fun</c>'s used with + <c>dbg:fun2ms</c> takes a single list as parameter instead of a + single tuple. The list matches a list of the parameters to the traced + function. A single variable may also be used of course. The body + of the fun expresses in a more imperative way actions to be taken if + the fun head (and the guards) matches. I return <c>true</c> here, but it's + only because the body of a fun cannot be empty, the return value will + be discarded. </p> + <p>When we run the test of our module now, we get the following trace + output:</p> + <code type="none"><![CDATA[ +(<0.86.0>) call ets:new(toy_table,[ordered_set]) ]]></code> + <p>Let's play we haven't spotted the problem yet, and want to see what + <c>ets:new</c> returns. We do a slightly different trace + pattern:</p> + <pre> +4> <input>dbg:tp(ets,new,dbg:fun2ms(fun([toy_table,_]) -> return_trace() end)).</input></pre> + <p>Resulting in the following trace output when we run the test:</p> + <code type="none"><![CDATA[ +(<0.86.0>) call ets:new(toy_table,[ordered_set]) +(<0.86.0>) returned from ets:new/2 -> 24 ]]></code> + <p>The call to <c>return_trace</c>, makes a trace message appear + when the function returns. It applies only to the specific function call + triggering the match specification (and matching the head/guards of + the match specification). This is the by far the most common call in the + body of a <c>dbg</c> match specification.</p> + <p>As the test now fails with <c>{badmatch,24}</c>, it's obvious + that the badmatch is because the atom <c>toy_table</c> does not + match the number returned for an unnamed table. So we spotted the + problem, the table should be named and the arguments supplied by our + test program does not include <c>named_table</c>. We rewrite the + start function to:</p> + <code type="none"> +start(Args) -> + toy_table = ets:new(toy_table,[named_table |Args]). </code> + <p>And with the same tracing turned on, we get the following trace + output:</p> + <code type="none"><![CDATA[ +(<0.86.0>) call ets:new(toy_table,[named_table,ordered_set]) +(<0.86.0>) returned from ets:new/2 -> toy_table ]]></code> + <p>Very well. Let's say the module now passes all testing and goes into + the system. After a while someone realizes that the table + <c>toy_table</c> grows while the system is running and that for some + reason there are a lot of elements with atom's as keys. You had + expected only integer keys and so does the rest of the system. Well, + obviously not all of the system. You turn on call tracing and try to + see calls to your module with an atom as the key:</p> + <pre> +1> <input>dbg:tracer().</input> +{ok,<0.88.0>} +2> <input>dbg:p(all,call).</input> +{ok,[{matched,nonode@nohost,25}]} +3> <input>dbg:tpl(toy,store,dbg:fun2ms(fun([A,_]) when is_atom(A) -> true end)).</input> +{ok,[{matched,nonode@nohost,1},{saved,1}]}</pre> + <p>We use <c>dbg:tpl</c> here to make sure to catch local calls + (let's say the module has grown since the smaller version and we're + not sure this inserting of atoms is not done locally...). When in + doubt always use local call tracing.</p> + <p>Let's say nothing happens when we trace in this way. Our function + is never called with these parameters. We make the conclusion that + someone else (some other module) is doing it and we realize that we + must trace on ets:insert and want to see the calling function. The + calling function may be retrieved using the match specification + function <c>caller</c> and to get it into the trace message, one + has to use the match spec function <c>message</c>. The filter + call looks like this (looking for calls to <c>ets:insert</c>):</p> + <pre> +4> <input>dbg:tpl(ets,insert,dbg:fun2ms(fun([toy_table,{A,_}]) when is_atom(A) -> </input> +<input> message(caller()) </input> +<input> end)). </input> +{ok,[{matched,nonode@nohost,1},{saved,2}]} </pre> + <p>The caller will now appear in the "additional message" part of the + trace output, and so after a while, the following output comes:</p> + <code type="none"><![CDATA[ +(<0.86.0>) call ets:insert(toy_table,{garbage,can}) ({evil_mod,evil_fun,2}) ]]></code> + <p>You have found out that the function <c>evil_fun</c> of the + module <c>evil_mod</c>, with arity <c>2</c>, is the one + causing all this trouble.</p> + <p>This was just a toy example, but it illustrated the most used + calls in match specifications for <c>dbg</c> The other, more + esotheric calls are listed and explained in the <em>Users guide of the ERTS application</em>, they really are beyond the scope of this + document.</p> + <p>To end this chatty introduction with something more precise, here + follows some parts about caveats and restrictions concerning the fun's + used in conjunction with <c>ets:fun2ms</c> and + <c>dbg:fun2ms</c>:</p> + <warning> + <p>To use the pseudo functions triggering the translation, one + <em>has to</em> include the header file <c>ms_transform.hrl</c> + in the source code. Failure to do so will possibly result in + runtime errors rather than compile time, as the expression may + be valid as a plain Erlang program without translation.</p> + </warning> + <warning> + <p>The <c>fun</c> has to be literally constructed inside the + parameter list to the pseudo functions. The <c>fun</c> cannot + be bound to a variable first and then passed to + <c>ets:fun2ms</c> or <c>dbg:fun2ms</c>, i.e this + will work: <c>ets:fun2ms(fun(A) -> A end)</c> but not this: + <c>F = fun(A) -> A end, ets:fun2ms(F)</c>. The later will result + in a compile time error if the header is included, otherwise a + runtime error. Even if the later construction would ever + appear to work, it really doesn't, so don't ever use it.</p> + </warning> + <p>Several restrictions apply to the fun that is being translated + into a match_spec. To put it simple you cannot use anything in + the fun that you cannot use in a match_spec. This means that, + among others, the following restrictions apply to the fun itself:</p> + <list type="bulleted"> + <item>Functions written in Erlang cannot be called, neither + local functions, global functions or real fun's</item> + <item>Everything that is written as a function call will be + translated into a match_spec call to a builtin function, so that + the call <c>is_list(X)</c> will be translated to <c>{'is_list', '$1'}</c> (<c>'$1'</c> is just an example, the numbering may + vary). If one tries to call a function that is not a match_spec + builtin, it will cause an error.</item> + <item>Variables occurring in the head of the <c>fun</c> will be + replaced by match_spec variables in the order of occurrence, so + that the fragment <c>fun({A,B,C})</c> will be replaced by + <c>{'$1', '$2', '$3'}</c> etc. Every occurrence of such a + variable later in the match_spec will be replaced by a + match_spec variable in the same way, so that the fun + <c>fun({A,B}) when is_atom(A) -> B end</c> will be translated into + <c>[{{'$1','$2'},[{is_atom,'$1'}],['$2']}]</c>.</item> + <item> + <p>Variables that are not appearing in the head are imported + from the environment and made into + match_spec <c>const</c> expressions. Example from the shell:</p> + <pre> +1> <input>X = 25.</input> +25 +2> <input>ets:fun2ms(fun({A,B}) when A > X -> B end).</input> +[{{'$1','$2'},[{'>','$1',{const,25}}],['$2']}]</pre> + </item> + <item> + <p>Matching with <c>=</c> cannot be used in the body. It can only + be used on the top level in the head of the fun. + Example from the shell again:</p> + <pre> +1> <input>ets:fun2ms(fun({A,[B|C]} = D) when A > B -> D end).</input> +[{{'$1',['$2'|'$3']},[{'>','$1','$2'}],['$_']}] +2> <input>ets:fun2ms(fun({A,[B|C]=D}) when A > B -> D end).</input> +Error: fun with head matching ('=' in head) cannot be translated into +match_spec +{error,transform_error} +3> <input>ets:fun2ms(fun({A,[B|C]}) when A > B -> D = [B|C], D end).</input> +Error: fun with body matching ('=' in body) is illegal as match_spec +{error,transform_error} </pre> + <p>All variables are bound in the head of a match_spec, so the + translator can not allow multiple bindings. The special case + when matching is done on the top level makes the variable bind + to <c>'$_'</c> in the resulting match_spec, it is to allow a more + natural access to the whole matched object. The pseudo + function <c>object()</c> could be used instead, see below. + The following expressions are translated equally: </p> + <code type="none"> +ets:fun2ms(fun({a,_} = A) -> A end). +ets:fun2ms(fun({a,_}) -> object() end).</code> + </item> + <item> + <p>The special match_spec variables <c>'$_'</c> and <c>'$*'</c> + can be accessed through the pseudo functions <c>object()</c> + (for <c>'$_'</c>) and <c>bindings()</c> (for <c>'$*'</c>). + as an example, one could translate the following + <c>ets:match_object/2</c> call to a <c>ets:select</c> call:</p> + <code type="none"> +ets:match_object(Table, {'$1',test,'$2'}). </code> + <p>...is the same as...</p> + <code type="none"> +ets:select(Table, ets:fun2ms(fun({A,test,B}) -> object() end)).</code> + <p>(This was just an example, in this simple case the former + expression is probably preferable in terms of readability). + The <c>ets:select/2</c> call will conceptually look like this + in the resulting code:</p> + <code type="none"> +ets:select(Table, [{{'$1',test,'$2'},[],['$_']}]).</code> + <p>Matching on the top level of the fun head might feel like a + more natural way to access <c>'$_'</c>, see above.</p> + </item> + <item>Term constructions/literals are translated as much as is + needed to get them into valid match_specs, so that tuples are + made into match_spec tuple constructions (a one element tuple + containing the tuple) and constant expressions are used when + importing variables from the environment. Records are also + translated into plain tuple constructions, calls to element + etc. The guard test <c>is_record/2</c> is translated into + match_spec code using the three parameter version that's built + into match_specs, so that <c>is_record(A,t)</c> is translated + into <c>{is_record,'$1',t,5}</c> given that the record size of + record type <c>t</c> is 5.</item> + <item>Language constructions like <c>case</c>, <c>if</c>, + <c>catch</c> etc that are not present in match_specs are not + allowed.</item> + <item>If the header file <c>ms_transform.hrl</c> is not included, + the fun won't be translated, which may result in a + <em>runtime error</em> (depending on if the fun is valid in a + pure Erlang context). Be absolutely sure that the header is + included when using <c>ets</c> and <c>dbg:fun2ms/1</c> in + compiled code.</item> + <item>If the pseudo function triggering the translation is + <c>ets:fun2ms/1</c>, the fun's head must contain a single + variable or a single tuple. If the pseudo function is + <c>dbg:fun2ms/1</c> the fun's head must contain a single + variable or a single list.</item> + </list> + <p>The translation from fun's to match_specs is done at compile + time, so runtime performance is not affected by using these pseudo + functions. The compile time might be somewhat longer though. </p> + <p>For more information about match_specs, please read about them + in <em>ERTS users guide</em>.</p> + </description> + <funcs> + <func> + <name>parse_transform(Forms,_Options) -> Forms</name> + <fsummary>Transforms Erlang abstract format containing calls to ets/dbg:fun2ms into literal match specifications.</fsummary> + <type> + <v>Forms = Erlang abstract code format, see the erl_parse module description </v> + <v>_Options = Option list, required but not used</v> + </type> + <desc> + <p>Implements the actual transformation at compile time. This + function is called by the compiler to do the source code + transformation if and when the <c>ms_transform.hrl</c> header + file is included in your source code. See the <c>ets</c> and + <c>dbg</c>:<c>fun2ms/1</c> function manual pages for + documentation on how to use this parse_transform, see the + <c>match_spec</c> chapter in <c>ERTS</c> users guide for a + description of match specifications. </p> + </desc> + </func> + <func> + <name>transform_from_shell(Dialect,Clauses,BoundEnvironment) -> term()</name> + <fsummary>Used when transforming fun's created in the shell into match_specifications.</fsummary> + <type> + <v>Dialect = ets | dbg</v> + <v>Clauses = Erlang abstract form for a single fun</v> + <v>BoundEnvironment = [{atom(), term()}, ...], list of variable bindings in the shell environment</v> + </type> + <desc> + <p>Implements the actual transformation when the <c>fun2ms</c> + functions are called from the shell. In this case the abstract + form is for one single fun (parsed by the Erlang shell), and + all imported variables should be in the key-value list passed + as <c>BoundEnvironment</c>. The result is a term, normalized, + i.e. not in abstract format.</p> + </desc> + </func> + <func> + <name>format_error(Errcode) -> ErrMessage</name> + <fsummary>Error formatting function as required by the parse_transform interface.</fsummary> + <type> + <v>Errcode = term()</v> + <v>ErrMessage = string()</v> + </type> + <desc> + <p>Takes an error code returned by one of the other functions + in the module and creates a textual description of the + error. Fairly uninteresting function actually.</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml new file mode 100644 index 0000000000..f7128b641d --- /dev/null +++ b/lib/stdlib/doc/src/notes.xml @@ -0,0 +1,2704 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>STDLIB Release Notes</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + <file>notes.xml</file> + </header> + <p>This document describes the changes made to the STDLIB application.</p> + +<section><title>STDLIB 1.16.4</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The documentation is now built with open source tools + (xsltproc and fop) that exists on most platforms. One + visible change is that the frames are removed.</p> + <p> + Own Id: OTP-8201</p> + </item> + <item> + <p> + [escript] The restriction that the first line in escripts + must begin with <c>#!</c> has been removed.</p> + <p> + [escript] Some command line options to the escript + executable has now been documented. For example you can + run an escript in the debugger by just adding a command + line option.</p> + <p> + [escript] The documentation of the escript header syntax + has been clarified. For example the header is optional. + This means that it is possible to directly "execute" + <c>.erl</c>, <c>.beam</c> and<c>.zip</c> files.</p> + <p> + Own Id: OTP-8215</p> + </item> + <item> + <p>Optimized array:from_orddict/1, it is now faster and + uses less memory if the orddict was sparse.</p> + <p>Changed array:reset/2, it will now never expand the + array which it could before for non fixed arrays. See the + documentation.</p> + <p> + Own Id: OTP-8216</p> + </item> + <item> + <p>The Erlang Pretty Printer (<c>erl_pp</c>) now puts the + leading <c>[</c> of list comprehensions as well as the + leading <c><<</c> of bit string comprehensions on a + separate line in order to expose the Cover counter of the + template.</p> + <p> + Own Id: OTP-8227</p> + </item> + <item> + <p>The extension ".xrl" used for Leex input files is now + recognized by the compiler.</p> + <p> + Own Id: OTP-8232</p> + </item> + <item> + <p> + Some clarifications have been made in the documentation + regarding <c>gen_server</c>, <c>gen_fsm</c>, and + <c>gen_event</c> behavior when handling <c>'EXIT'</c> + messages from the parent process. For more information + see the <seealso + marker="gen_server">gen_server(3)</seealso>, <seealso + marker="gen_fsm">gen_fsm(3)</seealso>, and <seealso + marker="gen_event">gen_event(3)</seealso> documentation.</p> + <p> + Own Id: OTP-8255 Aux Id: seq11419 </p> + </item> + <item> + <p>The -on_load() directive can be used to run a function + when a module is loaded. It is documented in the section + about code loading in the Reference Manual.</p> + <p> + Own Id: OTP-8295</p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 1.16.3.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + An erroneous type spec for <c>gen:start/6</c> caused + dialyzer to erroneously issue warnings when + <c>{spawn_opt, SpawnOptionList}</c> was passed in the + option list to the <c>gen_server</c> and <c>gen_fsm</c> + start functions.</p> + <p> + Own Id: OTP-8068 Aux Id: seq11323, seq11314 </p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 1.16.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>The linter used to crash on invalid <c>-opaque</c> + declarations.</p> + <p> + Own Id: OTP-8051</p> + </item> + <item> + <p>Bugs in <c>digraph:add_edge/5</c> and + <c>digraph:del_path/3</c> have been fixed. (Thanks to + Crystal Din.)</p> + <p> + Own Id: OTP-8066</p> + </item> + <item> + <p>When trying to insert objects with + <c>dets:insert_new()</c> into a Dets table of type + <c>duplicate_bag</c>, already existing objects would + sometimes be duplicated. This bug has been fixed. (Thanks + to Crystal Din.)</p> + <p> + Own Id: OTP-8070</p> + </item> + <item> + <p> + Running erlc in a very deep directory (with a path length + of more 256 or more characters) would cause the emulator + to crash in a call to <c>list_to_atom/1</c>. (Thanks to + Chris Newcombe.)</p> + <p> + Own Id: OTP-8124</p> + </item> + <item> + <p>A few minor bugs have been fixed in the Erlang Code + Preprocessor (<c>epp</c>).</p> + <p> + Own Id: OTP-8130</p> + </item> + <item> + <p>A bug in The Erlang Meta Interpreter (<c>erl_eval</c>) + has been fixed: exceptions generated in the template of + bit string comprehensions were not handled properly. + (Thanks to Ulf Wiger.)</p> + <p> + Own Id: OTP-8133</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Option <c>{capture,none}</c> was missing in documentation + for <c>re:run/3</c>.</p> + <p> + Own Id: OTP-8113</p> + </item> + <item> + <p>When <c>erl_scan:tokens()</c> returns an error tuple + <c>{error, ErrorInfo, EndLocation</c>}, the list + <c>LeftOverChars</c> is the remaining characters of the + input data, starting from <c>EndLocation</c>. It used to + be the empty list.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-8129</p> + </item> + <item> + <p>The Erlang Meta Interpreter (<c>erl_eval</c>) has been + somewhat optimized when it comes to interpreting + <c>receive</c>-expressions. (Thanks to Richard + Carlsson.)</p> + <p> + Own Id: OTP-8139</p> + </item> + <item> + <p>The Erlang Pretty Printer (<c>erl_pp</c>) has been + modified as to handle types.</p> + <p> + Own Id: OTP-8150</p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 1.16.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>The text of tokens returned by the Erlang scanner + (<c>erl_scan</c>) was sometimes empty when the + <c>text</c> option was given and <c>StartLocation</c> was + a line. This bug has been fixed.</p> + <p> + Own Id: OTP-7965</p> + </item> + <item> + <p>The documentation for <c>base64:decode/1</c> has been + updated to point out that it strips whitespace.</p> + <p><c>base64:decode/1</c> and <c>base64:mime_decode/1</c> + would sometimes fail instead of stripping away non-base64 + characters.</p> + <p> + Own Id: OTP-7984</p> + </item> + <item> + <p> + Two types in the <c>gen</c> module were corrected.</p> + <p> + Own Id: OTP-8029 Aux Id: seq11296 </p> + </item> + <item> + <p> + <c>array:from_orddict([])</c> and + <c>array:from_list([])</c> would construct fixed arrays + instead of extendible arrays.</p> + <p> + Own Id: OTP-8033</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Interpreted escripts are now tail recursive.</p> + <p> + The function erl_eval:expr/5 has been introduced.</p> + <p> + Own Id: OTP-7933</p> + </item> + <item> + <p> + <c>gen_server:call/2,3</c> will be somewhat faster if the + calling process has a many messages in its message queue.</p> + <p> + Own Id: OTP-7979</p> + </item> + <item> + <p> + Random now supports seed with arity one, + <c>random:seed/1</c>, which takes a three-tuple.</p> + <p> + Own Id: OTP-8019</p> + </item> + <item> + <p>The <c>regexp</c> module now recognizes the escape + sequences <c>\xXY</c> and <c>\x{X...}</c>.</p> + <p> + Own Id: OTP-8024</p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 1.16.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>The documentation of <c>dets:open_file/1</c> now + states that the file is repaired if it has not been + properly closed. (Thanks to Ulf Wiger.)</p> + <p> + Own Id: OTP-7895</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>The Erlang scanner no longer returns the text of + tokens when the start location is a pair of a line and + column unless the new option <c>text</c> is supplied + (incompatibility with R13A).</p> <p>There are new + functions to access the attributes of tokens: + <c>attributes_info/1,2</c> and + <c>set_attribute/3</c>.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7892 Aux Id: OTP-7810 </p> + </item> + <item> + <p> + Several glitches and performance issues in the Unicode + and I/O-system implementation of R13A have been + corrected.</p> + <p> + Own Id: OTP-7896 Aux Id: OTP-7648 OTP-7887 </p> + </item> + <item> + <p> + The type spec of filelib:wildcard/2 has been corrected.</p> + <p> + Own Id: OTP-7915</p> + </item> + <item> + <p>New functions: <c>gb_sets:is_disjoint/2</c>, + <c>ordsets:is_disjoint/2</c>, and + <c>gb_sets:is_disjoint/2</c>.</p> + <p> + Own Id: OTP-7947</p> + </item> + <item> + <p>The function <c>gb_trees:map/2</c> which was added in + R13A is now documented.</p> + <p> + Own Id: OTP-7948</p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 1.16</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Fixed a minor race conditions in + <c>gen_server:start*</c>: if one of these functions + returned <c>{error,Reason}</c> or <c>ignore</c>, the name + could still be registered (either locally or in + <c>global</c>).</p> + <p>A process started by <c>proc_lib</c> in some cases + depended on its process dictionary not to be erased, and + would crash when terminating abnormally and not generate + a proper crash report. This has been corrected (but the + initial call will not be shown in the error report if the + process dictionary has been erased). NOTE: There is no + longer any need to erase the process dictionary for + memory conservation reasons, since the actual call + arguments are no longer saved in the process + dictionary.</p> + <p> + Own Id: OTP-7669</p> + </item> + <item> + <p>The Erlang preprocessor used wrong line number when + stringifying macro arguments. (Thanks to John + Hughes.)</p> + <p> + Own Id: OTP-7702</p> + </item> + <item> + <p>A bug in the <c>qlc</c> module has been fixed: merge + join sometimes failed to return all answers. (Thanks to + Bernard Duggan.)</p> + <p> + Own Id: OTP-7714</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>A new option, <c>key_equality</c>, has been added to + <c>qlc:table/2</c>. This option makes it possible for + <c>qlc</c> to better handle tables that use <c>==/2</c> + when comparing keys for equality (examples of such tables + are ordered ETS tables and gb_table in qlc(3)).</p> + <p> + Own Id: OTP-6674</p> + </item> + <item> + <p>The functions <c>lists:seq/1,2</c> return the empty + list in a few cases when they used to generate an + exception, for example <c>lists:seq(1, 0)</c>. See + lists(3) for details. (Thanks to Richard O'Keefe.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7230</p> + </item> + <item> + <p> + The order of objects visited in select for ordered_set is + now documented.</p> + <p> + Own Id: OTP-7339</p> + </item> + <item> + <p> + It is now possible to debug code in escripts and + archives.</p> + <p> + Own Id: OTP-7626</p> + </item> + <item> + <p>Support for Unicode is implemented as described in + EEP10. Formatting and reading of unicode data both from + terminals and files is supported by the io and io_lib + modules. Files can be opened in modes with automatic + translation to and from different unicode formats. The + module 'unicode' contains functions for conversion + between external and internal unicode formats and the re + module has support for unicode data. There is also + language syntax for specifying string and character data + beyond the ISO-latin-1 range.</p> + <p>The interactive shell will support input and output of + unicode characters when the terminal and operating system + supports it.</p> + <p>Please see the EEP and the io/io_lib manual pages as + well as the stdlib users guide for details.</p> + <p><em>I/O-protocol incompatibilities:</em></p> + <p>The io_protocol between io_Server and client is + updated to handle protocol data in unicode formats. The + updated protocol is now documented. The specification + resides in the stdlib <em>users manual</em>, which is a + new part of the manual.</p> + <p><em>io module incompatibilities:</em></p> + <p>The io:put_chars, io:get_chars and io:get_line all + handle and return unicode data. In the case where + binaries can be provided (as to io:put_chars), they shall + be encoded in UTF-8. When binaries are returned (as by + io:get_line/get_chars when the io_server is set in + <em>binary mode</em>) the returned data is also + <em>always</em> encoded as UTF-8. The file module however + still returns byte-oriented data, why file:read can be + used instead of io:get_chars to read binary data in + ISO-latin-1.</p> + <p><em>io_lib module incompatibilities:</em></p> + <p>io_lib:format can, given new format directives (i.e + "~ts" and "~tc"), return lists containing integers larger + than 255. </p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7648 Aux Id: OTP-7580 OTP-7514 OTP-7494 + OTP-7443 OTP-7181 EEP10 EEP11 </p> + </item> + <item> + <p> + The function <c>pool:attach/1</c> now returns + <c>already_attached</c> if the node is already attached, + rather than <c>allready_attached</c> (sic!). (Thanks to + Edwin Fine.)</p> + <p> + Own Id: OTP-7653 Aux Id: OTP-7603 </p> + </item> + <item> + <p> + Preprocessor directives are now allowed in escripts. This + means that for example macros may be used in escripts.</p> + <p> + Own Id: OTP-7662</p> + </item> + <item> + <p>When a process started with <c>proc_lib</c>, + <c>gen_server</c>, or <c>gen_fsm</c> exits with reason + <c>{shutdown,Term}</c>, a crash report will no longer be + generated (to allow a clean shutdown, but still provide + additional information to process that are linked to the + terminating process).</p> + <p> + Own Id: OTP-7740 Aux Id: seq10847 </p> + </item> + <item> + <p> + A new BIF, <c>lists:keyfind/3</c>, has been added. It + works like <c>lists:keysearch/3</c> except that it does + not wrap the returned tuple in a <c>value</c> tuple in + case of success. (Thanks to James Hague for suggesting + this function.)</p> + <p> + Own Id: OTP-7752</p> + </item> + <item> + <p><c>lists:suffix(Suffix, List)</c> used to have a a + complexity of <c>length(Suffix)*length(List)</c> (which + could become quite slow for some inputs). It has now been + re-implemented so that its complexity is + <c>length(Suffix)+length(List)</c>. (Thanks to Richard + O'Keefe for the new implementation.)</p> + <p> + Own Id: OTP-7797</p> + </item> + <item> + <p>The Erlang scanner has been augmented as to return + white spaces, comments, and exact location of tokens. The + functions <c>string/3</c>, <c>tokens/4</c>, and + <c>token_info/1,2</c> are new. See erl_scan(3) for + details.</p> + <p><c>tokens/3,4</c> have been modified as to return a + list of tokens instead of an error when <c>eof</c> is + encountered before the dot.</p> + <p> + Own Id: OTP-7810</p> + </item> + <item> + <p> + <c>filelib:fold_files/5</c> now uses the <c>re</c> module + instead of the <c>regexp</c> module for regular + expression matching. In practice, this change will not be + a problem for most regular expressions used for + <c>filelib:fold_files/5</c>. (The major difference in + regular expression is that parenthesis and curly brackets + is treated as literal characters by <c>regexp</c> but as + special characters by <c>re</c>; fortunately, those + characters are rarely used in filenames.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7819</p> + </item> + <item> + <p> + <c>digraph:new(Type)</c> will now cause a <c>badarg</c> + exception if <c>Type</c> is not a valid type. Similarly, + <c>digraph_utils:subgraph/2,3</c> will now cause a + <c>badarg</c> if the arguments are invalid. (Those + functions used to return error tuples if something was + wrong.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7824</p> + </item> + <item> + <p>The argument passed to <c>random:uniform/1</c> must + now be an integer (as stated in the documentation). In + previous releases, a floating point number was also + allowed.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7827</p> + </item> + <item> + <p>The copyright notices have been updated.</p> + <p> + Own Id: OTP-7851</p> + </item> + <item> + <p>A few missing match spec functions was added to + dbg:fun2ms; exception_trace/0 and trace/2,3.</p> + <p>There is a new function queue:member/2.</p> + <p>A bug in io_lib:fread that made it accidentally + concatenate fields separated by newline has been + corrected. Reported and analyzed by Matthew Palmer to + erlang-patches.</p> + <p> + Own Id: OTP-7865</p> + </item> + </list> + </section> + +</section> + + +<section><title>STDLIB 1.15.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>A bug in the <c>qlc</c> module has been fixed: when + merge joining two query handles the temporary file used + for equivalence classes was not truncated properly which + could result in poor performance.</p> + <p> + Own Id: OTP-7552</p> + </item> + <item> + <p> + The characters 16#C0 and 16#E0 ("A" and "a" with grave + accent), were not properly converted by the + <c>string:to_lower/1</c> and <c>string:to_upper/1</c> + functions. (Thanks to Richard O'Keefe.)</p> + <p> + Own Id: OTP-7589</p> + </item> + <item> + <p> + The function <c>pool:attach/1</c> now returns + <c>already_attached</c> if the node is already attached, + rather than <c>allready_attached</c> (sic!). (Thanks to + Edwin Fine.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7603</p> + </item> + <item> + <p>The documentation for <c>io:get_line/1,2</c> now + mentions that the return value can also be + <c>{error,Reason}</c>.</p> + <p> + Own Id: OTP-7604 Aux Id: seq11063 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The split function is now added to the re library. + Exceptions and errors from both run, replace and split + are made more consistent.</p> + <p> + Own Id: OTP-7514 Aux Id: OTP-7494 </p> + </item> + <item> + <p>Processes spawned using <c>proc_lib</c> (including + <c>gen_server</c> and other library modules that use + <c>proc_lib</c>) no longer keep the entire argument list + for the initial call, but only the arity.</p> + <p>Also, if <c>proc_lib:spawn/1</c> is used to spawn a + fun, the actual fun is not kept, but only module, + function name, and arity of the function that implements + the fun.</p> + <p>The reason for the change is that keeping the initial + fun (or a fun in an argument list), would prevent + upgrading the code for the module. A secondary reason is + that keeping the fun and function arguments could waste a + significant amount of memory.</p> + <p>The drawback with the change is that the crash reports + will provide less precise information about the initial + call (only <c>Module:Function/Arity</c> instead of + <c>Module:Function(Arguments)</c>). The function + <c>proc_lib:initial_call/1</c> still returns a list, but + each argument has been replaced with a dummy atom.</p> + <p> + Own Id: OTP-7531 Aux Id: seq11036 </p> + </item> + <item> + <p> + There is now experimental support for loading of code + from archive files. See the documentation of <c>code</c>, + <c>init</c>, <c>erl_prim_loader </c> and <c>escript</c> + for more info.</p> + <p> + The error handling of <c>escripts</c> has been improved.</p> + <p> + An <c>escript</c> may now set explicit arguments to the + emulator, such as <c>-smp enabled</c>.</p> + <p> + An <c>escript</c> may now contain a precompiled beam + file.</p> + <p> + An <c>escript</c> may now contain an archive file + containing one or more applications (experimental).</p> + <p> + The internal module <c>code_aux</c> has been removed.</p> + <p> + Own Id: OTP-7548 Aux Id: otp-6622 </p> + </item> + <item> + <p> + Enabled explicit control of which types of files that + should be compressed in a ZIP archive.</p> + <p> + Own Id: OTP-7549 Aux Id: otp-6622 </p> + </item> + <item> + <p> + In the job control mode, the "s" and "r" commands now + take an optional argument to specify which shell to + start. (Thanks to Robert Virding.)</p> + <p> + Own Id: OTP-7617</p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 1.15.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A bug in the calendar module could cause + calendar:local_time_to_universal_time_dst/1 to return + duplicate identical values for local times in timezones + without DST. Multiple values should only be returned when + a local time is within the hour occurring twice due to + shift from DST to non-DST, and certainly only in + timezones with DST. The correct behaviour is now + implemented.</p> + <p> + Own Id: OTP-7344 Aux Id: seq10960 </p> + </item> + <item> + <p>The documentation of <c>(d)ets:init_table()</c> has + been corrected. (Thanks to Paul Mineiro.)</p> + <p> + Own Id: OTP-7413</p> + </item> + <item> + <p>The soft upper limit of 60 on the number of non-white + characters on a line, which was introduced in R12B-0 for + the control sequences <c>p</c> and <c>P</c> of the + functions <c>io:fwrite/2,3</c> and + <c>io_lib:fwrite/2</c>, has been removed. This means that + terms whose printed representation fits on a line will + have no NEWLINEs. The Erlang shell still uses the 60 + character limit, though.</p> + <p> + Own Id: OTP-7421 Aux Id: OTP-6708 </p> + </item> + <item> + <p>Some debug code has been removed from Dets.</p> + <p> + Own Id: OTP-7424</p> + </item> + <item> + <p>The documentation of <c>dets:match_delete/2</c> has + been corrected. (Thanks to Paul Mineiro.)</p> + <p> + Own Id: OTP-7445</p> + </item> + <item> + <p>Corrections of digraph(3). (Thanks to Vlad + Dumitrescu.)</p> + <p> + Own Id: OTP-7492</p> + </item> + <item> + <p> + For the process that an escript runs in, the + <c>trap_exit</c> process flag is now <c>false</c> instead + of <c>true</c> (as in previous releases). Scripts that + depend on the previous (counter-intuitive) behaviour + might not work. (Thanks to Bengt Kleberg.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-7517</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>The documentation of <c>lists:(u)sort/2</c> now states + what is expected of an ordering function.</p> + <p> + Own Id: OTP-7489</p> + </item> + <item> + <p> + The re module is extended with repetitive matches (global + option) and replacement function.</p> + <p> + Own Id: OTP-7494 Aux Id: OTP-7181 </p> + </item> + <item> + <p>The Erlang shell now displays a nicer error message + when evaluating an undefined command. (Thanks to Richard + Carlsson.)</p> + <p> + Own Id: OTP-7495</p> + </item> + </list> + </section> + +</section> + + +<section><title>STDLIB 1.15.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + zip:unzip to/from binary with empty directories did not + work. (Thanks to Martin Dvorak.)</p> + <p> + Own Id: OTP-7248</p> + </item> + <item> + <p>The documentation of the control sequence <c>w</c> of + the <c>io_lib</c> module now states that floating point + numbers are printed accurately.</p> + <p> + Own Id: OTP-7324 Aux Id: OTP-7084 </p> + </item> + <item> + <p> + zip:unzip was not supporting a flavour of the zip format + found in jar-files.</p> + <p> + Own Id: OTP-7382 Aux Id: seq10970 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + An experimental module "re" is added to the emulator + which interfaces a publicly available regular expression + library for Perl-like regular expressions (PCRE). The + interface is purely experimental and *will* be subject to + change.</p> + <p> + The implementation is for reference and testing in + connection to the relevant EEP.</p> + <p> + Own Id: OTP-7181</p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 1.15.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> When inserting many small objects, Dets sometimes + crashed when reaching the maximum number of slots. + (Thanks to Daniel Goertzen.) </p> + <p> + Own Id: OTP-7146</p> + </item> + <item> + <p>Processes linked to the Erlang shell did not get an + exit signal when the evaluator process was killed. This + bug, introduced in R12B-0, has been fixed.</p> + <p> + Own Id: OTP-7184 Aux Id: OTP-6554 </p> + </item> + <item> + <p> + Invalid arguments to <c>ets:update_counter/3</c> were not + handled correctly. A tuple position (<c>Pos</c>) less + than 1 caused the element directly following the key to + be updated (as if no position at all had been specified). + All invalid values for <c>Pos</c> will now fail with + <c>badarg</c>.</p> + <p> + Own Id: OTP-7226</p> + </item> + <item> + <p> + For certain terminals, io:columns/0 could return 0 + instead of enotsup. That is now corrected.</p> + <p> + Own Id: OTP-7229 Aux Id: seq10886 </p> + </item> + <item> + <p><c>qlc:info()</c> can now handle port identifiers, + pids, references, and funs. (Thanks to Wojciech Kaczmare + for reporting this bug.)</p> <p>When evaluating the + <c>parent_fun</c> messages sent to the process calling + <c>qlc:cursor()</c> were sometimes erroneously consumed. + This bug has been fixed.</p> + <p> + Own Id: OTP-7232</p> + </item> + <item> + <p><c>erl_parse:abstract()</c> can now handle bit + strings.</p> + <p> + Own Id: OTP-7234</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>The <c>queue</c> module has been rewritten to make it + easier to use. Suggestions and discussion from and with + among others Lev Walkin, Anders Ramsell and Rober Virding + in december 2007 on [email protected]. It was + also discussed to change the internal representation to + contain length information which would speed up + <c>len/1</c> but that change has been postponed. Anyone + interested may write an EEP and try to reach an + acceptable compromise for queue overhead and thereby the + speed of all other operations than <c>len/1</c>. The + <c>queue</c> module is now optimized for fast and minimal + garbage <c>in/2</c> and <c>out/1</c> and such. See the + documentation.</p> + <p>New functions: <c>is_queue/1</c>, <c>get/1</c>, + <c>get_r/1</c>, <c>peek/1</c>, <c>peek_r/1</c>, + <c>drop/1</c>, <c>drop_r/1</c> and <c>liat/1</c>. + <c>is_queue/1</c> is a new predicate, <c>liat/1</c> is a + correction of an old misspelling, and the others + (<c>get</c>*, <c>peek</c>* and <c>drop</c>*) are new + interface functions.</p> + <p> + Own Id: OTP-7064</p> + </item> + <item> + <p>The functions <c>io_lib:write/1,2</c> and + <c>io_lib:print/1,4</c> have been changed when it comes + to writing floating point numbers. This change affects + the control sequences <c>p</c>, <c>P</c>, <c>w</c>, and + <c>W</c> of the <c>io_lib</c> module. (Thanks to Bob + Ippolito for code contribution.) </p> + <p> + Own Id: OTP-7084</p> + </item> + <item> + <p> + Updated the documentation for + <c>erlang:function_exported/3</c> and <c>io:format/2</c> + functions to no longer state that those functions are + kept mainly for backwards compatibility.</p> + <p> + Own Id: OTP-7186</p> + </item> + <item> + <p> + A new BIF ets:update_element/3. To update individual + elements within an ets-tuple, without having to read, + update and write back the entire tuple.</p> + <p> + Own Id: OTP-7200</p> + </item> + <item> + <p><c>string:join/2</c> now accepts an empty list as + first argument.</p> + <p> + Own Id: OTP-7231 Aux Id: OTP-6671 </p> + </item> + <item> + <p><c>qlc:info/1,2</c> accepts a new option, + <c>depth</c>. The type <c>SelectedObjects</c> used in the + description of <c>qlc:table/2</c> has been augmented.</p> + <p> + Own Id: OTP-7238</p> + </item> + <item> + <p><c>tuple_size/1</c> and <c>byte_size/1</c> have been + substituted for <c>size/1</c> in the documentation.</p> + <p> + Own Id: OTP-7244</p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 1.15.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Ets:select/3 in combination with + ets:repair_continuation/2 and ordered_set data tables + could result in function_clause although used as + intended. This is now corrected. Thanks to Paul Mineiro + for finding and isolating the bug!</p> + <p> + Own Id: OTP-7025</p> + </item> + <item> + <p>The compiler warning for the deprecated function + <c>ftp:close/1</c> now mentions the correct replacement + function.</p> + <p>The warning for the removed functions in the + <c>httpd_util</c> module have been changed to say they + have been removed, not merely deprecated. (Thanks to + Fredrik Thulin.)</p> + <p> + Own Id: OTP-7034 Aux Id: seq10825 </p> + </item> + <item> + <p>In <c>(Expr)#r{}</c> (no fields are updated), + <c>Expr</c> is no longer evaluated more than once. There + is also a test that <c>Expr</c> is of the correct record + type. (Thanks to Dominic Williams.)</p> + <p> + Own Id: OTP-7078 Aux Id: OTP-4962 </p> + </item> + <item> + <p>Documentation bugfixes and clarifications.</p> (Thanks + to Joern ([email protected]), Matthias Lang, and Richard + Carlsson.) + <p> + Own Id: OTP-7079</p> + </item> + <item> + <p>Duplicated objects were sometimes not deleted from the + list of answers when a QLC table was traversed using a + match specification. (Thanks to Dmitri Girenko.)</p> + <p> + Own Id: OTP-7114</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>The documentation has been updated so as to reflect + the last updates of the Erlang shell as well as the minor + modifications of the control sequence <c>p</c> of the + <c>io_lib</c> module.</p> <p>Superfluous empty lines have + been removed from code examples and from Erlang shell + examples.</p> + <p> + Own Id: OTP-6944 Aux Id: OTP-6554, OTP-6911 </p> + </item> + <item> + <p><c>tuple_size/1</c> and <c>byte_size/1</c> have been + substituted for <c>size/1</c>.</p> + <p> + Own Id: OTP-7009</p> + </item> + <item> + <p> + It is now possible to hibernate a + gen_server/gen_event/gen_fsm. In gen_server and gen_fsm, + hibernation is triggered by returning the atom + 'hibernate'�instead of a timeout value. In the gen_event + case hibernation is triggered by a event handler + returning a tuple with an extra element containing the + atom 'hibernate'.</p> + <p> + Own Id: OTP-7026 Aux Id: seq10817 </p> + </item> + <item> + <p>Some undocumented debug functionality has been added + to Dets.</p> + <p> + Own Id: OTP-7066</p> + </item> + <item> + <p>The functions <c>digraph_utils:is_tree/1</c>, + <c>digraph_utils:is_arborescence/1</c>, and + <c>digraph_utils:arborescence_root/1</c> are new.</p> + <p> + Own Id: OTP-7081</p> + </item> + <item> + <p> + The compiler could generate suboptimal code for record + updates if the record update code consisted of multiple + source code lines.</p> + <p> + Own Id: OTP-7101</p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 1.15</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Bugs have been fixed in <c>qlc</c>:</p> <list + type="bulleted"> <item>Setting the <c>lookup_fun</c> + option of <c>qlc:table/2</c> to <c>undefined</c> could + cause a crash.</item> <item>If a QLC restricted some + column of a table in such a way that a traversal using a + match specification was possible and the QLC also + compared the key column or some indexed column of the the + table with a column of some other table, <c>qlc</c> + always chose to traverse the table first, never + considering lookup join. This has been changed so that + lookup join is always preferred; if an initial traversal + using the match specification is desired, the query needs + to be rewritten introducing an extra QLC with the + filter(s) restricting the column.</item> <item>When + trying to find candidates for match specifications and + lookup, filters using variables from one generator only + are ignored unless they are placed immediately after the + generator and possibly other filters using variables from + the same generator. In particular, filters joining two + tables should not be placed between the generator and the + filters using the generator only.</item> <item>The + call-back function <c>TraverseFun</c> used for + implementing QLC tables is allowed to return a term other + than a list since STDLIB 1.14 (OTP-5195). However, when + the returned term was a fun <c>qlc</c> often tried to + call the fun instead of returning it.</item> </list> <p>A + few minor optimizations have been implemented as + well.</p> + <p> + Own Id: OTP-6673</p> + </item> + <item> + <p>A bug concerning the use of parameterized modules from + the shell has been fixed.</p> + <p> + Own Id: OTP-6785</p> + </item> + <item> + <p>A bug regarding the size expression of the bit syntax + has been fixed in the <c>erl_eval</c> module.</p> + <p> + Own Id: OTP-6787</p> + </item> + <item> + <p> + The log_mf_h event handler didn't close the index file + when it was done reading it causing a file descriptor + leak.</p> + <p> + Own Id: OTP-6800</p> + </item> + <item> + <p> + Definitions for the <c>filename()</c> and + <c>dirname()</c> types have been added to the + documentation for the <c>filelib</c> module.</p> + <p> + Own Id: OTP-6870</p> + </item> + <item> + <p>file:write_file/3, file:write/2 and file:read/2 could + crash (contrary to documentation) for odd enough file + system problems, e.g write to full file system. This bug + has now been corrected.</p> <p>In this process the file + module has been rewritten to produce better error codes. + Posix error codes now originate from the OS file system + calls or are generated only for very similar causes (for + example 'enomem' is generated if a memory allocation + fails, and 'einval' is generated if the file handle in + Erlang is a file handle but currently invalid).</p> + <p>More Erlang-ish error codes are now generated. For + example <c>{error,badarg}</c> is now returned from + <c>file:close/1</c> if the argument is not of a file + handle type. See file(3).</p> <p>The possibility to write + a single byte using <c>file:write/2</c> instead of a list + or binary of one byte, contradictory to the + documentation, has been removed.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-6967 Aux Id: OTP-6597 OTP-6291 </p> + </item> + <item> + <p>A bug concerning the evaluation of the <c>++/2</c> + operator has been fixed in <c>erl_eval</c>. (Thanks to + Matthew Dempsky.)</p> + <p> + Own Id: OTP-6977</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>The behaviour of the internal functions gen:call/3,4 + has been changed slightly in the rare case that when the + caller was linked to the called server, and the server + crashed during the call; its exit signal was consumed by + the gen:call/3,4 code and converted to an exit exception. + This exit signal is no longer consumed.</p> + <p>To even notice this change, 1) the calling process has + to be linked to the called server.</p> + <p> + 2) the call must not be remote by name that is it must be + local or remote by pid, local by name or global by name.</p> + <p> + 3) the calling process has to have set + <c>process_flag(trap_exit, true)</c>.</p> + <p> + 4) the server has to crash during the call.</p> + <p> + 5) the calling process has to be sensitive to getting + previously consumed <c>{'EXIT',Pid,Reason}</c> messages + in its message queue.</p> + <p>The old behaviour was once the only way for a client + to notice if the server died, but has since + <c>erlang:monitor(process, {Name,Node})</c> was + introduced and used in gen:call been regarded as an + undesired behaviour if not a bug.</p> + <p>The affected user APIs are: + <c>gen_server:call/2,3</c>, + <c>gen_fsm:sync_send_event/2,3</c>, + <c>gen_fsm:sync_send_all_state_event/2,3</c>, + <c>gen_event:_</c>, <c>sys:_</c> and maybe a few others + that hardly will be noticed.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-3954 Aux Id: Seq 4538 </p> + </item> + <item> + <p>When an exception occurs the Erlang shell now displays + the class, the reason, and the stacktrace in a clearer + way (rather than dumping the raw EXIT tuples as before). + <c>proc_lib:format/1</c> displays the exception of crash + reports in the same clearer way.</p> <p>The new shell + command <c>catch_exception</c> and the new application + configuration parameter <c>shell_catch_exception</c> can + be used for catching exceptions that would normally exit + the Erlang shell.</p> + <p> + Own Id: OTP-6554 Aux Id: OTP-6289 </p> + </item> + <item> + <p>The function <c>string:join/2</c> joins strings in a + list with a separator. Example: '<c>string:join(["a", + "b", "c"], ", ") gives "a, b, c"</c>'</p> + <p> + Own Id: OTP-6671</p> + </item> + <item> + <p>The control sequence <c>P</c> of the <c>Format</c> + argument of the functions <c>io:fwrite/2,3</c> and + <c>io_lib:fwrite/2</c> now inserts fewer line breaks when + printing tuples and lists. A soft upper limit of 60 on + the number of non-white characters on a line has been + introduced.</p> + <p> + Own Id: OTP-6708</p> + </item> + <item> + <p> + The new module <c>array</c> provides a fast functional + array implementation.</p> + <p> + Own Id: OTP-6733</p> + </item> + <item> + <p>Functions that have long been deprecated have now been + removed from the following modules: <c>dict</c>, + <c>erl_eval</c>, <c>erl_pp</c>, <c>io</c>, <c>io_lib</c>, + <c>lists</c>, <c>orddict</c>, <c>ordsets</c>, + <c>sets</c>, and <c>string</c>.</p> + <p>The undocumented function <c>lists:zf/3</c> has also + been removed (use a list comprehension or + <c>lists:zf/2</c> instead).</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-6845</p> + </item> + <item> + <p> + Minor documentation corrections for file:pread/2 and + file:pread/3.</p> + <p> + Own Id: OTP-6853</p> + </item> + <item> + <p> + Contract directives for modules in Kernel and STDLIB.</p> + <p> + Own Id: OTP-6895</p> + </item> + <item> + <p>The <c>ets:fixtable/2</c> function, which has been + deprecated for several releases, has been removed.</p> + <p>The <c>ets:info/1</c> function has been reimplemented + as a BIF, which guarantees that information returned is + consistent.</p> + <p>The <c>ets:info/2</c> function now fails with reason + <c>badarg</c> if the second argument is invalid. + (Dialyzer can be used to find buggy code where the second + argument is misspelled.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-6906</p> + </item> + <item> + <p>The Erlang pretty printer <c>erl_pp</c> now inserts + more newlines in order to facilitate line coverage + analysis by <c>Cover</c>. (Thanks to Thomas Arts.)</p> + <p> + Own Id: OTP-6911</p> + </item> + <item> + <p> + The documentation for ets:safe_fixtable/2, ets:foldl/3, + and ets:foldr/3 is now clearer about what will happen if + objects are inserted during table traversals.</p> + <p> + Own Id: OTP-6928 Aux Id: seq10779 </p> + </item> + <item> + <p> + It is now possible to extract files in tar files directly + into binaries. It is also possible to add files to tar + files directly from binaries.</p> + <p> + Own Id: OTP-6943</p> + </item> + <item> + <p>The functions <c>keystore/4</c> and <c>keytake/3</c> + are new in the <c>lists</c> module.</p> + <p> + Own Id: OTP-6953</p> + </item> + <item> + <p>The new <c>qlc</c> option <c>tmpdir_usage</c> can be + used for outputting messages onto the error logger when a + temporary file is about to be created, or to prohibit the + usage of temporary files altogether.</p> + <p> + Own Id: OTP-6964</p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 1.14.5.3</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The allowed syntax for -type() and -spec() was updated.</p> + <p> + Own Id: OTP-6861 Aux Id: OTP-6834 </p> + </item> + </list> + </section> + +</section> + +<section><title>STDLIB 1.14.5.2</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The compiler will for forward compatibility ignore the + -type() and -spec() attributes that will be introduced in + the R12B release.</p> + <p> + Own Id: OTP-6834</p> + </item> + </list> + </section> + +</section> +<section><title>STDLIB 1.14.5.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The log_mf_h event handler didn't close the index file + when it was done reading it causing a file descriptor + leak.</p> + <p> + Own Id: OTP-6800</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The dict:size/1 and orddict:size/1 functions have been + documented.</p> + <p> + Own Id: OTP-6818</p> + </item> + </list> + </section> + +</section> + + <section> + <title>STDLIB 1.14.5</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Bugs have been fixed in Dets concerning comparison + (==) and matching (=:=).</p> + <p>The STDLIB manual pages + have been updated as to more carefully state when terms + are matched and when they are compared.</p> + <p>Own Id: OTP-4738 Aux Id: OTP-4685 </p> + </item> + <item> + <p>The shell has been updated to fix the following flaws: + Shell process exit left you with an unresponsive initial + shell if not using oldshell. Starting a restricted shell + with a nonexisting callback module resulted in a shell + where no commands could be used, not even init:stop/0. + Fun's could not be used as parameters to local shell + functions (in shell_default or user_default) when + restricted_shell was active.</p> + <p>Own Id: OTP-6537</p> + </item> + <item> + <p>A bug in QLC's parse transform has been fixed.</p> + <p>Own Id: OTP-6590</p> + </item> + <item> + <p>A bug concerning <c>lists:sort/1</c> and + <c>lists:keysort/2</c> and a mix of floating point + numbers and integers has been fixed.</p> + <p>Own Id: OTP-6606</p> + </item> + <item> + <p>When calling <c>erlang:garbage_collect/0</c> in the + Erlang shell not only the evaluator process (the one + returned by calling <c>self()</c> in the Erlang shell) is + garbage collected, but also the process holding the + history list.</p> + <p>Own Id: OTP-6659</p> + </item> + <item> + <p>Functions of the <c>beam_lib</c> module that used to + catch exceptions and return a tuple + <c>{'EXIT',Reason}</c> now exit with the reason + <c>Reason</c>.</p> + <p>Own Id: OTP-6711</p> + </item> + <item> + <p>The <c>erl_eval</c> module now calls the non-local + function handler whenever an operator is evaluated + (exceptions are <c>andalso</c>, <c>orelse</c>, and + <c>catch</c>). The non-local function handler is now also + called when the function or operator occurs in a guard + test (such calls used to be ignored).</p> + <p>These changes affect the Erlang shell when running in + restricted mode: the callback function + <c>non_local_allowed/3</c> is now called for operators + such as <c>'!'/2</c>. This means that + <c>non_local_allowed/3</c> may need to be changed as to + let operators through. Note that <c>erlang:'!'/2</c> as + well as <c>erlang:send/2,3</c> have to be restricted in + order to stop message passing in the shell.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-6714 Aux Id: seq10374 </p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The new compiler option <c>warn_obsolete_guard</c> can + be used for turning on warnings for calls to old type + testing BIFs.</p> + <p>Own Id: OTP-6585</p> + </item> + <item> + <p>For scripts written using <c>escript</c>, there is a new + function <c>escript:script_name/0</c>, which can be used + to retrieve the pathame of the script. The documentation + has been clarified regarding pre-defined macros such as + ?MODULE and the module name.</p> + <p>Own Id: OTP-6593</p> + </item> + <item> + <p>Minor Makefile changes.</p> + <p>Own Id: OTP-6689 Aux Id: OTP-6742 </p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.14.4</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The MD5 calculation of a BEAM file done by + <c>code:module_md5/1</c>, <c>beam_lib:md5/1</c>, and by + the compiler for the default value of the <c>vsn</c> + attribute have all been changed so that its result will + be the same on all platforms; modules containing funs + could get different MD5s on different platforms.</p> + <p>Own Id: OTP-6459</p> + </item> + <item> + <p>When sorting terms using the <c>file_sorter</c> module + (the option <c>Format</c> set to <c>term</c>), file + errors were not always properly handled. This bug has + been fixed.</p> + <p>The directory supplied with the + <c>tmpdir</c> option is no longer checked unless it is + actually used. The error reason <c>not_a_directory</c> + can no longer be returned; instead a <c>file_error</c> + tuple is returned</p> + <p>Own Id: OTP-6526</p> + </item> + <item> + <p>Bugs regarding <c>try</c>/<c>catch</c> have been fixed + in the <c>erl_eval</c> module.</p> + <p>Own Id: OTP-6539</p> + </item> + <item> + <p>When sorting the operands of a join operation, QLC + called <c>file:open/3</c> with bad arguments. This bug + has been fixed.</p> + <p>Own Id: OTP-6562 Aux Id: seq10606 </p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The functions <c>beam_lib:cmp/1</c> and + <c>beam_lib:strip/1</c> (and similar functions) have been + updated to handle optional chunks (such as "FunT") in + more general way in order to be future compatible.</p> + <p>The function <c>beam_lib:chunks/3</c> has been + added.</p> + <p>The function <c>beam_lib:md5/1</c> has been added.</p> + <p>Own Id: OTP-6443</p> + </item> + <item> + <p>Added base64 as a module to stdlib, encoding and decoding</p> + <p>Own Id: OTP-6470</p> + </item> + <item> + <p>Added the functions to_upper/1 and to_lower/1 to the + string module. These provide case conversion for ISO/IEC + 8859-1 characters (Latin1) and strings.</p> + <p>Own Id: OTP-6472</p> + </item> + <item> + <p>The callback function <c>non_local_allowed/3</c> used + by the restricted shell can now return the value + <c>{{restricted,NewFuncSpec,NewArgList},NewState}</c> + which can be used for letting the shell call some other + function than the one specified.</p> + <p>Own Id: OTP-6497 Aux Id: seq10555 </p> + </item> + <item> + <p>There is a new <c>escript</c> program that can be used + for writing scripts in Erlang. Erlang scripts don't need + to be compiled and any arguments can be passed to them + without risk that they are interpreted by the Erlang + system.</p> + <p>Own Id: OTP-6505</p> + </item> + <item> + <p>The <c>Format</c> argument of the functions + <c>io:fwrite/2,3</c> and <c>io_lib:fwrite/2</c> is now + allowed to be a binary.</p> + <p>Own Id: OTP-6517</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.14.3.1</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The control sequences <c>p</c> and <c>P</c> of the + <c>Format</c> argument of the functions + <c>io:fwrite/2,3</c> and <c>io_lib:fwrite/2</c> could + cause a <c>badarg</c> failure when applied to binaries. + This bug was introduced in STDLIB 1.14.3. (Thanks to + Denis Bilenko.)</p> + <p>Own Id: OTP-6495</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Added the option {cwd, Dir} to make zip-archives with + relative pathnames without having to do (a global) + file:set_cwd.</p> + <p>Own Id: OTP-6491 Aux Id: seq10551 </p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.14.3</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The <c>spawn_opt/2,3,4,5</c> option <c>monitor</c> -- + introduced in Kernel 2.11.2 -- is currently not possible + to use when starting a process using <c>proc_lib</c>, + that is, also when starting a gen_server, gen_fsm etc. </p> + <p>This limitation has now been properly documented and the + behavior of the <c>gen_fsm</c>, <c>gen_server</c>, and + <c>proc_lib</c><c>start</c> and <c>start_link</c> + functions when providing this option has been changed + from hanging indefinitely to failing with reason + <c>badarg</c>.</p> + <p>(Thanks to Fredrik Linder)</p> + <p>Own Id: OTP-6345</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The control sequence <c>P</c> of the <c>Format</c> + argument of the functions <c>io:fwrite/2,3</c> and + <c>io_lib:fwrite/2</c> now replaces the tail of binary + strings with <c>...</c> when the maximum depth has been + reached. For instance, <c><![CDATA[io:fwrite("~P", [<<"a binary string">>, 3]).]]></c> prints <c><![CDATA[<<"a binary"...>>]]></c>.</p> + <p>The indentation takes more care not to exceed the + right margin, if possible.</p> + <p>If the maximum depth is + reached while printing a tuple, <c>,...</c> is printed + instead of <c>|...</c> (this change applies to the + control sequence <c>W</c> as well).</p> + <p>Own Id: OTP-6354</p> + </item> + <item> + <p>The Erlang shell command <c>h/0</c> that prints the + history list now avoids printing (huge) terms referred to + by <c>v/1</c> but instead just prints the call to + <c>v/1</c>.</p> + <p>Own Id: OTP-6390</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.14.2.2</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The functions <c>dets:select/1,3</c>, + <c>dets:match/1,3</c>, and <c>dets:match_object/1,3</c> + have been changed as to never return + <c>{[],Continuation}</c>. This change affects the + corresponding functions in Mnesia.</p> + <p>Bugs have been + fixed in QLC: <c>qlc:info()</c> could crash if the + <c>tmpdir</c> option did not designate a valid directory; + the results of looking up keys are kept in RAM, which + should improve performance.</p> + <p>Own Id: OTP-6359</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.14.2.1</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>A bug in <c>erl_pp:exprs()</c> has been fixed.</p> + <p>Own Id: OTP-6321 Aux Id: seq10497 </p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.14.2</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The control sequences <c>p</c> and <c>P</c> of the + <c>Format</c> argument of the functions + <c>io:format/2,3</c> and <c>io_lib:format/2</c> did not + handle binaries very well. This bug, introduced in + stdlib-1.14, has been fixed.</p> + <p>Own Id: OTP-6230</p> + </item> + <item> + <p><c>filelib:wildcard(Wc, PathWithRedundantSlashes)</c>, + where <c>PathWithRedundantSlashes</c> is a directory path + containing redundant slashes, such as <c>/tmp/</c> or + <c>//tmp</c>, could return incorrect results. (Thanks to + Martin Bjorklund.)</p> + <p>Own Id: OTP-6271</p> + </item> + <item> + <p>The Erlang code preprocessor crashed if the predefined + macros ?MODULE or ?MODULE_STRING were used before the + module declaration. This bug has been fixed.</p> + <p>Own Id: OTP-6277</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Support for faster join of two tables has been added + to the <c>qlc</c> module. There are two kinds of fast + joins: lookup join that uses existing indices, and merge + join that takes two sorted inputs. There is a new + <c>join</c> option that can be used to force QLC to use a + particular kind of join in some QLC expression.</p> + <p>Several other changes have also been included:</p> + <p></p> + <list type="bulleted"> + <item> + <p>The new <c>tmpdir</c> option of <c>cursor/2</c>, + <c>eval/2</c>, <c>fold/4</c>, and <c>info/2</c> can be + used to set the directory that join uses for temporary + files. The option also overrides the <c>tmpdir</c> option + of <c>keysort/3</c> and <c>sort/2</c>.</p> + </item> + <item> + <p>The new <c>lookup</c> option can be used to + assert that constants are looked up when evaluating some + QLC expression.</p> + </item> + <item> + <p>The <c>cache</c> and <c>cache_all</c> options + accept new tags: <c>ets</c>, <c>list</c>, and <c>no</c>. + The tag <c>list</c> caches answers in a list using a + temporary file if the answers cannot be held in RAM. + Combining <c>{cache,list}</c> and <c>{unique, true}</c> + is equivalent to calling <c>sort/2</c> with the option + <c>unique</c> set to <c>true</c>. The old tags + <c>true</c> (equivalent to <c>ets</c>) and <c>false</c> + (equivalent to <c>no</c>) are recognized for backward + compatibility.</p> + </item> + <item> + <p>The new option <c>max_list_size</c> can be used + to set the limit where merge join starts to use temporary + files for large equivalence classes and when answers + cached in lists are put on temporary files.</p> + </item> + <item> + <p>There is a new callback <c>is_sorted_key</c> to + be supplied as an option to <c>table/2</c>.</p> + </item> + <item> + <p>QLC analyzes each and every QLC expression when + trying to find constants for the lookup function. + Hitherto only QLC expressions with exactly one generator + were analyzed.</p> + <p>Note that only filters with guard + syntax placed immediately after the generator are + analyzed. The restriction to guard filters is an + incompatible change. See <c>qlc(3)</c> for further + details.</p> + </item> + <item> + <p>In a similar way several match specifications + for traversal of QLC tables can be utilized for different + generators of one single QLC expression.</p> + </item> + <item> + <p>A bug has been fixed: when caching answers to a + sufficiently complex query it could happen that some + answers were not returned.</p> + </item> + </list> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-6038</p> + </item> + <item> + <p>The Erlang pretty printer (<c>erl_pp</c>) is now much + faster when the code is deeply nested. A few minor bugs + have been fixed as well.</p> + <p>Own Id: OTP-6227 Aux Id: OTP-5924 </p> + </item> + <item> + <p>The Erlang shell now tries to garbage collect large + binaries. Under certain circumstances such binaries could + otherwise linger on for an indefinite amount of time.</p> + <p>Own Id: OTP-6239</p> + </item> + <item> + <p>To help Dialyzer find more bugs, many functions in the + Kernel and STDLIB applications now only accept arguments + of the type that is documented.</p> + <p>For instance, the functions <c>lists:prefix/2</c> and + <c>lists:suffix/2</c> are documented to only accept lists + as their arguments, but they actually accepted anything + and returned <c>false</c>. That has been changed so that + the functions cause an exception if one or both arguments + are not lists.</p> + <p>Also, the <c>string:strip/3</c> function is documented + to take a character argument that is a character to strip + from one or both ends of the string. Given a list instead + of a character, it used to do nothing, but will now cause + an exception.</p> + <p>Dialyzer will find most cases where those functions + are passed arguments of the wrong type.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-6295</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.14.1</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The functions <c>c:y/1,2</c> which call + <c>yecc:file/1,2</c> are now listed by + <c>c:help/0</c>.</p> + <p>Documentation of <c>c:y/1,2</c> has been added to + <c>c(3)</c>.</p> + <p>The fact that the control sequence character <c>s</c> + recognizes binaries and deep character lists has been + documented in <c>io(3)</c>. This feature was added in + R11B-0 (OTP-5403).</p> + <p>Own Id: OTP-6140</p> + </item> + <item> + <p>The shell command rr() sometimes failed to read record + definitions from file(s). This problem has been fixed.</p> + <p>Own Id: OTP-6166 Aux Id: OTP-5878 </p> + </item> + <item> + <p>The nonlocal function handler in <c>erl_eval</c>, which + is used for implementing the restricted mode of the + Erlang shell, did not handle calls to + <c>erlang:apply/3</c> correctly. This bug has been fixed.</p> + <p>Own Id: OTP-6169 Aux Id: seq10374 </p> + </item> + <item> + <p>ets:rename/1 could deadlock, or crash the SMP emulator + when the table wasn't a named table.</p> + <p>ets:next/2, and ets:prev/2 could return erroneous results + on the SMP emulator.</p> + <p>Own Id: OTP-6198 Aux Id: seq10392, seq10415 </p> + </item> + <item> + <p>When closing a Dets table the space management data was + sometimes saved in such a way that opening the table + could not be done without repairing the file. This bug + has been fixed.</p> + <p>Own Id: OTP-6206</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.14</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>A bugfix in QLC: two of the call-back functions used + for implementing QLC tables, <c>TraverseFun</c> and + <c>LookupFun</c>, are now allowed to return a term other + than a list. Such a term is immediately returned as the + results of the current query, and is useful mostly for + returning error tuples.</p> + <p>Several other minor bugs have been also been fixed.</p> + <p>Own Id: OTP-5195</p> + </item> + <item> + <p>The STDLIB modules <c>error_logger_file_h</c> and + <c>error_logger_tty_h</c> now read the environment + variable <c>utc_log</c> from the SASL application.</p> + <p>Own Id: OTP-5535</p> + </item> + <item> + <p><c>ets:info/1</c> has been corrected to behave according + to the documentation and return a list of tuples, not a + tuple with tuples.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-5639</p> + </item> + <item> + <p>Referencing a so far undeclared record from the default + value of some record declaration is from now on considered + an error by the linter. It is also an error if the default + value of a record declaration uses or binds a variable.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-5878</p> + </item> + <item> + <p>When a file <c>.hrl</c> file is included using + <c>-include_lib</c>, the include path is temporarily + updated to include the directory the <c>.hrl</c> file was + found in, which will allow that <c>.hrl</c> file to itself + include files from the same directory as itself using + <c>-include</c>. (Thanks to Richard Carlsson.)</p> + <p>Own Id: OTP-5944</p> + </item> + <item> + <p>Corrected <c>filelib:ensure_dir/1</c> which sometimes + returned <c>true</c> and sometimes <c>ok</c> to always + return <c>ok</c> when successful. This goes against the + documentation which said <c>true</c>, but <c>ok</c> was + judged to be a more logical return value.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-5960 Aux Id: seq10240 </p> + </item> + <item> + <p>The shell now handles records better when used in calls + on the form <c>{Module, Function}(ArgList)</c>.</p> + <p>Own Id: OTP-5990 Aux Id: OTP-5876 </p> + </item> + <item> + <p>The functions <c>lists:ukeysort/2</c> and + <c>lists:ukeymerge/3</c> have been changed in such a way + that two tuples are considered equal if their keys + match.</p> + <p>For the sake of consistency, <c>lists:usort/2</c> and + <c>lists:umerge/3</c> have been modified too: two elements + are considered equal if they compare equal.</p> + <p>The <c>file_sorter</c> module has been modified in a + similar way: the <c>unique</c> option now applies to the + key (<c>keysort()</c> and <c>keymerge()</c>) and the + ordering function (the option <c>{order, Order} </c>).</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-6019</p> + </item> + <item> + <p>Correction in documentation for + <c>ets:update_counter/3</c>; failure with <c>badarg</c> + also if the counter to be updated is the key.</p> + <p>Own Id: OTP-6072</p> + </item> + <item> + <p>When sorting terms using the <c>file_sorter</c> module + and an ordering fun, the sort was not always stable. This + bug has been fixed.</p> + <p>Own Id: OTP-6088</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Improvements of the linter:</p> + <list type="bulleted"> + <item> + <p>The <c>compile</c> attribute is recognized after + function definitions.</p> + </item> + <item> + <p>The new compiler option + <c>nowarn_deprecated_function</c> can be used for + turning off warnings for calls to deprecated functions.</p> + </item> + <item> + <p>The new compiler option + <c>{nowarn_unused_function,[{Name,Arity}]}</c> turns off + warnings for unused local functions for the mentioned + functions. The new options + <c>{nowarn_deprecated_function,[{Module,Name,Arity}]}</c> + and <c>{nowarn_bif_clash,[{Name,Arity}]}</c> work + similarly.</p> + </item> + </list> + <p>The Erlang code preprocessor <c>epp</c> now recognizes + the <c>file</c> attribute. This attribute is meant to be + used by tools such as Yecc that generate source code + files.</p> + <p>Own Id: OTP-5362</p> + </item> + <item> + <p>The formatting option <c>~s</c> of <c>io:fwrite</c> and + <c>io_lib:fwrite</c> has been extended to handle arguments + that are binaries or I/O lists.</p> + <p>Own Id: OTP-5403</p> + </item> + <item> + <p>The control sequences <c>p</c> and <c>P</c> of the + <c>Format</c> argument of the functions + <c>io:format/2,3</c> and <c>io_lib:format/2</c> have been + changed as to display the contents of binaries containing + printable characters as strings.</p> + <p>Own Id: OTP-5485</p> + </item> + <item> + <p>The linter emits warnings for functions exported more + than once in <c>export</c> attributes.</p> + <p>Own Id: OTP-5494</p> + </item> + <item> + <p>A manual for STDLIB has been added, <c>stdlib(6)</c>. It + mentions the configuration parameters for the Erlang + shell.</p> + <p>Own Id: OTP-5530</p> + </item> + <item> + <p>Added the <c>zip</c> module with functions for reading + and creating zip archives. See <c>zip(3)</c>.</p> + <p>Own Id: OTP-5786</p> + </item> + <item> + <p>Simple-one-for-one supervisors now store the pids of + child processes using <c>dict</c> instead of a list. This + significantly improves performance when there are many + dynamic supervised child processes. (Thanks to Mickaël + Rémond et al.)</p> + <p>Own Id: OTP-5898</p> + </item> + <item> + <p>When given the new option '<c>strict_record_tests</c>', + the compiler will generate code that verifies the record + type for '<c>R#record.field</c>' operations in guards. Code + that verifies record types in bodies has already been + generated since R10B, but in this release there will be a + '<c>{badrecord,RecordTag}</c>' instead of a + '<c>badmatch</c>' if the record verification test fails. + See the documentation for the <c>compile</c> module for + more information.</p> + <p>The Erlang shell always applies strict record tests.</p> + <p>Own Id: OTP-5915 Aux Id: OTP-5714 </p> + </item> + <item> + <p>The Erlang pretty printer (<c>erl_pp</c>) now tries to + insert line breaks at appropriate places.</p> + <p>Own Id: OTP-5924</p> + </item> + <item> + <p>The <c>public</c> option has been removed from + <c>digraph:new/1</c>. The reason is that several + functions in the <c>digraph</c> module are implemented + using multiple ETS accesses, which is not thread safe. + (Thanks to Ulf Wiger.)</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-5985</p> + </item> + <item> + <p>The function <c>lists:keyreplace/4</c> checks that the + fourth argument (<c>NewTuple</c>) is a tuple.</p> + <p>Own Id: OTP-6023</p> + </item> + <item> + <p>Added an example of how to reconstruct source code from + debug info (abstract code) to <c>beam_lib(3)</c>. (Thanks + to Mats Cronqvist who wrote the example.)</p> + <p>Own Id: OTP-6073</p> + </item> + <item> + <p>The new compiler option <c>warn_unused_record</c> is used + for finding unused locally defined record types.</p> + <p>Own Id: OTP-6105</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.12</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p><c>shell_default:xm/1</c> has been added. It calls + <c>xref:m/1</c>.</p> + <p>Own Id: OTP-5405 Aux Id: OTP-4101 </p> + </item> + <item> + <p>Warnings are output whenever so far undeclared records are + referenced from some default value of a record + declaration. In STDLIB 1.14 (R11B) such forward references + will cause a compilation error.</p> + <p>Own Id: OTP-5878</p> + </item> + <item> + <p>The linter's check of the <c>deprecated</c> attribute did + not take the compile option <c>export_all</c> into + account. This bug has been fixed.</p> + <p>Own Id: OTP-5917</p> + </item> + <item> + <p>The Erlang pretty printer did not handle <c>try/catch</c> + correctly. This bug has been fixed.</p> + <p>Own Id: OTP-5926</p> + </item> + <item> + <p>Corrected documentation for <c>lists:nthtail/3</c>.</p> + <p>Added documentation for <c>lists:keymap/3</c>.</p> + <p>Tried to clarify some other type declarations and + function descriptions in <c>lists(3)</c>.</p> + <p>Corrected documentation for <c>timer:now_diff/2</c>.</p> + <p>Fixed broken links in <c>gen_fsm(3)</c>, + <c>gen_server(3)</c>, <c>io_lib(3)</c> and <c>lib(3)</c>.</p> + <p>Own Id: OTP-5931</p> + </item> + <item> + <p>Type checks have been added to functions in + <c>lists.erl</c>.</p> + <p>Own Id: OTP-5939</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The new STDLIB module <c>erl_expand_records</c> expands + records in abstract code. It is used by the Erlang shell, + which means that Compiler is no longer used by the shell.</p> + <p>Own Id: OTP-5876 Aux Id: OTP-5435 </p> + </item> + <item> + <p>The compiler will now warn that the + <c>megaco:format_versions/1</c> function is deprecated.</p> + <p>Own Id: OTP-5976</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.11</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>When calling <c>gen_server:enter_loop</c> with a + registered server name, it was only checked that the + registered name existed, not that it actually was the + name of the calling process.</p> + <p>Own Id: OTP-5854</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>More detail on <c>beam_lib:version/1</c> in + documentation.</p> + <p>Own Id: OTP-5789</p> + </item> + <item> + <p>The new function <c>io:read/3</c> works like + <c>io:read/1,2</c> but takes a third argument, + <c>StartLine</c>.</p> + <p>Own Id: OTP-5813</p> + </item> + <item> + <p>The new function <c>gen_fsm:enter_loop/4,5,6</c>, similar + to <c>gen_server:enter_loop/3,4,5</c>, has been added.</p> + <p>Own Id: OTP-5846 Aux Id: seq10163 </p> + </item> + <item> + <p>The function <c>c:i/1</c> is now exported.</p> + <p>Own Id: OTP-5848 Aux Id: seq10164 </p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.10</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>A couple of type errors have been fixed in <c>sofs</c>.</p> + <p>Own Id: OTP-5739</p> + </item> + <item> + <p>The pre-processor used to complain that the macro + definition '<c>-define(S(S), ??S).</c>' was circular, + which it isn't. (Thanks to Richard Carlsson.)</p> + <p>Own Id: OTP-5777</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.9</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The linter, QLC and the module <c>erl_pp</c> did not + handle the new '<c>fun M:F/A</c>' construct in all + situations. This problem has been fixed.</p> + <p>Own Id: OTP-5644</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The manual pages for most of the Kernel and some of + the STDLIB modules have been updated, in particular + regarding type definitions.</p> + <p>The documentation of the return value for + <c>erts:info/1</c> has been corrected.</p> + <p>The documentation for <c>erlang:statistics/1</c> now + lists all possible arguments.</p> + <p>Own Id: OTP-5360</p> + </item> + <item> + <p>Replaced some tuple funs with the new <c>fun M:F/A</c> + construct.</p> + <p>The high-order functions in the lists module no longer + accept bad funs under any circumstances. + '<c>lists:map(bad_fun, [])</c>' used to return + '<c>[]</c>' but now causes an exception.</p> + <p>Unused, broken compatibility code in the <c>ets</c> + module was removed. (Thanks to Dialyzer.)</p> + <p>Eliminated 5 discrepancies found by Dialyzer in the + Appmon application.</p> + <p>Own Id: OTP-5633</p> + </item> + <item> + <p>The <c>c:i/0</c> function will now run in a paged mode if + there are more than 100 processes in the system. (Thanks + to Ulf Wiger.)</p> + <p><c>erlang:system_info(process_count)</c> has been + optimized and does now return exactly the same value as + <c>length(processes())</c>. Previously + <c>erlang:system_info(process_count)</c> did not include + exiting processes which are included in + <c>length(processes())</c>.</p> + <p>The <c>+P</c> flag for <c>erl</c>, which sets the maximum + number of processes allowed to exist at the same, no longer + accepts values higher than 134217727. (You will still + probably run out of memory before you'll be able to reach + that limit.)</p> + <p>Own Id: OTP-5645 Aux Id: seq9984 </p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.8</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Very minor corrections in <c>beam_lib</c> and its + documentation.</p> + <p>Own Id: OTP-5589</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The <c>erlang:port_info/1</c> BIF is now documented. + Minor corrections of the documentation for + <c>erlang:port_info/2</c>.</p> + <p>Added a note to the documentation of the <c>math</c> + module that all functions are not available on all + platforms.</p> + <p>Added more information about the '<c>+c</c>' option in + the <c>erl</c> man page in the ERTS documentation.</p> + <p>Own Id: OTP-5555</p> + </item> + <item> + <p>The new <c>fun M:F/A</c> construct creates a fun that + refers to the latest version of <c>M:F/A</c>. This syntax is + meant to replace tuple funs <c>{M,F}</c> which have many + problems.</p> + <p>The new type test <c>is_function(Fun,A)</c> (which may be + used in guards) test whether <c>Fun</c> is a fun that can be + applied with <c>A</c> arguments. (Currently, <c>Fun</c> can + also be a tuple fun.)</p> + <p>Own Id: OTP-5584</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.7</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p><c>filelib:wildcard/2</c> was broken (it ignored its + second argument).</p> + <p>Also, <c>filelib:wildcard("Filename")</c> (where the + argument does not contain any meta-characters) would + always return <c>["Filename"]</c>. Corrected so that an + empty list will be returned if <c>"Filename"</c> does not + actually exist. (Same correction in + <c>filelib:wildcard/2</c>.) (This change is a slight + incompatibility.)</p> + <p><c>filelib:wildcard/1,2</c> will generate a different + exception when given bad patterns such as <c>"{a,"</c>. The + exception used to be caused by + '<c>exit(missing_delimiter)</c>' but is now + '<c>erlang:error({badpattern,missing_delimiter})</c>'.</p> + <p>Own Id: OTP-5523 Aux Id: seq9824 </p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Further improvements of encrypted debug info: New option + <c>encrypt_debug_info</c> for compiler.</p> + <p>Own Id: OTP-5541 Aux Id: seq9837 </p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.6</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>When opening a Dets table read only an attempt was + sometimes made to re-hash the table resulting in an error + message. This problem has been fixed.</p> + <p>Own Id: OTP-5487 Aux Id: OTP-4989 </p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>It is now possible to encrypt the debug information in + Beam files, to help keep the source code secret. See the + documentation for <c>compile</c> on how to provide the key + for encrypting, and the documentation for <c>beam_lib</c> + on how to provide the key for decryption so that tools such + as the Debugger, <c>xref</c>, or <c>cover</c> can be used.</p> + <p>The <c>beam_lib:chunks/2</c> functions now accepts an + additional chunk type <c>compile_info</c> to retrieve + the compilation information directly as a term. (Thanks + to Tobias Lindahl.)</p> + <p>Own Id: OTP-5460 Aux Id: seq9787 </p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.5</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Closing a Dets table kept in RAM would cause a crash if + the file could not be written. This problem has been + fixed by returning an error tuple.</p> + <p>Own Id: OTP-5402</p> + </item> + <item> + <p><c>erl_pp</c> now correctly pretty-prints <c>fun F/A</c>.</p> + <p>Own Id: OTP-5412</p> + </item> + <item> + <p>The Erlang shell failed if the compiler was not in the + code path. This problem has been fixed, but in order to + evaluate records the compiler is still needed.</p> + <p>Own Id: OTP-5435</p> + </item> + <item> + <p>Corrected the example in the documentation for + <c>ets:match/2</c>. Also clarified that + <c>ets:update_counter/3</c> updates the counter atomically. + (Thanks to Anders Svensson.)</p> + <p>Own Id: OTP-5452 Aux Id: seq9770, seq9789 </p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The possibility to start the Erlang shell in parallel + with the rest of the system was reintroduced for + backwards compatibility in STDLIB 1.13.1. The flag to be + used for this is now called <c>async_shell_start</c> and has + been documented. New shells started from the JCL menu are + not synchronized with <c>init</c> anymore. This makes it + possible to start a new shell (e.g. for debugging purposes) + even if the initial shell has not come up.</p> + <p>Own Id: OTP-5406 Aux Id: OTP-5218 </p> + </item> + <item> + <p>The compiler will now produce warnings when using the + deprecated functions in the <c>snmp</c> module.</p> + <p>Own Id: OTP-5425</p> + </item> + <item> + <p>The function <c>c:zi/0</c> has been removed. Use + <c>c:i/0</c> instead.</p> + <p>Own Id: OTP-5432</p> + </item> + <item> + <p>Corrected two minor bugs found by the Dialyzer: + Calling a parameterized module from a restricted shell + (i.e. if <c>shell:start_restricted/1</c> has been used) + would crash the shell evaluator. A debug printout in + <c>gen_fsm</c> had a clause that would never match; causing + less information to be printed.</p> + <p>And a somewhat more serious one also found by + Dialyzer: <c>rpc:yield/1</c> would crash unless the call + started by <c>rpc:async_call/4</c> had already finished; + <c>rpc:nb_yield(Key,infinity)</c> would also crash.</p> + <p>Cleaned up and removed redundant code found by + Dialyzer in <c>erlang:dmonitor_p/2</c>.</p> + <p>Own Id: OTP-5462</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.4</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Bugs in the Erlang shell have been fixed.</p> + <p>Own Id: OTP-5327</p> + </item> + <item> + <p>Some dead code reported by Dialyzer was eliminated.</p> + <p>A bug in <c>dbg</c> when tracing to wrap trace files has + been corrected. It failed to delete any already existing + wrap trace files with the same names when starting a new + wrap trace.</p> + <p>Own Id: OTP-5329</p> + </item> + <item> + <p>The linter could output invalid warnings about bit + patterns in record initializations. This problem has been + fixed.</p> + <p>Own Id: OTP-5338</p> + </item> + <item> + <p><c>ordsets:is_set(NoList)</c>, where <c>NoList</c> is any + term except a list, would crash. For consistency with + <c>sets:is_set/1</c> and <c>gb_sets:is_set/1</c>, it now + returns <c>false</c>.</p> + <p>Own Id: OTP-5341</p> + </item> + <item> + <p>A BIF <c>erlang:raise/3</c> has been added. See the manual + for details. It is intended for internal system programming + only, advanced error handling.</p> + <p>Own Id: OTP-5376 Aux Id: OTP-5257 </p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The <c>deprecated</c> attribute is now checked by the + linter. See <c>xref(3)</c> for a description of the + <c>deprecated</c> attribute.</p> + <p>Own Id: OTP-5276</p> + </item> + <item> + <p>The restricted shell will now indicate if the return + value from a user predicate is on an incorrect form.</p> + <p>Own Id: OTP-5335</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.3</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>Bugs concerning unused and shadowed variables have been + fixed in the linter.</p> + <p>Own Id: OTP-5091</p> + </item> + <item> + <p>A bug in the evaluator that caused the shell to choke on + bit syntax expressions has been fixed.</p> + <p>Own Id: OTP-5237</p> + </item> + <item> + <p><c>io:format/2</c> et.al no longer crashes for some + combinations of precision and value for format character + "g". Previously it crashed if the precision P was 4 or lower + and the absolute value of the float to print was lower + than 10^4 but 10^(P-1) or higher. Now it will not crash + depending on the value of the float.</p> + <p>Own Id: OTP-5263</p> + </item> + <item> + <p>Bugs in the handling of the bit syntax have been fixed in + the Erlang shell.</p> + <p>Own Id: OTP-5269</p> + </item> + <item> + <p><c>gb_sets:del_element/2</c> was changed to do the + same as <c>gb_sets:delete_any/2</c> which was the + original intention, not as <c>gb_sets:delete/2</c>. Code + that relies on <c>gb_sets:del_element/2</c> causing an + error if the element does not exist must be changed to + call <c>gb_sets:delete/2</c> instead.</p> + <p>The documentation was also updated to explicitly + document functions that were only referred to as + 'aliases' of a documented function. Also, a list of all + functions common to the <c>gb_sets</c>, <c>sets</c>, and + <c>ordsets</c> was added.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-5277</p> + </item> + <item> + <p>Debug messages have been removed from the QLC module.</p> + <p>Own Id: OTP-5283</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The size of continuations returned from + <c>dets:match/1,3</c>, <c>dets:match_object/1,3</c>, and + <c>dets:select/1,3</c> has been reduced. This affects the + amount of data Mnesia sends between nodes while + evaluating QLC queries.</p> + <p>Own Id: OTP-5232</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.2</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The <c>-rsh</c> switch for starting a remote shell + (introduced with OTP-5210) clashed with an already existing + switch used by <c>slave</c>. Therefore the switch for + the remote shell is now instead named <c>-remsh</c>.</p> + <p>Own Id: OTP-5248 Aux Id: OTP-5210 </p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.13.1</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The Pman 'trace shell' functionality was broken as has + now been fixed. Furthermore, Pman could not correctly + find the pid of the active shell if more than one shell + process was running on the node. This has also been + corrected.</p> + <p>Own Id: OTP-5191</p> + </item> + <item> + <p>When the undocumented feature "parameterized modules" was + used, the ?MODULE macro did not work correctly.</p> + <p>Own Id: OTP-5224</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>You can now start Erlang with the <c>-rsh</c> flag which + gives you a remote initial shell instead of a local one. + Example:</p> + <pre> + erl -sname this_node -rsh other_node@other_host + </pre> + <p>Own Id: OTP-5210</p> + </item> + <item> + <p>The man page for the <c>lists</c> module has been updated + with description of the new <c>zip</c>, <c>unzip</c>, + and <c>partition/2</c> functions.</p> + <p>Own Id: OTP-5213</p> + </item> + <item> + <p>The top level group leader used to be listed as job #1 in + the job list in JCL mode. Since there is no shell + associated with this process that can be connected to, it + will no longer be listed.</p> + <p>Own Id: OTP-5214</p> + </item> + <item> + <p>The possibility to start the Erlang shell in parallel + with the rest of the system has been reintroduced for + backwards compatibility. Note that this old behaviour is + error prone and should not be used unless for some reason + necessary.</p> + <p>Own Id: OTP-5218 Aux Id: seq9534 </p> + </item> + <item> + <p>The <c>shell</c> commands <c>rr/1,2,3</c> now accepts + wildcards when reading record definitions from BEAM + files.</p> + <p>Own Id: OTP-5226</p> + </item> + </list> + </section> + </section> +</chapter> + diff --git a/lib/stdlib/doc/src/notes_history.xml b/lib/stdlib/doc/src/notes_history.xml new file mode 100644 index 0000000000..85997f1717 --- /dev/null +++ b/lib/stdlib/doc/src/notes_history.xml @@ -0,0 +1,395 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2006</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>STDLIB Release Notes</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + + <section> + <title>STDLIB 1.13</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>For the bit syntax, when matching with a size field that + is bound during the same matching, a warning for unused + variable was emitted. This bug has been fixed.</p> + <p>Own Id: OTP-4858</p> + </item> + <item> + <p>When parsing a badly formed file <c>epp</c> hangs. This + problem has been fixed.</p> + <p>Own Id: OTP-4871 Aux Id: OTP-4870 </p> + </item> + <item> + <p>Bugs concerning guards have been fixed in the Erlang + interpreter.</p> + <p>Own Id: OTP-4885</p> + </item> + <item> + <p>The linter now checks the record name when calling the + function <c>erlang:is_record/2</c>.</p> + <p>Own Id: OTP-4886</p> + </item> + <item> + <p>Guards of mach specifications are corrected to resemble + the semantics of guards in real code more closely. The + implementation now corresponds to the documentation in + ERTS User's Guide. The following things are corrected:</p> + <list type="bulleted"> + <item>Guard semantics was wrong when it came to logical + operators and exceptions. + <c>{'or', {'is_integer','$1'}, {'or', '$1', '$1'}}</c> + evaluated to <c>true</c> with <c>'$1'</c> bound to an + integer.</item> + <item>Unary + and - was not implemented</item> + <item>Calling operators as Bif's was not supported by + <c>ets/dbg:fun2ms</c> (<c>erlang:'or'(A,B)</c> etc)</item> + <item>Old typetests (like <c>integer(X)</c> instead of + <c>is_integer(X)</c>) was not supported by + <c>ets/dbg:fun2ms</c></item> + <item>Semicolon (;) in guards was not supported by + <c>ets/dbg:fun2ms</c></item> + </list> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-4927</p> + </item> + <item> + <p>A bug that could cause a crash has been fixed in the + <c>file_sorter</c> module. The crash could only occur + when sorting or merging to a file and the input function + returned <c>{end_of_input, Value}</c>.</p> + <p>Own Id: OTP-5009</p> + </item> + <item> + <p>A function clause exit in <c>filelib:fold_files/5</c> has + been fixed.</p> + <p>Own Id: OTP-5137</p> + </item> + <item> + <p><c>filelib:fold_files/5</c> has been fixed to not include + directories that match the regular expression in the + result. In this process, <c>filelib:is_regular/1</c> has + been added to the module.</p> + <p>WARNING the behaviour of <c>filelib:fold_files/5</c> has + also been changed so the regexp match is tried not on + the full name, but locally in each traversed directory.</p> + <p>Own Id: OTP-5171 Aux Id: OTP-5128 </p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The initial shell process started in parallel with the + <c>init</c> boot process. This made it possible to pipe + commands to the shell that got evaluated before the system + had booted properly. Also the shell was normally accessible + before <c>.erlang</c> had been evaluated and this caused + problems especially related to code loading. This has now + been fixed so that the initial shell is not accessible + until after the init boot routine has finished and + <c>.erlang</c> has been evaluated. Note that the shell + starts before any <c>-s</c> arguments are executed.</p> + <p>Own Id: OTP-4877</p> + </item> + <item> + <p>It is now possible to compile files with <c>erlc</c> without + getting a lot of (for compilation) unnecessary code + loaded and executed (like distribution, inet config, + etc). <c>erlc</c> now also calls <c>erl</c> with <c>-boot start_clean</c> (so that SASL is not started even if + <c>start_sasl</c> is default boot script).</p> + <p>Own Id: OTP-4878</p> + </item> + <item> + <p>Dets tables can now be opened or closed in parallel. In + particular, if some table is being repaired, other tables + can still be opened or closed.</p> + <p>Own Id: OTP-4908</p> + </item> + <item> + <p>The new STDLIB module <c>qlc</c> implements a query + language with a list comprehension syntax completely + embedded in Erlang. There is support for reading data + from ETS, Dets, and Mnesia tables as well as for defining + other sources of data. For easy testing queries can be + stated in the Erlang shell. The <c>qlc</c> module aims at + replacing Mnemosyne. See <c>qlc(3)</c> for details and + examples.</p> + <p>Own Id: OTP-5043</p> + </item> + <item> + <p>Some support for records has been added to the Erlang + shell. There are commands for reading record definitions + from files and for manipulating record definitions in the + shell. The record syntax can be used in the shell and + return values are printed as records when possible using + the records definitions known to the shell. New commands + in the shell are <c>rd/2</c>, <c>rf/0,1</c>, + <c>rl/0,1</c>, <c>rp/1</c>, and <c>rr/1,2,3</c>. Existing + functions in <c>user_default.erl</c> with any of these + names need to be renamed. See <c>shell(3)</c> for further + details.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-5063</p> + </item> + <item> + <p>A new function, <c>string:to_integer/1,</c> has been added.</p> + <p>Own Id: OTP-5081 Aux Id: OTP-5136 </p> + </item> + <item> + <p>The new function <c>dets:repair_continuation/2</c> can be + used for restoring an opaque continuation returned by + <c>dets:select/1</c> or <c>dets:select/3</c> if the + continuation has passed through the external term format + (been sent between nodes or stored on disk).</p> + <p>Own Id: OTP-5126</p> + </item> + <item> + <p>A new function, <c>string:to_float/1,</c> has been added.</p> + <p>Own Id: OTP-5136 Aux Id: OTP-5081 </p> + </item> + <item> + <p>Test cases have been added for <c>string</c>.</p> + <p>Own Id: OTP-5138</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.12.8</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The functions <c>ets:insert_new/2</c> and + <c>dets:insert_new/2</c> are added. Please consult + the manual pages for details.</p> + <p>Own Id: OTP-5075</p> + </item> + <item> + <p>New function: <c>proc_lib:hibernate/3.</c> Processes spawned + using <c>proc_lib</c> (also indirectly, such as + <c>gen_server</c> process), should use this function + instead of the BIF <c>erlang:hibernate/3</c> directly to + ensure that the exception handler for the process continues + to work when the process is awaken.</p> + <p>Own Id: OTP-5077</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.12.6</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>If many files or sockets were open (more than 256), + <c>beam_lib</c> operations could fail. Corrected.</p> + <p>Own Id: OTP-5046 Aux Id: OTP-4997, seq8590 </p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.12.5</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>When opening a Dets table read only an attempt was made + to re-hash the table resulting in an error message. This + problem has been fixed.</p> + <p>Own Id: OTP-4989 Aux Id: seq8536 </p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>If a <c>gen_server</c>, <c>gen_event</c> or <c>gen_fsm</c> + process exits with <c>{undef,[{M,F,A}|...]}</c>, the error + report will now state if the function call failed because + the module could not be loaded or because the function was + not exported.</p> + <p>Own Id: OTP-4952 Aux Id: OTP-4925 </p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.12.4</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The shell function <c>c:regs()</c> did crash if there was + a registered port among the registered names. This is now + corrected.</p> + <p>Own Id: OTP-4890</p> + </item> + <item> + <p>A bug has been fixed in <c>dets</c>: not all objects were + always visible in tables with more than 131072 keys.</p> + <p>Own Id: OTP-4906</p> + </item> + <item> + <p>A bug has been fixed in <c>dets</c>: when trying to + repair a version 9 table, a <c>not_a_dets_file</c> error + message was returned unnecessarily often.</p> + <p>Own Id: OTP-4907</p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>Starting Erlang with the <c>+Bi</c> flag (to ignore ^C), now + also disables the quit ('q') option in the JCL menu.</p> + <p>Own Id: OTP-4897</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.12.3</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>A bug in <c>erl_scan</c> caused the compiler to hang when + end-of-file in a comment was encountered. This is now + corrected.</p> + <p>Own Id: OTP-4787</p> + </item> + <item> + <p>The linter now reports errors for unsafe variables when + the option <c>nowarn_unused_vars</c> is given.</p> + <p>Own Id: OTP-4831 Aux Id: seq8202 </p> + </item> + <item> + <p><c>gen_server:cast/2</c> now crashes for invalid + arguments.</p> + <p><c>gen_server:abcast/2-3</c> now crashes for invalid + arguments. The behaviour when casting to the name + <c>global</c> has been corrected. Previously, + <c>gen_server:abcast(global,[node@host])</c> tried to + cast to the globally registered name <c>node@host</c>, + which is more of a bug than less. Now such a call will + cast to the registered name <c>global</c> at the node + <c>node@host</c> as (probably) expected.</p> + <p>An <c>rpc:call/5</c> and <c>rpc:block_call/5</c> having a + timeout argument has been added.</p> + <p><c>rpc:abcast/2-3</c> has been improved not to get stuck + waiting for connection setup if the remote node is not + connected. In this case the send is spawned off to a + temporary process.</p> + <p>Two typos in the docs for module <c>calendar</c> has + been corrected thanks to Bengt Kleberg.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-4844 Aux Id: seq8226 </p> + </item> + </list> + </section> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p>The <c>f/1</c> shell command did not work correctly with + restricted shell.</p> + <p>Own Id: OTP-4818</p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.12.2</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p><c>gen_server</c>: the internal function <c>get_parent,</c> + called by <c>gen_server:enter_loop/[4,5],</c> now returns + the pid of parents that are registered processes, instead of + returning their name. The reason for this is that + <c>gen_server</c> relies on that the parent is represented + as a pid. This error in <c>get_parent/0</c> had the effect + that the terminate function of the child was not run when + it was shutdown.</p> + <p>Own Id: OTP-4820 Aux Id: seq8170 </p> + </item> + </list> + </section> + </section> + + <section> + <title>STDLIB 1.12.1</title> + + <section> + <title>Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>The code server could hang if invoked early in the startup. + For example if the emulator was started with + "<c>-s file eval Filename</c> and <c>Filename</c> contained + a call to <c>code:add_patha/1</c> the code server + accidentally tried to execute code in an unloaded module + from inside the code that loaded a module - hence hangup. + This bug has now been fixed.</p> + <p>Note! Starting Erlang through code loading from a remote + Erlang boot server will not work after this patch. It will + be fixed in a later patch. Rumours has it that remote boot + server code loading did not work before this patch either. + It is not a commonly used feature.</p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-4802 Aux Id: seq8314 </p> + </item> + </list> + </section> + </section> +</chapter> + diff --git a/lib/stdlib/doc/src/orddict.xml b/lib/stdlib/doc/src/orddict.xml new file mode 100644 index 0000000000..08c808f822 --- /dev/null +++ b/lib/stdlib/doc/src/orddict.xml @@ -0,0 +1,354 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>orddict</title> + <prepared>Robert Virding</prepared> + <responsible>nobody</responsible> + <docno></docno> + <approved>nobody</approved> + <checked>no</checked> + <date>2007-04-16</date> + <rev>B</rev> + <file>orddict.sgml</file> + </header> + <module>orddict</module> + <modulesummary>Key-Value Dictionary as Ordered List</modulesummary> + <description> + <p><c>Orddict</c> implements a <c>Key</c> - <c>Value</c> dictionary. + An <c>orddict</c> is a representation of a dictionary, where a + list of pairs is used to store the keys and values. The list is + ordered after the keys.</p> + <p>This module provides exactly the same interface as the module + <c>dict</c> but with a defined representation. One difference is + that while <c>dict</c> considers two keys as different if they + do not match (<c>=:=</c>), this module considers two keys as + different if and only if they do not compare equal + (<c>==</c>).</p> + </description> + + <section> + <title>DATA TYPES</title> + <code type="none"> +ordered_dictionary() + as returned by new/0</code> + </section> + <funcs> + <func> + <name>append(Key, Value, Orddict1) -> Orddict2</name> + <fsummary>Append a value to keys in a dictionary</fsummary> + <type> + <v>Key = Value = term()</v> + <v>Orddict1 = Orddict2 = ordered_dictionary()</v> + </type> + <desc> + <p>This function appends a new <c>Value</c> to the current list + of values associated with <c>Key</c>. An exception is + generated if the initial value associated with <c>Key</c> is + not a list of values.</p> + </desc> + </func> + <func> + <name>append_list(Key, ValList, Orddict1) -> Orddict2</name> + <fsummary>Append new values to keys in a dictionary</fsummary> + <type> + <v>ValList = [Value]</v> + <v>Key = Value = term()</v> + <v>Orddict1 = Orddict2 = ordered_dictionary()</v> + </type> + <desc> + <p>This function appends a list of values <c>ValList</c> to + the current list of values associated with <c>Key</c>. An + exception is generated if the initial value associated with + <c>Key</c> is not a list of values.</p> + </desc> + </func> + <func> + <name>erase(Key, Orddict1) -> Orddict2</name> + <fsummary>Erase a key from a dictionary</fsummary> + <type> + <v>Key = term()</v> + <v>Orddict1 = Orddict2 = ordered_dictionary()</v> + </type> + <desc> + <p>This function erases all items with a given key from a + dictionary.</p> + </desc> + </func> + <func> + <name>fetch(Key, Orddict) -> Value</name> + <fsummary>Look-up values in a dictionary</fsummary> + <type> + <v>Key = Value = term()</v> + <v>Orddict = ordered_dictionary()</v> + </type> + <desc> + <p>This function returns the value associated with <c>Key</c> + in the dictionary <c>Orddict</c>. <c>fetch</c> assumes that + the <c>Key</c> is present in the dictionary and an exception + is generated if <c>Key</c> is not in the dictionary.</p> + </desc> + </func> + <func> + <name>fetch_keys(Orddict) -> Keys</name> + <fsummary>Return all keys in a dictionary</fsummary> + <type> + <v>Orddict = ordered_dictionary()</v> + <v>Keys = [term()]</v> + </type> + <desc> + <p>This function returns a list of all keys in the dictionary.</p> + </desc> + </func> + <func> + <name>filter(Pred, Orddict1) -> Orddict2</name> + <fsummary>Choose elements which satisfy a predicate</fsummary> + <type> + <v>Pred = fun(Key, Value) -> bool()</v> + <v> Key = Value = term()</v> + <v>Orddict1 = Orddict2 = ordered_dictionary()</v> + </type> + <desc> + <p><c>Orddict2</c> is a dictionary of all keys and values in + <c>Orddict1</c> for which <c>Pred(Key, Value)</c> is <c>true</c>.</p> + </desc> + </func> + <func> + <name>find(Key, Orddict) -> {ok, Value} | error</name> + <fsummary>Search for a key in a dictionary</fsummary> + <type> + <v>Key = Value = term()</v> + <v>Orddict = ordered_dictionary()</v> + </type> + <desc> + <p>This function searches for a key in a dictionary. Returns + <c>{ok, Value}</c> where <c>Value</c> is the value associated + with <c>Key</c>, or <c>error</c> if the key is not present in + the dictionary.</p> + </desc> + </func> + <func> + <name>fold(Fun, Acc0, Orddict) -> Acc1</name> + <fsummary>Fold a function over a dictionary</fsummary> + <type> + <v>Fun = fun(Key, Value, AccIn) -> AccOut</v> + <v>Key = Value = term()</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v>Orddict = ordered_dictionary()</v> + </type> + <desc> + <p>Calls <c>Fun</c> on successive keys and values of + <c>Orddict</c> together with an extra argument <c>Acc</c> + (short for accumulator). <c>Fun</c> must return a new + accumulator which is passed to the next call. <c>Acc0</c> is + returned if the list is empty. The evaluation order is + undefined.</p> + </desc> + </func> + <func> + <name>from_list(List) -> Orddict</name> + <fsummary>Convert a list of pairs to a dictionary</fsummary> + <type> + <v>List = [{Key, Value}]</v> + <v>Orddict = ordered_dictionary()</v> + </type> + <desc> + <p>This function converts the key/value list <c>List</c> to a + dictionary.</p> + </desc> + </func> + <func> + <name>is_key(Key, Orddict) -> bool()</name> + <fsummary>Test if a key is in a dictionary</fsummary> + <type> + <v>Key = term()</v> + <v>Orddict = ordered_dictionary()</v> + </type> + <desc> + <p>This function tests if <c>Key</c> is contained in + the dictionary <c>Orddict</c>.</p> + </desc> + </func> + <func> + <name>map(Fun, Orddict1) -> Orddict2</name> + <fsummary>Map a function over a dictionary</fsummary> + <type> + <v>Fun = fun(Key, Value1) -> Value2</v> + <v> Key = Value1 = Value2 = term()</v> + <v>Orddict1 = Orddict2 = ordered_dictionary()</v> + </type> + <desc> + <p><c>map</c> calls <c>Func</c> on successive keys and values + of <c>Orddict</c> to return a new value for each key. + The evaluation order is undefined.</p> + </desc> + </func> + <func> + <name>merge(Fun, Orddict1, Orddict2) -> Orddict3</name> + <fsummary>Merge two dictionaries</fsummary> + <type> + <v>Fun = fun(Key, Value1, Value2) -> Value</v> + <v> Key = Value1 = Value2 = Value3 = term()</v> + <v>Orddict1 = Orddict2 = Orddict3 = ordered_dictionary()</v> + </type> + <desc> + <p><c>merge</c> merges two dictionaries, <c>Orddict1</c> and + <c>Orddict2</c>, to create a new dictionary. All the <c>Key</c> + - <c>Value</c> pairs from both dictionaries are included in + the new dictionary. If a key occurs in both dictionaries then + <c>Fun</c> is called with the key and both values to return a + new value. <c>merge</c> could be defined as:</p> + <code type="none"> +merge(Fun, D1, D2) -> + fold(fun (K, V1, D) -> + update(K, fun (V2) -> Fun(K, V1, V2) end, V1, D) + end, D2, D1).</code> + <p>but is faster.</p> + </desc> + </func> + <func> + <name>new() -> ordered_dictionary()</name> + <fsummary>Create a dictionary</fsummary> + <desc> + <p>This function creates a new dictionary.</p> + </desc> + </func> + <func> + <name>size(Orddict) -> int()</name> + <fsummary>Return the number of elements in an ordered dictionary</fsummary> + <type> + <v>Orddict = ordered_dictionary()</v> + </type> + <desc> + <p>Returns the number of elements in an <c>Orddict</c>.</p> + </desc> + </func> + <func> + <name>store(Key, Value, Orddict1) -> Orddict2</name> + <fsummary>Store a value in a dictionary</fsummary> + <type> + <v>Key = Value = term()</v> + <v>Orddict1 = Orddict2 = ordered_dictionary()</v> + </type> + <desc> + <p>This function stores a <c>Key</c> - <c>Value</c> pair in a + dictionary. If the <c>Key</c> already exists in <c>Orddict1</c>, + the associated value is replaced by <c>Value</c>.</p> + </desc> + </func> + <func> + <name>to_list(Orddict) -> List</name> + <fsummary>Convert a dictionary to a list of pairs</fsummary> + <type> + <v>Orddict = ordered_dictionary()</v> + <v>List = [{Key, Value}]</v> + </type> + <desc> + <p>This function converts the dictionary to a list + representation.</p> + </desc> + </func> + <func> + <name>update(Key, Fun, Orddict1) -> Orddict2</name> + <fsummary>Update a value in a dictionary</fsummary> + <type> + <v>Key = term()</v> + <v>Fun = fun(Value1) -> Value2</v> + <v> Value1 = Value2 = term()</v> + <v>Orddict1 = Orddict2 = ordered_dictionary()</v> + </type> + <desc> + <p>Update the a value in a dictionary by calling <c>Fun</c> on + the value to get a new value. An exception is generated if + <c>Key</c> is not present in the dictionary.</p> + </desc> + </func> + <func> + <name>update(Key, Fun, Initial, Orddict1) -> Orddict2</name> + <fsummary>Update a value in a dictionary</fsummary> + <type> + <v>Key = Initial = term()</v> + <v>Fun = fun(Value1) -> Value2</v> + <v> Value1 = Value2 = term()</v> + <v>Orddict1 = Orddict2 = ordered_dictionary()</v> + </type> + <desc> + <p>Update the a value in a dictionary by calling <c>Fun</c> on + the value to get a new value. If <c>Key</c> is not present + in the dictionary then <c>Initial</c> will be stored as + the first value. For example <c>append/3</c> could be defined + as:</p> + <code type="none"> +append(Key, Val, D) -> + update(Key, fun (Old) -> Old ++ [Val] end, [Val], D).</code> + </desc> + </func> + <func> + <name>update_counter(Key, Increment, Orddict1) -> Orddict2</name> + <fsummary>Increment a value in a dictionary</fsummary> + <type> + <v>Key = term()</v> + <v>Increment = number()</v> + <v>Orddict1 = Orddict2 = ordered_dictionary()</v> + </type> + <desc> + <p>Add <c>Increment</c> to the value associated with <c>Key</c> + and store this value. If <c>Key</c> is not present in + the dictionary then <c>Increment</c> will be stored as + the first value.</p> + <p>This could be defined as:</p> + <code type="none"> +update_counter(Key, Incr, D) -> + update(Key, fun (Old) -> Old + Incr end, Incr, D).</code> + <p>but is faster.</p> + </desc> + </func> + </funcs> + + <section> + <title>Notes</title> + <p>The functions <c>append</c> and <c>append_list</c> are included + so we can store keyed values in a list <em>accumulator</em>. For + example:</p> + <pre> +> D0 = orddict:new(), + D1 = orddict:store(files, [], D0), + D2 = orddict:append(files, f1, D1), + D3 = orddict:append(files, f2, D2), + D4 = orddict:append(files, f3, D3), + orddict:fetch(files, D4). +[f1,f2,f3] </pre> + <p>This saves the trouble of first fetching a keyed value, + appending a new value to the list of stored values, and storing + the result. + </p> + <p>The function <c>fetch</c> should be used if the key is known to + be in the dictionary, otherwise <c>find</c>.</p> + </section> + + <section> + <title>See Also</title> + <p><seealso marker="dict">dict(3)</seealso>, + <seealso marker="gb_trees">gb_trees(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/ordsets.xml b/lib/stdlib/doc/src/ordsets.xml new file mode 100644 index 0000000000..a20ab2d879 --- /dev/null +++ b/lib/stdlib/doc/src/ordsets.xml @@ -0,0 +1,254 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>ordsets</title> + <prepared>Robert Virding</prepared> + <responsible>Bjarne Dacker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>99-07-27</date> + <rev>A</rev> + <file>ordsets.sgml</file> + </header> + <module>ordsets</module> + <modulesummary>Functions for Manipulating Sets as Ordered Lists</modulesummary> + <description> + <p>Sets are collections of elements with no duplicate elements. + An <c>ordset</c> is a representation of a set, where an ordered + list is used to store the elements of the set. An ordered list + is more efficient than an unordered list.</p> + <p>This module provides exactly the same interface as the module + <c>sets</c> but with a defined representation. One difference is + that while <c>sets</c> considers two elements as different if they + do not match (<c>=:=</c>), this module considers two elements as + different if and only if they do not compare equal (<c>==</c>).</p> + </description> + + <section> + <title>DATA TYPES</title> + <code type="none"> +ordered_set() + as returned by new/0</code> + </section> + <funcs> + <func> + <name>new() -> Ordset</name> + <fsummary>Return an empty set</fsummary> + <type> + <v>Ordset = ordered_set()</v> + </type> + <desc> + <p>Returns a new empty ordered set.</p> + </desc> + </func> + <func> + <name>is_set(Ordset) -> bool()</name> + <fsummary>Test for an <c>Ordset</c></fsummary> + <type> + <v>Ordset = term()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Ordset</c> is an ordered set of + elements, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>size(Ordset) -> int()</name> + <fsummary>Return the number of elements in a set</fsummary> + <type> + <v>Ordset = term()</v> + </type> + <desc> + <p>Returns the number of elements in <c>Ordset</c>.</p> + </desc> + </func> + <func> + <name>to_list(Ordset) -> List</name> + <fsummary>Convert an <c>Ordset</c>into a list</fsummary> + <type> + <v>Ordset = ordered_set()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns the elements of <c>Ordset</c> as a list.</p> + </desc> + </func> + <func> + <name>from_list(List) -> Ordset</name> + <fsummary>Convert a list into an <c>Ordset</c></fsummary> + <type> + <v>List = [term()]</v> + <v>Ordset = ordered_set()</v> + </type> + <desc> + <p>Returns an ordered set of the elements in <c>List</c>.</p> + </desc> + </func> + <func> + <name>is_element(Element, Ordset) -> bool()</name> + <fsummary>Test for membership of an <c>Ordset</c></fsummary> + <type> + <v>Element = term()</v> + <v>Ordset = ordered_set()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Element</c> is an element of + <c>Ordset</c>, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>add_element(Element, Ordset1) -> Ordset2</name> + <fsummary>Add an element to an <c>Ordset</c></fsummary> + <type> + <v>Element = term()</v> + <v>Ordset1 = Ordset2 = ordered_set()</v> + </type> + <desc> + <p>Returns a new ordered set formed from <c>Ordset1</c> with + <c>Element</c> inserted.</p> + </desc> + </func> + <func> + <name>del_element(Element, Ordset1) -> Ordset2</name> + <fsummary>Remove an element from an <c>Ordset</c></fsummary> + <type> + <v>Element = term()</v> + <v>Ordset1 = Ordset2 = ordered_set()</v> + </type> + <desc> + <p>Returns <c>Ordset1</c>, but with <c>Element</c> removed.</p> + </desc> + </func> + <func> + <name>union(Ordset1, Ordset2) -> Ordset3</name> + <fsummary>Return the union of two <c>Ordsets</c></fsummary> + <type> + <v>Ordset1 = Ordset2 = Ordset3 = ordered_set()</v> + </type> + <desc> + <p>Returns the merged (union) set of <c>Ordset1</c> and + <c>Ordset2</c>.</p> + </desc> + </func> + <func> + <name>union(OrdsetList) -> Ordset</name> + <fsummary>Return the union of a list of <c>Ordsets</c></fsummary> + <type> + <v>OrdsetList = [ordered_set()]</v> + <v>Ordset = ordered_set()</v> + </type> + <desc> + <p>Returns the merged (union) set of the list of sets.</p> + </desc> + </func> + <func> + <name>intersection(Ordset1, Ordset2) -> Ordset3</name> + <fsummary>Return the intersection of two <c>Ordsets</c></fsummary> + <type> + <v>Ordset1 = Ordset2 = Ordset3 = ordered_set()</v> + </type> + <desc> + <p>Returns the intersection of <c>Ordset1</c> and + <c>Ordset2</c>.</p> + </desc> + </func> + <func> + <name>intersection(OrdsetList) -> Ordset</name> + <fsummary>Return the intersection of a list of <c>Ordsets</c></fsummary> + <type> + <v>OrdsetList = [ordered_set()]</v> + <v>Ordset = ordered_set()</v> + </type> + <desc> + <p>Returns the intersection of the non-empty list of sets.</p> + </desc> + </func> + <func> + <name>is_disjoint(Ordset1, Ordset2) -> bool()</name> + <fsummary>Check whether two <c>Ordsets</c> are disjoint</fsummary> + <type> + <v>Ordset1 = Ordset2 = ordered_set()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Ordset1</c> and + <c>Ordset2</c> are disjoint (have no elements in common), + and <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>subtract(Ordset1, Ordset2) -> Ordset3</name> + <fsummary>Return the difference of two <c>Ordsets</c></fsummary> + <type> + <v>Ordset1 = Ordset2 = Ordset3 = ordered_set()</v> + </type> + <desc> + <p>Returns only the elements of <c>Ordset1</c> which are not + also elements of <c>Ordset2</c>.</p> + </desc> + </func> + <func> + <name>is_subset(Ordset1, Ordset2) -> bool()</name> + <fsummary>Test for subset</fsummary> + <type> + <v>Ordset1 = Ordset2 = ordered_set()</v> + </type> + <desc> + <p>Returns <c>true</c> when every element of <c>Ordset</c>1 is + also a member of <c>Ordset2</c>, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>fold(Function, Acc0, Ordset) -> Acc1</name> + <fsummary>Fold over set elements</fsummary> + <type> + <v>Function = fun (E, AccIn) -> AccOut</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v>Ordset = ordered_set()</v> + </type> + <desc> + <p>Fold <c>Function</c> over every element in <c>Ordset</c> + returning the final value of the accumulator.</p> + </desc> + </func> + <func> + <name>filter(Pred, Ordset1) -> Set2</name> + <fsummary>Filter set elements</fsummary> + <type> + <v>Pred = fun (E) -> bool()</v> + <v>Set1 = Set2 = ordered_set()</v> + </type> + <desc> + <p>Filter elements in <c>Set1</c> with boolean function + <c>Fun</c>.</p> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p><seealso marker="gb_sets">gb_sets(3)</seealso>, + <seealso marker="sets">sets(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/part.xml b/lib/stdlib/doc/src/part.xml new file mode 100644 index 0000000000..25ca56ad86 --- /dev/null +++ b/lib/stdlib/doc/src/part.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1996</year> + <year>2009</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>STDLIB User's Guide</title> + <prepared>Patrik Nyblom</prepared> + <docno></docno> + <date>2008-02-25</date> + <rev>1.0</rev> + <file>part.xml</file> + </header> + <description> + <p>The Erlang standard library <em>STDLIB</em>.</p> + </description> + <xi:include href="io_protocol.xml"/> + <xi:include href="unicode_usage.xml"/> +</part> + diff --git a/lib/stdlib/doc/src/part_notes.xml b/lib/stdlib/doc/src/part_notes.xml new file mode 100644 index 0000000000..66ad294753 --- /dev/null +++ b/lib/stdlib/doc/src/part_notes.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>STDLIB Release Notes</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <description> + <p>The Standard Erlang Libraries application, <em>STDLIB</em>, + contains modules for manipulating lists, strings and files etc.</p> + <p>For information about older versions, see + <url href="part_notes_history_frame.html">Release Notes History</url>.</p> + </description> + <xi:include href="notes.xml"/> +</part> + diff --git a/lib/stdlib/doc/src/part_notes_history.xml b/lib/stdlib/doc/src/part_notes_history.xml new file mode 100644 index 0000000000..744b009583 --- /dev/null +++ b/lib/stdlib/doc/src/part_notes_history.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part> + <header> + <copyright> + <year>2006</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>STDLIB Release Notes History</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <description> + <p>The Standard Erlang Libraries application, <em>STDLIB</em>, + contains modules for manipulating lists, strings and files etc.</p> + </description> + <include file="notes_history"></include> +</part> + diff --git a/lib/stdlib/doc/src/pg.xml b/lib/stdlib/doc/src/pg.xml new file mode 100644 index 0000000000..66b9702ae0 --- /dev/null +++ b/lib/stdlib/doc/src/pg.xml @@ -0,0 +1,132 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>pg</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>pg</module> + <modulesummary>Distributed, Named Process Groups</modulesummary> + <description> + <p>This (experimental) module implements process groups. A process + group is a group of processes that can be accessed by a common + name. For example, a group named <c>foobar</c> can include a set + of processes as members of this group and they can be located on + different nodes.</p> + <p>When messages are sent to the named group, all members of + the group receive the message. The messages are serialized. If + the process <c>P1</c> sends the message <c>M1</c> to the group, + and process <c>P2</c> simultaneously sends message <c>M2</c>, then + all members of the group receive the two messages in the same + order. If members of a group terminate, they are automatically + removed from the group.</p> + <p>This module is not complete. The module is inspired by the ISIS + system and the causal order protocol of the ISIS system should + also be implemented. At the moment, all messages are serialized + by sending them through a group master process.</p> + </description> + <funcs> + <func> + <name>create(PgName) -> ok | {error, Reason}</name> + <fsummary>Create an empty group</fsummary> + <type> + <v>PgName = term()</v> + <v>Reason = already_created | term()</v> + </type> + <desc> + <p>Creates an empty group named <c>PgName</c> on the current + node.</p> + </desc> + </func> + <func> + <name>create(PgName, Node) -> ok | {error, Reason}</name> + <fsummary>Create an empty group on another node</fsummary> + <type> + <v>PgName = term()</v> + <v>Node = node()</v> + <v>Reason = already_created | term()</v> + </type> + <desc> + <p>Creates an empty group named <c>PgName</c> on the node + <c>Node</c>.</p> + </desc> + </func> + <func> + <name>join(PgName, Pid) -> Members</name> + <fsummary>Join a pid to a process group</fsummary> + <type> + <v>PgName = term()</v> + <v>Pid = pid()</v> + <v>Members = [pid()]</v> + </type> + <desc> + <p>Joins the pid <c>Pid</c> to the process group <c>PgName</c>. + Returns a list of all old members of the group.</p> + </desc> + </func> + <func> + <name>send(PgName, Msg) -> void()</name> + <fsummary>Send a message to all members of a process group</fsummary> + <type> + <v>PgName = Msg = term()</v> + </type> + <desc> + <p>Sends the tuple <c>{pg_message, From, PgName, Msg}</c> to + all members of the process group <c>PgName</c>.</p> + <p>Failure: <c>{badarg, {PgName, Msg}}</c> if <c>PgName</c> is + not a process group (a globally registered name).</p> + </desc> + </func> + <func> + <name>esend(PgName, Msg) -> void()</name> + <fsummary>Send a message to all members of a process group, except ourselves</fsummary> + <type> + <v>PgName = Msg = term()</v> + </type> + <desc> + <p>Sends the tuple <c>{pg_message, From, PgName, Msg}</c> to + all members of the process group <c>PgName</c>, except + ourselves.</p> + <p>Failure: <c>{badarg, {PgName, Msg}}</c> if <c>PgName</c> is + not a process group (a globally registered name).</p> + </desc> + </func> + <func> + <name>members(PgName) -> Members</name> + <fsummary>Return a list of all members of a process group</fsummary> + <type> + <v>PgName = term()</v> + <v>Members = [pid()]</v> + </type> + <desc> + <p>Returns a list of all members of the process group + <c>PgName</c>.</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/pool.xml b/lib/stdlib/doc/src/pool.xml new file mode 100644 index 0000000000..2b890352eb --- /dev/null +++ b/lib/stdlib/doc/src/pool.xml @@ -0,0 +1,148 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>pool</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>pool</module> + <modulesummary>Load Distribution Facility</modulesummary> + <description> + <p><c>pool</c> can be used to run a set of Erlang nodes as a pool + of computational processors. It is organized as a master and a + set of slave nodes and includes the following features:</p> + <list type="bulleted"> + <item>The slave nodes send regular reports to the master about + their current load.</item> + <item>Queries can be sent to the master to determine which node + will have the least load.</item> + </list> + <p>The BIF <c>statistics(run_queue)</c> is used for estimating + future loads. It returns the length of the queue of ready to run + processes in the Erlang runtime system.</p> + <p>The slave nodes are started with the <c>slave</c> module. This + effects, tty IO, file IO, and code loading.</p> + <p>If the master node fails, the entire pool will exit.</p> + </description> + <funcs> + <func> + <name>start(Name) -></name> + <name>start(Name, Args) -> Nodes</name> + <fsummary>>Start a new pool</fsummary> + <type> + <v>Name = atom()</v> + <v>Args = string()</v> + <v>Nodes = [node()]</v> + </type> + <desc> + <p>Starts a new pool. The file <c>.hosts.erlang</c> is read to + find host names where the pool nodes can be started. See + section <seealso marker="#files">Files</seealso> below. The + start-up procedure fails if the file is not found.</p> + <p>The slave nodes are started with <c>slave:start/2,3</c>, + passing along <c>Name</c> and, if provided, <c>Args</c>. + <c>Name</c> is used as the first part of the node names, + <c>Args</c> is used to specify command line arguments. See + <seealso marker="slave#start/2">slave(3)</seealso>.</p> + <p>Access rights must be set so that all nodes in the pool have + the authority to access each other.</p> + <p>The function is synchronous and all the nodes, as well as + all the system servers, are running when it returns a value.</p> + </desc> + </func> + <func> + <name>attach(Node) -> already_attached | attached</name> + <fsummary>Ensure that a pool master is running</fsummary> + <type> + <v>Node = node()</v> + </type> + <desc> + <p>This function ensures that a pool master is running and + includes <c>Node</c> in the pool master's pool of nodes.</p> + </desc> + </func> + <func> + <name>stop() -> stopped</name> + <fsummary>Stop the pool and kill all the slave nodes</fsummary> + <desc> + <p>Stops the pool and kills all the slave nodes.</p> + </desc> + </func> + <func> + <name>get_nodes() -> Nodes</name> + <fsummary>Return a list of the current member nodes of the pool</fsummary> + <type> + <v>Nodes = [node()]</v> + </type> + <desc> + <p>Returns a list of the current member nodes of the pool.</p> + </desc> + </func> + <func> + <name>pspawn(Mod, Fun, Args) -> pid()</name> + <fsummary>Spawn a process on the pool node with expected lowest future load</fsummary> + <type> + <v>Mod = Fun = atom()</v> + <v>Args = [term()]</v> + </type> + <desc> + <p>Spawns a process on the pool node which is expected to have + the lowest future load.</p> + </desc> + </func> + <func> + <name>pspawn_link(Mod, Fun, Args) -> pid()</name> + <fsummary>Spawn and link to a process on the pool node with expected lowest future load</fsummary> + <type> + <v>Mod = Fun = atom()</v> + <v>Args = [term()]</v> + </type> + <desc> + <p>Spawn links a process on the pool node which is expected to + have the lowest future load.</p> + </desc> + </func> + <func> + <name>get_node() -> node()</name> + <fsummary>Return the node with the expected lowest future load</fsummary> + <desc> + <p>Returns the node with the expected lowest future load.</p> + </desc> + </func> + </funcs> + + <section> + <marker id="files"></marker> + <title>Files</title> + <p><c>.hosts.erlang</c> is used to pick hosts where nodes can + be started. See + <seealso marker="kernel:net_adm#host_file/0">net_adm(3)</seealso> + for information about format and location of this file.</p> + <p><c>$HOME/.erlang.slave.out.HOST</c> is used for all additional IO + that may come from the slave nodes on standard IO. If the start-up + procedure does not work, this file may indicate the reason.</p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/proc_lib.xml b/lib/stdlib/doc/src/proc_lib.xml new file mode 100644 index 0000000000..791001cb52 --- /dev/null +++ b/lib/stdlib/doc/src/proc_lib.xml @@ -0,0 +1,322 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>proc_lib</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>proc_lib</module> + <modulesummary>Functions for asynchronous and synchronous start of processes adhering to the OTP design principles.</modulesummary> + <description> + <p>This module is used to start processes adhering to + the <seealso marker="doc/design_principles:des_princ">OTP Design Principles</seealso>. Specifically, the functions in this + module are used by the OTP standard behaviors (<c>gen_server</c>, + <c>gen_fsm</c>, ...) when starting new processes. The functions + can also be used to start <em>special processes</em>, user + defined processes which comply to the OTP design principles. See + <seealso marker="doc/design_principles:spec_proc">Sys and Proc_Lib</seealso> in OTP Design Principles for an example.</p> + <p>Some useful information is initialized when a process starts. + The registered names, or the process identifiers, of the parent + process, and the parent ancestors, are stored together with + information about the function initially called in the process.</p> + <p>While in "plain Erlang" a process is said to terminate normally + only for the exit reason <c>normal</c>, a process started + using <c>proc_lib</c> is also said to terminate normally if it + exits with reason <c>shutdown</c> or <c>{shutdown,Term}</c>. + <c>shutdown</c> is the reason used when + an application (supervision tree) is stopped.</p> + <p>When a process started using <c>proc_lib</c> terminates + abnormally -- that is, with another exit reason than <c>normal</c>, + <c>shutdown</c>, or <c>{shutdown,Term}</c> -- a <em>crash report</em> + is generated, which is written to terminal by the default SASL + event handler. That is, the crash report is normally only visible + if the SASL application is started. See + <seealso marker="sasl:sasl_app">sasl(6)</seealso> and + <seealso marker="sasl:error_logging">SASL User's Guide</seealso>.</p> + <p>The crash report contains the previously stored information such + as ancestors and initial function, the termination reason, and + information regarding other processes which terminate as a result + of this process terminating.</p> + </description> + <funcs> + <func> + <name>spawn(Fun) -> pid()</name> + <name>spawn(Node, Fun) -> pid()</name> + <name>spawn(Module, Function, Args) -> pid()</name> + <name>spawn(Node, Module, Function, Args) -> pid()</name> + <fsummary>Spawn a new process.</fsummary> + <type> + <v>Node = node()</v> + <v>Fun = fun() -> void()</v> + <v>Module = Function = atom()</v> + <v>Args = [term()]</v> + </type> + <desc> + <p>Spawns a new process and initializes it as described above. + The process is spawned using the + <seealso marker="erts:erlang#spawn/1">spawn</seealso> BIFs.</p> + </desc> + </func> + <func> + <name>spawn_link(Fun) -> pid()</name> + <name>spawn_link(Node, Fun) -> pid()</name> + <name>spawn_link(Module, Function, Args) -> pid()</name> + <name>spawn_link(Node, Module, Function, Args) -> pid()</name> + <fsummary>Spawn and link to a new process.</fsummary> + <type> + <v>Node = node()</v> + <v>Fun = fun() -> void()</v> + <v>Module = Function = atom()</v> + <v>Args = [term()]</v> + </type> + <desc> + <p>Spawns a new process and initializes it as described above. + The process is spawned using the + <seealso marker="erts:erlang#spawn_link/1">spawn_link</seealso> + BIFs.</p> + </desc> + </func> + <func> + <name>spawn_opt(Fun, SpawnOpts) -> pid()</name> + <name>spawn_opt(Node, Fun, SpawnOpts) -> pid()</name> + <name>spawn_opt(Module, Function, Args, SpawnOpts) -> pid()</name> + <name>spawn_opt(Node, Module, Func, Args, SpawnOpts) -> pid()</name> + <fsummary>Spawn a new process with given options.</fsummary> + <type> + <v>Node = node()</v> + <v>Fun = fun() -> void()</v> + <v>Module = Function = atom()</v> + <v>Args = [term()]</v> + <v>SpawnOpts -- see erlang:spawn_opt/2,3,4,5</v> + </type> + <desc> + <p>Spawns a new process and initializes it as described above. + The process is spawned using the + <seealso marker="erts:erlang#spawn_opt/2">spawn_opt</seealso> + BIFs.</p> + <note> + <p>Using the spawn option <c>monitor</c> is currently not + allowed, but will cause the function to fail with reason + <c>badarg</c>.</p> + </note> + </desc> + </func> + <func> + <name>start(Module, Function, Args) -> Ret</name> + <name>start(Module, Function, Args, Time) -> Ret</name> + <name>start(Module, Function, Args, Time, SpawnOpts) -> Ret</name> + <name>start_link(Module, Function, Args) -> Ret</name> + <name>start_link(Module, Function, Args, Time) -> Ret</name> + <name>start_link(Module, Function, Args, Time, SpawnOpts) -> Ret</name> + <fsummary>Start a new process synchronously.</fsummary> + <type> + <v>Module = Function = atom()</v> + <v>Args = [term()]</v> + <v>Time = int() >= 0 | infinity</v> + <v>SpawnOpts -- see erlang:spawn_opt/2,3,4,5</v> + <v>Ret = term() | {error, Reason}</v> + </type> + <desc> + <p>Starts a new process synchronously. Spawns the process and + waits for it to start. When the process has started, it + <em>must</em> call + <seealso marker="#init_ack/2">init_ack(Parent,Ret)</seealso> + or <seealso marker="#init_ack/1">init_ack(Ret)</seealso>, + where <c>Parent</c> is the process that evaluates this + function. At this time, <c>Ret</c> is returned.</p> + <p>If the <c>start_link/3,4,5</c> function is used and + the process crashes before it has called <c>init_ack/1,2</c>, + <c>{error, Reason}</c> is returned if the calling process + traps exits.</p> + <p>If <c>Time</c> is specified as an integer, this function + waits for <c>Time</c> milliseconds for the new process to call + <c>init_ack</c>, or <c>{error, timeout}</c> is returned, and + the process is killed.</p> + <p>The <c>SpawnOpts</c> argument, if given, will be passed + as the last argument to the <c>spawn_opt/2,3,4,5</c> BIF.</p> + <note> + <p>Using the spawn option <c>monitor</c> is currently not + allowed, but will cause the function to fail with reason + <c>badarg</c>.</p> + </note> + </desc> + </func> + <func> + <name>init_ack(Parent, Ret) -> void()</name> + <name>init_ack(Ret) -> void()</name> + <fsummary>Used by a process when it has started.</fsummary> + <type> + <v>Parent = pid()</v> + <v>Ret = term()</v> + </type> + <desc> + <p>This function must used by a process that has been started by + a <seealso marker="#start/3">start[_link]/3,4,5</seealso> + function. It tells <c>Parent</c> that the process has + initialized itself, has started, or has failed to initialize + itself.</p> + <p>The <c>init_ack/1</c> function uses the parent value + previously stored by the start function used.</p> + <p>If this function is not called, the start function will + return an error tuple (if a link and/or a timeout is used) or + hang otherwise.</p> + <p>The following example illustrates how this function and + <c>proc_lib:start_link/3</c> are used.</p> + <code type="none"> +-module(my_proc). +-export([start_link/0]). +-export([init/1]). + +start_link() -> + proc_lib:start_link(my_proc, init, [self()]). + +init(Parent) -> + case do_initialization() of + ok -> + proc_lib:init_ack(Parent, {ok, self()}); + {error, Reason} -> + exit(Reason) + end, + loop(). + +...</code> + </desc> + </func> + <func> + <name>format(CrashReport) -> string()</name> + <fsummary>Format a crash report.</fsummary> + <type> + <v>CrashReport = term()</v> + </type> + <desc> + <p>This function can be used by a user defined event handler to + format a crash report. The crash report is sent using + <c>error_logger:error_report(crash_report, CrashReport)</c>. + That is, the event to be handled is of the format + <c>{error_report, GL, {Pid, crash_report, CrashReport}}</c> + where <c>GL</c> is the group leader pid of the process + <c>Pid</c> which sent the crash report.</p> + </desc> + </func> + <func> + <name>initial_call(Process) -> {Module,Function,Args} | false</name> + <fsummary>Extract the initial call of a <c>proc_lib</c>spawned process.</fsummary> + <type> + <v>Process = pid() | {X,Y,Z} | ProcInfo</v> + <v> X = Y = Z = int()</v> + <v> ProcInfo = term()</v> + <v>Module = Function = atom()</v> + <v>Args = [atom()]</v> + </type> + <desc> + <p>Extracts the initial call of a process that was started + using one of the spawn or start functions described above. + <c>Process</c> can either be a pid, an integer tuple (from + which a pid can be created), or the process information of a + process <c>Pid</c> fetched through an + <c>erlang:process_info(Pid)</c> function call.</p> + + <note><p>The list <c>Args</c> no longer contains the actual arguments, + but the same number of atoms as the number of arguments; the first atom + is always <c>'Argument__1'</c>, the second <c>'Argument__2'</c>, and + so on. The reason is that the argument list could waste a significant + amount of memory, and if the argument list contained funs, it could + be impossible to upgrade the code for the module.</p> + + <p>If the process was spawned using a fun, <c>initial_call/1</c> no + longer returns the actual fun, but the module, function for the local + function implementing the fun, and the arity, for instance + <c>{some_module,-work/3-fun-0-,0}</c> (meaning that the fun was + created in the function <c>some_module:work/3</c>). + The reason is that keeping the fun would prevent code upgrade for the + module, and that a significant amount of memory could be wasted.</p> + </note> + </desc> + </func> + <func> + <name>translate_initial_call(Process) -> {Module,Function,Arity} | Fun</name> + <fsummary>Extract and translate the initial call of a <c>proc_lib</c>spawned process.</fsummary> + <type> + <v>Process = pid() | {X,Y,Z} | ProcInfo</v> + <v> X = Y = Z = int()</v> + <v> ProcInfo = term()</v> + <v>Module = Function = atom()</v> + <v>Arity = int()</v> + <v>Fun = fun() -> void()</v> + </type> + <desc> + <p>This function is used by the <c>c:i/0</c> and + <c>c:regs/0</c> functions in order to present process + information.</p> + <p>Extracts the initial call of a process that was started + using one of the spawn or start functions described above, + and translates it to more useful information. <c>Process</c> + can either be a pid, an integer tuple (from which a pid can + be created), or the process information of a process + <c>Pid</c> fetched through an <c>erlang:process_info(Pid)</c> + function call.</p> + <p>If the initial call is to one of the system defined behaviors + such as <c>gen_server</c> or <c>gen_event</c>, it is + translated to more useful information. If a <c>gen_server</c> + is spawned, the returned <c>Module</c> is the name of + the callback module and <c>Function</c> is <c>init</c> + (the function that initiates the new server).</p> + <p>A <c>supervisor</c> and a <c>supervisor_bridge</c> are also + <c>gen_server</c> processes. In order to return information + that this process is a supervisor and the name of the + call-back module, <c>Module</c> is <c>supervisor</c> and + <c>Function</c> is the name of the supervisor callback + module. <c>Arity</c> is <c>1</c> since the <c>init/1</c> + function is called initially in the callback module.</p> + <p>By default, <c>{proc_lib,init_p,5}</c> is returned if no + information about the initial call can be found. It is + assumed that the caller knows that the process has been + spawned with the <c>proc_lib</c> module.</p> + </desc> + </func> + <func> + <name>hibernate(Module, Function, Args)</name> + <fsummary>Hibernate a process until a message is sent to it</fsummary> + <type> + <v>Module = Function = atom()</v> + <v>Args = [term()]</v> + </type> + <desc> + <p>This function does the same as (and does call) the BIF + <seealso marker="erts:erlang#erlang:hibernate/3">hibernate/3</seealso>, + but ensures that exception handling and logging continues to + work as expected when the process wakes up. Always use this + function instead of the BIF for processes started using + <c>proc_lib</c> functions.</p> + </desc> + </func> + </funcs> + + <section> + <title>SEE ALSO</title> + <p><seealso marker="kernel:error_logger">error_logger(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/proplists.xml b/lib/stdlib/doc/src/proplists.xml new file mode 100644 index 0000000000..a218dcf1fe --- /dev/null +++ b/lib/stdlib/doc/src/proplists.xml @@ -0,0 +1,386 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2002</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>proplists</title> + <prepared>Patrik Nyblom</prepared> + <responsible>Kenneth Lundin</responsible> + <docno>1</docno> + <approved>Kenneth Lundin</approved> + <checked></checked> + <date>2002-09-28</date> + <rev>A</rev> + <file>proplists.sgml</file> + </header> + <module>proplists</module> + <modulesummary>Support functions for property lists</modulesummary> + <description> + <p>Property lists are ordinary lists containing entries in the form + of either tuples, whose first elements are keys used for lookup and + insertion, or atoms, which work as shorthand for tuples <c>{Atom, true}</c>. (Other terms are allowed in the lists, but are ignored + by this module.) If there is more than one entry in a list for a + certain key, the first occurrence normally overrides any later + (irrespective of the arity of the tuples).</p> + <p>Property lists are useful for representing inherited properties, + such as options passed to a function where a user may specify options + overriding the default settings, object properties, annotations, + etc.</p> + </description> + <funcs> + <func> + <name>append_values(Key, List) -> List</name> + <fsummary></fsummary> + <type> + <v>Key = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Similar to <c>get_all_values/2</c>, but each value is + wrapped in a list unless it is already itself a list, and the + resulting list of lists is concatenated. This is often useful for + "incremental" options; e.g., <c>append_values(a, [{a, [1,2]}, {b, 0}, {a, 3}, {c, -1}, {a, [4]}])</c> will return the list + <c>[1,2,3,4]</c>.</p> + </desc> + </func> + <func> + <name>compact(List) -> List</name> + <fsummary></fsummary> + <type> + <v>List = [term()]</v> + </type> + <desc> + <p>Minimizes the representation of all entries in the list. This is + equivalent to <c><![CDATA[[property(P) || P <- List]]]></c>.</p> + <p>See also: <c>property/1</c>, <c>unfold/1</c>.</p> + </desc> + </func> + <func> + <name>delete(Key, List) -> List</name> + <fsummary></fsummary> + <type> + <v>Key = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Deletes all entries associated with <c>Key</c> from + <c>List</c>.</p> + </desc> + </func> + <func> + <name>expand(Expansions, List) -> List</name> + <fsummary></fsummary> + <type> + <v>Key = term()</v> + <v>Expansions = [{Property,[term()]}]</v> + <v>Property = atom() | tuple()</v> + </type> + <desc> + <p>Expands particular properties to corresponding sets of + properties (or other terms). For each pair <c>{Property, Expansion}</c> in <c>Expansions</c>, if <c>E</c> is + the first entry in <c>List</c> with the same key as + <c>Property</c>, and <c>E</c> and <c>Property</c> + have equivalent normal forms, then <c>E</c> is replaced with + the terms in <c>Expansion</c>, and any following entries with + the same key are deleted from <c>List</c>.</p> + <p>For example, the following expressions all return <c>[fie, bar, baz, fum]</c>:</p> + <code type="none"> + expand([{foo, [bar, baz]}], + [fie, foo, fum]) + expand([{{foo, true}, [bar, baz]}], + [fie, foo, fum]) + expand([{{foo, false}, [bar, baz]}], + [fie, {foo, false}, fum])</code> + <p>However, no expansion is done in the following call:</p> + <code type="none"> + expand([{{foo, true}, [bar, baz]}], + [{foo, false}, fie, foo, fum])</code> + <p>because <c>{foo, false}</c> shadows <c>foo</c>.</p> + <p>Note that if the original property term is to be preserved in the + result when expanded, it must be included in the expansion list. The + inserted terms are not expanded recursively. If + <c>Expansions</c> contains more than one property with the same + key, only the first occurrence is used.</p> + <p>See also: <c>normalize/2</c>.</p> + </desc> + </func> + <func> + <name>get_all_values(Key, List) -> [term()]</name> + <fsummary></fsummary> + <type> + <v>Key = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Similar to <c>get_value/2</c>, but returns the list of + values for <em>all</em> entries <c>{Key, Value}</c> in + <c>List</c>. If no such entry exists, the result is the empty + list.</p> + <p>See also: <c>get_value/2</c>.</p> + </desc> + </func> + <func> + <name>get_bool(Key, List) -> bool()</name> + <fsummary></fsummary> + <type> + <v>Key = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns the value of a boolean key/value option. If + <c>lookup(Key, List)</c> would yield <c>{Key, true}</c>, + this function returns <c>true</c>; otherwise <c>false</c> + is returned.</p> + <p>See also: <c>get_value/2</c>, <c>lookup/2</c>.</p> + </desc> + </func> + <func> + <name>get_keys(List) -> [term()]</name> + <fsummary></fsummary> + <type> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns an unordered list of the keys used in <c>List</c>, + not containing duplicates.</p> + </desc> + </func> + <func> + <name>get_value(Key, List) -> term()</name> + <fsummary></fsummary> + <type> + <v>Key = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Equivalent to <c>get_value(Key, List, undefined)</c>.</p> + </desc> + </func> + <func> + <name>get_value(Key, List, Default) -> term()</name> + <fsummary></fsummary> + <type> + <v>Key = term()</v> + <v>Default = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns the value of a simple key/value property in + <c>List</c>. If <c>lookup(Key, List)</c> would yield + <c>{Key, Value}</c>, this function returns the corresponding + <c>Value</c>, otherwise <c>Default</c> is returned.</p> + <p>See also: <c>get_all_values/2</c>, <c>get_bool/2</c>, + <c>get_value/2</c>, <c>lookup/2</c>.</p> + </desc> + </func> + <func> + <name>is_defined(Key, List) -> bool()</name> + <fsummary></fsummary> + <type> + <v>Key = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>List</c> contains at least + one entry associated with <c>Key</c>, otherwise + <c>false</c> is returned.</p> + </desc> + </func> + <func> + <name>lookup(Key, List) -> none | tuple()</name> + <fsummary></fsummary> + <type> + <v>Key = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns the first entry associated with <c>Key</c> in + <c>List</c>, if one exists, otherwise returns + <c>none</c>. For an atom <c>A</c> in the list, the tuple + <c>{A, true}</c> is the entry associated with <c>A</c>.</p> + <p>See also: <c>get_bool/2</c>, <c>get_value/2</c>, + <c>lookup_all/2</c>.</p> + </desc> + </func> + <func> + <name>lookup_all(Key, List) -> [tuple()]</name> + <fsummary></fsummary> + <type> + <v>Key = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns the list of all entries associated with <c>Key</c> + in <c>List</c>. If no such entry exists, the result is the + empty list.</p> + <p>See also: <c>lookup/2</c>.</p> + </desc> + </func> + <func> + <name>normalize(List, Stages) -> List</name> + <fsummary></fsummary> + <type> + <v>List = [term()]</v> + <v>Stages = [Operation]</v> + <v>Operation = {aliases, Aliases} | {negations, Negations} | {expand, Expansions}</v> + <v>Aliases = [{Key, Key}]</v> + <v>Negations = [{Key, Key}]</v> + <v>Key = term()</v> + <v>Expansions = [{Property, [term()]}]</v> + <v>Property = atom() | tuple()</v> + </type> + <desc> + <p>Passes <c>List</c> through a sequence of + substitution/expansion stages. For an <c>aliases</c> operation, + the function <c>substitute_aliases/2</c> is applied using the + given list of aliases; for a <c>negations</c> operation, + <c>substitute_negations/2</c> is applied using the given + negation list; for an <c>expand</c> operation, the function + <c>expand/2</c> is applied using the given list of expansions. + The final result is automatically compacted (cf. + <c>compact/1</c>).</p> + <p>Typically you want to substitute negations first, then aliases, + then perform one or more expansions (sometimes you want to pre-expand + particular entries before doing the main expansion). You might want + to substitute negations and/or aliases repeatedly, to allow such + forms in the right-hand side of aliases and expansion lists.</p> + <p>See also: <c>compact/1</c>, <c>expand/2</c>, + <c>substitute_aliases/2</c>, <c>substitute_negations/2</c>.</p> + </desc> + </func> + <func> + <name>property(Property) -> Property</name> + <fsummary></fsummary> + <type> + <v>Property = atom() | tuple()</v> + </type> + <desc> + <p>Creates a normal form (minimal) representation of a property. If + <c>Property</c> is <c>{Key, true}</c> where <c>Key</c> is + an atom, this returns <c>Key</c>, otherwise the whole term + <c>Property</c> is returned.</p> + <p>See also: <c>property/2</c>.</p> + </desc> + </func> + <func> + <name>property(Key, Value) -> Property</name> + <fsummary></fsummary> + <type> + <v>Key = term()</v> + <v>Value = term()</v> + <v>Property = atom() | tuple()</v> + </type> + <desc> + <p>Creates a normal form (minimal) representation of a simple + key/value property. Returns <c>Key</c> if <c>Value</c> is + <c>true</c> and <c>Key</c> is an atom, otherwise a tuple + <c>{Key, Value}</c> is returned.</p> + <p>See also: <c>property/1</c>.</p> + </desc> + </func> + <func> + <name>split(List, Keys) -> {Lists, Rest}</name> + <fsummary></fsummary> + <type> + <v>List = [term()]</v> + <v>Keys = [term()]</v> + <v>Lists = [[term()]]</v> + <v>Rest = [term()]</v> + </type> + <desc> + <p>Partitions <c>List</c> into a list of sublists and a + remainder. <c>Lists</c> contains one sublist for each key in + <c>Keys</c>, in the corresponding order. The relative order of + the elements in each sublist is preserved from the original + <c>List</c>. <c>Rest</c> contains the elements in + <c>List</c> that are not associated with any of the given keys, + also with their original relative order preserved.</p> + <p>Example: + split([{c, 2}, {e, 1}, a, {c, 3, 4}, d, {b, 5}, b], [a, b, c])</p> + <p>returns</p> + <p>{[[a], [{b, 5}, b],[{c, 2}, {c, 3, 4}]], [{e, 1}, d]}</p> + </desc> + </func> + <func> + <name>substitute_aliases(Aliases, List) -> List</name> + <fsummary></fsummary> + <type> + <v>Aliases = [{Key, Key}]</v> + <v>Key = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Substitutes keys of properties. For each entry in + <c>List</c>, if it is associated with some key <c>K1</c> + such that <c>{K1, K2}</c> occurs in <c>Aliases</c>, the + key of the entry is changed to <c>Key2</c>. If the same + <c>K1</c> occurs more than once in <c>Aliases</c>, only + the first occurrence is used.</p> + <p>Example: <c>substitute_aliases([{color, colour}], L)</c> + will replace all tuples <c>{color, ...}</c> in <c>L</c> + with <c>{colour, ...}</c>, and all atoms <c>color</c> + with <c>colour</c>.</p> + <p>See also: <c>normalize/2</c>, <c>substitute_negations/2</c>.</p> + </desc> + </func> + <func> + <name>substitute_negations(Negations, List) -> List</name> + <fsummary></fsummary> + <type> + <v>Negations = [{Key, Key}]</v> + <v>Key = term()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Substitutes keys of boolean-valued properties and + simultaneously negates their values. For each entry in + <c>List</c>, if it is associated with some key <c>K1</c> + such that <c>{K1, K2}</c> occurs in <c>Negations</c>, then + if the entry was <c>{K1, true}</c> it will be replaced with + <c>{K2, false}</c>, otherwise it will be replaced with + <c>{K2, true}</c>, thus changing the name of the option and + simultaneously negating the value given by + <c>get_bool(List)</c>. If the same <c>K1</c> occurs more + than once in <c>Negations</c>, only the first occurrence is + used.</p> + <p>Example: <c>substitute_negations([{no_foo, foo}], L)</c> + will replace any atom <c>no_foo</c> or tuple + <c>{no_foo, true}</c> in <c>L</c> with <c>{foo, false}</c>, + and any other tuple <c>{no_foo, ...}</c> with + <c>{foo, true}</c>.</p> + <p>See also: <c>get_bool/2</c>, <c>normalize/2</c>, + <c>substitute_aliases/2</c>.</p> + </desc> + </func> + <func> + <name>unfold(List) -> List</name> + <fsummary></fsummary> + <type> + <v>List = [term()]</v> + </type> + <desc> + <p>Unfolds all occurrences of atoms in <c>List</c> to tuples + <c>{Atom, true}</c>.</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/qlc.xml b/lib/stdlib/doc/src/qlc.xml new file mode 100644 index 0000000000..da24ee9914 --- /dev/null +++ b/lib/stdlib/doc/src/qlc.xml @@ -0,0 +1,1486 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2004</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>qlc</title> + <prepared>Hans Bolinder</prepared> + <responsible>nobody</responsible> + <docno></docno> + <approved>nobody</approved> + <checked>no</checked> + <date>2004-08-25</date> + <rev>PA1</rev> + <file>qlc.sgml</file> + </header> + <module>qlc</module> + <modulesummary>Query Interface to Mnesia, ETS, Dets, etc</modulesummary> + <description> + <p>The <c>qlc</c> module provides a query interface to Mnesia, ETS, + Dets and other data structures that implement an iterator style + traversal of objects. </p> + </description> + + <section><title>Overview</title> + + <p>The <c>qlc</c> module implements a query interface to <em>QLC + tables</em>. Typical QLC tables are ETS, Dets, and Mnesia + tables. There is also support for user defined tables, see the + <seealso marker="#implementing_a_qlc_table">Implementing a QLC + table</seealso> section. A <em>query</em> is stated using + <em>Query List Comprehensions</em> (QLCs). The answers to a + query are determined by data in QLC tables that fulfill the + constraints expressed by the QLCs of the query. QLCs are similar + to ordinary list comprehensions as described in the Erlang + Reference Manual and Programming Examples except that variables + introduced in patterns cannot be used in list expressions. In + fact, in the absence of optimizations and options such as + <c>cache</c> and <c>unique</c> (see below), every QLC free of + QLC tables evaluates to the same list of answers as the + identical ordinary list comprehension. </p> + + <p>While ordinary list comprehensions evaluate to lists, calling + <seealso marker="#q">qlc:q/1,2</seealso> returns a <em>Query + Handle</em>. To obtain all the answers to a query, <seealso + marker="#eval">qlc:eval/1,2</seealso> should be called with the + query handle as first argument. Query handles are essentially + functional objects ("funs") created in the module calling <c>q/1,2</c>. + As the funs refer to the module's code, one should + be careful not to keep query handles too long if the module's + code is to be replaced. + Code replacement is described in the <seealso + marker="doc/reference_manual:code_loading">Erlang Reference + Manual</seealso>. The list of answers can also be traversed in + chunks by use of a <em>Query Cursor</em>. Query cursors are + created by calling <seealso + marker="#cursor">qlc:cursor/1,2</seealso> with a query handle as + first argument. Query cursors are essentially Erlang processes. + One answer at a time is sent from the query cursor process to + the process that created the cursor.</p> + + </section> + + <section><title>Syntax</title> + + <p>Syntactically QLCs have the same parts as ordinary list + comprehensions:</p> + + <code type="none">[Expression || Qualifier1, Qualifier2, ...]</code> + + <p><c>Expression</c> (the <em>template</em>) is an arbitrary + Erlang expression. Qualifiers are either <em>filters</em> or + <em>generators</em>. Filters are Erlang expressions returning + <c>bool()</c>. Generators have the form + <c><![CDATA[Pattern <- ListExpression]]></c>, where + <c>ListExpression</c> is an expression evaluating to a query + handle or a list. Query handles are returned from + <c>qlc:table/2</c>, <c>qlc:append/1,2</c>, <c>qlc:sort/1,2</c>, + <c>qlc:keysort/2,3</c>, <c>qlc:q/1,2</c>, and + <c>qlc:string_to_handle/1,2,3</c>.</p> + + </section> + + <section><title>Evaluation</title> + + <p>The evaluation of a query handle begins by the inspection of + options and the collection of information about tables. As a + result qualifiers are modified during the optimization phase. + Next all list expressions are evaluated. If a cursor has been + created evaluation takes place in the cursor process. For those + list expressions that are QLCs, the list expressions of the + QLCs' generators are evaluated as well. One has to be careful if + list expressions have side effects since the order in which list + expressions are evaluated is unspecified. Finally the answers + are found by evaluating the qualifiers from left to right, + backtracking when some filter returns <c>false</c>, or + collecting the template when all filters return <c>true</c>.</p> + + <p>Filters that do not return <c>bool()</c> but fail are handled + differently depending on their syntax: if the filter is a guard + it returns <c>false</c>, otherwise the query evaluation fails. + This behavior makes it possible for the <c>qlc</c> module to do + some optimizations without affecting the meaning of a query. For + example, when testing some position of a table and one or more + constants for equality, only + the objects with equal values are candidates for further + evaluation. The other objects are guaranteed to make the filter + return <c>false</c>, but never fail. The (small) set of + candidate objects can often be found by looking up some key + values of the table or by traversing the table using a match + specification. It is necessary to place the guard filters + immediately after the table's generator, otherwise the candidate + objects will not be restricted to a small set. The reason is + that objects that could make the query evaluation fail must not + be excluded by looking up a key or running a match + specification.</p> + + </section> + + <section><title>Join</title> + + <p>The <c>qlc</c> module supports fast join of two query handles. + Fast join is possible if some position <c>P1</c> of one query + handler and some position <c>P2</c> of another query handler are + tested for equality. Two fast join methods have been + implemented:</p> + + <list type="bulleted"> + <item>Lookup join traverses all objects of one query handle and + finds objects of the other handle (a QLC table) such that the + values at <c>P1</c> and <c>P2</c> match or compare equal. + The <c>qlc</c> module does not create + any indices but looks up values using the key position and + the indexed positions of the QLC table. + </item> + <item>Merge join sorts the objects of each query handle if + necessary and filters out objects where the values at + <c>P1</c> and <c>P2</c> do not compare equal. If there are + many objects with the same value of <c>P2</c> a temporary + file will be used for the equivalence classes. + </item> + </list> + + <p>The <c>qlc</c> module warns at compile time if a QLC + combines query handles in such a way that more than one join is + possible. In other words, there is no query planner that can + choose a good order between possible join operations. It is up + to the user to order the joins by introducing query handles.</p> + + <p>The join is to be expressed as a guard filter. The filter must + be placed immediately after the two joined generators, possibly + after guard filters that use variables from no other generators + but the two joined generators. The <c>qlc</c> module inspects + the operands of + <c>=:=/2</c>, <c>==/2</c>, <c>is_record/2</c>, <c>element/2</c>, + and logical operators (<c>and/2</c>, <c>or/2</c>, + <c>andalso/2</c>, <c>orelse/2</c>, <c>xor/2</c>) when + determining which joins to consider.</p> + + </section> + + <section><title>Common options</title> + + <p>The following options are accepted by <c>cursor/2</c>, + <c>eval/2</c>, <c>fold/4</c>, and <c>info/2</c>:</p> + + <list type="bulleted"> + <item><c>{cache_all, Cache}</c> where <c>Cache</c> is + equal to <c>ets</c> or <c>list</c> adds a + <c>{cache, Cache}</c> option to every list expression + of the query except tables and lists. Default is + <c>{cache_all, no}</c>. The option <c>cache_all</c> is + equivalent to <c>{cache_all, ets}</c>. + </item> + <item><c>{max_list_size, MaxListSize}</c> <marker + id="max_list_size"></marker> where <c>MaxListSize</c> is the + size in bytes of terms on the external format. If the + accumulated size of collected objects exceeds + <c>MaxListSize</c> the objects are written onto a temporary + file. This option is used by the <c>{cache, list}</c> + option as well as by the merge join method. Default is + 512*1024 bytes. + </item> + <item><c>{tmpdir_usage, TmpFileUsage}</c> determines the + action taken when <c>qlc</c> is about to create temporary + files on the directory set by the <c>tmpdir</c> option. If the + value is <c>not_allowed</c> an error tuple is returned, + otherwise temporary files are created as needed. Default is + <c>allowed</c> which means that no further action is taken. + The values <c>info_msg</c>, <c>warning_msg</c>, and + <c>error_msg</c> mean that the function with the corresponding + name in the module <c>error_logger</c> is called for printing + some information (currently the stacktrace). + </item> + <item><c>{tmpdir, TempDirectory}</c> sets the directory used by + merge join for temporary files and by the + <c>{cache, list}</c> option. The option also overrides + the <c>tmpdir</c> option of <c>keysort/3</c> and + <c>sort/2</c>. The default value is <c>""</c> which means that + the directory returned by <c>file:get_cwd()</c> is used. + </item> + <item><c>{unique_all, true}</c> adds a + <c>{unique, true}</c> option to every list expression of + the query. Default is <c>{unique_all, false}</c>. The + option <c>unique_all</c> is equivalent to + <c>{unique_all, true}</c>. + </item> + </list> + + </section> + + <section><title>Common data types</title> + + <list type="bulleted"> + <item><p><c>QueryCursor = {qlc_cursor, term()}</c></p> + </item> + <item><p><c>QueryHandle = {qlc_handle, term()}</c></p> + </item> + <item><p><c>QueryHandleOrList = QueryHandle | list()</c></p> + </item> + <item><p><c>Answers = [Answer]</c></p> + </item> + <item><p><c>Answer = term()</c></p> + </item> + <item><p><c>AbstractExpression = </c> - parse trees + for Erlang expressions, see the <seealso + marker="erts:absform">abstract format</seealso> + documentation in the ERTS User's Guide -</p> + </item> + <item><p><c>MatchExpression = </c> + - match specifications, see the <seealso + marker="erts:match_spec">match specification</seealso> + documentation in the ERTS User's Guide and <seealso + marker="ms_transform">ms_transform(3)</seealso> -</p> + </item> + <item><p><c>SpawnOptions = default | spawn_options()</c></p> + </item> + <item><p><c>SortOptions = [SortOption] | SortOption</c></p> + </item> + <item><p><c>SortOption = {compressed, bool()} + | {no_files, NoFiles} + | {order, Order} + | {size, Size} + | {tmpdir, TempDirectory} + | {unique, bool()} </c> + - see <seealso + marker="file_sorter">file_sorter(3)</seealso> -</p> + </item> + <item><p><c>Order = ascending | descending | OrderFun</c></p> + </item> + <item><p><c>OrderFun = fun(term(), term()) -> bool()</c></p> + </item> + <item><p><c>TempDirectory = "" | filename()</c></p> + </item> + <item><p><c>Size = int() > 0</c></p> + </item> + <item><p><c>NoFiles = int() > 1</c></p> + </item> + <item><p><c>KeyPos = int() > 0 | [int() > 0]</c></p> + </item> + <item><p><c>MaxListSize = int() >= 0</c></p> + </item> + <item><p><c>bool() = true | false</c></p> + </item> + <item><p><c>Cache = ets | list | no</c></p> + </item> + <item><p><c>TmpFileUsage = allowed | not_allowed | info_msg + | warning_msg | error_msg</c></p> + </item> + <item><p><c>filename() = </c> - see <seealso + marker="filename">filename(3)</seealso> -</p> + </item> + <item><p><c>spawn_options() = </c> - see <seealso + marker="erts:erlang">erlang(3)</seealso> -</p> + </item> + + </list> + + </section> + + <section><title>Getting started</title> + + <p><marker id="getting_started"></marker> As already mentioned + queries are stated in the list comprehension syntax as described + in the <seealso marker="doc/reference_manual:expressions">Erlang + Reference Manual</seealso>. In the following some familiarity + with list comprehensions is assumed. There are examples in + <seealso + marker="doc/programming_examples:list_comprehensions">Programming + Examples</seealso> that can get you started. It should be + stressed that list comprehensions do not add any computational + power to the language; anything that can be done with list + comprehensions can also be done without them. But they add a + syntax for expressing simple search problems which is compact + and clear once you get used to it.</p> + + <p>Many list comprehension expressions can be evaluated by the + <c>qlc</c> module. Exceptions are expressions such that + variables introduced in patterns (or filters) are used in some + generator later in the list comprehension. As an example + consider an implementation of lists:append(L): + <c><![CDATA[[X ||Y <- L, X <- Y]]]></c>. + Y is introduced in the first generator and used in the second. + The ordinary list comprehension is normally to be preferred when + there is a choice as to which to use. One difference is that + <c>qlc:eval/1,2</c> collects answers in a list which is finally + reversed, while list comprehensions collect answers on the stack + which is finally unwound.</p> + + <p>What the <c>qlc</c> module primarily adds to list + comprehensions is that data can be read from QLC tables in small + chunks. A QLC table is created by calling <c>qlc:table/2</c>. + Usually <c>qlc:table/2</c> is not called directly from the query + but via an interface function of some data structure. There are + a few examples of such functions in Erlang/OTP: + <c>mnesia:table/1,2</c>, <c>ets:table/1,2</c>, and + <c>dets:table/1,2</c>. For a given data structure there can be + several functions that create QLC tables, but common for all + these functions is that they return a query handle created by + <c>qlc:table/2</c>. Using the QLC tables provided by OTP is + probably sufficient in most cases, but for the more advanced + user the section <seealso + marker="#implementing_a_qlc_table">Implementing a QLC + table</seealso> describes the implementation of a function + calling <c>qlc:table/2</c>.</p> + + <p>Besides <c>qlc:table/2</c> there are other functions that + return query handles. They might not be used as often as tables, + but are useful from time to time. <c>qlc:append</c> traverses + objects from several tables or lists after each other. If, for + instance, you want to traverse all answers to a query QH and + then finish off by a term <c>{finished}</c>, you can do that by + calling <c>qlc:append(QH, [{finished}])</c>. <c>append</c> first + returns all objects of QH, then <c>{finished}</c>. If there is + one tuple <c>{finished}</c> among the answers to QH it will be + returned twice from <c>append</c>.</p> + + <p>As another example, consider concatenating the answers to two + queries QH1 and QH2 while removing all duplicates. The means to + accomplish this is to use the <c>unique</c> option:</p> + + <code type="none"><![CDATA[ +qlc:q([X || X <- qlc:append(QH1, QH2)], {unique, true})]]></code> + + <p>The cost is substantial: every returned answer will be stored + in an ETS table. Before returning an answer it is looked up in + the ETS table to check if it has already been returned. Without + the <c>unique</c> options all answers to QH1 would be returned + followed by all answers to QH2. The <c>unique</c> options keeps + the order between the remaining answers.</p> + + <p>If the order of the answers is not important there is the + alternative to sort the answers uniquely:</p> + + <code type="none"><![CDATA[ +qlc:sort(qlc:q([X || X <- qlc:append(QH1, QH2)], {unique, true})).]]></code> + + <p>This query also removes duplicates but the answers will be + sorted. If there are many answers temporary files will be used. + Note that in order to get the first unique answer all answers + have to be found and sorted. Both alternatives find duplicates + by comparing answers, that is, if A1 and A2 are answers found in + that order, then A2 is a removed if A1 == A2.</p> + + <p>To return just a few answers cursors can be used. The following + code returns no more than five answers using an ETS table for + storing the unique answers:</p> + + <code type="none"><![CDATA[ +C = qlc:cursor(qlc:q([X || X <- qlc:append(QH1, QH2)],{unique,true})), +R = qlc:next_answers(C, 5), +ok = qlc:delete_cursor(C), +R.]]></code> + + <p>Query list comprehensions are convenient for stating + constraints on data from two or more tables. An example that + does a natural join on two query handles on position 2:</p> + + <code type="none"><![CDATA[ +qlc:q([{X1,X2,X3,Y1} || + {X1,X2,X3} <- QH1, + {Y1,Y2} <- QH2, + X2 =:= Y2])]]></code> + + <p>The <c>qlc</c> module will evaluate this differently depending on + the query + handles <c>QH1</c> and <c>QH2</c>. If, for example, <c>X2</c> is + matched against the key of a QLC table the lookup join method + will traverse the objects of <c>QH2</c> while looking up key + values in the table. On the other hand, if neither <c>X2</c> nor + <c>Y2</c> is matched against the key or an indexed position of a + QLC table, the merge join method will make sure that <c>QH1</c> + and <c>QH2</c> are both sorted on position 2 and next do the + join by traversing the objects one by one.</p> + + <p>The <c>join</c> option can be used to force the <c>qlc</c> module + to use a + certain join method. For the rest of this section it is assumed + that the excessively slow join method called "nested loop" has + been chosen:</p> + + <code type="none"><![CDATA[ +qlc:q([{X1,X2,X3,Y1} || + {X1,X2,X3} <- QH1, + {Y1,Y2} <- QH2, + X2 =:= Y2], + {join, nested_loop})]]></code> + + <p>In this case the filter will be applied to every possible pair + of answers to QH1 and QH2, one at a time. If there are M answers + to QH1 and N answers to QH2 the filter will be run M*N + times.</p> + + <p>If QH2 is a call to the function for <c>gb_trees</c> as defined + in the <seealso marker="#implementing_a_qlc_table">Implementing + a QLC table</seealso> section, <c>gb_table:table/1</c>, the + iterator for the gb-tree will be initiated for each answer to + QH1 after which the objects of the gb-tree will be returned one + by one. This is probably the most efficient way of traversing + the table in that case since it takes minimal computational + power to get the following object. But if QH2 is not a table but + a more complicated QLC, it can be more efficient use some RAM + memory for collecting the answers in a cache, particularly if + there are only a few answers. It must then be assumed that + evaluating QH2 has no side effects so that the meaning of the + query does not change if QH2 is evaluated only once. One way of + caching the answers is to evaluate QH2 first of all and + substitute the list of answers for QH2 in the query. Another way + is to use the <c>cache</c> option. It is stated like this:</p> + + <code type="none"><![CDATA[ +QH2' = qlc:q([X || X <- QH2], {cache, ets})]]></code> + + <p>or just</p> + + <code type="none"><![CDATA[ +QH2' = qlc:q([X || X <- QH2], cache)]]></code> + + <p>The effect of the <c>cache</c> option is that when the + generator QH2' is run the first time every answer is stored in + an ETS table. When next answer of QH1 is tried, answers to QH2' + are copied from the ETS table which is very fast. As for the + <c>unique</c> option the cost is a possibly substantial amount + of RAM memory. The <c>{cache, list}</c> option offers the + possibility to store the answers in a list on the process heap. + While this has the potential of being faster than ETS tables + since there is no need to copy answers from the table it can + often result in slower evaluation due to more garbage + collections of the process' heap as well as increased RAM memory + consumption due to larger heaps. Another drawback with cache + lists is that if the size of the list exceeds a limit a + temporary file will be used. Reading the answers from a file is + very much slower than copying them from an ETS table. But if the + available RAM memory is scarce setting the <seealso + marker="#max_list_size">limit</seealso> to some low value is an + alternative.</p> + + <p>There is an option <c>cache_all</c> that can be set to + <c>ets</c> or <c>list</c> when evaluating a query. It adds a + <c>cache</c> or <c>{cache, list}</c> option to every list + expression except QLC tables and lists on all levels of the + query. This can be used for testing if caching would improve + efficiency at all. If the answer is yes further testing is + needed to pinpoint the generators that should be cached.</p> + + </section> + + <section><title>Implementing a QLC table</title> + + <p><marker id="implementing_a_qlc_table"></marker>As an example of + how to use the <seealso marker="#q">qlc:table/2</seealso> + function the implementation of a QLC table for the <seealso + marker="gb_trees">gb_trees</seealso> module is given:</p> + + <code type="none"><![CDATA[ +-module(gb_table). + +-export([table/1]). + +table(T) -> + TF = fun() -> qlc_next(gb_trees:next(gb_trees:iterator(T))) end, + InfoFun = fun(num_of_objects) -> gb_trees:size(T); + (keypos) -> 1; + (is_sorted_key) -> true; + (is_unique_objects) -> true; + (_) -> undefined + end, + LookupFun = + fun(1, Ks) -> + lists:flatmap(fun(K) -> + case gb_trees:lookup(K, T) of + {value, V} -> [{K,V}]; + none -> [] + end + end, Ks) + end, + FormatFun = + fun({all, NElements, ElementFun}) -> + ValsS = io_lib:format("gb_trees:from_orddict(~w)", + [gb_nodes(T, NElements, ElementFun)]), + io_lib:format("gb_table:table(~s)", [ValsS]); + ({lookup, 1, KeyValues, _NElements, ElementFun}) -> + ValsS = io_lib:format("gb_trees:from_orddict(~w)", + [gb_nodes(T, infinity, ElementFun)]), + io_lib:format("lists:flatmap(fun(K) -> " + "case gb_trees:lookup(K, ~s) of " + "{value, V} -> [{K,V}];none -> [] end " + "end, ~w)", + [ValsS, [ElementFun(KV) || KV <- KeyValues]]) + end, + qlc:table(TF, [{info_fun, InfoFun}, {format_fun, FormatFun}, + {lookup_fun, LookupFun},{key_equality,'=='}]). + +qlc_next({X, V, S}) -> + [{X,V} | fun() -> qlc_next(gb_trees:next(S)) end]; +qlc_next(none) -> + []. + +gb_nodes(T, infinity, ElementFun) -> + gb_nodes(T, -1, ElementFun); +gb_nodes(T, NElements, ElementFun) -> + gb_iter(gb_trees:iterator(T), NElements, ElementFun). + +gb_iter(_I, 0, _EFun) -> + '...'; +gb_iter(I0, N, EFun) -> + case gb_trees:next(I0) of + {X, V, I} -> + [EFun({X,V}) | gb_iter(I, N-1, EFun)]; + none -> + [] + end.]]></code> + + <p><c>TF</c> is the traversal function. The <c>qlc</c> module + requires that there is a way of traversing all objects of the + data structure; in <c>gb_trees</c> there is an iterator function + suitable for that purpose. Note that for each object returned a + new fun is created. As long as the list is not terminated by + <c>[]</c> it is assumed that the tail of the list is a nullary + function and that calling the function returns further objects + (and functions).</p> + + <p>The lookup function is optional. It is assumed that the lookup + function always finds values much faster than it would take to + traverse the table. The first argument is the position of the + key. Since <c>qlc_next</c> returns the objects as + {Key, Value} pairs the position is 1. Note that the lookup + function should return {Key, Value} pairs, just as the + traversal function does.</p> + + <p>The format function is also optional. It is called by + <c>qlc:info</c> to give feedback at runtime of how the query + will be evaluated. One should try to give as good feedback as + possible without showing too much details. In the example at + most 7 objects of the table are shown. The format function + handles two cases: <c>all</c> means that all objects of the + table will be traversed; <c>{lookup, 1, KeyValues}</c> + means that the lookup function will be used for looking up key + values.</p> + + <p>Whether the whole table will be traversed or just some keys + looked up depends on how the query is stated. If the query has + the form</p> + + <code type="none"><![CDATA[ +qlc:q([T || P <- LE, F])]]></code> + + <p>and P is a tuple, the <c>qlc</c> module analyzes P and F in + compile time to find positions of the tuple P that are tested + for equality to constants. If such a position at runtime turns + out to be the key position, the lookup function can be used, + otherwise all objects of the table have to be traversed. It is + the info function <c>InfoFun</c> that returns the key position. + There can be indexed positions as well, also returned by the + info function. An index is an extra table that makes lookup on + some position fast. Mnesia maintains indices upon request, + thereby introducing so called secondary keys. The <c>qlc</c> + module prefers to look up objects using the key before secondary + keys regardless of the number of constants to look up.</p> + + </section> + + <section><title>Key equality</title> + + <p>In Erlang there are two operators for testing term equality, + namely <c>==/2</c> and <c>=:=/2</c>. The difference between them + is all about the integers that can be represented by floats. For + instance, <c>2 == 2.0</c> evaluates to + <c>true</c> while <c>2 =:= 2.0</c> evaluates to <c>false</c>. + Normally this is a minor issue, but the <c>qlc</c> module cannot + ignore the difference, which affects the user's choice of + operators in QLCs.</p> + + <p>If the <c>qlc</c> module can find out at compile time that some + constant is free of integers, it does not matter which one of + <c>==/2</c> or <c>=:=/2</c> is used:</p> + + <pre> +1> <input>E1 = ets:new(t, [set]), % uses =:=/2 for key equality</input> +<input>Q1 = qlc:q([K ||</input> +<input>{K} <- ets:table(E1),</input> +<input>K == 2.71 orelse K == a]),</input> +<input>io:format("~s~n", [qlc:info(Q1)]).</input> +ets:match_spec_run(lists:flatmap(fun(V) -> + ets:lookup(20493, V) + end, + [a,2.71]), + ets:match_spec_compile([{{'$1'},[],['$1']}]))</pre> + + <p>In the example the <c>==/2</c> operator has been handled + exactly as <c>=:=/2</c> would have been handled. On the other + hand, if it cannot be determined at compile time that some + constant is free of integers and the table uses <c>=:=/2</c> + when comparing keys for equality (see the option <seealso + marker="#key_equality">key_equality</seealso>), the + <c>qlc</c> module will not try to look up the constant. The + reason is that there is in the general case no upper limit on + the number of key values that can compare equal to such a + constant; every combination of integers and floats has to be + looked up:</p> + + <pre> +2> <input>E2 = ets:new(t, [set]),</input> +<input>true = ets:insert(E2, [{{2,2},a},{{2,2.0},b},{{2.0,2},c}]),</input> +<input>F2 = fun(I) -></input> +<input>qlc:q([V || {K,V} <- ets:table(E2), K == I])</input> +<input>end,</input> +<input>Q2 = F2({2,2}),</input> +<input>io:format("~s~n", [qlc:info(Q2)]).</input> +ets:table(53264, + [{traverse, + {select,[{{'$1','$2'},[{'==','$1',{const,{2,2}}}],['$2']}]}}]) +3> <input>lists:sort(qlc:e(Q2)).</input> +[a,b,c]</pre> + + <p>Looking up just <c>{2,2}</c> would not return <c>b</c> and + <c>c</c>.</p> + + <p>If the table uses <c>==/2</c> when comparing keys for equality, + the <c>qlc</c> module will look up the constant regardless of + which operator is used in the QLC. However, <c>==/2</c> is to + be preferred:</p> + + <pre> +4> <input>E3 = ets:new(t, [ordered_set]), % uses ==/2 for key equality</input> +<input>true = ets:insert(E3, [{{2,2.0},b}]),</input> +<input>F3 = fun(I) -></input> +<input>qlc:q([V || {K,V} <- ets:table(E3), K == I])</input> +<input>end,</input> +<input>Q3 = F3({2,2}),</input> +<input>io:format("~s~n", [qlc:info(Q3)]).</input> +ets:match_spec_run(ets:lookup(86033, {2,2}), + ets:match_spec_compile([{{'$1','$2'},[],['$2']}])) +5> <input>qlc:e(Q3).</input> +[b]</pre> + + <p>Lookup join is handled analogously to lookup of constants in a + table: if the join operator is <c>==/2</c> and the table where + constants are to be looked up uses <c>=:=/2</c> when testing + keys for equality, the <c>qlc</c> module will not consider + lookup join for that table.</p> + + </section> + + <funcs> + + <func> + <name>append(QHL) -> QH</name> + <fsummary>Return a query handle.</fsummary> + <type> + <v>QHL = [QueryHandleOrList]</v> + <v>QH = QueryHandle</v> + </type> + <desc> + <p>Returns a query handle. When evaluating the query handle + <c>QH</c> all answers to the first query handle in + <c>QHL</c> is returned followed by all answers to the rest + of the query handles in <c>QHL</c>.</p> + </desc> + </func> + + <func> + <name>append(QH1, QH2) -> QH3</name> + <fsummary>Return a query handle.</fsummary> + <type> + <v>QH1 = QH2 = QueryHandleOrList</v> + <v>QH3 = QueryHandle</v> + </type> + <desc> + <p>Returns a query handle. When evaluating the query handle + <c>QH3</c> all answers to <c>QH1</c> are returned followed + by all answers to <c>QH2</c>.</p> + + <p><c>append(QH1, QH2)</c> is equivalent to + <c>append([QH1, QH2])</c>.</p> + </desc> + </func> + + <func> + <name>cursor(QueryHandleOrList [, Options]) -> QueryCursor</name> + <fsummary>Create a query cursor.</fsummary> + <type> + <v>Options = [Option] | Option</v> + <v>Option = {cache_all, Cache} | cache_all + | {max_list_size, MaxListSize} + | {spawn_options, SpawnOptions} + | {tmpdir_usage, TmpFileUsage} + | {tmpdir, TempDirectory} + | {unique_all, bool()} | unique_all</v> + </type> + <desc> + <p><marker id="cursor"></marker>Creates a query cursor and + makes the calling process the owner of the cursor. The + cursor is to be used as argument to <c>next_answers/1,2</c> + and (eventually) <c>delete_cursor/1</c>. Calls + <c>erlang:spawn_opt</c> to spawn and link a process which + will evaluate the query handle. The value of the option + <c>spawn_options</c> is used as last argument when calling + <c>spawn_opt</c>. The default value is <c>[link]</c>.</p> + + <pre> +1> <input>QH = qlc:q([{X,Y} || X <- [a,b], Y <- [1,2]]),</input> +<input>QC = qlc:cursor(QH),</input> +<input>qlc:next_answers(QC, 1).</input> +[{a,1}] +2> <input>qlc:next_answers(QC, 1).</input> +[{a,2}] +3> <input>qlc:next_answers(QC, all_remaining).</input> +[{b,1},{b,2}] +4> <input>qlc:delete_cursor(QC).</input> +ok</pre> + </desc> + </func> + + <func> + <name>delete_cursor(QueryCursor) -> ok</name> + <fsummary>Delete a query cursor.</fsummary> + <desc> + <p>Deletes a query cursor. Only the owner of the cursor can + delete the cursor.</p> + </desc> + </func> + + <func> + <name>eval(QueryHandleOrList [, Options]) -> Answers | Error</name> + <name>e(QueryHandleOrList [, Options]) -> Answers</name> + <fsummary>Return all answers to a query.</fsummary> + <type> + <v>Options = [Option] | Option</v> + <v>Option = {cache_all, Cache} | cache_all + | {max_list_size, MaxListSize} + | {tmpdir_usage, TmpFileUsage} + | {tmpdir, TempDirectory} + | {unique_all, bool()} | unique_all</v> + <v>Error = {error, module(), Reason}</v> + <v>Reason = - as returned by file_sorter(3) -</v> + </type> + <desc> + <p><marker id="eval"></marker>Evaluates a query handle in the + calling process and collects all answers in a list.</p> + + <pre> +1> <input>QH = qlc:q([{X,Y} || X <- [a,b], Y <- [1,2]]),</input> +<input>qlc:eval(QH).</input> +[{a,1},{a,2},{b,1},{b,2}]</pre> + </desc> + </func> + + <func> + <name>fold(Function, Acc0, QueryHandleOrList [, Options]) -> + Acc1 | Error</name> + <fsummary>Fold a function over the answers to a query.</fsummary> + <type> + <v>Function = fun(Answer, AccIn) -> AccOut</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v>Options = [Option] | Option</v> + <v>Option = {cache_all, Cache} | cache_all + | {max_list_size, MaxListSize} + | {tmpdir_usage, TmpFileUsage} + | {tmpdir, TempDirectory} + | {unique_all, bool()} | unique_all</v> + <v>Error = {error, module(), Reason}</v> + <v>Reason = - as returned by file_sorter(3) -</v> + </type> + <desc> + <p>Calls <c>Function</c> on successive answers to the query + handle together with an extra argument <c>AccIn</c>. The + query handle and the function are evaluated in the calling + process. <c>Function</c> must return a new accumulator which + is passed to the next call. <c>Acc0</c> is returned if there + are no answers to the query handle.</p> + + <pre> +1> <input>QH = [1,2,3,4,5,6],</input> +<input>qlc:fold(fun(X, Sum) -> X + Sum end, 0, QH).</input> +21</pre> + </desc> + </func> + + <func> + <name>format_error(Error) -> Chars</name> + <fsummary>Return an English description of a an error tuple.</fsummary> + <type> + <v>Error = {error, module(), term()}</v> + <v>Chars = [char() | Chars]</v> + </type> + <desc> + <p>Returns a descriptive string in English of an error tuple + returned by some of the functions of the <c>qlc</c> module + or the parse transform. This function is mainly used by the + compiler invoking the parse transform.</p> + </desc> + </func> + + <func> + <name>info(QueryHandleOrList [, Options]) -> Info</name> + <fsummary>Return code describing a query handle.</fsummary> + <type> + <v>Options = [Option] | Option</v> + <v>Option = EvalOption | ReturnOption</v> + <v>EvalOption = {cache_all, Cache} | cache_all + | {max_list_size, MaxListSize} + | {tmpdir_usage, TmpFileUsage} + | {tmpdir, TempDirectory} + | {unique_all, bool()} | unique_all</v> + <v>ReturnOption = {depth, Depth} + | {flat, bool()} + | {format, Format} + | {n_elements, NElements}</v> + <v>Depth = infinity | int() >= 0</v> + <v>Format = abstract_code | string</v> + <v>NElements = infinity | int() > 0</v> + <v>Info = AbstractExpression | string()</v> + </type> + <desc> + <p><marker id="info"></marker>Returns information about a + query handle. The information describes the simplifications + and optimizations that are the results of preparing the + query for evaluation. This function is probably useful + mostly during debugging.</p> + + <p>The information has the form of an Erlang expression where + QLCs most likely occur. Depending on the format functions of + mentioned QLC tables it may not be absolutely accurate.</p> + + <p>The default is to return a sequence of QLCs in a block, but + if the option <c>{flat, false}</c> is given, one single + QLC is returned. The default is to return a string, but if + the option <c>{format, abstract_code}</c> is given, + abstract code is returned instead. In the abstract code + port identifiers, references, and pids are represented by + strings. The default is to return + all elements in lists, but if the + <c>{n_elements, NElements}</c> option is given, only a + limited number of elements are returned. The default is to + show all of objects and match specifications, but if the + <c>{depth, Depth}</c> option is given, parts of terms + below a certain depth are replaced by <c>'...'</c>.</p> + + <pre> +1> <input>QH = qlc:q([{X,Y} || X <- [x,y], Y <- [a,b]]),</input> +<input>io:format("~s~n", [qlc:info(QH, unique_all)]).</input> +begin + V1 = + qlc:q([ + SQV || + SQV <- [x,y] + ], + [{unique,true}]), + V2 = + qlc:q([ + SQV || + SQV <- [a,b] + ], + [{unique,true}]), + qlc:q([ + {X,Y} || + X <- V1, + Y <- V2 + ], + [{unique,true}]) +end</pre> + + <p>In this example two simple QLCs have been inserted just to + hold the <c>{unique, true}</c> option.</p> + + <pre> +1> <input>E1 = ets:new(e1, []),</input> +<input>E2 = ets:new(e2, []),</input> +<input>true = ets:insert(E1, [{1,a},{2,b}]),</input> +<input>true = ets:insert(E2, [{a,1},{b,2}]),</input> +<input>Q = qlc:q([{X,Z,W} ||</input> +<input>{X, Z} <- ets:table(E1),</input> +<input>{W, Y} <- ets:table(E2),</input> +<input>X =:= Y]),</input> +<input>io:format("~s~n", [qlc:info(Q)]).</input> +begin + V1 = + qlc:q([ + P0 || + P0 = {W,Y} <- ets:table(17) + ]), + V2 = + qlc:q([ + [G1|G2] || + G2 <- V1, + G1 <- ets:table(16), + element(2, G1) =:= element(1, G2) + ], + [{join,lookup}]), + qlc:q([ + {X,Z,W} || + [{X,Z}|{W,Y}] <- V2 + ]) +end</pre> + + <p>In this example the query list comprehension <c>V2</c> has + been inserted to show the joined generators and the join + method chosen. A convention is used for lookup join: the + first generator (<c>G2</c>) is the one traversed, the second + one (<c>G1</c>) is the table where constants are looked up.</p> + </desc> + </func> + + <func> + <name>keysort(KeyPos, QH1 [, SortOptions]) -> QH2</name> + <fsummary>Return a query handle.</fsummary> + <type> + <v>QH1 = QueryHandleOrList</v> + <v>QH2 = QueryHandle</v> + </type> + <desc> + <p>Returns a query handle. When evaluating the query handle + <c>QH2</c> the answers to the query handle <c>QH1</c> are + sorted by <seealso + marker="file_sorter">file_sorter:keysort/4</seealso> + according to the options.</p> + + <p>The sorter will use temporary files only if <c>QH1</c> does + not evaluate to a list and the size of the binary + representation of the answers exceeds <c>Size</c> bytes, + where <c>Size</c> is the value of the <c>size</c> option.</p> + </desc> + </func> + + <func> + <name>next_answers(QueryCursor [, NumberOfAnswers]) -> + Answers | Error</name> + <fsummary>Return some or all answers to a query.</fsummary> + <type> + <v>NumberOfAnswers = all_remaining | int() > 0</v> + <v>Error = {error, module(), Reason}</v> + <v>Reason = - as returned by file_sorter(3) -</v> + </type> + <desc> + <p>Returns some or all of the remaining answers to a query + cursor. Only the owner of <c>Cursor</c> can retrieve + answers.</p> + + <p>The optional argument <c>NumberOfAnswers</c>determines the + maximum number of answers returned. The default value is + <c>10</c>. If less than the requested number of answers is + returned, subsequent calls to <c>next_answers</c> will + return <c>[]</c>.</p> + </desc> + </func> + + <func> + <name>q(QueryListComprehension [, Options]) -> QueryHandle</name> + <fsummary>Return a handle for a query list comprehension.</fsummary> + <type> + <v>QueryListComprehension = + - literal query listcomprehension -</v> + <v>Options = [Option] | Option</v> + <v>Option = {max_lookup, MaxLookup} + | {cache, Cache} | cache + | {join, Join} + | {lookup, Lookup} + | {unique, bool()} | unique</v> + <v>MaxLookup = int() >= 0 | infinity</v> + <v>Join = any | lookup | merge | nested_loop</v> + <v>Lookup = bool() | any</v> + </type> + <desc> + <p><marker id="q"></marker>Returns a query handle for a query + list comprehension. The query list comprehension must be the + first argument to <c>qlc:q/1,2</c> or it will be evaluated + as an ordinary list comprehension. It is also necessary to + add the line</p> + + <code type="none"> +-include_lib("stdlib/include/qlc.hrl").</code> + + <p>to the source file. This causes a parse transform to + substitute a fun for the query list comprehension. The + (compiled) fun will be called when the query handle is + evaluated.</p> + + <p>When calling <c>qlc:q/1,2</c> from the Erlang shell the + parse transform is automatically called. When this happens + the fun substituted for the query list comprehension is not + compiled but will be evaluated by <c>erl_eval(3)</c>. This + is also true when expressions are evaluated by means of + <c>file:eval/1,2</c> or in the debugger.</p> + + <p>To be very explicit, this will not work:</p> + + <pre> +... +A = [X || {X} <- [{1},{2}]], +QH = qlc:q(A), +...</pre> + + <p>The variable <c>A</c> will be bound to the evaluated value + of the list comprehension (<c>[1,2]</c>). The compiler + complains with an error message ("argument is not a query + list comprehension"); the shell process stops with a + <c>badarg</c> reason.</p> + + <p>The <c>{cache, ets}</c> option can be used to cache + the answers to a query list comprehension. The answers are + stored in one ETS table for each cached query list + comprehension. When a cached query list comprehension is + evaluated again, answers are fetched from the table without + any further computations. As a consequence, when all answers + to a cached query list comprehension have been found, the + ETS tables used for caching answers to the query list + comprehension's qualifiers can be emptied. The option + <c>cache</c> is equivalent to <c>{cache, ets}</c>.</p> + + <p>The <c>{cache, list}</c> option can be used to cache + the answers to a query list comprehension just like + <c>{cache, ets}</c>. The difference is that the answers + are kept in a list (on the process heap). If the answers + would occupy more than a certain amount of RAM memory a + temporary file is used for storing the answers. The option + <c>max_list_size</c> sets the limit in bytes and the temporary + file is put on the directory set by the <c>tmpdir</c> option.</p> + + <p>The <c>cache</c> option has no effect if it is known that + the query list comprehension will be evaluated at most once. + This is always true for the top-most query list + comprehension and also for the list expression of the first + generator in a list of qualifiers. Note that in the presence + of side effects in filters or callback functions the answers + to query list comprehensions can be affected by the + <c>cache</c> option.</p> + + <p>The <c>{unique, true}</c> option can be used to remove + duplicate answers to a query list comprehension. The unique + answers are stored in one ETS table for each query list + comprehension. The table is emptied every time it is known + that there are no more answers to the query list + comprehension. The option <c>unique</c> is equivalent to + <c>{unique, true}</c>. If the <c>unique</c> option is + combined with the <c>{cache, ets}</c> option, two ETS + tables are used, but the full answers are stored in one + table only. If the <c>unique</c> option is combined with the + <c>{cache, list}</c> option the answers are sorted + twice using <c>keysort/3</c>; once to remove duplicates, and + once to restore the order.</p> + + <p>The <c>cache</c> and <c>unique</c> options apply not only + to the query list comprehension itself but also to the + results of looking up constants, running match + specifications, and joining handles. </p> + + <pre> +1> <input>Q = qlc:q([{A,X,Z,W} ||</input> +<input>A <- [a,b,c],</input> +<input>{X,Z} <- [{a,1},{b,4},{c,6}],</input> +<input>{W,Y} <- [{2,a},{3,b},{4,c}],</input> +<input>X =:= Y],</input> +<input>{cache, list}),</input> +<input>io:format("~s~n", [qlc:info(Q)]).</input> +begin + V1 = + qlc:q([ + P0 || + P0 = {X,Z} <- + qlc:keysort(1, [{a,1},{b,4},{c,6}], []) + ]), + V2 = + qlc:q([ + P0 || + P0 = {W,Y} <- + qlc:keysort(2, [{2,a},{3,b},{4,c}], []) + ]), + V3 = + qlc:q([ + [G1|G2] || + G1 <- V1, + G2 <- V2, + element(1, G1) == element(2, G2) + ], + [{join,merge},{cache,list}]), + qlc:q([ + {A,X,Z,W} || + A <- [a,b,c], + [{X,Z}|{W,Y}] <- V3, + X =:= Y + ]) +end</pre> + + <p>In this example the cached results of the merge join are + traversed for each value of <c>A</c>. Note that without the + <c>cache</c> option the join would have been carried out + three times, once for each value of <c>A</c></p> + + <p><c>sort/1,2</c> and <c>keysort/2,3</c> can also be used for + caching answers and for removing duplicates. When sorting + answers are cached in a list, possibly stored on a temporary + file, and no ETS tables are used.</p> + + <p>Sometimes (see <seealso + marker="#lookup_fun">qlc:table/2</seealso> below) traversal + of tables can be done by looking up key values, which is + assumed to be fast. Under certain (rare) circumstances it + could happen that there are too many key values to look up. + <marker id="max_lookup"></marker> The + <c>{max_lookup, MaxLookup}</c> option can then be used + to limit the number of lookups: if more than + <c>MaxLookup</c> lookups would be required no lookups are + done but the table traversed instead. The default value is + <c>infinity</c> which means that there is no limit on the + number of keys to look up.</p> + <pre> +1> <input>T = gb_trees:empty(),</input> +<input>QH = qlc:q([X || {{X,Y},_} <- gb_table:table(T),</input> +<input>((X == 1) or (X == 2)) andalso</input> +<input>((Y == a) or (Y == b) or (Y == c))]),</input> +<input>io:format("~s~n", [qlc:info(QH)]).</input> +ets:match_spec_run( + lists:flatmap(fun(K) -> + case + gb_trees:lookup(K, + gb_trees:from_orddict([])) + of + {value,V} -> + [{K,V}]; + none -> + [] + end + end, + [{1,a},{1,b},{1,c},{2,a},{2,b},{2,c}]), + ets:match_spec_compile([{{{'$1','$2'},'_'},[],['$1']}]))</pre> + + <p>In this example using the <c>gb_table</c> module from the + <seealso marker="#implementing_a_qlc_table">Implementing a + QLC table</seealso> section there are six keys to look up: + <c>{1,a}</c>, <c>{1,b}</c>, <c>{1,c}</c>, <c>{2,a}</c>, + <c>{2,b}</c>, and <c>{2,c}</c>. The reason is that the two + elements of the key {X, Y} are compared separately.</p> + + <p>The <c>{lookup, true}</c> option can be used to ensure + that the <c>qlc</c> module will look up constants in some + QLC table. If there + are more than one QLC table among the generators' list + expressions, constants have to be looked up in at least one + of the tables. The evaluation of the query fails if there + are no constants to look up. This option is useful in + situations when it would be unacceptable to traverse all + objects in some table. Setting the <c>lookup</c> option to + <c>false</c> ensures that no constants will be looked up + (<c>{max_lookup, 0}</c> has the same effect). The + default value is <c>any</c> which means that constants will + be looked up whenever possible.</p> + + <p>The <c>{join, Join}</c> option can be used to ensure + that a certain join method will be used: + <c>{join, lookup}</c> invokes the lookup join method; + <c>{join, merge}</c> invokes the merge join method; and + <c>{join, nested_loop}</c> invokes the method of + matching every pair of objects from two handles. The last + method is mostly very slow. The evaluation of the query + fails if the <c>qlc</c> module cannot carry out the chosen + join method. The + default value is <c>any</c> which means that some fast join + method will be used if possible.</p> + </desc> + </func> + + <func> + <name>sort(QH1 [, SortOptions]) -> QH2</name> + <fsummary>Return a query handle.</fsummary> + <type> + <v>QH1 = QueryHandleOrList</v> + <v>QH2 = QueryHandle</v> + </type> + <desc> + <p>Returns a query handle. When evaluating the query handle + <c>QH2</c> the answers to the query handle <c>QH1</c> are + sorted by <seealso + marker="file_sorter">file_sorter:sort/3</seealso> according + to the options.</p> + + <p>The sorter will use temporary files only if <c>QH1</c> does + not evaluate to a list and the size of the binary + representation of the answers exceeds <c>Size</c> bytes, + where <c>Size</c> is the value of the <c>size</c> option.</p> + </desc> + </func> + + <func> + <name>string_to_handle(QueryString [, Options [, Bindings]]) -> + QueryHandle | Error</name> + <fsummary>Return a handle for a query list comprehension.</fsummary> + <type> + <v>QueryString = string()</v> + <v>Options = [Option] | Option</v> + <v>Option = {max_lookup, MaxLookup} + | {cache, Cache} | cache + | {join, Join} + | {lookup, Lookup} + | {unique, bool()} | unique</v> + <v>MaxLookup = int() >= 0 | infinity</v> + <v>Join = any | lookup | merge | nested_loop</v> + <v>Lookup = bool() | any</v> + <v>Bindings = - as returned by + erl_eval:bindings/1 -</v> + <v>Error = {error, module(), Reason}</v> + <v>Reason = - ErrorInfo as returned by + erl_scan:string/1 or erl_parse:parse_exprs/1 -</v> + </type> + <desc> + <p>A string version of <c>qlc:q/1,2</c>. When the query handle + is evaluated the fun created by the parse transform is + interpreted by <c>erl_eval(3)</c>. The query string is to be + one single query list comprehension terminated by a + period.</p> + + <pre> +1> <input>L = [1,2,3],</input> +<input>Bs = erl_eval:add_binding('L', L, erl_eval:new_bindings()),</input> +<input>QH = qlc:string_to_handle("[X+1 || X <- L].", [], Bs),</input> +<input>qlc:eval(QH).</input> +[2,3,4]</pre> + + <p>This function is probably useful mostly when called from + outside of Erlang, for instance from a driver written in C.</p> + </desc> + </func> + + <func> + <name>table(TraverseFun, Options) -> QueryHandle</name> + <fsummary>Return a query handle for a table.</fsummary> + <type> + <v>TraverseFun = TraverseFun0 | TraverseFun1</v> + <v>TraverseFun0 = fun() -> TraverseResult</v> + <v>TraverseFun1 = fun(MatchExpression) -> TraverseResult</v> + <v>TraverseResult = Objects | term()</v> + <v>Objects = [] | [term() | ObjectList]</v> + <v>ObjectList = TraverseFun0 | Objects</v> + <v>Options = [Option] | Option</v> + <v>Option = {format_fun, FormatFun} + | {info_fun, InfoFun} + | {lookup_fun, LookupFun} + | {parent_fun, ParentFun} + | {post_fun, PostFun} + | {pre_fun, PreFun} + | {key_equality, KeyComparison}</v> + <v>FormatFun = undefined | fun(SelectedObjects) -> FormatedTable</v> + <v>SelectedObjects = all + | {all, NElements, DepthFun} + | {match_spec, MatchExpression} + | {lookup, Position, Keys} + | {lookup, Position, Keys, NElements, DepthFun}</v> + <v>NElements = infinity | int() > 0</v> + <v>DepthFun = fun(term()) -> term()</v> + <v>FormatedTable = {Mod, Fun, Args} + | AbstractExpression + | character_list()</v> + <v>InfoFun = undefined | fun(InfoTag) -> InfoValue</v> + <v>InfoTag = indices | is_unique_objects | keypos | num_of_objects</v> + <v>InfoValue = undefined | term()</v> + <v>LookupFun = undefined | fun(Position, Keys) -> LookupResult</v> + <v>LookupResult = [term()] | term()</v> + <v>ParentFun = undefined | fun() -> ParentFunValue</v> + <v>PostFun = undefined | fun() -> void()</v> + <v>PreFun = undefined | fun([PreArg]) -> void()</v> + <v>PreArg = {parent_value, ParentFunValue} | {stop_fun, StopFun}</v> + <v>ParentFunValue = undefined | term()</v> + <v>StopFun = undefined | fun() -> void()</v> + <v>KeyComparison = '=:=' | '=='</v> + <v>Position = int() > 0</v> + <v>Keys = [term()]</v> + <v>Mod = Fun = atom()</v> + <v>Args = [term()]</v> + </type> + <desc> + <p><marker id="table"></marker>Returns a query handle for a + QLC table. In Erlang/OTP there is support for ETS, Dets and + Mnesia tables, but it is also possible to turn many other + data structures into QLC tables. The way to accomplish this + is to let function(s) in the module implementing the data + structure create a query handle by calling + <c>qlc:table/2</c>. The different ways to traverse the table + as well as properties of the table are handled by callback + functions provided as options to <c>qlc:table/2</c>.</p> + + <p>The callback function <c>TraverseFun</c> is used for + traversing the table. It is to return a list of objects + terminated by either <c>[]</c> or a nullary fun to be used + for traversing the not yet traversed objects of the table. + Any other return value is immediately returned as value of + the query evaluation. Unary <c>TraverseFun</c>s are to + accept a match specification as argument. The match + specification is created by the parse transform by analyzing + the pattern of the generator calling <c>qlc:table/2</c> and + filters using variables introduced in the pattern. If the + parse transform cannot find a match specification equivalent + to the pattern and filters, <c>TraverseFun</c> will be + called with a match specification returning every object. + Modules that can utilize match specifications for optimized + traversal of tables should call <c>qlc:table/2</c> with a + unary <c>TraverseFun</c> while other modules can provide a + nullary <c>TraverseFun</c>. <c>ets:table/2</c> is an example + of the former; <c>gb_table:table/1</c> in the <seealso + marker="#implementing_a_qlc_table">Implementing a QLC + table</seealso> section is an example of the latter.</p> + + <p><c>PreFun</c> is a unary callback function that is called + once before the table is read for the first time. If the + call fails, the query evaluation fails. Similarly, the + nullary callback function <c>PostFun</c> is called once + after the table was last read. The return value, which is + caught, is ignored. If <c>PreFun</c> has been called for a + table, <c>PostFun</c> is guaranteed to be called for that + table, even if the evaluation of the query fails for some + reason. The order in which pre (post) functions for + different tables are evaluated is not specified. Other table + access than reading, such as calling <c>InfoFun</c>, is + assumed to be OK at any time. The argument <c>PreArgs</c> is + a list of tagged values. Currently there are two tags, + <c>parent_value</c> and <c>stop_fun</c>, used by Mnesia for + managing transactions. The value of <c>parent_value</c> is + the value returned by <c>ParentFun</c>, or <c>undefined</c> + if there is no <c>ParentFun</c>. <c>ParentFun</c> is called + once just before the call of <c>PreFun</c> in the context of + the process calling <c>eval</c>, <c>fold</c>, or + <c>cursor</c>. The value of <c>stop_fun</c> is a nullary fun + that deletes the cursor if called from the parent, or + <c>undefined</c> if there is no cursor.</p> + + <p><marker id="lookup_fun"></marker>The binary callback + function <c>LookupFun</c> is used for looking up objects in + the table. The first argument <c>Position</c> is the key + position or an indexed position and the second argument + <c>Keys</c> is a sorted list of unique values. The return + value is to be a list of all objects (tuples) such that the + element at <c>Position</c> is a member of <c>Keys</c>. Any + other return value is immediately returned as value of the + query evaluation. <c>LookupFun</c> is called instead of + traversing the table if the parse transform at compile time + can find out that the filters match and compare the element + at <c>Position</c> in such a way that only <c>Keys</c> need + to be looked up in order to find all potential answers. The + key position is obtained by calling <c>InfoFun(keypos)</c> + and the indexed positions by calling + <c>InfoFun(indices)</c>. If the key position can be used for + lookup it is always chosen, otherwise the indexed position + requiring the least number of lookups is chosen. If there is + a tie between two indexed positions the one occurring first + in the list returned by <c>InfoFun</c> is chosen. Positions + requiring more than <seealso + marker="#max_lookup">max_lookup</seealso> lookups are + ignored.</p> + + <p>The unary callback function <c>InfoFun</c> is to return + information about the table. <c>undefined</c> should be + returned if the value of some tag is unknown:</p> + + <list type="bulleted"> + <item><c>indices</c>. Returns a list of indexed + positions, a list of positive integers. + </item> + <item><c>is_unique_objects</c>. Returns <c>true</c> if + the objects returned by <c>TraverseFun</c> are unique. + </item> + <item><c>keypos</c>. Returns the position of the table's + key, a positive integer. + </item> + <item><c>is_sorted_key</c>. Returns <c>true</c> if + the objects returned by <c>TraverseFun</c> are sorted + on the key. + </item> + <item><c>num_of_objects</c>. Returns the number of + objects in the table, a non-negative integer. + </item> + </list> + + <p>The unary callback function <c>FormatFun</c> is used by + <seealso marker="#info">qlc:info/1,2</seealso> for + displaying the call that created the table's query handle. + The default value, <c>undefined</c>, means that + <c>info/1,2</c> displays a call to <c>'$MOD':'$FUN'/0</c>. + It is up to <c>FormatFun</c> to present the selected objects + of the table in a suitable way. However, if a character list + is chosen for presentation it must be an Erlang expression + that can be scanned and parsed (a trailing dot will be added + by <c>qlc:info</c> though). <c>FormatFun</c> is called with + an argument that describes the selected objects based on + optimizations done as a result of analyzing the filters of + the QLC where the call to <c>qlc:table/2</c> occurs. The + possible values of the argument are:</p> + + <list type="bulleted"> + <item><c>{lookup, Position, Keys, NElements, DepthFun}</c>. + <c>LookupFun</c> is used for looking up objects in the + table. + </item> + <item><c>{match_spec, MatchExpression}</c>. No way of + finding all possible answers by looking up keys was + found, but the filters could be transformed into a + match specification. All answers are found by calling + <c>TraverseFun(MatchExpression)</c>. + </item> + <item><c>{all, NElements, DepthFun}</c>. No optimization was + found. A match specification matching all objects will be + used if <c>TraverseFun</c> is unary. + </item> + </list> + + <p><c>NElements</c> is the value of the <c>info/1,2</c> option + <c>n_elements</c>, and <c>DepthFun</c> is a function that + can be used for limiting the size of terms; calling + <c>DepthFun(Term)</c> substitutes <c>'...'</c> for parts of + <c>Term</c> below the depth specified by the <c>info/1,2</c> + option <c>depth</c>. If calling <c>FormatFun</c> with an + argument including <c>NElements</c> and <c>DepthFun</c> + fails, <c>FormatFun</c> is called once again with an + argument excluding <c>NElements</c> and <c>DepthFun</c> + (<c>{lookup, Position, Keys}</c> or + <c>all</c>).</p> + + <p><marker id="key_equality"></marker>The value of + <c>key_equality</c> is to be <c>'=:='</c> if the table + considers two keys equal if they match, and to be + <c>'=='</c> if two keys are equal if they compare equal. The + default is <c>'=:='</c>.</p> + + <p>See <seealso marker="ets#qlc_table">ets(3)</seealso>, + <seealso marker="dets#qlc_table">dets(3)</seealso> and + <seealso marker="mnesia:mnesia#qlc_table">mnesia(3)</seealso> + for the various options recognized by <c>table/1,2</c> in + respective module.</p> + </desc> + </func> + + </funcs> + + <section> + <title>See Also</title> + <p><seealso marker="dets">dets(3)</seealso>, + <seealso marker="doc/reference_manual:users_guide"> + Erlang Reference Manual</seealso>, + <seealso marker="erl_eval">erl_eval(3)</seealso>, + <seealso marker="erts:erlang">erlang(3)</seealso>, + <seealso marker="ets">ets(3)</seealso>, + <seealso marker="kernel:file">file(3)</seealso>, + <seealso marker="error_logger:file">error_logger(3)</seealso>, + <seealso marker="file_sorter">file_sorter(3)</seealso>, + <seealso marker="mnesia:mnesia">mnesia(3)</seealso>, + <seealso marker="doc/programming_examples:users_guide"> + Programming Examples</seealso>, + <seealso marker="shell">shell(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/queue.xml b/lib/stdlib/doc/src/queue.xml new file mode 100644 index 0000000000..5ada1c2c57 --- /dev/null +++ b/lib/stdlib/doc/src/queue.xml @@ -0,0 +1,454 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>queue</title> + <prepared>Joe</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>97-01-15</date> + <rev>B</rev> + <file>queue.sgml</file> + </header> + <module>queue</module> + <modulesummary>Abstract Data Type for FIFO Queues</modulesummary> + <description> + <p>This module implements (double ended) FIFO queues + in an efficient manner.</p> + <p>All functions fail with reason <c>badarg</c> if arguments + are of wrong type, for example queue arguments are not + queues, indexes are not integers, list arguments are + not lists. Improper lists cause internal crashes. + An index out of range for a queue also causes + a failure with reason <c>badarg</c>.</p> + <p>Some functions, where noted, fail with reason <c>empty</c> + for an empty queue.</p> + <p>The data representing a queue as used by this module + should be regarded as opaque by other modules. Any code + assuming knowledge of the format is running on thin ice.</p> + <p>All operations has an amortized O(1) running time, except + <c>len/1</c>, <c>join/2</c>, <c>split/2</c>, <c>filter/2</c> + and <c>member/2</c> that have O(n). + To minimize the size of a queue minimizing + the amount of garbage built by queue operations, the queues + do not contain explicit length information, and that is + why <c>len/1</c> is O(n). If better performance for this + particular operation is essential, it is easy for + the caller to keep track of the length.</p> + <p>Queues are double ended. The mental picture of + a queue is a line of people (items) waiting for + their turn. The queue front is the end with the item + that has waited the longest. The queue rear is the end + an item enters when it starts to wait. If instead using + the mental picture of a list, the front is called head + and the rear is called tail.</p> + <p>Entering at the front and exiting at the rear + are reverse operations on the queue.</p> + <p>The module has several sets of interface functions. The + "Original API", the "Extended API" and the "Okasaki API".</p> + <p>The "Original API" and the "Extended API" both use the + mental picture of a waiting line of items. Both also + have reverse operations suffixed "_r".</p> + <p>The "Original API" item removal functions return compound + terms with both the removed item and the resulting queue. + The "Extended API" contain alternative functions that build + less garbage as well as functions for just inspecting the + queue ends. Also the "Okasaki API" functions build less garbage.</p> + <p>The "Okasaki API" is inspired by "Purely Functional Data structures" + by Chris Okasaki. It regards queues as lists. + The API is by many regarded as strange and avoidable. + For example many reverse operations have lexically reversed names, + some with more readable but perhaps less understandable aliases.</p> + </description> + + + + <section> + <title>Original API</title> + </section> + + <funcs> + <func> + <name>new() -> Q</name> + <fsummary>Create an empty queue</fsummary> + <type> + <v>Q = queue()</v> + </type> + <desc> + <p>Returns an empty queue.</p> + </desc> + </func> + <func> + <name>is_queue(Term) -> true | false</name> + <fsummary>Test if a term is a queue</fsummary> + <type> + <v>Term = term()</v> + </type> + <desc> + <p>Tests if <c>Q</c> is a queue and returns <c>true</c> if so and + <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>is_empty(Q) -> true | false</name> + <fsummary>Test if a queue is empty</fsummary> + <type> + <v>Q = queue()</v> + </type> + <desc> + <p>Tests if <c>Q</c> is empty and returns <c>true</c> if so and + <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>len(Q) -> N</name> + <fsummary>Get the length of a queue</fsummary> + <type> + <v>Q = queue()</v> + <v>N = integer()</v> + </type> + <desc> + <p>Calculates and returns the length of queue <c>Q</c>.</p> + </desc> + </func> + + <func> + <name>in(Item, Q1) -> Q2</name> + <fsummary>Insert an item at the rear of a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Inserts <c>Item</c> at the rear of queue <c>Q1</c>. + Returns the resulting queue <c>Q2</c>.</p> + </desc> + </func> + <func> + <name>in_r(Item, Q1) -> Q2</name> + <fsummary>Insert an item at the front of a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Inserts <c>Item</c> at the front of queue <c>Q1</c>. + Returns the resulting queue <c>Q2</c>.</p> + </desc> + </func> + <func> + <name>out(Q1) -> Result</name> + <fsummary>Remove the front item from a queue</fsummary> + <type> + <v>Result = {{value, Item}, Q2} | {empty, Q1}</v> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Removes the item at the front of queue <c>Q1</c>. Returns the + tuple <c>{{value, Item}, Q2}</c>, where <c>Item</c> is the + item removed and <c>Q2</c> is the resulting queue. If <c>Q1</c> is + empty, the tuple <c>{empty, Q1}</c> is returned.</p> + </desc> + </func> + <func> + <name>out_r(Q1) -> Result</name> + <fsummary>Remove the rear item from a queue</fsummary> + <type> + <v>Result = {{value, Item}, Q2} | {empty, Q1}</v> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Removes the item at the rear of the queue <c>Q1</c>. Returns the + tuple <c>{{value, Item}, Q2}</c>, where <c>Item</c> is the + item removed and <c>Q2</c> is the new queue. If <c>Q1</c> is + empty, the tuple <c>{empty, Q1}</c> is returned. </p> + </desc> + </func> + + <func> + <name>from_list(L) -> queue()</name> + <fsummary>Convert a list to a queue</fsummary> + <type> + <v>L = list()</v> + </type> + <desc> + <p>Returns a queue containing the items in <c>L</c> in the + same order; the head item of the list will become the front + item of the queue.</p> + </desc> + </func> + <func> + <name>to_list(Q) -> list()</name> + <fsummary>Convert a queue to a list</fsummary> + <type> + <v>Q = queue()</v> + </type> + <desc> + <p>Returns a list of the items in the queue in the same order; + the front item of the queue will become the head of the list.</p> + </desc> + </func> + + <func> + <name>reverse(Q1) -> Q2</name> + <fsummary>Reverse a queue</fsummary> + <type> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Returns a queue <c>Q2</c> that contains the items of + <c>Q1</c> in the reverse order.</p> + </desc> + </func> + <func> + <name>split(N, Q1) -> {Q2,Q3}</name> + <fsummary>Split a queue in two</fsummary> + <type> + <v>N = integer()</v> + <v>Q1 = Q2 = Q3 = queue()</v> + </type> + <desc> + <p>Splits <c>Q1</c> in two. The <c>N</c> front items + are put in <c>Q2</c> and the rest in <c>Q3</c></p> + </desc> + </func> + <func> + <name>join(Q1, Q2) -> Q3</name> + <fsummary>Join two queues</fsummary> + <type> + <v>Q1 = Q2 = Q3 = queue()</v> + </type> + <desc> + <p>Returns a queue <c>Q3</c> that is the result of joining + <c>Q1</c> and <c>Q2</c> with <c>Q1</c> in front of + <c>Q2</c>.</p> + </desc> + </func> + <func> + <name>filter(Fun, Q1) -> Q2</name> + <fsummary>Filter a queue</fsummary> + <type> + <v>Fun = fun(Item) -> bool() | list()</v> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Returns a queue <c>Q2</c> that is the result of calling + <c>Fun(Item)</c> on all items in <c>Q1</c>, + in order from front to rear.</p> + <p>If <c>Fun(Item)</c> returns <c>true</c>, <c>Item</c> + is copied to the result queue. If it returns <c>false</c>, + <c>Item</c> is not copied. If it returns a list + the list elements are inserted instead of <c>Item</c> in the + result queue.</p> + <p>So, <c>Fun(Item)</c> returning <c>[Item]</c> is thereby + semantically equivalent to returning <c>true</c>, just + as returning <c>[]</c> is semantically equivalent to + returning <c>false</c>. But returning a list builds + more garbage than returning an atom.</p> + </desc> + </func> + <func> + <name>member(Item, Q) -> bool()</name> + <fsummary>Test if an item is in a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q = queue()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Item</c> matches some element + in <c>Q</c>, otherwise <c>false</c>.</p> + </desc> + </func> + </funcs> + + + + <section> + <title>Extended API</title> + </section> + + <funcs> + <func> + <name>get(Q) -> Item</name> + <fsummary>Return the front item of a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q = queue()</v> + </type> + <desc> + <p>Returns <c>Item</c> at the front of queue <c>Q</c>.</p> + <p>Fails with reason <c>empty</c> if <c>Q</c> is empty.</p> + </desc> + </func> + <func> + <name>get_r(Q) -> Item</name> + <fsummary>Return the rear item of a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q = queue()</v> + </type> + <desc> + <p>Returns <c>Item</c> at the rear of queue <c>Q</c>.</p> + <p>Fails with reason <c>empty</c> if <c>Q</c> is empty.</p> + </desc> + </func> + <func> + <name>drop(Q1) -> Q2</name> + <fsummary>Remove the front item from a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Returns a queue <c>Q2</c> that is the result of removing + the front item from <c>Q1</c>.</p> + <p>Fails with reason <c>empty</c> if <c>Q1</c> is empty.</p> + </desc> + </func> + <func> + <name>drop_r(Q1) -> Q2</name> + <fsummary>Remove the rear item from a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Returns a queue <c>Q2</c> that is the result of removing + the rear item from <c>Q1</c>.</p> + <p>Fails with reason <c>empty</c> if <c>Q1</c> is empty.</p> + </desc> + </func> + <func> + <name>peek(Q) -> {value,Item} | empty</name> + <fsummary>Return the front item of a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q = queue()</v> + </type> + <desc> + <p>Returns the tuple <c>{value, Item}</c> where <c>Item</c> is the + front item of <c>Q</c>, or <c>empty</c> if <c>Q1</c> is empty.</p> + </desc> + </func> + <func> + <name>peek_r(Q) -> {value,Item} | empty</name> + <fsummary>Return the rear item of a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q = queue()</v> + </type> + <desc> + <p>Returns the tuple <c>{value, Item}</c> where <c>Item</c> is the + rear item of <c>Q</c>, or <c>empty</c> if <c>Q1</c> is empty.</p> + </desc> + </func> + </funcs> + + + <section> + <title>Okasaki API</title> + </section> + + <funcs> + <func> + <name>cons(Item, Q1) -> Q2</name> + <fsummary>Insert an item at the head of a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Inserts <c>Item</c> at the head of queue <c>Q1</c>. Returns + the new queue <c>Q2</c>.</p> + </desc> + </func> + <func> + <name>head(Q) -> Item</name> + <fsummary>Return the item at the head of a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q = queue()</v> + </type> + <desc> + <p>Returns <c>Item</c> from the head of queue <c>Q</c>.</p> + <p>Fails with reason <c>empty</c> if <c>Q</c> is empty.</p> + </desc> + </func> + <func> + <name>tail(Q1) -> Q2</name> + <fsummary>Remove the head item from a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Returns a queue <c>Q2</c> that is the result of removing + the head item from <c>Q1</c>.</p> + <p>Fails with reason <c>empty</c> if <c>Q1</c> is empty.</p> + </desc> + </func> + <func> + <name>snoc(Q1, Item) -> Q2</name> + <fsummary>Insert an item at the tail of a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Inserts <c>Item</c> as the tail item of queue <c>Q1</c>. Returns + the new queue <c>Q2</c>.</p> + </desc> + </func> + <func> + <name>daeh(Q) -> Item</name> + <name>last(Q) -> Item</name> + <fsummary>Return the tail item of a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q = queue()</v> + </type> + <desc> + <p>Returns the tail item of queue <c>Q</c>.</p> + <p>Fails with reason <c>empty</c> if <c>Q</c> is empty.</p> + </desc> + </func> + <func> + <name>liat(Q1) -> Q2</name> + <name>init(Q1) -> Q2</name> + <name>lait(Q1) -> Q2</name> + <fsummary>Remove the tail item from a queue</fsummary> + <type> + <v>Item = term()</v> + <v>Q1 = Q2 = queue()</v> + </type> + <desc> + <p>Returns a queue <c>Q2</c> that is the result of removing + the tail item from <c>Q1</c>.</p> + <p>Fails with reason <c>empty</c> if <c>Q1</c> is empty.</p> + <p>The name <c>lait/1</c> is a misspelling - do not use it anymore.</p> + </desc> + </func> + </funcs> + +</erlref> diff --git a/lib/stdlib/doc/src/random.xml b/lib/stdlib/doc/src/random.xml new file mode 100644 index 0000000000..dcc6d756e1 --- /dev/null +++ b/lib/stdlib/doc/src/random.xml @@ -0,0 +1,151 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>random</title> + <prepared>Joe Armstrong</prepared> + <responsible>Bjarne Dacker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>96-09-09</date> + <rev>A</rev> + <file>random.sgml</file> + </header> + <module>random</module> + <modulesummary>Pseudo random number generation</modulesummary> + <description> + <p>Random number generator. The method is attributed to + B.A. Wichmann and I.D.Hill, in 'An efficient and portable + pseudo-random number generator', Journal of Applied + Statistics. AS183. 1982. Also Byte March 1987. </p> + <p>The current algorithm is a modification of the version attributed + to Richard A O'Keefe in the standard Prolog library.</p> + <p>Every time a random number is requested, a state is used to calculate + it, and a new state produced. The state can either be implicit (kept + in the process dictionary) or be an explicit argument and return value. + In this implementation, the state (the type <c>ran()</c>) consists of a + tuple of three integers.</p> + <p>It should be noted that this random number generator is not cryptographically + strong. If a strong cryptographic random number generator is needed for + example <c>crypto:rand_bytes/1</c> could be used instead.</p> + </description> + <funcs> + <func> + <name>seed() -> ran()</name> + <fsummary>Seeds random number generation with default values</fsummary> + <desc> + <p>Seeds random number generation with default (fixed) values + in the process dictionary, and returns the old state.</p> + </desc> + </func> + <func> + <name>seed(A1, A2, A3) -> undefined | ran()</name> + <fsummary>Seeds random number generator</fsummary> + <type> + <v>A1 = A2 = A3 = integer()</v> + </type> + <desc> + <p>Seeds random number generation with integer values in the process + dictionary, and returns the old state.</p> + <p>One way of obtaining a seed is to use the BIF <c>now/0</c>:</p> + <code type="none"> + ... + {A1,A2,A3} = now(), + random:seed(A1, A2, A3), + ...</code> + </desc> + </func> + <func> + <name>seed({A1, A2, A3}) -> undefined | ran()</name> + <fsummary>Seeds random number generator</fsummary> + <type> + <v>A1 = A2 = A3 = integer()</v> + </type> + <desc> + <p> + <c>seed({A1, A2, A3})</c> is equivalent to <c>seed(A1, A2, A3)</c>. + </p> + </desc> + </func> + <func> + <name>seed0() -> ran()</name> + <fsummary>Return default state for random number generation</fsummary> + <desc> + <p>Returns the default state.</p> + </desc> + </func> + <func> + <name>uniform()-> float()</name> + <fsummary>Return a random float</fsummary> + <desc> + <p>Returns a random float uniformly distributed between <c>0.0</c> + and <c>1.0</c>, updating the state in the process dictionary.</p> + </desc> + </func> + <func> + <name>uniform(N) -> integer()</name> + <fsummary>Return a random integer</fsummary> + <type> + <v>N = integer()</v> + </type> + <desc> + <p>Given an integer <c>N >= 1</c>, <c>uniform/1</c> returns a + random integer uniformly distributed between <c>1</c> and + <c>N</c>, updating the state in the process dictionary.</p> + </desc> + </func> + <func> + <name>uniform_s(State0) -> {float(), State1}</name> + <fsummary>Return a random float</fsummary> + <type> + <v>State0 = State1 = ran()</v> + </type> + <desc> + <p>Given a state, <c>uniform_s/1</c>returns a random float uniformly + distributed between <c>0.0</c> and <c>1.0</c>, and a new state.</p> + </desc> + </func> + <func> + <name>uniform_s(N, State0) -> {integer(), State1}</name> + <fsummary>Return a random integer</fsummary> + <type> + <v>N = integer()</v> + <v>State0 = State1 = ran()</v> + </type> + <desc> + <p>Given an integer <c>N >= 1</c> and a state, <c>uniform_s/2</c> + returns a random integer uniformly distributed between <c>1</c> and + <c>N</c>, and a new state.</p> + </desc> + </func> + </funcs> + + <section> + <title>Note</title> + <p>Some of the functions use the process dictionary variable + <c>random_seed</c> to remember the current seed.</p> + <p>If a process calls <c>uniform/0</c> or <c>uniform/1</c> without + setting a seed first, <c>seed/0</c> is called automatically.</p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml new file mode 100644 index 0000000000..41dce7f2a7 --- /dev/null +++ b/lib/stdlib/doc/src/re.xml @@ -0,0 +1,2957 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2007</year> + <year>2008</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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 on line 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. + </legalnotice> + + <title>re</title> + <prepared>Patrik Nyblom</prepared> + <responsible>Kenneth Lundin</responsible> + <docno>1</docno> + <approved></approved> + <checked></checked> + <date>2008-05-27</date> + <rev>A</rev> + <file>re.xml</file> + </header> + <module>re</module> + <modulesummary>Perl like regular expressions for Erlang</modulesummary> + <description> + + <p>This module contains functions for regular expression + matching for strings and binaries.</p> + + <p>The regular expression syntax and semantics resemble that of + Perl. This library in many ways replaces the old regexp library + written purely in Erlang, as it has a richer syntax as well as + many more options. The library is also faster than the + older regexp implementation.</p> + + <p>Although the library's matching algorithms are currently based + on the PCRE library, it is not to be viewed as an Erlang to PCRE + mapping. Only parts of the PCRE library is interfaced and the re + library in some ways extend PCRE. The PCRE documentation contains + many parts of no interest to the Erlang programmer, why only the + relevant part of the documentation is included here. There should + bee no need to go directly to the PCRE library documentation.</p> + + <note> + <p>The Erlang literal syntax for strings give special + meaning to the "\\" (backslash) character. To literally write + a regular expression or a replacement string containing a + backslash in your code or in the shell, two backslashes have to be written: + "\\\\".</p> + </note> + + + </description> + <section> + <title>DATA TYPES</title> + <code type="none"> + iodata() = iolist() | binary() + iolist() = [char() | binary() | iolist()] + - a binary is allowed as the tail of the list</code> + <code type="none"> + unicode_binary() = binary() with characters encoded in UTF-8 coding standard + unicode_char() = integer() representing valid unicode codepoint + + chardata() = charlist() | unicode_binary() + + charlist() = [unicode_char() | unicode_binary() | charlist()] + - a unicode_binary is allowed as the tail of the list</code> + + <code type="none"> + mp() = Opaque datatype containing a compiled regular expression.</code> + </section> + <funcs> + <func> + <name>compile(Regexp) -> {ok, MP} | {error, ErrSpec}</name> + <fsummary>Compile a regular expression into a match program</fsummary> + <type> + <v>Regexp = iodata()</v> + </type> + <desc> + <p>The same as <c>compile(Regexp,[])</c></p> + </desc> + </func> + <func> + <name>compile(Regexp,Options) -> {ok, MP} | {error, ErrSpec}</name> + <fsummary>Compile a regular expression into a match program</fsummary> + <type> + <v>Regexp = iodata() | charlist()</v> + <v>Options = [ Option ]</v> + <v>Option = unicode | anchored | caseless | dollar_endonly | dotall | extended | firstline | multiline | no_auto_capture | dupnames | ungreedy | {newline, NLSpec}| bsr_anycrlf | bsr_unicode</v> + <v>NLSpec = cr | crlf | lf | anycrlf | any </v> + <v>MP = mp()</v> + <v>ErrSpec = {ErrString, Position}</v> + <v>ErrString = string()</v> + <v>Position = int()</v> + </type> + <desc> + <p>This function compiles a regular expression with the syntax + described below into an internal format to be used later as a + parameter to the run/2,3 functions.</p> + <p>Compiling the regular expression before matching is useful if + the same expression is to be used in matching against multiple + subjects during the program's lifetime. Compiling once and + executing many times is far more efficient than compiling each + time one wants to match.</p> + <p>When the unicode option is given, the regular expression should be given as a valid unicode <c>charlist()</c>, otherwise as any valid <c>iodata()</c>.</p> + + <p>The options have the following meanings:</p> + <taglist> + <tag><c>unicode</c></tag> + <item>The regular expression is given as a unicode <c>charlist()</c> and the resulting regular expression code is to be run against a valid unicode <c>charlist()</c> subject.</item> + <tag><c>anchored</c></tag> + <item>The pattern is forced to be "anchored", that is, it is constrained to match only at the first matching point in the string that is being searched (the "subject string"). This effect can also be achieved by appropriate constructs in the pattern itself.</item> + <tag><c>caseless</c></tag> + <item>Letters in the pattern match both upper and lower case letters. It is equivalent to Perl's /i option, and it can be changed within a pattern by a (?i) option setting. Uppercase and lowercase letters are defined as in the ISO-8859-1 character set.</item> + <tag><c>dollar_endonly</c></tag> + <item>A dollar metacharacter in the pattern matches only at the end of the subject string. Without this option, a dollar also matches immediately before a newline at the end of the string (but not before any other newlines). The <c>dollar_endonly</c> option is ignored if <c>multiline</c> is given. There is no equivalent option in Perl, and no way to set it within a pattern.</item> + <tag><c>dotall</c></tag> + <item>A dot maturate in the pattern matches all characters, including those that indicate newline. Without it, a dot does not match when the current position is at a newline. This option is equivalent to Perl's /s option, and it can be changed within a pattern by a (?s) option setting. A negative class such as [^a] always matches newline characters, independent of the setting of this option.</item> + <tag><c>extended</c></tag> + <item>Whitespace data characters in the pattern are ignored except when escaped or inside a character class. Whitespace does not include the VT character (ASCII 11). In addition, characters between an unescaped # outside a character class and the next newline, inclusive, are also ignored. This is equivalent to Perl's /x option, and it can be changed within a pattern by a (?x) option setting. + +This option makes it possible to include comments inside complicated patterns. Note, however, that this applies only to data characters. Whitespace characters may never appear within special character sequences in a pattern, for example within the sequence <c>(?(</c> which introduces a conditional subpattern.</item> + <tag><c>firstline</c></tag> + <item>An unanchored pattern is required to match before or at the first newline in the subject string, though the matched text may continue over the newline.</item> + <tag><c>multiline</c></tag> + <item><p>By default, PCRE treats the subject string as consisting of a single line of characters (even if it actually contains newlines). The "start of line" metacharacter (^) matches only at the start of the string, while the "end of line" metacharacter ($) matches only at the end of the string, or before a terminating newline (unless <c>dollar_endonly</c> is given). This is the same as Perl.</p> + +<p>When <c>multiline</c> it is given, the "start of line" and "end of line" constructs match immediately following or immediately before internal newlines in the subject string, respectively, as well as at the very start and end. This is equivalent to Perl's /m option, and it can be changed within a pattern by a (?m) option setting. If there are no newlines in a subject string, or no occurrences of ^ or $ in a pattern, setting <c>multiline</c> has no effect.</p> </item> + <tag><c>no_auto_capture</c></tag> + <item>Disables the use of numbered capturing parentheses in the pattern. Any opening parenthesis that is not followed by ? behaves as if it were followed by ?: but named parentheses can still be used for capturing (and they acquire numbers in the usual way). There is no equivalent of this option in Perl. +</item> + <tag><c>dupnames</c></tag> + <item>Names used to identify capturing subpatterns need not be unique. This can be helpful for certain types of pattern when it is known that only one instance of the named subpattern can ever be matched. There are more details of named subpatterns below</item> + <tag><c>ungreedy</c></tag> + <item>This option inverts the "greediness" of the quantifiers so that they are not greedy by default, but become greedy if followed by "?". It is not compatible with Perl. It can also be set by a (?U) option setting within the pattern.</item> + <tag><c>{newline, NLSpec}</c></tag> + <item> + <p>Override the default definition of a newline in the subject string, which is LF (ASCII 10) in Erlang.</p> + <taglist> + <tag><c>cr</c></tag> + <item>Newline is indicated by a single character CR (ASCII 13)</item> + <tag><c>lf</c></tag> + <item>Newline is indicated by a single character LF (ASCII 10), the default</item> + <tag><c>crlf</c></tag> + <item>Newline is indicated by the two-character CRLF (ASCII 13 followed by ASCII 10) sequence.</item> + <tag><c>anycrlf</c></tag> + <item>Any of the three preceding sequences should be recognized.</item> + <tag><c>any</c></tag> + <item>Any of the newline sequences above, plus the Unicode sequences VT (vertical tab, U+000B), FF (formfeed, U+000C), NEL (next line, U+0085), LS (line separator, U+2028), and PS (paragraph separator, U+2029). </item> + </taglist> + </item> + <tag><c>bsr_anycrlf</c></tag> + <item>Specifies specifically that \\R is to match only the cr, lf or crlf sequences, not the Unicode specific newline characters.</item> + <tag><c>bsr_unicode</c></tag> + <item>Specifies specifically that \\R is to match all the Unicode newline characters (including crlf etc, the default).</item> + </taglist> + </desc> + </func> + + <func> + <name>run(Subject,RE) -> {match, Captured} | nomatch</name> + <fsummary>Match a subject against regular expression and capture subpatterns</fsummary> + <type> + <v>Subject = iodata() | charlist()</v> + <v>RE = mp() | iodata() | charlist()</v> + <v>Captured = [ CaptureData ]</v> + <v>CaptureData = {int(),int()}</v> + </type> + <desc> + <p>The same as <c>run(Subject,RE,[])</c>.</p> + </desc> + </func> + <func> + <name>run(Subject,RE,Options) -> {match, Captured} | match | nomatch</name> + <fsummary>Match a subject against regular expression and capture subpatterns</fsummary> + <type> + <v>Subject = iodata() | charlist()</v> + <v>RE = mp() | iodata() | charlist()</v> + <v>Options = [ Option ]</v> + <v>Option = anchored | global | notbol | noteol | notempty | {offset, int()} | {newline, NLSpec} | bsr_anycrlf | bsr_unicode | {capture, ValueSpec} | {capture, ValueSpec, Type} | CompileOpt</v> + <v>Type = index | list | binary</v> + <v>ValueSpec = all | all_but_first | first | none | ValueList</v> + <v>ValueList = [ ValueID ]</v> + <v>ValueID = int() | string() | atom()</v> + <v>CompileOpt = see compile/2 above</v> + <v>NLSpec = cr | crlf | lf | anycrlf | any</v> + <v>Captured = [ CaptureData ] | [ [ CaptureData ] ... ]</v> + <v>CaptureData = {int(),int()} | ListConversionData | binary()</v> + <v>ListConversionData = string() | {error, string(), binary()} | {incomplete, string(), binary()}</v> + </type> + <desc> + + <p>Executes a regexp matching, returning <c>match/{match, + Captured}</c> or <c>nomatch</c>. The regular expression can be + given either as <c>iodata()</c> in which case it is + automatically compiled (as by <c>re:compile/2</c>) and executed, + or as a pre compiled <c>mp()</c> in which case it is executed + against the subject directly.</p> + + <p>When compilation is involved, the exception <c>badarg</c> is thrown if + a compilation error occurs. To locate the error in the regular + expression, use the function <c>re:compile/2</c> to get more information.</p> + + <p>If the regular expression is previously compiled, the option + list can only contain the options <c>anchored</c>, + <c>global</c>, <c>notbol</c>, <c>noteol</c>, + <c>notempty</c>, <c>{offset, int()}</c>, <c>{newline, + NLSpec}</c> and <c>{capture, ValueSpec}/{capture, ValueSpec, + Type}</c>. Otherwise all options valid for the + <c>re:compile/2</c> function are allowed as well. Options + allowed both for compilation and execution of a match, namely + <c>anchored</c> and <c>{newline, NLSpec}</c>, will affect both + the compilation and execution if present together with a non + pre-compiled regular expression.</p> + + <p>If the regular expression was previously compiled with the + option <c>unicode</c>, the <c>Subject</c> should be provided as + a valid Unicode <c>charlist()</c>, otherwise any <c>iodata()</c> + will do. If compilation is involved and the option + <c>unicode</c> is given, both the <c>Subject</c> and the regular + expression should be given as valid Unicode + <c>charlists()</c>.</p> + + <p>The <c>{capture, ValueSpec}/{capture, ValueSpec, Type}</c> + defines what to return from the function upon successful + matching. The <c>capture</c> tuple may contain both a + value specification telling which of the captured + substrings are to be returned, and a type specification, telling + how captured substrings are to be returned (as index tuples, + lists or binaries). The <c>capture</c> option makes the function + quite flexible and powerful. The different options are described + in detail below</p> + + <p>If the capture options describe that no substring capturing + at all is to be done (<c>{capture, none}</c>), the function will + return the single atom <c>match</c> upon successful matching, + otherwise the tuple + <c>{match, ValueList}</c> is returned. Disabling capturing can + be done either by specifying <c>none</c> or an empty list as + <c>ValueSpec</c>.</p> + + <p>A description of all the options relevant for execution follows:</p> + + <taglist> + <tag><c>anchored</c></tag> + + <item>Limits <c>re:run/3</c> to matching at the first matching + position. If a pattern was compiled with <c>anchored</c>, or + turned out to be anchored by virtue of its contents, it cannot + be made unanchored at matching time, hence there is no + <c>unanchored</c> option.</item> + + <tag><c>global</c></tag> + <item> + + <p>Implements global (repetitive) search as the <c>g</c> flag in + i.e. Perl. Each match found is returned as a separate + <c>list()</c> containing the specific match as well as any + matching subexpressions (or as specified by the <c>capture + option</c>). The <c>Captured</c> part of the return value will + hence be a <c>list()</c> of <c>list()</c>'s when this + option is given.</p> + + <p>When the regular expression matches an empty string, the + behaviour might seem non-intuitive, why the behaviour requites + some clarifying. With the global option, <c>re:run/3</c> + handles empty matches in the same way as Perl, meaning that a + match at any point giving an empty string (with length 0) will + be retried with the options + <c>[anchored, notempty]</c> as well. If that + search gives a result of length > 0, the result is included. + An example:</p> + +<code> re:run("cat","(|at)",[global]).</code> + + <p>The matching will be performed as following:</p> + <taglist> + <tag>At offset <c>0</c></tag> + <item>The regexp <c>(|at)</c> will first match at the initial + position of the string <c>cat</c>, giving the result set + <c>[{0,0},{0,0}]</c> (the second <c>{0,0}</c> is due to the + subexpression marked by the parentheses). As the length of the + match is 0, we don't advance to the next position yet.</item> + <tag>At offset <c>0</c> with <c>[anchored, notempty]</c></tag> + <item> The search is retried + with the options <c>[anchored, notempty]</c> at the same + position, which does not give any interesting result of longer + length, why the search position is now advanced to the next + character (<c>a</c>).</item> + <tag>At offset <c>1</c></tag> + <item>Now the search results in + <c>[{1,0},{1,0}]</c> meaning this search will also be repeated + with the extra options.</item> + <tag>At offset <c>1</c> with <c>[anchored, notempty]</c></tag> + <item>Now the <c>ab</c> alternative + is found and the result will be [{1,2},{1,2}]. The result is + added to the list of results and the position in the + search string is advanced two steps.</item> + <tag>At offset <c>3</c></tag> + <item>The search now once again + matches the empty string, giving <c>[{3,0},{3,0}]</c>.</item> + <tag>At offset <c>1</c> with <c>[anchored, notempty]</c></tag> + <item>This will give no result of length > 0 and we are at + the last position, so the global search is complete.</item> + </taglist> + <p>The result of the call is:</p> + +<code> {match,[[{0,0},{0,0}],[{1,0},{1,0}],[{1,2},{1,2}],[{3,0},{3,0}]]}</code> +</item> + + <tag><c>notempty</c></tag> + <item> + <p>An empty string is not considered to be a valid match if this + option is given. If there are alternatives in the pattern, they + are tried. If all the alternatives match the empty string, the + entire match fails. For example, if the pattern</p> +<code> a?b?</code> + <p>is applied to a string not beginning with "a" or "b", it + matches the empty string at the start of the subject. With + <c>notempty</c> given, this match is not valid, so re:run/3 searches + further into the string for occurrences of "a" or "b".</p> + + <p>Perl has no direct equivalent of <c>notempty</c>, but it does + make a special case of a pattern match of the empty string + within its split() function, and when using the /g modifier. It + is possible to emulate Perl's behavior after matching a null + string by first trying the match again at the same offset with + <c>notempty</c> and <c>anchored</c>, and then if that fails by + advancing the starting offset (see below) and trying an ordinary + match again.</p> + </item> + <tag><c>notbol</c></tag> + + <item>This option specifies that the first character of the subject + string is not the beginning of a line, so the circumflex + metacharacter should not match before it. Setting this without + <c>multiline</c> (at compile time) causes circumflex never to + match. This option affects only the behavior of the circumflex + metacharacter. It does not affect \A.</item> + + <tag><c>noteol</c></tag> + + <item>This option specifies that the end of the subject string + is not the end of a line, so the dollar metacharacter should not + match it nor (except in multiline mode) a newline immediately + before it. Setting this without <c>multiline</c> (at compile time) + causes dollar never to match. This option affects only the + behavior of the dollar metacharacter. It does not affect \Z or + \z.</item> + + <tag><c>{offset, int()}</c></tag> + + <item>Start matching at the offset (position) given in the + subject string. The offset is zero-based, so that the default is + <c>{offset,0}</c> (all of the subject string).</item> + + <tag><c>{newline, NLSpec}</c></tag> + <item> + <p>Override the default definition of a newline in the subject string, which is LF (ASCII 10) in Erlang.</p> + <taglist> + <tag><c>cr</c></tag> + <item>Newline is indicated by a single character CR (ASCII 13)</item> + <tag><c>lf</c></tag> + <item>Newline is indicated by a single character LF (ASCII 10), the default</item> + <tag><c>crlf</c></tag> + <item>Newline is indicated by the two-character CRLF (ASCII 13 followed by ASCII 10) sequence.</item> + <tag><c>anycrlf</c></tag> + <item>Any of the three preceding sequences should be recognized.</item> + <tag><c>any</c></tag> + <item>Any of the newline sequences above, plus the Unicode sequences VT (vertical tab, U+000B), FF (formfeed, U+000C), NEL (next line, U+0085), LS (line separator, U+2028), and PS (paragraph separator, U+2029). </item> + </taglist> + </item> + <tag><c>bsr_anycrlf</c></tag> + <item>Specifies specifically that \\R is to match only the cr, lf or crlf sequences, not the Unicode specific newline characters.(overrides compilation option)</item> + <tag><c>bsr_unicode</c></tag> + <item>Specifies specifically that \\R is to match all the Unicode newline characters (including crlf etc, the default).(overrides compilation option)</item> + + <tag><c>{capture, ValueSpec}</c>/<c>{capture, ValueSpec, Type}</c></tag> + <item> + + <p>Specifies which captured substrings are returned and in what + format. By default, + <c>re:run/3</c> captures all of the matching part of the + substring as well as all capturing subpatterns (all of the + pattern is automatically captured). The default return type is + (zero-based) indexes of the captured parts of the string, given as + <c>{Offset,Length}</c> pairs (the <c>index</c> <c>Type</c> of + capturing).</p> + + <p>As an example of the default behavior, the following call:</p> + + <code> re:run("ABCabcdABC","abcd",[]).</code> + + <p>returns, as first and only captured string the matching part of the subject ("abcd" in the middle) as a index pair <c>{3,4}</c>, where character positions are zero based, just as in offsets. The return value of the call above would then be:</p> + <code> {match,[{3,4}]}</code> + <p>Another (and quite common) case is where the regular expression matches all of the subject, as in:</p> + <code> re:run("ABCabcdABC",".*abcd.*",[]).</code> + <p>where the return value correspondingly will point out all of the string, beginning at index 0 and being 10 characters long:</p> + <code> {match,[{0,10}]}</code> + + <p>If the regular expression contains capturing subpatterns, + like in the following case:</p> + + <code> re:run("ABCabcdABC",".*(abcd).*",[]).</code> + + <p>all of the matched subject is captured, as + well as the captured substrings:</p> + + <code> {match,[{0,10},{3,4}]}</code> + + <p>the complete matching pattern always giving the first return value in the + list and the rest of the subpatterns being added in the + order they occurred in the regular expression.</p> + + <p>The capture tuple is built up as follows:</p> + <taglist> + <tag><c>ValueSpec</c></tag> + <item><p>Specifies which captured (sub)patterns are to be returned. The ValueSpec can either be an atom describing a predefined set of return values, or a list containing either the indexes or the names of specific subpatterns to return.</p> + <p>The predefined sets of subpatterns are:</p> + <taglist> + <tag><c>all</c></tag> + <item>All captured subpatterns including the complete matching string. This is the default.</item> + <tag><c>first</c></tag> + <item>Only the first captured subpattern, which is always the complete matching part of the subject. All explicitly captured subpatterns are discarded.</item> + <tag><c>all_but_first</c></tag> + <item>All but the first matching subpattern, i.e. all explicitly captured subpatterns, but not the complete matching part of the subject string. This is useful if the regular expression as a whole matches a large part of the subject, but the part you're interested in is in an explicitly captured subpattern. If the return type is <c>list</c> or <c>binary</c>, not returning subpatterns you're not interested in is a good way to optimize.</item> + <tag><c>none</c></tag> + <item>Do not return matching subpatterns at all, yielding the single atom <c>match</c> as the return value of the function when matching successfully instead of the <c>{match, list()}</c> return. Specifying an empty list gives the same behavior.</item> + </taglist> + <p>The value list is a list of indexes for the subpatterns to return, where index 0 is for all of the pattern, and 1 is for the first explicit capturing subpattern in the regular expression, and so forth. When using named captured subpatterns (see below) in the regular expression, one can use <c>atom()</c>'s or <c>string()</c>'s to specify the subpatterns to be returned. This deserves an example, consider the following regular expression:</p> + <code> ".*(abcd).*"</code> + <p>matched against the string ""ABCabcdABC", capturing only the "abcd" part (the first explicit subpattern):</p> + <code> re:run("ABCabcdABC",".*(abcd).*",[{capture,[1]}]).</code> + <p>The call will yield the following result:</p> + <code> {match,[{3,4}]}</code> + <p>as the first explicitly captured subpattern is "(abcd)", matching "abcd" in the subject, at (zero-based) position 3, of length 4.</p> + <p>Now consider the same regular expression, but with the subpattern explicitly named 'FOO':</p> + <code> ".*(?<FOO>abcd).*"</code> + <p>With this expression, we could still give the index of the subpattern with the following call:</p> + <code> re:run("ABCabcdABC",".*(?<FOO>abcd).*",[{capture,[1]}]).</code> + <p>giving the same result as before. But as the subpattern is named, we can also give its name in the value list:</p> + <code> re:run("ABCabcdABC",".*(?<FOO>abcd).*",[{capture,['FOO']}]).</code> + <p>which would yield the same result as the earlier examples, namely:</p> + <code> {match,[{3,4}]}</code> + + <p>The values list might specify indexes or names not present in + the regular expression, in which case the return values vary + depending on the type. If the type is <c>index</c>, the tuple + <c>{-1,0}</c> is returned for values having no corresponding + subpattern in the regexp, but for the other types + (<c>binary</c> and <c>list</c>), the values are the empty binary + or list respectively.</p> + + </item> + <tag><c>Type</c></tag> + <item><p>Optionally specifies how captured substrings are to be returned. If omitted, the default of <c>index</c> is used. The <c>Type</c> can be one of the following:</p> + <taglist> + <tag><c>index</c></tag> + <item>Return captured substrings as pairs of byte indexes into the subject string and length of the matching string in the subject (as if the subject string was flattened with <c>iolist_to_binary/1</c> or <c>unicode:characters_to_binary/2</c> prior to matching). Note that the <c>unicode</c> option results in <em>byte-oriented</em> indexes in a (possibly imagined) <em>UTF-8 encoded</em> binary. A byte index tuple <c>{0,2}</c> might therefore represent one or two characters when <c>unicode</c> is in effect. This might seem contra-intuitive, but has been deemed the most effective and useful way to way to do it. To return lists instead might result in simpler code if that is desired. This return type is the default.</item> + <tag><c>list</c></tag> + <item>Return matching substrings as lists of characters (Erlang <c>string()</c>'s). It the <c>unicode</c> option is used in combination with the \\C sequence in the regular expression, a captured subpattern can contain bytes that has is not valid UTF-8 (\\C matches bytes regardless of character encoding). In that case the <c>list</c> capturing may result in the same types of tuples that <c>unicode:characters_to_list/2</c> can return, namely three-tuples with the tag <c>incomplete</c> or <c>error</c>, the successfully converted characters and the invalid UTF-8 tail of the conversion as a binary. The best strategy is to avoid using the\\C sequence when capturing lists.</item> + <tag><c>binary</c></tag> + <item>Return matching substrings as binaries. If the <c>unicode</c> option is used, these binaries is in UTF-8. If the \\C sequence is used together with <c>unicode</c> the binaries may be invalid UTF-8.</item> + </taglist> + </item> + </taglist> + <p>In general, subpatterns that got assigned no value in the match are returned as the tuple <c>{-1,0}</c> when <c>type</c> is <c>index</c>. Unassigned subpatterns are returned as the empty binary or list respectively for other return types. Consider the regular expression:</p> +<code> ".*((?<FOO>abdd)|a(..d)).*"</code> + <p>There are three explicitly capturing subpatterns, where the opening parenthesis position determines the order in the result, hence <c>((?<FOO>abdd)|a(..d))</c> is subpattern index 1, <c>(?<FOO>abdd)</c> is subpattern index 2 and <c>(..d)</c> is subpattern index 3. When matched against the following string:</p> +<code> "ABCabcdABC"</code> + <p>the subpattern at index 2 won't match, as "abdd" is not present in the string, but the complete pattern matches (due to the alternative <c>a(..d)</c>. The subpattern at index 2 is therefore unassigned and the default return value will be:</p> +<code> {match,[{0,10},{3,4},{-1,0},{4,3}]}</code> + <p>Setting the capture <c>Type</c> to <c>binary</c> would give the following:</p> +<code> {match,[<<"ABCabcdABC">>,<<"abcd">>,<<>>,<<"bcd">>]}</code> + <p>where the empty binary (<c><<>></c>) represents the unassigned subpattern. In the <c>binary</c> case, some information about the matching is therefore lost, the <c><<>></c> might just as well be an empty string captured.</p> + <p>If differentiation between empty matches and non existing subpatterns is necessary, use the <c>type</c> <c>index</c> + and do the conversion to the final type in Erlang code.</p> + + <p>When the option <c>global</c> is given, the <c>capture</c> + specification affects each match separately, so that:</p> + + <code> re:run("cacb","c(a|b)",[global,{capture,[1],list}]).</code> + + <p>gives the result:</p> + + <code> {match,[["a"],["b"]]}</code> + + </item> + </taglist> + <p>The options solely affecting the compilation step are described in the <c>re:compile/2</c> function.</p> + </desc> + </func> + <func> + <name>replace(Subject,RE,Replacement) -> iodata() | charlist()</name> + <fsummary>Match a subject against regular expression and replace matching elements with Replacement</fsummary> + <type> + <v>Subject = iodata() | charlist()</v> + <v>RE = mp() | iodata()</v> + <v>Replacement = iodata() | charlist()</v> + </type> + <desc> + <p>The same as <c>replace(Subject,RE,Replacement,[])</c>.</p> + </desc> + </func> + <func> + <name>replace(Subject,RE,Replacement,Options) -> iodata() | charlist() | binary() | list()</name> + <fsummary>Match a subject against regular expression and replace matching elements with Replacement</fsummary> + <type> + <v>Subject = iodata() | charlist()</v> + <v>RE = mp() | iodata() | charlist()</v> + <v>Replacement = iodata() | charlist()</v> + <v>Options = [ Option ]</v> + <v>Option = anchored | global | notbol | noteol | notempty | {offset, int()} | {newline, NLSpec} | bsr_anycrlf | bsr_unicode | {return, ReturnType} | CompileOpt</v> + <v>ReturnType = iodata | list | binary</v> + <v>CompileOpt = see compile/2 above</v> + <v>NLSpec = cr | crlf | lf | anycrlf | any </v> + </type> + <desc> + <p>Replaces the matched part of the <c>Subject</c> string with the content of <c>Replacement</c>.</p> + <p>Options are given as to the <c>re:run/3</c> function except that the <c>capture</c> option of <c>re:run/3</c> is not allowed. + Instead a <c>{return, ReturnType}</c> is present. The default return type is <c>iodata</c>, constructed in a + way to minimize copying. The <c>iodata</c> result can be used directly in many i/o-operations. If a flat <c>list()</c> is + desired, specify <c>{return, list}</c> and if a binary is preferred, specify <c>{return, binary}</c>.</p> + + <p>As in the <c>re:run/3</c> function, an <c>mp()</c> compiled + with the <c>unicode</c> option requires the <c>Subject</c> to be + a Unicode <c>charlist()</c>. If compilation is done implicitly + and the <c>unicode</c> compilation option is given to this + function, both the regular expression and the <c>Subject</c> + should be given as valid Unicode <c>charlist()</c>'s.</p> + + <p>The replacement string can contain the special character + <c>&</c>, which inserts the whole matching expression in the + result, and the special sequence <c>\\</c>N (where N is an + integer > 0), resulting in the subexpression number N will be + inserted in the result. If no subexpression with that number is + generated by the regular expression, nothing is inserted.</p> + <p>To insert an <c>&</c> or <c>\\</c> in the result, precede it + with a <c>\\</c>. Note that Erlang already gives a special + meaning to <c>\\</c> in literal strings, why a single <c>\\</c> + has to be written as <c>"\\\\"</c> and therefore a double <c>\\</c> + as <c>"\\\\\\\\"</c>. Example:</p> + <code> re:replace("abcd","c","[&]",[{return,list}]).</code> + <p>gives</p> + <code> "ab[c]d"</code> + <p>while</p> + <code> re:replace("abcd","c","[\\\&]",[{return,list}]).</code> + <p>gives</p> + <code> "ab[&]d"</code> + <p>As with <c>re:run/3</c>, compilation errors raise the <c>badarg</c> + exception, <c>re:compile/2</c> can be used to get more information + about the error.</p> + </desc> + </func> + <func> + <name>split(Subject,RE) -> SplitList</name> + <fsummary>Split a string by tokens specified as a regular expression</fsummary> + <type> + <v>Subject = iodata() | charlist()</v> + <v>RE = mp() | iodata()</v> + <v>SplitList = [ iodata() | charlist() ]</v> + </type> + <desc> + <p>The same as <c>split(Subject,RE,[])</c>.</p> + </desc> + </func> + + <func> + <name>split(Subject,RE,Options) -> SplitList</name> + <fsummary>Split a string by tokens specified as a regular expression</fsummary> + <type> + <v>Subject = iodata() | charlist()</v> + <v>RE = mp() | iodata() | charlist()</v> + <v>Options = [ Option ]</v> + <v>Option = anchored | global | notbol | noteol | notempty | {offset, int()} | {newline, NLSpec} | bsr_anycrlf | bsr_unicode | {return, ReturnType} | {parts, NumParts} | group | trim | CompileOpt</v> + <v>NumParts = int() | infinity</v> + <v>ReturnType = iodata | list | binary</v> + <v>CompileOpt = see compile/2 above</v> + <v>NLSpec = cr | crlf | lf | anycrlf | any </v> + <v>SplitList = [ RetData ] | [ GroupedRetData ]</v> + <v>GroupedRetData = [ RetData ]</v> + <v>RetData = iodata() charlist() | binary() | list()</v> + </type> + <desc> + <p>This function splits the input into parts by finding tokens + according to the regular expression supplied.</p> + + <p>The splitting is done basically by running a global regexp match and + dividing the initial string wherever a match occurs. The matching part + of the string is removed from the output.</p> + + <p>As in the <c>re:run/3</c> function, an <c>mp()</c> compiled + with the <c>unicode</c> option requires the <c>Subject</c> to be + a Unicode <c>charlist()</c>. If compilation is done implicitly + and the <c>unicode</c> compilation option is given to this + function, both the regular expression and the <c>Subject</c> + should be given as valid Unicode <c>charlist()</c>'s.</p> + + <p>The result is given as a list of "strings", the + preferred datatype given in the <c>return</c> option (default iodata).</p> + <p>If subexpressions are given in the regular expression, the + matching subexpressions are returned in the resulting list as + well. An example:</p> + +<code> re:split("Erlang","[ln]",[{return,list}]).</code> + + <p>will yield the result:</p> + +<code> ["Er","a","g"]</code> + + <p>while</p> + +<code> re:split("Erlang","([ln])",[{return,list}]).</code> + + <p>will yield</p> + +<code> ["Er","l","a","n","g"]</code> + + <p>The text matching the subexpression (marked by the parentheses + in the regexp) is + inserted in the result list where it was found. In effect this means + that concatenating the result of a split where the whole regexp is a + single subexpression (as in the example above) will always result in + the original string.</p> + + <p>As there is no matching subexpression for the last part in + the example (the "g"), there is nothing inserted after + that. To make the group of strings and the parts matching the + subexpressions more obvious, one might use the <c>group</c> + option, which groups together the part of the subject string with the + parts matching the subexpressions when the string was split:</p> + +<code> re:split("Erlang","([ln])",[{return,list},group]).</code> + + <p>gives:</p> + +<code> [["Er","l"],["a","n"],["g"]]</code> + + <p>Here the regular expression matched first the "l", + causing "Er" to be the first part in the result. When + the regular expression matched, the (only) subexpression was + bound to the "l", why the "l" is inserted + in the group together with "Er". The next match is of + the "n", making "a" the next part to be + returned. As the subexpression is bound to the substring + "n" in this case, the "n" is inserted into + this group. The last group consists of the rest of the string, + as no more matches are found.</p> + + + <p>By default, all parts of the string, including the empty + strings are returned from the function. As an example:</p> + +<code> re:split("Erlang","[lg]",[{return,list}]).</code> + + <p>The result will be:</p> + +<code> ["Er","an",[]]</code> + + <p>as the matching of the "g" in the end of the string + leaves an empty rest which is also returned. This behaviour + differs from the default behaviour of the split function in + Perl, where empty strings at the end are by default removed. To + get the + "trimming" default behavior of Perl, specify + <c>trim</c> as an option:</p> + +<code> re:split("Erlang","[lg]",[{return,list},trim]).</code> + + <p>The result will be:</p> + +<code> ["Er","an"]</code> + + <p>The "trim" option in effect says; "give me as + many parts as possible except the empty ones", which might + be useful in some circumstances. You can also specify how many + parts you want, by specifying <c>{parts,</c>N<c>}</c>:</p> + +<code> re:split("Erlang","[lg]",[{return,list},{parts,2}]).</code> + + <p>This will give:</p> + +<code> ["Er","ang"]</code> + + <p>Note that the last part is "ang", not + "an", as we only specified splitting into two parts, + and the splitting stops when enough parts are given, why the + result differs from that of <c>trim</c>.</p> + + <p>More than three parts are not possible with this indata, why</p> + +<code> re:split("Erlang","[lg]",[{return,list},{parts,4}]).</code> + + <p>will give the same result as the default, which is to be + viewed as "an infinite number of parts".</p> + + <p>Specifying <c>0</c> as the number of parts gives the same + effect as the option <c>trim</c>. If subexpressions are + captured, empty subexpression matches at the end are also + stripped from the result if <c>trim</c> or <c>{parts,0}</c> is + specified.</p> + + <p>If you are familiar with Perl, the <c>trim</c> + behaviour corresponds exactly to the Perl default, the + <c>{parts,N}</c> where N is a positive integer corresponds + exactly to the Perl behaviour with a positive numerical third + parameter and the default behaviour of <c>re:split/3</c> corresponds + to that when the Perl routine is given a negative integer as the + third parameter.</p> + + <p>Summary of options not previously described for the <c>re:run/3</c> function:</p> + <taglist> + <tag>{return,ReturnType}</tag> + <item><p>Specifies how the parts of the original string are presented in the result list. The possible types are:</p> + <taglist> + <tag>iodata</tag> + <item>The variant of <c>iodata()</c> that gives the least copying of data with the current implementation (often a binary, but don't depend on it).</item> + <tag>binary</tag> + <item>All parts returned as binaries.</item> + <tag>list</tag> + <item>All parts returned as lists of characters ("strings").</item> + </taglist> + </item> + <tag>group</tag> + <item> + + <p>Groups together the part of the string with + the parts of the string matching the subexpressions of the + regexp.</p> + <p>The return value from the function will in this case be a + <c>list()</c> of <c>list()</c>'s. Each sublist begins with the + string picked out of the subject string, followed by the parts + matching each of the subexpressions in order of occurrence in the + regular expression.</p> + + </item> + <tag>{parts,N}</tag> + <item> + + <p>Specifies the number of parts the subject string is to be + split into.</p> + + <p>The number of parts should be a positive integer for a specific maximum on the + number of parts and <c>infinity</c> for the maximum number of + parts possible (the default). Specifying <c>{parts,0}</c> gives as many parts as + possible disregarding empty parts at the end, the same as + specifying <c>trim</c></p> + </item> + <tag>trim</tag> + <item> + + <p>Specifies that empty parts at the end of the result list are + to be disregarded. The same as specifying <c>{parts,0}</c>. This + corresponds to the default behaviour of the <c>split</c> + built in function in Perl.</p> + </item> + </taglist> + + </desc> + </func> + </funcs> + + + <section> + <title>PERL LIKE REGULAR EXPRESSIONS SYNTAX</title> + <p>The following sections contain reference material for the + regular expressions used by this module. The regular expression + reference is taken from the PCRE documentation, but converted as + needed.</p> + <p>The documentation is altered where appropriate and where the re + module behaves differently than the PCRE library.</p> + </section> + +<section><title>PCRE regular expression details</title> + +<p>The syntax and semantics of the regular expressions that are supported by PCRE +are described in detail below. Perl's regular expressions are described in its own documentation, and +regular expressions in general are covered in a number of books, some of which +have copious examples. Jeffrey Friedl's "Mastering Regular Expressions", +published by O'Reilly, covers regular expressions in great detail. This +description of PCRE's regular expressions is intended as reference material.</p> +<p>The reference material is divided into the following sections:</p> +<list> +<item><seealso marker="#sect1">Newline conventions</seealso></item> +<item><seealso marker="#sect2">Characters and metacharacters</seealso></item> +<item><seealso marker="#sect3">Backslash</seealso></item> +<item><seealso marker="#sect4">Circumflex and dollar</seealso></item> +<item><seealso marker="#sect5">Full stop (period, dot)</seealso></item> +<item><seealso marker="#sect6">Matching a single byte</seealso></item> +<item><seealso marker="#sect7">Square brackets and character classes</seealso></item> +<item><seealso marker="#sect8">POSIX character classes</seealso></item> +<item><seealso marker="#sect9">Vertical bar</seealso></item> +<item><seealso marker="#sect10">Internal option setting</seealso></item> +<item><seealso marker="#sect11">Subpatterns</seealso></item> +<item><seealso marker="#sect12">Duplicate subpattern numbers</seealso></item> +<item><seealso marker="#sect13">Named subpatterns</seealso></item> +<item><seealso marker="#sect14">Repetition</seealso></item> +<item><seealso marker="#sect15">Atomic grouping and possessive quantifiers</seealso></item> +<item><seealso marker="#sect16">Back references</seealso></item> +<item><seealso marker="#sect17">Assertions</seealso></item> +<item><seealso marker="#sect18">Conditional subpatterns</seealso></item> +<item><seealso marker="#sect19">Comments</seealso></item> +<item><seealso marker="#sect20">Recursive patterns</seealso></item> +<item><seealso marker="#sect21">Subpatterns as subroutines</seealso></item> +<!-- XXX C Interface +<item><seealso marker="#sect22">Callouts</seealso></item> +--> +<item><seealso marker="#sect23">Backtracking control</seealso></item> +</list> + +</section> + + +<section><marker id="sect1"></marker><title>Newline conventions</title> + +<p>PCRE supports +five +different conventions for indicating line breaks in +strings: a single CR (carriage return) character, a single LF (linefeed) +character, the two-character sequence CRLF +, any of the three preceding, or any +Unicode newline sequence.</p> + +<p>It is also possible to specify a newline convention by starting a pattern +string with one of the following five sequences:</p> + +<taglist> + <tag>(*CR)</tag> <item>carriage return</item> + <tag>(*LF)</tag> <item>linefeed</item> + <tag>(*CRLF)</tag> <item>carriage return, followed by linefeed</item> + <tag>(*ANYCRLF)</tag> <item>any of the three above</item> + <tag>(*ANY)</tag> <item>all Unicode newline sequences</item> +</taglist> + +<p>These override the default and the options given to <c>re:compile/2</c>. For +example, the pattern:</p> + +<quote> +<p> (*CR)a.b</p> +</quote> + +<p>changes the convention to CR. That pattern matches "a\\nb" because LF is no +longer a newline. Note that these special settings, which are not +Perl-compatible, are recognized only at the very start of a pattern, and that +they must be in upper case. If more than one of them is present, the last one +is used.</p> + +<p>The newline convention does not affect what the \\R escape sequence matches. By +default, this is any Unicode newline sequence, for Perl compatibility. However, +this can be changed; see the description of \\R in the section entitled + +"Newline sequences" + +below. A change of \\R setting can be combined with a change of newline +convention.</p> + +</section> + + +<section><marker id="sect2"></marker><title>Characters and metacharacters</title> +<!-- .rs --> + +<p>A regular expression is a pattern that is matched against a subject +string from left to right. Most characters stand for themselves in a +pattern, and match the corresponding characters in the subject. As a +trivial example, the pattern</p> + +<quote> +<p> The quick brown fox</p> +</quote> + +<p>matches a portion of a subject string that is identical to +itself. When caseless matching is specified (the <c>caseless</c> +option), letters are matched independently of case.</p> + +<p>The power of regular expressions comes from the ability to include +alternatives and repetitions in the pattern. These are encoded in the +pattern by the use of <em>metacharacters</em>, which do not stand for +themselves but instead are interpreted in some special way.</p> + +<p>There are two different sets of metacharacters: those that are recognized +anywhere in the pattern except within square brackets, and those that are +recognized within square brackets. Outside square brackets, the metacharacters +are as follows:</p> + +<taglist> + <tag>\\</tag> <item>general escape character with several uses</item> + <tag>^</tag> <item>assert start of string (or line, in multiline mode)</item> + <tag>$</tag> <item>assert end of string (or line, in multiline mode)</item> + <tag>.</tag> <item>match any character except newline (by default)</item> + <tag>[</tag> <item>start character class definition</item> + <tag>|</tag> <item>start of alternative branch</item> + <tag>(</tag> <item>start subpattern</item> + <tag>)</tag> <item>end subpattern</item> + <tag>?</tag> <item>extends the meaning of (, + also 0 or 1 quantifier, + also quantifier minimizer</item> + <tag>*</tag> <item>0 or more quantifier</item> + <tag>+</tag> <item>1 or more quantifier, + also "possessive quantifier"</item> + <tag>{</tag> <item>start min/max quantifier</item> +</taglist> + +<p>Part of a pattern that is in square brackets is called a "character class". In +a character class the only metacharacters are:</p> + +<taglist> + <tag>\\</tag> <item>general escape character</item> + <tag>^</tag> <item>negate the class, but only if the first character</item> + <tag>-</tag> <item>indicates character range</item> + <tag>[</tag> <item>POSIX character class (only if followed by POSIX + syntax)</item> + <tag>]</tag> <item>terminates the character class</item> +</taglist> + +<p>The following sections describe the use of each of the metacharacters.</p> + + +</section> + +<section><marker id="sect3"></marker><title>Backslash</title> + + +<p>The backslash character has several uses. Firstly, if it is followed by a +non-alphanumeric character, it takes away any special meaning that character +may have. This use of backslash as an escape character applies both inside and +outside character classes.</p> + +<p>For example, if you want to match a * character, you write \\* in the pattern. +This escaping action applies whether or not the following character would +otherwise be interpreted as a metacharacter, so it is always safe to precede a +non-alphanumeric with backslash to specify that it stands for itself. In +particular, if you want to match a backslash, you write \\\\.</p> + +<p>If a pattern is compiled with the <c>extended</c> option, whitespace in the +pattern (other than in a character class) and characters between a # outside +a character class and the next newline are ignored. An escaping backslash can +be used to include a whitespace or # character as part of the pattern.</p> + +<p>If you want to remove the special meaning from a sequence of characters, you +can do so by putting them between \\Q and \\E. This is different from Perl in +that $ and @ are handled as literals in \\Q...\\E sequences in PCRE, whereas in +Perl, $ and @ cause variable interpolation. Note the following examples:</p> +<code type="none"> + Pattern PCRE matches Perl matches + + \\Qabc$xyz\\E abc$xyz abc followed by the contents of $xyz + \\Qabc\\$xyz\\E abc\\$xyz abc\\$xyz + \\Qabc\\E\\$\\Qxyz\\E abc$xyz abc$xyz</code> + + +<p>The \\Q...\\E sequence is recognized both inside and outside character classes.</p> + + +<p><em>Non-printing characters</em></p> + +<p>A second use of backslash provides a way of encoding non-printing characters +in patterns in a visible manner. There is no restriction on the appearance of +non-printing characters, apart from the binary zero that terminates a pattern, +but when a pattern is being prepared by text editing, it is usually easier to +use one of the following escape sequences than the binary character it +represents:</p> + +<taglist> + <tag>\\a</tag> <item>alarm, that is, the BEL character (hex 07)</item> + <tag>\\cx</tag> <item>"control-x", where x is any character</item> + <tag>\\e </tag> <item>escape (hex 1B)</item> + <tag>\\f</tag> <item>formfeed (hex 0C)</item> + <tag>\\n</tag> <item>linefeed (hex 0A)</item> + <tag>\\r</tag> <item>carriage return (hex 0D)</item> + <tag>\\t </tag> <item>tab (hex 09)</item> + <tag>\\ddd</tag> <item>character with octal code ddd, or backreference</item> + <tag>\\xhh </tag> <item>character with hex code hh</item> + <tag>\\x{hhh..}</tag> <item>character with hex code hhh..</item> +</taglist> + +<p>The precise effect of \\cx is as follows: if x is a lower case letter, it +is converted to upper case. Then bit 6 of the character (hex 40) is inverted. +Thus \\cz becomes hex 1A, but \\c{ becomes hex 3B, while \\c; becomes hex +7B.</p> + +<p>After \\x, from zero to two hexadecimal digits are read (letters can be in +upper or lower case). Any number of hexadecimal digits may appear between \\x{ +and }, but the value of the character code must be less than 256 in non-UTF-8 +mode, and less than 2**31 in UTF-8 mode. That is, the maximum value in +hexadecimal is 7FFFFFFF. Note that this is bigger than the largest Unicode code +point, which is 10FFFF.</p> + +<p>If characters other than hexadecimal digits appear between \\x{ and }, or if +there is no terminating }, this form of escape is not recognized. Instead, the +initial \\x will be interpreted as a basic hexadecimal escape, with no +following digits, giving a character whose value is zero.</p> + +<p>Characters whose value is less than 256 can be defined by either of the two +syntaxes for \\x. There is no difference in the way they are handled. For +example, \\xdc is exactly the same as \\x{dc}.</p> + +<p>After \\0 up to two further octal digits are read. If there are fewer than two +digits, just those that are present are used. Thus the sequence \\0\\x\\07 +specifies two binary zeros followed by a BEL character (code value 7). Make +sure you supply two digits after the initial zero if the pattern character that +follows is itself an octal digit.</p> + +<p>The handling of a backslash followed by a digit other than 0 is complicated. +Outside a character class, PCRE reads it and any following digits as a decimal +number. If the number is less than 10, or if there have been at least that many +previous capturing left parentheses in the expression, the entire sequence is +taken as a <em>back reference</em>. A description of how this works is given +later, following the discussion of parenthesized subpatterns.</p> + + +<p>Inside a character class, or if the decimal number is greater than 9 and there +have not been that many capturing subpatterns, PCRE re-reads up to three octal +digits following the backslash, and uses them to generate a data character. Any +subsequent digits stand for themselves. +The value of a +character specified in octal must be less than \\400. +In non-UTF-8 mode, the value of a +character specified in octal must be less than \\400. In UTF-8 mode, values up +to \\777 are permitted. + +For example:</p> + +<taglist> + <tag>\\040</tag> <item>is another way of writing a space</item> + + <tag>\\40</tag> <item>is the same, provided there are fewer than 40 + previous capturing subpatterns</item> + <tag>\\7</tag> <item>is always a back reference</item> + + <tag>\\11</tag> <item> might be a back reference, or another way of + writing a tab</item> + <tag>\\011</tag> <item>is always a tab</item> + <tag>\\0113</tag> <item>is a tab followed by the character "3"</item> + + <tag>\\113</tag> <item>might be a back reference, otherwise the + character with octal code 113</item> + + <tag>\\377</tag> <item>might be a back reference, otherwise + the byte consisting entirely of 1 bits</item> + + <tag>\\81</tag> <item>is either a back reference, or a binary zero + followed by the two characters "8" and "1"</item> +</taglist> + +<p>Note that octal values of 100 or greater must not be introduced by +a leading zero, because no more than three octal digits are ever +read.</p> + +<p>All the sequences that define a single character value can be used +both inside and outside character classes. In addition, inside a +character class, the sequence \\b is interpreted as the backspace +character (hex 08), and the sequences \\R and \\X are interpreted as +the characters "R" and "X", respectively. Outside a character class, +these sequences have different meanings (see below).</p> + +<p><em>Absolute and relative back references</em></p> + +<p>The sequence \\g followed by an unsigned or a negative number, +optionally enclosed in braces, is an absolute or relative back +reference. A named back reference can be coded as \\g{name}. Back +references are discussed later, following the discussion of +parenthesized subpatterns.</p> + +<p><em>Generic character types</em></p> + +<p>Another use of backslash is for specifying generic character types. The +following are always recognized:</p> + +<taglist> + <tag>\\d</tag> <item>any decimal digit</item> + <tag>\\D</tag> <item>any character that is not a decimal digit</item> + <tag>\\h</tag> <item>any horizontal whitespace character</item> + <tag>\\H</tag> <item>any character that is not a horizontal whitespace character</item> + <tag>\\s</tag> <item>any whitespace character</item> + <tag>\\S</tag> <item>any character that is not a whitespace character</item> + <tag>\\v</tag> <item>any vertical whitespace character</item> + <tag>\\V</tag> <item>any character that is not a vertical whitespace character</item> + <tag>\\w</tag> <item>any "word" character</item> + <tag>\\W</tag> <item>any "non-word" character</item> +</taglist> + +<p>Each pair of escape sequences partitions the complete set of characters into +two disjoint sets. Any given character matches one, and only one, of each pair.</p> + +<p>These character type sequences can appear both inside and outside character +classes. They each match one character of the appropriate type. If the current +matching point is at the end of the subject string, all of them fail, since +there is no character to match.</p> + +<p>For compatibility with Perl, \\s does not match the VT character (code 11). +This makes it different from the POSIX "space" class. The \\s characters +are HT (9), LF (10), FF (12), CR (13), and space (32). If "use locale;" is +included in a Perl script, \\s may match the VT character. In PCRE, it never +does.</p> + +<p>In UTF-8 mode, characters with values greater than 128 never match \\d, \\s, or +\\w, and always match \\D, \\S, and \\W. This is true even when Unicode +character property support is available. These sequences retain their original +meanings from before UTF-8 support was available, mainly for efficiency +reasons.</p> + +<p>The sequences \\h, \\H, \\v, and \\V are Perl 5.10 features. In contrast to the +other sequences, these do match certain high-valued codepoints in UTF-8 mode. +The horizontal space characters are:</p> + +<taglist> + <tag>U+0009</tag> <item>Horizontal tab</item> + <tag>U+0020</tag> <item>Space</item> + <tag>U+00A0</tag> <item>Non-break space</item> + <tag>U+1680</tag> <item>Ogham space mark</item> + <tag>U+180E</tag> <item>Mongolian vowel separator</item> + <tag>U+2000</tag> <item>En quad</item> + <tag>U+2001</tag> <item>Em quad</item> + <tag>U+2002</tag> <item>En space</item> + <tag>U+2003</tag> <item>Em space</item> + <tag>U+2004</tag> <item>Three-per-em space</item> + <tag>U+2005</tag> <item>Four-per-em space</item> + <tag>U+2006</tag> <item>Six-per-em space</item> + <tag>U+2007</tag> <item>Figure space</item> + <tag>U+2008</tag> <item>Punctuation space</item> + <tag>U+2009</tag> <item>Thin space</item> + <tag>U+200A</tag> <item>Hair space</item> + <tag>U+202F</tag> <item>Narrow no-break space</item> + <tag>U+205F</tag> <item>Medium mathematical space</item> + <tag>U+3000</tag> <item>Ideographic space</item> +</taglist> + +<p>The vertical space characters are:</p> + +<taglist> + <tag>U+000A</tag> <item>Linefeed</item> + <tag>U+000B</tag> <item>Vertical tab</item> + <tag>U+000C</tag> <item>Formfeed</item> + <tag>U+000D</tag> <item>Carriage return</item> + <tag>U+0085</tag> <item>Next line</item> + <tag>U+2028</tag> <item>Line separator</item> + <tag>U+2029</tag> <item>Paragraph separator</item> +</taglist> + +<p>A "word" character is an underscore or any character less than 256 that is a +letter or digit. The definition of letters and digits is controlled by PCRE's +low-valued character tables, which are always ISO-8859-1.</p> + +<p><em>Newline sequences</em></p> + +<p>Outside a character class, by default, the escape sequence \\R matches any +Unicode newline sequence. This is a Perl 5.10 feature. In non-UTF-8 mode \\R is +equivalent to the following:</p> + +<quote><p> (?>\\r\\n|\\n|\\x0b|\\f|\\r|\\x85)</p></quote> + +<p>This is an example of an "atomic group", details of which are given below.</p> + +<p>This particular group matches either the two-character sequence CR followed by +LF, or one of the single characters LF (linefeed, U+000A), VT (vertical tab, +U+000B), FF (formfeed, U+000C), CR (carriage return, U+000D), or NEL (next +line, U+0085). The two-character sequence is treated as a single unit that +cannot be split.</p> + +<p>In UTF-8 mode, two additional characters whose codepoints are greater than 255 +are added: LS (line separator, U+2028) and PS (paragraph separator, U+2029). +Unicode character property support is not needed for these characters to be +recognized.</p> + + +<p>It is possible to restrict \\R to match only CR, LF, or CRLF (instead of the +complete set of Unicode line endings) by setting the option <c>bsr_anycrlf</c> +either at compile time or when the pattern is matched. (BSR is an abbreviation +for "backslash R".) This can be made the default when PCRE is built; if this is +the case, the other behaviour can be requested via the <c>bsr_unicode</c> option. +It is also possible to specify these settings by starting a pattern string with +one of the following sequences:</p> + +<p> (*BSR_ANYCRLF) CR, LF, or CRLF only + (*BSR_UNICODE) any Unicode newline sequence</p> + +<p>These override the default and the options given to <c>re:compile/2</c>, but +they can be overridden by options given to <c>re:run/3</c>. Note that these +special settings, which are not Perl-compatible, are recognized only at the +very start of a pattern, and that they must be in upper case. If more than one +of them is present, the last one is used. They can be combined with a change of +newline convention, for example, a pattern can start with:</p> + +<p> (*ANY)(*BSR_ANYCRLF)</p> + +<p>Inside a character class, \\R matches the letter "R".</p> + + +<p><em>Unicode character properties</em></p> + +<p>When PCRE is built with Unicode character property support, three additional +escape sequences that match characters with specific properties are available. +When not in UTF-8 mode, these sequences are of course limited to testing +characters whose codepoints are less than 256, but they do work in this mode. +The extra escape sequences are:</p> + +<p> \\p{<em>xx</em>} a character with the <em>xx</em> property + \\P{<em>xx</em>} a character without the <em>xx</em> property + \\X an extended Unicode sequence</p> + +<p>The property names represented by <em>xx</em> above are limited to the Unicode +script names, the general category properties, and "Any", which matches any +character (including newline). Other properties such as "InMusicalSymbols" are +not currently supported by PCRE. Note that \\P{Any} does not match any +characters, so always causes a match failure.</p> + +<p>Sets of Unicode characters are defined as belonging to certain scripts. A +character from one of these sets can be matched using a script name. For +example:</p> + +<p> \\p{Greek} + \\P{Han}</p> + +<p>Those that are not part of an identified script are lumped together as +"Common". The current list of scripts is:</p> + +<list> +<item>Arabic</item> +<item>Armenian</item> +<item>Balinese</item> +<item>Bengali</item> +<item>Bopomofo</item> +<item>Braille</item> +<item>Buginese</item> +<item>Buhid</item> +<item>Canadian_Aboriginal</item> +<item>Cherokee</item> +<item>Common</item> +<item>Coptic</item> +<item>Cuneiform</item> +<item>Cypriot</item> +<item>Cyrillic</item> +<item>Deseret</item> +<item>Devanagari</item> +<item>Ethiopic</item> +<item>Georgian</item> +<item>Glagolitic</item> +<item>Gothic</item> +<item>Greek</item> +<item>Gujarati</item> +<item>Gurmukhi</item> +<item>Han</item> +<item>Hangul</item> +<item>Hanunoo</item> +<item>Hebrew</item> +<item>Hiragana</item> +<item>Inherited</item> +<item>Kannada</item> +<item>Katakana</item> +<item>Kharoshthi</item> +<item>Khmer</item> +<item>Lao</item> +<item>Latin</item> +<item>Limbu</item> +<item>Linear_B</item> +<item>Malayalam</item> +<item>Mongolian</item> +<item>Myanmar</item> +<item>New_Tai_Lue</item> +<item>Nko</item> +<item>Ogham</item> +<item>Old_Italic</item> +<item>Old_Persian</item> +<item>Oriya</item> +<item>Osmanya</item> +<item>Phags_Pa</item> +<item>Phoenician</item> +<item>Runic</item> +<item>Shavian</item> +<item>Sinhala</item> +<item>Syloti_Nagri</item> +<item>Syriac</item> +<item>Tagalog</item> +<item>Tagbanwa</item> +<item>Tai_Le</item> +<item>Tamil</item> +<item>Telugu</item> +<item>Thaana</item> +<item>Thai</item> +<item>Tibetan</item> +<item>Tifinagh</item> +<item>Ugaritic</item> +<item>Yi</item> +</list> + +<p>Each character has exactly one general category property, specified by a +two-letter abbreviation. For compatibility with Perl, negation can be specified +by including a circumflex between the opening brace and the property name. For +example, \\p{^Lu} is the same as \\P{Lu}.</p> + +<p>If only one letter is specified with \\p or \\P, it includes all the general +category properties that start with that letter. In this case, in the absence +of negation, the curly brackets in the escape sequence are optional; these two +examples have the same effect:</p> + +<list><item>\\p{L}</item> + <item>\\pL</item></list> + +<p>The following general category property codes are supported:</p> + +<taglist> + <tag>C</tag> <item>Other</item> + <tag>Cc</tag> <item>Control</item> + <tag>Cf</tag> <item>Format</item> + <tag>Cn</tag> <item>Unassigned</item> + <tag>Co</tag> <item>Private use</item> + <tag>Cs</tag> <item>Surrogate</item> +</taglist> + +<taglist> + <tag>L</tag> <item>Letter</item> + <tag>Ll</tag> <item>Lower case letter</item> + <tag>Lm</tag> <item>Modifier letter</item> + <tag>Lo</tag> <item>Other letter</item> + <tag>Lt</tag> <item>Title case letter</item> + <tag>Lu</tag> <item>Upper case letter</item> +</taglist> + + +<taglist> + <tag>M</tag> <item>Mark</item> + <tag>Mc</tag> <item>Spacing mark</item> + <tag>Me</tag> <item>Enclosing mark</item> + <tag>Mn</tag> <item>Non-spacing mark</item> +</taglist> + +<taglist> + <tag>N</tag> <item>Number</item> + <tag>Nd</tag> <item>Decimal number</item> + <tag>Nl</tag> <item>Letter number</item> + <tag>No</tag> <item>Other number</item> +</taglist> + +<taglist> + <tag>P</tag> <item>Punctuation</item> + <tag>Pc</tag> <item>Connector punctuation</item> + <tag>Pd</tag> <item>Dash punctuation</item> + <tag>Pe</tag> <item>Close punctuation</item> + <tag>Pf</tag> <item>Final punctuation</item> + <tag>Pi</tag> <item>Initial punctuation</item> + <tag>Po</tag> <item>Other punctuation</item> + <tag>Ps</tag> <item>Open punctuation</item> +</taglist> + +<taglist> + <tag>S</tag> <item>Symbol</item> + <tag>Sc</tag> <item>Currency symbol</item> + <tag>Sk</tag> <item>Modifier symbol</item> + <tag>Sm</tag> <item>Mathematical symbol</item> + <tag>So</tag> <item>Other symbol</item> +</taglist> + +<taglist> + <tag>Z</tag> <item>Separator</item> + <tag>Zl</tag> <item>Line separator</item> + <tag>Zp</tag> <item>Paragraph separator</item> + <tag>Zs</tag> <item>Space separator</item> +</taglist> + +<p>The special property L& is also supported: it matches a character that has +the Lu, Ll, or Lt property, in other words, a letter that is not classified as +a modifier or "other".</p> + +<p>The Cs (Surrogate) property applies only to characters in the range U+D800 to +U+DFFF. Such characters are not valid in UTF-8 strings (see RFC 3629) and so +cannot be tested by PCRE, unless UTF-8 validity checking has been turned off +(see the discussion of <c>no_utf8_check</c> in the +<em>pcreapi</em> +page).</p> + +<p>The long synonyms for these properties that Perl supports (such as \\p{Letter}) +are not supported by PCRE, nor is it permitted to prefix any of these +properties with "Is".</p> + +<p>No character that is in the Unicode table has the Cn (unassigned) property. +Instead, this property is assumed for any code point that is not in the +Unicode table.</p> + +<p>Specifying caseless matching does not affect these escape sequences. For +example, \\p{Lu} always matches only upper case letters.</p> + +<p>The \\X escape matches any number of Unicode characters that form an extended +Unicode sequence. \\X is equivalent to</p> + +<quote><p> (?>\\PM\\pM*)</p></quote> + +<p>That is, it matches a character without the "mark" property, followed by zero +or more characters with the "mark" property, and treats the sequence as an +atomic group +(see below). +Characters with the "mark" property are typically accents that affect the +preceding character. None of them have codepoints less than 256, so in +non-UTF-8 mode \\X matches any one character.</p> + +<p>Matching characters by Unicode property is not fast, because PCRE has to search +a structure that contains data for over fifteen thousand characters. That is +why the traditional escape sequences such as \\d and \\w do not use Unicode +properties in PCRE.</p> + +<p><em>Resetting the match start</em></p> + +<p>The escape sequence \\K, which is a Perl 5.10 feature, causes any previously +matched characters not to be included in the final matched sequence. For +example, the pattern:</p> + +<quote><p> foo\\Kbar</p></quote> + +<p>matches "foobar", but reports that it has matched "bar". This feature is +similar to a lookbehind assertion +<!-- HTML <a href="#lookbehind"> --> +<!-- </a> --> +(described below). + +However, in this case, the part of the subject before the real match does not +have to be of fixed length, as lookbehind assertions do. The use of \\K does +not interfere with the setting of +captured substrings. +For example, when the pattern</p> + +<quote><p> (foo)\\Kbar</p></quote> + +<p>matches "foobar", the first substring is still set to "foo".</p> + +<p><em>Simple assertions</em></p> + +<p>The final use of backslash is for certain simple assertions. An +assertion specifies a condition that has to be met at a particular +point in a match, without consuming any characters from the subject +string. The use of subpatterns for more complicated assertions is +described below. The backslashed assertions are:</p> + +<taglist> + <tag>\\b</tag> <item>matches at a word boundary</item> + <tag>\\B</tag> <item>matches when not at a word boundary</item> + <tag>\\A</tag> <item>matches at the start of the subject</item> + <tag>\\Z</tag> <item>matches at the end of the subject + also matches before a newline at the end of + the subject</item> + <tag>\\z</tag> <item>matches only at the end of the subject</item> + <tag>\\G</tag> <item>matches at the first matching position in the + subject</item> +</taglist> + +<p>These assertions may not appear in character classes (but note that \\b has a +different meaning, namely the backspace character, inside a character class).</p> + +<p>A word boundary is a position in the subject string where the current character +and the previous character do not both match \\w or \\W (i.e. one matches +\\w and the other matches \\W), or the start or end of the string if the +first or last character matches \\w, respectively.</p> + +<p>The \\A, \\Z, and \\z assertions differ from the traditional circumflex and +dollar (described in the next section) in that they only ever match at the very +start and end of the subject string, whatever options are set. Thus, they are +independent of multiline mode. These three assertions are not affected by the +<c>notbol</c> or <c>noteol</c> options, which affect only the behaviour of the +circumflex and dollar metacharacters. However, if the <em>startoffset</em> +argument of <c>re:run/3</c> is non-zero, indicating that matching is to start +at a point other than the beginning of the subject, \\A can never match. The +difference between \\Z and \\z is that \\Z matches before a newline at the end +of the string as well as at the very end, whereas \\z matches only at the end.</p> + +<p>The \\G assertion is true only when the current matching position is at the +start point of the match, as specified by the <em>startoffset</em> argument of +<c>re:run/3</c>. It differs from \\A when the value of <em>startoffset</em> is +non-zero. By calling <c>re:run/3</c> multiple times with appropriate +arguments, you can mimic Perl's /g option, and it is in this kind of +implementation where \\G can be useful.</p> + +<p>Note, however, that PCRE's interpretation of \\G, as the start of the current +match, is subtly different from Perl's, which defines it as the end of the +previous match. In Perl, these can be different when the previously matched +string was empty. Because PCRE does just one match at a time, it cannot +reproduce this behaviour.</p> + +<p>If all the alternatives of a pattern begin with \\G, the expression is anchored +to the starting match position, and the "anchored" flag is set in the compiled +regular expression.</p> + +</section> + +<section><marker id="sect4"></marker><title>Circumflex and dollar</title> + +<p>Outside a character class, in the default matching mode, the circumflex +character is an assertion that is true only if the current matching point is +at the start of the subject string. If the <em>startoffset</em> argument of +<c>re:run/3</c> is non-zero, circumflex can never match if the <c>multiline</c> +option is unset. Inside a character class, circumflex has an entirely different +meaning (see below).</p> + +<p>Circumflex need not be the first character of the pattern if a number of +alternatives are involved, but it should be the first thing in each alternative +in which it appears if the pattern is ever to match that branch. If all +possible alternatives start with a circumflex, that is, if the pattern is +constrained to match only at the start of the subject, it is said to be an +"anchored" pattern. (There are also other constructs that can cause a pattern +to be anchored.)</p> + +<p>A dollar character is an assertion that is true only if the current matching +point is at the end of the subject string, or immediately before a newline +at the end of the string (by default). Dollar need not be the last character of +the pattern if a number of alternatives are involved, but it should be the last +item in any branch in which it appears. Dollar has no special meaning in a +character class.</p> + +<p>The meaning of dollar can be changed so that it matches only at the +very end of the string, by setting the <c>dollar_endonly</c> option at +compile time. This does not affect the \\Z assertion.</p> + +<p>The meanings of the circumflex and dollar characters are changed if the +<c>multiline</c> option is set. When this is the case, a circumflex matches +immediately after internal newlines as well as at the start of the subject +string. It does not match after a newline that ends the string. A dollar +matches before any newlines in the string, as well as at the very end, when +<c>multiline</c> is set. When newline is specified as the two-character +sequence CRLF, isolated CR and LF characters do not indicate newlines.</p> + +<p>For example, the pattern /^abc$/ matches the subject string +"def\\nabc" (where \\n represents a newline) in multiline mode, but +not otherwise. Consequently, patterns that are anchored in single line +mode because all branches start with ^ are not anchored in multiline +mode, and a match for circumflex is possible when the +<em>startoffset</em> argument of <c>re:run/3</c> is non-zero. The +<c>dollar_endonly</c> option is ignored if <c>multiline</c> is set.</p> + +<p>Note that the sequences \\A, \\Z, and \\z can be used to match the start and +end of the subject in both modes, and if all branches of a pattern start with +\\A it is always anchored, whether or not <c>multiline</c> is set.</p> + + +</section> + +<section><marker id="sect5"></marker><title>Full stop (period, dot)</title> + +<p>Outside a character class, a dot in the pattern matches any one character in +the subject string except (by default) a character that signifies the end of a +line. + In UTF-8 mode, the matched character may be more than one byte long. +</p> + +<p>When a line ending is defined as a single character, dot never matches that +character; when the two-character sequence CRLF is used, dot does not match CR +if it is immediately followed by LF, but otherwise it matches all characters +(including isolated CRs and LFs). +When any Unicode line endings are being +recognized, dot does not match CR or LF or any of the other line ending +characters. +</p> + +<p>The behaviour of dot with regard to newlines can be changed. If +the <c>dotall</c> option is set, a dot matches any one character, +without exception. If the two-character sequence CRLF is present in +the subject string, it takes two dots to match it.</p> + +<p>The handling of dot is entirely independent of the handling of +circumflex and dollar, the only relationship being that they both +involve newlines. Dot has no special meaning in a character class.</p> + +</section> + +<section><marker id="sect6"></marker><title>Matching a single byte</title> + +<p>Outside a character class, the escape sequence \\C matches any one byte, both +in and out of UTF-8 mode. Unlike a dot, it always matches any line-ending +characters. The feature is provided in Perl in order to match individual bytes +in UTF-8 mode. Because it breaks up UTF-8 characters into individual bytes, +what remains in the string may be a malformed UTF-8 string. For this reason, +the \\C escape sequence is best avoided.</p> + +<p>PCRE does not allow \\C to appear in lookbehind assertions (described below), +because in UTF-8 mode this would make it impossible to calculate the length of +the lookbehind.</p> + +</section> + +<section><marker id="sect7"></marker><title>Square brackets and character classes</title> + +<p>An opening square bracket introduces a character class, terminated +by a closing square bracket. A closing square bracket on its own is +not special. If a closing square bracket is required as a member of +the class, it should be the first data character in the class (after +an initial circumflex, if present) or escaped with a backslash.</p> + +<p>A character class matches a single character in the subject. +In +UTF-8 mode, the character may occupy more than one byte. +A matched +character must be in the set of characters defined by the class, +unless the first character in the class definition is a circumflex, in +which case the subject character must not be in the set defined by the +class. If a circumflex is actually required as a member of the class, +ensure it is not the first character, or escape it with a +backslash.</p> + +<p>For example, the character class [aeiou] matches any lower case vowel, while +[^aeiou] matches any character that is not a lower case vowel. Note that a +circumflex is just a convenient notation for specifying the characters that +are in the class by enumerating those that are not. A class that starts with a +circumflex is not an assertion: it still consumes a character from the subject +string, and therefore it fails if the current pointer is at the end of the +string.</p> + +<p>In UTF-8 mode, characters with values greater than 255 can be included in a +class as a literal string of bytes, or by using the \\x{ escaping mechanism.</p> + +<p>When caseless matching is set, any letters in a class represent both their +upper case and lower case versions, so for example, a caseless [aeiou] matches +"A" as well as "a", and a caseless [^aeiou] does not match "A", whereas a +caseful version would. +In UTF-8 mode, PCRE always understands the concept of +case for characters whose values are less than 128, so caseless matching is +always possible. For characters with higher values, the concept of case is +supported if PCRE is compiled with Unicode property support, but not otherwise. +If you want to use caseless matching for characters 128 and above, you must +ensure that PCRE is compiled with Unicode property support as well as with +UTF-8 support. +</p> + +<p>Characters that might indicate line breaks are never treated in any +special way when matching character classes, whatever line-ending +sequence is in use, and whatever setting of the <c>dotall</c> and +<c>multiline</c> options is used. A class such as [^a] always matches +one of these characters.</p> + +<p>The minus (hyphen) character can be used to specify a range of +characters in a character class. For example, [d-m] matches any letter +between d and m, inclusive. If a minus character is required in a +class, it must be escaped with a backslash or appear in a position +where it cannot be interpreted as indicating a range, typically as the +first or last character in the class.</p> + +<p>It is not possible to have the literal character "]" as the end +character of a range. A pattern such as [W-]46] is interpreted as a +class of two characters ("W" and "-") followed by a literal string +"46]", so it would match "W46]" or "-46]". However, if the "]" is +escaped with a backslash it is interpreted as the end of range, so +[W-\\]46] is interpreted as a class containing a range followed by two +other characters. The octal or hexadecimal representation of "]" can +also be used to end a range.</p> + +<p>Ranges operate in the collating sequence of character values. They can also be +used for characters specified numerically, for example [\\000-\\037]. +In UTF-8 +mode, ranges can include characters whose values are greater than 255, for +example [\\x{100}-\\x{2ff}]. +</p> + +<p>If a range that includes letters is used when caseless matching is set, it +matches the letters in either case. For example, [W-c] is equivalent to +[][\\\\^_`wxyzabc], matched caselessly +, and in non-UTF-8 mode, if character +tables for a French locale are in use, [\\xc8-\\xcb] matches accented E +characters in both cases. In UTF-8 mode, PCRE supports the concept of case for +characters with values greater than 128 only when it is compiled with Unicode +property support.</p> + +<p>The character types \\d, \\D, \\p, \\P, \\s, \\S, \\w, and \\W may +also appear in a character class, and add the characters that they +match to the class. For example, [\\dABCDEF] matches any hexadecimal +digit. A circumflex can conveniently be used with the upper case +character types to specify a more restricted set of characters than +the matching lower case type. For example, the class [^\\W_] matches +any letter or digit, but not underscore.</p> + +<p>The only metacharacters that are recognized in character classes +are backslash, hyphen (only where it can be interpreted as specifying +a range), circumflex (only at the start), opening square bracket (only +when it can be interpreted as introducing a POSIX class name - see the +next section), and the terminating closing square bracket. However, +escaping other non-alphanumeric characters does no harm.</p> +</section> + + +<section><marker id="sect8"></marker><title>POSIX character classes</title> + +<p>Perl supports the POSIX notation for character classes. This uses names +enclosed by [: and :] within the enclosing square brackets. PCRE also supports +this notation. For example,</p> + +<quote><p> [01[:alpha:]%]</p></quote> + +<p>matches "0", "1", any alphabetic character, or "%". The supported class names +are</p> + +<taglist> + <tag>alnum</tag> <item>letters and digits</item> + <tag>alpha</tag> <item>letters</item> + <tag>ascii</tag> <item>character codes 0 - 127</item> + <tag>blank</tag> <item>space or tab only</item> + <tag>cntrl</tag> <item>control characters</item> + <tag>digit</tag> <item>decimal digits (same as \\d)</item> + <tag>graph</tag> <item>printing characters, excluding space</item> + <tag>lower</tag> <item>lower case letters</item> + <tag>print</tag> <item>printing characters, including space</item> + <tag>punct</tag> <item>printing characters, excluding letters and digits</item> + <tag>space</tag> <item>whitespace (not quite the same as \\s)</item> + <tag>upper</tag> <item>upper case letters</item> + <tag>word</tag> <item>"word" characters (same as \\w)</item> + <tag>xdigit</tag> <item>hexadecimal digits</item> +</taglist> + +<p>The "space" characters are HT (9), LF (10), VT (11), FF (12), CR (13), and +space (32). Notice that this list includes the VT character (code 11). This +makes "space" different to \\s, which does not include VT (for Perl +compatibility).</p> + +<p>The name "word" is a Perl extension, and "blank" is a GNU extension +from Perl 5.8. Another Perl extension is negation, which is indicated +by a ^ character after the colon. For example,</p> + +<quote><p> [12[:^digit:]]</p></quote> + +<p>matches "1", "2", or any non-digit. PCRE (and Perl) also recognize the POSIX +syntax [.ch.] and [=ch=] where "ch" is a "collating element", but these are not +supported, and an error is given if they are encountered.</p> + +<p>In UTF-8 mode, characters with values greater than 128 do not match any of +the POSIX character classes.</p> + +</section> + + +<section><marker id="sect9"></marker><title>Vertical bar</title> + +<p>Vertical bar characters are used to separate alternative +patterns. For example, the pattern</p> + +<quote><p> gilbert|sullivan</p></quote> + +<p>matches either "gilbert" or "sullivan". Any number of alternatives +may appear, and an empty alternative is permitted (matching the empty +string). The matching process tries each alternative in turn, from +left to right, and the first one that succeeds is used. If the +alternatives are within a subpattern (defined below), "succeeds" means +matching the rest of the main pattern as well as the alternative in +the subpattern.</p> + +</section> + +<section><marker id="sect10"></marker><title>Internal option setting</title> + +<p>The settings of the <c>caseless</c>, <c>multiline</c>, <c>dotall</c>, and +<c>extended</c> options (which are Perl-compatible) can be changed from within +the pattern by a sequence of Perl option letters enclosed between "(?" and ")". +The option letters are</p> + +<taglist> + <tag>i</tag> <item>for <c>caseless</c></item> + <tag>m</tag> <item>for <c>multiline</c></item> + <tag>s</tag> <item>for <c>dotall</c></item> + <tag>x</tag> <item>for <c>extended</c></item> +</taglist> + +<p>For example, (?im) sets caseless, multiline matching. It is also possible to +unset these options by preceding the letter with a hyphen, and a combined +setting and unsetting such as (?im-sx), which sets <c>caseless</c> and +<c>multiline</c> while unsetting <c>dotall</c> and <c>extended</c>, is also +permitted. If a letter appears both before and after the hyphen, the option is +unset.</p> + +<p>The PCRE-specific options <c>dupnames</c>, <c>ungreedy</c>, and +<c>extra</c> can be changed in the same way as the Perl-compatible +options by using the characters J, U and X respectively.</p> + +<p>When an option change occurs at top level (that is, not inside subpattern +parentheses), the change applies to the remainder of the pattern that follows. +If the change is placed right at the start of a pattern, PCRE extracts it into +the global options +<!-- XXX C Interface +(and it will therefore show up in data extracted by the +<c>pcre_fullinfo()</c> function). +--> +</p> + +<p>An option change within a subpattern (see below for a description +of subpatterns) affects only that part of the current pattern that +follows it, so</p> + +<quote><p> (a(?i)b)c</p></quote> + +<p>matches abc and aBc and no other strings (assuming <c>caseless</c> +is not used). By this means, options can be made to have different +settings in different parts of the pattern. Any changes made in one +alternative do carry on into subsequent branches within the same +subpattern. For example,</p> + +<quote><p> (a(?i)b|c)</p></quote> + +<p>matches "ab", "aB", "c", and "C", even though when matching "C" the first +branch is abandoned before the option setting. This is because the effects of +option settings happen at compile time. There would be some very weird +behaviour otherwise.</p> + +<p><em>Note:</em> There are other PCRE-specific options that can be set by the +application when the compile or match functions are called. In some cases the +pattern can contain special leading sequences to override what the application +has set or what has been defaulted. Details are given in the section entitled +"Newline sequences" above.</p> + + +</section> + +<section><marker id="sect11"></marker><title>Subpatterns</title> + +<p>Subpatterns are delimited by parentheses (round brackets), which +can be nested. Turning part of a pattern into a subpattern does two +things:</p> + +<p>1. It localizes a set of alternatives. For example, the pattern</p> + +<quote><p> cat(aract|erpillar|)</p></quote> + +<p>matches one of the words "cat", "cataract", or "caterpillar". Without the +parentheses, it would match "cataract", "erpillar" or an empty string.</p> + +<p>2. It sets up the subpattern as a capturing subpattern. This means that, when +the complete pattern matches, that portion of the subject string that matched the +subpattern is passed back to the caller via the return value of +<c>re:run/3</c>. Opening parentheses are counted from left to right (starting +from 1) to obtain numbers for the capturing subpatterns.</p> + +<p>For example, if the string "the red king" is matched against the pattern</p> + +<quote><p> the ((red|white) (king|queen))</p></quote> + +<p>the captured substrings are "red king", "red", and "king", and are numbered 1, +2, and 3, respectively.</p> + +<p>The fact that plain parentheses fulfil two functions is not always helpful. +There are often times when a grouping subpattern is required without a +capturing requirement. If an opening parenthesis is followed by a question mark +and a colon, the subpattern does not do any capturing, and is not counted when +computing the number of any subsequent capturing subpatterns. For example, if +the string "the white queen" is matched against the pattern</p> + +<quote><p> the ((?:red|white) (king|queen))</p></quote> + +<p>the captured substrings are "white queen" and "queen", and are numbered 1 and +2. The maximum number of capturing subpatterns is 65535.</p> + +<p>As a convenient shorthand, if any option settings are required at the start of +a non-capturing subpattern, the option letters may appear between the "?" and +the ":". Thus the two patterns</p> + +<list> +<item>(?i:saturday|sunday)</item> +<item>(?:(?i)saturday|sunday)</item> +</list> + +<p>match exactly the same set of strings. Because alternative branches are tried +from left to right, and options are not reset until the end of the subpattern +is reached, an option setting in one branch does affect subsequent branches, so +the above patterns match "SUNDAY" as well as "Saturday".</p> + + +</section> + +<section><marker id="sect12"></marker><title>Duplicate subpattern numbers</title> + +<p>Perl 5.10 introduced a feature whereby each alternative in a subpattern uses +the same numbers for its capturing parentheses. Such a subpattern starts with +(?| and is itself a non-capturing subpattern. For example, consider this +pattern:</p> + +<quote><p> (?|(Sat)ur|(Sun))day</p></quote> + +<p>Because the two alternatives are inside a (?| group, both sets of capturing +parentheses are numbered one. Thus, when the pattern matches, you can look +at captured substring number one, whichever alternative matched. This construct +is useful when you want to capture part, but not all, of one of a number of +alternatives. Inside a (?| group, parentheses are numbered as usual, but the +number is reset at the start of each branch. The numbers of any capturing +buffers that follow the subpattern start after the highest number used in any +branch. The following example is taken from the Perl documentation. +The numbers underneath show in which buffer the captured content will be +stored.</p> + +<code type="none"> + # before ---------------branch-reset----------- after + / ( a ) (?| x ( y ) z | (p (q) r) | (t) u (v) ) ( z ) /x + # 1 2 2 3 2 3 4</code> + +<p>A backreference or a recursive call to a numbered subpattern always +refers to the first one in the pattern with the given number.</p> + +<p>An alternative approach to using this "branch reset" feature is to use +duplicate named subpatterns, as described in the next section.</p> + +</section> + +<section><marker id="sect13"></marker><title>Named subpatterns</title> + +<p>Identifying capturing parentheses by number is simple, but it can be very hard +to keep track of the numbers in complicated regular expressions. Furthermore, +if an expression is modified, the numbers may change. To help with this +difficulty, PCRE supports the naming of subpatterns. This feature was not +added to Perl until release 5.10. Python had the feature earlier, and PCRE +introduced it at release 4.0, using the Python syntax. PCRE now supports both +the Perl and the Python syntax.</p> + +<p>In PCRE, a subpattern can be named in one of three ways: +(?<name>...) or (?'name'...) as in Perl, or (?P<name>...) +as in Python. References to capturing parentheses from other parts of +the pattern, such as backreferences, recursion, and conditions, can be +made by name as well as by number.</p> + +<p>Names consist of up to 32 alphanumeric characters and underscores. Named +capturing parentheses are still allocated numbers as well as names, exactly as +if the names were not present. +<!-- XXX C Interface +The PCRE API provides function calls for +extracting the name-to-number translation table from a compiled pattern. There +is also a convenience function for extracting a captured substring by name. +--> +The <c>capture</c> specification to <c>re:run/3</c> can use named values if they are present in the regular expression. +</p> + +<p>By default, a name must be unique within a pattern, but it is possible to relax +this constraint by setting the <c>dupnames</c> option at compile time. This can +be useful for patterns where only one instance of the named parentheses can +match. Suppose you want to match the name of a weekday, either as a 3-letter +abbreviation or as the full name, and in both cases you want to extract the +abbreviation. This pattern (ignoring the line breaks) does the job:</p> + +<code type="none"> + (?<DN>Mon|Fri|Sun)(?:day)?| + (?<DN>Tue)(?:sday)?| + (?<DN>Wed)(?:nesday)?| + (?<DN>Thu)(?:rsday)?| + (?<DN>Sat)(?:urday)?</code> + +<p>There are five capturing substrings, but only one is ever set after a match. +(An alternative way of solving this problem is to use a "branch reset" +subpattern, as described in the previous section.)</p> + +<!-- XXX C Interface + +<p>The convenience function for extracting the data by name returns the substring +for the first (and in this example, the only) subpattern of that name that +matched. This saves searching to find which numbered subpattern it was. If you +make a reference to a non-unique named subpattern from elsewhere in the +pattern, the one that corresponds to the lowest number is used. For further +details of the interfaces for handling named subpatterns, see the +<em>pcreapi</em> + +documentation.</p> +--> + +<p>In case of capturing named subpatterns which are not unique, the first occurrence is returned from <c>re:exec/3</c>, if the name is specified int the <c>values</c> part of the <c>capture</c> statement.</p> + +</section> + +<section><marker id="sect14"></marker><title>Repetition</title> + +<p>Repetition is specified by quantifiers, which can follow any of the +following items:</p> + +<list> + <item>a literal data character</item> + <item>the dot metacharacter</item> + <item>the \\C escape sequence</item> + <item>the \\X escape sequence +(in UTF-8 mode with Unicode properties) + </item> + <item>the \\R escape sequence</item> + <item>an escape such as \\d that matches a single character</item> + <item>a character class</item> + <item>a back reference (see next section)</item> + <item>a parenthesized subpattern (unless it is an assertion)</item> +</list> + +<p>The general repetition quantifier specifies a minimum and maximum number of +permitted matches, by giving the two numbers in curly brackets (braces), +separated by a comma. The numbers must be less than 65536, and the first must +be less than or equal to the second. For example:</p> + +<quote><p> z{2,4}</p></quote> + +<p>matches "zz", "zzz", or "zzzz". A closing brace on its own is not a special +character. If the second number is omitted, but the comma is present, there is +no upper limit; if the second number and the comma are both omitted, the +quantifier specifies an exact number of required matches. Thus</p> + +<quote><p> [aeiou]{3,}</p></quote> + +<p>matches at least 3 successive vowels, but may match many more, while</p> + +<quote><p> \\d{8}</p></quote> + +<p>matches exactly 8 digits. An opening curly bracket that appears in a position +where a quantifier is not allowed, or one that does not match the syntax of a +quantifier, is taken as a literal character. For example, {,6} is not a +quantifier, but a literal string of four characters.</p> + +<p>In UTF-8 mode, quantifiers apply to UTF-8 characters rather than to individual +bytes. Thus, for example, \\x{100}{2} matches two UTF-8 characters, each of +which is represented by a two-byte sequence. Similarly, when Unicode property +support is available, \\X{3} matches three Unicode extended sequences, each of +which may be several bytes long (and they may be of different lengths).</p> + +<p>The quantifier {0} is permitted, causing the expression to behave as if the +previous item and the quantifier were not present.</p> + +<p>For convenience, the three most common quantifiers have single-character +abbreviations:</p> + +<taglist> + <tag>*</tag> <item>is equivalent to {0,}</item> + <tag>+</tag> <item>is equivalent to {1,}</item> + <tag>?</tag> <item>is equivalent to {0,1}</item> +</taglist> + +<p>It is possible to construct infinite loops by following a +subpattern that can match no characters with a quantifier that has no +upper limit, for example:</p> + +<quote><p> (a?)*</p></quote> + +<p>Earlier versions of Perl and PCRE used to give an error at compile time for +such patterns. However, because there are cases where this can be useful, such +patterns are now accepted, but if any repetition of the subpattern does in fact +match no characters, the loop is forcibly broken.</p> + +<p>By default, the quantifiers are "greedy", that is, they match as much as +possible (up to the maximum number of permitted times), without causing the +rest of the pattern to fail. The classic example of where this gives problems +is in trying to match comments in C programs. These appear between /* and */ +and within the comment, individual * and / characters may appear. An attempt to +match C comments by applying the pattern</p> + +<quote><p> /\\*.*\\*/</p></quote> + +<p>to the string</p> + +<quote><p> /* first comment */ not comment /* second comment */</p></quote> + +<p>fails, because it matches the entire string owing to the greediness of the .* +item.</p> + +<p>However, if a quantifier is followed by a question mark, it ceases to be +greedy, and instead matches the minimum number of times possible, so the +pattern</p> + +<quote><p> /\\*.*?\\*/</p></quote> + +<p>does the right thing with the C comments. The meaning of the various +quantifiers is not otherwise changed, just the preferred number of matches. +Do not confuse this use of question mark with its use as a quantifier in its +own right. Because it has two uses, it can sometimes appear doubled, as in</p> + +<quote><p> \\d??\\d</p></quote> + +<p>which matches one digit by preference, but can match two if that is the only +way the rest of the pattern matches.</p> + +<p>If the <c>ungreedy</c> option is set (an option that is not available in Perl), +the quantifiers are not greedy by default, but individual ones can be made +greedy by following them with a question mark. In other words, it inverts the +default behaviour.</p> + +<p>When a parenthesized subpattern is quantified with a minimum repeat count that +is greater than 1 or with a limited maximum, more memory is required for the +compiled pattern, in proportion to the size of the minimum or maximum.</p> + +<p>If a pattern starts with .* or .{0,} and the <c>dotall</c> option (equivalent +to Perl's /s) is set, thus allowing the dot to match newlines, the pattern is +implicitly anchored, because whatever follows will be tried against every +character position in the subject string, so there is no point in retrying the +overall match at any position after the first. PCRE normally treats such a +pattern as though it were preceded by \\A.</p> + +<p>In cases where it is known that the subject string contains no newlines, it is +worth setting <c>dotall</c> in order to obtain this optimization, or +alternatively using ^ to indicate anchoring explicitly.</p> + +<p>However, there is one situation where the optimization cannot be used. When .* +is inside capturing parentheses that are the subject of a backreference +elsewhere in the pattern, a match at the start may fail where a later one +succeeds. Consider, for example:</p> + +<quote><p> (.*)abc\\1</p></quote> + +<p>If the subject is "xyz123abc123" the match point is the fourth character. For +this reason, such a pattern is not implicitly anchored.</p> + +<p>When a capturing subpattern is repeated, the value captured is the substring +that matched the final iteration. For example, after</p> + +<quote><p> (tweedle[dume]{3}\\s*)+</p></quote> + +<p>has matched "tweedledum tweedledee" the value of the captured substring is +"tweedledee". However, if there are nested capturing subpatterns, the +corresponding captured values may have been set in previous iterations. For +example, after</p> + +<quote><p> /(a|(b))+/</p></quote> + +<p>matches "aba" the value of the second captured substring is "b".</p> + + +</section> + +<section><marker id="sect15"></marker><title>Atomic grouping and possessive quantifiers</title> + +<p>With both maximizing ("greedy") and minimizing ("ungreedy" or "lazy") +repetition, failure of what follows normally causes the repeated item to be +re-evaluated to see if a different number of repeats allows the rest of the +pattern to match. Sometimes it is useful to prevent this, either to change the +nature of the match, or to cause it fail earlier than it otherwise might, when +the author of the pattern knows there is no point in carrying on.</p> + +<p>Consider, for example, the pattern \\d+foo when applied to the subject line</p> + +<quote><p> 123456bar</p></quote> + +<p>After matching all 6 digits and then failing to match "foo", the normal +action of the matcher is to try again with only 5 digits matching the \\d+ +item, and then with 4, and so on, before ultimately failing. "Atomic grouping" +(a term taken from Jeffrey Friedl's book) provides the means for specifying +that once a subpattern has matched, it is not to be re-evaluated in this way.</p> + +<p>If we use atomic grouping for the previous example, the matcher gives up +immediately on failing to match "foo" the first time. The notation is a kind of +special parenthesis, starting with (?> as in this example:</p> + +<quote><p> (?>\\d+)foo</p></quote> + +<p>This kind of parenthesis "locks up" the part of the pattern it contains once +it has matched, and a failure further into the pattern is prevented from +backtracking into it. Backtracking past it to previous items, however, works as +normal.</p> + +<p>An alternative description is that a subpattern of this type matches the string +of characters that an identical standalone pattern would match, if anchored at +the current point in the subject string.</p> + +<p>Atomic grouping subpatterns are not capturing subpatterns. Simple cases such as +the above example can be thought of as a maximizing repeat that must swallow +everything it can. So, while both \\d+ and \\d+? are prepared to adjust the +number of digits they match in order to make the rest of the pattern match, +(?>\\d+) can only match an entire sequence of digits.</p> + +<p>Atomic groups in general can of course contain arbitrarily complicated +subpatterns, and can be nested. However, when the subpattern for an atomic +group is just a single repeated item, as in the example above, a simpler +notation, called a "possessive quantifier" can be used. This consists of an +additional + character following a quantifier. Using this notation, the +previous example can be rewritten as</p> + +<quote><p> \\d++foo</p></quote> + +<p>Note that a possessive quantifier can be used with an entire group, for +example:</p> + +<quote><p> (abc|xyz){2,3}+</p></quote> + +<p>Possessive quantifiers are always greedy; the setting of the <c>ungreedy</c> +option is ignored. They are a convenient notation for the simpler forms of +atomic group. However, there is no difference in the meaning of a possessive +quantifier and the equivalent atomic group, though there may be a performance +difference; possessive quantifiers should be slightly faster.</p> + +<p>The possessive quantifier syntax is an extension to the Perl 5.8 syntax. +Jeffrey Friedl originated the idea (and the name) in the first edition of his +book. Mike McCloskey liked it, so implemented it when he built Sun's Java +package, and PCRE copied it from there. It ultimately found its way into Perl +at release 5.10.</p> + +<p>PCRE has an optimization that automatically "possessifies" certain simple +pattern constructs. For example, the sequence A+B is treated as A++B because +there is no point in backtracking into a sequence of A's when B must follow.</p> + +<p>When a pattern contains an unlimited repeat inside a subpattern that can itself +be repeated an unlimited number of times, the use of an atomic group is the +only way to avoid some failing matches taking a very long time indeed. The +pattern</p> + +<quote><p> (\\D+|<\\d+>)*[!?]</p></quote> + +<p>matches an unlimited number of substrings that either consist of non-digits, or +digits enclosed in <>, followed by either ! or ?. When it matches, it runs +quickly. However, if it is applied to</p> + +<quote><p> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa</p></quote> + +<p>it takes a long time before reporting failure. This is because the string can +be divided between the internal \\D+ repeat and the external * repeat in a +large number of ways, and all have to be tried. (The example uses [!?] rather +than a single character at the end, because both PCRE and Perl have an +optimization that allows for fast failure when a single character is used. They +remember the last single character that is required for a match, and fail early +if it is not present in the string.) If the pattern is changed so that it uses +an atomic group, like this:</p> + +<quote><p> ((?>\\D+)|<\\d+>)*[!?]</p></quote> + +<p>sequences of non-digits cannot be broken, and failure happens quickly.</p> + +</section> + +<section><marker id="sect16"></marker><title>Back references</title> + +<p>Outside a character class, a backslash followed by a digit greater than 0 (and +possibly further digits) is a back reference to a capturing subpattern earlier +(that is, to its left) in the pattern, provided there have been that many +previous capturing left parentheses.</p> + +<p>However, if the decimal number following the backslash is less than 10, it is +always taken as a back reference, and causes an error only if there are not +that many capturing left parentheses in the entire pattern. In other words, the +parentheses that are referenced need not be to the left of the reference for +numbers less than 10. A "forward back reference" of this type can make sense +when a repetition is involved and the subpattern to the right has participated +in an earlier iteration.</p> + +<p>It is not possible to have a numerical "forward back reference" to +a subpattern whose number is 10 or more using this syntax because a +sequence such as \\50 is interpreted as a character defined in +octal. See the subsection entitled "Non-printing characters" above for +further details of the handling of digits following a backslash. There +is no such problem when named parentheses are used. A back reference +to any subpattern is possible using named parentheses (see below).</p> + +<p>Another way of avoiding the ambiguity inherent in the use of digits +following a backslash is to use the \\g escape sequence, which is a +feature introduced in Perl 5.10. This escape must be followed by an +unsigned number or a negative number, optionally enclosed in +braces. These examples are all identical:</p> + +<list> + <item>(ring), \\1</item> + <item>(ring), \\g1</item> + <item>(ring), \\g{1}</item> +</list> + +<p>An unsigned number specifies an absolute reference without the +ambiguity that is present in the older syntax. It is also useful when +literal digits follow the reference. A negative number is a relative +reference. Consider this example:</p> + +<quote><p> (abc(def)ghi)\\g{-1}</p></quote> + +<p>The sequence \\g{-1} is a reference to the most recently started capturing +subpattern before \\g, that is, is it equivalent to \\2. Similarly, \\g{-2} +would be equivalent to \\1. The use of relative references can be helpful in +long patterns, and also in patterns that are created by joining together +fragments that contain references within themselves.</p> + +<p>A back reference matches whatever actually matched the capturing +subpattern in the current subject string, rather than anything +matching the subpattern itself (see "Subpatterns as subroutines" below +for a way of doing that). So the pattern</p> + +<quote><p> (sens|respons)e and \\1ibility</p></quote> + +<p>matches "sense and sensibility" and "response and responsibility", but not +"sense and responsibility". If caseful matching is in force at the time of the +back reference, the case of letters is relevant. For example,</p> + +<quote><p> ((?i)rah)\\s+\\1</p></quote> + +<p>matches "rah rah" and "RAH RAH", but not "RAH rah", even though the original +capturing subpattern is matched caselessly.</p> + +<p>There are several different ways of writing back references to named +subpatterns. The .NET syntax \\k{name} and the Perl syntax \\k<name> or +\\k'name' are supported, as is the Python syntax (?P=name). Perl 5.10's unified +back reference syntax, in which \\g can be used for both numeric and named +references, is also supported. We could rewrite the above example in any of +the following ways:</p> + +<list> + <item>(?<p1>(?i)rah)\\s+\\k<p1></item> + <item>(?'p1'(?i)rah)\\s+\\k{p1}</item> + <item>(?P<p1>(?i)rah)\\s+(?P=p1)</item> + <item>(?<p1>(?i)rah)\\s+\\g{p1}</item> +</list> + +<p>A subpattern that is referenced by name may appear in the pattern before or +after the reference.</p> + +<p>There may be more than one back reference to the same subpattern. If a +subpattern has not actually been used in a particular match, any back +references to it always fail. For example, the pattern</p> + +<quote><p> (a|(bc))\\2</p></quote> + +<p>always fails if it starts to match "a" rather than "bc". Because +there may be many capturing parentheses in a pattern, all digits +following the backslash are taken as part of a potential back +reference number. If the pattern continues with a digit character, +some delimiter must be used to terminate the back reference. If the +<c>extended</c> option is set, this can be whitespace. Otherwise an +empty comment (see "Comments" below) can be used.</p> + +<p>A back reference that occurs inside the parentheses to which it refers fails +when the subpattern is first used, so, for example, (a\\1) never matches. +However, such references can be useful inside repeated subpatterns. For +example, the pattern</p> + +<quote><p> (a|b\\1)+</p></quote> + +<p>matches any number of "a"s and also "aba", "ababbaa" etc. At each iteration of +the subpattern, the back reference matches the character string corresponding +to the previous iteration. In order for this to work, the pattern must be such +that the first iteration does not need to match the back reference. This can be +done using alternation, as in the example above, or by a quantifier with a +minimum of zero.</p> + +</section> + +<section><marker id="sect17"></marker><title>Assertions</title> + +<p>An assertion is a test on the characters following or preceding the current +matching point that does not actually consume any characters. The simple +assertions coded as \\b, \\B, \\A, \\G, \\Z, \\z, ^ and $ are described +above.</p> + + +<p>More complicated assertions are coded as subpatterns. There are two kinds: +those that look ahead of the current position in the subject string, and those +that look behind it. An assertion subpattern is matched in the normal way, +except that it does not cause the current matching position to be changed.</p> + +<p>Assertion subpatterns are not capturing subpatterns, and may not be repeated, +because it makes no sense to assert the same thing several times. If any kind +of assertion contains capturing subpatterns within it, these are counted for +the purposes of numbering the capturing subpatterns in the whole pattern. +However, substring capturing is carried out only for positive assertions, +because it does not make sense for negative assertions.</p> + +<p><em>Lookahead assertions</em></p> + +<p>Lookahead assertions start with (?= for positive assertions and (?! for +negative assertions. For example,</p> + +<quote><p> \\w+(?=;)</p></quote> + +<p>matches a word followed by a semicolon, but does not include the semicolon in +the match, and</p> + +<quote><p> foo(?!bar)</p></quote> + +<p>matches any occurrence of "foo" that is not followed by "bar". Note that the +apparently similar pattern</p> + +<quote><p> (?!foo)bar</p></quote> + +<p>does not find an occurrence of "bar" that is preceded by something other than +"foo"; it finds any occurrence of "bar" whatsoever, because the assertion +(?!foo) is always true when the next three characters are "bar". A +lookbehind assertion is needed to achieve the other effect.</p> + +<p>If you want to force a matching failure at some point in a pattern, the most +convenient way to do it is with (?!) because an empty string always matches, so +an assertion that requires there not to be an empty string must always fail.</p> + + +<p><em>Lookbehind assertions</em></p> + +<p>Lookbehind assertions start with (?<= for positive assertions and (?<! for +negative assertions. For example,</p> + +<quote><p> (?<!foo)bar</p></quote> + +<p>does find an occurrence of "bar" that is not preceded by "foo". The contents of +a lookbehind assertion are restricted such that all the strings it matches must +have a fixed length. However, if there are several top-level alternatives, they +do not all have to have the same fixed length. Thus</p> + +<quote><p> (?<=bullock|donkey)</p></quote> + +<p>is permitted, but</p> + +<quote><p> (?<!dogs?|cats?)</p></quote> + +<p>causes an error at compile time. Branches that match different length strings +are permitted only at the top level of a lookbehind assertion. This is an +extension compared with Perl (at least for 5.8), which requires all branches to +match the same length of string. An assertion such as</p> + +<quote><p> (?<=ab(c|de))</p></quote> + +<p>is not permitted, because its single top-level branch can match two different +lengths, but it is acceptable if rewritten to use two top-level branches:</p> + +<quote><p> (?<=abc|abde)</p></quote> + +<p>In some cases, the Perl 5.10 escape sequence \\K (see above) can be +used instead of a lookbehind assertion; this is not restricted to a +fixed-length.</p> + +<p>The implementation of lookbehind assertions is, for each alternative, to +temporarily move the current position back by the fixed length and then try to +match. If there are insufficient characters before the current position, the +assertion fails.</p> + +<p>PCRE does not allow the \\C escape (which matches a single byte in UTF-8 mode) +to appear in lookbehind assertions, because it makes it impossible to calculate +the length of the lookbehind. The \\X and \\R escapes, which can match +different numbers of bytes, are also not permitted.</p> + +<p>Possessive quantifiers can be used in conjunction with lookbehind assertions to +specify efficient matching at the end of the subject string. Consider a simple +pattern such as</p> + +<quote><p> abcd$</p></quote> + +<p>when applied to a long string that does not match. Because matching proceeds +from left to right, PCRE will look for each "a" in the subject and then see if +what follows matches the rest of the pattern. If the pattern is specified as</p> + +<quote><p> ^.*abcd$</p></quote> + +<p>the initial .* matches the entire string at first, but when this fails (because +there is no following "a"), it backtracks to match all but the last character, +then all but the last two characters, and so on. Once again the search for "a" +covers the entire string, from right to left, so we are no better off. However, +if the pattern is written as</p> + +<quote><p> ^.*+(?<=abcd)</p></quote> + +<p>there can be no backtracking for the .*+ item; it can match only the entire +string. The subsequent lookbehind assertion does a single test on the last four +characters. If it fails, the match fails immediately. For long strings, this +approach makes a significant difference to the processing time.</p> + +<p><em>Using multiple assertions</em></p> + +<p>Several assertions (of any sort) may occur in succession. For example,</p> + +<quote><p> (?<=\\d{3})(?<!999)foo</p></quote> + +<p>matches "foo" preceded by three digits that are not "999". Notice +that each of the assertions is applied independently at the same point +in the subject string. First there is a check that the previous three +characters are all digits, and then there is a check that the same +three characters are not "999". This pattern does <em>not</em> match +"foo" preceded by six characters, the first of which are digits and +the last three of which are not "999". For example, it doesn't match +"123abcfoo". A pattern to do that is</p> + +<quote><p> (?<=\\d{3}...)(?<!999)foo</p></quote> + +<p>This time the first assertion looks at the preceding six +characters, checking that the first three are digits, and then the +second assertion checks that the preceding three characters are not +"999".</p> + +<p>Assertions can be nested in any combination. For example,</p> + +<quote><p> (?<=(?<!foo)bar)baz</p></quote> + +<p>matches an occurrence of "baz" that is preceded by "bar" which in +turn is not preceded by "foo", while</p> + +<quote><p> (?<=\\d{3}(?!999)...)foo</p></quote> + +<p>is another pattern that matches "foo" preceded by three digits and any three +characters that are not "999".</p> + +</section> + +<section><marker id="sect18"></marker><title>Conditional subpatterns</title> + +<p>It is possible to cause the matching process to obey a subpattern +conditionally or to choose between two alternative subpatterns, depending on +the result of an assertion, or whether a previous capturing subpattern matched +or not. The two possible forms of conditional subpattern are</p> + +<list> +<item>(?(condition)yes-pattern)</item> +<item>(?(condition)yes-pattern|no-pattern)</item> +</list> + +<p>If the condition is satisfied, the yes-pattern is used; otherwise the +no-pattern (if present) is used. If there are more than two alternatives in the +subpattern, a compile-time error occurs.</p> + +<p>There are four kinds of condition: references to subpatterns, references to +recursion, a pseudo-condition called DEFINE, and assertions.</p> + + +<p><em>Checking for a used subpattern by number</em></p> + +<p>If the text between the parentheses consists of a sequence of +digits, the condition is true if the capturing subpattern of that +number has previously matched. An alternative notation is to precede +the digits with a plus or minus sign. In this case, the subpattern +number is relative rather than absolute. The most recently opened +parentheses can be referenced by (?(-1), the next most recent by +(?(-2), and so on. In looping constructs it can also make sense to +refer to subsequent groups with constructs such as (?(+2).</p> + +<p>Consider the following pattern, which contains non-significant +whitespace to make it more readable (assume the <c>extended</c> +option) and to divide it into three parts for ease of discussion:</p> + +<quote><p> ( \\( )? [^()]+ (?(1) \\) )</p></quote> + +<p>The first part matches an optional opening parenthesis, and if that +character is present, sets it as the first captured substring. The second part +matches one or more characters that are not parentheses. The third part is a +conditional subpattern that tests whether the first set of parentheses matched +or not. If they did, that is, if subject started with an opening parenthesis, +the condition is true, and so the yes-pattern is executed and a closing +parenthesis is required. Otherwise, since no-pattern is not present, the +subpattern matches nothing. In other words, this pattern matches a sequence of +non-parentheses, optionally enclosed in parentheses.</p> + +<p>If you were embedding this pattern in a larger one, you could use a relative +reference:</p> + +<quote><p> ...other stuff... ( \\( )? [^()]+ (?(-1) \\) ) ...</p></quote> + +<p>This makes the fragment independent of the parentheses in the larger pattern.</p> + +<p><em>Checking for a used subpattern by name</em></p> + +<p>Perl uses the syntax (?(<name>)...) or (?('name')...) to test +for a used subpattern by name. For compatibility with earlier versions +of PCRE, which had this facility before Perl, the syntax (?(name)...) +is also recognized. However, there is a possible ambiguity with this +syntax, because subpattern names may consist entirely of digits. PCRE +looks first for a named subpattern; if it cannot find one and the name +consists entirely of digits, PCRE looks for a subpattern of that +number, which must be greater than zero. Using subpattern names that +consist entirely of digits is not recommended.</p> + +<p>Rewriting the above example to use a named subpattern gives this:</p> + +<quote><p> (?<OPEN> \\( )? [^()]+ (?(<OPEN>) \\) )</p></quote> + +<p><em>Checking for pattern recursion</em></p> + +<p>If the condition is the string (R), and there is no subpattern with +the name R, the condition is true if a recursive call to the whole +pattern or any subpattern has been made. If digits or a name preceded +by ampersand follow the letter R, for example:</p> + +<quote><p> (?(R3)...) or (?(R&name)...)</p></quote> + +<p>the condition is true if the most recent recursion is into the +subpattern whose number or name is given. This condition does not +check the entire recursion stack.</p> + +<p>At "top level", all these recursion test conditions are false. Recursive +patterns are described below.</p> + +<p><em>Defining subpatterns for use by reference only</em></p> + +<p>If the condition is the string (DEFINE), and there is no subpattern with the +name DEFINE, the condition is always false. In this case, there may be only one +alternative in the subpattern. It is always skipped if control reaches this +point in the pattern; the idea of DEFINE is that it can be used to define +"subroutines" that can be referenced from elsewhere. (The use of "subroutines" +is described below.) For example, a pattern to match an IPv4 address could be +written like this (ignore whitespace and line breaks):</p> + +<quote><p> (?(DEFINE) (?<byte> 2[0-4]\\d | 25[0-5] | 1\\d\\d | [1-9]?\\d) ) + \\b (?&byte) (\\.(?&byte)){3} \\b</p></quote> + +<p>The first part of the pattern is a DEFINE group inside which a another group +named "byte" is defined. This matches an individual component of an IPv4 +address (a number less than 256). When matching takes place, this part of the +pattern is skipped because DEFINE acts like a false condition.</p> + +<p>The rest of the pattern uses references to the named group to match the four +dot-separated components of an IPv4 address, insisting on a word boundary at +each end.</p> + +<p><em>Assertion conditions</em></p> + +<p>If the condition is not in any of the above formats, it must be an +assertion. This may be a positive or negative lookahead or lookbehind +assertion. Consider this pattern, again containing non-significant +whitespace, and with the two alternatives on the second line:</p> + +<code type="none"> + (?(?=[^a-z]*[a-z]) + \\d{2}-[a-z]{3}-\\d{2} | \\d{2}-\\d{2}-\\d{2} )</code> + +<p>The condition is a positive lookahead assertion that matches an optional +sequence of non-letters followed by a letter. In other words, it tests for the +presence of at least one letter in the subject. If a letter is found, the +subject is matched against the first alternative; otherwise it is matched +against the second. This pattern matches strings in one of the two forms +dd-aaa-dd or dd-dd-dd, where aaa are letters and dd are digits.</p> + + +</section> + +<section><marker id="sect19"></marker><title>Comments</title> + +<p>The sequence (?# marks the start of a comment that continues up to the next +closing parenthesis. Nested parentheses are not permitted. The characters +that make up a comment play no part in the pattern matching at all.</p> + +<p>If the <c>extended</c> option is set, an unescaped # character outside a +character class introduces a comment that continues to immediately after the +next newline in the pattern.</p> + + +</section> + +<section><marker id="sect20"></marker><title>Recursive patterns</title> + +<p>Consider the problem of matching a string in parentheses, allowing for +unlimited nested parentheses. Without the use of recursion, the best that can +be done is to use a pattern that matches up to some fixed depth of nesting. It +is not possible to handle an arbitrary nesting depth.</p> + +<p>For some time, Perl has provided a facility that allows regular +expressions to recurse (amongst other things). It does this by +interpolating Perl code in the expression at run time, and the code +can refer to the expression itself. A Perl pattern using code +interpolation to solve the parentheses problem can be created like +this:</p> + +<quote><p> $re = qr{\\( (?: (?>[^()]+) | (?p{$re}) )* \\)}x;</p></quote> + +<p>The (?p{...}) item interpolates Perl code at run time, and in this +case refers recursively to the pattern in which it appears.</p> + +<p>Obviously, PCRE cannot support the interpolation of Perl code. Instead, it +supports special syntax for recursion of the entire pattern, and also for +individual subpattern recursion. After its introduction in PCRE and Python, +this kind of recursion was introduced into Perl at release 5.10.</p> + +<p>A special item that consists of (? followed by a number greater +than zero and a closing parenthesis is a recursive call of the +subpattern of the given number, provided that it occurs inside that +subpattern. (If not, it is a "subroutine" call, which is described in +the next section.) The special item (?R) or (?0) is a recursive call +of the entire regular expression.</p> + +<p>In PCRE (like Python, but unlike Perl), a recursive subpattern call +is always treated as an atomic group. That is, once it has matched +some of the subject string, it is never re-entered, even if it +contains untried alternatives and there is a subsequent matching +failure.</p> + +<p>This PCRE pattern solves the nested parentheses problem (assume the +<c>extended</c> option is set so that whitespace is ignored):</p> + +<quote><p> \\( ( (?>[^()]+) | (?R) )* \\)</p></quote> + +<p>First it matches an opening parenthesis. Then it matches any number +of substrings which can either be a sequence of non-parentheses, or a +recursive match of the pattern itself (that is, a correctly +parenthesized substring). Finally there is a closing parenthesis.</p> + +<p>If this were part of a larger pattern, you would not want to +recurse the entire pattern, so instead you could use this:</p> + +<quote><p> ( \\( ( (?>[^()]+) | (?1) )* \\) )</p></quote> + +<p>We have put the pattern into parentheses, and caused the recursion +to refer to them instead of the whole pattern.</p> + +<p>In a larger pattern, keeping track of parenthesis numbers can be +tricky. This is made easier by the use of relative references. (A Perl +5.10 feature.) Instead of (?1) in the pattern above you can write +(?-2) to refer to the second most recently opened parentheses +preceding the recursion. In other words, a negative number counts +capturing parentheses leftwards from the point at which it is +encountered.</p> + +<p>It is also possible to refer to subsequently opened parentheses, by +writing references such as (?+2). However, these cannot be recursive +because the reference is not inside the parentheses that are +referenced. They are always "subroutine" calls, as described in the +next section.</p> + +<p>An alternative approach is to use named parentheses instead. The +Perl syntax for this is (?&name); PCRE's earlier syntax +(?P>name) is also supported. We could rewrite the above example as +follows:</p> + +<quote><p> (?<pn> \\( ( (?>[^()]+) | (?&pn) )* \\) )</p></quote> + +<p>If there is more than one subpattern with the same name, the earliest one is +used.</p> + +<p>This particular example pattern that we have been looking at contains nested +unlimited repeats, and so the use of atomic grouping for matching strings of +non-parentheses is important when applying the pattern to strings that do not +match. For example, when this pattern is applied to</p> + +<quote><p> (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa()</p></quote> + +<p>it yields "no match" quickly. However, if atomic grouping is not used, +the match runs for a very long time indeed because there are so many different +ways the + and * repeats can carve up the subject, and all have to be tested +before failure can be reported.</p> + +<p>At the end of a match, the values set for any capturing subpatterns are those +from the outermost level of the recursion at which the subpattern value is set. + +<!-- XXX C Interface +If you want to obtain intermediate values, a callout function can be used (see +below and the + +<em>pcrecallout</em> + +documentation). +--> +If the pattern above is matched against</p> + +<quote><p> (ab(cd)ef)</p></quote> + +<p>the value for the capturing parentheses is "ef", which is the last value taken +on at the top level. If additional parentheses are added, giving</p> + +<code type="none"> + \\( ( ( (?>[^()]+) | (?R) )* ) \\) + ^ ^ + ^ ^</code> + +<p>the string they capture is "ab(cd)ef", the contents of the top level +parentheses. +<!-- XXX C interface +If there are more than 15 capturing parentheses in a pattern, PCRE +has to obtain extra memory to store data during a recursion, which it does by +using <em>pcre_malloc</em>, freeing it via <em>pcre_free</em> afterwards. If no +memory can be obtained, the match fails with the <c>error_nomemory</c> error.</p> +--> +</p> + +<p>Do not confuse the (?R) item with the condition (R), which tests +for recursion. Consider this pattern, which matches text in angle +brackets, allowing for arbitrary nesting. Only digits are allowed in +nested brackets (that is, when recursing), whereas any characters are +permitted at the outer level.</p> + +<quote><p> < (?: (?(R) \\d++ | [^<>]*+) | (?R)) * ></p></quote> + +<p>In this pattern, (?(R) is the start of a conditional subpattern, +with two different alternatives for the recursive and non-recursive +cases. The (?R) item is the actual recursive call.</p> + +</section> + +<section><marker id="sect21"></marker><title>Subpatterns as subroutines</title> + +<p>If the syntax for a recursive subpattern reference (either by number or by +name) is used outside the parentheses to which it refers, it operates like a +subroutine in a programming language. The "called" subpattern may be defined +before or after the reference. A numbered reference can be absolute or +relative, as in these examples:</p> + +<list> + <item>(...(absolute)...)...(?2)...</item> + <item>(...(relative)...)...(?-1)...</item> + <item>(...(?+1)...(relative)...</item> +</list> + +<p>An earlier example pointed out that the pattern</p> + +<quote><p> (sens|respons)e and \\1ibility</p></quote> + +<p>matches "sense and sensibility" and "response and responsibility", but not +"sense and responsibility". If instead the pattern</p> + +<quote><p> (sens|respons)e and (?1)ibility</p></quote> + +<p>is used, it does match "sense and responsibility" as well as the other two +strings. Another example is given in the discussion of DEFINE above.</p> + +<p>Like recursive subpatterns, a "subroutine" call is always treated +as an atomic group. That is, once it has matched some of the subject +string, it is never re-entered, even if it contains untried +alternatives and there is a subsequent matching failure.</p> + +<p>When a subpattern is used as a subroutine, processing options such as +case-independence are fixed when the subpattern is defined. They cannot be +changed for different calls. For example, consider this pattern:</p> + +<quote><p> (abc)(?i:(?-1))</p></quote> + +<p>It matches "abcabc". It does not match "abcABC" because the change of +processing option does not affect the called subpattern.</p> + + +</section> + +<!-- XXX C interface + +<section> <marker id="sect22"><title>Callouts</title></marker> + +<p>Perl has a feature whereby using the sequence (?{...}) causes arbitrary Perl +code to be obeyed in the middle of matching a regular expression. This makes it +possible, amongst other things, to extract different substrings that match the +same pair of parentheses when there is a repetition.</p> + +<p>PCRE provides a similar feature, but of course it cannot obey arbitrary Perl +code. The feature is called "callout". The caller of PCRE provides an external +function by putting its entry point in the global variable <em>pcre_callout</em>. +By default, this variable contains NULL, which disables all calling out.</p> + +<p>Within a regular expression, (?C) indicates the points at which the external +function is to be called. If you want to identify different callout points, you +can put a number less than 256 after the letter C. The default value is zero. +For example, this pattern has two callout points:</p> + +<quote><p> (?C1)abc(?C2)def</p></quote> + + +<p>If the <c>AUTO_CALLOUT</c> flag is passed to <c>re:compile/2</c>, callouts are +automatically installed before each item in the pattern. They are all numbered +255.</p> + +<p>During matching, when PCRE reaches a callout point (and <em>pcre_callout</em> is +set), the external function is called. It is provided with the number of the +callout, the position in the pattern, and, optionally, one item of data +originally supplied by the caller of <c>re:run/3</c>. The callout function +may cause matching to proceed, to backtrack, or to fail altogether. A complete +description of the interface to the callout function is given in the +<em>pcrecallout</em> +documentation.</p> + + +</section> +--> + +<section><marker id="sect23"></marker><title>Backtracking control</title> + +<p>Perl 5.10 introduced a number of "Special Backtracking Control Verbs", which +are described in the Perl documentation as "experimental and subject to change +or removal in a future version of Perl". It goes on to say: "Their usage in +production code should be noted to avoid problems during upgrades." The same +remarks apply to the PCRE features described in this section.</p> + +<!-- XXX C interface +<p>Since these verbs are specifically related to backtracking, they can be used +only when the pattern is to be matched using <c>re:run/3</c>, which uses a +backtracking algorithm. They cause an error if encountered by +<c>pcre_dfa_exec()</c>.</p> +--> + +<p>The new verbs make use of what was previously invalid syntax: an opening +parenthesis followed by an asterisk. In Perl, they are generally of the form +(*VERB:ARG) but PCRE does not support the use of arguments, so its general +form is just (*VERB). Any number of these verbs may occur in a pattern. There +are two kinds:</p> + + +<p><em>Verbs that act immediately</em></p> + +<p>The following verbs act as soon as they are encountered:</p> + +<quote><p> (*ACCEPT)</p></quote> + +<p>This verb causes the match to end successfully, skipping the remainder of the +pattern. When inside a recursion, only the innermost pattern is ended +immediately. PCRE differs from Perl in what happens if the (*ACCEPT) is inside +capturing parentheses. In Perl, the data so far is captured: in PCRE no data is +captured. For example:</p> + +<quote><p> A(A|B(*ACCEPT)|C)D</p></quote> + +<p>This matches "AB", "AAD", or "ACD", but when it matches "AB", no data is +captured.</p> + +<quote><p> (*FAIL) or (*F)</p></quote> + +<p>This verb causes the match to fail, forcing backtracking to occur. It is +equivalent to (?!) but easier to read. The Perl documentation notes that it is +probably useful only when combined with (?{}) or (??{}). Those are, of course, +Perl features that are not present in PCRE. The nearest equivalent is the +callout feature, as for example in this pattern:</p> + +<quote><p> a+(?C)(*FAIL)</p></quote> + +<p>A match with the string "aaaa" always fails, but the callout is taken before +each backtrack happens (in this example, 10 times).</p> + + + +<p><em>Verbs that act after backtracking</em></p> + +<p>The following verbs do nothing when they are encountered. Matching continues +with what follows, but if there is no subsequent match, a failure is forced. +The verbs differ in exactly what kind of failure occurs.</p> + +<quote><p> (*COMMIT)</p></quote> + +<p>This verb causes the whole match to fail outright if the rest of the pattern +does not match. Even if the pattern is unanchored, no further attempts to find +a match by advancing the start point take place. Once (*COMMIT) has been +passed, <c>re:run/3</c> is committed to finding a match at the current +starting point, or not at all. For example:</p> + +<quote><p> a+(*COMMIT)b</p></quote> + +<p>This matches "xxaab" but not "aacaab". It can be thought of as a kind of +dynamic anchor, or "I've started, so I must finish."</p> + +<quote><p> (*PRUNE)</p></quote> + +<p>This verb causes the match to fail at the current position if the rest of the +pattern does not match. If the pattern is unanchored, the normal "bumpalong" +advance to the next starting character then happens. Backtracking can occur as +usual to the left of (*PRUNE), or when matching to the right of (*PRUNE), but +if there is no match to the right, backtracking cannot cross (*PRUNE). +In simple cases, the use of (*PRUNE) is just an alternative to an atomic +group or possessive quantifier, but there are some uses of (*PRUNE) that cannot +be expressed in any other way.</p> + +<quote><p> (*SKIP)</p></quote> + +<p>This verb is like (*PRUNE), except that if the pattern is unanchored, the +"bumpalong" advance is not to the next character, but to the position in the +subject where (*SKIP) was encountered. (*SKIP) signifies that whatever text +was matched leading up to it cannot be part of a successful match. Consider:</p> + +<quote><p> a+(*SKIP)b</p></quote> + +<p>If the subject is "aaaac...", after the first match attempt fails (starting at +the first character in the string), the starting point skips on to start the +next attempt at "c". Note that a possessive quantifier does not have the same +effect in this example; although it would suppress backtracking during the +first match attempt, the second attempt would start at the second character +instead of skipping on to "c".</p> + +<quote><p> (*THEN)</p></quote> + +<p>This verb causes a skip to the next alternation if the rest of the pattern does +not match. That is, it cancels pending backtracking, but only within the +current alternation. Its name comes from the observation that it can be used +for a pattern-based if-then-else block:</p> + +<quote><p> ( COND1 (*THEN) FOO | COND2 (*THEN) BAR | COND3 (*THEN) BAZ ) ...</p></quote> + +<p>If the COND1 pattern matches, FOO is tried (and possibly further items after +the end of the group if FOO succeeds); on failure the matcher skips to the +second alternative and tries COND2, without backtracking into COND1. If (*THEN) +is used outside of any alternation, it acts exactly like (*PRUNE).</p> + +</section> + +</erlref> + diff --git a/lib/stdlib/doc/src/ref_man.xml b/lib/stdlib/doc/src/ref_man.xml new file mode 100644 index 0000000000..f6ae368e92 --- /dev/null +++ b/lib/stdlib/doc/src/ref_man.xml @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE application SYSTEM "application.dtd"> + +<application xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>STDLIB Reference Manual</title> + <prepared>OTP Team</prepared> + <docno></docno> + <date>1997-06-04</date> + <rev>1.3.1</rev> + <file>application.xml</file> + </header> + <description> + <p>The Standard Erlang Libraries application, <em>STDLIB</em>, + contains modules for manipulating lists, strings and files etc.</p> + <br></br> + </description> + <xi:include href="stdlib_app.xml"/> + <xi:include href="array.xml"/> + <xi:include href="base64.xml"/> + <xi:include href="beam_lib.xml"/> + <xi:include href="c.xml"/> + <xi:include href="calendar.xml"/> + <xi:include href="dets.xml"/> + <xi:include href="dict.xml"/> + <xi:include href="digraph.xml"/> + <xi:include href="digraph_utils.xml"/> + <xi:include href="epp.xml"/> + <xi:include href="erl_eval.xml"/> + <xi:include href="erl_expand_records.xml"/> + <xi:include href="erl_id_trans.xml"/> + <xi:include href="erl_internal.xml"/> + <xi:include href="erl_lint.xml"/> + <xi:include href="erl_parse.xml"/> + <xi:include href="erl_pp.xml"/> + <xi:include href="erl_scan.xml"/> + <xi:include href="erl_tar.xml"/> + <xi:include href="ets.xml"/> + <xi:include href="file_sorter.xml"/> + <xi:include href="filelib.xml"/> + <xi:include href="filename.xml"/> + <xi:include href="gb_sets.xml"/> + <xi:include href="gb_trees.xml"/> + <xi:include href="gen_event.xml"/> + <xi:include href="gen_fsm.xml"/> + <xi:include href="gen_server.xml"/> + <xi:include href="io.xml"/> + <xi:include href="io_lib.xml"/> + <xi:include href="lib.xml"/> + <xi:include href="lists.xml"/> + <xi:include href="log_mf_h.xml"/> + <xi:include href="math.xml"/> + <xi:include href="ms_transform.xml"/> + <xi:include href="orddict.xml"/> + <xi:include href="ordsets.xml"/> + <xi:include href="pg.xml"/> + <xi:include href="pool.xml"/> + <xi:include href="proc_lib.xml"/> + <xi:include href="proplists.xml"/> + <xi:include href="qlc.xml"/> + <xi:include href="queue.xml"/> + <xi:include href="random.xml"/> + <xi:include href="re.xml"/> + <xi:include href="regexp.xml"/> + <xi:include href="sets.xml"/> + <xi:include href="shell.xml"/> + <xi:include href="shell_default.xml"/> + <xi:include href="slave.xml"/> + <xi:include href="sofs.xml"/> + <xi:include href="string.xml"/> + <xi:include href="supervisor.xml"/> + <xi:include href="supervisor_bridge.xml"/> + <xi:include href="sys.xml"/> + <xi:include href="timer.xml"/> + <xi:include href="unicode.xml"/> + <xi:include href="win32reg.xml"/> + <xi:include href="zip.xml"/> +</application> + diff --git a/lib/stdlib/doc/src/regexp.xml b/lib/stdlib/doc/src/regexp.xml new file mode 100644 index 0000000000..8da636e4ad --- /dev/null +++ b/lib/stdlib/doc/src/regexp.xml @@ -0,0 +1,415 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>regexp</title> + <prepared>Robert Virding</prepared> + <responsible>Bjarne Dacker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>96-09-28</date> + <rev>A</rev> + <file>regexp.sgml</file> + </header> + <module>regexp</module> + <modulesummary>Regular Expression Functions for Strings</modulesummary> + <description> + <note><p>This module has been obsoleted by the + <seealso marker="re">re</seealso> module and will be removed in a future + release.</p></note> + <p>This module contains functions for regular expression + matching and substitution.</p> + </description> + <funcs> + <func> + <name>match(String, RegExp) -> MatchRes</name> + <fsummary>Match a regular expression</fsummary> + <type> + <v>String = RegExp = string()</v> + <v>MatchRes = {match,Start,Length} | nomatch | {error,errordesc()}</v> + <v>Start = Length = integer()</v> + </type> + <desc> + <p>Finds the first, longest match of the regular expression <c>RegExp</c> in <c>String</c>. This function searches for the longest possible match and returns the first one found if there are several expressions of the same length. It returns as follows:</p> + <taglist> + <tag><c>{match,Start,Length}</c></tag> + <item> + <p>if the match succeeded. <c>Start</c> is the starting + position of the match, and <c>Length</c> is the length of + the matching string.</p> + </item> + <tag><c>nomatch</c></tag> + <item> + <p>if there were no matching characters.</p> + </item> + <tag><c>{error,Error}</c></tag> + <item> + <p>if there was an error in <c>RegExp</c>.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>first_match(String, RegExp) -> MatchRes</name> + <fsummary>Match a regular expression</fsummary> + <type> + <v>String = RegExp = string()</v> + <v>MatchRes = {match,Start,Length} | nomatch | {error,errordesc()}</v> + <v>Start = Length = integer()</v> + </type> + <desc> + <p>Finds the first match of the regular expression <c>RegExp</c> in <c>String</c>. This call is + usually faster than <c>match</c> and it is also a useful way to ascertain that a match exists. It returns as follows:</p> + <taglist> + <tag><c>{match,Start,Length}</c></tag> + <item> + <p>if the match succeeded. <c>Start</c> is the starting + position of the match and <c>Length</c> is the length of + the matching string.</p> + </item> + <tag><c>nomatch</c></tag> + <item> + <p>if there were no matching characters.</p> + </item> + <tag><c>{error,Error}</c></tag> + <item> + <p>if there was an error in <c>RegExp</c>.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>matches(String, RegExp) -> MatchRes</name> + <fsummary>Match a regular expression</fsummary> + <type> + <v>String = RegExp = string()</v> + <v>MatchRes = {match, Matches} | {error, errordesc()}</v> + <v>Matches = list()</v> + </type> + <desc> + <p>Finds all non-overlapping matches of the + expression <c>RegExp</c> in <c>String</c>. + It returns as follows:</p> + <taglist> + <tag><c>{match, Matches}</c></tag> + <item> + <p>if the regular expression was correct. + The list will be empty if there was no match. Each element in the list looks like <c>{Start, Length}</c>, where <c>Start</c> is the starting position of the match, and <c>Length</c> is the length of the matching string.</p> + </item> + <tag><c>{error,Error}</c></tag> + <item> + <p>if there was an error in <c>RegExp</c>.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>sub(String, RegExp, New) -> SubRes</name> + <fsummary>Substitute the first occurrence of a regular expression</fsummary> + <type> + <v>String = RegExp = New = string()</v> + <v>SubRes = {ok,NewString,RepCount} | {error,errordesc()}</v> + <v>RepCount = integer()</v> + </type> + <desc> + <p>Substitutes the first occurrence of a substring matching <c>RegExp</c> in <c>String</c> with the string <c>New</c>. A <c><![CDATA[&]]></c> in the string <c>New</c> is replaced by the matched substring of <c>String</c>. <c><![CDATA[\\&]]></c> puts a literal <c><![CDATA[&]]></c> into the replacement string. It returns as follows:</p> + <taglist> + <tag><c>{ok,NewString,RepCount}</c></tag> + <item> + <p>if <c>RegExp</c> is correct. <c>RepCount</c> is the number of replacements which have been made + (this will be either 0 or 1).</p> + </item> + <tag><c>{error, Error}</c></tag> + <item> + <p>if there is an error in <c>RegExp</c>.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>gsub(String, RegExp, New) -> SubRes</name> + <fsummary>Substitute all occurrences of a regular expression</fsummary> + <type> + <v>String = RegExp = New = string()</v> + <v>SubRes = {ok,NewString,RepCount} | {error,errordesc()}</v> + <v>RepCount = integer()</v> + </type> + <desc> + <p>The same as <c>sub</c>, except that all non-overlapping + occurrences of a substring matching + <c>RegExp</c> in <c>String</c> are replaced by the string <c>New</c>. It returns:</p> + <taglist> + <tag><c>{ok,NewString,RepCount}</c></tag> + <item> + <p>if <c>RegExp</c> is correct. <c>RepCount</c> is the number of replacements which have been made.</p> + </item> + <tag><c>{error, Error}</c></tag> + <item> + <p>if there is an error in <c>RegExp</c>.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>split(String, RegExp) -> SplitRes</name> + <fsummary>Split a string into fields</fsummary> + <type> + <v>String = RegExp = string()</v> + <v>SubRes = {ok,FieldList} | {error,errordesc()}</v> + <v>Fieldlist = [string()]</v> + </type> + <desc> + <p><c>String</c> is split into fields (sub-strings) by the + regular expression <c>RegExp</c>.</p> + <p>If the separator expression is <c>" "</c> (a single space), + then the fields are separated by blanks and/or tabs and + leading and trailing blanks and tabs are discarded. For all + other values of the separator, leading and trailing blanks + and tabs are not discarded. It returns:</p> + <taglist> + <tag><c>{ok, FieldList}</c></tag> + <item> + <p>to indicate that the string has been split up into the fields of + <c>FieldList</c>.</p> + </item> + <tag><c>{error, Error}</c></tag> + <item> + <p>if there is an error in <c>RegExp</c>.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>sh_to_awk(ShRegExp) -> AwkRegExp</name> + <fsummary>Convert an <c>sh</c>regular expression into an <c>AWK</c>one</fsummary> + <type> + <v>ShRegExp AwkRegExp = string()</v> + <v>SubRes = {ok,NewString,RepCount} | {error,errordesc()}</v> + <v>RepCount = integer()</v> + </type> + <desc> + <p>Converts the <c>sh</c> type regular expression + <c>ShRegExp</c> into a full <c>AWK</c> regular + expression. Returns the converted regular expression + string. <c>sh</c> expressions are used in the shell for + matching file names and have the following special + characters:</p> + <taglist> + <tag><c>*</c></tag> + <item> + <p>matches any string including the null string.</p> + </item> + <tag><c>?</c></tag> + <item> + <p>matches any single character.</p> + </item> + <tag><c>[...]</c></tag> + <item> + <p>matches any of the enclosed characters. Character + ranges are specified by a pair of characters separated + by a <c>-</c>. If the first character after <c>[</c> is a + <c>!</c>, then any character not enclosed is matched.</p> + </item> + </taglist> + <p>It may sometimes be more practical to use <c>sh</c> type + expansions as they are simpler and easier to use, even though they are not as powerful.</p> + </desc> + </func> + <func> + <name>parse(RegExp) -> ParseRes</name> + <fsummary>Parse a regular expression</fsummary> + <type> + <v>RegExp = string()</v> + <v>ParseRes = {ok,RE} | {error,errordesc()}</v> + </type> + <desc> + <p>Parses the regular expression <c>RegExp</c> and builds the + internal representation used in the other regular expression + functions. Such representations can be used in all of the + other functions instead of a regular expression string. This + is more efficient when the same regular expression is used + in many strings. It returns:</p> + <taglist> + <tag><c>{ok, RE}</c>if <c>RegExp</c>is correct and <c>RE</c>is the internal representation.</tag> + <item> + <p></p> + </item> + <tag><c>{error, Error}</c>if there is an error in <c>RegExpString</c>.</tag> + <item> + <p></p> + </item> + </taglist> + </desc> + </func> + <func> + <name>format_error(ErrorDescriptor) -> Chars</name> + <fsummary>Format an error descriptor</fsummary> + <type> + <v>ErrorDescriptor = errordesc()</v> + <v>Chars = [char() | Chars]</v> + </type> + <desc> + <p>Returns a string which describes the error <c>ErrorDescriptor</c> + returned when there is an error in a regular expression.</p> + </desc> + </func> + </funcs> + + <section> + <title>Regular Expressions</title> + <p>The regular expressions allowed here is a subset of the set found + in <c>egrep</c> and in the <c>AWK</c> programming language, as + defined in the book, <c>The AWK Programming Language, by A. V. Aho, B. W. Kernighan, P. J. Weinberger</c>. They are + composed of the following characters:</p> + <taglist> + <tag>c</tag> + <item> + <p>matches the non-metacharacter <c>c</c>.</p> + </item> + <tag>\\c</tag> + <item> + <p>matches the escape sequence or literal character <c>c</c>.</p> + </item> + <tag>.</tag> + <item> + <p>matches any character.</p> + </item> + <tag>^</tag> + <item> + <p>matches the beginning of a string.</p> + </item> + <tag>$</tag> + <item> + <p>matches the end of a string.</p> + </item> + <tag>[abc...]</tag> + <item> + <p>character class, which matches any of the characters + <c>abc...</c> Character ranges are specified by a pair of + characters separated by a <c>-</c>.</p> + </item> + <tag>[^abc...]</tag> + <item> + <p>negated character class, which matches any character except + <c>abc...</c>.</p> + </item> + <tag>r1 | r2</tag> + <item> + <p>alternation. It matches either <c>r1</c> or <c>r2</c>.</p> + </item> + <tag>r1r2</tag> + <item> + <p>concatenation. It matches <c>r1</c> and then <c>r2</c>.</p> + </item> + <tag>r+</tag> + <item> + <p>matches one or more <c>r</c>s.</p> + </item> + <tag>r*</tag> + <item> + <p>matches zero or more <c>r</c>s.</p> + </item> + <tag>r?</tag> + <item> + <p>matches zero or one <c>r</c>s.</p> + </item> + <tag>(r)</tag> + <item> + <p>grouping. It matches <c>r</c>.</p> + </item> + </taglist> + <p>The escape sequences allowed are the same as for Erlang + strings:</p> + <taglist> + <tag><c>\\b</c></tag> + <item> + <p>backspace</p> + </item> + <tag><c>\\f</c></tag> + <item> + <p>form feed </p> + </item> + <tag><c>\</c></tag> + <item> + <p>newline (line feed) </p> + </item> + <tag><c>\\r</c></tag> + <item> + <p>carriage return </p> + </item> + <tag><c>\\t</c></tag> + <item> + <p>tab </p> + </item> + <tag><c>\\e</c></tag> + <item> + <p>escape </p> + </item> + <tag><c>\\v</c></tag> + <item> + <p>vertical tab </p> + </item> + <tag><c>\\s</c></tag> + <item> + <p>space </p> + </item> + <tag><c>\\d</c></tag> + <item> + <p>delete </p> + </item> + <tag><c>\\ddd</c></tag> + <item> + <p>the octal value ddd </p> + </item> + <tag><c>\\xhh</c></tag> + <item> + <p>The hexadecimal value <c>hh</c>.</p> + </item> + <tag><c>\\x{h...}</c></tag> + <item> + <p>The hexadecimal value <c>h...</c>.</p> + </item> + <tag><c>\\c</c></tag> + <item> + <p>any other character literally, for example <c>\\\\</c> for backslash, + <c>\\"</c> for ")</p> + </item> + </taglist> + <p>To make these functions easier to use, in combination with the + function <c>io:get_line</c> which terminates the input line with + a new line, the <c>$</c> characters also matches a string ending + with <c>"...\ "</c>. The following examples + define Erlang data types:</p> + <pre> +Atoms [a-z][0-9a-zA-Z_]* + +Variables [A-Z_][0-9a-zA-Z_]* + +Floats (\\+|-)?[0-9]+\\.[0-9]+((E|e)(\\+|-)?[0-9]+)?</pre> + <p>Regular expressions are written as Erlang strings when used with the functions in this module. This means that any <c>\\</c> or <c>"</c> characters in a regular expression + string must be written with <c>\\</c> as they are also escape characters for the string. For example, the regular expression string for Erlang floats is: + <c>"(\\\\+|-)?[0-9]+\\\\.[0-9]+((E|e)(\\\\+|-)?[0-9]+)?"</c>.</p> + <p>It is not really necessary to have the escape sequences as part of the regular expression syntax as they can always be generated directly in the string. They are included for completeness and can they can also be useful when generating regular expressions, or when they are entered other than with Erlang strings.</p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/sets.xml b/lib/stdlib/doc/src/sets.xml new file mode 100644 index 0000000000..3610bb0184 --- /dev/null +++ b/lib/stdlib/doc/src/sets.xml @@ -0,0 +1,252 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>sets</title> + <prepared>Robert Virding</prepared> + <responsible>Bjarne Dacker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>99-07-27</date> + <rev>A</rev> + <file>sets.sgml</file> + </header> + <module>sets</module> + <modulesummary>Functions for Set Manipulation</modulesummary> + <description> + <p>Sets are collections of elements with no duplicate elements. + The representation of a set is not defined.</p> + <p>This module provides exactly the same interface as the module + <c>ordsets</c> but with a defined representation. One difference is + that while this module considers two elements as different if they + do not match (<c>=:=</c>), <c>ordsets</c> considers two elements as + different if and only if they do not compare equal (<c>==</c>).</p> + </description> + + <section> + <title>DATA TYPES</title> + <code type="none"> +set() + as returned by new/0</code> + </section> + <funcs> + <func> + <name>new() -> Set</name> + <fsummary>Return an empty set</fsummary> + <type> + <v>Set = set()</v> + </type> + <desc> + <p>Returns a new empty set.</p> + </desc> + </func> + <func> + <name>is_set(Set) -> bool()</name> + <fsummary>Test for an <c>Set</c></fsummary> + <type> + <v>Set = term()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Set</c> is a set of + elements, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>size(Set) -> int()</name> + <fsummary>Return the number of elements in a set</fsummary> + <type> + <v>Set = term()</v> + </type> + <desc> + <p>Returns the number of elements in <c>Set</c>.</p> + </desc> + </func> + <func> + <name>to_list(Set) -> List</name> + <fsummary>Convert an <c>Set</c>into a list</fsummary> + <type> + <v>Set = set()</v> + <v>List = [term()]</v> + </type> + <desc> + <p>Returns the elements of <c>Set</c> as a list.</p> + </desc> + </func> + <func> + <name>from_list(List) -> Set</name> + <fsummary>Convert a list into an <c>Set</c></fsummary> + <type> + <v>List = [term()]</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns an set of the elements in <c>List</c>.</p> + </desc> + </func> + <func> + <name>is_element(Element, Set) -> bool()</name> + <fsummary>Test for membership of an <c>Set</c></fsummary> + <type> + <v>Element = term()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Element</c> is an element of + <c>Set</c>, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>add_element(Element, Set1) -> Set2</name> + <fsummary>Add an element to an <c>Set</c></fsummary> + <type> + <v>Element = term()</v> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns a new set formed from <c>Set1</c> with + <c>Element</c> inserted.</p> + </desc> + </func> + <func> + <name>del_element(Element, Set1) -> Set2</name> + <fsummary>Remove an element from an <c>Set</c></fsummary> + <type> + <v>Element = term()</v> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns <c>Set1</c>, but with <c>Element</c> removed.</p> + </desc> + </func> + <func> + <name>union(Set1, Set2) -> Set3</name> + <fsummary>Return the union of two <c>Sets</c></fsummary> + <type> + <v>Set1 = Set2 = Set3 = set()</v> + </type> + <desc> + <p>Returns the merged (union) set of <c>Set1</c> and + <c>Set2</c>.</p> + </desc> + </func> + <func> + <name>union(SetList) -> Set</name> + <fsummary>Return the union of a list of <c>Sets</c></fsummary> + <type> + <v>SetList = [set()]</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the merged (union) set of the list of sets.</p> + </desc> + </func> + <func> + <name>intersection(Set1, Set2) -> Set3</name> + <fsummary>Return the intersection of two <c>Sets</c></fsummary> + <type> + <v>Set1 = Set2 = Set3 = set()</v> + </type> + <desc> + <p>Returns the intersection of <c>Set1</c> and + <c>Set2</c>.</p> + </desc> + </func> + <func> + <name>intersection(SetList) -> Set</name> + <fsummary>Return the intersection of a list of <c>Sets</c></fsummary> + <type> + <v>SetList = [set()]</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the intersection of the non-empty list of sets.</p> + </desc> + </func> + <func> + <name>is_disjoint(Set1, Set2) -> bool()</name> + <fsummary>Check whether two <c>Sets</c> are disjoint</fsummary> + <type> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns <c>true</c> if <c>Set1</c> and + <c>Set2</c> are disjoint (have no elements in common), + and <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>subtract(Set1, Set2) -> Set3</name> + <fsummary>Return the difference of two <c>Sets</c></fsummary> + <type> + <v>Set1 = Set2 = Set3 = set()</v> + </type> + <desc> + <p>Returns only the elements of <c>Set1</c> which are not + also elements of <c>Set2</c>.</p> + </desc> + </func> + <func> + <name>is_subset(Set1, Set2) -> bool()</name> + <fsummary>Test for subset</fsummary> + <type> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns <c>true</c> when every element of <c>Set</c>1 is + also a member of <c>Set2</c>, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>fold(Function, Acc0, Set) -> Acc1</name> + <fsummary>Fold over set elements</fsummary> + <type> + <v>Function = fun (E, AccIn) -> AccOut</v> + <v>Acc0 = Acc1 = AccIn = AccOut = term()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Fold <c>Function</c> over every element in <c>Set</c> + returning the final value of the accumulator.</p> + </desc> + </func> + <func> + <name>filter(Pred, Set1) -> Set2</name> + <fsummary>Filter set elements</fsummary> + <type> + <v>Pred = fun (E) -> bool()</v> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Filter elements in <c>Set1</c> with boolean function + <c>Fun</c>.</p> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p><seealso marker="ordsets">ordsets(3)</seealso>, + <seealso marker="gb_sets">gb_sets(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/shell.xml b/lib/stdlib/doc/src/shell.xml new file mode 100644 index 0000000000..24b845fee9 --- /dev/null +++ b/lib/stdlib/doc/src/shell.xml @@ -0,0 +1,810 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>shell</title> + <prepared>Bjorn Gustavsson</prepared> + <responsible>Bjarne Dacker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>97-01-24</date> + <rev>A</rev> + <file>shell.sgml</file> + </header> + <module>shell</module> + <modulesummary>The Erlang Shell</modulesummary> + <description> + <p>The module <c>shell</c> implements an Erlang shell. + </p> + <p>The shell is a user interface program + for entering expression sequences. The expressions are + evaluated and a value is returned. + A history mechanism saves previous commands and their + values, which can then be incorporated in later commands. + How many commands and results to save can be determined by the user, + either interactively, by calling <c>shell:history/1</c> and + <c>shell:results/1</c>, or by setting the application configuration + parameters <c>shell_history_length</c> and + <c>shell_saved_results</c> for the application STDLIB. + </p> + <p>The shell uses a helper process for evaluating commands in + order to protect the history mechanism from exceptions. By + default the evaluator process is killed when an exception + occurs, but by calling <c>shell:catch_exception/1</c> or by + setting the application configuration parameter + <c>shell_catch_exception</c> for the application STDLIB + this behavior can be changed. See also the example below. + </p> + <p>Variable bindings, and local process dictionary changes + which are generated in user expressions are preserved, and the variables + can be used in later commands to access their values. The + bindings can also be forgotten so the variables can be re-used. + </p> + <p>The special shell commands all have the syntax of (local) + function calls. They are evaluated as + normal function calls and many commands can be used in one + expression sequence. + </p> + <p>If a command (local function call) is not recognized by the + shell, an attempt is first made to find the function in the + module <c>user_default</c>, where customized local commands + can be placed. If found, then the function is evaluated. + Otherwise, an attempt is made to evaluate the function in the + module <c>shell_default</c>. The module + <c>user_default</c> must be explicitly loaded. + </p> + <p>The shell also permits the user to start multiple concurrent + jobs. A job can be regarded as a set of processes which can + communicate with the shell. + </p> + <p>There is some support for reading and printing records in + the shell. During compilation record expressions are translated + to tuple expressions. In runtime it is not known whether a tuple + actually represents a record. Nor are the record definitions + used by compiler available at runtime. So in order to read the + record syntax and print tuples as records when possible, record + definitions have to be maintained by the shell itself. The shell + commands for reading, defining, forgetting, listing, and + printing records are described below. Note that each job has its + own set of record definitions. To facilitate matters record + definitions in the modules <c>shell_default</c> and + <c>user_default</c> (if loaded) are read each time a new job is + started. For instance, adding the line</p> + <code type="none"> + -include_lib("kernel/include/file.hrl").</code> + <p>to <c>user_default</c> makes the definition of <c>file_info</c> + readily available in the shell. + </p> + <p>The shell runs in two modes: </p> + <list type="bulleted"> + <item><c>Normal (possibly restricted)</c> mode, in which + commands can be edited and expressions evaluated. + </item> + <item>Job Control Mode <c>JCL</c>, in which jobs can be + started, killed, detached and connected. + </item> + </list> + <p>Only the currently connected job can 'talk' to the shell.</p> + </description> + + <section> + <title>Shell Commands</title> + <taglist> + <tag><c>b()</c></tag> + <item> + <p>Prints the current variable bindings.</p> + </item> + <tag><c>f()</c></tag> + <item> + <p>Removes all variable bindings. + </p> + </item> + <tag><c>f(X)</c></tag> + <item> + <p>Removes the binding of variable <c>X</c>. + </p> + </item> + <tag><c>h()</c></tag> + <item> + <p>Prints the history list. + </p> + </item> + <tag><c>history(N)</c></tag> + <item> + <p>Sets the number of previous commands to keep in the + history list to <c>N</c>. The previous number is returned. + The default number is 20. + </p> + </item> + <tag><c>results(N)</c></tag> + <item> + <p>Sets the number of results from previous commands to keep in + the history list to <c>N</c>. The previous number is returned. + The default number is 20. + </p> + </item> + <tag><c>e(N)</c></tag> + <item> + <p>Repeats the command <c>N</c>, if <c>N</c> is positive. If + it is negative, the <c>N</c>th previous command is repeated + (i.e., <c>e(-1)</c> repeats the previous command). + </p> + </item> + <tag><c>v(N)</c></tag> + <item> + <p>Uses the return value of the command <c>N</c> in the + current command, if <c>N</c> is positive. If it is negative, + the return value of the <c>N</c>th previous command is used + (i.e., <c>v(-1)</c> uses the value of the previous command). + </p> + </item> + <tag><c>help()</c></tag> + <item> + <p>Evaluates <c>shell_default:help()</c>. + </p> + </item> + <tag><c>c(File)</c></tag> + <item> + <p>Evaluates <c>shell_default:c(File)</c>. This compiles + and loads code in <c>File</c> and purges old versions of + code, if necessary. Assumes that the file and module names + are the same. + </p> + </item> + <tag><c>catch_exception(Bool)</c></tag> + <item> + <p>Sets the exception handling of the evaluator process. The + previous exception handling is returned. The default + (<c>false</c>) is to kill the evaluator process when an + exception occurs, which causes the shell to create a new + evaluator process. When the exception handling is set to + <c>true</c> the evaluator process lives on which means that + for instance ports and ETS tables as well as processes + linked to the evaluator process survive the exception. + </p> + </item> + <tag><c>rd(RecordName, RecordDefinition)</c></tag> + <item> + <p>Defines a record in the shell. <c>RecordName</c> is + an atom and <c>RecordDefinition</c> lists the field names + and the default values. Usually record definitions are made + known to the shell by use of the <c>rr</c> commands + described below, but sometimes it is handy to define records + on the fly. + </p> + </item> + <tag><c>rf()</c></tag> + <item> + <p>Removes all record definitions, then reads record + definitions from the modules <c>shell_default</c> and + <c>user_default</c> (if loaded). Returns the names of the + records defined. + </p> + </item> + <tag><c>rf(RecordNames)</c></tag> + <item> + <p>Removes selected record definitions. + <c>RecordNames</c> is a record name or a list of record names. + Use <c>'_'</c> to remove all record definitions. + </p> + </item> + <tag><c>rl()</c></tag> + <item> + <p>Prints all record definitions. + </p> + </item> + <tag><c>rl(RecordNames)</c></tag> + <item> + <p>Prints selected record definitions. + <c>RecordNames</c> is a record name or a list of record names. + </p> + </item> + <tag><c>rp(Term)</c></tag> + <item> + <p>Prints a term using the record definitions known to the + shell. All of <c>Term</c> is printed; the depth is not + limited as is the case when a return value is printed. + </p> + </item> + <tag><c>rr(Module)</c></tag> + <item> + <p>Reads record definitions from a module's BEAM file. If + there are no record definitions in the BEAM file, the + source file is located and read instead. Returns the names + of the record definitions read. <c>Module</c> is an atom. + </p> + </item> + <tag><c>rr(Wildcard)</c></tag> + <item> + <p>Reads record definitions from files. Existing + definitions of any of the record names read are replaced. + <c>Wildcard</c> is a wildcard string as defined in + <c>filelib(3)</c> but not an atom. + </p> + </item> + <tag><c>rr(WildcardOrModule, RecordNames)</c></tag> + <item> + <p>Reads record definitions from files but + discards record names not mentioned in <c>RecordNames</c> (a + record name or a list of record names). + </p> + </item> + <tag><c>rr(WildcardOrModule, RecordNames, Options)</c></tag> + <item> + <p>Reads record definitions from files. The compiler + options <c>{i, Dir}</c>, <c>{d, Macro}</c>, and + <c>{d, Macro, Value}</c> are recognized and used + for setting up the include path and macro definitions. Use + <c>'_'</c> as value of <c>RecordNames</c> to read all record + definitions. + </p> + </item> + </taglist> + </section> + + <section> + <title>Example</title> + <p>The following example is a long dialogue with the shell. Commands + starting with <c>></c> are inputs to the shell. All other lines + are output from the shell. All commands in this example are explained at the end of the dialogue. + .</p> + <pre> +strider 1> <input>erl</input> +Erlang (BEAM) emulator version 5.3 [hipe] [threads:0] + +Eshell V5.3 (abort with ^G) +1><input>Str = "abcd".</input> +"abcd" +2> <input>L = length(Str).</input> +4 +3> <input>Descriptor = {L, list_to_atom(Str)}.</input> +{4,abcd} +4> <input>L.</input> +4 +5> <input>b().</input> +Descriptor = {4,abcd} +L = 4 +Str = "abcd" +ok +6> <input>f(L).</input> +ok +7> <input>b().</input> +Descriptor = {4,abcd} +Str = "abcd" +ok +8> <input>f(L).</input> +ok +9> <input>{L, _} = Descriptor.</input> +{4,abcd} +10> <input>L.</input> +4 +11> <input>{P, Q, R} = Descriptor.</input> +** exception error: no match of right hand side value {4,abcd} +12> <input>P.</input> +* 1: variable 'P' is unbound ** +13> <input>Descriptor.</input> +{4,abcd} +14><input>{P, Q} = Descriptor.</input> +{4,abcd} +15> <input>P.</input> +4 +16> <input>f().</input> +ok +17> <input>put(aa, hello).</input> +undefined +18> <input>get(aa).</input> +hello +19> <input>Y = test1:demo(1).</input> +11 +20> <input>get().</input> +[{aa,worked}] +21> <input>put(aa, hello).</input> +worked +22> <input>Z = test1:demo(2).</input> +** exception error: no match of right hand side value 1 + in function test1:demo/1 +23> <input>Z.</input> +* 1: variable 'Z' is unbound ** +24> <input>get(aa).</input> +hello +25> <input>erase(), put(aa, hello).</input> +undefined +26> <input>spawn(test1, demo, [1]).</input> +<0.57.0> +27> <input>get(aa).</input> +hello +28> <input>io:format("hello hello\ ").</input> +hello hello ok +29> <input>e(28).</input> +hello hello ok +30> <input>v(28).</input> +ok +31> <input>c(ex).</input> +{ok,ex} +32> <input>rr(ex).</input> +[rec] +33> <input>rl(rec).</input> +-record(rec,{a,b = val()}). +ok +34> <input>#rec{}.</input> +** exception error: undefined shell command val/0 +35> <input>#rec{b = 3}.</input> +#rec{a = undefined,b = 3} +36> <input>rp(v(-1)).</input> +#rec{a = undefined,b = 3} +ok +37> <input>rd(rec, {f = orddict:new()}).</input> +rec +38> <input>#rec{}.</input> +#rec{f = []} +ok +39> <input>rd(rec, {c}), A.</input> +* 1: variable 'A' is unbound ** +40> <input>#rec{}.</input> +#rec{c = undefined} +ok +41> <input>test1:loop(0).</input> +Hello Number: 0 +Hello Number: 1 +Hello Number: 2 +Hello Number: 3 + +User switch command + --> i + --> c +. +. +. +Hello Number: 3374 +Hello Number: 3375 +Hello Number: 3376 +Hello Number: 3377 +Hello Number: 3378 +** exception exit: killed +42> <input>E = ets:new(t, []).</input> +17 +43> <input>ets:insert({d,1,2}).</input> +** exception error: undefined function ets:insert/1 +44> <input>ets:insert(E, {d,1,2}).</input> +** exception error: argument is of wrong type + in function ets:insert/2 + called as ets:insert(16,{d,1,2}) +45> <input>f(E).</input> +ok +46> <input>catch_exception(true).</input> +false +47> <input>E = ets:new(t, []).</input> +18 +48> <input>ets:insert({d,1,2}).</input> +* exception error: undefined function ets:insert/1 +49> <input>ets:insert(E, {d,1,2}).</input> +true +50> <input>halt().</input> +strider 2></pre> + </section> + + <section> + <title>Comments</title> + <p>Command 1 sets the variable <c>Str</c> to the string + <c>"abcd"</c>. + </p> + <p>Command 2 sets <c>L</c> to the length of the string evaluating + the BIF <c>atom_to_list</c>. + </p> + <p>Command 3 builds the tuple <c>Descriptor</c>. + </p> + <p>Command 4 prints the value of the variable <c>L</c>. + </p> + <p>Command 5 evaluates the internal shell command <c>b()</c>, which + is an abbreviation of "bindings". This prints + the current shell variables and their bindings. The <c>ok</c> at + the end is the return value of the <c>b()</c> function. + </p> + <p>Command 6 <c>f(L)</c> evaluates the internal shell command + <c>f(L)</c> (abbreviation of "forget"). The value of the variable + <c>L</c> is removed. + </p> + <p>Command 7 prints the new bindings. + </p> + <p>Command 8 has no effect since <c>L</c> has no value.</p> + <p>Command 9 performs a pattern matching operation on + <c>Descriptor</c>, binding a new value to <c>L</c>. + </p> + <p>Command 10 prints the current value of <c>L</c>. + </p> + <p>Command 11 tries to match <c>{P, Q, R}</c> against + <c>Descriptor</c> which is <c>{4, abc}</c>. The match fails and + none of the new variables become bound. The printout starting + with "<c>** exception error:</c>" is not the value of the + expression (the expression had no value because its evaluation + failed), but rather a warning printed by the system to inform + the user that an error has occurred. The values of the other + variables (<c>L</c>, <c>Str</c>, etc.) are unchanged. + </p> + <p>Commands 12 and 13 show that <c>P</c> is unbound because the + previous command failed, and that <c>Descriptor</c> has not + changed. + </p> + <p>Commands 14 and 15 show a correct match where <c>P</c> and + <c>Q</c> are bound. + </p> + <p>Command 16 clears all bindings. + </p> + <p>The next few commands assume that <c>test1:demo(X)</c> is + defined in the following way:</p> + <pre> +demo(X) -> + put(aa, worked), + X = 1, + X + 10. </pre> + <p>Commands 17 and 18 set and inspect the value of the item + <c>aa</c> in the process dictionary. + </p> + <p>Command 19 evaluates <c>test1:demo(1)</c>. The evaluation + succeeds and the changes made in the process dictionary become + visible to the shell. The new value of the dictionary item + <c>aa</c> can be seen in command 20. + </p> + <p>Commands 21 and 22 change the value of the dictionary item + <c>aa</c> to <c>hello</c> and call <c>test1:demo(2)</c>. Evaluation + fails and the changes made to the dictionary in + <c>test1:demo(2)</c>, before the error occurred, are discarded. + </p> + <p>Commands 23 and 24 show that <c>Z</c> was not bound and that the + dictionary item <c>aa</c> has retained its original value. + </p> + <p>Commands 25, 26 and 27 show the effect of evaluating + <c>test1:demo(1)</c> in the background. In this case, the + expression is evaluated in a newly spawned process. Any + changes made in the process dictionary are local to the newly + spawned process and therefore not visible to the shell. + </p> + <p>Commands 28, 29 and 30 use the history facilities of the shell. + </p> + <p>Command 29 is <c>e(28)</c>. This re-evaluates command + 28. Command 30 is <c>v(28)</c>. This uses the value (result) of + command 28. In the cases of a pure function (a function + with no side effects), the result is the same. For a function + with side effects, the result can be different. + </p> + <p>The next few commands show some record manipulation. It is + assumed that <c>ex.erl</c> defines a record like this:</p> + <pre> +-record(rec, {a, b = val()}). + +val() -> + 3. </pre> + <p>Commands 31 and 32 compiles the file <c>ex.erl</c> and reads + the record definitions in <c>ex.beam</c>. If the compiler did not + output any record definitions on the BEAM file, <c>rr(ex)</c> + tries to read record definitions from the source file instead. + </p> + <p>Command 33 prints the definition of the record named + <c>rec</c>. + </p> + <p>Command 34 tries to create a <c>rec</c> record, but fails + since the function <c>val/0</c> is undefined. Command 35 shows + the workaround: explicitly assign values to record fields that + cannot otherwise be initialized. + </p> + <p>Command 36 prints the newly created record using record + definitions maintained by the shell. + </p> + <p>Command 37 defines a record directly in the shell. The + definition replaces the one read from the file <c>ex.beam</c>. + </p> + <p>Command 38 creates a record using the new definition, and + prints the result. + </p> + <p>Command 39 and 40 show that record definitions are updated + as side effects. The evaluation of the command fails but + the definition of <c>rec</c> has been carried out. + </p> + <p>For the next command, it is assumed that <c>test1:loop(N)</c> is + defined in the following way:</p> + <pre> +loop(N) -> + io:format("Hello Number: ~w~n", [N]), + loop(N+1).</pre> + <p>Command 41 evaluates <c>test1:loop(0)</c>, which puts the + system into an infinite loop. At this point the user types + <c>Control G</c>, which suspends output from the current process, + which is stuck in a loop, and activates <c>JCL</c> mode. In <c>JCL</c> + mode the user can start and stop jobs. + </p> + <p>In this particular case, the <c>i</c> command ("interrupt") is + used to terminate the looping program, and the <c>c</c> command + is used to connect to the shell again. Since the process was + running in the background before we killed it, there will be + more printouts before the "<c>** exception exit: killed</c>" + message is shown. + </p> + <p>Command 42 creates an ETS table.</p> + <p>Command 43 tries to insert a tuple into the ETS table but the + first argument (the table) is missing. The exception kills the + evaluator process.</p> + <p>Command 44 corrects the mistake, but the ETS table has been + destroyed since it was owned by the killed evaluator process.</p> + <p>Command 46 sets the exception handling of the evaluator process + to <c>true</c>. The exception handling can also be set when + starting Erlang, like this: <c>erl -stdlib shell_catch_exception + true</c>.</p> + <p>Command 48 makes the same mistake as in command 43, but this time + the evaluator process lives on. The single star at the beginning + of the printout signals that the exception has been caught.</p> + <p>Command 49 successfully inserts the tuple into the ETS table.</p> + <p>The <c>halt()</c> command exits the Erlang runtime system. + </p> + </section> + + <section> + <title>JCL Mode</title> + <p>When the shell starts, it starts a single evaluator + process. This process, together with any local processes which + it spawns, is referred to as a <c>job</c>. Only the current job, + which is said to be <c>connected</c>, can perform operations + with standard IO. All other jobs, which are said to be <c>detached</c>, are + <c>blocked</c> if they attempt to use standard IO. + </p> + <p>All jobs which do not use standard IO run in the normal way. + </p> + <p>The shell escape key <em><c>^G</c></em> (Control G) detaches the current job + and activates <c>JCL</c> mode. The <c>JCL</c> mode prompt is <c>"-->"</c>. If <c>"?"</c> is entered at the prompt, the following help message is + displayed:</p> + <pre> + --> ? + c [nn] - connect to job + i [nn] - interrupt job + k [nn] - kill job + j - list all jobs + s [shell] - start local shell + r [node [shell]] - start remote shell + q - quit erlang + ? | h - this message </pre> + <p>The <c>JCL</c> commands have the following meaning:</p> + <taglist> + <tag><c>c [nn]</c></tag> + <item> + <p>Connects to job number <c><![CDATA[<nn>]]></c> or the current + job. The standard shell is resumed. Operations which use + standard IO by the current job will be interleaved with + user inputs to the shell. + </p> + </item> + <tag><c>i [nn]</c></tag> + <item> + <p>Stops the current evaluator process for job number + <c>nn</c> or the current job, but does not kill the shell + process. Accordingly, any variable bindings and the process dictionary + will be preserved and the job can be connected again. + This command can be used to interrupt an endless loop. + </p> + </item> + <tag><c>k [nn]</c></tag> + <item> + <p>Kills job number <c>nn</c> or the current + job. All spawned processes in the job are + killed, provided they have not evaluated the + <c>group_leader/1</c> BIF and are located on + the local machine. Processes spawned on remote nodes will + not be killed. + </p> + </item> + <tag><c>j</c></tag> + <item> + <p>Lists all jobs. A list of all known jobs is + printed. The current job name is prefixed with '*'. + </p> + </item> + <tag><c>s</c></tag> + <item> + <p>Starts a new job. This will be assigned the new index + <c>[nn]</c> which can be used in references. + </p> + </item> + <tag><c>s [shell]</c></tag> + <item> + <p>Starts a new job. This will be assigned the new index + <c>[nn]</c> which can be used in references. + If the optional argument <c>shell</c> is given, it is assumed + to be a module that implements an alternative shell. + </p> + </item> + <tag><c>r [node]</c></tag> + <item> + <p>Starts a remote job on <c>node</c>. This is used in + distributed Erlang to allow a shell running on one node to + control a number of applications running on a network of + nodes. + If the optional argument <c>shell</c> is given, it is assumed + to be a module that implements an alternative shell. + </p> + </item> + <tag><c>q</c></tag> + <item> + <p>Quits Erlang. Note that this option is disabled if + Erlang is started with the ignore break, <c>+Bi</c>, + system flag (which may be useful e.g. when running + a restricted shell, see below). + </p> + </item> + <tag><c>?</c></tag> + <item> + <p>Displays this message.</p> + </item> + </taglist> + <p>It is possible to alter the behavior of shell escape by means + of the STDLIB application variable <c>shell_esc</c>. The value of + the variable can be either <c>jcl</c> (<c>erl -stdlib shell_esc jcl</c>) + or <c>abort</c> (<c>erl -stdlib shell_esc abort</c>). The + first option sets ^G to activate <c>JCL</c> mode (which is also + default behavior). The latter sets ^G to terminate the current + shell and start a new one. <c>JCL</c> mode cannot be invoked when + <c>shell_esc</c> is set to <c>abort</c>. </p> + <p>If you want an Erlang node to have a remote job active from the start + (rather than the default local job), you start Erlang with the + <c>-remsh</c> flag. Example: <c>erl -sname this_node -remsh other_node@other_host</c></p> + </section> + + <section> + <title>Restricted Shell</title> + <p>The shell may be started in a + restricted mode. In this mode, the shell evaluates a function call + only if allowed. This feature makes it possible to, for example, + prevent a user from accidentally calling a function from the + prompt that could harm a running system (useful in combination + with the the system flag <em><c>+Bi</c></em>).</p> + <p>When the restricted shell evaluates an expression and + encounters a function call or an operator application, + it calls a callback function (with + information about the function call in question). This callback + function returns <c>true</c> to let the shell go ahead with the + evaluation, or <c>false</c> to abort it. There are two possible + callback functions for the user to implement:</p> + <p><em><c>local_allowed(Func, ArgList, State) -> {true,NewState} | {false,NewState}</c></em></p> + <p>to determine if the call to the local function <c>Func</c> + with arguments <c>ArgList</c> should be allowed.</p> + <p><em><c>non_local_allowed(FuncSpec, ArgList, State) -> {true,NewState} | {false,NewState} | {{redirect,NewFuncSpec,NewArgList},NewState}</c></em></p> + <p>to determine if the call to non-local function + <c>FuncSpec</c> (<c>{Module,Func}</c> or a fun) with arguments + <c>ArgList</c> should be allowed. The return value + <c>{redirect,NewFuncSpec,NewArgList}</c> can be used to let + the shell evaluate some other function than the one specified by + <c>FuncSpec</c> and <c>ArgList</c>.</p> + <p>These callback functions are in fact called from local and + non-local evaluation function handlers, described in the + <seealso marker="erl_eval">erl_eval</seealso> + manual page. (Arguments in <c>ArgList</c> are evaluated before the + callback functions are called.)</p> + <p>The <c>State</c> argument is a tuple + <c>{ShellState,ExprState}</c>. The return value <c>NewState</c> + has the same form. This may be used to carry a state between calls + to the callback functions. Data saved in <c>ShellState</c> lives + through an entire shell session. Data saved in <c>ExprState</c> + lives only through the evaluation of the current expression.</p> + <p>There are two ways to start a restricted shell session:</p> + <list type="bulleted"> + <item>Use the STDLIB application variable <c>restricted_shell</c> + and specify, as its value, the name of the callback + module. Example (with callback functions implemented in + callback_mod.erl): <c>$ erl -stdlib restricted_shell callback_mod</c></item> + <item>From a normal shell session, call function + <c>shell:start_restricted/1</c>. This exits the current evaluator + and starts a new one in restricted mode.</item> + </list> + <p><em>Notes:</em></p> + <list type="bulleted"> + <item>When restricted shell mode is activated or + deactivated, new jobs started on the node will run in restricted + or normal mode respectively.</item> + <item>If restricted mode has been enabled on a + particular node, remote shells connecting to this node will also + run in restricted mode.</item> + <item>The callback functions cannot be used to allow or disallow + execution of functions called from compiled code (only functions + called from expressions entered at the shell prompt).</item> + </list> + <p>Errors when loading the callback module is handled in different + ways depending on how the restricted shell is activated:</p> + <list type="bulleted"> + <item>If the restricted shell is activated by setting the kernel + variable during emulator startup and the callback module cannot be + loaded, a default restricted shell allowing only the commands + <c>q()</c> and <c>init:stop()</c> is used as fallback.</item> + <item>If the restricted shell is activated using + <c>shell:start_restricted/1</c> and the callback module cannot be + loaded, an error report is sent to the error logger and the call + returns <c>{error,Reason}</c>.</item> + </list> + </section> + <funcs> + <func> + <name>history(N) -> integer()</name> + <fsummary>Sets the number of previous commands to keep</fsummary> + <type> + <v>N = integer()</v> + </type> + <desc> + <p>Sets the number of previous commands to keep in the + history list to <c>N</c>. The previous number is returned. + The default number is 20.</p> + </desc> + </func> + <func> + <name>results(N) -> integer()</name> + <fsummary>Sets the number of previous results to keep</fsummary> + <type> + <v>N = integer()</v> + </type> + <desc> + <p>Sets the number of results from previous commands to keep in + the history list to <c>N</c>. The previous number is returned. + The default number is 20.</p> + </desc> + </func> + <func> + <name>catch_exception(Bool) -> Bool</name> + <fsummary>Sets the exception handling of the shell</fsummary> + <type> + <v>Bool = bool()</v> + </type> + <desc> + <p>Sets the exception handling of the evaluator process. The + previous exception handling is returned. The default + (<c>false</c>) is to kill the evaluator process when an + exception occurs, which causes the shell to create a new + evaluator process. When the exception handling is set to + <c>true</c> the evaluator process lives on which means that + for instance ports and ETS tables as well as processes + linked to the evaluator process survive the exception.</p> + </desc> + </func> + <func> + <name>start_restricted(Module) -> ok | {error, Reason}</name> + <fsummary>Exits a normal shell and starts a restricted shell.</fsummary> + <type> + <v>Module = atom()</v> + <v>Reason = atom()</v> + </type> + <desc> + <p>Exits a normal shell and starts a restricted + shell. <c>Module</c> specifies the callback module for the + functions <c>local_allowed/3</c> and <c>non_local_allowed/3</c>. + The function is meant to be called from the shell.</p> + <p>If the callback module cannot be loaded, an error tuple is + returned. The <c>Reason</c> in the error tuple is the one + returned by the code loader when trying to load the code of the callback + module.</p> + </desc> + </func> + <func> + <name>stop_restricted() -> ok</name> + <fsummary>Exits a restricted shell and starts a normal shell.</fsummary> + <desc> + <p>Exits a restricted shell and starts a normal shell. The function + is meant to be called from the shell.</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/shell_default.xml b/lib/stdlib/doc/src/shell_default.xml new file mode 100644 index 0000000000..4f8cc6c5bb --- /dev/null +++ b/lib/stdlib/doc/src/shell_default.xml @@ -0,0 +1,70 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>shell_default</title> + <prepared>Joe Armstrong</prepared> + <responsible>Joe Armstrong</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked>Joe Armstrong</checked> + <date>1996-09-09</date> + <rev>A</rev> + <file>shell_default.sgml</file> + </header> + <module>shell_default</module> + <modulesummary>Customizing the Erlang Environment</modulesummary> + <description> + <p>The functions in <c>shell_default</c> are called when no module + name is given in a shell command. + </p> + <p>Consider the following shell dialogue:</p> + <pre> +1 > <input>lists:reverse("abc").</input> +"cba" +2 > <input>c(foo).</input> +{ok, foo} </pre> + <p>In command one, the module <c>lists</c> is called. In command + two, no module name is specified. The shell searches the modules + <c>user_default</c> followed by <c>shell_default</c> for the + function <c>foo/1</c>. + </p> + <p><c>shell_default</c> is intended for "system wide" + customizations to the shell. <c>user_default</c> is intended for + "local" or individual user customizations.</p> + </description> + + <section> + <title>Hint</title> + <p>To add your own commands to the shell, create a module called + <c>user_default</c> and add the commands you want. Then add the + following line as the <em>first</em> line in your <c>.erlang</c> file in your + home directory. </p> + <pre> +code:load_abs("$PATH/user_default"). </pre> + <p><c>$PATH</c> is the directory where your + <c>user_default</c> module can be found.</p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/slave.xml b/lib/stdlib/doc/src/slave.xml new file mode 100644 index 0000000000..168d83f301 --- /dev/null +++ b/lib/stdlib/doc/src/slave.xml @@ -0,0 +1,215 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>slave</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>slave</module> + <modulesummary>Functions to Starting and Controlling Slave Nodes</modulesummary> + <description> + <p>This module provides functions for starting Erlang slave nodes. + All slave nodes which are started by a master will terminate + automatically when the master terminates. All TTY output produced + at the slave will be sent back to the master node. File I/O is + done via the master.</p> + <p>Slave nodes on other hosts than the current one are started with + the program <c>rsh</c>. The user must be allowed to <c>rsh</c> to + the remote hosts without being prompted for a password. This can + be arranged in a number of ways (refer to the <c>rsh</c> + documentation for details). A slave node started on the same host + as the master inherits certain environment values from the master, + such as the current directory and the environment variables. For + what can be assumed about the environment when a slave is started + on another host, read the documentation for the <c>rsh</c> + program.</p> + <p>An alternative to the <c>rsh</c> program can be specified on + the command line to <c>erl</c> as follows: <c>-rsh Program</c>.</p> + <p>The slave node should use the same file system at the master. At + least, Erlang/OTP should be installed in the same place on both + computers and the same version of Erlang should be used.</p> + <p>Currently, a node running on Windows NT can only start slave + nodes on the host on which it is running.</p> + <p>The master node must be alive.</p> + </description> + <funcs> + <func> + <name>start(Host) -></name> + <name>start(Host, Name) -></name> + <name>start(Host, Name, Args) -> {ok, Node} | {error, Reason}</name> + <fsummary>Start a slave node on a host</fsummary> + <type> + <v>Host = Name = atom()</v> + <v>Args = string()</v> + <v>Node = node()</v> + <v>Reason = timeout | no_rsh | {already_running, Node}</v> + </type> + <desc> + <p>Starts a slave node on the host <c>Host</c>. Host names need + not necessarily be specified as fully qualified names; short + names can also be used. This is the same condition that + applies to names of distributed Erlang nodes.</p> + <p>The name of the started node will be <c>Name@Host</c>. If no + name is provided, the name will be the same as the node which + executes the call (with the exception of the host name part of + the node name).</p> + <p>The slave node resets its <c>user</c> process so that all + terminal I/O which is produced at the slave is automatically + relayed to the master. Also, the file process will be relayed + to the master.</p> + <p>The <c>Args</c> argument is used to set <c>erl</c> command + line arguments. If provided, it is passed to the new node and + can be used for a variety of purposes. See + <seealso marker="erts:erl#erl">erl(1)</seealso></p> + <p>As an example, suppose that we want to start a slave node at + host <c>H</c> with the node name <c>Name@H</c>, and we also + want the slave node to have the following properties:</p> + <list type="bulleted"> + <item> + <p>directory <c>Dir</c> should be added to the code path;</p> + </item> + <item> + <p>the Mnesia directory should be set to <c>M</c>;</p> + </item> + <item> + <p>the unix <c>DISPLAY</c> environment variable should be + set to the display of the master node.</p> + </item> + </list> + <p>The following code is executed to achieve this:</p> + <code type="none"> +E = " -env DISPLAY " ++ net_adm:localhost() ++ ":0 ", +Arg = "-mnesia_dir " ++ M ++ " -pa " ++ Dir ++ E, +slave:start(H, Name, Arg).</code> + <p>If successful, the function returns <c>{ok, Node}</c>, + where <c>Node</c> is the name of the new node. Otherwise it + returns <c>{error, Reason}</c>, where <c>Reason</c> can be + one of:</p> + <taglist> + <tag><c>timeout</c></tag> + <item> + <p>The master node failed to get in contact with the slave + node. This can happen in a number of circumstances:</p> + <list type="bulleted"> + <item>Erlang/OTP is not installed on the remote host</item> + <item>the file system on the other host has a different + structure to the the master</item> + <item>the Erlang nodes have different cookies.</item> + </list> + </item> + <tag><c>no_rsh</c></tag> + <item> + <p>There is no <c>rsh</c> program on the computer.</p> + </item> + <tag><c>{already_running, Node}</c></tag> + <item> + <p>A node with the name <c>Name@Host</c> already exists.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>start_link(Host) -></name> + <name>start_link(Host, Name) -></name> + <name>start_link(Host, Name, Args) -> {ok, Node} | {error, Reason}</name> + <fsummary>Start and link to a slave node on a host</fsummary> + <type> + <v>Host = Name = atom()</v> + <v>Args = string()</v> + <v>Node = node()</v> + <v>Reason = timeout | no_rsh | {already_running, Node}</v> + </type> + <desc> + <p>Starts a slave node in the same way as <c>start/1,2,3</c>, + except that the slave node is linked to the currently + executing process. If that process terminates, the slave node + also terminates.</p> + <p>See <c>start/1,2,3</c> for a description of arguments and + return values.</p> + </desc> + </func> + <func> + <name>stop(Node) -> ok</name> + <fsummary>Stop (kill) a node</fsummary> + <type> + <v>Node = node()</v> + </type> + <desc> + <p>Stops (kills) a node.</p> + </desc> + </func> + <func> + <name>pseudo([Master | ServerList]) -> ok</name> + <fsummary>Start a number of pseudo servers</fsummary> + <type> + <v>Master = node()</v> + <v>ServerList = [atom()]</v> + </type> + <desc> + <p>Calls <c>pseudo(Master, ServerList)</c>. If we want to start + a node from the command line and set up a number of pseudo + servers, an Erlang runtime system can be started as + follows:</p> + <pre> +% erl -name abc -s slave pseudo klacke@super x --</pre> + </desc> + </func> + <func> + <name>pseudo(Master, ServerList) -> ok</name> + <fsummary>Start a number of pseudo servers</fsummary> + <type> + <v>Master = node()</v> + <v>ServerList = [atom()]</v> + </type> + <desc> + <p>Starts a number of pseudo servers. A pseudo server is a + server with a registered name which does absolutely nothing + but pass on all message to the real server which executes at a + master node. A pseudo server is an intermediary which only has + the same registered name as the real server.</p> + <p>For example, if we have started a slave node <c>N</c> and + want to execute <c>pxw</c> graphics code on this node, we can + start the server <c>pxw_server</c> as a pseudo server at + the slave node. The following code illustrates:</p> + <code type="none"> +rpc:call(N, slave, pseudo, [node(), [pxw_server]]).</code> + </desc> + </func> + <func> + <name>relay(Pid)</name> + <fsummary>Run a pseudo server</fsummary> + <type> + <v>Pid = pid()</v> + </type> + <desc> + <p>Runs a pseudo server. This function never returns any value + and the process which executes the function will receive + messages. All messages received will simply be passed on to + <c>Pid</c>.</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/sofs.xml b/lib/stdlib/doc/src/sofs.xml new file mode 100644 index 0000000000..ac434ec5b7 --- /dev/null +++ b/lib/stdlib/doc/src/sofs.xml @@ -0,0 +1,1781 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2001</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>sofs</title> + <prepared>Hans Bolinder</prepared> + <responsible>nobody</responsible> + <docno></docno> + <approved>nobody</approved> + <checked>no</checked> + <date>2001-08-25</date> + <rev>PA1</rev> + <file>sofs.sgml</file> + </header> + <module>sofs</module> + <modulesummary>Functions for Manipulating Sets of Sets</modulesummary> + <description> + <p>The <c>sofs</c> module implements operations on finite sets and + relations represented as sets. Intuitively, a set is a + collection of elements; every element belongs to the set, and + the set contains every element.</p> + <p>Given a set A and a sentence S(x), where x is a free variable, + a new set B whose elements are exactly those elements of A for + which S(x) holds can be formed, this is denoted B = + {x in A : S(x)}. Sentences are expressed using + the logical operators "for some" (or "there exists"), "for all", + "and", "or", "not". If the existence of a set containing all the + specified elements is known (as will always be the case in this + module), we write B = {x : S(x)}. </p> + <p>The <em>unordered set</em> containing the elements a, b and c + is denoted {a, b, c}. This notation is not to be + confused with tuples. The <em>ordered pair</em> of a and b, with + first <em>coordinate</em> a and second coordinate b, is denoted + (a, b). An ordered pair is an <em>ordered set</em> of two + elements. In this module ordered sets can contain one, two or + more elements, and parentheses are used to enclose the elements. + Unordered sets and ordered sets are orthogonal, again in this + module; there is no unordered set equal to any ordered set.</p> + <p>The set that contains no elements is called the <em>empty set</em>. + If two sets A and B contain the same elements, then A + is <marker id="equal"></marker><em>equal</em> to B, denoted + A = B. Two ordered sets are equal if they contain the + same number of elements and have equal elements at each + coordinate. If a set A contains all elements that B contains, + then B is a <marker id="subset"></marker><em>subset</em> of A. + The <marker id="union"></marker><em>union</em> of two sets A and B is + the smallest set that contains all elements of A and all elements of + B. The <marker id="intersection"></marker><em>intersection</em> of two + sets A and B is the set that contains all elements of A that + belong to B. + Two sets are <marker id="disjoint"></marker><em>disjoint</em> if their + intersection is the empty set. + The <marker id="difference"></marker><em>difference</em> of + two sets A and B is the set that contains all elements of A that + do not belong to B. + The <marker id="symmetric_difference"></marker><em>symmetric + difference</em> of + two sets is the set that contains those element that belong to + either of the two sets, but not both. + The <marker id="union_n"></marker><em>union</em> of a collection + of sets is the smallest set that contains all the elements that + belong to at least one set of the collection. + The <marker id="intersection_n"></marker><em>intersection</em> of + a non-empty collection of sets is the set that contains all elements + that belong to every set of the collection.</p> + <p>The <marker id="Cartesian_product"></marker><em>Cartesian + product</em> of + two sets X and Y, denoted X × Y, is the set + {a : a = (x, y) for some x in X and for + some y in Y}. + A <marker id="relation"></marker><em>relation</em> is a subset of + X × Y. Let R be a relation. The fact that + (x, y) belongs to R is written as x R y. Since + relations are sets, the definitions of the last paragraph + (subset, union, and so on) apply to relations as well. + The <marker id="domain"></marker><em>domain</em> of R is the + set {x : x R y for some y in Y}. + The <marker id="range"></marker><em>range</em> of R is the + set {y : x R y for some x in X}. + The <marker id="converse"></marker><em>converse</em> of R is the + set {a : a = (y, x) for some + (x, y) in R}. If A is a subset of X, then + the <marker id="image"></marker><em>image</em> of + A under R is the set {y : x R y for some + x in A}, and if B is a subset of Y, then + the <marker id="inverse_image"></marker><em>inverse image</em> of B is + the set {x : x R y for some y in B}. If R is a + relation from X to Y and S is a relation from Y to Z, then + the <marker id="relative_product"></marker><em>relative product</em> of + R and S is the relation T from X to Z defined so that x T z + if and only if there exists an element y in Y such that + x R y and y S z. + The <marker id="restriction"></marker><em>restriction</em> of R to A is + the set S defined so that x S y if and only if there exists an + element x in A such that x R y. If S is a restriction + of R to A, then R is + an <marker id="extension"></marker><em>extension</em> of S to X. + If X = Y then we call R a relation <em>in</em> X. + The <marker id="field"></marker><em>field</em> of a relation R in X + is the union of the domain of R and the range of R. + If R is a relation in X, and + if S is defined so that x S y if x R y and + not x = y, then S is + the <marker id="strict_relation"></marker><em>strict</em> relation + corresponding to + R, and vice versa, if S is a relation in X, and if R is defined + so that x R y if x S y or x = y, + then R is the <marker id="weak_relation"></marker><em>weak</em> relation + corresponding to S. A relation R in X is <em>reflexive</em> if + x R x for every element x of X; it is + <em>symmetric</em> if x R y implies that + y R x; and it is <em>transitive</em> if + x R y and y R z imply that x R z.</p> + <p>A <marker id="function"></marker><em>function</em> F is a relation, a + subset of X × Y, such that the domain of F is + equal to X and such that for every x in X there is a unique + element y in Y with (x, y) in F. The latter condition can + be formulated as follows: if x F y and x F z + then y = z. In this module, it will not be required + that the domain of F be equal to X for a relation to be + considered a function. Instead of writing + (x, y) in F or x F y, we write + F(x) = y when F is a function, and say that F maps x + onto y, or that the value of F at x is y. Since functions are + relations, the definitions of the last paragraph (domain, range, + and so on) apply to functions as well. If the converse of a + function F is a function F', then F' is called + the <marker id="inverse"></marker><em>inverse</em> of F. + The relative product of two functions F1 and F2 is called + the <marker id="composite"></marker><em>composite</em> of F1 and F2 + if the range of F1 is a subset of the domain of F2. </p> + <p>Sometimes, when the range of a function is more important than + the function itself, the function is called a <em>family</em>. + The domain of a family is called the <em>index set</em>, and the + range is called the <em>indexed set</em>. If x is a family from + I to X, then x[i] denotes the value of the function at index i. + The notation "a family in X" is used for such a family. When the + indexed set is a set of subsets of a set X, then we call x + a <marker id="family"></marker><em>family of subsets</em> of X. If x + is a family of subsets of X, then the union of the range of x is + called the <em>union of the family</em> x. If x is non-empty + (the index set is non-empty), + the <em>intersection of the family</em> x is the intersection of + the range of x. In this + module, the only families that will be considered are families + of subsets of some set X; in the following the word "family" + will be used for such families of subsets.</p> + <p>A <marker id="partition"></marker><em>partition</em> of a set X is a + collection S of non-empty subsets of X whose union is X and + whose elements are pairwise disjoint. A relation in a set is an + <em>equivalence relation</em> if it is reflexive, symmetric and + transitive. If R is an equivalence relation in X, and x is an + element of X, + the <marker id="equivalence_class"></marker><em>equivalence + class</em> of x with respect to R is the set of all those + elements y of X for which x R y holds. The equivalence + classes constitute a partitioning of X. Conversely, if C is a + partition of X, then the relation that holds for any two + elements of X if they belong to the same equivalence class, is + an equivalence relation induced by the partition C. If R is an + equivalence relation in X, then + the <marker id="canonical_map"></marker><em>canonical map</em> is + the function that maps every element of X onto its equivalence class. + </p> + <p>Relations as defined above (as sets of ordered pairs) will from + now on be referred to as <em>binary relations</em>. We call a + set of ordered sets (x[1], ..., x[n]) + an <em>(n-ary) relation</em>, and say that the relation is a subset of + the <marker id="Cartesian_product_tuple"></marker>Cartesian product + X[1] × ... × X[n] where x[i] is + an element of X[i], 1 <= i <= n. + The <marker id="projection"></marker><em>projection</em> of an n-ary + relation R onto coordinate i is the set {x[i] : + (x[1], ..., x[i], ..., x[n]) in R for some + x[j] in X[j], 1 <= j <= n + and not i = j}. The projections of a binary relation R + onto the first and second coordinates are the domain and the + range of R respectively. The relative product of binary + relations can be generalized to n-ary relations as follows. Let + TR be an ordered set (R[1], ..., R[n]) of binary + relations from X to Y[i] and S a binary relation from + (Y[1] × ... × Y[n]) to Z. + The <marker id="tuple_relative_product"></marker><em>relative + product</em> of + TR and S is the binary relation T from X to Z defined so that + x T z if and only if there exists an element y[i] in + Y[i] for each 1 <= i <= n such that + x R[i] y[i] and + (y[1], ..., y[n]) S z. Now let TR be a an + ordered set (R[1], ..., R[n]) of binary relations from + X[i] to Y[i] and S a subset of + X[1] × ... × X[n]. + The <marker id="multiple_relative_product"></marker><em>multiple + relative product</em> of TR and and S is defined to be the + set {z : z = ((x[1], ..., x[n]), (y[1],...,y[n])) + for some (x[1], ..., x[n]) in S and for some + (x[i], y[i]) in R[i], + 1 <= i <= n}. + The <marker id="natural_join"></marker><em>natural join</em> of + an n-ary relation R + and an m-ary relation S on coordinate i and j is defined to be + the set {z : z = (x[1], ..., x[n], + y[1], ..., y[j-1], y[j+1], ..., y[m]) + for some (x[1], ..., x[n]) in R and for some + (y[1], ..., y[m]) in S such that + x[i] = y[j]}.</p> + <p><marker id="sets_definition"></marker>The sets recognized by this + module will be represented by elements of the relation Sets, defined as + the smallest set such that:</p> + <list type="bulleted"> + <item>for every atom T except '_' and for every term X, + (T, X) belongs to Sets (<em>atomic sets</em>); + </item> + <item>(['_'], []) belongs to Sets (the <em>untyped empty set</em>); + </item> + <item>for every tuple T = {T[1], ..., T[n]} and + for every tuple X = {X[1], ..., X[n]}, if + (T[i], X[i]) belongs to Sets for every + 1 <= i <= n then (T, X) belongs + to Sets (<em>ordered sets</em>); + </item> + <item>for every term T, if X is the empty list or a non-empty + sorted list [X[1], ..., X[n]] without duplicates + such that (T, X[i]) belongs to Sets for every + 1 <= i <= n, then ([T], X) + belongs to Sets (<em>typed unordered sets</em>).</item> + </list> + <p>An <marker id="external_set"></marker><em>external set</em> is an + element of the range of Sets. + A <marker id="type"></marker><em>type</em> + is an element of the domain of Sets. If S is an element + (T, X) of Sets, then T is + a <marker id="valid_type"></marker><em>valid type</em> of X, + T is the type of S, and X is the external set + of S. <seealso marker="#from_term">from_term/2</seealso> creates a + set from a type and an Erlang term turned into an external set.</p> + <p>The actual sets represented by Sets are the elements of the + range of the function Set from Sets to Erlang terms and sets of + Erlang terms:</p> + <list type="bulleted"> + <item>Set(T,Term) = Term, where T is an atom;</item> + <item>Set({T[1], ..., T[n]}, {X[1], ..., X[n]}) + = (Set(T[1], X[1]), ..., Set(T[n], X[n]));</item> + <item>Set([T], [X[1], ..., X[n]]) + = {Set(T, X[1]), ..., Set(T, X[n])};</item> + <item>Set([T], []) = {}.</item> + </list> + <p>When there is no risk of confusion, elements of Sets will be + identified with the sets they represent. For instance, if U is + the result of calling <c>union/2</c> with S1 and S2 as + arguments, then U is said to be the union of S1 and S2. A more + precise formulation would be that Set(U) is the union of Set(S1) + and Set(S2).</p> + <p>The types are used to implement the various conditions that + sets need to fulfill. As an example, consider the relative + product of two sets R and S, and recall that the relative + product of R and S is defined if R is a binary relation to Y and + S is a binary relation from Y. The function that implements the relative + product, <seealso marker="#relprod_impl">relative_product/2</seealso>, checks + that the arguments represent binary relations by matching [{A,B}] + against the type of the first argument (Arg1 say), and [{C,D}] + against the type of the second argument (Arg2 say). The fact + that [{A,B}] matches the type of Arg1 is to be interpreted as + Arg1 representing a binary relation from X to Y, where X is + defined as all sets Set(x) for some element x in Sets the type + of which is A, and similarly for Y. In the same way Arg2 is + interpreted as representing a binary relation from W to Z. + Finally it is checked that B matches C, which is sufficient to + ensure that W is equal to Y. The untyped empty set is handled + separately: its type, ['_'], matches the type of any unordered + set.</p> + <p>A few functions of this module (<c>drestriction/3</c>, + <c>family_projection/2</c>, <c>partition/2</c>, + <c>partition_family/2</c>, <c>projection/2</c>, + <c>restriction/3</c>, <c>substitution/2</c>) accept an Erlang + function as a means to modify each element of a given unordered + set. Such a function, called SetFun in the following, can be + specified as a functional object (fun), a tuple + <c>{external, Fun}</c>, or an integer. If SetFun is + specified as a fun, the fun is applied to each element of the + given set and the return value is assumed to be a set. If SetFun + is specified as a tuple <c>{external, Fun}</c>, Fun is applied + to the external set of each element of the given set and the + return value is assumed to be an external set. Selecting the + elements of an unordered set as external sets and assembling a + new unordered set from a list of external sets is in the present + implementation more efficient than modifying each element as a + set. However, this optimization can only be utilized when the + elements of the unordered set are atomic or ordered sets. It + must also be the case that the type of the elements matches some + clause of Fun (the type of the created set is the result of + applying Fun to the type of the given set), and that Fun does + nothing but selecting, duplicating or rearranging parts of the + elements. Specifying a SetFun as an integer I is equivalent to + specifying <c>{external, fun(X) -> element(I, X)}</c>, + but is to be preferred since it makes it possible to handle this + case even more efficiently. Examples of SetFuns:</p> + <pre> +{sofs, union} +fun(S) -> sofs:partition(1, S) end +{external, fun(A) -> A end} +{external, fun({A,_,C}) -> {C,A} end} +{external, fun({_,{_,C}}) -> C end} +{external, fun({_,{_,{_,E}=C}}) -> {E,{E,C}} end} +2</pre> + <p>The order in which a SetFun is applied to the elements of an + unordered set is not specified, and may change in future + versions of sofs.</p> + <p>The execution time of the functions of this module is dominated + by the time it takes to sort lists. When no sorting is needed, + the execution time is in the worst case proportional to the sum + of the sizes of the input arguments and the returned value. A + few functions execute in constant time: <c>from_external</c>, + <c>is_empty_set</c>, <c>is_set</c>, <c>is_sofs_set</c>, + <c>to_external</c>, <c>type</c>.</p> + <p>The functions of this module exit the process with a + <c>badarg</c>, <c>bad_function</c>, or <c>type_mismatch</c> + message when given badly formed arguments or sets the types of + which are not compatible.</p> + <p><em>Types</em></p> + <pre> +anyset() = - an unordered, ordered or atomic set - +binary_relation() = - a binary relation - +bool() = true | false +external_set() = - an external set - +family() = - a family (of subsets) - +function() = - a function - +ordset() = - an ordered set - +relation() = - an n-ary relation - +set() = - an unordered set - +set_of_sets() = - an unordered set of set() - +set_fun() = integer() >= 1 + | {external, fun(external_set()) -> external_set()} + | fun(anyset()) -> anyset() +spec_fun() = {external, fun(external_set()) -> bool()} + | fun(anyset()) -> bool() +type() = - a type - </pre> + </description> + <funcs> + <func> + <name>a_function(Tuples [, Type]) -> Function</name> + <fsummary>Create a function.</fsummary> + <type> + <v>Function = function()</v> + <v>Tuples = [tuple()]</v> + <v>Type = type()</v> + </type> + <desc> + <p>Creates a <seealso marker="#function">function</seealso>. + <c>a_function(F, T)</c> is equivalent to + <c>from_term(F, T)</c>, if the result is a function. If + no <seealso marker="#type">type</seealso> is explicitly + given, <c>[{atom, atom}]</c> is used as type of the + function.</p> + </desc> + </func> + <func> + <name>canonical_relation(SetOfSets) -> BinRel</name> + <fsummary>Return the canonical map.</fsummary> + <type> + <v>BinRel = binary_relation()</v> + <v>SetOfSets = set_of_sets()</v> + </type> + <desc> + <p>Returns the binary relation containing the elements + (E, Set) such that Set belongs to SetOfSets and E + belongs to Set. If SetOfSets is + a <seealso marker="#partition">partition</seealso> of a set X and + R is the equivalence relation in X induced by SetOfSets, then the + returned relation is + the <seealso marker="#canonical_map">canonical map</seealso> from + X onto the equivalence classes with respect to R.</p> + <pre> +1> <input>Ss = sofs:from_term([[a,b],[b,c]]),</input> +<input>CR = sofs:canonical_relation(Ss),</input> +<input>sofs:to_external(CR).</input> +[{a,[a,b]},{b,[a,b]},{b,[b,c]},{c,[b,c]}]</pre> + </desc> + </func> + <func> + <name>composite(Function1, Function2) -> Function3</name> + <fsummary>Return the composite of two functions.</fsummary> + <type> + <v>Function1 = Function2 = Function3 = function()</v> + </type> + <desc> + <p>Returns the <seealso marker="#composite">composite</seealso> of + the functions Function1 and Function2.</p> + <pre> +1> <input>F1 = sofs:a_function([{a,1},{b,2},{c,2}]),</input> +<input>F2 = sofs:a_function([{1,x},{2,y},{3,z}]),</input> +<input>F = sofs:composite(F1, F2),</input> +<input>sofs:to_external(F).</input> +[{a,x},{b,y},{c,y}]</pre> + </desc> + </func> + <func> + <name>constant_function(Set, AnySet) -> Function</name> + <fsummary>Create the function that maps each element of a + set onto another set.</fsummary> + <type> + <v>AnySet = anyset()</v> + <v>Function = function()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Creates the <seealso marker="#function">function</seealso> + that maps each element of the set Set onto AnySet.</p> + <pre> +1> <input>S = sofs:set([a,b]),</input> +<input>E = sofs:from_term(1),</input> +<input>R = sofs:constant_function(S, E),</input> +<input>sofs:to_external(R).</input> +[{a,1},{b,1}]</pre> + </desc> + </func> + <func> + <name>converse(BinRel1) -> BinRel2</name> + <fsummary>Return the converse of a binary relation.</fsummary> + <type> + <v>BinRel1 = BinRel2 = binary_relation()</v> + </type> + <desc> + <p>Returns the <seealso marker="#converse">converse</seealso> + of the binary relation BinRel1.</p> + <pre> +1> <input>R1 = sofs:relation([{1,a},{2,b},{3,a}]),</input> +<input>R2 = sofs:converse(R1),</input> +<input>sofs:to_external(R2).</input> +[{a,1},{a,3},{b,2}]</pre> + </desc> + </func> + <func> + <name>difference(Set1, Set2) -> Set3</name> + <fsummary>Return the difference of two sets.</fsummary> + <type> + <v>Set1 = Set2 = Set3 = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#difference">difference</seealso> of + the sets Set1 and Set2.</p> + </desc> + </func> + <func> + <name>digraph_to_family(Graph [, Type]) -> Family</name> + <fsummary>Create a family from a directed graph.</fsummary> + <type> + <v>Graph = digraph() - see digraph(3) -</v> + <v>Family = family()</v> + <v>Type = type()</v> + </type> + <desc> + <p>Creates a <seealso marker="#family">family</seealso> from + the directed graph Graph. Each vertex a of Graph is + represented by a pair (a, {b[1], ..., b[n]}) + where the b[i]'s are the out-neighbours of a. If no type is + explicitly given, [{atom, [atom]}] is used as type of + the family. It is assumed that Type is + a <seealso marker="#valid_type">valid type</seealso> of the + external set of the family.</p> + <p>If G is a directed graph, it holds that the vertices and + edges of G are the same as the vertices and edges of + <c>family_to_digraph(digraph_to_family(G))</c>.</p> + </desc> + </func> + <func> + <name>domain(BinRel) -> Set</name> + <fsummary>Return the domain of a binary relation.</fsummary> + <type> + <v>BinRel = binary_relation()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#domain">domain</seealso> of + the binary relation BinRel.</p> + <pre> +1> <input>R = sofs:relation([{1,a},{1,b},{2,b},{2,c}]),</input> +<input>S = sofs:domain(R),</input> +<input>sofs:to_external(S).</input> +[1,2]</pre> + </desc> + </func> + <func> + <name>drestriction(BinRel1, Set) -> BinRel2</name> + <fsummary>Return a restriction of a binary relation.</fsummary> + <type> + <v>BinRel1 = BinRel2 = binary_relation()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the difference between the binary relation BinRel1 + and the <seealso marker="#restriction">restriction</seealso> + of BinRel1 to Set.</p> + <pre> +1> <input>R1 = sofs:relation([{1,a},{2,b},{3,c}]),</input> +<input>S = sofs:set([2,4,6]),</input> +<input>R2 = sofs:drestriction(R1, S),</input> +<input>sofs:to_external(R2).</input> +[{1,a},{3,c}]</pre> + <p><c>drestriction(R, S)</c> is equivalent to + <c>difference(R, restriction(R, S))</c>.</p> + </desc> + </func> + <func> + <name>drestriction(SetFun, Set1, Set2) -> Set3</name> + <fsummary>Return a restriction of a relation.</fsummary> + <type> + <v>SetFun = set_fun()</v> + <v>Set1 = Set2 = Set3 = set()</v> + </type> + <desc> + <p>Returns a subset of Set1 containing those elements that do + not yield an element in Set2 as the result of applying + SetFun.</p> + <pre> +1> <input>SetFun = {external, fun({_A,B,C}) -> {B,C} end},</input> +<input>R1 = sofs:relation([{a,aa,1},{b,bb,2},{c,cc,3}]),</input> +<input>R2 = sofs:relation([{bb,2},{cc,3},{dd,4}]),</input> +<input>R3 = sofs:drestriction(SetFun, R1, R2),</input> +<input>sofs:to_external(R3).</input> +[{a,aa,1}]</pre> + <p><c>drestriction(F, S1, S2)</c> is equivalent to + <c>difference(S1, restriction(F, S1, S2))</c>.</p> + </desc> + </func> + <func> + <name>empty_set() -> Set</name> + <fsummary>Return the untyped empty set.</fsummary> + <type> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#sets_definition">untyped empty + set</seealso>. <c>empty_set()</c> is equivalent to + <c>from_term([], ['_'])</c>.</p> + </desc> + </func> + <func> + <name>extension(BinRel1, Set, AnySet) -> BinRel2</name> + <fsummary>Extend the domain of a binary relation.</fsummary> + <type> + <v>AnySet = anyset()</v> + <v>BinRel1 = BinRel2 = binary_relation()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#extension">extension</seealso> of + BinRel1 such that + for each element E in Set that does not belong to the + <seealso marker="#domain">domain</seealso> of BinRel1, + BinRel2 contains the pair (E, AnySet).</p> + <pre> +1> <input>S = sofs:set([b,c]),</input> +<input>A = sofs:empty_set(),</input> +<input>R = sofs:family([{a,[1,2]},{b,[3]}]),</input> +<input>X = sofs:extension(R, S, A),</input> +<input>sofs:to_external(X).</input> +[{a,[1,2]},{b,[3]},{c,[]}]</pre> + </desc> + </func> + <func> + <name>family(Tuples [, Type]) -> Family</name> + <fsummary>Create a family of subsets.</fsummary> + <type> + <v>Family = family()</v> + <v>Tuples = [tuple()]</v> + <v>Type = type()</v> + </type> + <desc> + <p>Creates a <seealso marker="#family">family of subsets</seealso>. + <c>family(F, T)</c> is equivalent to + <c>from_term(F, T)</c>, if the result is a family. If + no <seealso marker="#type">type</seealso> is explicitly + given, <c>[{atom, [atom]}]</c> is used as type of the + family.</p> + </desc> + </func> + <func> + <name>family_difference(Family1, Family2) -> Family3</name> + <fsummary>Return the difference of two families.</fsummary> + <type> + <v>Family1 = Family2 = Family3 = family()</v> + </type> + <desc> + <p>If Family1 and Family2 + are <seealso marker="#family">families</seealso>, then + Family3 is the family + such that the index set is equal to the index set of + Family1, and Family3[i] is the difference between Family1[i] + and Family2[i] if Family2 maps i, Family1[i] otherwise.</p> + <pre> +1> <input>F1 = sofs:family([{a,[1,2]},{b,[3,4]}]),</input> +<input>F2 = sofs:family([{b,[4,5]},{c,[6,7]}]),</input> +<input>F3 = sofs:family_difference(F1, F2),</input> +<input>sofs:to_external(F3).</input> +[{a,[1,2]},{b,[3]}]</pre> + </desc> + </func> + <func> + <name>family_domain(Family1) -> Family2</name> + <fsummary>Return a family of domains.</fsummary> + <type> + <v>Family1 = Family2 = family()</v> + </type> + <desc> + <p>If Family1 is a <seealso marker="#family">family</seealso> + and Family1[i] is a binary relation for every i in the index + set of Family1, then Family2 is the family with the same + index set as Family1 such that Family2[i] is + the <seealso marker="#domain">domain</seealso> of Family1[i].</p> + <pre> +1> <input>FR = sofs:from_term([{a,[{1,a},{2,b},{3,c}]},{b,[]},{c,[{4,d},{5,e}]}]),</input> +<input>F = sofs:family_domain(FR),</input> +<input>sofs:to_external(F).</input> +[{a,[1,2,3]},{b,[]},{c,[4,5]}]</pre> + </desc> + </func> + <func> + <name>family_field(Family1) -> Family2</name> + <fsummary>Return a family of fields.</fsummary> + <type> + <v>Family1 = Family2 = family()</v> + </type> + <desc> + <p>If Family1 is a <seealso marker="#family">family</seealso> + and Family1[i] is a binary relation for every i in the index + set of Family1, then Family2 is the family with the same + index set as Family1 such that Family2[i] is + the <seealso marker="#field">field</seealso> of Family1[i].</p> + <pre> +1> <input>FR = sofs:from_term([{a,[{1,a},{2,b},{3,c}]},{b,[]},{c,[{4,d},{5,e}]}]),</input> +<input>F = sofs:family_field(FR),</input> +<input>sofs:to_external(F).</input> +[{a,[1,2,3,a,b,c]},{b,[]},{c,[4,5,d,e]}]</pre> + <p><c>family_field(Family1)</c> is equivalent to + <c>family_union(family_domain(Family1), family_range(Family1))</c>.</p> + </desc> + </func> + <func> + <name>family_intersection(Family1) -> Family2</name> + <fsummary>Return the intersection of a family + of sets of sets.</fsummary> + <type> + <v>Family1 = Family2 = family()</v> + </type> + <desc> + <p>If Family1 is a <seealso marker="#family">family</seealso> + and Family1[i] is a set of sets for every i in the index set + of Family1, then Family2 is the family with the same index + set as Family1 such that Family2[i] is + the <seealso marker="#intersection_n">intersection</seealso> of + Family1[i].</p> + <p>If Family1[i] is an empty set for some i, then the process + exits with a <c>badarg</c> message.</p> + <pre> +1> <input>F1 = sofs:from_term([{a,[[1,2,3],[2,3,4]]},{b,[[x,y,z],[x,y]]}]),</input> +<input>F2 = sofs:family_intersection(F1),</input> +<input>sofs:to_external(F2).</input> +[{a,[2,3]},{b,[x,y]}]</pre> + </desc> + </func> + <func> + <name>family_intersection(Family1, Family2) -> Family3</name> + <fsummary>Return the intersection of two families.</fsummary> + <type> + <v>Family1 = Family2 = Family3 = family()</v> + </type> + <desc> + <p>If Family1 and Family2 + are <seealso marker="#family">families</seealso>, then Family3 + is the family such that the index set is the intersection of + Family1's and Family2's index sets, and Family3[i] is the + intersection of Family1[i] and Family2[i].</p> + <pre> +1> <input>F1 = sofs:family([{a,[1,2]},{b,[3,4]},{c,[5,6]}]),</input> +<input>F2 = sofs:family([{b,[4,5]},{c,[7,8]},{d,[9,10]}]),</input> +<input>F3 = sofs:family_intersection(F1, F2),</input> +<input>sofs:to_external(F3).</input> +[{b,[4]},{c,[]}]</pre> + </desc> + </func> + <func> + <name>family_projection(SetFun, Family1) -> Family2</name> + <fsummary>Return a family of modified subsets.</fsummary> + <type> + <v>SetFun = set_fun()</v> + <v>Family1 = Family2 = family()</v> + <v>Set = set()</v> + </type> + <desc> + <p>If Family1 is a <seealso marker="#family">family</seealso> + then Family2 is the family with the same index set as + Family1 such that Family2[i] is the result of calling SetFun + with Family1[i] as argument.</p> + <pre> +1> <input>F1 = sofs:from_term([{a,[[1,2],[2,3]]},{b,[[]]}]),</input> +<input>F2 = sofs:family_projection({sofs, union}, F1),</input> +<input>sofs:to_external(F2).</input> +[{a,[1,2,3]},{b,[]}]</pre> + </desc> + </func> + <func> + <name>family_range(Family1) -> Family2</name> + <fsummary>Return a family of ranges.</fsummary> + <type> + <v>Family1 = Family2 = family()</v> + </type> + <desc> + <p>If Family1 is a <seealso marker="#family">family</seealso> + and Family1[i] is a binary relation for every i in the index + set of Family1, then Family2 is the family with the same + index set as Family1 such that Family2[i] is + the <seealso marker="#range">range</seealso> of Family1[i].</p> + <pre> +1> <input>FR = sofs:from_term([{a,[{1,a},{2,b},{3,c}]},{b,[]},{c,[{4,d},{5,e}]}]),</input> +<input>F = sofs:family_range(FR),</input> +<input>sofs:to_external(F).</input> +[{a,[a,b,c]},{b,[]},{c,[d,e]}]</pre> + </desc> + </func> + <func> + <name>family_specification(Fun, Family1) -> Family2</name> + <fsummary>Select a subset of a family using a predicate.</fsummary> + <type> + <v>Fun = spec_fun()</v> + <v>Family1 = Family2 = family()</v> + </type> + <desc> + <p>If Family1 is a <seealso marker="#family">family</seealso>, + then Family2 is + the <seealso marker="#restriction">restriction</seealso> of + Family1 to those elements i of the + index set for which Fun applied to Family1[i] returns + <c>true</c>. If Fun is a tuple <c>{external, Fun2}</c>, + Fun2 is applied to + the <seealso marker="#external_set">external set</seealso> of + Family1[i], otherwise Fun is applied to Family1[i].</p> + <pre> +1> <input>F1 = sofs:family([{a,[1,2,3]},{b,[1,2]},{c,[1]}]),</input> +<input>SpecFun = fun(S) -> sofs:no_elements(S) =:= 2 end,</input> +<input>F2 = sofs:family_specification(SpecFun, F1),</input> +<input>sofs:to_external(F2).</input> +[{b,[1,2]}]</pre> + </desc> + </func> + <func> + <name>family_to_digraph(Family [, GraphType]) -> Graph</name> + <fsummary>Create a directed graph from a family.</fsummary> + <type> + <v>Graph = digraph()</v> + <v>Family = family()</v> + <v>GraphType = - see digraph(3) -</v> + </type> + <desc> + <p>Creates a directed graph from + the <seealso marker="#family">family</seealso> Family. For each + pair (a, {b[1], ..., b[n]}) of Family, the vertex + a as well the edges (a, b[i]) for + 1 <= i <= n are added to a newly + created directed graph.</p> + <p>If no graph type is given, <c>digraph:new/1</c> is used for + creating the directed graph, otherwise the GraphType + argument is passed on as second argument to + <c>digraph:new/2</c>.</p> + <p>It F is a family, it holds that F is a subset of + <c>digraph_to_family(family_to_digraph(F), type(F))</c>. + Equality holds if <c>union_of_family(F)</c> is a subset of + <c>domain(F)</c>.</p> + <p>Creating a cycle in an acyclic graph exits the process with + a <c>cyclic</c> message.</p> + </desc> + </func> + <func> + <name>family_to_relation(Family) -> BinRel</name> + <fsummary>Create a binary relation from a family.</fsummary> + <type> + <v>Family = family()</v> + <v>BinRel = binary_relation()</v> + </type> + <desc> + <p>If Family is a <seealso marker="#family">family</seealso>, + then BinRel is the binary relation containing all pairs + (i, x) such that i belongs to the index set of Family + and x belongs to Family[i].</p> + <pre> +1> <input>F = sofs:family([{a,[]}, {b,[1]}, {c,[2,3]}]),</input> +<input>R = sofs:family_to_relation(F),</input> +<input>sofs:to_external(R).</input> +[{b,1},{c,2},{c,3}]</pre> + </desc> + </func> + <func> + <name>family_union(Family1) -> Family2</name> + <fsummary>Return the union of a family of sets of sets.</fsummary> + <type> + <v>Family1 = Family2 = family()</v> + </type> + <desc> + <p>If Family1 is a <seealso marker="#family">family</seealso> + and Family1[i] is a set of sets for each i in the index set + of Family1, then Family2 is the family with the same index + set as Family1 such that Family2[i] is + the <seealso marker="#union_n">union</seealso> of Family1[i].</p> + <pre> +1> <input>F1 = sofs:from_term([{a,[[1,2],[2,3]]},{b,[[]]}]),</input> +<input>F2 = sofs:family_union(F1),</input> +<input>sofs:to_external(F2).</input> +[{a,[1,2,3]},{b,[]}]</pre> + <p><c>family_union(F)</c> is equivalent to + <c>family_projection({sofs,union}, F)</c>.</p> + </desc> + </func> + <func> + <name>family_union(Family1, Family2) -> Family3</name> + <fsummary>Return the union of two families.</fsummary> + <type> + <v>Family1 = Family2 = Family3 = family()</v> + </type> + <desc> + <p>If Family1 and Family2 + are <seealso marker="#family">families</seealso>, then Family3 + is the family such that the index set is the union of Family1's + and Family2's index sets, and Family3[i] is the union of + Family1[i] and Family2[i] if both maps i, Family1[i] or + Family2[i] otherwise.</p> + <pre> +1> <input>F1 = sofs:family([{a,[1,2]},{b,[3,4]},{c,[5,6]}]),</input> +<input>F2 = sofs:family([{b,[4,5]},{c,[7,8]},{d,[9,10]}]),</input> +<input>F3 = sofs:family_union(F1, F2),</input> +<input>sofs:to_external(F3).</input> +[{a,[1,2]},{b,[3,4,5]},{c,[5,6,7,8]},{d,[9,10]}]</pre> + </desc> + </func> + <func> + <name>field(BinRel) -> Set</name> + <fsummary>Return the field of a binary relation.</fsummary> + <type> + <v>BinRel = binary_relation()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#field">field</seealso> of the + binary relation BinRel.</p> + <pre> +1> <input>R = sofs:relation([{1,a},{1,b},{2,b},{2,c}]),</input> +<input>S = sofs:field(R),</input> +<input>sofs:to_external(S).</input> +[1,2,a,b,c]</pre> + <p><c>field(R)</c> is equivalent + to <c>union(domain(R), range(R))</c>.</p> + </desc> + </func> + <func> + <name>from_external(ExternalSet, Type) -> AnySet</name> + <fsummary>Create a set.</fsummary> + <type> + <v>ExternalSet = external_set()</v> + <v>AnySet = anyset()</v> + <v>Type = type()</v> + </type> + <desc> + <p>Creates a set from the <seealso marker="#external_set">external + set</seealso> ExternalSet + and the <seealso marker="#type">type</seealso> Type. It is + assumed that Type is a <seealso marker="#valid_type">valid + type</seealso> of ExternalSet.</p> + </desc> + </func> + <func> + <name>from_sets(ListOfSets) -> Set</name> + <fsummary>Create a set out of a list of sets.</fsummary> + <type> + <v>Set = set()</v> + <v>ListOfSets = [anyset()]</v> + </type> + <desc> + <p>Returns the <seealso marker="#sets_definition">unordered + set</seealso> containing the sets of the list ListOfSets.</p> + <pre> +1> <input>S1 = sofs:relation([{a,1},{b,2}]),</input> +<input>S2 = sofs:relation([{x,3},{y,4}]),</input> +<input>S = sofs:from_sets([S1,S2]),</input> +<input>sofs:to_external(S).</input> +[[{a,1},{b,2}],[{x,3},{y,4}]]</pre> + </desc> + </func> + <func> + <name>from_sets(TupleOfSets) -> Ordset</name> + <fsummary>Create an ordered set out of a tuple of sets.</fsummary> + <type> + <v>Ordset = ordset()</v> + <v>TupleOfSets = tuple-of(anyset())</v> + </type> + <desc> + <p>Returns the <seealso marker="#sets_definition">ordered + set</seealso> containing the sets of the non-empty tuple + TupleOfSets.</p> + </desc> + </func> + <func> + <name>from_term(Term [, Type]) -> AnySet</name> + <fsummary>Create a set.</fsummary> + <type> + <v>AnySet = anyset()</v> + <v>Term = term()</v> + <v>Type = type()</v> + </type> + <desc> + <p><marker id="from_term"></marker>Creates an element + of <seealso marker="#sets_definition">Sets</seealso> by + traversing the term Term, sorting lists, removing duplicates and + deriving or verifying a <seealso marker="#valid_type">valid + type</seealso> for the so obtained external set. An + explicitly given <seealso marker="#type">type</seealso> Type + can be used to limit the depth of the traversal; an atomic + type stops the traversal, as demonstrated by this example + where "foo" and {"foo"} are left unmodified:</p> + <pre> +1> <input>S = sofs:from_term([{{"foo"},[1,1]},{"foo",[2,2]}], [{atom,[atom]}]),</input> +<input>sofs:to_external(S).</input> +[{{"foo"},[1]},{"foo",[2]}]</pre> + <p><c>from_term</c> can be used for creating atomic or ordered + sets. The only purpose of such a set is that of later + building unordered sets since all functions in this module + that <em>do</em> anything operate on unordered sets. + Creating unordered sets from a collection of ordered sets + may be the way to go if the ordered sets are big and one + does not want to waste heap by rebuilding the elements of + the unordered set. An example showing that a set can be + built "layer by layer":</p> + <pre> +1> <input>A = sofs:from_term(a),</input> +<input>S = sofs:set([1,2,3]),</input> +<input>P1 = sofs:from_sets({A,S}),</input> +<input>P2 = sofs:from_term({b,[6,5,4]}),</input> +<input>Ss = sofs:from_sets([P1,P2]),</input> +<input>sofs:to_external(Ss).</input> +[{a,[1,2,3]},{b,[4,5,6]}]</pre> + <p>Other functions that create sets are <c>from_external/2</c> + and <c>from_sets/1</c>. Special cases of <c>from_term/2</c> + are <c>a_function/1,2</c>, <c>empty_set/0</c>, + <c>family/1,2</c>, <c>relation/1,2</c>, and <c>set/1,2</c>.</p> + </desc> + </func> + <func> + <name>image(BinRel, Set1) -> Set2</name> + <fsummary>Return the image of a set under a binary relation.</fsummary> + <type> + <v>BinRel = binary_relation()</v> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#image">image</seealso> of the + set Set1 under the binary relation BinRel.</p> + <pre> +1> <input>R = sofs:relation([{1,a},{2,b},{2,c},{3,d}]),</input> +<input>S1 = sofs:set([1,2]),</input> +<input>S2 = sofs:image(R, S1),</input> +<input>sofs:to_external(S2).</input> +[a,b,c]</pre> + </desc> + </func> + <func> + <name>intersection(SetOfSets) -> Set</name> + <fsummary>Return the intersection of a set of sets.</fsummary> + <type> + <v>Set = set()</v> + <v>SetOfSets = set_of_sets()</v> + </type> + <desc> + <p>Returns + the <seealso marker="#intersection_n">intersection</seealso> of + the set of sets SetOfSets.</p> + <p>Intersecting an empty set of sets exits the process with a + <c>badarg</c> message.</p> + </desc> + </func> + <func> + <name>intersection(Set1, Set2) -> Set3</name> + <fsummary>Return the intersection of two sets.</fsummary> + <type> + <v>Set1 = Set2 = Set3 = set()</v> + </type> + <desc> + <p>Returns + the <seealso marker="#intersection">intersection</seealso> of + Set1 and Set2.</p> + </desc> + </func> + <func> + <name>intersection_of_family(Family) -> Set</name> + <fsummary>Return the intersection of a family.</fsummary> + <type> + <v>Family = family()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the intersection of + the <seealso marker="#family">family</seealso> Family.</p> + <p>Intersecting an empty family exits the process with a + <c>badarg</c> message.</p> + <pre> +1> <input>F = sofs:family([{a,[0,2,4]},{b,[0,1,2]},{c,[2,3]}]),</input> +<input>S = sofs:intersection_of_family(F),</input> +<input>sofs:to_external(S).</input> +[2]</pre> + </desc> + </func> + <func> + <name>inverse(Function1) -> Function2</name> + <fsummary>Return the inverse of a function.</fsummary> + <type> + <v>Function1 = Function2 = function()</v> + </type> + <desc> + <p>Returns the <seealso marker="#inverse">inverse</seealso> + of the function Function1.</p> + <pre> +1> <input>R1 = sofs:relation([{1,a},{2,b},{3,c}]),</input> +<input>R2 = sofs:inverse(R1),</input> +<input>sofs:to_external(R2).</input> +[{a,1},{b,2},{c,3}]</pre> + </desc> + </func> + <func> + <name>inverse_image(BinRel, Set1) -> Set2</name> + <fsummary>Return the inverse image of a set under + a binary relation.</fsummary> + <type> + <v>BinRel = binary_relation()</v> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#inverse_image">inverse + image</seealso> of Set1 under the binary relation BinRel.</p> + <pre> +1> <input>R = sofs:relation([{1,a},{2,b},{2,c},{3,d}]),</input> +<input>S1 = sofs:set([c,d,e]),</input> +<input>S2 = sofs:inverse_image(R, S1),</input> +<input>sofs:to_external(S2).</input> +[2,3]</pre> + </desc> + </func> + <func> + <name>is_a_function(BinRel) -> Bool</name> + <fsummary>Test for a function.</fsummary> + <type> + <v>Bool = bool()</v> + <v>BinRel = binary_relation()</v> + </type> + <desc> + <p>Returns <c>true</c> if the binary relation BinRel is a + <seealso marker="#function">function</seealso> or the + untyped empty set, <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>is_disjoint(Set1, Set2) -> Bool</name> + <fsummary>Test for disjoint sets.</fsummary> + <type> + <v>Bool = bool()</v> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns <c>true</c> if Set1 and Set2 + are <seealso marker="#disjoint">disjoint</seealso>, <c>false</c> + otherwise.</p> + </desc> + </func> + <func> + <name>is_empty_set(AnySet) -> Bool</name> + <fsummary>Test for an empty set.</fsummary> + <type> + <v>AnySet = anyset()</v> + <v>Bool = bool()</v> + </type> + <desc> + <p>Returns <c>true</c> if Set is an empty unordered set, + <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>is_equal(AnySet1, AnySet2) -> Bool</name> + <fsummary>Test two sets for equality.</fsummary> + <type> + <v>AnySet1 = AnySet2 = anyset()</v> + <v>Bool = bool()</v> + </type> + <desc> + <p>Returns <c>true</c> if the AnySet1 and AnySet2 + are <seealso marker="#equal">equal</seealso>, <c>false</c> + otherwise.</p> + </desc> + </func> + <func> + <name>is_set(AnySet) -> Bool</name> + <fsummary>Test for an unordered set.</fsummary> + <type> + <v>AnySet = anyset()</v> + <v>Bool = bool()</v> + </type> + <desc> + <p>Returns <c>true</c> if AnySet is + an <seealso marker="#sets_definition">unordered set</seealso>, and + <c>false</c> if AnySet is an ordered set or an atomic set.</p> + </desc> + </func> + <func> + <name>is_sofs_set(Term) -> Bool</name> + <fsummary>Test for an unordered set.</fsummary> + <type> + <v>Bool = bool()</v> + <v>Term = term()</v> + </type> + <desc> + <p>Returns <c>true</c> if Term is + an <seealso marker="#sets_definition">unordered set</seealso>, an + ordered set or an atomic set, <c>false</c> otherwise.</p> + </desc> + </func> + <func> + <name>is_subset(Set1, Set2) -> Bool</name> + <fsummary>Test two sets for subset.</fsummary> + <type> + <v>Bool = bool()</v> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns <c>true</c> if Set1 is + a <seealso marker="#subset">subset</seealso> of Set2, <c>false</c> + otherwise.</p> + </desc> + </func> + <func> + <name>is_type(Term) -> Bool</name> + <fsummary>Test for a type.</fsummary> + <type> + <v>Bool = bool()</v> + <v>Term = term()</v> + </type> + <desc> + <p>Returns <c>true</c> if the term Term is + a <seealso marker="#type">type</seealso>.</p> + </desc> + </func> + <func> + <name>join(Relation1, I, Relation2, J) -> Relation3</name> + <fsummary>Return the join of two relations.</fsummary> + <type> + <v>Relation1 = Relation2 = Relation3 = relation()</v> + <v>I = J = integer() > 0</v> + </type> + <desc> + <p>Returns the <seealso marker="#natural_join">natural + join</seealso> of the relations Relation1 and Relation2 on + coordinates I and J.</p> + <pre> +1> <input>R1 = sofs:relation([{a,x,1},{b,y,2}]),</input> +<input>R2 = sofs:relation([{1,f,g},{1,h,i},{2,3,4}]),</input> +<input>J = sofs:join(R1, 3, R2, 1),</input> +<input>sofs:to_external(J).</input> +[{a,x,1,f,g},{a,x,1,h,i},{b,y,2,3,4}]</pre> + </desc> + </func> + <func> + <name>multiple_relative_product(TupleOfBinRels, BinRel1) -> BinRel2</name> + <fsummary>Return the multiple relative product of a tuple of binary + relations and a relation.</fsummary> + <type> + <v>TupleOfBinRels = tuple-of(BinRel)</v> + <v>BinRel = BinRel1 = BinRel2 = binary_relation()</v> + </type> + <desc> + <p>If TupleOfBinRels is a non-empty tuple + {R[1], ..., R[n]} of binary relations and BinRel1 + is a binary relation, then BinRel2 is + the <seealso marker="#multiple_relative_product">multiple relative + product</seealso> of the ordered set + (R[i], ..., R[n]) and BinRel1.</p> + <pre> +1> <input>Ri = sofs:relation([{a,1},{b,2},{c,3}]),</input> +<input>R = sofs:relation([{a,b},{b,c},{c,a}]),</input> +<input>MP = sofs:multiple_relative_product({Ri, Ri}, R),</input> +<input>sofs:to_external(sofs:range(MP)).</input> +[{1,2},{2,3},{3,1}]</pre> + </desc> + </func> + <func> + <name>no_elements(ASet) -> NoElements</name> + <fsummary>Return the number of elements of a set.</fsummary> + <type> + <v>ASet = set() | ordset()</v> + <v>NoElements = integer() >= 0 </v> + </type> + <desc> + <p>Returns the number of elements of the ordered or unordered + set ASet.</p> + </desc> + </func> + <func> + <name>partition(SetOfSets) -> Partition</name> + <fsummary>Return the coarsest partition given a set of sets.</fsummary> + <type> + <v>SetOfSets = set_of_sets()</v> + <v>Partition = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#partition">partition</seealso> of + the union of the set of sets SetOfSets such that two + elements are considered equal if they belong to the same + elements of SetOfSets.</p> + <pre> +1> <input>Sets1 = sofs:from_term([[a,b,c],[d,e,f],[g,h,i]]),</input> +<input>Sets2 = sofs:from_term([[b,c,d],[e,f,g],[h,i,j]]),</input> +<input>P = sofs:partition(sofs:union(Sets1, Sets2)),</input> +<input>sofs:to_external(P).</input> +[[a],[b,c],[d],[e,f],[g],[h,i],[j]]</pre> + </desc> + </func> + <func> + <name>partition(SetFun, Set) -> Partition</name> + <fsummary>Return a partition of a set.</fsummary> + <type> + <v>SetFun = set_fun()</v> + <v>Partition = set()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#partition">partition</seealso> of + Set such that two elements are considered equal if the + results of applying SetFun are equal.</p> + <pre> +1> <input>Ss = sofs:from_term([[a],[b],[c,d],[e,f]]),</input> +<input>SetFun = fun(S) -> sofs:from_term(sofs:no_elements(S)) end,</input> +<input>P = sofs:partition(SetFun, Ss),</input> +<input>sofs:to_external(P).</input> +[[[a],[b]],[[c,d],[e,f]]]</pre> + </desc> + </func> + <func> + <name>partition(SetFun, Set1, Set2) -> {Set3, Set4}</name> + <fsummary>Return a partition of a set.</fsummary> + <type> + <v>SetFun = set_fun()</v> + <v>Set1 = Set2 = Set3 = Set4 = set()</v> + </type> + <desc> + <p>Returns a pair of sets that, regarded as constituting a + set, forms a <seealso marker="#partition">partition</seealso> of + Set1. If the + result of applying SetFun to an element of Set1 yields an + element in Set2, the element belongs to Set3, otherwise the + element belongs to Set4.</p> + <pre> +1> <input>R1 = sofs:relation([{1,a},{2,b},{3,c}]),</input> +<input>S = sofs:set([2,4,6]),</input> +<input>{R2,R3} = sofs:partition(1, R1, S),</input> +<input>{sofs:to_external(R2),sofs:to_external(R3)}.</input> +{[{2,b}],[{1,a},{3,c}]}</pre> + <p><c>partition(F, S1, S2)</c> is equivalent to + <c>{restriction(F, S1, S2), + drestriction(F, S1, S2)}</c>.</p> + </desc> + </func> + <func> + <name>partition_family(SetFun, Set) -> Family</name> + <fsummary>Return a family indexing a partition.</fsummary> + <type> + <v>Family = family()</v> + <v>SetFun = set_fun()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#family">family</seealso> + Family where the indexed set is + a <seealso marker="#partition">partition</seealso> of Set + such that two elements are considered equal if the results + of applying SetFun are the same value i. This i is the index + that Family maps onto + the <seealso marker="#equivalence_class">equivalence + class</seealso>.</p> + <pre> +1> <input>S = sofs:relation([{a,a,a,a},{a,a,b,b},{a,b,b,b}]),</input> +<input>SetFun = {external, fun({A,_,C,_}) -> {A,C} end},</input> +<input>F = sofs:partition_family(SetFun, S),</input> +<input>sofs:to_external(F).</input> +[{{a,a},[{a,a,a,a}]},{{a,b},[{a,a,b,b},{a,b,b,b}]}]</pre> + </desc> + </func> + <func> + <name>product(TupleOfSets) -> Relation</name> + <fsummary>Return the Cartesian product of a tuple of sets.</fsummary> + <type> + <v>Relation = relation()</v> + <v>TupleOfSets = tuple-of(set())</v> + </type> + <desc> + <p>Returns the <seealso marker="#Cartesian_product_tuple">Cartesian + product</seealso> of the non-empty tuple of sets + TupleOfSets. If (x[1], ..., x[n]) is an element of + the n-ary relation Relation, then x[i] is drawn from element + i of TupleOfSets.</p> + <pre> +1> <input>S1 = sofs:set([a,b]),</input> +<input>S2 = sofs:set([1,2]),</input> +<input>S3 = sofs:set([x,y]),</input> +<input>P3 = sofs:product({S1,S2,S3}),</input> +<input>sofs:to_external(P3).</input> +[{a,1,x},{a,1,y},{a,2,x},{a,2,y},{b,1,x},{b,1,y},{b,2,x},{b,2,y}]</pre> + </desc> + </func> + <func> + <name>product(Set1, Set2) -> BinRel</name> + <fsummary>Return the Cartesian product of two sets.</fsummary> + <type> + <v>BinRel = binary_relation()</v> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#Cartesian_product">Cartesian + product</seealso> of Set1 and Set2.</p> + <pre> +1> <input>S1 = sofs:set([1,2]),</input> +<input>S2 = sofs:set([a,b]),</input> +<input>R = sofs:product(S1, S2),</input> +<input>sofs:to_external(R).</input> +[{1,a},{1,b},{2,a},{2,b}]</pre> + <p><c>product(S1, S2)</c> is equivalent to + <c>product({S1, S2})</c>.</p> + </desc> + </func> + <func> + <name>projection(SetFun, Set1) -> Set2</name> + <fsummary>Return a set of substituted elements.</fsummary> + <type> + <v>SetFun = set_fun()</v> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns the set created by substituting each element of + Set1 by the result of applying SetFun to the element.</p> + <p>If SetFun is a number i >= 1 and Set1 is a + relation, then the returned set is + the <seealso marker="#projection">projection</seealso> of Set1 + onto coordinate i.</p> + <pre> +1> <input>S1 = sofs:from_term([{1,a},{2,b},{3,a}]),</input> +<input>S2 = sofs:projection(2, S1),</input> +<input>sofs:to_external(S2).</input> +[a,b]</pre> + </desc> + </func> + <func> + <name>range(BinRel) -> Set</name> + <fsummary>Return the range of a binary relation.</fsummary> + <type> + <v>BinRel = binary_relation()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#range">range</seealso> of the + binary relation BinRel.</p> + <pre> +1> <input>R = sofs:relation([{1,a},{1,b},{2,b},{2,c}]),</input> +<input>S = sofs:range(R),</input> +<input>sofs:to_external(S).</input> +[a,b,c]</pre> + </desc> + </func> + <func> + <name>relation(Tuples [, Type]) -> Relation</name> + <fsummary>Create a relation.</fsummary> + <type> + <v>N = integer()</v> + <v>Type = N | type()</v> + <v>Relation = relation()</v> + <v>Tuples = [tuple()]</v> + </type> + <desc> + <p>Creates a <seealso marker="#relation">relation</seealso>. + <c>relation(R, T)</c> is equivalent to + <c>from_term(R, T)</c>, if T is + a <seealso marker="#type">type</seealso> and the result is a + relation. If Type is an integer N, then + <c>[{atom, ..., atom}])</c>, where the size of the + tuple is N, is used as type of the relation. If no type is + explicitly given, the size of the first tuple of Tuples is + used if there is such a tuple. <c>relation([])</c> is + equivalent to <c>relation([], 2)</c>.</p> + </desc> + </func> + <func> + <name>relation_to_family(BinRel) -> Family</name> + <fsummary>Create a family from a binary relation.</fsummary> + <type> + <v>Family = family()</v> + <v>BinRel = binary_relation()</v> + </type> + <desc> + <p>Returns the <seealso marker="#family">family</seealso> + Family such that the index set is equal to + the <seealso marker="#domain">domain</seealso> of the binary + relation BinRel, and Family[i] is + the <seealso marker="#image">image</seealso> of the set of i + under BinRel.</p> + <pre> +1> <input>R = sofs:relation([{b,1},{c,2},{c,3}]),</input> +<input>F = sofs:relation_to_family(R),</input> +<input>sofs:to_external(F).</input> +[{b,[1]},{c,[2,3]}]</pre> + </desc> + </func> + <func> + <name>relative_product(TupleOfBinRels [, BinRel1]) -> BinRel2</name> + <fsummary>Return the relative product of a tuple of binary relations + and a binary relation.</fsummary> + <type> + <v>TupleOfBinRels = tuple-of(BinRel)</v> + <v>BinRel = BinRel1 = BinRel2 = binary_relation()</v> + </type> + <desc> + <p>If TupleOfBinRels is a non-empty tuple + {R[1], ..., R[n]} of binary relations and BinRel1 + is a binary relation, then BinRel2 is + the <seealso marker="#tuple_relative_product">relative + product</seealso> of the ordered set (R[i], ..., R[n]) + and BinRel1.</p> + <p>If BinRel1 is omitted, the relation of equality between the + elements of + the <seealso marker="#Cartesian_product_tuple">Cartesian + product</seealso> of the ranges of R[i], + range R[1] × ... × range R[n], + is used instead (intuitively, nothing is "lost").</p> + <pre> +1> <input>TR = sofs:relation([{1,a},{1,aa},{2,b}]),</input> +<input>R1 = sofs:relation([{1,u},{2,v},{3,c}]),</input> +<input>R2 = sofs:relative_product({TR, R1}),</input> +<input>sofs:to_external(R2).</input> +[{1,{a,u}},{1,{aa,u}},{2,{b,v}}]</pre> + <p>Note that <c>relative_product({R1}, R2)</c> is + different from <c>relative_product(R1, R2)</c>; the + tuple of one element is not identified with the element + itself.</p> + </desc> + </func> + <func> + <name>relative_product(BinRel1, BinRel2) -> BinRel3</name> + <fsummary>Return the relative product of + two binary relations.</fsummary> + <type> + <v>BinRel1 = BinRel2 = BinRel3 = binary_relation()</v> + </type> + <desc> + <p><marker id="relprod_impl"></marker>Returns + the <seealso marker="#relative_product">relative + product</seealso> of the binary relations BinRel1 and BinRel2.</p> + </desc> + </func> + <func> + <name>relative_product1(BinRel1, BinRel2) -> BinRel3</name> + <fsummary>Return the relative_product of + two binary relations.</fsummary> + <type> + <v>BinRel1 = BinRel2 = BinRel3 = binary_relation()</v> + </type> + <desc> + <p>Returns the <seealso marker="#relative_product">relative + product</seealso> of + the <seealso marker="#converse">converse</seealso> of the + binary relation BinRel1 and the binary relation BinRel2.</p> + <pre> +1> <input>R1 = sofs:relation([{1,a},{1,aa},{2,b}]),</input> +<input>R2 = sofs:relation([{1,u},{2,v},{3,c}]),</input> +<input>R3 = sofs:relative_product1(R1, R2),</input> +<input>sofs:to_external(R3).</input> +[{a,u},{aa,u},{b,v}]</pre> + <p><c>relative_product1(R1, R2)</c> is equivalent to + <c>relative_product(converse(R1), R2)</c>.</p> + </desc> + </func> + <func> + <name>restriction(BinRel1, Set) -> BinRel2</name> + <fsummary>Return a restriction of a binary relation.</fsummary> + <type> + <v>BinRel1 = BinRel2 = binary_relation()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#restriction">restriction</seealso> of + the binary relation BinRel1 to Set.</p> + <pre> +1> <input>R1 = sofs:relation([{1,a},{2,b},{3,c}]),</input> +<input>S = sofs:set([1,2,4]),</input> +<input>R2 = sofs:restriction(R1, S),</input> +<input>sofs:to_external(R2).</input> +[{1,a},{2,b}]</pre> + </desc> + </func> + <func> + <name>restriction(SetFun, Set1, Set2) -> Set3</name> + <fsummary>Return a restriction of a set.</fsummary> + <type> + <v>SetFun = set_fun()</v> + <v>Set1 = Set2 = Set3 = set()</v> + </type> + <desc> + <p>Returns a subset of Set1 containing those elements that + yield an element in Set2 as the result of applying SetFun.</p> + <pre> +1> <input>S1 = sofs:relation([{1,a},{2,b},{3,c}]),</input> +<input>S2 = sofs:set([b,c,d]),</input> +<input>S3 = sofs:restriction(2, S1, S2),</input> +<input>sofs:to_external(S3).</input> +[{2,b},{3,c}]</pre> + </desc> + </func> + <func> + <name>set(Terms [, Type]) -> Set</name> + <fsummary>Create a set of atoms or any type of sets.</fsummary> + <type> + <v>Set = set()</v> + <v>Terms = [term()]</v> + <v>Type = type()</v> + </type> + <desc> + <p>Creates an <seealso marker="#sets_definition">unordered + set</seealso>. <c>set(L, T)</c> is equivalent to + <c>from_term(L, T)</c>, if the result is an unordered + set. If no <seealso marker="#type">type</seealso> is + explicitly given, <c>[atom]</c> is used as type of the set.</p> + </desc> + </func> + <func> + <name>specification(Fun, Set1) -> Set2</name> + <fsummary>Select a subset using a predicate.</fsummary> + <type> + <v>Fun = spec_fun()</v> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns the set containing every element of Set1 for which + Fun returns <c>true</c>. If Fun is a tuple + <c>{external, Fun2}</c>, Fun2 is applied to the + <seealso marker="#external_set">external set</seealso> of + each element, otherwise Fun is applied to each element.</p> + <pre> +1> <input>R1 = sofs:relation([{a,1},{b,2}]),</input> +<input>R2 = sofs:relation([{x,1},{x,2},{y,3}]),</input> +<input>S1 = sofs:from_sets([R1,R2]),</input> +<input>S2 = sofs:specification({sofs,is_a_function}, S1),</input> +<input>sofs:to_external(S2).</input> +[[{a,1},{b,2}]]</pre> + </desc> + </func> + <func> + <name>strict_relation(BinRel1) -> BinRel2</name> + <fsummary>Return the strict relation corresponding to + a given relation.</fsummary> + <type> + <v>BinRel1 = BinRel2 = binary_relation()</v> + </type> + <desc> + <p>Returns the <seealso marker="#strict_relation">strict + relation</seealso> corresponding to the binary relation BinRel1.</p> + <pre> +1> <input>R1 = sofs:relation([{1,1},{1,2},{2,1},{2,2}]),</input> +<input>R2 = sofs:strict_relation(R1),</input> +<input>sofs:to_external(R2).</input> +[{1,2},{2,1}]</pre> + </desc> + </func> + <func> + <name>substitution(SetFun, Set1) -> Set2</name> + <fsummary>Return a function with a given set as domain.</fsummary> + <type> + <v>SetFun = set_fun()</v> + <v>Set1 = Set2 = set()</v> + </type> + <desc> + <p>Returns a function, the domain of which is Set1. The value + of an element of the domain is the result of applying SetFun + to the element.</p> + <pre> +1> <input>L = [{a,1},{b,2}].</input> +[{a,1},{b,2}] +2> <input>sofs:to_external(sofs:projection(1,sofs:relation(L))).</input> +[a,b] +3> <input>sofs:to_external(sofs:substitution(1,sofs:relation(L))).</input> +[{{a,1},a},{{b,2},b}] +4> <input>SetFun = {external, fun({A,_}=E) -> {E,A} end},</input> +<input>sofs:to_external(sofs:projection(SetFun,sofs:relation(L))).</input> +[{{a,1},a},{{b,2},b}]</pre> + <p>The relation of equality between the elements of {a,b,c}:</p> + <pre> +1> <input>I = sofs:substitution(fun(A) -> A end, sofs:set([a,b,c])),</input> +<input>sofs:to_external(I).</input> +[{a,a},{b,b},{c,c}]</pre> + <p>Let SetOfSets be a set of sets and BinRel a binary + relation. The function that maps each element Set of + SetOfSets onto the <seealso marker="#image">image</seealso> + of Set under BinRel is returned by this function:</p> + <pre> +images(SetOfSets, BinRel) -> + Fun = fun(Set) -> sofs:image(BinRel, Set) end, + sofs:substitution(Fun, SetOfSets).</pre> + <p>Here might be the place to reveal something that was more + or less stated before, namely that external unordered sets + are represented as sorted lists. As a consequence, creating + the image of a set under a relation R may traverse all + elements of R (to that comes the sorting of results, the + image). In <c>images/2</c>, BinRel will be traversed once + for each element of SetOfSets, which may take too long. The + following efficient function could be used instead under the + assumption that the image of each element of SetOfSets under + BinRel is non-empty:</p> + <pre> +images2(SetOfSets, BinRel) -> + CR = sofs:canonical_relation(SetOfSets), + R = sofs:relative_product1(CR, BinRel), + sofs:relation_to_family(R).</pre> + </desc> + </func> + <func> + <name>symdiff(Set1, Set2) -> Set3</name> + <fsummary>Return the symmetric difference of two sets.</fsummary> + <type> + <v>Set1 = Set2 = Set3 = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#symmetric_difference">symmetric + difference</seealso> (or the Boolean sum) of Set1 and Set2.</p> + <pre> +1> <input>S1 = sofs:set([1,2,3]),</input> +<input>S2 = sofs:set([2,3,4]),</input> +<input>P = sofs:symdiff(S1, S2),</input> +<input>sofs:to_external(P).</input> +[1,4]</pre> + </desc> + </func> + <func> + <name>symmetric_partition(Set1, Set2) -> {Set3, Set4, Set5}</name> + <fsummary>Return a partition of two sets.</fsummary> + <type> + <v>Set1 = Set2 = Set3 = Set4 = Set5 = set()</v> + </type> + <desc> + <p>Returns a triple of sets: Set3 contains the elements + of Set1 that do not belong to Set2; Set4 contains the + elements of Set1 that belong to Set2; Set5 contains the + elements of Set2 that do not belong to Set1.</p> + </desc> + </func> + <func> + <name>to_external(AnySet) -> ExternalSet</name> + <fsummary>Return the elements of a set.</fsummary> + <type> + <v>ExternalSet = external_set()</v> + <v>AnySet = anyset()</v> + </type> + <desc> + <p>Returns the <seealso marker="#external_set">external + set</seealso> of an atomic, ordered or unordered set.</p> + </desc> + </func> + <func> + <name>to_sets(ASet) -> Sets</name> + <fsummary>Return a list or a tuple of the elements of set.</fsummary> + <type> + <v>ASet = set() | ordset()</v> + <v>Sets = tuple_of(AnySet) | [AnySet]</v> + </type> + <desc> + <p>Returns the elements of the ordered set ASet as a tuple of + sets, and the elements of the unordered set ASet as a sorted + list of sets without duplicates.</p> + </desc> + </func> + <func> + <name>type(AnySet) -> Type</name> + <fsummary>Return the type of a set.</fsummary> + <type> + <v>AnySet = anyset()</v> + <v>Type = type()</v> + </type> + <desc> + <p>Returns the <seealso marker="#type">type</seealso> of an + atomic, ordered or unordered set.</p> + </desc> + </func> + <func> + <name>union(SetOfSets) -> Set</name> + <fsummary>Return the union of a set of sets.</fsummary> + <type> + <v>Set = set()</v> + <v>SetOfSets = set_of_sets()</v> + </type> + <desc> + <p>Returns the <seealso marker="#union_n">union</seealso> of the + set of sets SetOfSets.</p> + </desc> + </func> + <func> + <name>union(Set1, Set2) -> Set3</name> + <fsummary>Return the union of two sets.</fsummary> + <type> + <v>Set1 = Set2 = Set3 = set()</v> + </type> + <desc> + <p>Returns the <seealso marker="#union">union</seealso> of + Set1 and Set2.</p> + </desc> + </func> + <func> + <name>union_of_family(Family) -> Set</name> + <fsummary>Return the union of a family.</fsummary> + <type> + <v>Family = family()</v> + <v>Set = set()</v> + </type> + <desc> + <p>Returns the union of + the <seealso marker="#family">family</seealso> Family.</p> + <pre> +1> <input>F = sofs:family([{a,[0,2,4]},{b,[0,1,2]},{c,[2,3]}]),</input> +<input>S = sofs:union_of_family(F),</input> +<input>sofs:to_external(S).</input> +[0,1,2,3,4]</pre> + </desc> + </func> + <func> + <name>weak_relation(BinRel1) -> BinRel2</name> + <fsummary>Return the weak relation corresponding to + a given relation.</fsummary> + <type> + <v>BinRel1 = BinRel2 = binary_relation()</v> + </type> + <desc> + <p>Returns a subset S of the <seealso marker="#weak_relation">weak + relation</seealso> W + corresponding to the binary relation BinRel1. Let F be the + <seealso marker="#field">field</seealso> of BinRel1. The + subset S is defined so that x S y if x W y for some x in F + and for some y in F.</p> + <pre> +1> <input>R1 = sofs:relation([{1,1},{1,2},{3,1}]),</input> +<input>R2 = sofs:weak_relation(R1),</input> +<input>sofs:to_external(R2).</input> +[{1,1},{1,2},{2,2},{3,1},{3,3}]</pre> + </desc> + </func> + </funcs> + + <section> + <title>See Also</title> + <p><seealso marker="dict">dict(3)</seealso>, + <seealso marker="digraph">digraph(3)</seealso>, + <seealso marker="orddict">orddict(3)</seealso>, + <seealso marker="ordsets">ordsets(3)</seealso>, + <seealso marker="sets">sets(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/stdlib_app.xml b/lib/stdlib/doc/src/stdlib_app.xml new file mode 100644 index 0000000000..da046b8a8d --- /dev/null +++ b/lib/stdlib/doc/src/stdlib_app.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE appref SYSTEM "appref.dtd"> + +<appref> + <header> + <copyright> + <year>2005</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>STDLIB</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <app>STDLIB</app> + <appsummary>The STDLIB Application</appsummary> + <description> + <p>The STDLIB is mandatory in the sense that the minimal system + based on Erlang/OTP consists of Kernel and STDLIB. The STDLIB + application contains no services.</p> + </description> + + <section> + <title>Configuration</title> + <p>The following configuration parameters are defined for the STDLIB + application. See <c>app(4)</c> for more information about + configuration parameters.</p> + <taglist> + <tag><c>shell_esc = icl | abort</c></tag> + <item> + <p>This parameter can be used to alter the behaviour of + the Erlang shell when ^G is pressed.</p> + </item> + <tag><c>restricted_shell = module()</c></tag> + <item> + <p>This parameter can be used to run the Erlang shell + in restricted mode.</p> + </item> + <tag><c>shell_catch_exception = bool()</c></tag> + <item> + <p>This parameter can be used to set the exception handling + of the Erlang shell's evaluator process.</p> + </item> + <tag><c>shell_history_length = integer() >= 0</c></tag> + <item> + <p>This parameter can be used to determine how many + commands are saved by the Erlang shell.</p> + </item> + <tag><c>shell_saved_results = integer() >= 0</c></tag> + <item> + <p>This parameter can be used to determine how many + results are saved by the Erlang shell.</p> + </item> + </taglist> + </section> + + <section> + <title>See Also</title> + <p><seealso marker="kernel:app">app(4)</seealso>, + <seealso marker="kernel:application">application(3)</seealso>, + <seealso marker="shell">shell(3)</seealso>, </p> + </section> +</appref> + diff --git a/lib/stdlib/doc/src/string.xml b/lib/stdlib/doc/src/string.xml new file mode 100644 index 0000000000..7ee38e496d --- /dev/null +++ b/lib/stdlib/doc/src/string.xml @@ -0,0 +1,415 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>string</title> + <prepared>Robert Virding</prepared> + <responsible>Bjarne Dacker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>96-09-28</date> + <rev>A</rev> + <file>string.sgml</file> + </header> + <module>string</module> + <modulesummary>String Processing Functions</modulesummary> + <description> + <p>This module contains functions for string processing.</p> + </description> + <funcs> + <func> + <name>len(String) -> Length</name> + <fsummary>Return the length of a string</fsummary> + <type> + <v>String = string()</v> + <v>Length = integer()</v> + </type> + <desc> + <p>Returns the number of characters in the string.</p> + </desc> + </func> + <func> + <name>equal(String1, String2) -> bool()</name> + <fsummary>Test string equality</fsummary> + <type> + <v>String1 = String2 = string()</v> + </type> + <desc> + <p>Tests whether two strings are equal. Returns <c>true</c> if + they are, otherwise <c>false</c>.</p> + </desc> + </func> + <func> + <name>concat(String1, String2) -> String3</name> + <fsummary>Concatenate two strings</fsummary> + <type> + <v>String1 = String2 = String3 = string()</v> + </type> + <desc> + <p>Concatenates two strings to form a new string. Returns the + new string.</p> + </desc> + </func> + <func> + <name>chr(String, Character) -> Index</name> + <name>rchr(String, Character) -> Index</name> + <fsummary>Return the index of the first/last occurrence of<c>Character</c>in <c>String</c></fsummary> + <type> + <v>String = string()</v> + <v>Character = char()</v> + <v>Index = integer()</v> + </type> + <desc> + <p>Returns the index of the first/last occurrence of + <c>Character</c> in <c>String</c>. <c>0</c> is returned if <c>Character</c> does not + occur.</p> + </desc> + </func> + <func> + <name>str(String, SubString) -> Index</name> + <name>rstr(String, SubString) -> Index</name> + <fsummary>Find the index of a substring</fsummary> + <type> + <v>String = SubString = string()</v> + <v>Index = integer()</v> + </type> + <desc> + <p>Returns the position where the first/last occurrence of + <c>SubString</c> begins in <c>String</c>. <c>0</c> is returned if <c>SubString</c> + does not exist in <c>String</c>. + For example:</p> + <code type="none"> +> string:str(" Hello Hello World World ", "Hello World"). +8 </code> + </desc> + </func> + <func> + <name>span(String, Chars) -> Length </name> + <name>cspan(String, Chars) -> Length</name> + <fsummary>Span characters at start of string</fsummary> + <type> + <v>String = Chars = string()</v> + <v>Length = integer()</v> + </type> + <desc> + <p>Returns the length of the maximum initial segment of + String, which consists entirely of characters from (not + from) Chars.</p> + <p>For example:</p> + <code type="none"> +> string:span("\\t abcdef", " \\t"). +5 +> string:cspan("\\t abcdef", " \\t"). +0 </code> + </desc> + </func> + <func> + <name>substr(String, Start) -> SubString</name> + <name>substr(String, Start, Length) -> Substring</name> + <fsummary>Return a substring of <c>String</c></fsummary> + <type> + <v>String = SubString = string()</v> + <v>Start = Length = integer()</v> + </type> + <desc> + <p>Returns a substring of <c>String</c>, starting at the + position <c>Start</c>, and ending at the end of the string or + at length <c>Length</c>.</p> + <p>For example:</p> + <code type="none"> +> substr("Hello World", 4, 5). +"lo Wo" </code> + </desc> + </func> + <func> + <name>tokens(String, SeparatorList) -> Tokens</name> + <fsummary>Split string into tokens</fsummary> + <type> + <v>String = SeparatorList = string()</v> + <v>Tokens = [string()]</v> + </type> + <desc> + <p>Returns a list of tokens in <c>String</c>, separated by the + characters in <c>SeparatorList</c>.</p> + <p>For example:</p> + <code type="none"> +> tokens("abc defxxghix jkl", "x "). +["abc", "def", "ghi", "jkl"] </code> + </desc> + </func> + <func> + <name>join(StringList, Separator) -> String</name> + <fsummary>Join a list of strings with separator</fsummary> + <type> + <v>StringList = [string()]</v> + <v>Separator = string()</v> + </type> + <desc> + <p>Returns a string with the elements of <c>StringList</c> + separated by the string in <c>Seperator</c>.</p> + <p>For example:</p> + <code type="none"> +> join(["one", "two", "three"], ", "). +"one, two, three" </code> + </desc> + </func> + <func> + <name>chars(Character, Number) -> String</name> + <name>chars(Character, Number, Tail) -> String</name> + <fsummary>Returns a string consisting of numbers of characters</fsummary> + <type> + <v>Character = char()</v> + <v>Number = integer()</v> + <v>String = string()</v> + </type> + <desc> + <p>Returns a string consisting of <c>Number</c> of characters + <c>Character</c>. Optionally, the string can end with the + string <c>Tail</c>.</p> + </desc> + </func> + <func> + <name>copies(String, Number) -> Copies</name> + <fsummary>Copy a string</fsummary> + <type> + <v>String = Copies = string()</v> + <v>Number = integer()</v> + </type> + <desc> + <p>Returns a string containing <c>String</c> repeated + <c>Number</c> times.</p> + </desc> + </func> + <func> + <name>words(String) -> Count</name> + <name>words(String, Character) -> Count</name> + <fsummary>Count blank separated words</fsummary> + <type> + <v>String = string()</v> + <v>Character = char()</v> + <v>Count = integer()</v> + </type> + <desc> + <p>Returns the number of words in <c>String</c>, separated by + blanks or <c>Character</c>.</p> + <p>For example:</p> + <code type="none"> +> words(" Hello old boy!", $o). +4 </code> + </desc> + </func> + <func> + <name>sub_word(String, Number) -> Word</name> + <name>sub_word(String, Number, Character) -> Word</name> + <fsummary>Extract subword</fsummary> + <type> + <v>String = Word = string()</v> + <v>Character = char()</v> + <v>Number = integer()</v> + </type> + <desc> + <p>Returns the word in position <c>Number</c> of <c>String</c>. + Words are separated by blanks or <c>Character</c>s.</p> + <p>For example:</p> + <code type="none"> +> string:sub_word(" Hello old boy !",3,$o). +"ld b" </code> + </desc> + </func> + <func> + <name>strip(String) -> Stripped</name> + <name>strip(String, Direction) -> Stripped</name> + <name>strip(String, Direction, Character) -> Stripped</name> + <fsummary>Strip leading or trailing characters</fsummary> + <type> + <v>String = Stripped = string()</v> + <v>Direction = left | right | both</v> + <v>Character = char()</v> + </type> + <desc> + <p>Returns a string, where leading and/or trailing blanks or a + number of <c>Character</c> have been removed. + <c>Direction</c> can be <c>left</c>, <c>right</c>, or + <c>both</c> and indicates from which direction blanks are to be + removed. The function <c>strip/1</c> is equivalent to + <c>strip(String, both)</c>.</p> + <p>For example:</p> + <code type="none"> +> string:strip("...Hello.....", both, $.). +"Hello" </code> + </desc> + </func> + <func> + <name>left(String, Number) -> Left</name> + <name>left(String, Number, Character) -> Left</name> + <fsummary>Adjust left end of string</fsummary> + <type> + <v>String = Left = string()</v> + <v>Character = char</v> + <v>Number = integer()</v> + </type> + <desc> + <p>Returns the <c>String</c> with the length adjusted in + accordance with <c>Number</c>. The left margin is + fixed. If the <c>length(String)</c> < <c>Number</c>, + <c>String</c> is padded with blanks or <c>Character</c>s.</p> + <p>For example:</p> + <code type="none"> +> string:left("Hello",10,$.). +"Hello....." </code> + </desc> + </func> + <func> + <name>right(String, Number) -> Right</name> + <name>right(String, Number, Character) -> Right</name> + <fsummary>Adjust right end of string</fsummary> + <type> + <v>String = Right = string()</v> + <v>Character = char</v> + <v>Number = integer()</v> + </type> + <desc> + <p>Returns the <c>String</c> with the length adjusted in + accordance with <c>Number</c>. The right margin is + fixed. If the length of <c>(String)</c> < <c>Number</c>, + <c>String</c> is padded with blanks or <c>Character</c>s.</p> + <p>For example:</p> + <code type="none"> +> string:right("Hello", 10, $.). +".....Hello" </code> + </desc> + </func> + <func> + <name>centre(String, Number) -> Centered</name> + <name>centre(String, Number, Character) -> Centered</name> + <fsummary>Center a string</fsummary> + <type> + <v>String = Centered = string()</v> + <v>Character = char</v> + <v>Number = integer()</v> + </type> + <desc> + <p>Returns a string, where <c>String</c> is centred in the + string and surrounded by blanks or characters. The resulting + string will have the length <c>Number</c>.</p> + </desc> + </func> + <func> + <name>sub_string(String, Start) -> SubString</name> + <name>sub_string(String, Start, Stop) -> SubString</name> + <fsummary>Extract a substring</fsummary> + <type> + <v>String = SubString = string()</v> + <v>Start = Stop = integer()</v> + </type> + <desc> + <p>Returns a substring of <c>String</c>, starting at the + position <c>Start</c> to the end of the string, or to and + including the <c>Stop</c> position.</p> + <p>For example:</p> + <code type="none"> +sub_string("Hello World", 4, 8). +"lo Wo" </code> + </desc> + </func> + <func> + <name>to_float(String) -> {Float,Rest} | {error,Reason} </name> + <fsummary>Returns a float whose text representation is the integers (ASCII values) in String.</fsummary> + <type> + <v>String = string()</v> + <v>Float = float()</v> + <v>Rest = string()</v> + <v>Reason = no_float | not_a_list</v> + </type> + <desc> + <p>Argument <c>String</c> is expected to start with a valid text + represented float (the digits being ASCII values). Remaining characters + in the string after the float are returned in <c>Rest</c>.</p> + <p>Example:</p> + <code type="none"> + > {F1,Fs} = string:to_float("1.0-1.0e-1"), + > {F2,[]} = string:to_float(Fs), + > F1+F2. + 0.9 + > string:to_float("3/2=1.5"). + {error,no_float} + > string:to_float("-1.5eX"). + {-1.5,"eX"}</code> + </desc> + </func> + <func> + <name>to_integer(String) -> {Int,Rest} | {error,Reason} </name> + <fsummary>Returns an integer whose text representation is the integers (ASCII values) in String.</fsummary> + <type> + <v>String = string()</v> + <v>Int = integer()</v> + <v>Rest = string()</v> + <v>Reason = no_integer | not_a_list</v> + </type> + <desc> + <p>Argument <c>String</c> is expected to start with a valid text + represented integer (the digits being ASCII values). Remaining characters + in the string after the integer are returned in <c>Rest</c>.</p> + <p>Example:</p> + <code type="none"> + > {I1,Is} = string:to_integer("33+22"), + > {I2,[]} = string:to_integer(Is), + > I1-I2. + 11 + > string:to_integer("0.5"). + {0,".5"} + > string:to_integer("x=2"). + {error,no_integer}</code> + </desc> + </func> + <func> + <name>to_lower(String) -> Result</name> + <name>to_lower(Char) -> CharResult</name> + <name>to_upper(String) -> Result</name> + <name>to_upper(Char) -> CharResult</name> + <fsummary>Convert case of string (ISO/IEC 8859-1)</fsummary> + <type> + <v>String = Result = string()</v> + <v>Char = CharResult = integer()</v> + </type> + <desc> + <p>The given string or character is case-converted. Note that + the supported character set is ISO/IEC 8859-1 (a.k.a. Latin 1), + all values outside this set is unchanged</p> + </desc> + </func> + </funcs> + + <section> + <title>Notes</title> + <p>Some of the general string functions may seem to overlap each + other. The reason for this is that this string package is the + combination of two earlier packages and all the functions of + both packages have been retained. + </p> + <note> + <p>Any undocumented functions in <c>string</c> should not be used.</p> + </note> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml new file mode 100644 index 0000000000..adf9d24eae --- /dev/null +++ b/lib/stdlib/doc/src/supervisor.xml @@ -0,0 +1,495 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>supervisor</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>supervisor</module> + <modulesummary>Generic Supervisor Behaviour</modulesummary> + <description> + <p>A behaviour module for implementing a supervisor, a process which + supervises other processes called child processes. A child + process can either be another supervisor or a worker process. + Worker processes are normally implemented using one of + the <c>gen_event</c>, <c>gen_fsm</c>, or <c>gen_server</c> + behaviours. A supervisor implemented using this module will have + a standard set of interface functions and include functionality + for tracing and error reporting. Supervisors are used to build an + hierarchical process structure called a supervision tree, a + nice way to structure a fault tolerant application. Refer to + <em>OTP Design Principles</em> for more information.</p> + <p>A supervisor assumes the definition of which child processes to + supervise to be located in a callback module exporting a + pre-defined set of functions.</p> + <p>Unless otherwise stated, all functions in this module will fail + if the specified supervisor does not exist or if bad arguments + are given.</p> + </description> + + <section> + <title>Supervision Principles</title> + <p>The supervisor is responsible for starting, stopping and + monitoring its child processes. The basic idea of a supervisor is + that it should keep its child processes alive by restarting them + when necessary.</p> + <p>The children of a supervisor is defined as a list of <em>child specifications</em>. When the supervisor is started, the child + processes are started in order from left to right according to + this list. When the supervisor terminates, it first terminates + its child processes in reversed start order, from right to left.</p> + <p></p> + <p>A supervisor can have one of the following <em>restart strategies</em>:</p> + <list type="bulleted"> + <item> + <p><c>one_for_one</c> - if one child process terminates and + should be restarted, only that child process is affected.</p> + </item> + <item> + <p><c>one_for_all</c> - if one child process terminates and + should be restarted, all other child processes are terminated + and then all child processes are restarted.</p> + </item> + <item> + <p><c>rest_for_one</c> - if one child process terminates and + should be restarted, the 'rest' of the child processes -- + i.e. the child processes after the terminated child process + in the start order -- are terminated. Then the terminated + child process and all child processes after it are restarted.</p> + </item> + <item> + <p><c>simple_one_for_one</c> - a simplified <c>one_for_one</c> + supervisor, where all child processes are dynamically added + instances of the same process type, i.e. running the same + code.</p> + <p>The functions <c>terminate_child/2</c>, <c>delete_child/2</c> + and <c>restart_child/2</c> are invalid for + <c>simple_one_for_one</c> supervisors and will return + <c>{error,simple_one_for_one}</c> if the specified supervisor + uses this restart strategy.</p> + </item> + </list> + <p>To prevent a supervisor from getting into an infinite loop of + child process terminations and restarts, a <em>maximum restart frequency</em> is defined using two integer values <c>MaxR</c> + and <c>MaxT</c>. If more than <c>MaxR</c> restarts occur within + <c>MaxT</c> seconds, the supervisor terminates all child + processes and then itself. + </p> + <marker id="child_spec"/> + <p>This is the type definition of a child specification:</p> + <pre> +child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} + Id = term() + StartFunc = {M,F,A} + M = F = atom() + A = [term()] + Restart = permanent | transient | temporary + Shutdown = brutal_kill | int()>=0 | infinity + Type = worker | supervisor + Modules = [Module] | dynamic + Module = atom()</pre> + <list type="bulleted"> + <item> + <p><c>Id</c> is a name that is used to identify the child + specification internally by the supervisor.</p> + </item> + <item> + <p><c>StartFunc</c> defines the function call used to start + the child process. It should be a module-function-arguments + tuple <c>{M,F,A}</c> used as <c>apply(M,F,A)</c>.</p> + <p> <br></br> +</p> + <p>The start function <em>must create and link to</em> the child + process, and should return <c>{ok,Child}</c> or + <c>{ok,Child,Info}</c> where <c>Child</c> is the pid of + the child process and <c>Info</c> an arbitrary term which is + ignored by the supervisor.</p> + <p> <br></br> +</p> + <p>The start function can also return <c>ignore</c> if the child + process for some reason cannot be started, in which case + the child specification will be kept by the supervisor but + the non-existing child process will be ignored.</p> + <p> <br></br> +</p> + <p>If something goes wrong, the function may also return an + error tuple <c>{error,Error}</c>.</p> + <p> <br></br> +</p> + <p>Note that the <c>start_link</c> functions of the different + behaviour modules fulfill the above requirements.</p> + </item> + <item> + <p><c>Restart</c> defines when a terminated child process + should be restarted. A <c>permanent</c> child process should + always be restarted, a <c>temporary</c> child process should + never be restarted and a <c>transient</c> child process + should be restarted only if it terminates abnormally, i.e. + with another exit reason than <c>normal</c>.</p> + </item> + <item> + <p><c>Shutdown</c> defines how a child process should be + terminated. <c>brutal_kill</c> means the child process will + be unconditionally terminated using <c>exit(Child,kill)</c>. + An integer timeout value means that the supervisor will tell + the child process to terminate by calling + <c>exit(Child,shutdown)</c> and then wait for an exit signal + with reason <c>shutdown</c> back from the child process. If + no exit signal is received within the specified time, + the child process is unconditionally terminated using + <c>exit(Child,kill)</c>.</p> + <p>If the child process is another supervisor, <c>Shutdown</c> + should be set to <c>infinity</c> to give the subtree ample + time to shutdown.</p> + <p><em>Important note on simple-one-for-one supervisors:</em> + The dynamically created child processes of a + simple-one-for-one supervisor are not explicitly killed, + regardless of shutdown strategy, but are expected to terminate + when the supervisor does (that is, when an exit signal from + the parent process is received).</p> + <p>Note that all child processes implemented using the standard + OTP behavior modules automatically adhere to the shutdown + protocol.</p> + </item> + <item> + <p><c>Type</c> specifies if the child process is a supervisor or + a worker.</p> + </item> + <item> + <p><c>Modules</c> is used by the release handler during code + replacement to determine which processes are using a certain + module. As a rule of thumb <c>Modules</c> should be a list + with one element <c>[Module]</c>, where <c>Module</c> is + the callback module, if the child process is a supervisor, + gen_server or gen_fsm. If the child process is an event + manager (gen_event) with a dynamic set of callback modules, + <c>Modules</c> should be <c>dynamic</c>. See <em>OTP Design Principles</em> for more information about release handling.</p> + </item> + <item> + <p>Internally, the supervisor also keeps track of the pid + <c>Child</c> of the child process, or <c>undefined</c> if no + pid exists.</p> + </item> + </list> + </section> + <funcs> + <func> + <name>start_link(Module, Args) -> Result</name> + <name>start_link(SupName, Module, Args) -> Result</name> + <fsummary>Create a supervisor process.</fsummary> + <type> + <v>SupName = {local,Name} | {global,Name}</v> + <v> Name = atom()</v> + <v>Module = atom()</v> + <v>Args = term()</v> + <v>Result = {ok,Pid} | ignore | {error,Error}</v> + <v> Pid = pid()</v> + <v> Error = {already_started,Pid}} | shutdown | term()</v> + </type> + <desc> + <p>Creates a supervisor process as part of a supervision tree. + The function will, among other things, ensure that + the supervisor is linked to the calling process (its + supervisor).</p> + <p>The created supervisor process calls <c>Module:init/1</c> to + find out about restart strategy, maximum restart frequency + and child processes. To ensure a synchronized start-up + procedure, <c>start_link/2,3</c> does not return until + <c>Module:init/1</c> has returned and all child processes + have been started.</p> + <p>If <c>SupName={local,Name}</c> the supervisor is registered + locally as <c>Name</c> using <c>register/2</c>. If + <c>SupName={global,Name}</c> the supervisor is registered + globally as <c>Name</c> using <c>global:register_name/2</c>. + If no name is provided, the supervisor is not registered.</p> + <p><c>Module</c> is the name of the callback module.</p> + <p><c>Args</c> is an arbitrary term which is passed as + the argument to <c>Module:init/1</c>.</p> + <p>If the supervisor and its child processes are successfully + created (i.e. if all child process start functions return + <c>{ok,Child}</c>, <c>{ok,Child,Info}</c>, or <c>ignore</c>) + the function returns <c>{ok,Pid}</c>, where <c>Pid</c> is + the pid of the supervisor. If there already exists a process + with the specified <c>SupName</c> the function returns + <c>{error,{already_started,Pid}}</c>, where <c>Pid</c> is + the pid of that process.</p> + <p>If <c>Module:init/1</c> returns <c>ignore</c>, this function + returns <c>ignore</c> as well and the supervisor terminates + with reason <c>normal</c>. + If <c>Module:init/1</c> fails or returns an incorrect value, + this function returns <c>{error,Term}</c> where <c>Term</c> + is a term with information about the error, and the supervisor + terminates with reason <c>Term</c>.</p> + <p>If any child process start function fails or returns an error + tuple or an erroneous value, the function returns + <c>{error,shutdown}</c> and the supervisor terminates all + started child processes and then itself with reason + <c>shutdown</c>.</p> + </desc> + </func> + <func> + <name>start_child(SupRef, ChildSpec) -> Result</name> + <fsummary>Dynamically add a child process to a supervisor.</fsummary> + <type> + <v>SupRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>ChildSpec = child_spec() | [term()]</v> + <v>Result = {ok,Child} | {ok,Child,Info} | {error,Error}</v> + <v> Child = pid() | undefined</v> + <v> Info = term()</v> + <v> Error = already_present | {already_started,Child} | term()</v> + </type> + <desc> + <p>Dynamically adds a child specification to the supervisor + <c>SupRef</c> which starts the corresponding child process.</p> + <p><c>SupRef</c> can be:</p> + <list type="bulleted"> + <item>the pid,</item> + <item><c>Name</c>, if the supervisor is locally registered,</item> + <item><c>{Name,Node}</c>, if the supervisor is locally + registered at another node, or</item> + <item><c>{global,Name}</c>, if the supervisor is globally + registered.</item> + </list> + <p><c>ChildSpec</c> should be a valid child specification + (unless the supervisor is a <c>simple_one_for_one</c> + supervisor, see below). The child process will be started by + using the start function as defined in the child + specification.</p> + <p>If the case of a <c>simple_one_for_one</c> supervisor, + the child specification defined in <c>Module:init/1</c> will + be used and <c>ChildSpec</c> should instead be an arbitrary + list of terms <c>List</c>. The child process will then be + started by appending <c>List</c> to the existing start + function arguments, i.e. by calling + <c>apply(M, F, A++List)</c> where <c>{M,F,A}</c> is the start + function defined in the child specification.</p> + <p>If there already exists a child specification with + the specified <c>Id</c>, <c>ChildSpec</c> is discarded and + the function returns <c>{error,already_present}</c> or + <c>{error,{already_started,Child}}</c>, depending on if + the corresponding child process is running or not.</p> + <p>If the child process start function returns <c>{ok,Child}</c> + or <c>{ok,Child,Info}</c>, the child specification and pid is + added to the supervisor and the function returns the same + value.</p> + <p>If the child process start function returns <c>ignore</c>, + the child specification is added to the supervisor, the pid + is set to <c>undefined</c> and the function returns + <c>{ok,undefined}</c>.</p> + <p>If the child process start function returns an error tuple or + an erroneous value, or if it fails, the child specification is + discarded and the function returns <c>{error,Error}</c> where + <c>Error</c> is a term containing information about the error + and child specification.</p> + </desc> + </func> + <func> + <name>terminate_child(SupRef, Id) -> Result</name> + <fsummary>Terminate a child process belonging to a supervisor.</fsummary> + <type> + <v>SupRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Id = term()</v> + <v>Result = ok | {error,Error}</v> + <v> Error = not_found | simple_one_for_one</v> + </type> + <desc> + <p>Tells the supervisor <c>SupRef</c> to terminate the child + process corresponding to the child specification identified + by <c>Id</c>. The process, if there is one, is terminated but + the child specification is kept by the supervisor. This means + that the child process may be later be restarted by + the supervisor. The child process can also be restarted + explicitly by calling <c>restart_child/2</c>. Use + <c>delete_child/2</c> to remove the child specification.</p> + <p>See <c>start_child/2</c> for a description of + <c>SupRef</c>.</p> + <p>If successful, the function returns <c>ok</c>. If there is + no child specification with the specified <c>Id</c>, + the function returns <c>{error,not_found}</c>.</p> + </desc> + </func> + <func> + <name>delete_child(SupRef, Id) -> Result</name> + <fsummary>Delete a child specification from a supervisor.</fsummary> + <type> + <v>SupRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Id = term()</v> + <v>Result = ok | {error,Error}</v> + <v> Error = running | not_found | simple_one_for_one</v> + </type> + <desc> + <p>Tells the supervisor <c>SupRef</c> to delete the child + specification identified by <c>Id</c>. The corresponding child + process must not be running, use <c>terminate_child/2</c> to + terminate it.</p> + <p>See <c>start_child/2</c> for a description of <c>SupRef</c>.</p> + <p>If successful, the function returns <c>ok</c>. If the child + specification identified by <c>Id</c> exists but + the corresponding child process is running, the function + returns <c>{error,running}</c>. If the child specification + identified by <c>Id</c> does not exist, the function returns + <c>{error,not_found}</c>.</p> + </desc> + </func> + <func> + <name>restart_child(SupRef, Id) -> Result</name> + <fsummary>Restart a terminated child process belonging to a supervisor.</fsummary> + <type> + <v>SupRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Id = term()</v> + <v>Result = {ok,Child} | {ok,Child,Info} | {error,Error}</v> + <v> Child = pid() | undefined</v> + <v> Error = running | not_found | simple_one_for_one | term()</v> + </type> + <desc> + <p>Tells the supervisor <c>SupRef</c> to restart a child process + corresponding to the child specification identified by + <c>Id</c>. The child specification must exist and + the corresponding child process must not be running.</p> + <p>See <c>start_child/2</c> for a description of <c>SupRef</c>.</p> + <p>If the child specification identified by <c>Id</c> does not + exist, the function returns <c>{error,not_found}</c>. If + the child specification exists but the corresponding process + is already running, the function returns + <c>{error,running}</c>.</p> + <p>If the child process start function returns <c>{ok,Child}</c> + or <c>{ok,Child,Info}</c>, the pid is added to the supervisor + and the function returns the same value.</p> + <p>If the child process start function returns <c>ignore</c>, + the pid remains set to <c>undefined</c> and the function + returns <c>{ok,undefined}</c>.</p> + <p>If the child process start function returns an error tuple or + an erroneous value, or if it fails, the function returns + <c>{error,Error}</c> where <c>Error</c> is a term containing + information about the error.</p> + </desc> + </func> + <func> + <name>which_children(SupRef) -> [{Id,Child,Type,Modules}]</name> + <fsummary>Return information about all children specifications and child processes belonging to a supervisor.</fsummary> + <type> + <v>SupRef = Name | {Name,Node} | {global,Name} | pid()</v> + <v> Name = Node = atom()</v> + <v>Id = term() | undefined</v> + <v>Child = pid() | undefined</v> + <v>Type = worker | supervisor</v> + <v>Modules = [Module] | dynamic</v> + <v> Module = atom()</v> + </type> + <desc> + <p>Returns a list with information about all child + specifications and child processes belonging to + the supervisor <c>SupRef</c>.</p> + <p>See <c>start_child/2</c> for a description of <c>SupRef</c>.</p> + <p>The information given for each child specification/process + is:</p> + <list type="bulleted"> + <item> + <p><c>Id</c> - as defined in the child specification or + <c>undefined</c> in the case of a + <c>simple_one_for_one</c> supervisor.</p> + </item> + <item> + <p><c>Child</c> - the pid of the corresponding child + process, or <c>undefined</c> if there is no such process.</p> + </item> + <item> + <p><c>Type</c> - as defined in the child specification.</p> + </item> + <item> + <p><c>Modules</c> - as defined in the child specification.</p> + </item> + </list> + </desc> + </func> + <func> + <name>check_childspecs([ChildSpec]) -> Result</name> + <fsummary>Check if children specifications are syntactically correct.</fsummary> + <type> + <v>ChildSpec = child_spec()</v> + <v>Result = ok | {error,Error}</v> + <v> Error = term()</v> + </type> + <desc> + <p>This function takes a list of child specification as argument + and returns <c>ok</c> if all of them are syntactically + correct, or <c>{error,Error}</c> otherwise.</p> + </desc> + </func> + </funcs> + + <section> + <title>CALLBACK FUNCTIONS</title> + <p>The following functions should be exported from a + <c>supervisor</c> callback module.</p> + </section> + <funcs> + <func> + <name>Module:init(Args) -> Result</name> + <fsummary>Return a supervisor specification.</fsummary> + <type> + <v>Args = term()</v> + <v>Result = {ok,{{RestartStrategy,MaxR,MaxT},[ChildSpec]}} | ignore</v> + <v> RestartStrategy = one_for_all | one_for_one | rest_for_one | simple_one_for_one</v> + <v> MaxR = MaxT = int()>=0</v> + <v> ChildSpec = child_spec()</v> + </type> + <desc> + <p>Whenever a supervisor is started using + <c>supervisor:start_link/2,3</c>, this function is called by + the new process to find out about restart strategy, maximum + restart frequency and child specifications.</p> + <p><c>Args</c> is the <c>Args</c> argument provided to the start + function.</p> + <p><c>RestartStrategy</c> is the restart strategy and + <c>MaxR</c> and <c>MaxT</c> defines the maximum restart + frequency of the supervisor. <c>[ChildSpec]</c> is a list of + valid child specifications defining which child processes + the supervisor should start and monitor. See the discussion + about Supervision Principles above.</p> + <p>Note that when the restart strategy is + <c>simple_one_for_one</c>, the list of child specifications + must be a list with one child specification only. + (The <c>Id</c> is ignored). No child process is then started + during the initialization phase, but all children are assumed + to be started dynamically using + <c>supervisor:start_child/2</c>.</p> + <p>The function may also return <c>ignore</c>.</p> + </desc> + </func> + </funcs> + + <section> + <title>SEE ALSO</title> + <p><seealso marker="gen_event">gen_event(3)</seealso>, + <seealso marker="gen_fsm">gen_fsm(3)</seealso>, + <seealso marker="gen_server">gen_server(3)</seealso>, + <seealso marker="sys">sys(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/supervisor_bridge.xml b/lib/stdlib/doc/src/supervisor_bridge.xml new file mode 100644 index 0000000000..b334f57caf --- /dev/null +++ b/lib/stdlib/doc/src/supervisor_bridge.xml @@ -0,0 +1,162 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>supervisor_bridge</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>supervisor_bridge</module> + <modulesummary>Generic Supervisor Bridge Behaviour.</modulesummary> + <description> + <p>A behaviour module for implementing a supervisor_bridge, a process + which connects a subsystem not designed according to the OTP design + principles to a supervision tree. The supervisor_bridge sits between + a supervisor and the subsystem. It behaves like a real supervisor to + its own supervisor, but has a different interface than a real + supervisor to the subsystem. Refer to <em>OTP Design Principles</em> + for more information.</p> + <p>A supervisor_bridge assumes the functions for starting and stopping + the subsystem to be located in a callback module exporting a + pre-defined set of functions.</p> + <p>The <c>sys</c> module can be used for debugging a + supervisor_bridge.</p> + <p>Unless otherwise stated, all functions in this module will fail if + the specified supervisor_bridge does not exist or if bad arguments are + given.</p> + </description> + <funcs> + <func> + <name>start_link(Module, Args) -> Result</name> + <name>start_link(SupBridgeName, Module, Args) -> Result</name> + <fsummary>Create a supervisor bridge process.</fsummary> + <type> + <v>SupBridgeName = {local,Name} | {global,Name}</v> + <v> Name = atom()</v> + <v>Module = atom()</v> + <v>Args = term()</v> + <v>Result = {ok,Pid} | ignore | {error,Error}</v> + <v> Pid = pid()</v> + <v> Error = {already_started,Pid} | term()</v> + </type> + <desc> + <p>Creates a supervisor_bridge process, linked to the calling + process, which calls <c>Module:init/1</c> to start the subsystem. + To ensure a synchronized start-up procedure, this function does + not return until <c>Module:init/1</c> has returned.</p> + <p>If <c>SupBridgeName={local,Name}</c> the supervisor_bridge is + registered locally as <c>Name</c> using <c>register/2</c>. + If <c>SupBridgeName={global,Name}</c> the supervisor_bridge is + registered globally as <c>Name</c> using + <c>global:register_name/2</c>. + If no name is provided, the supervisor_bridge is not registered. + If there already exists a process with the specified + <c>SupBridgeName</c> the function returns + <c>{error,{already_started,Pid}}</c>, where <c>Pid</c> is the pid + of that process.</p> + <p><c>Module</c> is the name of the callback module.</p> + <p><c>Args</c> is an arbitrary term which is passed as the argument + to <c>Module:init/1</c>.</p> + <p>If the supervisor_bridge and the subsystem are successfully + started the function returns <c>{ok,Pid}</c>, where <c>Pid</c> is + is the pid of the supervisor_bridge.</p> + <p>If <c>Module:init/1</c> returns <c>ignore</c>, this function + returns <c>ignore</c> as well and the supervisor_bridge terminates + with reason <c>normal</c>. + If <c>Module:init/1</c> fails or returns an error tuple or an + incorrect value, this function returns <c>{error,Term}</c> where + <c>Term</c> is a term with information about the error, and + the supervisor_bridge terminates with reason <c>Term</c>.</p> + </desc> + </func> + </funcs> + + <section> + <title>CALLBACK FUNCTIONS</title> + <p>The following functions should be exported from a + <c>supervisor_bridge</c> callback module.</p> + </section> + <funcs> + <func> + <name>Module:init(Args) -> Result</name> + <fsummary>Initialize process and start subsystem.</fsummary> + <type> + <v>Args = term()</v> + <v>Result = {ok,Pid,State} | ignore | {error,Error}</v> + <v> Pid = pid()</v> + <v> State = term()</v> + <v> Error = term()</v> + </type> + <desc> + <p>Whenever a supervisor_bridge is started using + <c>supervisor_bridge:start_link/2,3</c>, this function is called + by the new process to start the subsystem and initialize.</p> + <p><c>Args</c> is the <c>Args</c> argument provided to the start + function.</p> + <p>The function should return <c>{ok,Pid,State}</c> where <c>Pid</c> + is the pid of the main process in the subsystem and <c>State</c> + is any term.</p> + <p>If later <c>Pid</c> terminates with a reason <c>Reason</c>, + the supervisor bridge will terminate with reason <c>Reason</c> as + well. + If later the supervisor_bridge is stopped by its supervisor with + reason <c>Reason</c>, it will call + <c>Module:terminate(Reason,State)</c> to terminate.</p> + <p>If something goes wrong during the initialization the function + should return <c>{error,Error}</c> where <c>Error</c> is any + term, or <c>ignore</c>.</p> + </desc> + </func> + <func> + <name>Module:terminate(Reason, State)</name> + <fsummary>Clean up and stop subsystem.</fsummary> + <type> + <v>Reason = shutdown | term()</v> + <v>State = term()</v> + </type> + <desc> + <p>This function is called by the supervisor_bridge when it is about + to terminate. It should be the opposite of <c>Module:init/1</c> + and stop the subsystem and do any necessary cleaning up. + The return value is ignored.</p> + <p><c>Reason</c> is <c>shutdown</c> if the supervisor_bridge is + terminated by its supervisor. If the supervisor_bridge terminates + because a a linked process (apart from the main process of + the subsystem) has terminated with reason <c>Term</c>, + <c>Reason</c> will be <c>Term</c>.</p> + <p><c>State</c> is taken from the return value of + <c>Module:init/1</c>.</p> + </desc> + </func> + </funcs> + + <section> + <title>SEE ALSO</title> + <p><seealso marker="supervisor">supervisor(3)</seealso>, + <seealso marker="sys">sys(3)</seealso></p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml new file mode 100644 index 0000000000..a395a8a415 --- /dev/null +++ b/lib/stdlib/doc/src/sys.xml @@ -0,0 +1,429 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2007</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>sys</title> + <prepared>Martin Björklund</prepared> + <responsible>Bjarne Däcker</responsible> + <docno></docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>1996-06-06</date> + <rev></rev> + <file>sys.sgml</file> + </header> + <module>sys</module> + <modulesummary>A Functional Interface to System Messages</modulesummary> + <description> + <p>This module contains functions for sending system messages used by programs, and messaged used for debugging purposes. + </p> + <p>Functions used for implementation of processes + should also understand system messages such as debugging + messages and code change. These functions must be used to implement the use of system messages for a process; either directly, or through standard behaviours, such as <c>gen_server</c>.</p> + <p>The following types are used in the functions defined below:</p> + <list type="bulleted"> + <item> + <p><c>Name = pid() | atom() | {global, atom()}</c></p> + </item> + <item> + <p><c>Timeout = int() >= 0 | infinity</c></p> + </item> + <item> + <p><c>system_event() = {in, Msg} | {in, Msg, From} | {out, Msg, To} | term()</c></p> + </item> + </list> + <p>The default timeout is 5000 ms, unless otherwise specified. The + <c>timeout</c> defines the time period to wait for the process to + respond to a request. If the process does not respond, the + function evaluates <c>exit({timeout, {M, F, A}})</c>. + </p> + <p>The functions make reference to a debug structure. + The debug structure is a list of <c>dbg_opt()</c>. + <c>dbg_opt()</c> is an internal data type used by the + <c>handle_system_msg/6</c> function. No debugging is performed if it is an empty list. + </p> + </description> + + <section> + <title>System Messages</title> + <p>Processes which are not implemented as one of the standard + behaviours must still understand system + messages. There are three different messages which must be + understood: + </p> + <list type="bulleted"> + <item> + <p>Plain system messages. These are received as + <c>{system, From, Msg}</c>. The content and meaning of + this message are not interpreted by the + receiving process module. When a system message has been + received, the function <c>sys:handle_system_msg/6</c> + is called in order to handle the request. + </p> + </item> + <item> + <p>Shutdown messages. If the process traps exits, it must + be able to handle an shut-down request from its parent, the + supervisor. The message <c>{'EXIT', Parent, Reason}</c> + from the parent is an order to terminate. The process must terminate when this message is received, normally with the + same <c>Reason</c> as <c>Parent</c>. + </p> + </item> + <item> + <p>There is one more message which the process must understand if the modules used to implement the process change dynamically during runtime. An example of such a process is the <c>gen_event</c> processes. This message is <c>{get_modules, From}</c>. The reply to this message is <c>From ! {modules, Modules}</c>, + where <c>Modules</c> is a list of the currently active modules in the process. + </p> + <p>This message is used by the release handler to find which + processes execute a certain module. The process may at a + later time be suspended and ordered to perform a code change + for one of its modules. + </p> + </item> + </list> + </section> + + <section> + <title>System Events</title> + <p>When debugging a process with the functions of this + module, the process generates <em>system_events</em> which are + then treated in the debug function. For example, <c>trace</c> + formats the system events to the tty. + </p> + <p>There are three predefined system events which are used when a + process receives or sends a message. The process can also define its + own system events. It is always up to the process itself + to format these events.</p> + </section> + <funcs> + <func> + <name>log(Name,Flag)</name> + <name>log(Name,Flag,Timeout) -> ok | {ok, [system_event()]}</name> + <fsummary>Log system events in memory</fsummary> + <type> + <v>Flag = true | {true, N} | false | get | print</v> + <v>N = integer() > 0</v> + </type> + <desc> + <p>Turns the logging of system events On or Off. If On, a + maximum of <c>N</c> events are kept in the + debug structure (the default is 10). If <c>Flag</c> is <c>get</c>, a list of all + logged events is returned. If <c>Flag</c> is <c>print</c>, the + logged events are printed to <c>standard_io</c>. The events are + formatted with a function that is defined by the process that + generated the event (with a call to + <c>sys:handle_debug/4</c>).</p> + </desc> + </func> + <func> + <name>log_to_file(Name,Flag)</name> + <name>log_to_file(Name,Flag,Timeout) -> ok | {error, open_file}</name> + <fsummary>Log system events to the specified file</fsummary> + <type> + <v>Flag = FileName | false</v> + <v>FileName = string()</v> + </type> + <desc> + <p>Enables or disables the logging of all system events in textual + format to the file. The events are formatted with a function that is + defined by the process that generated the event (with a call + to <c>sys:handle_debug/4</c>).</p> + </desc> + </func> + <func> + <name>statistics(Name,Flag)</name> + <name>statistics(Name,Flag,Timeout) -> ok | {ok, Statistics} </name> + <fsummary>Enable or disable the collections of statistics</fsummary> + <type> + <v>Flag = true | false | get</v> + <v>Statistics = [{start_time, {Date1, Time1}}, {current_time, {Date, Time2}}, {reductions, integer()}, {messages_in, integer()}, {messages_out, integer()}]</v> + <v>Date1 = Date2 = {Year, Month, Day}</v> + <v>Time1 = Time2 = {Hour, Min, Sec}</v> + </type> + <desc> + <p>Enables or disables the collection of statistics. If <c>Flag</c> is + <c>get</c>, the statistical collection is returned.</p> + </desc> + </func> + <func> + <name>trace(Name,Flag)</name> + <name>trace(Name,Flag,Timeout) -> void()</name> + <fsummary>Print all system events on <c>standard_io</c></fsummary> + <type> + <v>Flag = boolean()</v> + </type> + <desc> + <p>Prints all system events on <c>standard_io</c>. The events are + formatted with a function that is defined by the process that + generated the event (with a call to + <c>sys:handle_debug/4</c>).</p> + </desc> + </func> + <func> + <name>no_debug(Name)</name> + <name>no_debug(Name,Timeout) -> void()</name> + <fsummary>Turn off debugging</fsummary> + <desc> + <p>Turns off all debugging for the process. This includes + functions that have been installed explicitly with the + <c>install</c> function, for example triggers.</p> + </desc> + </func> + <func> + <name>suspend(Name)</name> + <name>suspend(Name,Timeout) -> void()</name> + <fsummary>Suspend the process</fsummary> + <desc> + <p>Suspends the process. When the process is suspended, it + will only respond to other system messages, but not other + messages.</p> + </desc> + </func> + <func> + <name>resume(Name)</name> + <name>resume(Name,Timeout) -> void()</name> + <fsummary>Resume a suspended process</fsummary> + <desc> + <p>Resumes a suspended process.</p> + </desc> + </func> + <func> + <name>change_code(Name, Module, OldVsn, Extra)</name> + <name>change_code(Name, Module, OldVsn, Extra, Timeout) -> ok | {error, Reason}</name> + <fsummary>Send the code change system message to the process</fsummary> + <type> + <v>OldVsn = undefined | term()</v> + <v>Module = atom()</v> + <v>Extra = term()</v> + </type> + <desc> + <p>Tells the process to change code. The process must be + suspended to handle this message. The <c>Extra</c> argument is + reserved for each process to use as its own. The function + <c>Mod:system_code_change/4</c> is called. <c>OldVsn</c> is + the old version of the <c>Module</c>.</p> + </desc> + </func> + <func> + <name>get_status(Name)</name> + <name>get_status(Name,Timeout) -> {status, Pid, {module, Mod}, [PDict, SysState, Parent, Dbg, Misc]}</name> + <fsummary>Get the status of the process</fsummary> + <type> + <v>PDict = [{Key, Value}]</v> + <v>SysState = running | suspended</v> + <v>Parent = pid()</v> + <v>Dbg = [dbg_opt()]</v> + <v>Misc = term()</v> + </type> + <desc> + <p>Gets the status of the process.</p> + </desc> + </func> + <func> + <name>install(Name,{Func,FuncState})</name> + <name>install(Name,{Func,FuncState},Timeout)</name> + <fsummary>Install a debug function in the process</fsummary> + <type> + <v>Func = dbg_fun()</v> + <v>dbg_fun() = fun(FuncState, Event, ProcState) -> done | NewFuncState</v> + <v>FuncState = term()</v> + <v>Event = system_event()</v> + <v>ProcState = term()</v> + <v>NewFuncState = term()</v> + </type> + <desc> + <p>This function makes it possible to install other debug + functions than the ones defined above. An example of such a + function is a trigger, a function that waits for some + special event and performs some action when the event is + generated. This could, for example, be turning on low level tracing. + </p> + <p><c>Func</c> is called whenever a system event is + generated. This function should return <c>done</c>, or a new + func state. In the first case, the function is removed. It is removed + if the function fails.</p> + </desc> + </func> + <func> + <name>remove(Name,Func)</name> + <name>remove(Name,Func,Timeout) -> void()</name> + <fsummary>Remove a debug function from the process</fsummary> + <type> + <v>Func = dbg_fun()</v> + </type> + <desc> + <p>Removes a previously installed debug function from the + process. <c>Func</c> must be the same as previously + installed.</p> + </desc> + </func> + </funcs> + + <section> + <title>Process Implementation Functions</title> + <p>The following functions are used when implementing a + special process. This is an ordinary process which does not use a + standard behaviour, but a process which understands the standard system messages.</p> + </section> + <funcs> + <func> + <name>debug_options(Options) -> [dbg_opt()]</name> + <fsummary>Convert a list of options to a debug structure</fsummary> + <type> + <v>Options = [Opt]</v> + <v>Opt = trace | log | statistics | {log_to_file, FileName} | {install, {Func, FuncState}}</v> + <v>Func = dbg_fun()</v> + <v>FuncState = term()</v> + </type> + <desc> + <p>This function can be used by a process that initiates a debug + structure from a list of options. The values of the + <c>Opt</c> argument are the same as the corresponding + functions.</p> + </desc> + </func> + <func> + <name>get_debug(Item,Debug,Default) -> term()</name> + <fsummary>Get the data associated with a debug option</fsummary> + <type> + <v>Item = log | statistics</v> + <v>Debug = [dbg_opt()]</v> + <v>Default = term()</v> + </type> + <desc> + <p>This function gets the data associated with a debug option. <c>Default</c> is returned if the + <c>Item</c> is not found. Can be + used by the process to retrieve debug data for printing + before it terminates.</p> + </desc> + </func> + <func> + <name>handle_debug([dbg_opt()],FormFunc,Extra,Event) -> [dbg_opt()]</name> + <fsummary>Generate a system event</fsummary> + <type> + <v>FormFunc = dbg_fun()</v> + <v>Extra = term()</v> + <v>Event = system_event()</v> + </type> + <desc> + <p>This function is called by a process when it generates a system event. <c>FormFunc</c> is a formatting function which is called as <c>FormFunc(Device, Event, Extra)</c> in order to print the events, which is necessary if tracing is activated. <c>Extra</c> is any + extra information which the process needs in the format function, for example the name of the process.</p> + </desc> + </func> + <func> + <name>handle_system_msg(Msg,From,Parent,Module,Debug,Misc)</name> + <fsummary>Take care of system messages</fsummary> + <type> + <v>Msg = term()</v> + <v>From = pid()</v> + <v>Parent = pid()</v> + <v>Module = atom()</v> + <v>Debug = [dbg_opt()]</v> + <v>Misc = term()</v> + </type> + <desc> + <p>This function is used by a process module that wishes to take care of system + messages. The process receives a <c>{system, From, Msg}</c> + message and passes the <c>Msg</c> and <c>From</c> to this + function. + </p> + <p>This function <em>never</em> returns. It calls the function + <c>Module:system_continue(Parent, NDebug, Misc)</c> where the + process continues the execution, or + <c>Module:system_terminate(Reason, Parent, Debug, Misc)</c> if + the process should terminate. The <c>Module</c> must export + <c>system_continue/3</c>, <c>system_terminate/4</c>, and + <c>system_code_change/4</c> (see below). + </p> + <p>The <c>Misc</c> argument can be used to save internal data + in a process, for example its state. It is sent to + <c>Module:system_continue/3</c> or + <c>Module:system_terminate/4</c></p> + </desc> + </func> + <func> + <name>print_log(Debug) -> void()</name> + <fsummary>Print the logged events in the debug structure</fsummary> + <type> + <v>Debug = [dbg_opt()]</v> + </type> + <desc> + <p>Prints the logged system events in the debug structure + using <c>FormFunc</c> as defined when the event was + generated by a call to <c>handle_debug/4</c>.</p> + </desc> + </func> + <func> + <name>Mod:system_continue(Parent, Debug, Misc)</name> + <fsummary>Called when the process should continue its execution</fsummary> + <type> + <v>Parent = pid()</v> + <v>Debug = [dbg_opt()]</v> + <v>Misc = term()</v> + </type> + <desc> + <p>This function is called from <c>sys:handle_system_msg/6</c> when the process + should continue its execution (for example after it has been + suspended). This function never returns.</p> + </desc> + </func> + <func> + <name>Mod:system_terminate(Reason, Parent, Debug, Misc)</name> + <fsummary>Called when the process should terminate</fsummary> + <type> + <v>Reason = term()</v> + <v>Parent = pid()</v> + <v>Debug = [dbg_opt()]</v> + <v>Misc = term()</v> + </type> + <desc> + <p>This function is called from <c>sys:handle_system_msg/6</c> when the process + should terminate. For example, this function is called when + the process is suspended and its parent orders shut-down. + It gives the process a chance to do a clean-up. This function never + returns.</p> + </desc> + </func> + <func> + <name>Mod:system_code_change(Misc, Module, OldVsn, Extra) -> {ok, NMisc}</name> + <fsummary>Called when the process should perform a code change</fsummary> + <type> + <v>Misc = term()</v> + <v>OldVsn = undefined | term()</v> + <v>Module = atom()</v> + <v>Extra = term()</v> + <v>NMisc = term()</v> + </type> + <desc> + <p>Called from <c>sys:handle_system_msg/6</c> when the process + should perform a code change. The code change is used when the + internal data structure has changed. This function + converts the <c>Misc</c> argument to the new data + structure. <c>OldVsn</c> is the <em>vsn</em> attribute of the + old version of the <c>Module</c>. If no such attribute was + defined, the atom <c>undefined</c> is sent.</p> + </desc> + </func> + </funcs> +</erlref> + diff --git a/lib/stdlib/doc/src/timer.xml b/lib/stdlib/doc/src/timer.xml new file mode 100644 index 0000000000..0b6807dd6c --- /dev/null +++ b/lib/stdlib/doc/src/timer.xml @@ -0,0 +1,300 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>timer</title> + <prepared>Sebastian Strollo</prepared> + <responsible>Bjarne Däcker</responsible> + <docno>1</docno> + <approved>Bjarne Däcker</approved> + <checked></checked> + <date>1998-09-09</date> + <rev>D</rev> + <file>timer.sgml</file> + </header> + <module>timer</module> + <modulesummary>Timer Functions</modulesummary> + <description> + <p>This module provides useful functions related to time. Unless otherwise + stated, time is always measured in <c>milliseconds</c>. All + timer functions return immediately, regardless of work carried + out by another process. + </p> + <p>Successful evaluations of the timer functions yield return values + containing a timer reference, denoted <c>TRef</c> below. By using + <c>cancel/1</c>, the returned reference can be used to cancel any + requested action. A <c>TRef</c> is an Erlang term, the contents + of which must not be altered. + </p> + <p>The timeouts are not exact, but should be <c>at least</c> as long + as requested. + </p> + </description> + <funcs> + <func> + <name>start() -> ok</name> + <fsummary>Start a global timer server (named <c>timer_server</c>).</fsummary> + <desc> + <p>Starts the timer server. Normally, the server does not need + to be started explicitly. It is started dynamically if it + is needed. This is useful during development, but in a + target system the server should be started explicitly. Use + configuration parameters for <c>kernel</c> for this.</p> + </desc> + </func> + <func> + <name>apply_after(Time, Module, Function, Arguments) -> {ok, Tref} | {error, Reason}</name> + <fsummary>Apply <c>Module:Function(Arguments)</c>after a specified <c>Time</c>.</fsummary> + <type> + <v>Time = integer() in Milliseconds</v> + <v>Module = Function = atom()</v> + <v>Arguments = [term()]</v> + </type> + <desc> + <p>Evaluates <c>apply(M, F, A)</c> after <c>Time</c> amount of time + has elapsed. Returns <c>{ok, TRef}</c>, or <c>{error, Reason}</c>.</p> + </desc> + </func> + <func> + <name>send_after(Time, Pid, Message) -> {ok, TRef} | {error,Reason}</name> + <name>send_after(Time, Message) -> {ok, TRef} | {error,Reason}</name> + <fsummary>Send <c>Message</c>to <c>Pid</c>after a specified <c>Time</c>.</fsummary> + <type> + <v>Time = integer() in Milliseconds</v> + <v>Pid = pid() | atom()</v> + <v>Message = term()</v> + <v>Result = {ok, TRef} | {error, Reason}</v> + </type> + <desc> + <p></p> + <taglist> + <tag><c>send_after/3</c></tag> + <item> + <p>Evaluates <c>Pid ! Message</c> after <c>Time</c> amount + of time has elapsed. (<c>Pid</c> can also be an atom of a + registered name.) Returns <c>{ok, TRef}</c>, or + <c>{error, Reason}</c>.</p> + </item> + <tag><c>send_after/2</c></tag> + <item> + <p>Same as <c>send_after(Time, self(), Message)</c>.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>exit_after(Time, Pid, Reason1) -> {ok, TRef} | {error,Reason2}</name> + <name>exit_after(Time, Reason1) -> {ok, TRef} | {error,Reason2}</name> + <name>kill_after(Time, Pid)-> {ok, TRef} | {error,Reason2}</name> + <name>kill_after(Time) -> {ok, TRef} | {error,Reason2}</name> + <fsummary>Send an exit signal with <c>Reason</c>after a specified <c>Time</c>.</fsummary> + <type> + <v>Time = integer() in milliseconds</v> + <v>Pid = pid() | atom()</v> + <v>Reason1 = Reason2 = term()</v> + </type> + <desc> + <p></p> + <taglist> + <tag><c>exit_after/3</c></tag> + <item> + <p>Send an exit signal with reason <c>Reason1</c> to Pid + <c>Pid</c>. Returns <c>{ok, TRef}</c>, or + <c>{error, Reason2}</c>.</p> + </item> + <tag><c>exit_after/2</c></tag> + <item> + <p>Same as <c>exit_after(Time, self(), Reason1)</c>. </p> + </item> + <tag><c>kill_after/2</c></tag> + <item> + <p>Same as <c>exit_after(Time, Pid, kill)</c>. </p> + </item> + <tag><c>kill_after/1</c></tag> + <item> + <p>Same as <c>exit_after(Time, self(), kill)</c>. </p> + </item> + </taglist> + </desc> + </func> + <func> + <name>apply_interval(Time, Module, Function, Arguments) -> {ok, TRef} | {error, Reason}</name> + <fsummary>Evaluate <c>Module:Function(Arguments)</c>repeatedly at intervals of <c>Time</c>.</fsummary> + <type> + <v>Time = integer() in milliseconds</v> + <v>Module = Function = atom()</v> + <v>Arguments = [term()]</v> + </type> + <desc> + <p>Evaluates <c>apply(Module, Function, Arguments)</c> repeatedly at + intervals of <c>Time</c>. Returns <c>{ok, TRef}</c>, or + <c>{error, Reason}</c>.</p> + </desc> + </func> + <func> + <name>send_interval(Time, Pid, Message) -> {ok, TRef} | {error, Reason}</name> + <name>send_interval(Time, Message) -> {ok, TRef} | {error, Reason}</name> + <fsummary>Send <c>Message</c>repeatedly at intervals of <c>Time</c>.</fsummary> + <type> + <v>Time = integer() in milliseconds</v> + <v>Pid = pid() | atom()</v> + <v>Message = term()</v> + <v>Reason = term()</v> + </type> + <desc> + <p></p> + <taglist> + <tag><c>send_interval/3</c></tag> + <item> + <p>Evaluates <c>Pid ! Message</c> repeatedly after <c>Time</c> + amount of time has elapsed. (<c>Pid</c> can also be an atom of + a registered name.) Returns <c>{ok, TRef}</c> or + <c>{error, Reason}</c>.</p> + </item> + <tag><c>send_interval/2</c></tag> + <item> + <p>Same as <c>send_interval(Time, self(), Message)</c>.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>cancel(TRef) -> {ok, cancel} | {error, Reason}</name> + <fsummary>Cancel a previously requested timeout identified by <c>TRef</c>.</fsummary> + <desc> + <p>Cancels a previously requested timeout. <c>TRef</c> is a unique + timer reference returned by the timer function in question. Returns + <c>{ok, cancel}</c>, or <c>{error, Reason}</c> when <c>TRef</c> + is not a timer reference.</p> + </desc> + </func> + <func> + <name>sleep(Time) -> ok</name> + <fsummary>Suspend the calling process for <c>Time</c>amount of milliseconds.</fsummary> + <type> + <v>Time = integer() in milliseconds or the atom infinity</v> + </type> + <desc> + <p>Suspends the process calling this function for <c>Time</c> amount + of milliseconds and then returns <c>ok</c>, or suspend the process + forever if <c>Time</c> is the atom <c>infinity</c>. Naturally, this + function does <em>not</em> return immediately.</p> + </desc> + </func> + <func> + <name>tc(Module, Function, Arguments) -> {Time, Value}</name> + <fsummary>Measure the real time it takes to evaluate <c>apply(Module, Function, Arguments)</c></fsummary> + <type> + <v>Module = Function = atom()</v> + <v>Arguments = [term()]</v> + <v>Time = integer() in microseconds</v> + <v>Value = term()</v> + </type> + <desc> + <p>Evaluates <c>apply(Module, Function, Arguments)</c> and measures + the elapsed real time. Returns <c>{Time, Value}</c>, where + <c>Time</c> is the elapsed real time in <em>microseconds</em>, + and <c>Value</c> is what is returned from the apply.</p> + </desc> + </func> + <func> + <name>now_diff(T2, T1) -> Tdiff</name> + <fsummary>Calculate time difference between <c>now/0</c>timestamps</fsummary> + <type> + <v>T1 = T2 = {MegaSecs, Secs, MicroSecs}</v> + <v>Tdiff = MegaSecs = Secs = MicroSecs = integer()</v> + </type> + <desc> + <p>Calculates the time difference <c>Tdiff = T2 - T1</c> in + <em>microseconds</em>, where <c>T1</c> and <c>T2</c> probably + are timestamp tuples returned from <c>erlang:now/0</c>.</p> + </desc> + </func> + <func> + <name>seconds(Seconds) -> Milliseconds</name> + <fsummary>Convert <c>Seconds</c>to <c>Milliseconds</c>.</fsummary> + <desc> + <p>Returns the number of milliseconds in <c>Seconds</c>.</p> + </desc> + </func> + <func> + <name>minutes(Minutes) -> Milliseconds</name> + <fsummary>Converts <c>Minutes</c>to <c>Milliseconds</c>.</fsummary> + <desc> + <p>Return the number of milliseconds in <c>Minutes</c>.</p> + </desc> + </func> + <func> + <name>hours(Hours) -> Milliseconds</name> + <fsummary>Convert <c>Hours</c>to <c>Milliseconds</c>.</fsummary> + <desc> + <p>Returns the number of milliseconds in <c>Hours</c>.</p> + </desc> + </func> + <func> + <name>hms(Hours, Minutes, Seconds) -> Milliseconds</name> + <fsummary>Convert <c>Hours</c>+<c>Minutes</c>+<c>Seconds</c>to <c>Milliseconds</c>.</fsummary> + <desc> + <p>Returns the number of milliseconds in <c>Hours + Minutes + Seconds</c>.</p> + </desc> + </func> + </funcs> + + <section> + <title>Examples</title> + <p>This example illustrates how to print out "Hello World!" in 5 seconds:</p> + <p></p> + <pre> + 1> <input>timer:apply_after(5000, io, format, ["~nHello World!~n", []]).</input> + {ok,TRef} + Hello World!</pre> + <p>The following coding example illustrates a process which performs a + certain action and if this action is not completed within a certain + limit, then the process is killed.</p> + <code type="none"> + Pid = spawn(mod, fun, [foo, bar]), + %% If pid is not finished in 10 seconds, kill him + {ok, R} = timer:kill_after(timer:seconds(10), Pid), + ... + %% We change our mind... + timer:cancel(R), + ...</code> + </section> + + <section> + <title>WARNING</title> + <p>A timer can always be removed by calling <c>cancel/1</c>. + </p> + <p>An interval timer, i.e. a timer created by evaluating any of the + functions <c>apply_interval/4</c>, <c>send_interval/3</c>, and + <c>send_interval/2</c>, is linked to the process towards which + the timer performs its task. + </p> + <p>A one-shot timer, i.e. a timer created by evaluating any of the + functions <c>apply_after/4</c>, <c>send_after/3</c>, + <c>send_after/2</c>, <c>exit_after/3</c>, <c>exit_after/2</c>, + <c>kill_after/2</c>, and <c>kill_after/1</c> is not linked to any + process. Hence, such a timer is removed only when it reaches its + timeout, or if it is explicitly removed by a call to <c>cancel/1</c>.</p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/unicode.xml b/lib/stdlib/doc/src/unicode.xml new file mode 100644 index 0000000000..b3aad51591 --- /dev/null +++ b/lib/stdlib/doc/src/unicode.xml @@ -0,0 +1,311 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>1996</year> + <year>2009</year> + <holder>Ericsson AB, All Rights Reserved</holder> + </copyright> + <legalnotice> + 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. + </legalnotice> + + <title>unicode</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <module>unicode</module> + <modulesummary>Functions for converting Unicode characters</modulesummary> + <description> + <p>This module contains functions for converting between different character representations. Basically it converts between iso-latin-1 characters and Unicode ditto, but it can also convert between different Unicode encodings (like UTF-8, UTF-16 and UTF-32).</p> + <p>The default Unicode encoding in Erlang is in binaries UTF-8, which is also the format in which built in functions and libraries in OTP expect to find binary Unicode data. In lists, Unicode data is encoded as integers, each integer representing one character and encoded simply as the Unicode codepoint for the character.</p> + <p>Other Unicode encodings than integers representing codepoints or UTF-8 in binaries are referred to as "external encodings". The iso-latin-1 encoding is in binaries and lists referred to as latin1-encoding.</p> + <p>It is recommended to only use external encodings for communication with external entities where this is required. When working inside the Erlang/OTP environment, it is recommended to keep binaries in UTF-8 when representing Unicode characters. Latin1 encoding is supported both for backward compatibility and for communication with external entities not supporting Unicode character sets.</p> + </description> + + <section> + <title>DATA TYPES</title> + <marker id="charlist_definition"></marker> + <code type="none"> +unicode_binary() = binary() with characters encoded in UTF-8 coding standard +unicode_char() = integer() representing valid unicode codepoint + +chardata() = charlist() | unicode_binary() + +charlist() = [unicode_char() | unicode_binary() | charlist()] + a unicode_binary is allowed as the tail of the list</code> + + <code type="none"> +external_unicode_binary() = binary() with characters coded in a user specified Unicode encoding other than UTF-8 (UTF-16 or UTF-32) + +external_chardata() = external_charlist() | external_unicode_binary() + +external_charlist() = [unicode_char() | external_unicode_binary() | external_charlist()] + an external_unicode_binary is allowed as the tail of the list</code> + + <code type="none"> +latin1_binary() = binary() with characters coded in iso-latin-1 +latin1_char() = integer() representing valid latin1 character (0-255) + +latin1_chardata() = latin1_charlist() | latin1_binary() + +latin1_charlist() = [latin1_char() | latin1_binary() | latin1_charlist()] + a latin1_binary is allowed as the tail of the list</code> + </section> + <funcs> + <func> + <name>bom_to_encoding(Bin) -> {Encoding,Length}</name> + <fsummary>Identify UTF byte order marks in a binary.</fsummary> + <type> + <v>Bin = binary() of byte_size 4 or more</v> + <v>Encoding = latin1 | utf8 | {utf16,little} | {utf16,big} | {utf32,little} | {utf32,big}</v> + <v>Length = int()</v> + </type> + <desc> + + <p>Check for a UTF byte order mark (BOM) in the beginning of a + binary. If the supplied binary <c>Bin</c> begins with a valid + byte order mark for either UTF-8, UTF-16 or UTF-32, the function + returns the encoding identified along with the length of the BOM + in bytes.</p> + + <p>If no BOM is found, the function returns <c>{latin1,0}</c></p> + </desc> + </func> + <func> + <name>characters_to_list(Data) -> list() | {error, list(), RestData} | {incomplete, list(), binary()} </name> + <fsummary>Convert a collection of characters to list of Unicode characters</fsummary> + <type> + <v>Data = latin1_chardata() | chardata() | external_chardata()</v> + <v>RestData = latin1_chardata() | chardata() | external_chardata()</v> + </type> + <desc> + <p>Same as characters_to_list(Data,unicode).</p> + </desc> + </func> + <func> + <name>characters_to_list(Data, InEncoding) -> list() | {error, list(), RestData} | {incomplete, list(), binary()} </name> + <fsummary>Convert a collection of characters to list of Unicode characters</fsummary> + <type> + <v>Data = latin1_chardata() | chardata() | external_chardata()</v> + <v>RestData = latin1_chardata() | chardata() | external_chardata()</v> + <v>InEncoding = latin1 | unicode | utf8 | utf16 | utf32 | {utf16,little} | {utf16,big} | {utf32,little} | {utf32,big}</v> + </type> + <desc> + + <p>This function converts a possibly deep list of integers and + binaries into a list of integers representing unicode + characters. The binaries in the input may have characters + encoded as latin1 (0 - 255, one character per byte), in which + case the <c>InEncoding</c> parameter should be given as + <c>latin1</c>, or have characters encoded as one of the + UTF-encodings, which is given as the <c>InEncoding</c> + parameter. Only when the <c>InEncoding</c> is one of the UTF + encodings, integers in the list are allowed to be grater than + 255.</p> + + <p>If <c>InEncoding</c> is <c>latin1</c>, the <c>Data</c> parameter + corresponds to the <c>iodata()</c> type, but for <c>unicode</c>, + the <c>Data</c> parameter can contain integers greater than 255 + (unicode characters beyond the iso-latin-1 range), which would + make it invalid as <c>iodata()</c>.</p> + + <p>The purpose of the function is mainly to be able to convert + combinations of unicode characters into a pure unicode + string in list representation for further processing. For + writing the data to an external entity, the reverse function + <seealso + marker="#characters_to_binary/3">characters_to_binary/3</seealso> + comes in handy.</p> + + <p>The option <c>unicode</c> is an alias for <c>utf8</c>, as this is the + preferred encoding for Unicode characters in + binaries. <c>utf16</c> is an alias for <c>{utf16,big}</c> and + <c>utf32</c> is an alias for <c>{utf32,big}</c>. The <c>big</c> + and <c>little</c> atoms denote big or little endian + encoding.</p> + + <p>If for some reason, the data cannot be converted, either + because of illegal unicode/latin1 characters in the list, or + because of invalid UTF encoding in any binaries, an error + tuple is returned. The error tuple contains the tag + <c>error</c>, a list representing the characters that could be + converted before the error occurred and a representation of the + characters including and after the offending integer/bytes. The + last part is mostly for debugging as it still constitutes a + possibly deep and/or mixed list, not necessarily of the same + depth as the original data. The error occurs when traversing the + list and whatever's left to decode is simply returned as is.</p> + + <p>However, if the input <c>Data</c> is a pure binary, the third + part of the error tuple is guaranteed to be a binary as + well.</p> + + <p>Errors occur for the following reasons:</p> + <list type="bulleted"> + + <item>Integers out of range - If <c>InEncoding</c> is + <c>latin1</c>, an error occurs whenever an integer greater + than 255 is found in the lists. If <c>InEncoding</c> is + of a Unicode type, error occurs whenever an integer greater than + <c>16#10FFFF</c> (the maximum unicode character) or in the + range <c>16#D800</c> to <c>16#DFFF</c> (invalid unicode + range) is found.</item> + + <item>UTF encoding incorrect - If <c>InEncoding</c> is + one of the UTF types, the bytes in any binaries have to be valid + in that encoding. Errors can occur for various + reasons, including "pure" decoding errors + (like the upper + bits of the bytes being wrong), the bytes are decoded to a + too large number, the bytes are decoded to a code-point in the + invalid unicode + range or encoding is "overlong", meaning that a + number should have been encoded in fewer bytes. The + case of a truncated UTF is handled specially, see the + paragraph about incomplete binaries below. If + <c>InEncoding</c> is <c>latin1</c>, binaries are always valid + as long as they contain whole bytes, + as each byte falls into the valid iso-latin-1 range.</item> + + </list> + + <p>A special type of error is when no actual invalid integers or + bytes are found, but a trailing <c>binary()</c> consists of too + few bytes to decode the last character. This error might occur + if bytes are read from a file in chunks or binaries in other + ways are split on non UTF character boundaries. In this case an + <c>incomplete</c> tuple is returned instead of the <c>error</c> + tuple. It consists of the same parts as the <c>error</c> tuple, but + the tag is <c>incomplete</c> instead of <c>error</c> and the + last element is always guaranteed to be a binary consisting of + the first part of a (so far) valid UTF character.</p> + + <p>If one UTF characters is split over two consecutive + binaries in the <c>Data</c>, the conversion succeeds. This means + that a character can be decoded from a range of binaries as long + as the whole range is given as input without errors + occurring. Example:</p> + +<code> + decode_data(Data) -> + case unicode:characters_to_list(Data,unicode) of + {incomplete,Encoded, Rest} -> + More = get_some_more_data(), + Encoded ++ decode_data([Rest, More]); + {error,Encoded,Rest} -> + handle_error(Encoded,Rest); + List -> + List + end. +</code> + <p>Bit-strings that are not whole bytes are however not allowed, + so a UTF character has to be split along 8-bit boundaries to + ever be decoded.</p> + + <p>If any parameters are of the wrong type, the list structure + is invalid (a number as tail) or the binaries does not contain + whole bytes (bit-strings), a <c>badarg</c> exception is + thrown.</p> + + </desc> + </func> + <func> + <name>characters_to_binary(Data) -> binary() | {error, binary(), RestData} | {incomplete, binary(), binary()} </name> + <fsummary>Convert a collection of characters to an UTF-8 binary</fsummary> <type> + <v>Data = latin1_chardata() | chardata() | external_chardata()</v> + <v>RestData = latin1_chardata() | chardata() | external_chardata()</v> + </type> + <desc> + <p>Same as characters_to_binary(Data, unicode, unicode).</p> + </desc> + </func> + <func> + <name>characters_to_binary(Data,InEncoding) -> binary() | {error, binary(), RestData} | {incomplete, binary(), binary()} </name> + <fsummary>Convert a collection of characters to an UTF-8 binary</fsummary> <type> + <v>Data = latin1_chardata() | chardata() | external_chardata()</v> + <v>RestData = latin1_chardata() | chardata() | external_chardata()</v> + <v>InEncoding = latin1 | unicode | utf8 | utf16 | utf32 | {utf16,little} | {utf16,big} | {utf32,little} | {utf32,big}</v> + </type> + <desc> + <p>Same as characters_to_binary(Data, InEncoding, unicode).</p> + </desc> + </func> + <func> + <name>characters_to_binary(Data, InEncoding, OutEncoding) -> binary() | {error, binary(), RestData} | {incomplete, binary(), binary()} </name> + <fsummary>Convert a collection of characters to an UTF-8 binary</fsummary> + <type> + <v>Data = latin1_chardata() | chardata() | external_chardata()</v> + <v>RestData = latin1_chardata() | chardata() | external_chardata()</v> + <v>InEncoding = latin1 | unicode | utf8 | utf16 | utf32 | {utf16,little} | {utf16,big} | {utf32,little} | {utf32,big}</v> + <v>OutEncoding = latin1 | unicode | utf8 | utf16 | utf32| {utf16,little} | {utf16,big} | {utf32,little} | {utf32,big}</v> + </type> + <desc> + + <p>This function behaves as <seealso + marker="#characters_to_list/2"> + characters_to_list/2</seealso>, but produces an binary + instead of a unicode list. The + <c>InEncoding</c> defines how input is to be interpreted if + binaries are present in the <c>Data</c>, while + <c>OutEncoding</c> defines in what format output is to be + generated.</p> + + <p>The option <c>unicode</c> is an alias for <c>utf8</c>, as this is the + preferred encoding for Unicode characters in + binaries. <c>utf16</c> is an alias for <c>{utf16,big}</c> and + <c>utf32</c> is an alias for <c>{utf32,big}</c>. The <c>big</c> + and <c>little</c> atoms denote big or little endian + encoding.</p> + + <p>Errors and exceptions occur as in <seealso + marker="#characters_to_list/2"> + characters_to_list/2</seealso>, but the second element + in the <c>error</c> or + <c>incomplete</c> tuple will be a <c>binary()</c> and not a + <c>list()</c>.</p> + + </desc> + </func> + <func> + <name>encoding_to_bom(InEncoding) -> Bin</name> + <fsummary>Create a binary UTF byte order mark from encoding.</fsummary> + <type> + <v>Bin = binary() of byte_size 4 or less</v> + <v>InEncoding = latin1 | unicode | utf8 | utf16 | utf32 | {utf16,little} | {utf16,big} | {utf32,little} | {utf32,big}</v> + <v>Length = int()</v> + </type> + <desc> + + <p>Create an UTF byte order mark (BOM) as a binary from the + supplied <c>InEncoding</c>. The BOM is, if supported at all, + expected to be placed first in UTF encoded files or + messages.</p> + + <p>The function returns <c><<>></c> for the + <c>latin1</c> encoding, there is no BOM for ISO-latin-1.</p> + + <p>It can be noted that the BOM for UTF-8 is seldom used, and it + is really not a <em>byte order</em> mark. There are obviously no + byte order issues with UTF-8, so the BOM is only there to + differentiate UTF-8 encoding from other UTF formats.</p> + + </desc> + </func> + </funcs> +</erlref> diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml new file mode 100644 index 0000000000..06347b3aae --- /dev/null +++ b/lib/stdlib/doc/src/unicode_usage.xml @@ -0,0 +1,289 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>1999</year> + <year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>Using Unicode in Erlang</title> + <prepared>Patrik Nyblom</prepared> + <responsible></responsible> + <docno></docno> + <approved></approved> + <checked></checked> + <date>2009-02-25</date> + <rev>PA1</rev> + <file>unicode_usage.xml</file> + </header> +<p>Implementing support for Unicode character sets is an ongoing process. The Erlang Enhancement Proposal (EEP) 10 outlines the basics of Unicode support and also specifies a default encoding in binaries that all Unicode-aware modules should handle in the future.</p> +<p>The functionality described in EEP10 is implemented in Erlang/OTP as of R13A, but that's by no means the end of it. More functionality will be needed in the future and more OTP-libraries might need updating to cope with Unicode data. One example of future development is obvious when reading this manual, our documentation format is limited to the ISO-latin-1 character range, why no Unicode characters beyond that range will occur in this document.</p> +<p>This guide outlines the current Unicode support and gives a couple of recipes for working with Unicode data.</p> +<section> +<title>What Unicode is</title> +<p>Unicode is a standard defining codepoints (numbers) for all known, living or dead, scripts. In principle, every known symbol used in any language has a Unicode codepoint.</p> +<p>Unicode codepoints are defined and published by the <em>Unicode Consortium</em>, which is a non profit organization.</p> +<p>Support for Unicode is increasing throughout the world of computing, as the benefits of one common character set are overwhelming when programs are used in a global environment.</p> +<p>Along with the base of the standard, the codepoints for all the scripts, there are a couple of encoding standards available. Different operating systems and tools support different encodings. For example Linux and MacOS X has chosen the UTF-8 encoding, which is backwards compatible with 7-bit ASCII and therefore affects programs written in plain English the least. Windows® on the other hand supports a limited version of UTF-16, namely all the code planes where the characters can be stored in one single 16-bit entity, which includes most living languages.</p> +<p>The most widely spread encodings are:</p> +<taglist> +<tag>UTF-8</tag> +<item>Each character is stored in one to four bytes depending on codepoint. The encoding is backwards compatible with 7-bit ASCII as all 7-bit characters are stored in one single byte as is. The characters beyond codepoint 127 are stored in more bytes, letting the most significant bit in the first character indicate a multi-byte character. For details on the encoding, the RFC is publicly available.</item> +<tag>UTF-16</tag> +<item>This encoding has many similarities to UTF-8, but the basic unit is a 16-bit number. This means that all characters occupy at least two bytes, some high numbers even four bytes. Some programs and operating systems claiming to use UTF-16 only allows for characters that can be stored in one 16-bit entity, which is usually sufficient to handle living languages. As the basic unit is more than one byte, byte-order issues occur, why UTF-16 exists in both a big-endian and little-endian variant.</item> +<tag>UTF-32</tag> +<item>The most straight forward representation, each character is stored in one single 32-bit number. There is no need for escapes or any variable amount of entities for one character, all Unicode codepoints can be stored in one single 32-bit entity. As with UTF-16, there are byte-order issues, UTF-32 can be both big- and little-endian.</item> +<tag>UCS-4</tag> +<item>Basically the same as UTF-32, but without some Unicode semantics, defined by IEEE and has little use as a separate encoding standard. For all normal (and possibly abnormal) usages, UTF-32 and UCS-4 are interchangeable.</item> +</taglist> +<p>Certain ranges of characters are left unused and certain ranges are even deemed invalid. The most notable invalid range is 16#D800 - 16#DFFF, as the UTF-16 encoding does not allow for encoding of these numbers. It can be speculated that the UTF-16 encoding standard was, from the beginning, expected to be able to hold all Unicode characters in one 16-bit entity, but then had to be extended, leaving a whole in the Unicode range to cope with backward compatibility.</p> +<p>Additionally, the codepoint 16#FEFF is used for byte order marks (BOM's) and use of that character is not encouraged in other contexts than that. It actually is valid though, as the character "ZWNBS" (Zero Width Non Breaking Space). BOM's are used to identify encodings and byte order for programs where such parameters are not known in advance. Byte order marks are more seldom used than one could expect, put their use is becoming more widely spread as they provide the means for programs to make educated guesses about the Unicode format of a certain file.</p> +</section> +<section> +<title>Standard Unicode representation in Erlang</title> +<p>In Erlang, strings are actually lists of integers. A string is defined to be encoded in the ISO-latin-1 (ISO8859-1) character set, which is, codepoint by codepoint, a sub-range of the Unicode character set.</p> +<p>The standard list encoding for strings is therefore easily extendible to cope with the whole Unicode range: A Unicode string in Erlang is simply a list containing integers, each integer being a valid Unicode codepoint and representing one character in the Unicode character set.</p> +<p>Regular Erlang strings in ISO-latin-1 are a subset of there Unicode strings.</p> + +<p>Binaries on the other hand are more troublesome. For performance reasons, programs often store textual data in binaries instead of lists, mainly because they are more compact (one byte per character instead of two words per character, as is the case with lists). Using erlang:list_to_binary/1, an regular Erlang string can be converted into a binary, effectively using the ISO-latin-1 encoding in the binary - one byte per character. This is very convenient for those regular Erlang strings, but cannot be done for Unicode lists.</p> +<p>As the UTF-8 encoding is widely spread and provides the most compact storage, it is selected as the standard encoding of Unicode characters in binaries for Erlang.</p> +<p>The standard binary encoding is used whenever a library function in Erlang should cope with Unicode data in binaries, but is of course not enforced when communicating externally. Functions and bit-syntax exist to encode and decode both UTF-8, UTF-16 and UTF-32 in binaries. Library functions dealing with binaries and Unicode in general, however, only deal with the default encoding.</p> + +<p>Character data may be combined from several sources, sometimes available in a mix of strings and binaries. Erlang has for long had the concept of iodata or iolists, where binaries and lists can be combined to represent a sequence of bytes. In the same way, the Unicode aware modules often allow for combinations of binaries and lists where the binaries have characters encoded in UTF-8 and the lists contain such binaries or numbers representing Unicode codepoints:</p> +<code type="none"> +unicode_binary() = binary() with characters encoded in UTF-8 coding standard +unicode_char() = integer() representing valid unicode codepoint + +chardata() = charlist() | unicode_binary() + +charlist() = [unicode_char() | unicode_binary() | charlist()] + a unicode_binary is allowed as the tail of the list</code> +<p>The module <c>unicode</c> in stdlib even supports similar mixes with binaries containing other encodings than UTF-8, but that is a special case to allow for conversions to and from external data:</p> + <code type="none"> +external_unicode_binary() = binary() with characters coded in a user specified Unicode encoding other than UTF-8 (UTF-16 or UTF-32) + +external_chardata() = external_charlist() | external_unicode_binary() + +external_charlist() = [unicode_char() | external_unicode_binary() | external_charlist()] + an external_unicode_binary is allowed as the tail of the list</code> +</section> +<section> +<title>Basic language support for Unicode</title> +<p>First of all, Erlang is still defined to be written in the ISO-latin-1 character set. Functions have to be named in that character set, atoms are restricted to ISO-latin-1 and regular strings are still lists of characters 0..255 in the ISO-latin-1 encoding. This has not (yet) changed, but the language has been slightly extended to cope with Unicode characters and encodings.</p> + +<section> +<title>Bit-syntax</title> +<p>The bit-syntax contains types for coping with binary data in the three main encodings. The types are named <c>utf8</c>, <c>utf16</c> and <c>utf32</c> respectively. The <c>utf16</c> and <c>utf32</c> types can be in a big- or little-endian variant:</p> +<code> +<<Ch/utf8,_/binary>> = Bin1, +<<Ch/utf16-little,_/binary>> = Bin2, +Bin3 = <<$H/utf32-little, $e/utf32-little, $l/utf32-little, $l/utf32-little, $o/utf32-little>>,</code> +<p>For convenience, literal strings can be encoded with a Unicode encoding in binaries using the following (or similar) syntax:</p> +<code> +Bin4 = <<"Hello"/utf16>>,</code> +</section> +<section> +<title>String- and character-literals</title> +<warning> +<p>The literal syntax described here may be subject to change in R13B, it has not yet passed the usual process for language changes approval.</p> +</warning> +<p>It is convenient to be able to write a list of Unicode characters in the string syntax. However, the language specifies strings as being in the ISO-latin-1 character set which the compiler tool chain as well as many other tools expect.</p> +<p>Also the source code is (for now) still expected to be written using the ISO-latin-1 character set, why Unicode characters beyond that range cannot be entered in string literals.</p> +<p>To make it easier to enter Unicode characters in the shell, it allows strings with Unicode characters on input, immediately converting them to regular lists of integers. They will, by the evaluator etc be viewed as if they were input using the regular list syntax, which is - in the end - how the language actually treats them. They will in the same way not be output as strings by i.e <c>io:write/2</c> or <c>io:format/3</c> unless the format string supplied to <c>io:format</c> uses the Unicode translation modifier (which we will talk about later).</p> +<p>For source code, there is an extension to the \OOO (backslash followed by three octal numbers) and \xHH (backslash followed by 'x', followed by two hexadecimal characters) syntax, namely \x{H ...} (a backslash followed by an 'x', followed by left curly bracket, any number of hexadecimal digits and a terminating right curly bracket). This allows for entering characters of any codepoint literally in a string. The string is immediately converted into a list by the scanner however, which is obvious when calling it directly:</p> +<pre> +1> <input>erl_scan:string("\"X\".").</input> +{ok,[{string,1,"X"},{dot,1}],1} +2> <input>erl_scan:string("\"\x{400}\".").</input> +{ok,[{'[',1},{integer,1,1024},{']',1},{dot,1}],1}</pre> +<p>Character literals, or rather integers representing Unicode codepoints can be expressed in a similar way using $\x{H ...}:</p> +<pre> +4> <input>$\x{400}.</input> +1024</pre> +<p>This also is a translation by the scanner:</p> +<pre> +5> <input>erl_scan:string("$Y.").</input> +{ok,[{char,1,89},{dot,1}],1} +6> <input>erl_scan:string("$\x{400}.").</input> +{ok,[{integer,1,1024},{dot,1}],1}</pre> +<p>In the shell, if using a Unicode input device, '$' can be followed directly by a Unicode character producing an integer. In the following example, let's imagine the character 'c' is actually a Cyrillic 's' (looking fairly similar):</p> +<pre> +7> <input>$c.</input> +1089</pre> +</section> +<p>The literal syntax allowing Unicode characters is to be viewed as "syntactic sugar", but is, as such, fairly useful.</p> +</section> +<section> +<title>The interactive shell</title> +<p>The interactive Erlang shell, when started towards a terminal or started using the <c>werl</c> command on windows, can support Unicode input and output.</p> +<p>On Windows®, proper operation requires that a suitable font is installed and selected for the Erlang application to use. If no suitable font is available on your system, try installing the DejaVu fonts (dejavu-fonts.org), which are freely available and then select that font in the Erlang shell application.</p> +<p>On Unix®-like operating systems, the terminal should be able to handle UTF-8 on input and output (modern versions of XTerm, KDE konsole and the Gnome terminal do for example) and your locale settings have to be proper. As an example, my LANG environment variable is set as this:</p> +<pre> +$ <input>echo $LANG</input> +en_US.UTF-8</pre> +<p>Actually, most systems handle the LC_CTYPE variable before LANG, so if that is set, it has to be set to UTF-8:</p> +<pre> +$ echo <input>$LC_CTYPE</input> +en_US.UTF-8</pre> +<p>The LANG or LC_CTYPE setting should be consistent with what the terminal is capable of, there is no portable way for Erlang to ask the actual terminal about it's UTF-8 capacity, we have to rely on the language and character type settings.</p> +<p>To investigate what Erlang thinks about the terminal, the <c>io:getopts()</c> call can be used when the shell is started:</p> +<pre> +$ <input>LC_CTYPE=en_US.ISO-8859-1 erl</input> +Erlang R13A (erts-5.7) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false] + +Eshell V5.7 (abort with ^G) +1> <input>lists:keyfind(encoding,1,io:getopts()).</input> +{encoding,latin1} +2> <input>q().</input> +ok +$ <input>LC_CTYPE=en_US.UTF-8 erl</input> +Erlang R13A (erts-5.7) [source] [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false] + +Eshell V5.7 (abort with ^G) +1> <input>lists:keyfind(encoding,1,io:getopts()).</input> +{encoding,unicode} +2></pre> +<p>When (finally?) everything is in order with the locale settings, fonts and the terminal emulator, you probably also have discovered a way to input characters in the script you desire. For testing, the simplest way is to add some keyboard mappings for other languages, usually done with some applet in your desktop environment. In my KDE environment, I start the KDE Control Center (Personal Settings), select "Regional and Accessibility" and then "Keyboard Layout". On Windows XP®, I start Control Panel->Regional and Language Options, select the Language tab and click the Details... button in the square named "Text services and input Languages". Your environment probably provides similar means of changing the keyboard layout. Make sure you have a way to easily switch back and forth between keyboards if you are not used to this, entering commands using a Cyrillic character set is, as an example, not easily done in the Erlang shell.</p> +<p>Now you are set up for some Unicode input and output. The simplest thing to do is of course to enter a string in the shell:</p> +<image file="ushell1.gif"><icaption>Cyrillic characters in an Erlang shell</icaption></image> +<p>While strings can be input as Unicode characters, the language elements are still limited to the ISO-latin-1 character set. Only character constants and strings are allowed to be beyond that range:</p> +<image file="ushell2.gif"><icaption>Unicode characters in allowed and disallowed context</icaption></image> +</section> +<section> +<title>Unicode-aware modules</title> +<p>Most of the modules in Erlang/OTP are of course Unicode-unaware in the sense that they have no notion of Unicode and really shouldn't have. Typically they handle non-textual or byte-oriented data (like <c>gen_tcp</c> etc).</p> +<p>Modules that actually handle textual data (like <c>io_lib</c>, <c>string</c> etc) are sometimes subject to conversion or extension to be able to handle Unicode characters.</p> +<p>Fortunately, most textual data has been stored in lists and range checking has been sparse, why modules like <c>string</c> works well for Unicode lists with little need for conversion or extension.</p> +<p>Some modules are however changed to be explicitly Unicode-aware. These modules include:</p> +<taglist> +<tag><c>unicode</c></tag> +<item> +<p>The module <seealso marker="stdlib:unicode">unicode</seealso> is obviously Unicode-aware. It contains functions for conversion between different Unicode formats as well as some utilities for identifying byte order marks. Few programs handling Unicode data will survive without this module.</p> +</item> +<tag><c>io</c></tag> +<item> +<p>The <seealso marker="stdlib:io">io</seealso> module has been extended along with the actual I/O-protocol to handle Unicode data. This means that several functions require binaries to be in UTF-8 and there are modifiers to formatting control sequences to allow for outputting of Unicode strings.</p> +</item> +<tag><c>file</c>, <c>group</c> and <c>user</c></tag> +<item> +<p>I/O-servers throughout the system are able both to handle Unicode data and has options for converting data upon actual output or input to/from the device. As shown earlier, the <seealso marker="stdlib:shell">shell</seealso> has support for Unicode terminals and the <seealso marker="kernel:file">file</seealso> module allows for translation to and from various Unicode formats on disk.</p> +<p>The actual reading and writing of files with Unicode data is however not best done with the <c>file</c> module as it's interface is byte oriented. A file opened with a Unicode encoding (like UTF-8), is then best read or written using the <seealso marker="stdlib:io">io</seealso> module.</p> +</item> +<tag><c>re</c></tag> +<item> +<p>The <seealso marker="stdlib:re">re</seealso> module allows for matching Unicode strings as a special option. As the library is actually centered on matching in binaries, the Unicode support is UTF-8-centered.</p> +</item> +<tag><c>wx</c></tag> +<item> +<p>The <seealso marker="wx:wx">wx</seealso> graphical library has extensive support for Unicode text</p> +</item> +</taglist> +<p>The module <seealso marker="stdlib:string">string</seealso> works perfect for Unicode strings as well as for ISO-latin-1 strings with the exception of the language-dependent <seealso marker="stdlib:string#to_upper/1">to_upper</seealso> and <seealso marker="stdlib:string#to_lower/1">to_lower</seealso> functions, which are only correct for the ISO-latin-1 character set. Actually they can never function correctly for Unicode characters in their current form, there are language and locale issues as well as multi-character mappings to consider when conversion text between cases. Converting case in an international environment is a big subject not yet addressed in OTP.</p> +</section> +<section> +<title>Unicode recipes</title> +<p>When starting with Unicode, one often stumbles over some common issues. I try to outline some methods of dealing with Unicode data in this section.</p> +<section> +<title>Byte order marks</title> +<p>A common method of identifying encoding in text-files is to put a byte order mark (BOM) first in the file. The BOM is the codepoint 16#FEFF encoded in the same way as the rest of the file. If such a file is to be read, the first few bytes (depending on encoding) is not part of the actual text. This code outlines how to open a file which is believed to have a BOM and set the files encoding and position for further sequential reading (preferably using the <seealso marker="stdlib:io">io</seealso> module). Note that error handling is omitted from the code:</p> +<code> +open_bom_file_for_reading(File) -> + {ok,F} = file:open(File,[read,binary]), + {ok,Bin} = file:read(F,4), + {Type,Bytes} = unicode:bom_to_encoding(Bin), + file:position(F,Bytes), + io:setopts(F,[{encoding,Type}]), + {ok,F}. +</code> +<p>The <c>unicode:bom_to_encoding/1</c> function identifies the encoding from a binary of at least four bytes. It returns, along with an term suitable for setting the encoding of the file, the actual length of the BOM, so that the file position can be set accordingly. Note that <c>file:position</c> always works on byte-offsets, so that the actual byte-length of the BOM is needed.</p> +<p>To open a file for writing and putting the BOM first is even simpler:</p> +<code> +open_bom_file_for_writing(File,Encoding) -> + {ok,F} = file:open(File,[write,binary]), + ok = file:write(File,unicode:encoding_to_bom(Encoding)), + io:setopts(F,[{encoding,Encoding}]), + {ok,F}. +</code> +<p>In both cases the file is then best processed using the <c>io</c> module, as the functions in <c>io</c> can handle codepoints beyond the ISO-latin-1 range.</p> +</section> +<section> +<title>Formatted input and output</title> +<p>When reading and writing to Unicode-aware entities, like the User or a file opened for Unicode translation, you will probably want to format text strings using the functions in <seealso marker="stdlib:io">io</seealso> or <seealso marker="stdlib:io_lib">io_lib</seealso>. For backward compatibility reasons, these functions don't accept just any list as a string, but require e special "translation modifier" when working with Unicode texts. The modifier is "t". When applied to the "s" control character in a formatting string, it accepts all Unicode codepoints and expect binaries to be in UTF-8:</p> +<pre> +1> <input>io:format("~ts~n",[<<"���"/utf8>>]).</input> +��� +ok +2> <input>io:format("~s~n",[<<"���"/utf8>>]).</input> +åäö +ok</pre> +<p>Obviously the second <c>io:format</c> gives undesired output because the UTF-8 binary is not in latin1. Because ISO-latin-1 is still the defined character set of Erlang, the non prefixed "s" control character expects ISO-latin-1 in binaries as well as lists.</p> +<p>As long as the data is always lists, the "t" modifier can be used for any string, but when binary data is involved, care must be taken to make the tight choice of formatting characters.</p> +<p>The function <c>format</c> in <c>io_lib</c> behaves similarly. This function is defined to return a deep list of characters and the output could easily be converted to binary data for outputting on a device of any kind by a simple <c>erlang:list_to_binary</c>. When the translation modifier is used, the list can however contain characters that cannot be stored in one byte. The call to <c>erlang:list_to_binary</c> will in that case fail. However, if the io_server you want to communicate with is Unicode-aware, the list returned can still be used directly:</p> +<image file="ushell3.gif"><icaption>io_lib:format with Unicode translation</icaption></image> +<p>The Unicode string is returned as a Unicode list, why the return value of <c>io_lib:format</c> no longer qualifies as a regular Erlang string (the function <seealso marker="stdlib:io_lib#deep_char_list/1">io_lib:deep_char_list</seealso> will, as an example, return <c>false</c>). The Unicode list is however valid input to the <seealso marker="stdlib:io#put_chars/2">io:put_chars</seealso> function, so data can be output on any Unicode capable device anyway. If the device is a terminal, characters will be output in the \x{H ...} format if encoding is <c>latin1</c> otherwise in UTF-8 (for the non-interactive terminal - "oldshell" or "noshell") or whatever is suitable to show the character properly (for an interactive terminal - the regular shell). The bottom line is that you can always send Unicode data to the <c>standard_io</c> device. Files will however only accept Unicode codepoints beyond ISO-latin-1 if <c>encoding</c> is set to something else than <c>latin1</c>.</p> +</section> +<section> +<title>Heuristic identification of UTF-8</title> +<p>While it's strongly encouraged that the actual encoding of characters in binary data is known prior to processing, that is not always possible. On a typical Linux® system, there is a mix of UTF-8 and ISO-latin-1 text files and there are seldom any BOM's in the files to identify them.</p> +<p>UTF-8 is designed in such a way that ISO-latin-1 characters with numbers beyond the 7-bit ASCII range are seldom considered valid when decoded as UTF-8. Therefore one can usually use heuristics to determine if a file is in UTF-8 or if it is encoded in ISO-latin-1 (one byte per character) encoding. The <c>unicode</c> module can be used to determine if data can be interpreted as UTF-8:</p> +<code> +heuristic_encoding_bin(Bin) when is_binary(Bin) -> + case unicode:characters_to_binary(Bin,utf8,utf8) of + Bin -> + utf8; + _ -> + latin1 + end. +</code> +<p>If one does not have a complete binary of the file content, one could instead chunk through the file and check part by part. The return-tuple <c>{incomplete,Decoded,Rest}</c> from <c>unicode:characters_to_binary/{1,2,3}</c> comes in handy. The incomplete rest from one chunk of data read from the file is prepended to the next chunk and we therefore circumvent the problem of character boundaries when reading chunks of bytes in UTF-8 encoding:</p> +<code> +heuristic_encoding_file(FileName) -> + {ok,F} = file:open(FileName,[read,binary]), + loop_through_file(F,<<>>,file:read(F,1024)). + +loop_through_file(_,<<>>,eof) -> + utf8; +loop_through_file(_,_,eof) -> + latin1; +loop_through_file(F,Acc,{ok,Bin}) when is_binary(Bin) -> + case unicode:characters_to_binary([Acc,Bin]) of + {error,_,_} -> + latin1; + {incomplete,_,Rest} -> + loop_through_file(F,Rest,file:read(F,1024)); + Res when is_binary(Res) -> + loop_through_file(F,<<>>,file:read(F,1024)) + end. +</code> +<p>Another option is to try to read the whole file in utf8 encoding and see if it fails. Here we need to read the file using <c>io:get_chars/3</c>, as we have to succeed in reading characters with a codepoint over 255:</p> +<code> +heuristic_encoding_file2(FileName) -> + {ok,F} = file:open(FileName,[read,binary,{encoding,utf8}]), + loop_through_file2(F,io:get_chars(F,'',1024)). + +loop_through_file2(_,eof) -> + utf8; +loop_through_file2(_,{error,_Err}) -> + latin1; +loop_through_file2(F,Bin) when is_binary(Bin) -> + loop_through_file2(F,io:get_chars(F,'',1024)). +</code> +</section> +</section> +</chapter> diff --git a/lib/stdlib/doc/src/user_guide.gif b/lib/stdlib/doc/src/user_guide.gif Binary files differnew file mode 100644 index 0000000000..e6275a803d --- /dev/null +++ b/lib/stdlib/doc/src/user_guide.gif diff --git a/lib/stdlib/doc/src/ushell1.gif b/lib/stdlib/doc/src/ushell1.gif Binary files differnew file mode 100644 index 0000000000..7c46464fd2 --- /dev/null +++ b/lib/stdlib/doc/src/ushell1.gif diff --git a/lib/stdlib/doc/src/ushell1.ps b/lib/stdlib/doc/src/ushell1.ps new file mode 100644 index 0000000000..95bfebf194 --- /dev/null +++ b/lib/stdlib/doc/src/ushell1.ps @@ -0,0 +1,1196 @@ +%!PS-Adobe-3.0 +%%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner +%%Title: ushell1.ps +%%CreationDate: Mon Mar 16 09:53:27 2009 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%Pages: 1 +%%BoundingBox: 14 14 468 142 +%%EndComments +%%BeginProlog +% Use own dictionary to avoid conflicts +10 dict begin +%%EndProlog +%%Page: 1 1 +% Translate for offset +14.173228346456694 14.173228346456694 translate +% Translate to begin of first scanline +0 127.55905511811024 translate +453.54330708661422 -127.55905511811024 scale +% Image geometry +640 180 8 +% Transformation matrix +[ 640 0 0 180 0 0 ] +% Strings to hold RGB-samples per scanline +/rstr 640 string def +/gstr 640 string def +/bstr 640 string def +{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop} +{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop} +{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop} +true 3 +%%BeginData: 67571 ASCII Bytes +colorimage +JP1PeJP1PeJP1L~> +JP1PeJP1PeJP1L~> +JP1PeJP1PeJP1L~> +!!e'9JNA?CJNABDJ,~> +!!e'9JNA?CJNABDJ,~> +!!e'9JNA?CJNABDJ,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$2%<!Lr-2rr]6=Dt\b^JcC<$JcD\KJ,~> +!$2%<!Lr-2rr]6=Dt\b^JcC<$JcD\KJ,~> +!$2%<!Lr-2rr]6=Dt\b^JcC<$JcD\KJ,~> +#9EjEY>Q6)=6BMbc`J;XJcC<$JcC<$W;hA~> +#9EjEY>Q6)=6BMbc`J;XJcC<$JcC<$W;hA~> +#9EjEY>Q6)=6BMbc`J;XJcC<$JcC<$W;hA~> +#T`rUH-/@H`Dbmu!A3bks+13$s+13Ks*t~> +#T`rUH-/@H`Dbmu!A3bks+13$s+13Ks*t~> +#T`rUH-/@H`Dbmu!A3bks+13$s+13Ks*t~> +#T`rEG5Y4]rp0@Z!W@cP*=4P!s-oDP9H?1krVlmMmt(Lis+13$s/>sJ~> +#T`rEG5Y4]rp0@Z!W@cP*=4P!s-oDP9H?1krVlmMmt(Lis+13$s/>sJ~> +#T`rEG5Y4]rp0@Z!W@cP*=4P!s-oDP9H?1krVlmMmt(Lis+13$s/>sJ~> +#9EjER>jY@r:g3lQA5D=$0F2Hs)Ak%s4op<rrF_?JcC<$JcC<$W;hA~> +#9EjER>jY@r:g3lQA5D=$0F2Hs)Ak%s4op<rrF_?JcC<$JcC<$W;hA~> +#9EjER>jY@r:g3lQA5D=$0F2Hs)Ak%s4op<rrF_?JcC<$JcC<$W;hA~> +!$2(="-F9Q\G-"(Q=^'2$*?/ds)G.?s5e.srrF_?JcC<$JcC<$W;hA~> +!$2(="-F9Q\G-"(Q=^'2$*?/ds)G.?s5e.srrF_?JcC<$JcC<$W;hA~> +!$2(="-F9Q\G-"(Q=^'2$*?/ds)G.?s5e.srrF_?JcC<$JcC<$W;hA~> +!$2%<"&I0WZ2">"Q8&8B"FpIOENK!9!A3bks+13$s+13Ks*t~> +!$2%<"&I0WZ2">"Q8&8B"FpIOENK!9!A3bks+13$s+13Ks*t~> +!$2%<"&I0WZ2">"Q8&8B"FpIOENK!9!A3bks+13$s+13Ks*t~> +#T`rq^Ah!RpEo\8!LAK:rrI,@q>UIImt(Lis+13$s/>sJ~> +#T`rq^Ah!RpEo\8!LAK:rrI,@q>UIImt(Lis+13$s/>sJ~> +#T`rq^Ah!RpEo\8!LAK:rrI,@q>UIImt(Lis+13$s/>sJ~> +#T`s"JSH?.CSgh+!RuStC&iMXrrI,@qu6esC(k*/JcC<$JcC<$WW.J~> +#T`s"JSH?.CSgh+!RuStC&iMXrrI,@qu6esC(k*/JcC<$JcC<$WW.J~> +#T`s"JSH?.CSgh+!RuStC&iMXrrI,@qu6esC(k*/JcC<$JcC<$WW.J~> +#9EjEgp/o#[J'V#fD`&U])M^1eE6Z.!7LkP!5F*bJcC<$JcD_LJ,~> +#9EjEgp/o#[J'V#fD`&U])M^1eE6Z.!7LkP!5F*bJcC<$JcD_LJ,~> +#9EjEgp/o#[J'V#fD`&U])M^1eE6Z.!7LkP!5F*bJcC<$JcD_LJ,~> +!$2%<!T*O$s+13$s+13+s*t~> +!$2%<!T*O$s+13$s+13+s*t~> +!$2%<!T*O$s+13$s+13+s*t~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$.X1!VbZgrrMcToD\g]rn%5Fci4"4rn%5Kp&>-Vf\#!)rr_95f\lE%"5DJ\kK!T&r;P=KmIgJZ +p&<SDo\]ZKoD[ABp@\Fcm/GW;rJ1CTgXt0Ap&>$hrn%5=kPp&~> +!$.X1!VbZgrrMcToD\g]rn%5Fci4"4rn%5Kp&>-Vf\#!)rr_95f\lE%"5DJ\kK!T&r;P=KmIgJZ +p&<SDo\]ZKoD[ABp@\Fcm/GW;rJ1CTgXt0Ap&>$hrn%5=kPp&~> +!$.X1!VbZgrrMcToD\g]rn%5Fci4"4rn%5Kp&>-Vf\#!)rr_95f\lE%"5DJ\kK!T&r;P=KmIgJZ +p&<SDo\]ZKoD[ABp@\Fcm/GW;rJ1CTgXt0Ap&>$hrn%5=kPp&~> +!Zh=)r4;sJp\t?M]=[dnrrC^M])^+RrrBt8rrCOG])^O`rrN,;oD\mfUOUkp!5JHD!:K[_!<2l- +"nM]nb];P3rrf;C6q#_Srrf>i6k8JSrrZO_6rs9d"4Ffn`;BQ8r5SL2!SZc5rrL6To`##66p3I# +rrWs'7#p%%s5ESL#i+SBs6i?D-]@Zt"M5R?7*O]k#gN&Bs2.5m(WQ.J"Fqsi7/+e&!SceorrM<; +mf3=!!7LiG"&[email protected])jpjdIXT/=<lMlA~> +!Zh=)r4;sJp\t?M]=[dnrrC^M])^+RrrBt8rrCOG])^O`rrN,;oD\mfUOUkp!5JHD!:K[_!<2l- +"nM]nb];P3rrf;C6q#_Srrf>i6k8JSrrZO_6rs9d"4Ffn`;BQ8r5SL2!SZc5rrL6To`##66p3I# +rrWs'7#p%%s5ESL#i+SBs6i?D-]@Zt"M5R?7*O]k#gN&Bs2.5m(WQ.J"Fqsi7/+e&!SceorrM<; +mf3=!!7LiG"&[email protected])jpjdIXT/=<lMlA~> +!Zh=)r4;sJp\t?M]=[dnrrC^M])^+RrrBt8rrCOG])^O`rrN,;oD\mfUOUkp!5JHD!:K[_!<2l- +"nM]nb];P3rrf;C6q#_Srrf>i6k8JSrrZO_6rs9d"4Ffn`;BQ8r5SL2!SZc5rrL6To`##66p3I# +rrWs'7#p%%s5ESL#i+SBs6i?D-]@Zt"M5R?7*O]k#gN&Bs2.5m(WQ.J"Fqsi7/+e&!SceorrM<; +mf3=!!7LiG"&[email protected])jpjdIXT/=<lMlA~> +"!.E>/H&uWGk_4?XC2t&hZ!Um6iLKpEPqeU!Nm==rrAJc@0&Z7rr3%sBt![6!U2E,rrMo!m/I&" +r*]TWq>UHor*]UHci3qFSUgA4!NC.^rrFq?p&>%u_#438a`V$#Fo21>SLO=5!Hk=9rrIX^qu6]" +qYL3mju2l3!$0bm!oI+@o`#!G9q_Fa!Ki<5rrK`?iVrtr.,4\"!ER55rrIY@bPqUQnGW@fGGa6s +!Mju/rrf?1@<TfkrrKf@p&>'T2Z3RT*U<ZT~> +"!.E>/H&uWGk_4?XC2t&hZ!Um6iLKpEPqeU!Nm==rrAJc@0&Z7rr3%sBt![6!U2E,rrMo!m/I&" +r*]TWq>UHor*]UHci3qFSUgA4!NC.^rrFq?p&>%u_#438a`V$#Fo21>SLO=5!Hk=9rrIX^qu6]" +qYL3mju2l3!$0bm!oI+@o`#!G9q_Fa!Ki<5rrK`?iVrtr.,4\"!ER55rrIY@bPqUQnGW@fGGa6s +!Mju/rrf?1@<TfkrrKf@p&>'T2Z3RT*U<ZT~> +"!.E>/H&uWGk_4?XC2t&hZ!Um6iLKpEPqeU!Nm==rrAJc@0&Z7rr3%sBt![6!U2E,rrMo!m/I&" +r*]TWq>UHor*]UHci3qFSUgA4!NC.^rrFq?p&>%u_#438a`V$#Fo21>SLO=5!Hk=9rrIX^qu6]" +qYL3mju2l3!$0bm!oI+@o`#!G9q_Fa!Ki<5rrK`?iVrtr.,4\"!ER55rrIY@bPqUQnGW@fGGa6s +!Mju/rrf?1@<TfkrrKf@p&>'T2Z3RT*U<ZT~> +"!.E>Fn#D352P/r!Go">rs$)Ds8SmD(]"(;jFF`>s."Z-J$8PF!JQp-rrML@m/I&+mf*?sJ*6h2 +!mQ8Ap&>&lF34F_1[4T4!F<M>rrU8keG9+GR!:(SrrI8?nc&V>o(r@eju2l3!$0en"6=u%O7iMT +gjhP\r;Qe[MtR)N]4'_!"297-g\h'P<lXh4!J$`arrGO?rVlnBVV_=RUj2D/#+pAEs3lJ>rVlo3 [email protected]#ju3/;!$1A)J,~> +"!.E>Fn#D352P/r!Go">rs$)Ds8SmD(]"(;jFF`>s."Z-J$8PF!JQp-rrML@m/I&+mf*?sJ*6h2 +!mQ8Ap&>&lF34F_1[4T4!F<M>rrU8keG9+GR!:(SrrI8?nc&V>o(r@eju2l3!$0en"6=u%O7iMT +gjhP\r;Qe[MtR)N]4'_!"297-g\h'P<lXh4!J$`arrGO?rVlnBVV_=RUj2D/#+pAEs3lJ>rVlo3 [email protected]#ju3/;!$1A)J,~> +"!.E>Fn#D352P/r!Go">rs$)Ds8SmD(]"(;jFF`>s."Z-J$8PF!JQp-rrML@m/I&+mf*?sJ*6h2 +!mQ8Ap&>&lF34F_1[4T4!F<M>rrU8keG9+GR!:(SrrI8?nc&V>o(r@eju2l3!$0en"6=u%O7iMT +gjhP\r;Qe[MtR)N]4'_!"297-g\h'P<lXh4!J$`arrGO?rVlnBVV_=RUj2D/#+pAEs3lJ>rVlo3 [email protected]#ju3/;!$1A)J,~> +"!.E>Fo21B`NfH(A8hDG!C#B=rrB%tA-dJ\s0]Y*A7U/grro!)A9-Unq#:A2Yl=Y,]4(`5N:.e` +rsS:7]`8"tO7rV9LTgFO!$1t:!-S9O&?Pp3K(J/9A?l17I9dLsA@MR<!+u4@!5/(+!?L;$A,sX@ +rrHo@r;QeISb<!`WH8";!8%0["6KR_df!\YlMob-rr3C]n,M+2s.s7:o`+s/rF?$+s8Th3A,uW, +rrFq?p&>%u_#=96O,`u8"-Sf5.JNiGFf1%+A;L6b!gR;1rVm%pA.`0ZP5P=\ju2l3!$1t:!.4]U% +&a.*Lh(\`A?>h2KC/YK!3uM&!omgerVm#hE4h0krVlrPA?Pn2"QaaBIA$N<!Ki<5rrK`?rVm2rJ +cEJqAD7(`h>Updc%Y]errTT=df'1K_1:6*g\h'P<lXh4!J$a=rrBe3A-;i2s1/,>"DIi8`ioCA# +^67J_6fbDA97bM!36$/!-n8<'sV9g<Fg^]s*(>sA7UJqs/40BEb(..rrA/[A,qbkrr@uVA,qqpr +s4?iA;[1-s8RZLA,r>%rrVe&PlC[`45p2=!K3->rrKf@p&>'T2Z3RT*W?!?Us]5;rF?8Ss8R9Bc +X^S/s8RT~> +"!.E>Fo21B`NfH(A8hDG!C#B=rrB%tA-dJ\s0]Y*A7U/grro!)A9-Unq#:A2Yl=Y,]4(`5N:.e` +rsS:7]`8"tO7rV9LTgFO!$1t:!-S9O&?Pp3K(J/9A?l17I9dLsA@MR<!+u4@!5/(+!?L;$A,sX@ +rrHo@r;QeISb<!`WH8";!8%0["6KR_df!\YlMob-rr3C]n,M+2s.s7:o`+s/rF?$+s8Th3A,uW, +rrFq?p&>%u_#=96O,`u8"-Sf5.JNiGFf1%+A;L6b!gR;1rVm%pA.`0ZP5P=\ju2l3!$1t:!.4]U% +&a.*Lh(\`A?>h2KC/YK!3uM&!omgerVm#hE4h0krVlrPA?Pn2"QaaBIA$N<!Ki<5rrK`?rVm2rJ +cEJqAD7(`h>Updc%Y]errTT=df'1K_1:6*g\h'P<lXh4!J$a=rrBe3A-;i2s1/,>"DIi8`ioCA# +^67J_6fbDA97bM!36$/!-n8<'sV9g<Fg^]s*(>sA7UJqs/40BEb(..rrA/[A,qbkrr@uVA,qqpr +s4?iA;[1-s8RZLA,r>%rrVe&PlC[`45p2=!K3->rrKf@p&>'T2Z3RT*W?!?Us]5;rF?8Ss8R9Bc +X^S/s8RT~> +"!.E>Fo21B`NfH(A8hDG!C#B=rrB%tA-dJ\s0]Y*A7U/grro!)A9-Unq#:A2Yl=Y,]4(`5N:.e` +rsS:7]`8"tO7rV9LTgFO!$1t:!-S9O&?Pp3K(J/9A?l17I9dLsA@MR<!+u4@!5/(+!?L;$A,sX@ +rrHo@r;QeISb<!`WH8";!8%0["6KR_df!\YlMob-rr3C]n,M+2s.s7:o`+s/rF?$+s8Th3A,uW, +rrFq?p&>%u_#=96O,`u8"-Sf5.JNiGFf1%+A;L6b!gR;1rVm%pA.`0ZP5P=\ju2l3!$1t:!.4]U% +&a.*Lh(\`A?>h2KC/YK!3uM&!omgerVm#hE4h0krVlrPA?Pn2"QaaBIA$N<!Ki<5rrK`?rVm2rJ +cEJqAD7(`h>Updc%Y]errTT=df'1K_1:6*g\h'P<lXh4!J$a=rrBe3A-;i2s1/,>"DIi8`ioCA# +^67J_6fbDA97bM!36$/!-n8<'sV9g<Fg^]s*(>sA7UJqs/40BEb(..rrA/[A,qbkrr@uVA,qqpr +s4?iA;[1-s8RZLA,r>%rrVe&PlC[`45p2=!K3->rrKf@p&>'T2Z3RT*W?!?Us]5;rF?8Ss8R9Bc +X^S/s8RT~> +"!.E>+oY"=nGiOLJ4Q':Y\F(9!C#B=rrC[M[h5T^s+Mqh\$r2\s.PF]\#s&_q#:A21B'fKA^g\. +li/"%rrth%K`D'Nb5VDAU3cP5!$2";!HG1>[hOJ#s2@f;\$pmts21i\\$t2ns'E/5[fL`lq#:@. +>Q2)4ER=CY!i_%@r;QeISb<!`WH8%<!Tdkj[f]k-he;tt"'>BB;Z?\)39C2.O@Y5;[oi[TF8`QM +>5uWerO2c3r;QdRl1P&W?,6F="cnXr84[+erreOOo(+=)rsNs&T!u2#L]@D"[ho#C"k:"&Y.)XQ +rrM7?o`"n3r;QeBVuF.6Lo^P:UT.b3KX(P47fKjtJ@GOX!mgp]rVm"#a8_-[rVlr7!.+YE"nc'C +s*^R<rrJ7?p&>')@K$34qP-T)\$ol2lsTh%!c/D1rr3%Q!4Dh+"j;#Cs$>E;rrH0?p&>&CSc&Kf +iVg4f>lVWdrjN$<@K3$Jrr3BIs8SH4NjlL"D?$enrjMp-F85bQgUAo,\&JCIG;#Mr\"8?Sen[gZ +\!r?VOdQ-W"IG;Os2k8L%$R(YKV,`_S1]'dI\ZnO!K<iRrrVKd:]C@p45p2=!K3->rrKf@p&>'T +2Z3R\*WQ/Q8;ZX3=oGf:EmOcj88>WCDUnc;~> +"!.E>+oY"=nGiOLJ4Q':Y\F(9!C#B=rrC[M[h5T^s+Mqh\$r2\s.PF]\#s&_q#:A21B'fKA^g\. +li/"%rrth%K`D'Nb5VDAU3cP5!$2";!HG1>[hOJ#s2@f;\$pmts21i\\$t2ns'E/5[fL`lq#:@. +>Q2)4ER=CY!i_%@r;QeISb<!`WH8%<!Tdkj[f]k-he;tt"'>BB;Z?\)39C2.O@Y5;[oi[TF8`QM +>5uWerO2c3r;QdRl1P&W?,6F="cnXr84[+erreOOo(+=)rsNs&T!u2#L]@D"[ho#C"k:"&Y.)XQ +rrM7?o`"n3r;QeBVuF.6Lo^P:UT.b3KX(P47fKjtJ@GOX!mgp]rVm"#a8_-[rVlr7!.+YE"nc'C +s*^R<rrJ7?p&>')@K$34qP-T)\$ol2lsTh%!c/D1rr3%Q!4Dh+"j;#Cs$>E;rrH0?p&>&CSc&Kf +iVg4f>lVWdrjN$<@K3$Jrr3BIs8SH4NjlL"D?$enrjMp-F85bQgUAo,\&JCIG;#Mr\"8?Sen[gZ +\!r?VOdQ-W"IG;Os2k8L%$R(YKV,`_S1]'dI\ZnO!K<iRrrVKd:]C@p45p2=!K3->rrKf@p&>'T +2Z3R\*WQ/Q8;ZX3=oGf:EmOcj88>WCDUnc;~> +"!.E>+oY"=nGiOLJ4Q':Y\F(9!C#B=rrC[M[h5T^s+Mqh\$r2\s.PF]\#s&_q#:A21B'fKA^g\. +li/"%rrth%K`D'Nb5VDAU3cP5!$2";!HG1>[hOJ#s2@f;\$pmts21i\\$t2ns'E/5[fL`lq#:@. +>Q2)4ER=CY!i_%@r;QeISb<!`WH8%<!Tdkj[f]k-he;tt"'>BB;Z?\)39C2.O@Y5;[oi[TF8`QM +>5uWerO2c3r;QdRl1P&W?,6F="cnXr84[+erreOOo(+=)rsNs&T!u2#L]@D"[ho#C"k:"&Y.)XQ +rrM7?o`"n3r;QeBVuF.6Lo^P:UT.b3KX(P47fKjtJ@GOX!mgp]rVm"#a8_-[rVlr7!.+YE"nc'C +s*^R<rrJ7?p&>')@K$34qP-T)\$ol2lsTh%!c/D1rr3%Q!4Dh+"j;#Cs$>E;rrH0?p&>&CSc&Kf +iVg4f>lVWdrjN$<@K3$Jrr3BIs8SH4NjlL"D?$enrjMp-F85bQgUAo,\&JCIG;#Mr\"8?Sen[gZ +\!r?VOdQ-W"IG;Os2k8L%$R(YKV,`_S1]'dI\ZnO!K<iRrrVKd:]C@p45p2=!K3->rrKf@p&>'T +2Z3R\*WQ/Q8;ZX3=oGf:EmOcj88>WCDUnc;~> +"!.E>@K+aVr;Q`rJHPNDmOnJ<!C#B9rt+!Ns+Ppms8UV?s*^O>s62?6rrm5&e/6]nr;Qa;qYpcM +e=;Er;p,+>!MXo6rr=);rrG.?rr3F`PlLb'g].;(SH&WV0`:qO+T;<>"6]4S55Zo5_Z/6Crr3"* +^@hL,Lm7f:!Ip[5rrK*?rVloQ62gfch#5\orVlsEq8uV7rsUmKs8Sm*mJm2,s1)Y<rr^sSZ#'C= +!$2";!Aj!5rrHE@rVmFi(nB+*^0^i/Nq35A.KBF4r$r%hs)j7ms8U&>rVlj<qu6[Ho(r@eju2l3 +!$2";!CPT?rs\;\s#T/u49(2%s"_RmrrI\?rr3&oeE6c1"\.)Cs,E*<rrViBl2L\d6/2G>IA$N< +!Ki<5rrK`?r;R&L5j&+H4l>?\rr3&Z/Ed$4$gQ75s8UhXjo>?Hg\h'P<lXh4!J$a8rrX;AWH8(= +"TI-TTmQe=$m#BJQu;Bms6)??OGs2="8^pTS,=c:AcD]17+hJ<&U0-*s8U)>s8Prqqu=?:s(8b> +rrKN?qu7)+E;rqZs8VbKGlLIarr3#elMgebr7'^)rrG4?rr3"WP5YC]]jUO5!Tl<<rs0Y*.qmH" +s8O,<rsE/Hs6;)ns8Q3>s*t~> +"!.E>@K+aVr;Q`rJHPNDmOnJ<!C#B9rt+!Ns+Ppms8UV?s*^O>s62?6rrm5&e/6]nr;Qa;qYpcM +e=;Er;p,+>!MXo6rr=);rrG.?rr3F`PlLb'g].;(SH&WV0`:qO+T;<>"6]4S55Zo5_Z/6Crr3"* +^@hL,Lm7f:!Ip[5rrK*?rVloQ62gfch#5\orVlsEq8uV7rsUmKs8Sm*mJm2,s1)Y<rr^sSZ#'C= +!$2";!Aj!5rrHE@rVmFi(nB+*^0^i/Nq35A.KBF4r$r%hs)j7ms8U&>rVlj<qu6[Ho(r@eju2l3 +!$2";!CPT?rs\;\s#T/u49(2%s"_RmrrI\?rr3&oeE6c1"\.)Cs,E*<rrViBl2L\d6/2G>IA$N< +!Ki<5rrK`?r;R&L5j&+H4l>?\rr3&Z/Ed$4$gQ75s8UhXjo>?Hg\h'P<lXh4!J$a8rrX;AWH8(= +"TI-TTmQe=$m#BJQu;Bms6)??OGs2="8^pTS,=c:AcD]17+hJ<&U0-*s8U)>s8Prqqu=?:s(8b> +rrKN?qu7)+E;rqZs8VbKGlLIarr3#elMgebr7'^)rrG4?rr3"WP5YC]]jUO5!Tl<<rs0Y*.qmH" +s8O,<rsE/Hs6;)ns8Q3>s*t~> +"!.E>@K+aVr;Q`rJHPNDmOnJ<!C#B9rt+!Ns+Ppms8UV?s*^O>s62?6rrm5&e/6]nr;Qa;qYpcM +e=;Er;p,+>!MXo6rr=);rrG.?rr3F`PlLb'g].;(SH&WV0`:qO+T;<>"6]4S55Zo5_Z/6Crr3"* +^@hL,Lm7f:!Ip[5rrK*?rVloQ62gfch#5\orVlsEq8uV7rsUmKs8Sm*mJm2,s1)Y<rr^sSZ#'C= +!$2";!Aj!5rrHE@rVmFi(nB+*^0^i/Nq35A.KBF4r$r%hs)j7ms8U&>rVlj<qu6[Ho(r@eju2l3 +!$2";!CPT?rs\;\s#T/u49(2%s"_RmrrI\?rr3&oeE6c1"\.)Cs,E*<rrViBl2L\d6/2G>IA$N< +!Ki<5rrK`?r;R&L5j&+H4l>?\rr3&Z/Ed$4$gQ75s8UhXjo>?Hg\h'P<lXh4!J$a8rrX;AWH8(= +"TI-TTmQe=$m#BJQu;Bms6)??OGs2="8^pTS,=c:AcD]17+hJ<&U0-*s8U)>s8Prqqu=?:s(8b> +rrKN?qu7)+E;rqZs8VbKGlLIarr3#elMgebr7'^)rrG4?rr3"WP5YC]]jUO5!Tl<<rs0Y*.qmH" +s8O,<rsE/Hs6;)ns8Q3>s*t~> +"!.E>Fo)+AJXc]>rq-0h!C#B>rrMn@rZ)+Z5Q?G(rr38S8H4C6nF56up\tD5YlF#Po_e^h*VfX; +WcJ,<(]GEU&pj9O!$2";!BD(t*<[.Hs8O,=rrr2os8VI?r;Qfh+9!8_PktFNr:'daqu6\'^@qR. +Wd+@:rrIV?p&>&lF8c+>rO`"K"3gbn9)\bl,PfJ[rr3-]jo>@VGlI^FoDc@2qu6]%%/h1H.fB;I +1[4T4!F<M>rt(6GqZ$TP56$WZ*??+'>Q=KrnH8IaFf56=!QA.=rr=):rrFV?qYpTY2Y@"L*W5p< +ofW3o%!VLH3o]*[s,*$?1@+r>!J-a8rr=\N*WHZN[eTk&+9!8^%MHbZrrJ7?p&>')@Jp-+cqXN> +"82WS3;rjX2<Xf8!S.q`*<HH`q>L<o<lXh4!J$a>rrMt`r>btZs8%lW*<[SWs.Of=rraABs-SK= +rrhOCs,`3:rrDlmnGr7]rrGO?rVlnBVZ-T(``E->;9](?qtC&%(&f3V)0#WK;Z7[>'QF(PaSu2B +Uj2q47/e2-Dts,-!B]9>rrJ%@[email protected]#ju3/;!ua,Xm/?qa')`gR'Ysb61B.:TpAFr@~> +"!.E>Fo)+AJXc]>rq-0h!C#B>rrMn@rZ)+Z5Q?G(rr38S8H4C6nF56up\tD5YlF#Po_e^h*VfX; +WcJ,<(]GEU&pj9O!$2";!BD(t*<[.Hs8O,=rrr2os8VI?r;Qfh+9!8_PktFNr:'daqu6\'^@qR. +Wd+@:rrIV?p&>&lF8c+>rO`"K"3gbn9)\bl,PfJ[rr3-]jo>@VGlI^FoDc@2qu6]%%/h1H.fB;I +1[4T4!F<M>rt(6GqZ$TP56$WZ*??+'>Q=KrnH8IaFf56=!QA.=rr=):rrFV?qYpTY2Y@"L*W5p< +ofW3o%!VLH3o]*[s,*$?1@+r>!J-a8rr=\N*WHZN[eTk&+9!8^%MHbZrrJ7?p&>')@Jp-+cqXN> +"82WS3;rjX2<Xf8!S.q`*<HH`q>L<o<lXh4!J$a>rrMt`r>btZs8%lW*<[SWs.Of=rraABs-SK= +rrhOCs,`3:rrDlmnGr7]rrGO?rVlnBVZ-T(``E->;9](?qtC&%(&f3V)0#WK;Z7[>'QF(PaSu2B +Uj2q47/e2-Dts,-!B]9>rrJ%@[email protected]#ju3/;!ua,Xm/?qa')`gR'Ysb61B.:TpAFr@~> +"!.E>Fo)+AJXc]>rq-0h!C#B>rrMn@rZ)+Z5Q?G(rr38S8H4C6nF56up\tD5YlF#Po_e^h*VfX; +WcJ,<(]GEU&pj9O!$2";!BD(t*<[.Hs8O,=rrr2os8VI?r;Qfh+9!8_PktFNr:'daqu6\'^@qR. +Wd+@:rrIV?p&>&lF8c+>rO`"K"3gbn9)\bl,PfJ[rr3-]jo>@VGlI^FoDc@2qu6]%%/h1H.fB;I +1[4T4!F<M>rt(6GqZ$TP56$WZ*??+'>Q=KrnH8IaFf56=!QA.=rr=):rrFV?qYpTY2Y@"L*W5p< +ofW3o%!VLH3o]*[s,*$?1@+r>!J-a8rr=\N*WHZN[eTk&+9!8^%MHbZrrJ7?p&>')@Jp-+cqXN> +"82WS3;rjX2<Xf8!S.q`*<HH`q>L<o<lXh4!J$a>rrMt`r>btZs8%lW*<[SWs.Of=rraABs-SK= +rrhOCs,`3:rrDlmnGr7]rrGO?rVlnBVZ-T(``E->;9](?qtC&%(&f3V)0#WK;Z7[>'QF(PaSu2B +Uj2q47/e2-Dts,-!B]9>rrJ%@[email protected]#ju3/;!ua,Xm/?qa')`gR'Ysb61B.:TpAFr@~> +"!.E>Fo)+=JXcK8!C#B>s8S,ZrrrD25Q?G(rr35R8H7pi/1a!Yrs!;Ds8UtYjSf)Y*W?!=j7N?N +"KHMB;p,+>!MXo6rrGC?rVlmYj8/cU*W#d@m4eS?kjSQ)rVln:Xn_nrf_tgN?G?F=!qFb*rVlrl +R#h.E!q(Q@p&>&lF8c+>q;2)M""Woj9)\bl,PfJ[rr3-]jo>@VGl7RB\RYU<"5*XYD"mr11[4T4 +!F<M>rrJ1?rr3#U55bE]o-sG6#'Ggrs8U&>rVlj<qu6dKo)J:BrVlo\2Y@"L*W5p<htd9O%$HMJ +3o]*[s,*$?1;s1l!J-a>rrVrDjneuXNK=&<!qat*qYpSET`"fjOc/o4!P;e<rrLJ@r;QfZ3<&pZ +i@O0krrVK7o(r@e6/2>;!ER55rrIY@rVlo(C]=>:fH("]kPkJiq'?!6HiO-#)uor*K`:uSkV`C% +N;ihXqVLrG#=R5EpYc'qVZ-T!``E->;9\t<!G8h<rt/POs8VeRE;rqZs8V_IGlQ^rrr3"hJc>ZN +r6sX(rrucDs8VSDV>^Dp]jUO5!Tl<<rs0Y+/83N"s8O,9rrMC?qu;0~> +"!.E>Fo)+=JXcK8!C#B>s8S,ZrrrD25Q?G(rr35R8H7pi/1a!Yrs!;Ds8UtYjSf)Y*W?!=j7N?N +"KHMB;p,+>!MXo6rrGC?rVlmYj8/cU*W#d@m4eS?kjSQ)rVln:Xn_nrf_tgN?G?F=!qFb*rVlrl +R#h.E!q(Q@p&>&lF8c+>q;2)M""Woj9)\bl,PfJ[rr3-]jo>@VGl7RB\RYU<"5*XYD"mr11[4T4 +!F<M>rrJ1?rr3#U55bE]o-sG6#'Ggrs8U&>rVlj<qu6dKo)J:BrVlo\2Y@"L*W5p<htd9O%$HMJ +3o]*[s,*$?1;s1l!J-a>rrVrDjneuXNK=&<!qat*qYpSET`"fjOc/o4!P;e<rrLJ@r;QfZ3<&pZ +i@O0krrVK7o(r@e6/2>;!ER55rrIY@rVlo(C]=>:fH("]kPkJiq'?!6HiO-#)uor*K`:uSkV`C% +N;ihXqVLrG#=R5EpYc'qVZ-T!``E->;9\t<!G8h<rt/POs8VeRE;rqZs8V_IGlQ^rrr3"hJc>ZN +r6sX(rrucDs8VSDV>^Dp]jUO5!Tl<<rs0Y+/83N"s8O,9rrMC?qu;0~> +"!.E>Fo)+=JXcK8!C#B>s8S,ZrrrD25Q?G(rr35R8H7pi/1a!Yrs!;Ds8UtYjSf)Y*W?!=j7N?N +"KHMB;p,+>!MXo6rrGC?rVlmYj8/cU*W#d@m4eS?kjSQ)rVln:Xn_nrf_tgN?G?F=!qFb*rVlrl +R#h.E!q(Q@p&>&lF8c+>q;2)M""Woj9)\bl,PfJ[rr3-]jo>@VGl7RB\RYU<"5*XYD"mr11[4T4 +!F<M>rrJ1?rr3#U55bE]o-sG6#'Ggrs8U&>rVlj<qu6dKo)J:BrVlo\2Y@"L*W5p<htd9O%$HMJ +3o]*[s,*$?1;s1l!J-a>rrVrDjneuXNK=&<!qat*qYpSET`"fjOc/o4!P;e<rrLJ@r;QfZ3<&pZ +i@O0krrVK7o(r@e6/2>;!ER55rrIY@rVlo(C]=>:fH("]kPkJiq'?!6HiO-#)uor*K`:uSkV`C% +N;ihXqVLrG#=R5EpYc'qVZ-T!``E->;9\t<!G8h<rt/POs8VeRE;rqZs8V_IGlQ^rrr3"hJc>ZN +r6sX(rrucDs8VSDV>^Dp]jUO5!Tl<<rs0Y+/83N"s8O,9rrMC?qu;0~> +"!.E><;j6._>jOdS,<3sfsWK(^&S,8L:4Ot5<o1%Qi@!feO]_7NW-?d`V9B5Cp<p=%(fsJe$c\" +[^O]cMOa[S"Ho5R;p,+>!MXo6rrM@?rVln=WrBF,f`(mN*W#dAnm/]4I)#\h[JmT8GfBIX!*]?0 +!HHNdrrT>'N;`bW_HQg9!M+c5rrK*?rVlo[Ac9%>>P6lerO)f1qq5fb[KU*@s8Sm>r;QfBF8`NL +>Q;`frO2V'!Aj!5rrHE@rVlo%L&SL]W-/%<!V7c7rsa*)S[PttL]@D![M?6mrVm"5Z*os^rVlo\ +2Y@"L*W5p<Gc(JK%#:qa3o]FGs,*$?1.V>P!J%]ZrrUOIC&7i1NK=&<!l+e^qYpSET`"fjOc/o4 +!P;e<rrLJ@r;Qfa@K*\:C_,_.rrRiR[JKn(6/2>;!ER55rrIY@rVlo>GQ,#R<ZM.VHN(>]ZXWsI +I^Z[i'EA*"K`:uSkV`CEL&SL]WH@k6#C<5TTn35fVZ-T!``E->;9\t<!Ki`J[M6pbs,3AT[\#9n +s+R&Q[[]!qs*pdB[K2>`rr3&c!)NRn"CAOFOdu@L!PMn6rrM7?r;R$Cs8Tc(M<Y%DrO)jhs8V@> +qu;0~> +"!.E><;j6._>jOdS,<3sfsWK(^&S,8L:4Ot5<o1%Qi@!feO]_7NW-?d`V9B5Cp<p=%(fsJe$c\" +[^O]cMOa[S"Ho5R;p,+>!MXo6rrM@?rVln=WrBF,f`(mN*W#dAnm/]4I)#\h[JmT8GfBIX!*]?0 +!HHNdrrT>'N;`bW_HQg9!M+c5rrK*?rVlo[Ac9%>>P6lerO)f1qq5fb[KU*@s8Sm>r;QfBF8`NL +>Q;`frO2V'!Aj!5rrHE@rVlo%L&SL]W-/%<!V7c7rsa*)S[PttL]@D![M?6mrVm"5Z*os^rVlo\ +2Y@"L*W5p<Gc(JK%#:qa3o]FGs,*$?1.V>P!J%]ZrrUOIC&7i1NK=&<!l+e^qYpSET`"fjOc/o4 +!P;e<rrLJ@r;Qfa@K*\:C_,_.rrRiR[JKn(6/2>;!ER55rrIY@rVlo>GQ,#R<ZM.VHN(>]ZXWsI +I^Z[i'EA*"K`:uSkV`CEL&SL]WH@k6#C<5TTn35fVZ-T!``E->;9\t<!Ki`J[M6pbs,3AT[\#9n +s+R&Q[[]!qs*pdB[K2>`rr3&c!)NRn"CAOFOdu@L!PMn6rrM7?r;R$Cs8Tc(M<Y%DrO)jhs8V@> +qu;0~> +"!.E><;j6._>jOdS,<3sfsWK(^&S,8L:4Ot5<o1%Qi@!feO]_7NW-?d`V9B5Cp<p=%(fsJe$c\" +[^O]cMOa[S"Ho5R;p,+>!MXo6rrM@?rVln=WrBF,f`(mN*W#dAnm/]4I)#\h[JmT8GfBIX!*]?0 +!HHNdrrT>'N;`bW_HQg9!M+c5rrK*?rVlo[Ac9%>>P6lerO)f1qq5fb[KU*@s8Sm>r;QfBF8`NL +>Q;`frO2V'!Aj!5rrHE@rVlo%L&SL]W-/%<!V7c7rsa*)S[PttL]@D![M?6mrVm"5Z*os^rVlo\ +2Y@"L*W5p<Gc(JK%#:qa3o]FGs,*$?1.V>P!J%]ZrrUOIC&7i1NK=&<!l+e^qYpSET`"fjOc/o4 +!P;e<rrLJ@r;Qfa@K*\:C_,_.rrRiR[JKn(6/2>;!ER55rrIY@rVlo>GQ,#R<ZM.VHN(>]ZXWsI +I^Z[i'EA*"K`:uSkV`CEL&SL]WH@k6#C<5TTn35fVZ-T!``E->;9\t<!Ki`J[M6pbs,3AT[\#9n +s+R&Q[[]!qs*pdB[K2>`rr3&c!)NRn"CAOFOdu@L!PMn6rrM7?r;R$Cs8Tc(M<Y%DrO)jhs8V@> +qu;0~> +!Zh<`r+6(Zs8TIDqu6Z!ral.Qrr38'AnGcCN;p?%rr3,`OoNUMral1M\bQ1*VpPGC"4j.FUASU* +V>pRRral;$s8SGCrr3#>YP.ttno2/<rr@6AAcSt4rr@9=rr_7mB".d>!,):C!5/(+!;?A'!65!; +!mYDhrVloQSGW<fj+Xf2rs,MlR@3@?s4I9^"6KR_e,<k\lMpn0ral>jGQ7]bY5A5!_u40Lq>^K/ +rFQ<6s8UK7R31\drrZPJRA9c]!36$1!."[email protected];Qh8As<5o"1">P +2Y@"O(n$f.rr2tGral;2s8RrDrr3,2^AftMral/8rVlrZAu5A(!P?#CrrUkcYPS8)Z,ZhDp6h=M +MtR)U]/uFKj8]/>Pl(I\hYq*gc8FearrTT?e,'(MNTpKChjKlh`qB?:J6nY3qu?]2ral<"GQ7]S +ral.Frr383AnL-Fs8TpCrr3,kL&_1Rral.Uo`#,DAqU-`Xi^SB"l5XIs-DU?rrA2\AcS"nrt(-$ +AqnR0s8RjdArFa5s8R]MAcSS(rrVe(Q2L[^AcS:urr]!`EFAJ>#Nd.sRF;-8GQ%ODV:,D=rFQ2O +s8VYCqu;0~> +!Zh<`r+6(Zs8TIDqu6Z!ral.Qrr38'AnGcCN;p?%rr3,`OoNUMral1M\bQ1*VpPGC"4j.FUASU* +V>pRRral;$s8SGCrr3#>YP.ttno2/<rr@6AAcSt4rr@9=rr_7mB".d>!,):C!5/(+!;?A'!65!; +!mYDhrVloQSGW<fj+Xf2rs,MlR@3@?s4I9^"6KR_e,<k\lMpn0ral>jGQ7]bY5A5!_u40Lq>^K/ +rFQ<6s8UK7R31\drrZPJRA9c]!36$1!."[email protected];Qh8As<5o"1">P +2Y@"O(n$f.rr2tGral;2s8RrDrr3,2^AftMral/8rVlrZAu5A(!P?#CrrUkcYPS8)Z,ZhDp6h=M +MtR)U]/uFKj8]/>Pl(I\hYq*gc8FearrTT?e,'(MNTpKChjKlh`qB?:J6nY3qu?]2ral<"GQ7]S +ral.Frr383AnL-Fs8TpCrr3,kL&_1Rral.Uo`#,DAqU-`Xi^SB"l5XIs-DU?rrA2\AcS"nrt(-$ +AqnR0s8RjdArFa5s8R]MAcSS(rrVe(Q2L[^AcS:urr]!`EFAJ>#Nd.sRF;-8GQ%ODV:,D=rFQ2O +s8VYCqu;0~> +!Zh<`r+6(Zs8TIDqu6Z!ral.Qrr38'AnGcCN;p?%rr3,`OoNUMral1M\bQ1*VpPGC"4j.FUASU* +V>pRRral;$s8SGCrr3#>YP.ttno2/<rr@6AAcSt4rr@9=rr_7mB".d>!,):C!5/(+!;?A'!65!; +!mYDhrVloQSGW<fj+Xf2rs,MlR@3@?s4I9^"6KR_e,<k\lMpn0ral>jGQ7]bY5A5!_u40Lq>^K/ +rFQ<6s8UK7R31\drrZPJRA9c]!36$1!."[email protected];Qh8As<5o"1">P +2Y@"O(n$f.rr2tGral;2s8RrDrr3,2^AftMral/8rVlrZAu5A(!P?#CrrUkcYPS8)Z,ZhDp6h=M +MtR)U]/uFKj8]/>Pl(I\hYq*gc8FearrTT?e,'(MNTpKChjKlh`qB?:J6nY3qu?]2ral<"GQ7]S +ral.Frr383AnL-Fs8TpCrr3,kL&_1Rral.Uo`#,DAqU-`Xi^SB"l5XIs-DU?rrA2\AcS"nrt(-$ +AqnR0s8RjdArFa5s8R]MAcSS(rrVe(Q2L[^AcS:urr]!`EFAJ>#Nd.sRF;-8GQ%ODV:,D=rFQ2O +s8VYCqu;0~> +!$0_l!I^U>rrL>?c2Rh,WkJE5h6Z_Q!7h($!9VW-!65"j!;,sa"0dE1O3[b-Tn@ugo`##OK7gQ" +rrFn@g]%9Grdt3jp&>$Krdt4,o)A_JkOAKOfD^C&j7WEP_>]&eqXFLccb08W!$.[2"-%qcZ1\+s +oDX@BaQNSR~> +!$0_l!I^U>rrL>?c2Rh,WkJE5h6Z_Q!7h($!9VW-!65"j!;,sa"0dE1O3[b-Tn@ugo`##OK7gQ" +rrFn@g]%9Grdt3jp&>$Krdt4,o)A_JkOAKOfD^C&j7WEP_>]&eqXFLccb08W!$.[2"-%qcZ1\+s +oDX@BaQNSR~> +!$0_l!I^U>rrL>?c2Rh,WkJE5h6Z_Q!7h($!9VW-!65"j!;,sa"0dE1O3[b-Tn@ugo`##OK7gQ" +rrFn@g]%9Grdt3jp&>$Krdt4,o)A_JkOAKOfD^C&j7WEP_>]&eqXFLccb08W!$.[2"-%qcZ1\+s +oDX@BaQNSR~> +!$0_l!R>og?NFuWJcC<$dJj5&laHfo2<W*]!Si8*?N?dNs6ou<~> +!$0_l!R>og?NFuWJcC<$dJj5&laHfo2<W*]!Si8*?N?dNs6ou<~> +!$0_l!R>og?NFuWJcC<$dJj5&laHfo2<W*]!Si8*?N?dNs6ou<~> +!$0\k!7h(]!6TlmJcF*s!Qk2HrrL:<aSu7trk&7.JcG3=J,~> +!$0\k!7h(]!6TlmJcF*s!Qk2HrrL:<aSu7trk&7.JcG3=J,~> +!$0\k!7h(]!6TlmJcF*s!Qk2HrrL:<aSu7trk&7.JcG3=J,~> +!$..#"#_JQH%H!Hs+13$s7lVE~> +!$..#"#_JQH%H!Hs+13$s7lVE~> +!$..#"#_JQH%H!Hs+13$s7lVE~> +!$1P.",Is-hrXk>C)m`\rrQ[N'D)5,m2m?Wo_8@e73")Lrr`#hZsnUdJcC<$JcGNFJ,~> +!$1P.",Is-hrXk>C)m`\rrQ[N'D)5,m2m?Wo_8@e73")Lrr`#hZsnUdJcC<$JcGNFJ,~> +!$1P.",Is-hrXk>C)m`\rrQ[N'D)5,m2m?Wo_8@e73")Lrr`#hZsnUdJcC<$JcGNFJ,~> +!$1J,!C#B#rr=)9rr=)2rraJBs/L,5rrMX?lMgms@Y+Q1s+13$s7lVE~> +!$1J,!C#B#rr=)9rr=)2rraJBs/L,5rrMX?lMgms@Y+Q1s+13$s7lVE~> +!$1J,!C#B#rr=)9rr=)2rraJBs/L,5rrMX?lMgms@Y+Q1s+13$s7lVE~> +#9Ej*e^C_-[/U(*g&A5V[f$.+52Q#5"kqkTZ*D%BrrC@DYlMW<rr=)9rr=)9rrKOBr;R!Er;X^+ +s8Tq7YlN)JrrMX?r;Qc0rilIPrr2u0rilIRr;Qf0@Y+Q1s+13$s7lVE~> +#9Ej*e^C_-[/U(*g&A5V[f$.+52Q#5"kqkTZ*D%BrrC@DYlMW<rr=)9rr=)9rrKOBr;R!Er;X^+ +s8Tq7YlN)JrrMX?r;Qc0rilIPrr2u0rilIRr;Qf0@Y+Q1s+13$s7lVE~> +#9Ej*e^C_-[/U(*g&A5V[f$.+52Q#5"kqkTZ*D%BrrC@DYlMW<rr=)9rr=)9rrKOBr;R!Er;X^+ +s8Tq7YlN)JrrMX?r;Qc0rilIPrr2u0rilIRr;Qf0@Y+Q1s+13$s7lVE~> +$Q]8F7!rccCo%*_JGs<bDQ*O6!C#B6rs=B]GACu7ZN&$mrbDOU[f-4+*W#d9*W#d:$nqPY!?h=< +rr@rUCB8b%rr3#h/,fJKY]9YX"F\VrXDe)R!IiJqrrK`@JcC<$JcC<$q#>j~> +$Q]8F7!rccCo%*_JGs<bDQ*O6!C#B6rs=B]GACu7ZN&$mrbDOU[f-4+*W#d9*W#d:$nqPY!?h=< +rr@rUCB8b%rr3#h/,fJKY]9YX"F\VrXDe)R!IiJqrrK`@JcC<$JcC<$q#>j~> +$Q]8F7!rccCo%*_JGs<bDQ*O6!C#B6rs=B]GACu7ZN&$mrbDOU[f-4+*W#d9*W#d:$nqPY!?h=< +rr@rUCB8b%rr3#h/,fJKY]9YX"F\VrXDe)R!IiJqrrK`@JcC<$JcC<$q#>j~> +$Q]8F50X',pEop4IfB?JmOnJ<!C#B>rrBt7G70i=Ki$S)s4'[?I@pN=!R+C=rr=)9rr=)9rrJ+N +rr3,"G7Sk^q>UJiHN*pFnLOS<!CGQ?rrgQfs#K-=rrIq?rVlo1@Y+Q1s+13$s7lVE~> +$Q]8F50X',pEop4IfB?JmOnJ<!C#B>rrBt7G70i=Ki$S)s4'[?I@pN=!R+C=rr=)9rr=)9rrJ+N +rr3,"G7Sk^q>UJiHN*pFnLOS<!CGQ?rrgQfs#K-=rrIq?rVlo1@Y+Q1s+13$s7lVE~> +$Q]8F50X',pEop4IfB?JmOnJ<!C#B>rrBt7G70i=Ki$S)s4'[?I@pN=!R+C=rr=)9rr=)9rrJ+N +rr3,"G7Sk^q>UJiHN*pFnLOS<!CGQ?rrgQfs#K-=rrIq?rVlo1@Y+Q1s+13$s7lVE~> +"!.E>FoMCDpEop4/cJoS<%e.L!C#B>rrC[KV$"@0KpVf="P$'CI@pN=!R+C=rr=)9rr=)4rrg<; +'r/;;rr@KH=ogX0rr3#h/,fJK]Oh(G"JPkq3DocZ!AKc:rrK`@JcC<$JcC<$q#>j~> +"!.E>FoMCDpEop4/cJoS<%e.L!C#B>rrC[KV$"@0KpVf="P$'CI@pN=!R+C=rr=)9rr=)4rrg<; +'r/;;rr@KH=ogX0rr3#h/,fJK]Oh(G"JPkq3DocZ!AKc:rrK`@JcC<$JcC<$q#>j~> +"!.E>FoMCDpEop4/cJoS<%e.L!C#B>rrC[KV$"@0KpVf="P$'CI@pN=!R+C=rr=)9rr=)4rrg<; +'r/;;rr@KH=ogX0rr3#h/,fJK]Oh(G"JPkq3DocZ!AKc:rrK`@JcC<$JcC<$q#>j~> +"!.E>FoMCDpEop4?i@e@c2IYC52Q#5!JQm>rrgkCs*^O=rrL>?rVlj<qYpO9oD\h6r;HWrI&?nZ +!IK.lrrMX?r;Qc>rkS_oVuJcYrP8KqrVlo1@Y+Q1s+13$s7lVE~> +"!.E>FoMCDpEop4?i@e@c2IYC52Q#5!JQm>rrgkCs*^O=rrL>?rVlj<qYpO9oD\h6r;HWrI&?nZ +!IK.lrrMX?r;Qc>rkS_oVuJcYrP8KqrVlo1@Y+Q1s+13$s7lVE~> +"!.E>FoMCDpEop4?i@e@c2IYC52Q#5!JQm>rrgkCs*^O=rrL>?rVlj<qYpO9oD\h6r;HWrI&?nZ +!IK.lrrMX?r;Qc>rkS_oVuJcYrP8KqrVlo1@Y+Q1s+13$s7lVE~> +"!.E>FoMCDpEop4Ie`pD52Q#5$&'&,s8UV?s*^O=rrL>?rVlj<qYpO9qYpRH9)S\i+T23<##i\E +s2Pk#rr3#h/,fJK>2T>Z"HeWB3TKo7!P;fls+13$s+14Fs*t~> +"!.E>FoMCDpEop4Ie`pD52Q#5$&'&,s8UV?s*^O=rrL>?rVlj<qYpO9qYpRH9)S\i+T23<##i\E +s2Pk#rr3#h/,fJK>2T>Z"HeWB3TKo7!P;fls+13$s+14Fs*t~> +"!.E>FoMCDpEop4Ie`pD52Q#5$&'&,s8UV?s*^O=rrL>?rVlj<qYpO9qYpRH9)S\i+T23<##i\E +s2Pk#rr3#h/,fJK>2T>Z"HeWB3TKo7!P;fls+13$s+14Fs*t~> +"!.EGKDtlRpH/ESNrC%!/H5YPL`IBR1\^nUKp>sb*CB](rG_`V#YFsos(WPm*Duh9"CiGj*Ei=? +!@1&1rrG%UrVmK-9-#$QWJCNR73*9eGQ7^@4oQH)IJs3D2?"TrLAq2TkiSgQJcC<$JcC<$q#>j~> +"!.EGKDtlRpH/ESNrC%!/H5YPL`IBR1\^nUKp>sb*CB](rG_`V#YFsos(WPm*Duh9"CiGj*Ei=? +!@1&1rrG%UrVmK-9-#$QWJCNR73*9eGQ7^@4oQH)IJs3D2?"TrLAq2TkiSgQJcC<$JcC<$q#>j~> +"!.EGKDtlRpH/ESNrC%!/H5YPL`IBR1\^nUKp>sb*CB](rG_`V#YFsos(WPm*Duh9"CiGj*Ei=? +!@1&1rrG%UrVmK-9-#$QWJCNR73*9eGQ7^@4oQH)IJs3D2?"TrLAq2TkiSgQJcC<$JcC<$q#>j~> +!$1"t!JQlGrrY\J2M6S\JcC<$JcGNFJ,~> +!$1"t!JQlGrrY\J2M6S\JcC<$JcGNFJ,~> +!$1"t!JQlGrrY\J2M6S\JcC<$JcGNFJ,~> +!$1"t!JQkks+13$s+13Hs*t~> +!$1"t!JQkks+13$s+13Hs*t~> +!$1"t!JQkks+13$s+13Hs*t~> +!$1"t!P?=%s+13$s+13Hs*t~> +!$1"t!P?=%s+13$s+13Hs*t~> +!$1"t!P?=%s+13$s+13Hs*t~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$.@)!V"X)rrM*>JcC<$JcFU,J,~> +!$.@)!V"X)rrM*>JcC<$JcFU,J,~> +!$.@)!V"X)rrM*>JcC<$JcFU,J,~> +!Zh<ur1X1qq#:BJe+3M@aJ,F)rVlu=U8%SZrrL7$rr3)_`W*sUU&`:0rrBk4U&`O-rrVhUQM1=Z +Z2;uL!p66)pAY0d\+'Cuce\R"!9*mN!;6?k!jdU@JcC<$JcFX-J,~> +!Zh<ur1X1qq#:BJe+3M@aJ,F)rVlu=U8%SZrrL7$rr3)_`W*sUU&`:0rrBk4U&`O-rrVhUQM1=Z +Z2;uL!p66)pAY0d\+'Cuce\R"!9*mN!;6?k!jdU@JcC<$JcFX-J,~> +!Zh<ur1X1qq#:BJe+3M@aJ,F)rVlu=U8%SZrrL7$rr3)_`W*sUU&`:0rrBk4U&`O-rrVhUQM1=Z +Z2;uL!p66)pAY0d\+'Cuce\R"!9*mN!;6?k!jdU@JcC<$JcFX-J,~> +"!.E>3;n.'NqiVTQA4u1"0d(en,<7gXEkNRpAY/0Yl=Y*]4(_L=T*OGZ2">!V>Y]@9mZ7-!T6*5 +rrFP?lMgnMW9aHbgNpR2rrLi`rVloY3V!+Sc@:E's8V55rH\HtrVln5Z@W%,s+14-s*t~> +"!.E>3;n.'NqiVTQA4u1"0d(en,<7gXEkNRpAY/0Yl=Y*]4(_L=T*OGZ2">!V>Y]@9mZ7-!T6*5 +rrFP?lMgnMW9aHbgNpR2rrLi`rVloY3V!+Sc@:E's8V55rH\HtrVln5Z@W%,s+14-s*t~> +"!.E>3;n.'NqiVTQA4u1"0d(en,<7gXEkNRpAY/0Yl=Y*]4(_L=T*OGZ2">!V>Y]@9mZ7-!T6*5 +rrFP?lMgnMW9aHbgNpR2rrLi`rVloY3V!+Sc@:E's8V55rH\HtrVln5Z@W%,s+14-s*t~> +"!.E>Fn>V6QA4o/!A3d;rrFG?pAY/0Yl=Y*]4(_L\aTP"fm1^.rrW1;YP%nr..lg)!RjX#rrKB? +rVloY3V*1UdsK?QFR&nK;Z6UqU](2o_KOsjs+13$s5<p-~> +"!.E>Fn>V6QA4o/!A3d;rrFG?pAY/0Yl=Y*]4(_L\aTP"fm1^.rrW1;YP%nr..lg)!RjX#rrKB? +rVloY3V*1UdsK?QFR&nK;Z6UqU](2o_KOsjs+13$s5<p-~> +"!.E>Fn>V6QA4o/!A3d;rrFG?pAY/0Yl=Y*]4(_L\aTP"fm1^.rrW1;YP%nr..lg)!RjX#rrKB? +rVloY3V*1UdsK?QFR&nK;Z6UqU](2o_KOsjs+13$s5<p-~> +"!.E>Fo)+<VuB<p=9&;dL5\bu?2jj(S,Q%\A,Q?-/arT:!@@L6rsdIoh#HGJd/RUdBM2!LoD\j+ +?1.^nrZD%;!*T:o"Ju.u.-LS&!3?,!!)<Gc&@)98@/nYJ9=Os$<^%9l9>1-#!WHO+rs")2s5QaF +V>gK%nk1e^92!h8j#P!U9*!]@rs@Uudf9?f>5QH?p\t7gd"24Js+14.s*t~> +"!.E>Fo)+<VuB<p=9&;dL5\bu?2jj(S,Q%\A,Q?-/arT:!@@L6rsdIoh#HGJd/RUdBM2!LoD\j+ +?1.^nrZD%;!*T:o"Ju.u.-LS&!3?,!!)<Gc&@)98@/nYJ9=Os$<^%9l9>1-#!WHO+rs")2s5QaF +V>gK%nk1e^92!h8j#P!U9*!]@rs@Uudf9?f>5QH?p\t7gd"24Js+14.s*t~> +"!.E>Fo)+<VuB<p=9&;dL5\bu?2jj(S,Q%\A,Q?-/arT:!@@L6rsdIoh#HGJd/RUdBM2!LoD\j+ +?1.^nrZD%;!*T:o"Ju.u.-LS&!3?,!!)<Gc&@)98@/nYJ9=Os$<^%9l9>1-#!WHO+rs")2s5QaF +V>gK%nk1e^92!h8j#P!U9*!]@rs@Uudf9?f>5QH?p\t7gd"24Js+14.s*t~> +"!.E>(&ffgmf3<kIf@_'``2u((m`Rs^g$i5M>km']41a=!A3d;rrFG?p&>IscMuQcs8QRQ\'`Tr +L%YHIj&b4-rrN*@qu6ZGrm:k!Y5]n0rm:jp[JreDrm;:"]`6A3=4,E7_uJ2f4OMREq#:Bn+8u3D +:!`k7d=?cHrsJ\OO]TrXo`*qYAcC'X:[RuX!VbILrr^mPb#8!6!DUpls+13$s5<p-~> +"!.E>(&ffgmf3<kIf@_'``2u((m`Rs^g$i5M>km']41a=!A3d;rrFG?p&>IscMuQcs8QRQ\'`Tr +L%YHIj&b4-rrN*@qu6ZGrm:k!Y5]n0rm:jp[JreDrm;:"]`6A3=4,E7_uJ2f4OMREq#:Bn+8u3D +:!`k7d=?cHrsJ\OO]TrXo`*qYAcC'X:[RuX!VbILrr^mPb#8!6!DUpls+13$s5<p-~> +"!.E>(&ffgmf3<kIf@_'``2u((m`Rs^g$i5M>km']41a=!A3d;rrFG?p&>IscMuQcs8QRQ\'`Tr +L%YHIj&b4-rrN*@qu6ZGrm:k!Y5]n0rm:jp[JreDrm;:"]`6A3=4,E7_uJ2f4OMREq#:Bn+8u3D +:!`k7d=?cHrsJ\OO]TrXo`*qYAcC'X:[RuX!VbILrr^mPb#8!6!DUpls+13$s5<p-~> +"!.E>D>ro*rr<"nIfAsJoC;jHIJNpCju<=#M#R#Idm*g2!A3d;rrFG?p&>J%a8XI[s8V`Yr;Zf' +C%_K,e4B!,!WF2<rrD`koE9K1s!Zt-rrdSCruh:>rs`nKs7mi/s8QrHs8UP>p&>9q+9/Bms%Ui= +rrJ[@r;Qf&C]487j#-H-rrFt?nc&g9;ZHc1*>SMP!DUpls+13$s5<p-~> +"!.E>D>ro*rr<"nIfAsJoC;jHIJNpCju<=#M#R#Idm*g2!A3d;rrFG?p&>J%a8XI[s8V`Yr;Zf' +C%_K,e4B!,!WF2<rrD`koE9K1s!Zt-rrdSCruh:>rs`nKs7mi/s8QrHs8UP>p&>9q+9/Bms%Ui= +rrJ[@r;Qf&C]487j#-H-rrFt?nc&g9;ZHc1*>SMP!DUpls+13$s5<p-~> +"!.E>D>ro*rr<"nIfAsJoC;jHIJNpCju<=#M#R#Idm*g2!A3d;rrFG?p&>J%a8XI[s8V`Yr;Zf' +C%_K,e4B!,!WF2<rrD`koE9K1s!Zt-rrdSCruh:>rs`nKs7mi/s8QrHs8UP>p&>9q+9/Bms%Ui= +rrJ[@r;Qf&C]487j#-H-rrFt?nc&g9;ZHc1*>SMP!DUpls+13$s5<p-~> +"!.E>Fo)+<Q2W071uA7uLAq2Uju<=#(B#W]?2ad(/arT:!@@L4rrOq7-MdZBZYB.5!W"&-rrN*@ +r;QfS2?#!,'V,1Oo`"jnGbtE_rVlg"Dls'8,PqE@dn064#Q5bEV0Dr6ci3qFSUgY<!O6G=rrM.? +rVlmTkjeZRb#83<!$2";!DUpls+13$s5<p-~> +"!.E>Fo)+<Q2W071uA7uLAq2Uju<=#(B#W]?2ad(/arT:!@@L4rrOq7-MdZBZYB.5!W"&-rrN*@ +r;QfS2?#!,'V,1Oo`"jnGbtE_rVlg"Dls'8,PqE@dn064#Q5bEV0Dr6ci3qFSUgY<!O6G=rrM.? +rVlmTkjeZRb#83<!$2";!DUpls+13$s5<p-~> +"!.E>Fo)+<Q2W071uA7uLAq2Uju<=#(B#W]?2ad(/arT:!@@L4rrOq7-MdZBZYB.5!W"&-rrN*@ +r;QfS2?#!,'V,1Oo`"jnGbtE_rVlg"Dls'8,PqE@dn064#Q5bEV0Dr6ci3qFSUgY<!O6G=rrM.? +rVlmTkjeZRb#83<!$2";!DUpls+13$s5<p-~> +"!.E>Fo21>jkTk8"R[oBQA5D="QhZCNfNo7!A3d;rrFG?o`"tIi[4[)!S-Q9rrKH?rVlo1ao)/> +^0^1+!rc-@rVm0Ym/R+I?(CpC\,QC1GbtE_rVlg"Dls'8,PqEDdn0T>e*Zu2#Q5b5OaQ._ci3qF +SUgY<#I/(Es2t)r3W8sY2!FK0!Qn==rr=)<rrUech1>TWs+14.s*t~> +"!.E>Fo21>jkTk8"R[oBQA5D="QhZCNfNo7!A3d;rrFG?o`"tIi[4[)!S-Q9rrKH?rVlo1ao)/> +^0^1+!rc-@rVm0Ym/R+I?(CpC\,QC1GbtE_rVlg"Dls'8,PqEDdn0T>e*Zu2#Q5b5OaQ._ci3qF +SUgY<#I/(Es2t)r3W8sY2!FK0!Qn==rr=)<rrUech1>TWs+14.s*t~> +"!.E>Fo21>jkTk8"R[oBQA5D="QhZCNfNo7!A3d;rrFG?o`"tIi[4[)!S-Q9rrKH?rVlo1ao)/> +^0^1+!rc-@rVm0Ym/R+I?(CpC\,QC1GbtE_rVlg"Dls'8,PqEDdn0T>e*Zu2#Q5b5OaQ._ci3qF +SUgY<#I/(Es2t)r3W8sY2!FK0!Qn==rr=)<rrUech1>TWs+14.s*t~> +"!.E>8H#(]XT-4grga1[IfG^grr3,`2ugF@rga%hrr3,?SK*iqrr3,<SJRZup&>)DQ?rQ1!M>AN +SH4YDrVlm#2uN[U*U<Y*i&pu<$%SG7SVAkhs!V@USHOD^s)sq3SHO>bs7mo9rrqJ)SXk#Wq>Us( +Boe[jKQQ2Qn=<r_S`TkN#L@afST*rU3W8sY2!FK0!T%ttSH*F'rrHl?JcC<$JcFX-J,~> +"!.E>8H#(]XT-4grga1[IfG^grr3,`2ugF@rga%hrr3,?SK*iqrr3,<SJRZup&>)DQ?rQ1!M>AN +SH4YDrVlm#2uN[U*U<Y*i&pu<$%SG7SVAkhs!V@USHOD^s)sq3SHO>bs7mo9rrqJ)SXk#Wq>Us( +Boe[jKQQ2Qn=<r_S`TkN#L@afST*rU3W8sY2!FK0!T%ttSH*F'rrHl?JcC<$JcFX-J,~> +"!.E>8H#(]XT-4grga1[IfG^grr3,`2ugF@rga%hrr3,?SK*iqrr3,<SJRZup&>)DQ?rQ1!M>AN +SH4YDrVlm#2uN[U*U<Y*i&pu<$%SG7SVAkhs!V@USHOD^s)sq3SHO>bs7mo9rrqJ)SXk#Wq>Us( +Boe[jKQQ2Qn=<r_S`TkN#L@afST*rU3W8sY2!FK0!T%ttSH*F'rrHl?JcC<$JcFX-J,~> +!Zh<ir-ng3s8Tn6IftQ,s2r4Xrrhn]s8TS-IfPT0rrBD)IfP`4rrB8%IfPl.rrA)WrrAemIfQ>C +rrIY>r;QbWlMgqTJ$&\L#`4%\YeSH_POSR$!5ng9!.b&u"NUQBr/pgT"586Sd.dPGn"'LY[+PEY +lhu;5h#76Waa\g!s7)TWrrJP[nG`L>rI4h<rr3&;J(]DQJcC<$huA3~> +!Zh<ir-ng3s8Tn6IftQ,s2r4Xrrhn]s8TS-IfPT0rrBD)IfP`4rrB8%IfPl.rrA)WrrAemIfQ>C +rrIY>r;QbWlMgqTJ$&\L#`4%\YeSH_POSR$!5ng9!.b&u"NUQBr/pgT"586Sd.dPGn"'LY[+PEY +lhu;5h#76Waa\g!s7)TWrrJP[nG`L>rI4h<rr3&;J(]DQJcC<$huA3~> +!Zh<ir-ng3s8Tn6IftQ,s2r4Xrrhn]s8TS-IfPT0rrBD)IfP`4rrB8%IfPl.rrA)WrrAemIfQ>C +rrIY>r;QbWlMgqTJ$&\L#`4%\YeSH_POSR$!5ng9!.b&u"NUQBr/pgT"586Sd.dPGn"'LY[+PEY +lhu;5h#76Waa\g!s7)TWrrJP[nG`L>rI4h<rr3&;J(]DQJcC<$huA3~> +!$.@)!U.7_rrLKtJcC<$JcFU,J,~> +!$.@)!U.7_rrLKtJcC<$JcFU,J,~> +!$.@)!U.7_rrLKtJcC<$JcFU,J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$2%<!VH<grrMlioD\pdn*g5QrrVf\rndYUo_[nQ"9.cXpAP!ln+6&K!VZ?grrW(rKA$8/oDJXg +qX=1=rrMiio`#!en,'Hk!THTHrrG4Kqu6[UnU^^ks2P(h~> +!$2%<!VH<grrMlioD\pdn*g5QrrVf\rndYUo_[nQ"9.cXpAP!ln+6&K!VZ?grrW(rKA$8/oDJXg +qX=1=rrMiio`#!en,'Hk!THTHrrG4Kqu6[UnU^^ks2P(h~> +!$2%<!VH<grrMlioD\pdn*g5QrrVf\rndYUo_[nQ"9.cXpAP!ln+6&K!VZ?grrW(rKA$8/oDJXg +qX=1=rrMiio`#!en,'Hk!THTHrrG4Kqu6[UnU^^ks2P(h~> +!$2(=!p)_mrVlqdOn//E",\Z;k5>5\CG#,LrrLpOmJd2k_<Lt+`@WZ`lMpn`/RS#I!I1I?rrL/? +f`).EfDklc/Y1u&!pa0mo`"uX/]ZZH!TE_;rrLpOo)A\1qYpO9qu6]o,(]cFs2P(h~> +!$2(=!p)_mrVlqdOn//E",\Z;k5>5\CG#,LrrLpOmJd2k_<Lt+`@WZ`lMpn`/RS#I!I1I?rrL/? +f`).EfDklc/Y1u&!pa0mo`"uX/]ZZH!TE_;rrLpOo)A\1qYpO9qu6]o,(]cFs2P(h~> +!$2(=!p)_mrVlqdOn//E",\Z;k5>5\CG#,LrrLpOmJd2k_<Lt+`@WZ`lMpn`/RS#I!I1I?rrL/? +f`).EfDklc/Y1u&!pa0mo`"uX/]ZZH!TE_;rrLpOo)A\1qYpO9qu6]o,(]cFs2P(h~> +"s*aDh09a\r;Qh\Qh0hK!B0*,rrG1?mJd2k_<Lt&*WQ/%MsLBIGbtH?pRR)lrrGR?i;WoBL*<S@ +rrH*?li-uIiUd'M_-?d9!Ed>=rrW+#a+=8As2Y.i~> +"s*aDh09a\r;Qh\Qh0hK!B0*,rrG1?mJd2k_<Lt&*WQ/%MsLBIGbtH?pRR)lrrGR?i;WoBL*<S@ +rrH*?li-uIiUd'M_-?d9!Ed>=rrW+#a+=8As2Y.i~> +"s*aDh09a\r;Qh\Qh0hK!B0*,rrG1?mJd2k_<Lt&*WQ/%MsLBIGbtH?pRR)lrrGR?i;WoBL*<S@ +rrH*?li-uIiUd'M_-?d9!Ed>=rrW+#a+=8As2Y.i~> +"s*a!J\Fq)qu6_[OS\VL!B0*=rr^-*R/$X[!5JN##d+.,a-\'+R'?Si!4`#q!42V'!M-:jrrH?? +rr3,W`rH(Arg3u*s8TOps8V)prVm0Es8TdDs8Sj]Yl4S&XRlFY!6bBA$(RBM_g&$Xs5Z0;rrE#r +Qiu"?s.o&]Qil%As7ZDY"5NqVo)4pXi;`iGrg3rB7G%S*R$c5!rrVhrh#<ZClMpnGrg3cHWqlJj +"R:fBEiSg4"4rp-jSf)YeGYd4rrT]tpAY'lc2O(5o;_ijao7Y5UAt8AQnilQV>gJp_Z#o6WW3"A +fX$s4XT/=@Qm7?QYl=Y&\GhiqZi0n).e<H9!Tl<;rrLq?JcC<$a8^Y~> +"s*a!J\Fq)qu6_[OS\VL!B0*=rr^-*R/$X[!5JN##d+.,a-\'+R'?Si!4`#q!42V'!M-:jrrH?? +rr3,W`rH(Arg3u*s8TOps8V)prVm0Es8TdDs8Sj]Yl4S&XRlFY!6bBA$(RBM_g&$Xs5Z0;rrE#r +Qiu"?s.o&]Qil%As7ZDY"5NqVo)4pXi;`iGrg3rB7G%S*R$c5!rrVhrh#<ZClMpnGrg3cHWqlJj +"R:fBEiSg4"4rp-jSf)YeGYd4rrT]tpAY'lc2O(5o;_ijao7Y5UAt8AQnilQV>gJp_Z#o6WW3"A +fX$s4XT/=@Qm7?QYl=Y&\GhiqZi0n).e<H9!Tl<;rrLq?JcC<$a8^Y~> +"s*a!J\Fq)qu6_[OS\VL!B0*=rr^-*R/$X[!5JN##d+.,a-\'+R'?Si!4`#q!42V'!M-:jrrH?? +rr3,W`rH(Arg3u*s8TOps8V)prVm0Es8TdDs8Sj]Yl4S&XRlFY!6bBA$(RBM_g&$Xs5Z0;rrE#r +Qiu"?s.o&]Qil%As7ZDY"5NqVo)4pXi;`iGrg3rB7G%S*R$c5!rrVhrh#<ZClMpnGrg3cHWqlJj +"R:fBEiSg4"4rp-jSf)YeGYd4rrT]tpAY'lc2O(5o;_ijao7Y5UAt8AQnilQV>gJp_Z#o6WW3"A +fX$s4XT/=@Qm7?QYl=Y&\GhiqZi0n).e<H9!Tl<;rrLq?JcC<$a8^Y~> +"s*`o]`1dPqYpS`K_59F2Wju<"1Ek"n,E=f]Rg'8%"b>U]S%>KKVAGGZ[r+/!J7HPrrEN]rr3:/ +_>j(QI_5WWK)UE/J\(kRdf9?VB)V`0*W,j<O`W_arrFipre(B(bl<e(KEcrfV>pSV3;idVL])l/ +J(ai;IK"m%Ibk$RrIb9%ir4?(KEH\cqL&9q#C[iJs6,,1M#RDUiu<IHKEHYom!\kd!e,arq>UTZ +XT*=@p&>-?KJL1=rrL`$rIb0.rVm'u!9sO`c@>hH"FQ[<aajAD%"joHab23XKTuN:_1;N<'S<"X +IS>?HKS$$"]n@GLKV8AFZ[r+/!J7HQrrFV?qYpTY2Z*LTh*6JjJcEdjJ,~> +"s*`o]`1dPqYpS`K_59F2Wju<"1Ek"n,E=f]Rg'8%"b>U]S%>KKVAGGZ[r+/!J7HPrrEN]rr3:/ +_>j(QI_5WWK)UE/J\(kRdf9?VB)V`0*W,j<O`W_arrFipre(B(bl<e(KEcrfV>pSV3;idVL])l/ +J(ai;IK"m%Ibk$RrIb9%ir4?(KEH\cqL&9q#C[iJs6,,1M#RDUiu<IHKEHYom!\kd!e,arq>UTZ +XT*=@p&>-?KJL1=rrL`$rIb0.rVm'u!9sO`c@>hH"FQ[<aajAD%"joHab23XKTuN:_1;N<'S<"X +IS>?HKS$$"]n@GLKV8AFZ[r+/!J7HQrrFV?qYpTY2Z*LTh*6JjJcEdjJ,~> +"s*`o]`1dPqYpS`K_59F2Wju<"1Ek"n,E=f]Rg'8%"b>U]S%>KKVAGGZ[r+/!J7HPrrEN]rr3:/ +_>j(QI_5WWK)UE/J\(kRdf9?VB)V`0*W,j<O`W_arrFipre(B(bl<e(KEcrfV>pSV3;idVL])l/ +J(ai;IK"m%Ibk$RrIb9%ir4?(KEH\cqL&9q#C[iJs6,,1M#RDUiu<IHKEHYom!\kd!e,arq>UTZ +XT*=@p&>-?KJL1=rrL`$rIb0.rVm'u!9sO`c@>hH"FQ[<aajAD%"joHab23XKTuN:_1;N<'S<"X +IS>?HKS$$"]n@GLKV8AFZ[r+/!J7HQrrFV?qYpTY2Z*LTh*6JjJcEdjJ,~> +!$2%<!Dgu9rr=)3rrG%?qu6[Kn,E=fI@pN=!URQ"rrG1?rVln7Yl=Y'k/I<!!N!+$rs;oGF(M&\ +s8Q$?rr3M'HN-Ucs8TQ?s8Rm]$XStnrrM%?rVlmQR/[*pJ=QWfo`+sD9;V[gj>d);!$2%<"D>1C +(pX)?"(&_A*W?!?_!:k?rVlsoch&XbrrU.ifDbdNP_f>=!okQBrr3'WkhAE&rrG^@p&>&5Wq65k +@CuO=!O6J>rr=)<rs$32p](8dIK'6L*WQ/+L&V)Qk;N>>!E@/=rrIk?rr3;U8,n$Kk5YJ+:]C@p +45p/<!H#%>rrM9#rr3!Ko(r@eju3,:!Sotks+13js*t~> +!$2%<!Dgu9rr=)3rrG%?qu6[Kn,E=fI@pN=!URQ"rrG1?rVln7Yl=Y'k/I<!!N!+$rs;oGF(M&\ +s8Q$?rr3M'HN-Ucs8TQ?s8Rm]$XStnrrM%?rVlmQR/[*pJ=QWfo`+sD9;V[gj>d);!$2%<"D>1C +(pX)?"(&_A*W?!?_!:k?rVlsoch&XbrrU.ifDbdNP_f>=!okQBrr3'WkhAE&rrG^@p&>&5Wq65k +@CuO=!O6J>rr=)<rs$32p](8dIK'6L*WQ/+L&V)Qk;N>>!E@/=rrIk?rr3;U8,n$Kk5YJ+:]C@p +45p/<!H#%>rrM9#rr3!Ko(r@eju3,:!Sotks+13js*t~> +!$2%<!Dgu9rr=)3rrG%?qu6[Kn,E=fI@pN=!URQ"rrG1?rVln7Yl=Y'k/I<!!N!+$rs;oGF(M&\ +s8Q$?rr3M'HN-Ucs8TQ?s8Rm]$XStnrrM%?rVlmQR/[*pJ=QWfo`+sD9;V[gj>d);!$2%<"D>1C +(pX)?"(&_A*W?!?_!:k?rVlsoch&XbrrU.ifDbdNP_f>=!okQBrr3'WkhAE&rrG^@p&>&5Wq65k +@CuO=!O6J>rr=)<rs$32p](8dIK'6L*WQ/+L&V)Qk;N>>!E@/=rrIk?rr3;U8,n$Kk5YJ+:]C@p +45p/<!H#%>rrM9#rr3!Ko(r@eju3,:!Sotks+13js*t~> +!$2%<!Dgu:rrHN?o`"qMk55/Z/ar]=!T%ep5lbQrrrG1?rVloOB`:9tFSGe;>;EA"rVlms2#]cO +.=2"ddf9?VB)hnV^)"H2r;QfU4T59\1$no>"G!$B..mN="aHmDs5Z0;rr<r85m&%6ruM(<"(&_A +*W,j;r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkhAE&rrG^@p&>&5Wq65k@CuO=!O6J>rr=)7 +rrJd@rr3*As8SE0r]pQH2ZE^W<65%<!JZp>rrgnCs*gR=rrLA?rr3!\iVicWg1^IO!-A,=!@m[: +rrM7?qu6]Q5Crics2Y.i~> +!$2%<!Dgu:rrHN?o`"qMk55/Z/ar]=!T%ep5lbQrrrG1?rVloOB`:9tFSGe;>;EA"rVlms2#]cO +.=2"ddf9?VB)hnV^)"H2r;QfU4T59\1$no>"G!$B..mN="aHmDs5Z0;rr<r85m&%6ruM(<"(&_A +*W,j;r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkhAE&rrG^@p&>&5Wq65k@CuO=!O6J>rr=)7 +rrJd@rr3*As8SE0r]pQH2ZE^W<65%<!JZp>rrgnCs*gR=rrLA?rr3!\iVicWg1^IO!-A,=!@m[: +rrM7?qu6]Q5Crics2Y.i~> +!$2%<!Dgu:rrHN?o`"qMk55/Z/ar]=!T%ep5lbQrrrG1?rVloOB`:9tFSGe;>;EA"rVlms2#]cO +.=2"ddf9?VB)hnV^)"H2r;QfU4T59\1$no>"G!$B..mN="aHmDs5Z0;rr<r85m&%6ruM(<"(&_A +*W,j;r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkhAE&rrG^@p&>&5Wq65k@CuO=!O6J>rr=)7 +rrJd@rr3*As8SE0r]pQH2ZE^W<65%<!JZp>rrgnCs*gR=rrLA?rr3!\iVicWg1^IO!-A,=!@m[: +rrM7?qu6]Q5Crics2Y.i~> +!$2%<!Dgu;rrQWBrUg*j2Wjo:!A3d=rrD9^gB"`srr3![ir&fVk5O*9Wd+=="'_Wb48o0[;m$#Q +#OMI_df9?VB)V`0*W#d:i&pu<!AWs?rrdkBs![O=rrmYDs8V.>r;Qa:r7_;GruM(<"(&_A*W,j; +r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkk_C[,QXh=p&>&5Wq65k@CuO=!O6J>rr=)7rrMYA +rZhWqs8SF+rS%>3rr3!uaSl,>L6hi="P-*CI\-Q=!R4F>rrG4?r;[email protected]<H9!Tl<; +rrLq?JcC<$a8^Y~> +!$2%<!Dgu;rrQWBrUg*j2Wjo:!A3d=rrD9^gB"`srr3![ir&fVk5O*9Wd+=="'_Wb48o0[;m$#Q +#OMI_df9?VB)V`0*W#d:i&pu<!AWs?rrdkBs![O=rrmYDs8V.>r;Qa:r7_;GruM(<"(&_A*W,j; +r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkk_C[,QXh=p&>&5Wq65k@CuO=!O6J>rr=)7rrMYA +rZhWqs8SF+rS%>3rr3!uaSl,>L6hi="P-*CI\-Q=!R4F>rrG4?r;[email protected]<H9!Tl<; +rrLq?JcC<$a8^Y~> +!$2%<!Dgu;rrQWBrUg*j2Wjo:!A3d=rrD9^gB"`srr3![ir&fVk5O*9Wd+=="'_Wb48o0[;m$#Q +#OMI_df9?VB)V`0*W#d:i&pu<!AWs?rrdkBs![O=rrmYDs8V.>r;Qa:r7_;GruM(<"(&_A*W,j; +r?)"<"&7,6./j/H7G%P=!L/E>rrM.?rVlsVkk_C[,QXh=p&>&5Wq65k@CuO=!O6J>rr=)7rrMYA +rZhWqs8SF+rS%>3rr3!uaSl,>L6hi="P-*CI\-Q=!R4F>rrG4?r;[email protected]<H9!Tl<; +rrLq?JcC<$a8^Y~> +%NYTElKUsRlL"WOoPM5>p&>0dl7pcSrr38pl71QUs8S%KrosO!?iL'19%*"9C]Ag_rosNhDZ0S9 +'/fdh$!Y7@i>l@us'`V?l3Qq[s&m;*`t`4brr=):rs7u:2sU&8s"Wm>rsjRLs#T-(lBDdTs8W)9 +>5eI$0`C8=pAb.5rVlt+^Afhal2tM?r@e-7"'3nD2u`(NC^AYmqs&uclMCP@3W8s[2!Egmro*tA +qu-O&IgEmjs82*HBq4JRrVlq:#grYO#l!UeX6T]a[r;61!&4BO#$)#ps8T-Jro+(Hs8SaFrosLM +rVm+4]^!gBs,`ECl3YL3s*bTflKZ/krr33rdH\>Ys*h!Il2e2-rr3#p,l7NA,Ph9;!rFA@r;Qii +#YfmMJcF'rJ,~> +%NYTElKUsRlL"WOoPM5>p&>0dl7pcSrr38pl71QUs8S%KrosO!?iL'19%*"9C]Ag_rosNhDZ0S9 +'/fdh$!Y7@i>l@us'`V?l3Qq[s&m;*`t`4brr=):rs7u:2sU&8s"Wm>rsjRLs#T-(lBDdTs8W)9 +>5eI$0`C8=pAb.5rVlt+^Afhal2tM?r@e-7"'3nD2u`(NC^AYmqs&uclMCP@3W8s[2!Egmro*tA +qu-O&IgEmjs82*HBq4JRrVlq:#grYO#l!UeX6T]a[r;61!&4BO#$)#ps8T-Jro+(Hs8SaFrosLM +rVm+4]^!gBs,`ECl3YL3s*bTflKZ/krr33rdH\>Ys*h!Il2e2-rr3#p,l7NA,Ph9;!rFA@r;Qii +#YfmMJcF'rJ,~> +%NYTElKUsRlL"WOoPM5>p&>0dl7pcSrr38pl71QUs8S%KrosO!?iL'19%*"9C]Ag_rosNhDZ0S9 +'/fdh$!Y7@i>l@us'`V?l3Qq[s&m;*`t`4brr=):rs7u:2sU&8s"Wm>rsjRLs#T-(lBDdTs8W)9 +>5eI$0`C8=pAb.5rVlt+^Afhal2tM?r@e-7"'3nD2u`(NC^AYmqs&uclMCP@3W8s[2!Egmro*tA +qu-O&IgEmjs82*HBq4JRrVlq:#grYO#l!UeX6T]a[r;61!&4BO#$)#ps8T-Jro+(Hs8SaFrosLM +rVm+4]^!gBs,`ECl3YL3s*bTflKZ/krr33rdH\>Ys*h!Il2e2-rr3#p,l7NA,Ph9;!rFA@r;Qii +#YfmMJcF'rJ,~> +!Zh<Nr%\CPs8SOkoD\fMr\=IJrr2tQr\=IQrr2tJr\=IXr;Qgi11L7_!-.un!,;B2!BaK`rrIJk +rr3,5NrT,br\=J%rr3+%10(eqrVljiqu6Xfr\=V=s8Q6jrr3:mYlF_b1,=WJ\,QC/dUqP=rrDoo +1'=ZYs%<7i"+JGnmJSdB])VfmrA"Jks8V!U1'FgqhuD@-1'>l&l!XJi"'k6gV>W.MZMa_%"dK_8 +s8UXI1&s31rrRrdd/O%FYPg3Yp](8mrA"BPrVm(C1@>,Am",-k"?b98s-3L<!(Qnd!a[WVrr2tR +r\=aXs8RP>BJM>Hr;Qgj11C1^!-8&o!,2<1!CkZ<rrLS?qu6]C:&FqloeL<6s+13rs*t~> +!Zh<Nr%\CPs8SOkoD\fMr\=IJrr2tQr\=IQrr2tJr\=IXr;Qgi11L7_!-.un!,;B2!BaK`rrIJk +rr3,5NrT,br\=J%rr3+%10(eqrVljiqu6Xfr\=V=s8Q6jrr3:mYlF_b1,=WJ\,QC/dUqP=rrDoo +1'=ZYs%<7i"+JGnmJSdB])VfmrA"Jks8V!U1'FgqhuD@-1'>l&l!XJi"'k6gV>W.MZMa_%"dK_8 +s8UXI1&s31rrRrdd/O%FYPg3Yp](8mrA"BPrVm(C1@>,Am",-k"?b98s-3L<!(Qnd!a[WVrr2tR +r\=aXs8RP>BJM>Hr;Qgj11C1^!-8&o!,2<1!CkZ<rrLS?qu6]C:&FqloeL<6s+13rs*t~> +!Zh<Nr%\CPs8SOkoD\fMr\=IJrr2tQr\=IQrr2tJr\=IXr;Qgi11L7_!-.un!,;B2!BaK`rrIJk +rr3,5NrT,br\=J%rr3+%10(eqrVljiqu6Xfr\=V=s8Q6jrr3:mYlF_b1,=WJ\,QC/dUqP=rrDoo +1'=ZYs%<7i"+JGnmJSdB])VfmrA"Jks8V!U1'FgqhuD@-1'>l&l!XJi"'k6gV>W.MZMa_%"dK_8 +s8UXI1&s31rrRrdd/O%FYPg3Yp](8mrA"BPrVm(C1@>,Am",-k"?b98s-3L<!(Qnd!a[WVrr2tR +r\=aXs8RP>BJM>Hr;Qgj11C1^!-8&o!,2<1!CkZ<rrLS?qu6]C:&FqloeL<6s+13rs*t~> +!$/$<"ip05s0lUqrrL'0a8Z1p62gfa/+NT<!F<J3rrGj@kPkRUIK'6Imk*c'!IgX(rrMb1r;Qe0 +r;6Ko@tFZ2s2G"g~> +!$/$<"ip05s0lUqrrL'0a8Z1p62gfa/+NT<!F<J3rrGj@kPkRUIK'6Imk*c'!IgX(rrMb1r;Qe0 +r;6Ko@tFZ2s2G"g~> +!$/$<"ip05s0lUqrrL'0a8Z1p62gfa/+NT<!F<J3rrGj@kPkRUIK'6Imk*c'!IgX(rrMb1r;Qe0 +r;6Ko@tFZ2s2G"g~> +!$/$<"db13PDH-0rrMD.rK@8'p\t0oa*QJ3rrTu\jQHODaFF2Q!Ki-#rrIS?JcC<$SH"*~> +!$/$<"db13PDH-0rrMD.rK@8'p\t0oa*QJ3rrTu\jQHODaFF2Q!Ki-#rrIS?JcC<$SH"*~> +!$/$<"db13PDH-0rrMD.rK@8'p\t0oa*QJ3rrTu\jQHODaFF2Q!Ki-#rrIS?JcC<$SH"*~> +!$/!;".k@+Wh04jiVeT5li$ha_US2W!P7(JrrC%;M#`Y#rrL$cJcC<$SH"*~> +!$/!;".k@+Wh04jiVeT5li$ha_US2W!P7(JrrC%;M#`Y#rrL$cJcC<$SH"*~> +!$/!;".k@+Wh04jiVeT5li$ha_US2W!P7(JrrC%;M#`Y#rrL$cJcC<$SH"*~> +!$2";!d\!iJc>iPBN]t=s+13$s,R,0~> +!$2";!d\!iJc>iPBN]t=s+13$s,R,0~> +!$2";!d\!iJc>iPBN]t=s+13$s,R,0~> +!$2%<"*pi_bhN-ufQmJr!GFXFrrGGskl1[N](l:-aMX^)JcC<$JcCf2J,~> +!$2%<"*pi_bhN-ufQmJr!GFXFrrGGskl1[N](l:-aMX^)JcC<$JcCf2J,~> +!$2%<"*pi_bhN-ufQmJr!GFXFrrGGskl1[N](l:-aMX^)JcC<$JcCf2J,~> +!$2%<!DgtnrrL>?rr3#^i7%],i9'8'!I1I7rrKi?JcC<$JcCf2J,~> +!$2%<!DgtnrrL>?rr3#^i7%],i9'8'!I1I7rrKi?JcC<$JcCf2J,~> +!$2%<!DgtnrrL>?rr3#^i7%],i9'8'!I1I7rrKi?JcC<$JcCf2J,~> +!$2%<!b/kArr2uhroFFJs8V`^mcEQnrr2ufroF.Drr2ueroF.Err3>ojlP[L;#gR`jlQI@"n;9O +jlPk.rrqcNjluO/q#:fjq>^Kimf3=RqW?o$n,E=gkiM+-rrD9^jT+iMrrD6]jT+lNrs.]Jjm[Mk +s8W&Z!;-9j!rK6?JcC<$JcCf2J,~> +!$2%<!b/kArr2uhroFFJs8V`^mcEQnrr2ufroF.Drr2ueroF.Err3>ojlP[L;#gR`jlQI@"n;9O +jlPk.rrqcNjluO/q#:fjq>^Kimf3=RqW?o$n,E=gkiM+-rrD9^jT+iMrrD6]jT+lNrs.]Jjm[Mk +s8W&Z!;-9j!rK6?JcC<$JcCf2J,~> +!$2%<!b/kArr2uhroFFJs8V`^mcEQnrr2ufroF.Drr2ueroF.Err3>ojlP[L;#gR`jlQI@"n;9O +jlPk.rrqcNjluO/q#:fjq>^Kimf3=RqW?o$n,E=gkiM+-rrD9^jT+iMrrD6]jT+lNrs.]Jjm[Mk +s8W&Z!;-9j!rK6?JcC<$JcCf2J,~> +!$2(=#N*U%n,NFQJc7S:6.5e!BkoXd7b%J#GQ'N(9%Et'ErJ!-:Y5X,D)XC@TMY[gHoD</rsik& +;`?XAh>c;<2`FX*MYR2b;p,.?^Kpm>8u4d32f[pYs&:a0rVloJ8,bFMHKbCW6N/nPJ*R'\4Z><@ +?D[\J3W:rBM=(?Cj'9[bJcC<$JcCi3J,~> +!$2(=#N*U%n,NFQJc7S:6.5e!BkoXd7b%J#GQ'N(9%Et'ErJ!-:Y5X,D)XC@TMY[gHoD</rsik& +;`?XAh>c;<2`FX*MYR2b;p,.?^Kpm>8u4d32f[pYs&:a0rVloJ8,bFMHKbCW6N/nPJ*R'\4Z><@ +?D[\J3W:rBM=(?Cj'9[bJcC<$JcCi3J,~> +!$2(=#N*U%n,NFQJc7S:6.5e!BkoXd7b%J#GQ'N(9%Et'ErJ!-:Y5X,D)XC@TMY[gHoD</rsik& +;`?XAh>c;<2`FX*MYR2b;p,.?^Kpm>8u4d32f[pYs&:a0rVloJ8,bFMHKbCW6N/nPJ*R'\4Z><@ +?D[\J3W:rBM=(?Cj'9[bJcC<$JcCi3J,~> +!$2(=!c7q^rr3"kIfB?UmOnO*/AhGeju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<%;\)^ +s8T]>s'rV>s3OI6rshuMs8Ti>s8P\[p&G&[KDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ +ruh:>rrI&?rr3&6!.0:sJcC<$OT0h~> +!$2(=!c7q^rr3"kIfB?UmOnO*/AhGeju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<%;\)^ +s8T]>s'rV>s3OI6rshuMs8Ti>s8P\[p&G&[KDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ +ruh:>rrI&?rr3&6!.0:sJcC<$OT0h~> +!$2(=!c7q^rr3"kIfB?UmOnO*/AhGeju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<%;\)^ +s8T]>s'rV>s3OI6rshuMs8Ti>s8P\[p&G&[KDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ +ruh:>rrI&?rr3&6!.0:sJcC<$OT0h~> +!$2(=#Hi'&pAb/b7fJDNKeECkLAq2Uju<=#Nr/hWKpVf="P$'CI@pN=!R+C=rr=)<rrHr?rr389 +@K0iJs8UG>p\tOub5_LV?2spsdf07IR=kM=!U2E=rrG.?qu6[Om/I"fJ=QWfo`"jnGbtE_NW+qC +5-=kbmtYnkJcC<$JcCi3J,~> +!$2(=#Hi'&pAb/b7fJDNKeECkLAq2Uju<=#Nr/hWKpVf="P$'CI@pN=!R+C=rr=)<rrHr?rr389 +@K0iJs8UG>p\tOub5_LV?2spsdf07IR=kM=!U2E=rrG.?qu6[Om/I"fJ=QWfo`"jnGbtE_NW+qC +5-=kbmtYnkJcC<$JcCi3J,~> +!$2(=#Hi'&pAb/b7fJDNKeECkLAq2Uju<=#Nr/hWKpVf="P$'CI@pN=!R+C=rr=)<rrHr?rr389 +@K0iJs8UG>p\tOub5_LV?2spsdf07IR=kM=!U2E=rrG.?qu6[Om/I"fJ=QWfo`"jnGbtE_NW+qC +5-=kbmtYnkJcC<$JcCi3J,~> +!$2%<#+^SDs8S]\rJguSs-AE=rrhICs,N-:rrIh?rr3,O8H4+1rr3#C;#UCo*W?!=Cp<p=#eOOF +\p8:8G-L`@#uf"Hs1_k>s%:`=rrJO?rr3#`1]@=S3TL#:!AWs?rrdkBs![O=rrdSCrud="NWn2; +s6k`>JcC<$JcCf2J,~> +!$2%<#+^SDs8S]\rJguSs-AE=rrhICs,N-:rrIh?rr3,O8H4+1rr3#C;#UCo*W?!=Cp<p=#eOOF +\p8:8G-L`@#uf"Hs1_k>s%:`=rrJO?rr3#`1]@=S3TL#:!AWs?rrdkBs![O=rrdSCrud="NWn2; +s6k`>JcC<$JcCf2J,~> +!$2%<#+^SDs8S]\rJguSs-AE=rrhICs,N-:rrIh?rr3,O8H4+1rr3#C;#UCo*W?!=Cp<p=#eOOF +\p8:8G-L`@#uf"Hs1_k>s%:`=rrJO?rr3#`1]@=S3TL#:!AWs?rrdkBs![O=rrdSCrud="NWn2; +s6k`>JcC<$JcCf2J,~> +!$2%<!Dgu>rrJa@qu6\_LAq2Uju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<!Go">rs-/E +s-JqMX1J3.!EOLFrs;WHs8Ti>s8P^>rr3"eKDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ +ruh:9rrKi?JcC<$JcCf2J,~> +!$2%<!Dgu>rrJa@qu6\_LAq2Uju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<!Go">rs-/E +s-JqMX1J3.!EOLFrs;WHs8Ti>s8P^>rr3"eKDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ +ruh:9rrKi?JcC<$JcCf2J,~> +!$2%<!Dgu>rrJa@qu6\_LAq2Uju<=#NrK%]k^NPcQi@!keO]^gTE"r]6W!a]!$2%<!Go">rs-/E +s-JqMX1J3.!EOLFrs;WHs8Ti>s8P^>rr3"eKDtlOkqi;<!BK3>rrfR8s"Wm>rsXFJs![O>s0sGQ +ruh:9rrKi?JcC<$JcCf2J,~> +!$2%<!Dgu>rrMD9r\jsKs8SC>rr3,`2ui#ar\jsPec4`Or\kNefDjlJ2`F*s;#gQC2[23Qs8Qo> +rr3,[email protected]\jgur;Qd"2u`g`g/U'j>EbER9%*_=%%2bJs&:`]2i[k;e49Ks"FB;3dR*pl%"IRB +coj<HF'b^CcT1t`!3#kr!PVlks+13$s,[21~> +!$2%<!Dgu>rrMD9r\jsKs8SC>rr3,`2ui#ar\jsPec4`Or\kNefDjlJ2`F*s;#gQC2[23Qs8Qo> +rr3,[email protected]\jgur;Qd"2u`g`g/U'j>EbER9%*_=%%2bJs&:`]2i[k;e49Ks"FB;3dR*pl%"IRB +coj<HF'b^CcT1t`!3#kr!PVlks+13$s,[21~> +!$2%<!Dgu>rrMD9r\jsKs8SC>rr3,`2ui#ar\jsPec4`Or\kNefDjlJ2`F*s;#gQC2[23Qs8Qo> +rr3,[email protected]\jgur;Qd"2u`g`g/U'j>EbER9%*_=%%2bJs&:`]2i[k;e49Ks"FB;3dR*pl%"IRB +coj<HF'b^CcT1t`!3#kr!PVlks+13$s,[21~> +!$2%<#44f!56(ZRroF:Fs8V`^rr3-!lMpnRroF.Drr2ueroF.Err38mjlP\%mJm4SroF:Ks8VT_ +rr3,rn,IL3roF0ZH2[aDc8Y_%#jUO5lh0fJm/$_]"SD9bs60ID!:^!f!9jFD!:g'g!9a@C!:p-h +#Nk.0nF?5Ps8D$`o`+qH*Dc*Ss+13$s,[21~> +!$2%<#44f!56(ZRroF:Fs8V`^rr3-!lMpnRroF.Drr2ueroF.Err38mjlP\%mJm4SroF:Ks8VT_ +rr3,rn,IL3roF0ZH2[aDc8Y_%#jUO5lh0fJm/$_]"SD9bs60ID!:^!f!9jFD!:g'g!9a@C!:p-h +#Nk.0nF?5Ps8D$`o`+qH*Dc*Ss+13$s,[21~> +!$2%<#44f!56(ZRroF:Fs8V`^rr3-!lMpnRroF.Drr2ueroF.Err38mjlP\%mJm4SroF:Ks8VT_ +rr3,rn,IL3roF0ZH2[aDc8Y_%#jUO5lh0fJm/$_]"SD9bs60ID!:^!f!9jFD!:g'g!9a@C!:p-h +#Nk.0nF?5Ps8D$`o`+qH*Dc*Ss+13$s,[21~> +!$/lT!I(UDhuT^&rVloB:kAXts+13$s3Udr~> +!$/lT!I(UDhuT^&rVloB:kAXts+13$s3Udr~> +!$/lT!I(UDhuT^&rVloB:kAXts+13$s3Udr~> +!$/iS!-8'$!-\;?!)nIKJcC<$JcF'rJ,~> +!$/iS!-8'$!-\;?!)nIKJcC<$JcF'rJ,~> +!$/iS!-8'$!-\;?!)nIKJcC<$JcF'rJ,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +"!.FAao7+sNW/qY`R48V"0^kcRDo1.QN,gOJcC<$JcC<$iW"E~> +"!.FAao7+sNW/qY`R48V"0^kcRDo1.QN,gOJcC<$JcC<$iW"E~> +"!.FAao7+sNW/qY`R48V"0^kcRDo1.QN,gOJcC<$JcC<$iW"E~> +"!.EcIf>N8P(N`6b'V_2rrZ3AqBEoY"!.ENAqBu5s+13$s5F!.~> +"!.EcIf>N8P(N`6b'V_2rrZ3AqBEoY"!.ENAqBu5s+13$s5F!.~> +"!.EcIf>N8P(N`6b'V_2rrZ3AqBEoY"!.ENAqBu5s+13$s5F!.~> +"!.E>FoMCApEon>!mbW@o`#"land4#rrX;A[q:3kJcC<$JcF^/J,~> +"!.E>FoMCApEon>!mbW@o`#"land4#rrX;A[q:3kJcC<$JcF^/J,~> +"!.E>FoMCApEon>!mbW@o`#"land4#rrX;A[q:3kJcC<$JcF^/J,~> +"!.F0jSo/[8C[V<!o$B@p&>9Qo`!>>s.-4irrh.os-Btirrgnos,aejrs6qrs,"Pks57Vjrr?j6 +1&u7krrYqM13WZs!+#RZ!.FhG"4R;?iIV#[s+13$s5F!.~> +"!.F0jSo/[8C[V<!o$B@p&>9Qo`!>>s.-4irrh.os-Btirrgnos,aejrs6qrs,"Pks57Vjrr?j6 +1&u7krrYqM13WZs!+#RZ!.FhG"4R;?iIV#[s+13$s5F!.~> +"!.F0jSo/[8C[V<!o$B@p&>9Qo`!>>s.-4irrh.os-Btirrgnos,aejrs6qrs,"Pks57Vjrr?j6 +1&u7krrYqM13WZs!+#RZ!.FhG"4R;?iIV#[s+13$s5F!.~> +!$2%<!r>IAqu6]a0CSoAKpVf="P$'CI@pN='[0DRFK#6>hA08oCp<s>fgPl?E3K9+!NL>Brs'\0 +[oNJ.@D2[*!M"jps+13$s+14(s*t~> +!$2%<!r>IAqu6]a0CSoAKpVf="P$'CI@pN='[0DRFK#6>hA08oCp<s>fgPl?E3K9+!NL>Brs'\0 +[oNJ.@D2[*!M"jps+13$s+14(s*t~> +!$2%<!r>IAqu6]a0CSoAKpVf="P$'CI@pN='[0DRFK#6>hA08oCp<s>fgPl?E3K9+!NL>Brs'\0 +[oNJ.@D2[*!M"jps+13$s+14(s*t~> +!$2(=!pX(@qYpTT4R`:NKpVf="P$'CI>RsX'X(@5FK#5r5/^V(Cp<s>fgPl?A%DU=!OHM>rs'\E +aAr9?;m$&R!K28Ts+13$s+14(s*t~> +!$2(=!pX(@qYpTT4R`:NKpVf="P$'CI>RsX'X(@5FK#5r5/^V(Cp<s>fgPl?A%DU=!OHM>rs'\E +aAr9?;m$&R!K28Ts+13$s+14(s*t~> +!$2(=!pX(@qYpTT4R`:NKpVf="P$'CI>RsX'X(@5FK#5r5/^V(Cp<s>fgPl?A%DU=!OHM>rs'\E +aAr9?;m$&R!K28Ts+13$s+14(s*t~> +"WdXCiHE09rrUPJp@&"^KpVf="P$'CI4>.]'JrYdFK!D[s28(?Cp<s>fgPl?A%DU=%'s[Js34F> +aAr9?;`+G=!1\W?JcC<$JcFI(J,~> +"WdXCiHE09rrUPJp@&"^KpVf="P$'CI4>.]'JrYdFK!D[s28(?Cp<s>fgPl?A%DU=%'s[Js34F> +aAr9?;`+G=!1\W?JcC<$JcFI(J,~> +"WdXCiHE09rrUPJp@&"^KpVf="P$'CI4>.]'JrYdFK!D[s28(?Cp<s>fgPl?A%DU=%'s[Js34F> +aAr9?;`+G=!1\W?JcC<$JcFI(J,~> +"<IO"K"LmZ!lf6Amf*TIQiI*^L.M>mTDnj)bY\=]C2NA<`**+VYlFaV70!9s\c2U;ZYBI>52ZC] +<WE(tb45K5pS#?Qs+13$s+146s*t~> +"<IO"K"LmZ!lf6Amf*TIQiI*^L.M>mTDnj)bY\=]C2NA<`**+VYlFaV70!9s\c2U;ZYBI>52ZC] +<WE(tb45K5pS#?Qs+13$s+146s*t~> +"<IO"K"LmZ!lf6Amf*TIQiI*^L.M>mTDnj)bY\=]C2NA<`**+VYlFaV70!9s\c2U;ZYBI>52ZC] +<WE(tb45K5pS#?Qs+13$s+146s*t~> +"!.E>4oL$;QN.!%J(j;i$,D(EKS*o.s*^O=rtN[Rs)_,ss8U#?s(knmKQ&0Bs0%"QKFEF;s0*Ve +KP)jJs/(DIKE/:MrrVEb;1\aus+13$s60K5~> +"!.E>4oL$;QN.!%J(j;i$,D(EKS*o.s*^O=rtN[Rs)_,ss8U#?s(knmKQ&0Bs0%"QKFEF;s0*Ve +KP)jJs/(DIKE/:MrrVEb;1\aus+13$s60K5~> +"!.E>4oL$;QN.!%J(j;i$,D(EKS*o.s*^O=rtN[Rs)_,ss8U#?s(knmKQ&0Bs0%"QKFEF;s0*Ve +KP)jJs/(DIKE/:MrrVEb;1\aus+13$s60K5~> +!Zh<rr0RVbs8U<pli.7-R$aGp8H6ibrr3,d\GsV)rr3)`]`5qKQiqA:s8TJ*Qisnus''RDQiq#A +s8T8$QiOknrrVn]\Ujd3s+13$s60K5~> +!Zh<rr0RVbs8U<pli.7-R$aGp8H6ibrr3,d\GsV)rr3)`]`5qKQiqA:s8TJ*Qisnus''RDQiq#A +s8T8$QiOknrrVn]\Ujd3s+13$s60K5~> +!Zh<rr0RVbs8U<pli.7-R$aGp8H6ibrr3,d\GsV)rr3)`]`5qKQiqA:s8TJ*Qisnus''RDQiq#A +s8T8$QiOknrrVn]\Ujd3s+13$s60K5~> +!$1"t!NEL+rrLY@li.!t@JKj'cgC`3!Tqsas+13$s+13us*t~> +!$1"t!NEL+rrLY@li.!t@JKj'cgC`3!Tqsas+13$s+13us*t~> +!$1"t!NEL+rrLY@li.!t@JKj'cgC`3!Tqsas+13$s+13us*t~> +!$1"t!U4S&/HJH"li."Wj+75]s+13$s2+ed~> +!$1"t!U4S&/HJH"li."Wj+75]s+13$s2+ed~> +!$1"t!U4S&/HJH"li."Wj+75]s+13$s2+ed~> +!$2(="8MHXoB-&Qp&=C[nU^_$rr`#do(.G4JcDABJ,~> +!$2(="8MHXoB-&Qp&=C[nU^_$rr`#do(.G4JcDABJ,~> +!$2(="8MHXoB-&Qp&=C[nU^_$rr`#do(.G4JcDABJ,~> +!$2(=")T&-1&V%PiV<?N"6A%arr2otkl0-5g\h'Ph>HmE!8@>M!oDM`r;QiRf%p?*!9F(/!9j.V +!WCjOrrUg'j8ArWec=e0rr`5Nf&cQ(!VYROrr`)Jf'<87!<)lI!:]mc!U0(HrrMTRr;Qlif%0?h +rr_fBf(/e>!:^!=!;Q6e!U0(Ors%i@f(]4Eo_d8?g&D!Ol2K9+rrM*Rr;Qu_f%0j#s6]a8!oX+E +r72)2s8RBo.2IL7JcDABJ,~> +!$2(=")T&-1&V%PiV<?N"6A%arr2otkl0-5g\h'Ph>HmE!8@>M!oDM`r;QiRf%p?*!9F(/!9j.V +!WCjOrrUg'j8ArWec=e0rr`5Nf&cQ(!VYROrr`)Jf'<87!<)lI!:]mc!U0(HrrMTRr;Qlif%0?h +rr_fBf(/e>!:^!=!;Q6e!U0(Ors%i@f(]4Eo_d8?g&D!Ol2K9+rrM*Rr;Qu_f%0j#s6]a8!oX+E +r72)2s8RBo.2IL7JcDABJ,~> +!$2(=")T&-1&V%PiV<?N"6A%arr2otkl0-5g\h'Ph>HmE!8@>M!oDM`r;QiRf%p?*!9F(/!9j.V +!WCjOrrUg'j8ArWec=e0rr`5Nf&cQ(!VYROrr`)Jf'<87!<)lI!:]mc!U0(HrrMTRr;Qlif%0?h +rr_fBf(/e>!:^!=!;Q6e!U0(Ors%i@f(]4Eo_d8?g&D!Ol2K9+rrM*Rr;Qu_f%0j#s6]a8!oX+E +r72)2s8RBo.2IL7JcDABJ,~> +!$2(=!H#(<rrU\+ec#LRg2BGM^An5kH2^86<m(FA!mMnWo`"s6(&\(7c<Nh@bPqMIbZRD>cN!oK +2>ouERJ-X]ZRbtR"N*i$CY/Rc"MdJrDV>$h"M.&lEnpBg!r.jWrVm0%WCB@+j8].frC-gJmJ[%d +i)?WKrrVP,JGoK[ns2a7ORE/Kmug.0Pk"eRm>h08!9!SN!oR"WrVm,bK18>*qZ"e;7KaM,s5A>( +7KEG]rrU_-eG]CPg2KMN^&S,8rC-lP56%S[7KGS@r;Qa;JcC<$TDsE~> +!$2(=!H#(<rrU\+ec#LRg2BGM^An5kH2^86<m(FA!mMnWo`"s6(&\(7c<Nh@bPqMIbZRD>cN!oK +2>ouERJ-X]ZRbtR"N*i$CY/Rc"MdJrDV>$h"M.&lEnpBg!r.jWrVm0%WCB@+j8].frC-gJmJ[%d +i)?WKrrVP,JGoK[ns2a7ORE/Kmug.0Pk"eRm>h08!9!SN!oR"WrVm,bK18>*qZ"e;7KaM,s5A>( +7KEG]rrU_-eG]CPg2KMN^&S,8rC-lP56%S[7KGS@r;Qa;JcC<$TDsE~> +!$2(=!H#(<rrU\+ec#LRg2BGM^An5kH2^86<m(FA!mMnWo`"s6(&\(7c<Nh@bPqMIbZRD>cN!oK +2>ouERJ-X]ZRbtR"N*i$CY/Rc"MdJrDV>$h"M.&lEnpBg!r.jWrVm0%WCB@+j8].frC-gJmJ[%d +i)?WKrrVP,JGoK[ns2a7ORE/Kmug.0Pk"eRm>h08!9!SN!oR"WrVm,bK18>*qZ"e;7KaM,s5A>( +7KEG]rrU_-eG]CPg2KMN^&S,8rC-lP56%S[7KGS@r;Qa;JcC<$TDsE~> +!$2(=!H#(=rr^Pl*7b&g$.aRGs8Ql>s,N-=rs.@Es8U#Z'(>Mn!krU^rVmJLFlEAaEl.jnF6<M^ +FN+8a_=IU-X^NaYrt`"Xqu=rhdf6Ufs8U/hec2gjs8Tudg%YLJQVCKYrs5BFs8TH[ir:%trrHH? +rr3)XK.X(srr__K4b3P3')7TQs8SOJoCS*2s8S@Gp@4-5oD\pMK.O&%rs%YBXT/<NSGW<iX)\0u +KX^RQ"4)95eGfIPf7(a>s(nt<rrW1aM>[ATqNHs;rr='js+13Bs*t~> +!$2(=!H#(=rr^Pl*7b&g$.aRGs8Ql>s,N-=rs.@Es8U#Z'(>Mn!krU^rVmJLFlEAaEl.jnF6<M^ +FN+8a_=IU-X^NaYrt`"Xqu=rhdf6Ufs8U/hec2gjs8Tudg%YLJQVCKYrs5BFs8TH[ir:%trrHH? +rr3)XK.X(srr__K4b3P3')7TQs8SOJoCS*2s8S@Gp@4-5oD\pMK.O&%rs%YBXT/<NSGW<iX)\0u +KX^RQ"4)95eGfIPf7(a>s(nt<rrW1aM>[ATqNHs;rr='js+13Bs*t~> +!$2(=!H#(=rr^Pl*7b&g$.aRGs8Ql>s,N-=rs.@Es8U#Z'(>Mn!krU^rVmJLFlEAaEl.jnF6<M^ +FN+8a_=IU-X^NaYrt`"Xqu=rhdf6Ufs8U/hec2gjs8Tudg%YLJQVCKYrs5BFs8TH[ir:%trrHH? +rr3)XK.X(srr__K4b3P3')7TQs8SOJoCS*2s8S@Gp@4-5oD\pMK.O&%rs%YBXT/<NSGW<iX)\0u +KX^RQ"4)95eGfIPf7(a>s(nt<rrW1aM>[ATqNHs;rr='js+13Bs*t~> +!$2(=!H#(>rrgYtbt$=`rrJF?rr3,`2uenurr35Z5QATNg+Dderr]f^iZ8!t!Go">rt)eNs0@.> +s6"m>s'*=#It+Hlrr]'Il7;i5!CGQ?rsY$Js.+]?s3cD>s"Wm>rrIY?q#:GWNQ5&trr=)<rrZoB +ruM(<#[Y7Fs5ea>F/es7"T!VCSUg_>!UMN=rsLsInURY>s/:J?gHkH2"QY'BEiT-=!Q&(>rr=): +rra_Bs06D3rrgYtbt-@`rrJI?rr3#^2Z3RUq]Yk:!V7c;rr='js+13Bs*t~> +!$2(=!H#(>rrgYtbt$=`rrJF?rr3,`2uenurr35Z5QATNg+Dderr]f^iZ8!t!Go">rt)eNs0@.> +s6"m>s'*=#It+Hlrr]'Il7;i5!CGQ?rsY$Js.+]?s3cD>s"Wm>rrIY?q#:GWNQ5&trr=)<rrZoB +ruM(<#[Y7Fs5ea>F/es7"T!VCSUg_>!UMN=rsLsInURY>s/:J?gHkH2"QY'BEiT-=!Q&(>rr=): +rra_Bs06D3rrgYtbt-@`rrJI?rr3#^2Z3RUq]Yk:!V7c;rr='js+13Bs*t~> +!$2(=!H#(>rrgYtbt$=`rrJF?rr3,`2uenurr35Z5QATNg+Dderr]f^iZ8!t!Go">rt)eNs0@.> +s6"m>s'*=#It+Hlrr]'Il7;i5!CGQ?rsY$Js.+]?s3cD>s"Wm>rrIY?q#:GWNQ5&trr=)<rrZoB +ruM(<#[Y7Fs5ea>F/es7"T!VCSUg_>!UMN=rsLsInURY>s/:J?gHkH2"QY'BEiT-=!Q&(>rr=): +rra_Bs06D3rrgYtbt-@`rrJI?rr3#^2Z3RUq]Yk:!V7c;rr='js+13Bs*t~> +!$2(=!H#(>rrh'#s$tW=rrJF?rr3Mk2uenus8W!s5QB*^s"3^5rr^F#ruM(<!Go">rt2kOs8TTE +@Vr^Vs'&*]SXkV9q#:H,mdVh+rrGI@rr3ChMuWgT@UaQ)s8Oh?rr3"LSG<*dWW'q<rVlj<rVlt4 +[f7BIrs>hR^Am_@]`3&Pq#:KoXT+iArr3#c0`D"[4Q-8(M.0qOli5^*`Vs<HjS8`Xlb3==WrE#! +_H[!=!$2";#)nfDs06C@raGm,q#:KNc2U>arr3"cL&V)Qk;N8<!HY:<rrI&?qu6X:JcC<$TDsE~> +!$2(=!H#(>rrh'#s$tW=rrJF?rr3Mk2uenus8W!s5QB*^s"3^5rr^F#ruM(<!Go">rt2kOs8TTE +@Vr^Vs'&*]SXkV9q#:H,mdVh+rrGI@rr3ChMuWgT@UaQ)s8Oh?rr3"LSG<*dWW'q<rVlj<rVlt4 +[f7BIrs>hR^Am_@]`3&Pq#:KoXT+iArr3#c0`D"[4Q-8(M.0qOli5^*`Vs<HjS8`Xlb3==WrE#! +_H[!=!$2";#)nfDs06C@raGm,q#:KNc2U>arr3"cL&V)Qk;N8<!HY:<rrI&?qu6X:JcC<$TDsE~> +!$2(=!H#(>rrh'#s$tW=rrJF?rr3Mk2uenus8W!s5QB*^s"3^5rr^F#ruM(<!Go">rt2kOs8TTE +@Vr^Vs'&*]SXkV9q#:H,mdVh+rrGI@rr3ChMuWgT@UaQ)s8Oh?rr3"LSG<*dWW'q<rVlj<rVlt4 +[f7BIrs>hR^Am_@]`3&Pq#:KoXT+iArr3#c0`D"[4Q-8(M.0qOli5^*`Vs<HjS8`Xlb3==WrE#! +_H[!=!$2";#)nfDs06C@raGm,q#:KNc2U>arr3"cL&V)Qk;N8<!HY:<rrI&?qu6X:JcC<$TDsE~> +!$2(=!H#(;rrGX?rr3"bLAq2Zju<=uGst.lTg/MU!A3d3rr=)<rrHr?rr3SB@K6@PVn/[Ps8UQZ +pAb/mEq]M6nLOS<!CGQ?rsY$Js8Q96\riK^s"Wm>rrIY?pAY06<W2pt*W?!?B=@iLr^@-E7DAe$ +aT)9]WV-8lSUg_>!UMN=rsV$Js42%u\n]pugCeK)\cGt,pAY/6WrE#!_H[!=!$2";#"7,Ds03St +rji)5p&>%`eGfIKQ\GG=!TuB=rr=)9rr=)9rr='js+13Bs*t~> +!$2(=!H#(;rrGX?rr3"bLAq2Zju<=uGst.lTg/MU!A3d3rr=)<rrHr?rr3SB@K6@PVn/[Ps8UQZ +pAb/mEq]M6nLOS<!CGQ?rsY$Js8Q96\riK^s"Wm>rrIY?pAY06<W2pt*W?!?B=@iLr^@-E7DAe$ +aT)9]WV-8lSUg_>!UMN=rsV$Js42%u\n]pugCeK)\cGt,pAY/6WrE#!_H[!=!$2";#"7,Ds03St +rji)5p&>%`eGfIKQ\GG=!TuB=rr=)9rr=)9rr='js+13Bs*t~> +!$2(=!H#(;rrGX?rr3"bLAq2Zju<=uGst.lTg/MU!A3d3rr=)<rrHr?rr3SB@K6@PVn/[Ps8UQZ +pAb/mEq]M6nLOS<!CGQ?rsY$Js8Q96\riK^s"Wm>rrIY?pAY06<W2pt*W?!?B=@iLr^@-E7DAe$ +aT)9]WV-8lSUg_>!UMN=rsV$Js42%u\n]pugCeK)\cGt,pAY/6WrE#!_H[!=!$2";#"7,Ds03St +rji)5p&>%`eGfIKQ\GG=!TuB=rr=)9rr=)9rr='js+13Bs*t~> +!$2(=!H#(;rrGX?rr3"bLAq2Zju<>?l.=P>h*:l<!A3d3rr=)<rrHr?rr3;:@K1_Qq>^5bJc#HJ +WcIh5!V%]=rrGI@rr3ChMuQnts8VVDV>i::rr3"LSG)s`a&W*<!$2%<")#(BrVkCOls@F+$N;FT +&f]0jrrJ[@rr3#c0`D"[4Q,F!jT#8@9^LLmk5PA]/+N?5!HP4>rrKu@rVlj<rVm+KW;6JnZ!6So +rr=)4rrG[?rr3"cL&V)Qk;N;=!E[;<rrGp?qYpO9JcC<$TDsE~> +!$2(=!H#(;rrGX?rr3"bLAq2Zju<>?l.=P>h*:l<!A3d3rr=)<rrHr?rr3;:@K1_Qq>^5bJc#HJ +WcIh5!V%]=rrGI@rr3ChMuQnts8VVDV>i::rr3"LSG)s`a&W*<!$2%<")#(BrVkCOls@F+$N;FT +&f]0jrrJ[@rr3#c0`D"[4Q,F!jT#8@9^LLmk5PA]/+N?5!HP4>rrKu@rVlj<rVm+KW;6JnZ!6So +rr=)4rrG[?rr3"cL&V)Qk;N;=!E[;<rrGp?qYpO9JcC<$TDsE~> +!$2(=!H#(;rrGX?rr3"bLAq2Zju<>?l.=P>h*:l<!A3d3rr=)<rrHr?rr3;:@K1_Qq>^5bJc#HJ +WcIh5!V%]=rrGI@rr3ChMuQnts8VVDV>i::rr3"LSG)s`a&W*<!$2%<")#(BrVkCOls@F+$N;FT +&f]0jrrJ[@rr3#c0`D"[4Q,F!jT#8@9^LLmk5PA]/+N?5!HP4>rrKu@rVlj<rVm+KW;6JnZ!6So +rr=)4rrG[?rr3"cL&V)Qk;N;=!E[;<rrGp?qYpO9JcC<$TDsE~> +!$2(=!H#(;rrGX?rr31nL&(cKfL5W:!ROO=rrF_?qu6]dn,*+b*W?!MG,kK?r3L5>DR'->r2b#? +o_\Xf!NL2=rrMNXr;Qff/,fJ`:X9"?q2^a>8(IY>q1kI>5McA>pjf.=rrW,cp&+gja&W*<"t]9D +s7^9?r;QlmA&J?FoE&p)r;Q]tq<dtTrrJ[@rr3St47iLPoL@j%6hC?Xo02Ho62gfa/+NW=!qu$Y +r;Qe<WrE#&`aJN?s7%Z>rrVn+_#F?7Z#'C=!$2%<!qYgXr;QdgeGfIPSqQq>s4Kd=rrVdXkPY>] +o/c@:rr='js+13Bs*t~> +!$2(=!H#(;rrGX?rr31nL&(cKfL5W:!ROO=rrF_?qu6]dn,*+b*W?!MG,kK?r3L5>DR'->r2b#? +o_\Xf!NL2=rrMNXr;Qff/,fJ`:X9"?q2^a>8(IY>q1kI>5McA>pjf.=rrW,cp&+gja&W*<"t]9D +s7^9?r;QlmA&J?FoE&p)r;Q]tq<dtTrrJ[@rr3St47iLPoL@j%6hC?Xo02Ho62gfa/+NW=!qu$Y +r;Qe<WrE#&`aJN?s7%Z>rrVn+_#F?7Z#'C=!$2%<!qYgXr;QdgeGfIPSqQq>s4Kd=rrVdXkPY>] +o/c@:rr='js+13Bs*t~> +!$2(=!H#(;rrGX?rr31nL&(cKfL5W:!ROO=rrF_?qu6]dn,*+b*W?!MG,kK?r3L5>DR'->r2b#? +o_\Xf!NL2=rrMNXr;Qff/,fJ`:X9"?q2^a>8(IY>q1kI>5McA>pjf.=rrW,cp&+gja&W*<"t]9D +s7^9?r;QlmA&J?FoE&p)r;Q]tq<dtTrrJ[@rr3St47iLPoL@j%6hC?Xo02Ho62gfa/+NW=!qu$Y +r;Qe<WrE#&`aJN?s7%Z>rrVn+_#F?7Z#'C=!$2%<!qYgXr;QdgeGfIPSqQq>s4Kd=rrVdXkPY>] +o/c@:rr='js+13Bs*t~> +!$2(=!H#(>rseACd5nGXg&M)7QI4)Lrr3GhdF$63s8V?2d3Z]XhYmHT,o6L[%Hc'c(t$ais8R#B +dC<ffrs3;IdBd]is*:UCd/f_qrr3&r!'pP`%GoLO,LOp&s8Pd:d@H*mrrbg=d?p!orrbd<d?9go +rrULHCB"5Ef$U6^dF%I`qF/fZJueqOr;P(EIBrbM!HY7=ruS!:PlLd^dF!JXdF%ahf3m"RB?pPW +d:L_Q@b(M<=T-VJ9(W&^'70_os8Vc>d9V[XdJs6SHdU58nG`FgJ"HW=!P`^Sd/ZZ7rt8-.l2UeO +dEt%YdFnR"P*XMC7fE>f<64t:!DLl9rr='js+13Bs*t~> +!$2(=!H#(>rseACd5nGXg&M)7QI4)Lrr3GhdF$63s8V?2d3Z]XhYmHT,o6L[%Hc'c(t$ais8R#B +dC<ffrs3;IdBd]is*:UCd/f_qrr3&r!'pP`%GoLO,LOp&s8Pd:d@H*mrrbg=d?p!orrbd<d?9go +rrULHCB"5Ef$U6^dF%I`qF/fZJueqOr;P(EIBrbM!HY7=ruS!:PlLd^dF!JXdF%ahf3m"RB?pPW +d:L_Q@b(M<=T-VJ9(W&^'70_os8Vc>d9V[XdJs6SHdU58nG`FgJ"HW=!P`^Sd/ZZ7rt8-.l2UeO +dEt%YdFnR"P*XMC7fE>f<64t:!DLl9rr='js+13Bs*t~> +!$2(=!H#(>rseACd5nGXg&M)7QI4)Lrr3GhdF$63s8V?2d3Z]XhYmHT,o6L[%Hc'c(t$ais8R#B +dC<ffrs3;IdBd]is*:UCd/f_qrr3&r!'pP`%GoLO,LOp&s8Pd:d@H*mrrbg=d?p!orrbd<d?9go +rrULHCB"5Ef$U6^dF%I`qF/fZJueqOr;P(EIBrbM!HY7=ruS!:PlLd^dF!JXdF%ahf3m"RB?pPW +d:L_Q@b(M<=T-VJ9(W&^'70_os8Vc>d9V[XdJs6SHdU58nG`FgJ"HW=!P`^Sd/ZZ7rt8-.l2UeO +dEt%YdFnR"P*XMC7fE>f<64t:!DLl9rr='js+13Bs*t~> +!$2(=#&Sap[f?B>r(@$+rr3(Z92#3^rr\``92GQe!3,lh!.OnH!G*,IrrAVf9)skKrrR(2B)MZ1 +BM31?rr@9B9)sbGrrW'`5lUc`JG`%?W;ceu:eQK?rr`6n98`]J"8GM^OSo+[h)/sHrr?O+9*WB8 +s5lsIUAk/mp&7SaW;?MpSAY=*"i)ONs8Vlk9*XGVs2[i+_#=98_FmPArr2uGrC[.KrVm%q*5DOR +gAFSD:&b.pX%Q+BrVlnp]);R.Zi*Msrr)j#KFd>Is1J8&!,MT6"-#rHr;HWrLY2M(!J0,*rr^WT +Zl=SrJcDABJ,~> +!$2(=#&Sap[f?B>r(@$+rr3(Z92#3^rr\``92GQe!3,lh!.OnH!G*,IrrAVf9)skKrrR(2B)MZ1 +BM31?rr@9B9)sbGrrW'`5lUc`JG`%?W;ceu:eQK?rr`6n98`]J"8GM^OSo+[h)/sHrr?O+9*WB8 +s5lsIUAk/mp&7SaW;?MpSAY=*"i)ONs8Vlk9*XGVs2[i+_#=98_FmPArr2uGrC[.KrVm%q*5DOR +gAFSD:&b.pX%Q+BrVlnp]);R.Zi*Msrr)j#KFd>Is1J8&!,MT6"-#rHr;HWrLY2M(!J0,*rr^WT +Zl=SrJcDABJ,~> +!$2(=#&Sap[f?B>r(@$+rr3(Z92#3^rr\``92GQe!3,lh!.OnH!G*,IrrAVf9)skKrrR(2B)MZ1 +BM31?rr@9B9)sbGrrW'`5lUc`JG`%?W;ceu:eQK?rr`6n98`]J"8GM^OSo+[h)/sHrr?O+9*WB8 +s5lsIUAk/mp&7SaW;?MpSAY=*"i)ONs8Vlk9*XGVs2[i+_#=98_FmPArr2uGrC[.KrVm%q*5DOR +gAFSD:&b.pX%Q+BrVlnp]);R.Zi*Msrr)j#KFd>Is1J8&!,MT6"-#rHr;HWrLY2M(!J0,*rr^WT +Zl=SrJcDABJ,~> +!$2(="/omHD;5'j*S^Spgd'Wo!O?IprrIq?g]%:[^YAbh1[3cr"/0CAFFjICs.B=A~> +!$2(="/omHD;5'j*S^Spgd'Wo!O?IprrIq?g]%:[^YAbh1[3cr"/0CAFFjICs.B=A~> +!$2(="/omHD;5'j*S^Spgd'Wo!O?IprrIq?g]%:[^YAbh1[3cr"/0CAFFjICs.B=A~> +!$0Vi!KE/qrrW+FUtktOk'abprrUPsbhW4"\q/eprrT!Kon!-os+14Fs*t~> +!$0Vi!KE/qrrW+FUtktOk'abprrUPsbhW4"\q/eprrT!Kon!-os+14Fs*t~> +!$0Vi!KE/qrrW+FUtktOk'abprrUPsbhW4"\q/eprrT!Kon!-os+14Fs*t~> +!$0Vi!O2LWrrN)%g]%<B^>&YghTjmU!RKTVrrKn$JcC<$JcGKEJ,~> +!$0Vi!O2LWrrN)%g]%<B^>&YghTjmU!RKTVrrKn$JcC<$JcGKEJ,~> +!$0Vi!O2LWrrN)%g]%<B^>&YghTjmU!RKTVrrKn$JcC<$JcGKEJ,~> +!$.X1!SDh6rrC7A5QK%#rrJ>#p&>&uU\t,l_>Z\"ec#LKV6GONJcC<$hZ&*~> +!$.X1!SDh6rrC7A5QK%#rrJ>#p&>&uU\t,l_>Z\"ec#LKV6GONJcC<$hZ&*~> +!$.X1!SDh6rrC7A5QK%#rrJ>#p&>&uU\t,l_>Z\"ec#LKV6GONJcC<$hZ&*~> +!Zh<Ir$)>4s8S:^o)Ac,,O4Up!^%].ec,^;8E]sO"TCUbZAJS\"Z/[Js,sDOrs&<E>Q=_N_"[j3 +dV8`9[J'V'\lIP@p@\FeS;d+>rrC+<,66HsrrV_<Y5SA'o\A4na8Q#>mVojjs+13$s53j,~> +!Zh<Ir$)>4s8S:^o)Ac,,O4Up!^%].ec,^;8E]sO"TCUbZAJS\"Z/[Js,sDOrs&<E>Q=_N_"[j3 +dV8`9[J'V'\lIP@p@\FeS;d+>rrC+<,66HsrrV_<Y5SA'o\A4na8Q#>mVojjs+13$s53j,~> +!Zh<Ir$)>4s8S:^o)Ac,,O4Up!^%].ec,^;8E]sO"TCUbZAJS\"Z/[Js,sDOrs&<E>Q=_N_"[j3 +dV8`9[J'V'\lIP@p@\FeS;d+>rrC+<,66HsrrV_<Y5SA'o\A4na8Q#>mVojjs+13$s53j,~> +!Zh=>rV6]S3WK-WF0PQ6rrW)nrp9Xf5Ml4O?/GS],PqE@f1,]<&cNmPVK`(?2WiUik^]N0s6V]9 +rrs_D_.`%J]_DF/b>J:\WV6>m\mk:2!r%S@rr3#S7/co^0_,/B!f!3?qu6[sa8Gr=GH(Ijs+13$ +s5<p-~> +!Zh=>rV6]S3WK-WF0PQ6rrW)nrp9Xf5Ml4O?/GS],PqE@f1,]<&cNmPVK`(?2WiUik^]N0s6V]9 +rrs_D_.`%J]_DF/b>J:\WV6>m\mk:2!r%S@rr3#S7/co^0_,/B!f!3?qu6[sa8Gr=GH(Ijs+13$ +s5<p-~> +!Zh=>rV6]S3WK-WF0PQ6rrW)nrp9Xf5Ml4O?/GS],PqE@f1,]<&cNmPVK`(?2WiUik^]N0s6V]9 +rrs_D_.`%J]_DF/b>J:\WV6>m\mk:2!r%S@rr3#S7/co^0_,/B!f!3?qu6[sa8Gr=GH(Ijs+13$ +s5<p-~> +!$2";!S0d=rrR#CrV$6nilfOArVllVrlY;kr;QfHd/<nK3o^1dHN4$"rlYl+s8V$Is3AgBs8Us! +bPB?;rr2uLrlYT(s8Ufr(X("[rVlj<qu7B09`MVcs8Q9ls2[$bs8UT^-HjTqrr2uBrlY`7s8Pal +s0OVbs8UL?rlY<.rr3,OFoRN7pAY0)@f?<-qpkZF"k`YNs/C)<rrM+mrr3&R:%\Da!F<J;rrH-? +qu6[kd"24Js+14.s*t~> +!$2";!S0d=rrR#CrV$6nilfOArVllVrlY;kr;QfHd/<nK3o^1dHN4$"rlYl+s8V$Is3AgBs8Us! +bPB?;rr2uLrlYT(s8Ufr(X("[rVlj<qu7B09`MVcs8Q9ls2[$bs8UT^-HjTqrr2uBrlY`7s8Pal +s0OVbs8UL?rlY<.rr3,OFoRN7pAY0)@f?<-qpkZF"k`YNs/C)<rrM+mrr3&R:%\Da!F<J;rrH-? +qu6[kd"24Js+14.s*t~> +!$2";!S0d=rrR#CrV$6nilfOArVllVrlY;kr;QfHd/<nK3o^1dHN4$"rlYl+s8V$Is3AgBs8Us! +bPB?;rr2uLrlYT(s8Ufr(X("[rVlj<qu7B09`MVcs8Q9ls2[$bs8UT^-HjTqrr2uBrlY`7s8Pal +s0OVbs8UL?rlY<.rr3,OFoRN7pAY0)@f?<-qpkZF"k`YNs/C)<rrM+mrr3&R:%\Da!F<J;rrH-? +qu6[kd"24Js+14.s*t~> +!$2%<!luR\qu6\6YP.tuSPTp\rr3#PGQ(D>@)`*E!@8NZrrG1?rVloGD>m?GC!H[BQ*41aD:&;e +4]%qNE7=jeFoG2CF4L;C:^KrpQMpg`*UNe4CeG:8:p'ct\P`?&!J]_2rrF"/r_NWSlgOiS\mkX< +!UMN=rrkOCs8T'>q>UNBCZ53k!F<J;rrH-?qu6[kd"24Js+14.s*t~> +!$2%<!luR\qu6\6YP.tuSPTp\rr3#PGQ(D>@)`*E!@8NZrrG1?rVloGD>m?GC!H[BQ*41aD:&;e +4]%qNE7=jeFoG2CF4L;C:^KrpQMpg`*UNe4CeG:8:p'ct\P`?&!J]_2rrF"/r_NWSlgOiS\mkX< +!UMN=rrkOCs8T'>q>UNBCZ53k!F<J;rrH-?qu6[kd"24Js+14.s*t~> +!$2%<!luR\qu6\6YP.tuSPTp\rr3#PGQ(D>@)`*E!@8NZrrG1?rVloGD>m?GC!H[BQ*41aD:&;e +4]%qNE7=jeFoG2CF4L;C:^KrpQMpg`*UNe4CeG:8:p'ct\P`?&!J]_2rrF"/r_NWSlgOiS\mkX< +!UMN=rrkOCs8T'>q>UNBCZ53k!F<J;rrH-?qu6[kd"24Js+14.s*t~> +!$2%<".O.FUAOrj*VB@42Wk#=!JQm>rrLY@rVlnMHN*pI`0)9pTDnikCp<p=&\DKOs$g8gs0HG> +>J^=[s/L,:rrJj?rr2s=qYpO9li."Q0`:qO+T;<>!Nj`DrrEjhrr3"*^@2(&\mkX<$hSPIs8TTP +mJm3cF8Gn<b'_b:rrHE?qu6[sa8>l;:!eIkJcC<$i;\<~> +!$2%<".O.FUAOrj*VB@42Wk#=!JQm>rrLY@rVlnMHN*pI`0)9pTDnikCp<p=&\DKOs$g8gs0HG> +>J^=[s/L,:rrJj?rr2s=qYpO9li."Q0`:qO+T;<>!Nj`DrrEjhrr3"*^@2(&\mkX<$hSPIs8TTP +mJm3cF8Gn<b'_b:rrHE?qu6[sa8>l;:!eIkJcC<$i;\<~> +!$2%<".O.FUAOrj*VB@42Wk#=!JQm>rrLY@rVlnMHN*pI`0)9pTDnikCp<p=&\DKOs$g8gs0HG> +>J^=[s/L,:rrJj?rr2s=qYpO9li."Q0`:qO+T;<>!Nj`DrrEjhrr3"*^@2(&\mkX<$hSPIs8TTP +mJm3cF8Gn<b'_b:rrHE?qu6[sa8>l;:!eIkJcC<$i;\<~> +!$1t:!V[r=rrJ%?o`"qMk5PA]KpVf=!S'a9rrg)o++'CSrrHr?rr3\E@K6?sf)Pd*])Q!NruM-> +ErZ0&rcJ66HN*pE*W#d9*UE_+m4eJ<!1Ee.!5nR2!$2%<!FEM/rrK]?r;QrH:B1>t_uBZ:WH7t: +!mH/@qYpS%^\e$3<QG":!DUpls+13$s5<p-~> +!$1t:!V[r=rrJ%?o`"qMk5PA]KpVf=!S'a9rrg)o++'CSrrHr?rr3\E@K6?sf)Pd*])Q!NruM-> +ErZ0&rcJ66HN*pE*W#d9*UE_+m4eJ<!1Ee.!5nR2!$2%<!FEM/rrK]?r;QrH:B1>t_uBZ:WH7t: +!mH/@qYpS%^\e$3<QG":!DUpls+13$s5<p-~> +!$1t:!V[r=rrJ%?o`"qMk5PA]KpVf=!S'a9rrg)o++'CSrrHr?rr3\E@K6?sf)Pd*])Q!NruM-> +ErZ0&rcJ66HN*pE*W#d9*UE_+m4eJ<!1Ee.!5nR2!$2%<!FEM/rrK]?r;QrH:B1>t_uBZ:WH7t: +!mH/@qYpS%^\e$3<QG":!DUpls+13$s5<p-~> +!$1t:!V[r>rrRqDqt0mh2Wk#=!JQm>[email protected]/lXCp<p="hS4Cs$kT;rs;oGruM->ErV/d +rhfd3HN*pE*W#d9*UE_+m4eG;!3#mp!IDl_rr=)<rrHH?n,EF"@f660mZ3s:MsC<A!NC/<rrU\m +deWnD?,-::!EI2;rrGj@JcC<$JcF[.J,~> +!$1t:!V[r>rrRqDqt0mh2Wk#=!JQm>[email protected]/lXCp<p="hS4Cs$kT;rs;oGruM->ErV/d +rhfd3HN*pE*W#d9*UE_+m4eG;!3#mp!IDl_rr=)<rrHH?n,EF"@f660mZ3s:MsC<A!NC/<rrU\m +deWnD?,-::!EI2;rrGj@JcC<$JcF[.J,~> +!$1t:!V[r>rrRqDqt0mh2Wk#=!JQm>[email protected]/lXCp<p="hS4Cs$kT;rs;oGruM->ErV/d +rhfd3HN*pE*W#d9*UE_+m4eG;!3#mp!IDl_rr=)<rrHH?n,EF"@f660mZ3s:MsC<A!NC/<rrU\m +deWnD?,-::!EI2;rrGj@JcC<$JcF[.J,~> +"!.ESQ2^dapEon>!f3H@oD\hLk5PA]KpVf=!S'a>rrH1pr;QdYir/lXCp<p="hS4Cs$kT;rsi8L +ruM->ErT(\s8U@jHN*pI*WQ/ET`4rl\mt+,#jj>Gs-L=s;uQ^q!H5+8rr=)<rrHH?pAY3*40AJ] +!P2b;rr]NAGGY9<!pbT@rr3&[?J>5T!h#5@qu6[sa8Gr=N19J;rrRp:iIV#[s+146s*t~> +"!.ESQ2^dapEon>!f3H@oD\hLk5PA]KpVf=!S'a>rrH1pr;QdYir/lXCp<p="hS4Cs$kT;rsi8L +ruM->ErT(\s8U@jHN*pI*WQ/ET`4rl\mt+,#jj>Gs-L=s;uQ^q!H5+8rr=)<rrHH?pAY3*40AJ] +!P2b;rr]NAGGY9<!pbT@rr3&[?J>5T!h#5@qu6[sa8Gr=N19J;rrRp:iIV#[s+146s*t~> +"!.ESQ2^dapEon>!f3H@oD\hLk5PA]KpVf=!S'a>rrH1pr;QdYir/lXCp<p="hS4Cs$kT;rsi8L +ruM->ErT(\s8U@jHN*pI*WQ/ET`4rl\mt+,#jj>Gs-L=s;uQ^q!H5+8rr=)<rrHH?pAY3*40AJ] +!P2b;rr]NAGGY9<!pbT@rr3&[?J>5T!h#5@qu6[sa8Gr=N19J;rrRp:iIV#[s+146s*t~> +"!.F7L]/>!-0>1,OHfM3rs4/s"rf])s7("+*W\IhrVlmE(B"153o^,<!Ua.j*X,I.s8PR>r;R72 +_>iTrWcJ.*7ii^IO*^g*"P=b:D".H(!U2E,rs8S9*Zg(.s5bC&*W_5mq#:=7rVln)^@qR.V#ZbY +rrK]?qu6clO,!<)rrJ(@rr3#R#lG_DoD\ajH_UB:!EI2<rrHl?qu6_+!8)l&JcC<$kl6/~> +"!.F7L]/>!-0>1,OHfM3rs4/s"rf])s7("+*W\IhrVlmE(B"153o^,<!Ua.j*X,I.s8PR>r;R72 +_>iTrWcJ.*7ii^IO*^g*"P=b:D".H(!U2E,rs8S9*Zg(.s5bC&*W_5mq#:=7rVln)^@qR.V#ZbY +rrK]?qu6clO,!<)rrJ(@rr3#R#lG_DoD\ajH_UB:!EI2<rrHl?qu6_+!8)l&JcC<$kl6/~> +"!.F7L]/>!-0>1,OHfM3rs4/s"rf])s7("+*W\IhrVlmE(B"153o^,<!Ua.j*X,I.s8PR>r;R72 +_>iTrWcJ.*7ii^IO*^g*"P=b:D".H(!U2E,rs8S9*Zg(.s5bC&*W_5mq#:=7rVln)^@qR.V#ZbY +rrK]?qu6clO,!<)rrJ(@rr3#R#lG_DoD\ajH_UB:!EI2<rrHl?qu6_+!8)l&JcC<$kl6/~> +!Zh=@r;Q]q!<2Qhr;Q]qr;QWos8Mrr!<2lqr;Q]q!<2lq!<2or!ri6"rVcitrr)lrrqucsct2PC +rr2osr;QHj!<2rs!<2Wj!Jcp<rrg.X*?E#qs8W)qrrW1K\,QF)rr2ouUltZU"L]<k*6nH^!L9>S +s8W(Ls+13$s6'E4~> +!Zh=@r;Q]q!<2Qhr;Q]qr;QWos8Mrr!<2lqr;Q]q!<2lq!<2or!ri6"rVcitrr)lrrqucsct2PC +rr2osr;QHj!<2rs!<2Wj!Jcp<rrg.X*?E#qs8W)qrrW1K\,QF)rr2ouUltZU"L]<k*6nH^!L9>S +s8W(Ls+13$s6'E4~> +!Zh=@r;Q]q!<2Qhr;Q]qr;QWos8Mrr!<2lqr;Q]q!<2lq!<2or!ri6"rVcitrr)lrrqucsct2PC +rr2osr;QHj!<2rs!<2Wj!Jcp<rrg.X*?E#qs8W)qrrW1K\,QF)rr2ouUltZU"L]<k*6nH^!L9>S +s8W(Ls+13$s6'E4~> +!$-XjhZ!ZCKWKb)JcC<$W;hA~> +!$-XjhZ!ZCKWKb)JcC<$W;hA~> +!$-XjhZ!ZCKWKb)JcC<$W;hA~> +!$-XjhZ!VoV1JYts+13Js*t~> +!$-XjhZ!VoV1JYts+13Js*t~> +!$-XjhZ!VoV1JYts+13Js*t~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +"!.EGKDtlRpH/DRMZ3VYn3d5LP5bIij\#Q@RfEEb3<0$WGlA]a6N$i_#?;`a8,rVfC&T+R;>l(G +JcC<$JcE=]J,~> +"!.EGKDtlRpH/DRMZ3VYn3d5LP5bIij\#Q@RfEEb3<0$WGlA]a6N$i_#?;`a8,rVfC&T+R;>l(G +JcC<$JcE=]J,~> +"!.EGKDtlRpH/DRMZ3VYn3d5LP5bIij\#Q@RfEEb3<0$WGlA]a6N$i_#?;`a8,rVfC&T+R;>l(G +JcC<$JcE=]J,~> +"!.E>FoMCDpEop4IfB?]mOnO*LB%;6+?0=\NrT.U,6.[sQi@!ceO]]>#=@//1]RJsW;cet`*%Zk +JcC<$JcE=]J,~> +"!.E>FoMCDpEop4IfB?]mOnO*LB%;6+?0=\NrT.U,6.[sQi@!ceO]]>#=@//1]RJsW;cet`*%Zk +JcC<$JcE=]J,~> +"!.E>FoMCDpEop4IfB?]mOnO*LB%;6+?0=\NrT.U,6.[sQi@!ceO]]>#=@//1]RJsW;cet`*%Zk +JcC<$JcE=]J,~> +"!.E>FoMCDpEop4?iIkU[4_KFLB#Xsj#@!uNrT.U,6.[sQi@!ceO]]>#=@//1]RJsJ,[7bPZ`S; +JcC<$JcE=]J,~> +"!.E>FoMCDpEop4?iIkU[4_KFLB#Xsj#@!uNrT.U,6.[sQi@!ceO]]>#=@//1]RJsJ,[7bPZ`S; +JcC<$JcE=]J,~> +"!.E>FoMCDpEop4?iIkU[4_KFLB#Xsj#@!uNrT.U,6.[sQi@!ceO]]>#=@//1]RJsJ,[7bPZ`S; +JcC<$JcE=]J,~> +"!.E>FoMCDpEop4/cJof<%e3:L;e#pju<=#NrT.U,6.[sQi@!neO]`?`bsu(1]RJs4T/F`P_&jc +s+13$s185\~> +"!.E>FoMCDpEop4/cJof<%e3:L;e#pju<=#NrT.U,6.[sQi@!neO]`?`bsu(1]RJs4T/F`P_&jc +s+13$s185\~> +"!.E>FoMCDpEop4/cJof<%e3:L;e#pju<=#NrT.U,6.[sQi@!neO]`?`bsu(1]RJs4T/F`P_&jc +s+13$s185\~> +"!.E>FoMCDN@+[tIfB?]mOnO*7t'7oju<=#NrT.U,6.[sQi@!neO]`?@(lU)1]RJsW.Fu"s+13$ +s0_lW~> +"!.E>FoMCDN@+[tIfB?]mOnO*7t'7oju<=#NrT.U,6.[sQi@!neO]`?@(lU)1]RJsW.Fu"s+13$ +s0_lW~> +"!.E>FoMCDN@+[tIfB?]mOnO*7t'7oju<=#NrT.U,6.[sQi@!neO]`?@(lU)1]RJsW.Fu"s+13$ +s0_lW~> +"!.EqJc9EfN$eRsIfB?]mOnO*:>,[Iju<=#4DS_H%ZgY6I/[miEjG_O-r4Vf'q,*@H2_RZNIh+\ +s+13$s1//[~> +"!.EqJc9EfN$eRsIfB?]mOnO*:>,[Iju<=#4DS_H%ZgY6I/[miEjG_O-r4Vf'q,*@H2_RZNIh+\ +s+13$s1//[~> +"!.EqJc9EfN$eRsIfB?]mOnO*:>,[Iju<=#4DS_H%ZgY6I/[miEjG_O-r4Vf'q,*@H2_RZNIh+\ +s+13$s1//[~> +"!.FAg]"G\n0\1pfDbdQqS3'fgA_*SpVQscrNQKo5QCc2rilU?s8RLcrilTd;#gR>rilI@JcC<$ +JcC<$\c70~> +"!.FAg]"G\n0\1pfDbdQqS3'fgA_*SpVQscrNQKo5QCc2rilU?s8RLcrilTd;#gR>rilI@JcC<$ +JcC<$\c70~> +"!.FAg]"G\n0\1pfDbdQqS3'fgA_*SpVQscrNQKo5QCc2rilU?s8RLcrilTd;#gR>rilI@JcC<$ +JcC<$\c70~> +"!.EOOT,7\pEo5+!Sp!8rrM9Lrr3#lh1>TWs+13$s0DZT~> +"!.EOOT,7\pEo5+!Sp!8rrM9Lrr3#lh1>TWs+13$s0DZT~> +"!.EOOT,7\pEo5+!Sp!8rrM9Lrr3#lh1>TWs+13$s0DZT~> +"!.F:N;agu,jt!u!W;G<s+13$s+13Es*t~> +"!.F:N;agu,jt!u!W;G<s+13$s+13Es*t~> +"!.F:N;agu,jt!u!W;G<s+13$s+13Es*t~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$1k7!Tr3hs+13$s+130s*t~> +!$1k7!Tr3hs+13$s+130s*t~> +!$1k7!Tr3hs+13$s+130s*t~> +!$1k7!M=gls+13$s+130s*t~> +!$1k7!M=gls+13$s+130s*t~> +!$1k7!M=gls+13$s+130s*t~> +!$1k7!M=gls+13$s+130s*t~> +!$1k7!M=gls+13$s+130s*t~> +!$1k7!M=gls+13$s+130s*t~> +"!.FA\c-1DC]FF,IfB?Jon%bpJcC<$JcCo5J,~> +"!.FA\c-1DC]FF,IfB?Jon%bpJcC<$JcCo5J,~> +"!.FA\c-1DC]FF,IfB?Jon%bpJcC<$JcCo5J,~> +"!.EWHiCG[ZXj*.IfKF\:r@kaJcC<$JcCo5J,~> +"!.EWHiCG[ZXj*.IfKF\:r@kaJcC<$JcCo5J,~> +"!.EWHiCG[ZXj*.IfKF\:r@kaJcC<$JcCo5J,~> +"!.E>FoMCHpEop4IX`oYeq*jPs+13$s,m>3~> +"!.E>FoMCHpEop4IX`oYeq*jPs+13$s,m>3~> +"!.E>FoMCHpEop4IX`oYeq*jPs+13$s,m>3~> +"!.E>FoMCGpEop4%[H&MJcC<$JcC<$OT0h~> +"!.E>FoMCGpEop4%[H&MJcC<$JcC<$OT0h~> +"!.E>FoMCGpEop4%[H&MJcC<$JcC<$OT0h~> +"!.E>FoMCHpEop4IXWfXf7EsQs+13$s,m>3~> +"!.E>FoMCHpEop4IXWfXf7EsQs+13$s,m>3~> +"!.E>FoMCHpEop4IXWfXf7EsQs+13$s,m>3~> +"!.EWHiCJ\Zt'-.IfKF[:W.haJcC<$JcCo5J,~> +"!.EWHiCJ\Zt'-.IfKF[:W.haJcC<$JcCo5J,~> +"!.EWHiCJ\Zt'-.IfKF[:W.haJcC<$JcCo5J,~> +"!.FA\Gg"ACB+=QZ2Xb(omhVnJcC<$JcCo5J,~> +"!.FA\Gg"ACB+=QZ2Xb(omhVnJcC<$JcCo5J,~> +"!.FA\Gg"ACB+=QZ2Xb(omhVnJcC<$JcCo5J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$1>(!5\M"!/Q4+JcC<$JcDMFJ,~> +!$1>(!5\M"!/Q4+JcC<$JcDMFJ,~> +!$1>(!5\M"!/Q4+JcC<$JcDMFJ,~> +!$1>(!NTW+fE%aPJcC<$JcC<$U]5i~> +!$1>(!NTW+fE%aPJcC<$JcC<$U]5i~> +!$1>(!NTW+fE%aPJcC<$JcC<$U]5i~> +!$2";!UqE7rrS:OqY'piX)\(;!Phrks+13$s+13Fs*t~> +!$2";!UqE7rrS:OqY'piX)\(;!Phrks+13$s+13Fs*t~> +!$2";!UqE7rrS:OqY'piX)\(;!Phrks+13$s+13Fs*t~> +!$2%<!o?]]rVlqMU\FN_!NU5<rrKo?JcC<$JcC<$U]5i~> +!$2%<!o?]]rVlqMU\FN_!NU5<rrKo?JcC<$JcC<$U]5i~> +!$2%<!o?]]rVlqMU\FN_!NU5<rrKo?JcC<$JcC<$U]5i~> +!$2(="4M)A*W5p=I\Q`7rrK0?r;Qf5>_2p+s+13$s.fUE~> +!$2(="4M)A*W5p=I\Q`7rrK0?r;Qf5>_2p+s+13$s.fUE~> +!$2(="4M)A*W5p=I\Q`7rrK0?r;Qf5>_2p+s+13$s.fUE~> +#9EjEc[=+>*W,j;JsuK7!NU5<rrKo?JcC<$JcC<$U]5i~> +#9EjEc[=+>*W,j;JsuK7!NU5<rrKo?JcC<$JcC<$U]5i~> +#9EjEc[=+>*W,j;JsuK7!NU5<rrKo?JcC<$JcC<$U]5i~> +#9EilJ'@rm*W#d9*VfX8X)\(;!Phrks+13$s+13Fs*t~> +#9EilJ'@rm*W#d9*VfX8X)\(;!Phrks+13$s+13Fs*t~> +#9EilJ'@rm*W#d9*VfX8X)\(;!Phrks+13$s+13Fs*t~> +"!.E>.fNZR$Zu=H!Ht@8rrK0?r;Qf5>_2p+s+13$s.fUE~> +"!.E>.fNZR$Zu=H!Ht@8rrK0?r;Qf5>_2p+s+13$s.fUE~> +"!.E>.fNZR$Zu=H!Ht@8rrK0?r;Qf5>_2p+s+13$s.fUE~> +!Zh=*rP/FLao25@FK>?7rrK0?r;Qf5>_2p+s+13$s.fUE~> +!Zh=*rP/FLao25@FK>?7rrK0?r;Qf5>_2p+s+13$s.fUE~> +!Zh=*rP/FLao25@FK>?7rrK0?r;Qf5>_2p+s+13$s.fUE~> +!$1t:!$2%<!dUd@p\t8pEW#h;^g)HjJcC<$JcDMFJ,~> +!$1t:!$2%<!dUd@p\t8pEW#h;^g)HjJcC<$JcDMFJ,~> +!$1t:!$2%<!dUd@p\t8pEW#h;^g)HjJcC<$JcDMFJ,~> +!$1t:!&FQR!g'2VpAY/oEW#h;^g)HjJcC<$JcDMFJ,~> +!$1t:!&FQR!g'2VpAY/oEW#h;^g)HjJcC<$JcDMFJ,~> +!$1t:!&FQR!g'2VpAY/oEW#h;^g)HjJcC<$JcDMFJ,~> +!$1>(!NU5<rrKo?JcC<$JcC<$U]5i~> +!$1>(!NU5<rrKo?JcC<$JcC<$U]5i~> +!$1>(!NU5<rrKo?JcC<$JcC<$U]5i~> +!$1>(!NSrmXT=#YJcC<$JcC<$U]5i~> +!$1>(!NSrmXT=#YJcC<$JcC<$U]5i~> +!$1>(!NSrmXT=#YJcC<$JcC<$U]5i~> +!$1>(!71L[!2G,FJcC<$JcDMFJ,~> +!$1>(!71L[!2G,FJcC<$JcDMFJ,~> +!$1>(!71L[!2G,FJcC<$JcDMFJ,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +!$-XjJcC<$JcC?%J,~> +%%EndData +showpage +%%Trailer +end +%%EOF diff --git a/lib/stdlib/doc/src/ushell2.gif b/lib/stdlib/doc/src/ushell2.gif Binary files differnew file mode 100644 index 0000000000..273cf2078a --- /dev/null +++ b/lib/stdlib/doc/src/ushell2.gif diff --git a/lib/stdlib/doc/src/ushell2.ps b/lib/stdlib/doc/src/ushell2.ps new file mode 100644 index 0000000000..e6db3c2be2 --- /dev/null +++ b/lib/stdlib/doc/src/ushell2.ps @@ -0,0 +1,404 @@ +%!PS-Adobe-3.0 +%%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner +%%Title: ushell2.ps +%%CreationDate: Mon Mar 16 09:52:14 2009 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%Pages: 1 +%%BoundingBox: 14 14 468 74 +%%EndComments +%%BeginProlog +% Use own dictionary to avoid conflicts +10 dict begin +%%EndProlog +%%Page: 1 1 +% Translate for offset +14.173228346456694 14.173228346456694 translate +% Translate to begin of first scanline +0 59.527559055118118 translate +453.54330708661422 -59.527559055118118 scale +% Image geometry +640 84 8 +% Transformation matrix +[ 640 0 0 84 0 0 ] +% Strings to hold RGB-samples per scanline +/rstr 640 string def +/gstr 640 string def +/bstr 640 string def +{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop} +{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop} +{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop} +true 3 +%%BeginData: 18704 ASCII Bytes +colorimage +J`MCCJ`MCCJ`M=~> +J`MCCJ`MCCJ`M=~> +J`MCCJ`MCCJ`M=~> +!)nG7JO+iQJO+lRJ,~> +!)nG7JO+iQJO+lRJ,~> +!)nG7JO+iQJO+lRJ,~> +!D=/Y=b0_,=b0_.=b$~> +!D=/Y=b0_,=b0_.=b$~> +!D=/Y=b0_,=b0_.=b$~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M>rrKOJQ2^i3JcC<$JcFU,J,~> +!D>M>rrKOJQ2^i3JcC<$JcFU,J,~> +!D>M>rrKOJQ2^i3JcC<$JcFU,J,~> +"%t`UXo(ooJ,'$ES](+!!dROKr;Qh<:2'>#!I!f.rr]@2s).a0!581-!+,Ru!6ss3!kNp@p\t9X +H-uWnOA=s3rrK.0nG`Jtr;QbGr_<HIrVlo/@tFZ2s+14-s*t~> +"%t`UXo(ooJ,'$ES](+!!dROKr;Qh<:2'>#!I!f.rr]@2s).a0!581-!+,Ru!6ss3!kNp@p\t9X +H-uWnOA=s3rrK.0nG`Jtr;QbGr_<HIrVlo/@tFZ2s+14-s*t~> +"%t`UXo(ooJ,'$ES](+!!dROKr;Qh<:2'>#!I!f.rr]@2s).a0!581-!+,Ru!6ss3!kNp@p\t9X +H-uWnOA=s3rrK.0nG`Jtr;QbGr_<HIrVlo/@tFZ2s+14-s*t~> +"A:iVM0T!F!8RAL!HP42rrUp#*W5p=fZ5E4rrG1@rr3+VQ2`JQrQbK2q#:?CrQbLB\*j7sS:L>5 +!T-**rrJOjli.%FchRG<!HlihrrIe?nc&Yn]MJP,!J%!FcN0Vnrr3#u++aHCs+14-s*t~> +"A:iVM0T!F!8RAL!HP42rrUp#*W5p=fZ5E4rrG1@rr3+VQ2`JQrQbK2q#:?CrQbLB\*j7sS:L>5 +!T-**rrJOjli.%FchRG<!HlihrrIe?nc&Yn]MJP,!J%!FcN0Vnrr3#u++aHCs+14-s*t~> +"A:iVM0T!F!8RAL!HP42rrUp#*W5p=fZ5E4rrG1@rr3+VQ2`JQrQbK2q#:?CrQbLB\*j7sS:L>5 +!T-**rrJOjli.%FchRG<!HlihrrIe?nc&Yn]MJP,!J%!FcN0Vnrr3#u++aHCs+14-s*t~> +"A:iVM3Rl:!;QQc#kn;uEiSm+o_8@b!;HKb!;HEk!$;%;!V[r6rs;$Hs8VtORf>#.rq$3eoD\lN +QMU(M!l&CArVllrrU^6ks5-$;rq$<ks8W#qoFLs$rV6Ego^r._r:GB$o^qnX!W2]krs&2ss8)B[ +rVlg+qXdY#o_/=bKUDN+o_/%Z$2J#IrQSC<s'rY>rrMrfrVloH97d+os+14.s*t~> +"A:iVM3Rl:!;QQc#kn;uEiSm+o_8@b!;HKb!;HEk!$;%;!V[r6rs;$Hs8VtORf>#.rq$3eoD\lN +QMU(M!l&CArVllrrU^6ks5-$;rq$<ks8W#qoFLs$rV6Ego^r._r:GB$o^qnX!W2]krs&2ss8)B[ +rVlg+qXdY#o_/=bKUDN+o_/%Z$2J#IrQSC<s'rY>rrMrfrVloH97d+os+14.s*t~> +"A:iVM3Rl:!;QQc#kn;uEiSm+o_8@b!;HKb!;HEk!$;%;!V[r6rs;$Hs8VtORf>#.rq$3eoD\lN +QMU(M!l&CArVllrrU^6ks5-$;rq$<ks8W#qoFLs$rV6Ego^r._r:GB$o^qnX!W2]krs&2ss8)B[ +rVlg+qXdY#o_/=bKUDN+o_/%Z$2J#IrQSC<s'rY>rrMrfrVloH97d+os+14.s*t~> +#>7/YM1+"-g&D!PlY?DI$r#a^Efa$E-rf=.k?@j5!F+acrr=,;rrMj@o`#1<s8Sp?s8O^er[7f! +nFce_n:I\.rrK]@r;QcHr?qfQqqj5tr[7lYrV35f-kO2nd:1^L-n*1:a!_W=-n+farrK!?rr35q +.KBF2-jn]-rsk_N%3R&fs8Rb&=stdhj7rWTKtI?a"NGcfA%MI8!T6+ls+13$s5<p-~> +#>7/YM1+"-g&D!PlY?DI$r#a^Efa$E-rf=.k?@j5!F+acrr=,;rrMj@o`#1<s8Sp?s8O^er[7f! +nFce_n:I\.rrK]@r;QcHr?qfQqqj5tr[7lYrV35f-kO2nd:1^L-n*1:a!_W=-n+farrK!?rr35q +.KBF2-jn]-rsk_N%3R&fs8Rb&=stdhj7rWTKtI?a"NGcfA%MI8!T6+ls+13$s5<p-~> +#>7/YM1+"-g&D!PlY?DI$r#a^Efa$E-rf=.k?@j5!F+acrr=,;rrMj@o`#1<s8Sp?s8O^er[7f! +nFce_n:I\.rrK]@r;QcHr?qfQqqj5tr[7lYrV35f-kO2nd:1^L-n*1:a!_W=-n+farrK!?rr35q +.KBF2-jn]-rsk_N%3R&fs8Rb&=stdhj7rWTKtI?a"NGcfA%MI8!T6+ls+13$s5<p-~> +#>7/YM'th_:B(7oI@pN=%,$43E\H&Es1hq?B=@g>!OQP=rr=,;rrMj@o`#1<s8Sp?s8Qb.rr3"H +U%SEdTmZ8-!P2e8rrb=Bh[t\DrrXkBdn0N<#U90GWZSDDruV1>!J6g6rs#?Ds3C3-.K08I6JDA; +!EI5>rs"-+b5_Li9CVrcA%M^:\[g>jrrM%@JcC<$JcF[.J,~> +#>7/YM'th_:B(7oI@pN=%,$43E\H&Es1hq?B=@g>!OQP=rr=,;rrMj@o`#1<s8Sp?s8Qb.rr3"H +U%SEdTmZ8-!P2e8rrb=Bh[t\DrrXkBdn0N<#U90GWZSDDruV1>!J6g6rs#?Ds3C3-.K08I6JDA; +!EI5>rs"-+b5_Li9CVrcA%M^:\[g>jrrM%@JcC<$JcF[.J,~> +#>7/YM'th_:B(7oI@pN=%,$43E\H&Es1hq?B=@g>!OQP=rr=,;rrMj@o`#1<s8Sp?s8Qb.rr3"H +U%SEdTmZ8-!P2e8rrb=Bh[t\DrrXkBdn0N<#U90GWZSDDruV1>!J6g6rs#?Ds3C3-.K08I6JDA; +!EI5>rs"-+b5_Li9CVrcA%M^:\[g>jrrM%@JcC<$JcF[.J,~> +"A:iVM3Ro;!O.@YS-6(rs)P.=rrg,Cs(?9LS,mM@rVlj=qu6]k-M7<@Ff=JZXSVqtI%g96!p59A +mJd3uA,Q?,li!=U,37WFrVlsOnC'u-rraPCs/L,=rr@3@rrI_@p&>5nG5k:_oI9b=!CGN<rrH-@ +rVlnOR/[*ddS'*0#%P7Eo4(4*rVloV4b<Was+14.s*t~> +"A:iVM3Ro;!O.@YS-6(rs)P.=rrg,Cs(?9LS,mM@rVlj=qu6]k-M7<@Ff=JZXSVqtI%g96!p59A +mJd3uA,Q?,li!=U,37WFrVlsOnC'u-rraPCs/L,=rr@3@rrI_@p&>5nG5k:_oI9b=!CGN<rrH-@ +rVlnOR/[*ddS'*0#%P7Eo4(4*rVloV4b<Was+14.s*t~> +"A:iVM3Ro;!O.@YS-6(rs)P.=rrg,Cs(?9LS,mM@rVlj=qu6]k-M7<@Ff=JZXSVqtI%g96!p59A +mJd3uA,Q?,li!=U,37WFrVlsOnC'u-rraPCs/L,=rr@3@rrI_@p&>5nG5k:_oI9b=!CGN<rrH-@ +rVlnOR/[*ddS'*0#%P7Eo4(4*rVloV4b<Was+14.s*t~> +"A:iVM3Rl:!3lHR"G!EMEiT-="Me=CB3bCd!4;_)!$;%;!V[r5rr`6B_HQd8!IUU7rrKi?m/I*t +A,ZE.oRHgj"!$CZ55kK`/b%4\rVm!Equ<[:qYpSJS+ZdcVKVu6ch&[brrGI?r;QdtaSl,>KUDc= +!RaX1rrHW@rr3#'D#OA7i&uYkJcC<$i;\<~> +"A:iVM3Rl:!3lHR"G!EMEiT-="Me=CB3bCd!4;_)!$;%;!V[r5rr`6B_HQd8!IUU7rrKi?m/I*t +A,ZE.oRHgj"!$CZ55kK`/b%4\rVm!Equ<[:qYpSJS+ZdcVKVu6ch&[brrGI?r;QdtaSl,>KUDc= +!RaX1rrHW@rr3#'D#OA7i&uYkJcC<$i;\<~> +"A:iVM3Rl:!3lHR"G!EMEiT-="Me=CB3bCd!4;_)!$;%;!V[r5rr`6B_HQd8!IUU7rrKi?m/I*t +A,ZE.oRHgj"!$CZ55kK`/b%4\rVm!Equ<[:qYpSJS+ZdcVKVu6ch&[brrGI?r;QdtaSl,>KUDc= +!RaX1rrHW@rr3#'D#OA7i&uYkJcC<$i;\<~> +"A:iVM3Ro;!O'H@rrgMCs)P.=rrg,Cs(Ae8rr=,;rrMj@o`#$m+2V4\rrITArr3"HU&P&nhI3>\ +rrVG(_X.:(jbC#[email protected]($+6gRf<<h/b%4\rVm!Equ<[:qYp\MS,`M0q#:PqG,("4kUHK1 +!CGN<rs)QFs6>F?KUDc=!RaX1rrHW@rr3#'D#XG9rb/]js+13$s5<p-~> +"A:iVM3Ro;!O'H@rrgMCs)P.=rrg,Cs(Ae8rr=,;rrMj@o`#$m+2V4\rrITArr3"HU&P&nhI3>\ +rrVG(_X.:(jbC#[email protected]($+6gRf<<h/b%4\rVm!Equ<[:qYp\MS,`M0q#:PqG,("4kUHK1 +!CGN<rs)QFs6>F?KUDc=!RaX1rrHW@rr3#'D#XG9rb/]js+13$s5<p-~> +"A:iVM3Ro;!O'H@rrgMCs)P.=rrg,Cs(Ae8rr=,;rrMj@o`#$m+2V4\rrITArr3"HU&P&nhI3>\ +rrVG(_X.:(jbC#[email protected]($+6gRf<<h/b%4\rVm!Equ<[:qYp\MS,`M0q#:PqG,("4kUHK1 +!CGN<rs)QFs6>F?KUDc=!RaX1rrHW@rr3#'D#XG9rb/]js+13$s5<p-~> +"A:iVM'r6h"*ae$E;i3->g`RlWrE#$^g6ulB)Y-tHN*pIEC1"!K)YcQBL)tmMtR)OX^KZXrrL26 +r^-^;k5PA^aT->ZrrLn@lMgmTJH#QLq5"!W"d:Fsh_(&j6Na7`oU5YF"K_V&WcIt9"Q"/d6bE-n% +HrJ%lcE#Es8S]Y&NNhhrs-tX6W;80KUDc=!RaX1rrL\]r^-^"f`(mOrZ?^kJcC<$huA3~> +"A:iVM'r6h"*ae$E;i3->g`RlWrE#$^g6ulB)Y-tHN*pIEC1"!K)YcQBL)tmMtR)OX^KZXrrL26 +r^-^;k5PA^aT->ZrrLn@lMgmTJH#QLq5"!W"d:Fsh_(&j6Na7`oU5YF"K_V&WcIt9"Q"/d6bE-n% +HrJ%lcE#Es8S]Y&NNhhrs-tX6W;80KUDc=!RaX1rrL\]r^-^"f`(mOrZ?^kJcC<$huA3~> +"A:iVM'r6h"*ae$E;i3->g`RlWrE#$^g6ulB)Y-tHN*pIEC1"!K)YcQBL)tmMtR)OX^KZXrrL26 +r^-^;k5PA^aT->ZrrLn@lMgmTJH#QLq5"!W"d:Fsh_(&j6Na7`oU5YF"K_V&WcIt9"Q"/d6bE-n% +HrJ%lcE#Es8S]Y&NNhhrs-tX6W;80KUDc=!RaX1rrL\]r^-^"f`(mOrZ?^kJcC<$huA3~> +"%t`Umek`?jT#8Drn.G5s8VBUrr3,pkPtSCrn.;4rr2uYrn.;6rr2uWrn.;8p&>'hir&fVh#>t, +mJ[%dpY"j1rrMuVlMgqTJ#rYL!;QQH"nL[MqW%/Gf`V$Ls7H9C"T&/uoBQ/O"6eFkrV-<pmdL2U +hZ!NTm/GZ<h>I9Win<2gs6]=TrrMoUn,ECKrn.;5rVlm_hLY]Xs+14-s*t~> +"%t`Umek`?jT#8Drn.G5s8VBUrr3,pkPtSCrn.;4rr2uYrn.;6rr2uWrn.;8p&>'hir&fVh#>t, +mJ[%dpY"j1rrMuVlMgqTJ#rYL!;QQH"nL[MqW%/Gf`V$Ls7H9C"T&/uoBQ/O"6eFkrV-<pmdL2U +hZ!NTm/GZ<h>I9Win<2gs6]=TrrMoUn,ECKrn.;5rVlm_hLY]Xs+14-s*t~> +"%t`Umek`?jT#8Drn.G5s8VBUrr3,pkPtSCrn.;4rr2uYrn.;6rr2uWrn.;8p&>'hir&fVh#>t, +mJ[%dpY"j1rrMuVlMgqTJ#rYL!;QQH"nL[MqW%/Gf`V$Ls7H9C"T&/uoBQ/O"6eFkrV-<pmdL2U +hZ!NTm/GZ<h>I9Win<2gs6]=TrrMoUn,ECKrn.;5rVlm_hLY]Xs+14-s*t~> +!D>M>rrN#pQ2^jZJcC<$JcFU,J,~> +!D>M>rrN#pQ2^jZJcC<$JcFU,J,~> +!D>M>rrN#pQ2^jZJcC<$JcFU,J,~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>NQrrK"krVlo0ipm$KT)JZh\GVHh_h%i=s+13$s/Z0M~> +!D>NQrrK"krVlo0ipm$KT)JZh\GVHh_h%i=s+13$s/Z0M~> +!D>NQrrK"krVlo0ipm$KT)JZh\GVHh_h%i=s+13$s/Z0M~> +!D>NRrrSc-mJ[%d[sIB4rsbK>%<J'>s0[duMN!M0JcC<$JcC<$X8d\~> +!D>NRrrSc-mJ[%d[sIB4rsbK>%<J'>s0[duMN!M0JcC<$JcC<$X8d\~> +!D>NRrrSc-mJ[%d[sIB4rsbK>%<J'>s0[duMN!M0JcC<$JcC<$X8d\~> +#>7/Ys.,5omJQtc^LI'5rsP9XW>)=oS,`M<TDjEAJcC<$JcD\KJ,~> +#>7/Ys.,5omJQtc^LI'5rsP9XW>)=oS,`M<TDjEAJcC<$JcD\KJ,~> +#>7/Ys.,5omJQtc^LI'5rsP9XW>)=oS,`M<TDjEAJcC<$JcD\KJ,~> +#>7/YUPnOomJHnacVF36$>6gI*rkZbs8P:?JcC<$JcC<$VuM8~> +#>7/YUPnOomJHnacVF36$>6gI*rkZbs8P:?JcC<$JcC<$VuM8~> +#>7/YUPnOomJHnacVF36$>6gI*rkZbs8P:?JcC<$JcC<$VuM8~> +#>7/YoCW&:mJ?h`dn0<6"RfFC*W>s:"6h]b:P&Oss+13$s/H$K~> +#>7/YoCW&:mJ?h`dn0<6"RfFC*W>s:"6h]b:P&Oss+13$s/H$K~> +#>7/YoCW&:mJ?h`dn0<6"RfFC*W>s:"6h]b:P&Oss+13$s/H$K~> +!D>NQrrFh@qYpTB:A+Vm7Kc'As8V@[j+75]s+13$s/5mI~> +!D>NQrrFh@qYpTB:A+Vm7Kc'As8V@[j+75]s+13$s/5mI~> +!D>NQrrFh@qYpTB:A+Vm7Kc'As8V@[j+75]s+13$s/5mI~> +!D>NQrrFh@qu6]>;Y0nm*o1A]s'3Bks+13$s+13Is*t~> +!D>NQrrFh@qu6]>;Y0nm*o1A]s'3Bks+13$s+13Is*t~> +!D>NQrrFh@qu6]>;Y0nm*o1A]s'3Bks+13$s+13Is*t~> +!D>NQrrFh@r;Qi1B);6$$-D</*riT\s'3D9rrW+o]Rg*6s+13$s0;TS~> +!D>NQrrFh@r;Qi1B);6$$-D</*riT\s'3D9rrW+o]Rg*6s+13$s0;TS~> +!D>NQrrFh@r;Qi1B);6$$-D</*riT\s'3D9rrW+o]Rg*6s+13$s0;TS~> +%SJn`a+f<dI>4^#s0R1?p&>?%JqahkK!>9SKDpT*YPnJ&pAdU4s+13$s+13Ts*t~> +%SJn`a+f<dI>4^#s0R1?p&>?%JqahkK!>9SKDpT*YPnJ&pAdU4s+13$s+13Ts*t~> +%SJn`a+f<dI>4^#s0R1?p&>?%JqahkK!>9SKDpT*YPnJ&pAdU4s+13$s+13Ts*t~> +"%t`UcMWt2ZiC'>jR`BS[$D;i[Jp1+Yl9phLTURU!rS@iJcC<$JcC<$Z2]=~> +"%t`UcMWt2ZiC'>jR`BS[$D;i[Jp1+Yl9phLTURU!rS@iJcC<$JcC<$Z2]=~> +"%t`UcMWt2ZiC'>jR`BS[$D;i[Jp1+Yl9phLTURU!rS@iJcC<$JcC<$Z2]=~> +!D>N9rrBb-rrK*@JcC<$JcC<$X8d\~> +!D>N9rrBb-rrK*@JcC<$JcC<$X8d\~> +!D>N9rrBb-rrK*@JcC<$JcC<$X8d\~> +!D>N1rr_L<A`eRDJcC<$JcDeNJ,~> +!D>N1rr_L<A`eRDJcC<$JcDeNJ,~> +!D>N1rr_L<A`eRDJcC<$JcDeNJ,~> +!D>N1rrW/foR[$ns+13$s/Q*L~> +!D>N1rrW/foR[$ns+13$s/Q*L~> +!D>N1rrW/foR[$ns+13$s/Q*L~> +"A:iVs5s=1"5EkUl29$2ir8rZh:1/0s+13$s+13<s*t~> +"A:iVs5s=1"5EkUl29$2ir8rZh:1/0s+13$s+13<s*t~> +"A:iVs5s=1"5EkUl29$2ir8rZh:1/0s+13$s+13<s*t~> +"A:iVh08ih"Bs"KI4bCg#D<'VcX9:FaasJCs+13$s-it<~> +"A:iVh08ih"Bs"KI4bCg#D<'VcX9:FaasJCs+13$s-it<~> +"A:iVh08ih"Bs"KI4bCg#D<'VcX9:FaasJCs+13$s-it<~> +"A:iVM3S#>"P-'BI@pE:#01rEs6Fa?JcC<$JcC<$S,\!~> +"A:iVM3S#>"P-'BI@pE:#01rEs6Fa?JcC<$JcC<$S,\!~> +"A:iVM3S#>"P-'BI@pE:#01rEs6Fa?JcC<$JcC<$S,\!~> +"A:iVM3S#>&_9GOI@m*XH^=^3]7/f?mX;?ks+13$s+13>s*t~> +"A:iVM3S#>&_9GOI@m*XH^=^3]7/f?mX;?ks+13$s+13>s*t~> +"A:iVM3S#>&_9GOI@m*XH^=^3]7/f?mX;?ks+13$s+13>s*t~> +(eZsjM3S&?peOBZI63OaTp(Z>s1iGWB=NNmJcC<$JcD2=J,~> +(eZsjM3S&?peOBZI63OaTp(Z>s1iGWB=NNmJcC<$JcD2=J,~> +(eZsjM3S&?peOBZI63OaTp(Z>s1iGWB=NNmJcC<$JcD2=J,~> +(eZsjiH7CN7\E6NhS8LYs3"=?s+$lZY&JslJcC<$JcD2=J,~> +(eZsjiH7CN7\E6NhS8LYs3"=?s+$lZY&JslJcC<$JcD2=J,~> +(eZsjiH7CN7\E6NhS8LYs3"=?s+$lZY&JslJcC<$JcD2=J,~> +#tmA[s6JIqhUY0nrs?kHs+R*>s8&m>JcC<$JcC<$S,\!~> +#tmA[s6JIqhUY0nrs?kHs+R*>s8&m>JcC<$JcC<$S,\!~> +#tmA[s6JIqhUY0nrs?kHs+R*>s8&m>JcC<$JcC<$S,\!~> +!D>NPrrrDA=TA!drr3;J;ZD6@qZ$K"Ck;V;s+13$s-s%=~> +!D>NPrrrDA=TA!drr3;J;ZD6@qZ$K"Ck;V;s+13$s-s%=~> +!D>NPrrrDA=TA!drr3;J;ZD6@qZ$K"Ck;V;s+13$s-s%=~> +$qi\^s5;#@_cHg;R?IQk#ci.Ks*1Qc[V16lJcC<$JcD2=J,~> +$qi\^s5;#@_cHg;R?IQk#ci.Ks*1Qc[V16lJcC<$JcD2=J,~> +$qi\^s5;#@_cHg;R?IQk#ci.Ks*1Qc[V16lJcC<$JcD2=J,~> +#>7/Ys-lqc>Q+R%Pl=S]G5_FBGZ/@.s+13$s+13<s*t~> +#>7/Ys-lqc>Q+R%Pl=S]G5_FBGZ/@.s+13$s+13<s*t~> +#>7/Ys-lqc>Q+R%Pl=S]G5_FBGZ/@.s+13$s+13<s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +"A:iVrHeGa#!r.ds)PpSp&>3n>ok%TqqqDSq^h^f!K[21s+13$s+13ns*t~> +"A:iVrHeGa#!r.ds)PpSp&>3n>ok%TqqqDSq^h^f!K[21s+13$s+13ns*t~> +"A:iVrHeGa#!r.ds)PpSp&>3n>ok%TqqqDSq^h^f!K[21s+13$s+13ns*t~> +"A:iVM3S#>!S0a>rrQHBrq??qB=@j?dS&Kt!DCl?rrJ._JcC<$JcC<$bQ!(~> +"A:iVM3S#>!S0a>rrQHBrq??qB=@j?dS&Kt!DCl?rrJ._JcC<$JcC<$bQ!(~> +"A:iVM3S#>!S0a>rrQHBrq??qB=@j?dS&Kt!DCl?rrJ._JcC<$JcC<$bQ!(~> +#tmA[Vm$.#r2Oo<rrHB@pAYG3[f?BU9E5%Cn,E=fl.l:<!64s:$./AAbQ$Y^s8U+<^B!*hrr<u: +^B!3krrBk6^B!;Fs+13$s+13us*t~> +#tmA[Vm$.#r2Oo<rrHB@pAYG3[f?BU9E5%Cn,E=fl.l:<!64s:$./AAbQ$Y^s8U+<^B!*hrr<u: +^B!3krrBk6^B!;Fs+13$s+13us*t~> +#tmA[Vm$.#r2Oo<rrHB@pAYG3[f?BU9E5%Cn,E=fl.l:<!64s:$./AAbQ$Y^s8U+<^B!*hrr<u: +^B!3krrBk6^B!;Fs+13$s+13us*t~> +!D>NPrrJs@qu6\1[.jS,B60c?KhMIG>f$F>!NC2?rr=,<rs;-HlS8F'MZ:+rra#_Uf`/6dra#_X +h#FNara#VXi.:oZs+13$s3q!u~> +!D>NPrrJs@qu6\1[.jS,B60c?KhMIG>f$F>!NC2?rr=,<rs;-HlS8F'MZ:+rra#_Uf`/6dra#_X +h#FNara#VXi.:oZs+13$s3q!u~> +!D>NPrrJs@qu6\1[.jS,B60c?KhMIG>f$F>!NC2?rr=,<rs;-HlS8F'MZ:+rra#_Uf`/6dra#_X +h#FNara#VXi.:oZs+13$s3q!u~> +!D>NQrrJU@qYpT[2#%"[B39M-AkW1(X+Kg?jFOf>rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr3+K +U&QA5rr3#-e:IXNs+13$s3q!u~> +!D>NQrrJU@qYpT[2#%"[B39M-AkW1(X+Kg?jFOf>rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr3+K +U&QA5rr3#-e:IXNs+13$s3q!u~> +!D>NQrrJU@qYpT[2#%"[B39M-AkW1(X+Kg?jFOf>rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr3+K +U&QA5rr3#-e:IXNs+13$s3q!u~> +!D>NRrrSFGq"k!kDm&j7"_Y:Ds3aR>rrbOCs2S1=rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr34N +U&V$'AnJ&os+13$s+13ts*t~> +!D>NRrrSFGq"k!kDm&j7"_Y:Ds3aR>rrbOCs2S1=rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr34N +U&V$'AnJ&os+13$s+13ts*t~> +!D>NRrrSFGq"k!kDm&j7"_Y:Ds3aR>rrbOCs2S1=rr=,<rs;-HlS8F'MZ5`trr3+VQ2`K)rr34N +U&V$'AnJ&os+13$s+13ts*t~> +#"q&Xs-8l>qYpS+](Z.-B=@j?dS'T>"NXX/@F+oP!$;(<#t<M41&mGps#T3>rre+Bs"<a=rs*qF +s'i@E\(?32JcC<$JcF-tJ,~> +#"q&Xs-8l>qYpS+](Z.-B=@j?dS'T>"NXX/@F+oP!$;(<#t<M41&mGps#T3>rre+Bs"<a=rs*qF +s'i@E\(?32JcC<$JcF-tJ,~> +#"q&Xs-8l>qYpS+](Z.-B=@j?dS'T>"NXX/@F+oP!$;(<#t<M41&mGps#T3>rre+Bs"<a=rs*qF +s'i@E\(?32JcC<$JcF-tJ,~> +"\UrWSW34:rrQZBrq??qB=@j?dS'Q=![-G]r;R9Ks2TNes$bT+1&mGps#T3>rre+Bs"<a=rrd_C +s!.@=rrItfrr3&A/!>J`JcC<$JcFF'J,~> +"\UrWSW34:rrQZBrq??qB=@j?dS'Q=![-G]r;R9Ks2TNes$bT+1&mGps#T3>rre+Bs"<a=rrd_C +s!.@=rrItfrr3&A/!>J`JcC<$JcFF'J,~> +"\UrWSW34:rrQZBrq??qB=@j?dS'Q=![-G]r;R9Ks2TNes$bT+1&mGps#T3>rre+Bs"<a=rrd_C +s!.@=rrItfrr3&A/!>J`JcC<$JcFF'J,~> +"A:iVO;Rp;"^M*-EkD;Crrr.#*Zd]BrVlrj2YI"J&*t?<p](9d4rX\IGkqC42?"X"Jbf?</H-[n +MYdAE,5rVaPl(I[!l>M%JcC<$JcC<$g&HR~> +"A:iVO;Rp;"^M*-EkD;Crrr.#*Zd]BrVlrj2YI"J&*t?<p](9d4rX\IGkqC42?"X"Jbf?</H-[n +MYdAE,5rVaPl(I[!l>M%JcC<$JcC<$g&HR~> +"A:iVO;Rp;"^M*-EkD;Crrr.#*Zd]BrVlrj2YI"J&*t?<p](9d4rX\IGkqC42?"X"Jbf?</H-[n +MYdAE,5rVaPl(I[!l>M%JcC<$JcC<$g&HR~> +!D>N"rrMF?JcC<$JcC<$\Gq'~> +!D>N"rrMF?JcC<$JcC<$\Gq'~> +!D>N"rrMF?JcC<$JcC<$\Gq'~> +!D>N"rrMF?JcC<$JcC<$\Gq'~> +!D>N"rrMF?JcC<$JcC<$\Gq'~> +!D>N"rrMF?JcC<$JcC<$\Gq'~> +!D>N"rrM_GJcC<$JcC<$\Gq'~> +!D>N"rrM_GJcC<$JcC<$\Gq'~> +!D>N"rrM_GJcC<$JcC<$\Gq'~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>NQrrIH;oD\f.li.!"FSu.?F^'4jrrR%AK'!"7oNPOlmf*=XI"D<Ks+13$s7QDB~> +!D>NQrrIH;oD\f.li.!"FSu.?F^'4jrrR%AK'!"7oNPOlmf*=XI"D<Ks+13$s7QDB~> +!D>NQrrIH;oD\f.li.!"FSu.?F^'4jrrR%AK'!"7oNPOlmf*=XI"D<Ks+13$s7QDB~> +#tmA[V69hPmGN'ZrrHa>li."*b5D8@bH`l#rrU9A4lu\Gqn\)'mf*=Q1YMd/Qb7nLJcC<$TDsE~> +#tmA[V69hPmGN'ZrrHa>li."*b5D8@bH`l#rrU9A4lu\Gqn\)'mf*=Q1YMd/Qb7nLJcC<$TDsE~> +#tmA[V69hPmGN'ZrrHa>li."*b5D8@bH`l#rrU9A4lu\Gqn\)'mf*=Q1YMd/Qb7nLJcC<$TDsE~> +#tmA[n8Punj$2c%rrQrD)WUhulS8;:!T6-$rrKH@mf*=Q1YMd/G,BijJcC<$TDsE~> +#tmA[n8Punj$2c%rrQrD)WUhulS8;:!T6-$rrKH@mf*=Q1YMd/G,BijJcC<$TDsE~> +#tmA[n8Punj$2c%rrQrD)WUhulS8;:!T6-$rrKH@mf*=Q1YMd/G,BijJcC<$TDsE~> +#YR8Zs6a"o,j+k$"+miX*r>m;&MNhW!_OI]qu6]_1&LtOi'%&=!U2-6*XdYos6(XJ*d)V6s8)[8 +!L<EYrrKH@pAY0m`Vgh\YP[T:VZ%V=\GZBJr>l?_rRb34I3'HPs8TJ)*WsmkpmV.&$f1io*Y&i) +*rl96M#JG%-KtK-K&fcM0C",gJcC<$ZN#F~> +#YR8Zs6a"o,j+k$"+miX*r>m;&MNhW!_OI]qu6]_1&LtOi'%&=!U2-6*XdYos6(XJ*d)V6s8)[8 +!L<EYrrKH@pAY0m`Vgh\YP[T:VZ%V=\GZBJr>l?_rRb34I3'HPs8TJ)*WsmkpmV.&$f1io*Y&i) +*rl96M#JG%-KtK-K&fcM0C",gJcC<$ZN#F~> +#YR8Zs6a"o,j+k$"+miX*r>m;&MNhW!_OI]qu6]_1&LtOi'%&=!U2-6*XdYos6(XJ*d)V6s8)[8 +!L<EYrrKH@pAY0m`Vgh\YP[T:VZ%V=\GZBJr>l?_rRb34I3'HPs8TJ)*WsmkpmV.&$f1io*Y&i) +*rl96M#JG%-KtK-K&fcM0C",gJcC<$ZN#F~> +#tmA[j`JBojA4A"rr=,:rrGJko`"sd-N!fDlS8;:!T6->rrFb?rr37OU&QA5s8S+>qYpS-\,QC. +ZYK46!VIi=rrd2tl3hh8rrG+?qu6sSnGfp5T`>$9qtpBq*rio]rVljnrr3"BVZ$MqVKVt=$1o\H +s*Z-8s6):js+13$s0DZT~> +#tmA[j`JBojA4A"rr=,:rrGJko`"sd-N!fDlS8;:!T6->rrFb?rr37OU&QA5s8S+>qYpS-\,QC. +ZYK46!VIi=rrd2tl3hh8rrG+?qu6sSnGfp5T`>$9qtpBq*rio]rVljnrr3"BVZ$MqVKVt=$1o\H +s*Z-8s6):js+13$s0DZT~> +#tmA[j`JBojA4A"rr=,:rrGJko`"sd-N!fDlS8;:!T6->rrFb?rr37OU&QA5s8S+>qYpS-\,QC. +ZYK46!VIi=rrd2tl3hh8rrG+?qu6sSnGfp5T`>$9qtpBq*rio]rVljnrr3"BVZ$MqVKVt=$1o\H +s*Z-8s6):js+13$s0DZT~> +#tmA[Z+0ffmGruorr=,+rrMj@qu6]_1&LtOi'%&=!A9uCW=)Uts!.@>s,N->s8Dnq!CO?qrrKH@ +pAY0d-i<oEl8/D="$#BAlM[[b*q93<BE%o5D#F=nrM]l7s1Mh9rrI;?rVlnq:B%4!U+--BI@pQ> +n9BNaJcC<$ZN#F~> +#tmA[Z+0ffmGruorr=,+rrMj@qu6]_1&LtOi'%&=!A9uCW=)Uts!.@>s,N->s8Dnq!CO?qrrKH@ +pAY0d-i<oEl8/D="$#BAlM[[b*q93<BE%o5D#F=nrM]l7s1Mh9rrI;?rVlnq:B%4!U+--BI@pQ> +n9BNaJcC<$ZN#F~> +#tmA[Z+0ffmGruorr=,+rrMj@qu6]_1&LtOi'%&=!A9uCW=)Uts!.@>s,N->s8Dnq!CO?qrrKH@ +pAY0d-i<oEl8/D="$#BAlM[[b*q93<BE%o5D#F=nrM]l7s1Mh9rrI;?rVlnq:B%4!U+--BI@pQ> +n9BNaJcC<$ZN#F~> +!D>NQrrJ/QoD\e3li."[-N!fDlS8;:!T6->rrF`grGr=hs+cMkN.JhFs-EV)!A:k\rrKH@pAY0d +-i<oEl8/D="$#B2LAc/r'_).2BDhc1k(N\S!tkRH@/9g'G,G6<!N%dREs.C#s*^Mjs+13$s/uBP~> +!D>NQrrJ/QoD\e3li."[-N!fDlS8;:!T6->rrF`grGr=hs+cMkN.JhFs-EV)!A:k\rrKH@pAY0d +-i<oEl8/D="$#B2LAc/r'_).2BDhc1k(N\S!tkRH@/9g'G,G6<!N%dREs.C#s*^Mjs+13$s/uBP~> +!D>NQrrJ/QoD\e3li."[-N!fDlS8;:!T6->rrF`grGr=hs+cMkN.JhFs-EV)!A:k\rrKH@pAY0d +-i<oEl8/D="$#B2LAc/r'_).2BDhc1k(N\S!tkRH@/9g'G,G6<!N%dREs.C#s*^Mjs+13$s/uBP~> +!D>NArr=,:rrI;!o`"sd-N!fDlS8;:!T6->rrFb?qu6eNOHG[Brr2s>rr3&1/@YWY!OHP7rrMd? +rVltal0:)'rrY7Ah`h&>"dftms0cS<rrL2@rr3+[&c]OPrVlkIrr34HVZ6[Gs/'u9rrIP?JcC<$ +JcDnQJ,~> +!D>NArr=,:rrI;!o`"sd-N!fDlS8;:!T6->rrFb?qu6eNOHG[Brr2s>rr3&1/@YWY!OHP7rrMd? +rVltal0:)'rrY7Ah`h&>"dftms0cS<rrL2@rr3+[&c]OPrVlkIrr34HVZ6[Gs/'u9rrIP?JcC<$ +JcDnQJ,~> +!D>NArr=,:rrI;!o`"sd-N!fDlS8;:!T6->rrFb?qu6eNOHG[Brr2s>rr3&1/@YWY!OHP7rrMd? +rVltal0:)'rrY7Ah`h&>"dftms0cS<rrL2@rr3+[&c]OPrVlkIrr34HVZ6[Gs/'u9rrIP?JcC<$ +JcDnQJ,~> +!D>NDrs#)m;$g)sOT#1[%P@AR"ER<H;3V"Z"Dg[A;4IRb#\6F=;54*j]iY21"KMM%\l8T*"1%t, +[/No/IRUaGo2.Lk;8N&-!W8Vh;$3-Ul8/D="$#B7R/TqdP99;o[V,O<!Uc$J;$<@(s6>O@;#mj" +rs.%n;,Ok'j+I>.!*K7#!I^Sks+13$s/uBP~> +!D>NDrs#)m;$g)sOT#1[%P@AR"ER<H;3V"Z"Dg[A;4IRb#\6F=;54*j]iY21"KMM%\l8T*"1%t, +[/No/IRUaGo2.Lk;8N&-!W8Vh;$3-Ul8/D="$#B7R/TqdP99;o[V,O<!Uc$J;$<@(s6>O@;#mj" +rs.%n;,Ok'j+I>.!*K7#!I^Sks+13$s/uBP~> +!D>NDrs#)m;$g)sOT#1[%P@AR"ER<H;3V"Z"Dg[A;4IRb#\6F=;54*j]iY21"KMM%\l8T*"1%t, +[/No/IRUaGo2.Lk;8N&-!W8Vh;$3-Ul8/D="$#B7R/TqdP99;o[V,O<!Uc$J;$<@(s6>O@;#mj" +rs.%n;,Ok'j+I>.!*K7#!I^Sks+13$s/uBP~> +!D>NDrrD*WbQ-Q!rrLHrp&>$CrlbB"rr2uJrlbB%rr2uHrlbB'rr2uErlbN-s8Pm:rlbIg^&S*2 +bQR%cnc/OcbQ.&)rrDflbQID8qpt`G"5!DLoDZr;nC@I:nDX9E!:Kj1"SL4Cs6T^.!<)lr!oD/F +rr2u]rlbAfrr3#\m",1fs+13Qs*t~> +!D>NDrrD*WbQ-Q!rrLHrp&>$CrlbB"rr2uJrlbB%rr2uHrlbB'rr2uErlbN-s8Pm:rlbIg^&S*2 +bQR%cnc/OcbQ.&)rrDflbQID8qpt`G"5!DLoDZr;nC@I:nDX9E!:Kj1"SL4Cs6T^.!<)lr!oD/F +rr2u]rlbAfrr3#\m",1fs+13Qs*t~> +!D>NDrrD*WbQ-Q!rrLHrp&>$CrlbB"rr2uJrlbB%rr2uHrlbB'rr2uErlbN-s8Pm:rlbIg^&S*2 +bQR%cnc/OcbQ.&)rrDflbQID8qpt`G"5!DLoDZr;nC@I:nDX9E!:Kj1"SL4Cs6T^.!<)lr!oD/F +rr2u]rlbAfrr3#\m",1fs+13Qs*t~> +!D>MarrFV?rq?G6YCZ_)s+13$s3q!u~> +!D>MarrFV?rq?G6YCZ_)s+13$s3q!u~> +!D>MarrFV?rq?G6YCZ_)s+13$s3q!u~> +!D>M`rr=PJ-30Zhs+13$s+13us*t~> +!D>M`rr=PJ-30Zhs+13$s+13us*t~> +!D>M`rr=PJ-30Zhs+13$s+13us*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +"A:iVs2Y,1!3Z>$!Q4&Ns+13$s+132s*t~> +"A:iVs2Y,1!3Z>$!Q4&Ns+13$s+132s*t~> +"A:iVs2Y,1!3Z>$!Q4&Ns+13$s+132s*t~> +"A:iV`..c8#(NHKs0$t?JcC<$JcC<$OT0h~> +"A:iV`..c8#(NHKs0$t?JcC<$JcC<$OT0h~> +"A:iV`..c8#(NHKs0$t?JcC<$JcC<$OT0h~> +"A:iVM3S#>!S0a>rrTTDqgncus+13$s,m>3~> +"A:iVM3S#>!S0a>rrTTDqgncus+13$s,m>3~> +"A:iVM3S#>!S0a>rrTTDqgncus+13$s,m>3~> +#tmA[hr=\9pK5Z<rrL#?JcC<$JcC<$OoKq~> +#tmA[hr=\9pK5Z<rrL#?JcC<$JcC<$OoKq~> +#tmA[hr=\9pK5Z<rrL#?JcC<$JcC<$OoKq~> +!D>NPrrG@?qu6]<<.Y(#s+13$s-!D4~> +!D>NPrrG@?qu6]<<.Y(#s+13$s-!D4~> +!D>NPrrG@?qu6]<<.Y(#s+13$s-!D4~> +!D>NRrrVaZjneuXg-^GkJcC<$JcCo5J,~> +!D>NRrrVaZjneuXg-^GkJcC<$JcCo5J,~> +!D>NRrrVaZjneuXg-^GkJcC<$JcCo5J,~> +#"q&Xs5RM>qYpTI7tL\ks+13$s,m>3~> +#"q&Xs5RM>qYpTI7tL\ks+13$s,m>3~> +#"q&Xs5RM>qYpTI7tL\ks+13$s,m>3~> +"\UrWgN^j:rrU/EqLSZts+13$s,m>3~> +"\UrWgN^j:rrU/EqLSZts+13$s,m>3~> +"\UrWgN^j:rrU/EqLSZts+13$s,m>3~> +"A:iVM,sS>"gS+-]QWRks+13$s+133s*t~> +"A:iVM,sS>"gS+-]QWRks+13$s+133s*t~> +"A:iVM,sS>"gS+-]QWRks+13$s+133s*t~> +"%t`UaS^ktWrN+,i.:oZs+13$s,[21~> +"%t`UaS^ktWrN+,i.:oZs+13$s,[21~> +"%t`UaS^ktWrN+,i.:oZs+13$s,[21~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +!D>M*s+13$s+13&s*t~> +%%EndData +showpage +%%Trailer +end +%%EOF diff --git a/lib/stdlib/doc/src/ushell3.gif b/lib/stdlib/doc/src/ushell3.gif Binary files differnew file mode 100644 index 0000000000..2141268b91 --- /dev/null +++ b/lib/stdlib/doc/src/ushell3.gif diff --git a/lib/stdlib/doc/src/ushell3.ps b/lib/stdlib/doc/src/ushell3.ps new file mode 100644 index 0000000000..dd64eeab5c --- /dev/null +++ b/lib/stdlib/doc/src/ushell3.ps @@ -0,0 +1,662 @@ +%!PS-Adobe-3.0 +%%Creator: GIMP PostScript file plugin V 1.17 by Peter Kirchgessner +%%Title: ushell3.ps +%%CreationDate: Mon Mar 16 12:15:17 2009 +%%DocumentData: Clean7Bit +%%LanguageLevel: 2 +%%Pages: 1 +%%BoundingBox: 14 14 468 78 +%%EndComments +%%BeginProlog +% Use own dictionary to avoid conflicts +10 dict begin +%%EndProlog +%%Page: 1 1 +% Translate for offset +14.173228346456694 14.173228346456694 translate +% Translate to begin of first scanline +0 63.070866141732289 translate +453.54330708661422 -63.070866141732289 scale +% Image geometry +640 89 8 +% Transformation matrix +[ 640 0 0 89 0 0 ] +% Strings to hold RGB-samples per scanline +/rstr 640 string def +/gstr 640 string def +/bstr 640 string def +{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop} +{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop} +{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop} +true 3 +%%BeginData: 37475 ASCII Bytes +colorimage +!1\W%J`VIEJ`VLFJ,~> +!1\W%J`VIEJ`VLFJ,~> +!1\W%J`VIEJ`VLFJ,~> +!T[+/6@hIS6@hIU6@]~> +!T[+/6@hIS6@hIU6@]~> +!T[+/6@hIS6@hIU6@]~> +!ouWfJQ.2"JQ.2"KN*I~> +!ouWfJQ.2"JQ.2"KN*I~> +!ouWfJQ.2"JQ.2"KN*I~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLQ2^m!`0L?'S`PG&JcC<$i;\<~> +!ouXLQ2^m!`0L?'S`PG&JcC<$i;\<~> +!ouXLQ2^m!`0L?'S`PG&JcC<$i;\<~> +"QVjNs.9-i!1*E[!L)+*rrR=EF8Z%>Dc_2VrrI?7rr3)%^&N-N<rg/5rr?^0<rgP6rrU,eg\:^K +o6/O]!ioDNpAY05U[\9aJa!(4!2BHo!,VW6!lAR@JcC<$JcF^/J,~> +"QVjNs.9-i!1*E[!L)+*rrR=EF8Z%>Dc_2VrrI?7rr3)%^&N-N<rg/5rr?^0<rgP6rrU,eg\:^K +o6/O]!ioDNpAY05U[\9aJa!(4!2BHo!,VW6!lAR@JcC<$JcF^/J,~> +"QVjNs.9-i!1*E[!L)+*rrR=EF8Z%>Dc_2VrrI?7rr3)%^&N-N<rg/5rr?^0<rgP6rrU,eg\:^K +o6/O]!ioDNpAY05U[\9aJa!(4!2BHo!,VW6!lAR@JcC<$JcF^/J,~> +"lqsOs)!Pi_uSNdrrHB@o)Ad;\gmXX!mS).p&>%Ili-neJXl`h]D]YJlM1AZb5K6Z:po`k!N()7 +rrML@l2LdgT^2UZil(<`rrJFsrVlntF7K88K;)-<s8T'RrkniDCAn/50C=>jJcC<$iW"E~> +"lqsOs)!Pi_uSNdrrHB@o)Ad;\gmXX!mS).p&>%Ili-neJXl`h]D]YJlM1AZb5K6Z:po`k!N()7 +rrML@l2LdgT^2UZil(<`rrJFsrVlntF7K88K;)-<s8T'RrkniDCAn/50C=>jJcC<$iW"E~> +"lqsOs)!Pi_uSNdrrHB@o)Ad;\gmXX!mS).p&>%Ili-neJXl`h]D]YJlM1AZb5K6Z:po`k!N()7 +rrML@l2LdgT^2UZil(<`rrJFsrVlntF7K88K;)-<s8T'RrkniDCAn/50C=>jJcC<$iW"E~> +"lqsOs)#"3rrHB@nc&X\.f95Hkqi#4!AWp>rrdnCs!dR.rrSCIp@&"_b$si5rrML@l2LdPK]E(5 +GGY9<!NC/2rs4ONpZ4C7s,`6>rrN#\rVlo\2M(mZs+14/s*t~> +"lqsOs)#"3rrHB@nc&X\.f95Hkqi#4!AWp>rrdnCs!dR.rrSCIp@&"_b$si5rrML@l2LdPK]E(5 +GGY9<!NC/2rs4ONpZ4C7s,`6>rrN#\rVlo\2M(mZs+14/s*t~> +"lqsOs)#"3rrHB@nc&X\.f95Hkqi#4!AWp>rrdnCs!dR.rrSCIp@&"_b$si5rrML@l2LdPK]E(5 +GGY9<!NC/2rs4ONpZ4C7s,`6>rrN#\rVlo\2M(mZs+14/s*t~> +#in9Rs)"@hjludE!Us(f*"5s=s'2Za*#r;Ts6`DV*!'XArr3#i.f95Hkqi#4$2ktGs.=c>s!c4l +*!(ffp&>*eKVIo7!Q/(<rrCjQ*!EJBm4518*!<VHr42bG&A7u":Z[6L*5hd.*"`Z#*8gPk!Q/1@ +rrsVGs/-hF]Dhg?\f;.l*$"qWWG$>m*$OSArs>H^rr<#^9E1*5p\t46JcC<$JcF^/J,~> +#in9Rs)"@hjludE!Us(f*"5s=s'2Za*#r;Ts6`DV*!'XArr3#i.f95Hkqi#4$2ktGs.=c>s!c4l +*!(ffp&>*eKVIo7!Q/(<rrCjQ*!EJBm4518*!<VHr42bG&A7u":Z[6L*5hd.*"`Z#*8gPk!Q/1@ +rrsVGs/-hF]Dhg?\f;.l*$"qWWG$>m*$OSArs>H^rr<#^9E1*5p\t46JcC<$JcF^/J,~> +#in9Rs)"@hjludE!Us(f*"5s=s'2Za*#r;Ts6`DV*!'XArr3#i.f95Hkqi#4$2ktGs.=c>s!c4l +*!(ffp&>*eKVIo7!Q/(<rrCjQ*!EJBm4518*!<VHr42bG&A7u":Z[6L*5hd.*"`Z#*8gPk!Q/1@ +rrsVGs/-hF]Dhg?\f;.l*$"qWWG$>m*$OSArs>H^rr<#^9E1*5p\t46JcC<$JcF^/J,~> +#in9Rs(s&?2H0VT!G&_>rsZf$s'-u6s8T->s&7&=rrJm@rr3#i.f95Hkqhu3#T`sFSpp_><^Zld +!I1F5rrJj?mJd4)=nhq!7G$o6ErQ(@4l><[rVm<akl8@2QiI(:nGiNVK_>?L_HQutn,FF,rrHT? +r;QeAV>^DuW>MT6s7dl/rs"REs8UEef)5OJ*J+6As+14/s*t~> +#in9Rs(s&?2H0VT!G&_>rsZf$s'-u6s8T->s&7&=rrJm@rr3#i.f95Hkqhu3#T`sFSpp_><^Zld +!I1F5rrJj?mJd4)=nhq!7G$o6ErQ(@4l><[rVm<akl8@2QiI(:nGiNVK_>?L_HQutn,FF,rrHT? +r;QeAV>^DuW>MT6s7dl/rs"REs8UEef)5OJ*J+6As+14/s*t~> +#in9Rs(s&?2H0VT!G&_>rsZf$s'-u6s8T->s&7&=rrJm@rr3#i.f95Hkqhu3#T`sFSpp_><^Zld +!I1F5rrJj?mJd4)=nhq!7G$o6ErQ(@4l><[rVm<akl8@2QiI(:nGiNVK_>?L_HQutn,FF,rrHT? +r;QeAV>^DuW>MT6s7dl/rs"REs8UEef)5OJ*J+6As+14/s*t~> +"lqsOs)#";rrJFMriH=Cs8Q??rr3,%EW8soriH3>HN*pFngaP:!U2E4rrciCl&)D8rrIA?pAY3[ +N2>qA!Q/(<rrDWgXTL6.m4eM="$PQ&3;rj[2<b(S?N0s.E:s82R=t85#/XRDCU3s\rVln-]);R/ +GGY9<!NC/>rrMm?nG`]SNW9#h7m6eM!$-XjJcC<$iW"E~> +"lqsOs)#";rrJFMriH=Cs8Q??rr3,%EW8soriH3>HN*pFngaP:!U2E4rrciCl&)D8rrIA?pAY3[ +N2>qA!Q/(<rrDWgXTL6.m4eM="$PQ&3;rj[2<b(S?N0s.E:s82R=t85#/XRDCU3s\rVln-]);R/ +GGY9<!NC/>rrMm?nG`]SNW9#h7m6eM!$-XjJcC<$iW"E~> +"lqsOs)#";rrJFMriH=Cs8Q??rr3,%EW8soriH3>HN*pFngaP:!U2E4rrciCl&)D8rrIA?pAY3[ +N2>qA!Q/(<rrDWgXTL6.m4eM="$PQ&3;rj[2<b(S?N0s.E:s82R=t85#/XRDCU3s\rVln-]);R/ +GGY9<!NC/>rrMm?nG`]SNW9#h7m6eM!$-XjJcC<$iW"E~> +"lqsOs)#":rrAAaD?P3us'3D>rrfBBs&2tsD?.$BrrM[?qu6]]1\C\Lp*RC[q>UJ?V"Xfh^Kp4+ +!Q/(=rrN"UrGD]YfBk9jrrYFAj>d,<"?#EC^0^[9!L\W6rs$>Ds(eq?*W?!=@_2L;!I(C=rrK*? +rr3#o,k1g7OH'8>!T-'<rr='js+13$s5F!.~> +"lqsOs)#":rrAAaD?P3us'3D>rrfBBs&2tsD?.$BrrM[?qu6]]1\C\Lp*RC[q>UJ?V"Xfh^Kp4+ +!Q/(=rrN"UrGD]YfBk9jrrYFAj>d,<"?#EC^0^[9!L\W6rs$>Ds(eq?*W?!=@_2L;!I(C=rrK*? +rr3#o,k1g7OH'8>!T-'<rr='js+13$s5F!.~> +"lqsOs)#":rrAAaD?P3us'3D>rrfBBs&2tsD?.$BrrM[?qu6]]1\C\Lp*RC[q>UJ?V"Xfh^Kp4+ +!Q/(=rrN"UrGD]YfBk9jrrYFAj>d,<"?#EC^0^[9!L\W6rs$>Ds(eq?*W?!=@_2L;!I(C=rrK*? +rr3#o,k1g7OH'8>!T-'<rr='js+13$s5F!.~> +"lqsOs)#";rrK1Rrr3,.C&_GSrr3,%EW8tZq>UKd.f95Hkqhu3"84(R@K-9-Mu!AP!I1F>rrV/% +Zi0n*m!?)+rrV55[Jp1,odBb="fictm1u>nrrYFAj>d,<"?#EC^0^[9"dt&Ds,$[Lrs$>D^O^an +*W?!=@_2L;#C!$Es+UKPF8l1?pa#A/!K`<?rrM"?rVlnZNIh+\s+14/s*t~> +"lqsOs)#";rrK1Rrr3,.C&_GSrr3,%EW8tZq>UKd.f95Hkqhu3"84(R@K-9-Mu!AP!I1F>rrV/% +Zi0n*m!?)+rrV55[Jp1,odBb="fictm1u>nrrYFAj>d,<"?#EC^0^[9"dt&Ds,$[Lrs$>D^O^an +*W?!=@_2L;#C!$Es+UKPF8l1?pa#A/!K`<?rrM"?rVlnZNIh+\s+14/s*t~> +"lqsOs)#";rrK1Rrr3,.C&_GSrr3,%EW8tZq>UKd.f95Hkqhu3"84(R@K-9-Mu!AP!I1F>rrV/% +Zi0n*m!?)+rrV55[Jp1,odBb="fictm1u>nrrYFAj>d,<"?#EC^0^[9"dt&Ds,$[Lrs$>D^O^an +*W?!=@_2L;#C!$Es+UKPF8l1?pa#A/!K`<?rrM"?rVlnZNIh+\s+14/s*t~> +"lqsOs(spt=Tb&ka`%/]"E;N`>f$F>"KQPB_eK*Q!1!Q`"F!iV=e#Ej"E@<P=ePKg"8nU*aSu2? +ZsEZ6!J95.rrU7AErH"=gd(0)!N()?rrN%dr`KD\/_BA3O8`8aPP"R6rE08hp]%s6qYp`RIT]gC +rV?I'lAL)E_.]YEs1_\\6!=!^rs-kl=]qs.WH8(=!Vdr0rrLc"r`K83]D_a10C=>jJcC<$iW"E~> +"lqsOs(spt=Tb&ka`%/]"E;N`>f$F>"KQPB_eK*Q!1!Q`"F!iV=e#Ej"E@<P=ePKg"8nU*aSu2? +ZsEZ6!J95.rrU7AErH"=gd(0)!N()?rrN%dr`KD\/_BA3O8`8aPP"R6rE08hp]%s6qYp`RIT]gC +rV?I'lAL)E_.]YEs1_\\6!=!^rs-kl=]qs.WH8(=!Vdr0rrLc"r`K83]D_a10C=>jJcC<$iW"E~> +"lqsOs(spt=Tb&ka`%/]"E;N`>f$F>"KQPB_eK*Q!1!Q`"F!iV=e#Ej"E@<P=ePKg"8nU*aSu2? +ZsEZ6!J95.rrU7AErH"=gd(0)!N()?rrN%dr`KD\/_BA3O8`8aPP"R6rE08hp]%s6qYp`RIT]gC +rV?I'lAL)E_.]YEs1_\\6!=!^rs-kl=]qs.WH8(=!Vdr0rrLc"r`K83]D_a10C=>jJcC<$iW"E~> +"QVjNs4mOh"53_Se,I2eeGoR$nG`FjleVU@ci1c]f`(mNc2PQ[gA_*PbPo?Yh"C[Jp<rm=!6+rS +!93tW!qO4arVlomdH^`5l@c>>rrDcl_?K,Np&!#$rk\d,s8VZg_?BH0s7"\:rr_/q_Y3a(#jL4G +s3:H@s6'?t!<)lr#1p`/s8VB?rr3#tb4#?1h>Y7kb5M>AGH(Ijs+13$s5F!.~> +"QVjNs4mOh"53_Se,I2eeGoR$nG`FjleVU@ci1c]f`(mNc2PQ[gA_*PbPo?Yh"C[Jp<rm=!6+rS +!93tW!qO4arVlomdH^`5l@c>>rrDcl_?K,Np&!#$rk\d,s8VZg_?BH0s7"\:rr_/q_Y3a(#jL4G +s3:H@s6'?t!<)lr#1p`/s8VB?rr3#tb4#?1h>Y7kb5M>AGH(Ijs+13$s5F!.~> +"QVjNs4mOh"53_Se,I2eeGoR$nG`FjleVU@ci1c]f`(mNc2PQ[gA_*PbPo?Yh"C[Jp<rm=!6+rS +!93tW!qO4arVlomdH^`5l@c>>rrDcl_?K,Np&!#$rk\d,s8VZg_?BH0s7"\:rr_/q_Y3a(#jL4G +s3:H@s6'?t!<)lr#1p`/s8VB?rr3#tb4#?1h>Y7kb5M>AGH(Ijs+13$s5F!.~> +!ouXLQ2^mSnWj+TkkTf0JcC<$i;\<~> +!ouXLQ2^mSnWj+TkkTf0JcC<$i;\<~> +!ouXLQ2^mSnWj+TkkTf0JcC<$i;\<~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcG]K!TNR]rr_0&bgEm!"4YQ=h#.0PdXhFLs/5mI~> +!ouXLJcG]K!TNR]rr_0&bgEm!"4YQ=h#.0PdXhFLs/5mI~> +!ouXLJcG]K!TNR]rr_0&bgEm!"4YQ=h#.0PdXhFLs/5mI~> +!ouXLrVll.r;Qf;o()e]\@V&,!kGPPr;QirYf6S@!PSC#rr_SkYi""2!o&"@rVm>df)Ne\s8V;e +g&M)arUBgji3;2?s1.k'"4H?3\b5t)>rthhrVluBmf'fsrr^ZQYd<0c!6"l@!6Y!7"1eHrci3qH +Bhpuir;Qe$_L_`<s/>sJ~> +!ouXLrVll.r;Qf;o()e]\@V&,!kGPPr;QirYf6S@!PSC#rr_SkYi""2!o&"@rVm>df)Ne\s8V;e +g&M)arUBgji3;2?s1.k'"4H?3\b5t)>rthhrVluBmf'fsrr^ZQYd<0c!6"l@!6Y!7"1eHrci3qH +Bhpuir;Qe$_L_`<s/>sJ~> +!ouXLrVll.r;Qf;o()e]\@V&,!kGPPr;QirYf6S@!PSC#rr_SkYi""2!o&"@rVm>df)Ne\s8V;e +g&M)arUBgji3;2?s1.k'"4H?3\b5t)>rthhrVluBmf'fsrr^ZQYd<0c!6"l@!6Y!7"1eHrci3qH +Bhpuir;Qe$_L_`<s/>sJ~> +!ouXLrr3"u(&\(5P`>P2rrICpm/I-7?T\2c!r?\qrVlmIoCDnbn;;!sKAbYe!T1]hrrJ(?r;RA& +HiH[ds6YVXJCjfHq>^KAch7;Bie2*#ir:%mrr[/AruLe4!F<J;rsMiIr#l%>c$X;BD5H.i!P<LR +CB8[tpAY48s0uV;rrLA?r;QfW3e@<^s/>sJ~> +!ouXLrr3"u(&\(5P`>P2rrICpm/I-7?T\2c!r?\qrVlmIoCDnbn;;!sKAbYe!T1]hrrJ(?r;RA& +HiH[ds6YVXJCjfHq>^KAch7;Bie2*#ir:%mrr[/AruLe4!F<J;rsMiIr#l%>c$X;BD5H.i!P<LR +CB8[tpAY48s0uV;rrLA?r;QfW3e@<^s/>sJ~> +!ouXLrr3"u(&\(5P`>P2rrICpm/I-7?T\2c!r?\qrVlmIoCDnbn;;!sKAbYe!T1]hrrJ(?r;RA& +HiH[ds6YVXJCjfHq>^KAch7;Bie2*#ir:%mrr[/AruLe4!F<J;rsMiIr#l%>c$X;BD5H.i!P<LR +CB8[tpAY48s0uV;rrLA?r;QfW3e@<^s/>sJ~> +#NS0Qs8SgH'Dqe1RtBDp!T?-5rrFS?o)AmK5l^js[GUubZ>0::!n)SAr;RA&HiH[ds3jR>_1$W_ +r;ZeYN:m2T\mk]II!C_Grr[/AruLe4!F<J;rsMiIr#l%>LR%o>oI8\t#.&^Es8U`apAY48s0uV; +rrLA?r;QigKVj>#JcD_LJ,~> +#NS0Qs8SgH'Dqe1RtBDp!T?-5rrFS?o)AmK5l^js[GUubZ>0::!n)SAr;RA&HiH[ds3jR>_1$W_ +r;ZeYN:m2T\mk]II!C_Grr[/AruLe4!F<J;rsMiIr#l%>LR%o>oI8\t#.&^Es8U`apAY48s0uV; +rrLA?r;QigKVj>#JcD_LJ,~> +#NS0Qs8SgH'Dqe1RtBDp!T?-5rrFS?o)AmK5l^js[GUubZ>0::!n)SAr;RA&HiH[ds3jR>_1$W_ +r;ZeYN:m2T\mk]II!C_Grr[/AruLe4!F<J;rsMiIr#l%>LR%o>oI8\t#.&^Es8U`apAY48s0uV; +rrLA?r;QigKVj>#JcD_LJ,~> +#NS0Qs.PG>*W#d:UNuP4!e+Bor;QbBr`fGnp&>'O48f*[Bj?GlrrFS4r`fH/rVlrS>c%E!#M_TE +s2a:$pAJ50_Z0XSs3"YPaT)6E>a;X#c2[h+rEKWWs79J\-<sg.rr3#!F8PtRh9c29n,Mjis8U'5 +o)IQO1br<@mf3=+rEKd&s5qB%s1G-(s3748r`fI&rr3)Dir?1SrrHE?qu72Dli+*fs+cm>s7@c? +s/j-:rrM&<rr3"Nm/?qjU<NXUs4*P;s,-e\!/pjV"@#[e>`o$c!.XuQ!1*T`"0V[da8Gr<btn6: +!QA,ks+13Ls*t~> +#NS0Qs.PG>*W#d:UNuP4!e+Bor;QbBr`fGnp&>'O48f*[Bj?GlrrFS4r`fH/rVlrS>c%E!#M_TE +s2a:$pAJ50_Z0XSs3"YPaT)6E>a;X#c2[h+rEKWWs79J\-<sg.rr3#!F8PtRh9c29n,Mjis8U'5 +o)IQO1br<@mf3=+rEKd&s5qB%s1G-(s3748r`fI&rr3)Dir?1SrrHE?qu72Dli+*fs+cm>s7@c? +s/j-:rrM&<rr3"Nm/?qjU<NXUs4*P;s,-e\!/pjV"@#[e>`o$c!.XuQ!1*T`"0V[da8Gr<btn6: +!QA,ks+13Ls*t~> +#NS0Qs.PG>*W#d:UNuP4!e+Bor;QbBr`fGnp&>'O48f*[Bj?GlrrFS4r`fH/rVlrS>c%E!#M_TE +s2a:$pAJ50_Z0XSs3"YPaT)6E>a;X#c2[h+rEKWWs79J\-<sg.rr3#!F8PtRh9c29n,Mjis8U'5 +o)IQO1br<@mf3=+rEKd&s5qB%s1G-(s3748r`fI&rr3)Dir?1SrrHE?qu72Dli+*fs+cm>s7@c? +s/j-:rrM&<rr3"Nm/?qjU<NXUs4*P;s,-e\!/pjV"@#[e>`o$c!.XuQ!1*T`"0V[da8Gr<btn6: +!QA,ks+13Ls*t~> +#NS0Qs4Zf=*W#d;ql"c5rrUHX,5qNBGcC\W!KEfHrrM(?r;Qi:U."t[!@^M;^B&_orr3&@!-8&< +!Sfs<rr>sq^CtP2s0b1+^V=R6rYN>5HbX4Is7Q?*#\)ch^P5S"^[V7&!NL5.rsA82Ch^Z!q#AcZ +rP&>0q#:E#)he4*!*/Ie!F<J5rs=H,5X7I]s8RS?rr3#E:B(7o4Q68=$#ZsH*WNf[s,<HH^BC!c +s+R-F^BBjes*pjD^B'Ldp&>';:](.m`E.WjJcD_LJ,~> +#NS0Qs4Zf=*W#d;ql"c5rrUHX,5qNBGcC\W!KEfHrrM(?r;Qi:U."t[!@^M;^B&_orr3&@!-8&< +!Sfs<rr>sq^CtP2s0b1+^V=R6rYN>5HbX4Is7Q?*#\)ch^P5S"^[V7&!NL5.rsA82Ch^Z!q#AcZ +rP&>0q#:E#)he4*!*/Ie!F<J5rs=H,5X7I]s8RS?rr3#E:B(7o4Q68=$#ZsH*WNf[s,<HH^BC!c +s+R-F^BBjes*pjD^B'Ldp&>';:](.m`E.WjJcD_LJ,~> +#NS0Qs4Zf=*W#d;ql"c5rrUHX,5qNBGcC\W!KEfHrrM(?r;Qi:U."t[!@^M;^B&_orr3&@!-8&< +!Sfs<rr>sq^CtP2s0b1+^V=R6rYN>5HbX4Is7Q?*#\)ch^P5S"^[V7&!NL5.rsA82Ch^Z!q#AcZ +rP&>0q#:E#)he4*!*/Ie!F<J5rs=H,5X7I]s8RS?rr3#E:B(7o4Q68=$#ZsH*WNf[s,<HH^BC!c +s+R-F^BBjes*pjD^B'Ldp&>';:](.m`E.WjJcD_LJ,~> +!ouXLrVlj<q>UKC9D/;cqBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@cOtrrIA?rr3&og["k="?7J0 +,`Vg'!$2%<&RW6Okq)#ts&R/=+9/3^s%^l:rrkjCs8TB>qu6\sF6ii,OGs/<!Q&%=rrCsOrrTH1 +mf*4d*U`q.?,-(4%YoShgX7PNs6XR>s6`D>rr3!]iVic_DQj'\s1Me>A[h[="LVqC?,6I>"KZSB +<65(=!V5UMrrLA?qu6]9=+UC&s/H$K~> +!ouXLrVlj<q>UKC9D/;cqBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@cOtrrIA?rr3&og["k="?7J0 +,`Vg'!$2%<&RW6Okq)#ts&R/=+9/3^s%^l:rrkjCs8TB>qu6\sF6ii,OGs/<!Q&%=rrCsOrrTH1 +mf*4d*U`q.?,-(4%YoShgX7PNs6XR>s6`D>rr3!]iVic_DQj'\s1Me>A[h[="LVqC?,6I>"KZSB +<65(=!V5UMrrLA?qu6]9=+UC&s/H$K~> +!ouXLrVlj<q>UKC9D/;cqBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@cOtrrIA?rr3&og["k="?7J0 +,`Vg'!$2%<&RW6Okq)#ts&R/=+9/3^s%^l:rrkjCs8TB>qu6\sF6ii,OGs/<!Q&%=rrCsOrrTH1 +mf*4d*U`q.?,-(4%YoShgX7PNs6XR>s6`D>rr3!]iVic_DQj'\s1Me>A[h[="LVqC?,6I>"KZSB +<65(=!V5UMrrLA?qu6]9=+UC&s/H$K~> +!ouXLrVlj<qYpWR7/HTV!W"#=rrGd@rr3"fK(f3FiB-r:!SKm>rrFS?rr3"DV"jrmpsqY'qu6Tq +*W?!@?bQL(1]IC^qYgC8s/(#?:<rj^r>YtHfDklVCA\#3WcRM+!K`9=rrN(ur>Ygmq#:B"C]485 +*U`q.?,-(4"c&BCs7@c>rrd5Er7aR:rrG7@rVm1AYQ#XC]jLeN\,QC1[:oSG_#F?=XDn4+7iWLI +oD\j9:](.m`E.WjJcD_LJ,~> +!ouXLrVlj<qYpWR7/HTV!W"#=rrGd@rr3"fK(f3FiB-r:!SKm>rrFS?rr3"DV"jrmpsqY'qu6Tq +*W?!@?bQL(1]IC^qYgC8s/(#?:<rj^r>YtHfDklVCA\#3WcRM+!K`9=rrN(ur>Ygmq#:B"C]485 +*U`q.?,-(4"c&BCs7@c>rrd5Er7aR:rrG7@rVm1AYQ#XC]jLeN\,QC1[:oSG_#F?=XDn4+7iWLI +oD\j9:](.m`E.WjJcD_LJ,~> +!ouXLrVlj<qYpWR7/HTV!W"#=rrGd@rr3"fK(f3FiB-r:!SKm>rrFS?rr3"DV"jrmpsqY'qu6Tq +*W?!@?bQL(1]IC^qYgC8s/(#?:<rj^r>YtHfDklVCA\#3WcRM+!K`9=rrN(ur>Ygmq#:B"C]485 +*U`q.?,-(4"c&BCs7@c>rrd5Er7aR:rrG7@rVm1AYQ#XC]jLeN\,QC1[:oSG_#F?=XDn4+7iWLI +oD\j9:](.m`E.WjJcD_LJ,~> +!ouXLrVlj<qu6]J7e?W\qBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@c+hrrIA?rr3&lcfG')!Sfs< +rr=)<rrc]Bs62?;rsAZHs/(#?:<rM[rr3Mf37n31Z>0F>gA1dK\p3N,rs+XEs8UUKoAKTI!$1k7 +!O6G=rr=)4rrV!%r;HWr?,-(4"c&BCs7@c=rrPU@*W5pJ4Q6.is8Qu?ruM-Q?iO]Hrr3,/B`DAR +rr3,&E;rnYrr3#ejn8WSbtn9;!rAp@r;Qincf'HTJcE"TJ,~> +!ouXLrVlj<qu6]J7e?W\qBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@c+hrrIA?rr3&lcfG')!Sfs< +rr=)<rrc]Bs62?;rsAZHs/(#?:<rM[rr3Mf37n31Z>0F>gA1dK\p3N,rs+XEs8UUKoAKTI!$1k7 +!O6G=rr=)4rrV!%r;HWr?,-(4"c&BCs7@c=rrPU@*W5pJ4Q6.is8Qu?ruM-Q?iO]Hrr3,/B`DAR +rr3,&E;rnYrr3#ejn8WSbtn9;!rAp@r;Qincf'HTJcE"TJ,~> +!ouXLrVlj<qu6]J7e?W\qBGn<!DCl?rrJR?pAY0P48]$YfgPf=!@c+hrrIA?rr3&lcfG')!Sfs< +rr=)<rrc]Bs62?;rsAZHs/(#?:<rM[rr3Mf37n31Z>0F>gA1dK\p3N,rs+XEs8UUKoAKTI!$1k7 +!O6G=rr=)4rrV!%r;HWr?,-(4"c&BCs7@c=rrPU@*W5pJ4Q6.is8Qu?ruM-Q?iO]Hrr3,/B`DAR +rr3,&E;rnYrr3#ejn8WSbtn9;!rAp@r;Qincf'HTJcE"TJ,~> +&*-#Ys3n9Z'XG$js8U/Gp@S@j_ljo_cN!oqT`24tMQ$:L"M:6SZI]$T#e?<UZIo3W.8^#L!I_`^ +rrU7AErH"=gd(f;!+#Q/"EMoikqi8;$2u%H_4Ua&cM1ZDZ3k[gfDklmGI"Mcl2L\`N0*E+#I/ug +Z<@4XE;d'B>PS4!Z"s=<!$1b4!_EC^rVln(^\.U1X,+'eY%dk7!dpbLr;R:NVPeS:s-]%U'XF*e +s-&cJZN$0ks,EHGZ36;Zs+m3EZ2ouZp&>';:]14ni]?u:!nmW^JcC<$Z2]=~> +&*-#Ys3n9Z'XG$js8U/Gp@S@j_ljo_cN!oqT`24tMQ$:L"M:6SZI]$T#e?<UZIo3W.8^#L!I_`^ +rrU7AErH"=gd(f;!+#Q/"EMoikqi8;$2u%H_4Ua&cM1ZDZ3k[gfDklmGI"Mcl2L\`N0*E+#I/ug +Z<@4XE;d'B>PS4!Z"s=<!$1b4!_EC^rVln(^\.U1X,+'eY%dk7!dpbLr;R:NVPeS:s-]%U'XF*e +s-&cJZN$0ks,EHGZ36;Zs+m3EZ2ouZp&>';:]14ni]?u:!nmW^JcC<$Z2]=~> +&*-#Ys3n9Z'XG$js8U/Gp@S@j_ljo_cN!oqT`24tMQ$:L"M:6SZI]$T#e?<UZIo3W.8^#L!I_`^ +rrU7AErH"=gd(f;!+#Q/"EMoikqi8;$2u%H_4Ua&cM1ZDZ3k[gfDklmGI"Mcl2L\`N0*E+#I/ug +Z<@4XE;d'B>PS4!Z"s=<!$1b4!_EC^rVln(^\.U1X,+'eY%dk7!dpbLr;R:NVPeS:s-]%U'XF*e +s-&cJZN$0ks,EHGZ36;Zs+m3EZ2ouZp&>';:]14ni]?u:!nmW^JcC<$Z2]=~> +"QVjNs/Gp1"JPkqP32B9!/UVg!2'8j!/(8b!i5k1qj%?1s8RBDB`P=8rr@0?B`tdBs+0V;B`P[A +rrV%kXSr/"l]1oC!;HG+"NUQBnq[/C!WIHErr\VIs60Gr!l^>crr3)9Bkc?#rrTfah<b.GXD)D; +s8U7?B`Rf#rrLNGrVlkDp&>)W'(Pr#"'oo4T_ABfVeKj`qu6\Hq>:0mH?oJh"INm3Boi8n!0dCr +!0mK_!07%m!1Eid!/^\h!1roa"/_B0:]14nOc0,:!pOEmJcC<$Z2]=~> +"QVjNs/Gp1"JPkqP32B9!/UVg!2'8j!/(8b!i5k1qj%?1s8RBDB`P=8rr@0?B`tdBs+0V;B`P[A +rrV%kXSr/"l]1oC!;HG+"NUQBnq[/C!WIHErr\VIs60Gr!l^>crr3)9Bkc?#rrTfah<b.GXD)D; +s8U7?B`Rf#rrLNGrVlkDp&>)W'(Pr#"'oo4T_ABfVeKj`qu6\Hq>:0mH?oJh"INm3Boi8n!0dCr +!0mK_!07%m!1Eid!/^\h!1roa"/_B0:]14nOc0,:!pOEmJcC<$Z2]=~> +"QVjNs/Gp1"JPkqP32B9!/UVg!2'8j!/(8b!i5k1qj%?1s8RBDB`P=8rr@0?B`tdBs+0V;B`P[A +rrV%kXSr/"l]1oC!;HG+"NUQBnq[/C!WIHErr\VIs60Gr!l^>crr3)9Bkc?#rrTfah<b.GXD)D; +s8U7?B`Rf#rrLNGrVlkDp&>)W'(Pr#"'oo4T_ABfVeKj`qu6\Hq>:0mH?oJh"INm3Boi8n!0dCr +!0mK_!07%m!1Eid!/^\h!1roa"/_B0:]14nOc0,:!pOEmJcC<$Z2]=~> +!ouXLg&D&Xqh5$jXoAF5fYd^i/+NT<"0mQ6OPKj9*SgYsQ\C-or;Qb\JcC<$VuM8~> +!ouXLg&D&Xqh5$jXoAF5fYd^i/+NT<"0mQ6OPKj9*SgYsQ\C-or;Qb\JcC<$VuM8~> +!ouXLg&D&Xqh5$jXoAF5fYd^i/+NT<"0mQ6OPKj9*SgYsQ\C-or;Qb\JcC<$VuM8~> +!ouXLJcEIa!fWE@eGfLhJcC<$JcGNFJ,~> +!ouXLJcEIa!fWE@eGfLhJcC<$JcGNFJ,~> +!ouXLJcEIa!fWE@eGfLhJcC<$JcGNFJ,~> +!ouXLJcEIa!RUJfrrBugs+13$s7lVE~> +!ouXLJcEIa!RUJfrrBugs+13$s7lVE~> +!ouXLJcEIa!RUJfrrBugs+13$s7lVE~> +!ouXLrr3't-73*urrYk?->%i/VuHj>-71q,rrYb<->A&2JcDGDJ,~> +!ouXLrr3't-73*urrYk?->%i/VuHj>-71q,rrYb<->A&2JcDGDJ,~> +!ouXLrr3't-73*urrYk?->%i/VuHj>-71q,rrYb<->A&2JcDGDJ,~> +!ouXLrr3'UiUusDrs(%<p%\ReoM>H+"C_!'=r@2X",R!J62hi)Dt`u+!V%uF*!C]as#M+t*!3#; +5lDZ''<(^+!:'M&".8rb)Z1QV`W%.\*!$Vlq>UKpc2AUb[/Bt%Y5TCHaoDD<V]6\VqtU0lr3?2? +"47(m&H*RN*rl,4r>Ygpq#:BkQMhd'mem(cnKn27"SQdS*96en!V^p>*!%tfr;Qr]1&q:ID#PCZ +7.^HYq"=;#o`#1Qo$gS;s)5IHo)Ae=s1<%Frr_uf`D;'bJcDGDJ,~> +!ouXLrr3'UiUusDrs(%<p%\ReoM>H+"C_!'=r@2X",R!J62hi)Dt`u+!V%uF*!C]as#M+t*!3#; +5lDZ''<(^+!:'M&".8rb)Z1QV`W%.\*!$Vlq>UKpc2AUb[/Bt%Y5TCHaoDD<V]6\VqtU0lr3?2? +"47(m&H*RN*rl,4r>Ygpq#:BkQMhd'mem(cnKn27"SQdS*96en!V^p>*!%tfr;Qr]1&q:ID#PCZ +7.^HYq"=;#o`#1Qo$gS;s)5IHo)Ae=s1<%Frr_uf`D;'bJcDGDJ,~> +!ouXLrr3'UiUusDrs(%<p%\ReoM>H+"C_!'=r@2X",R!J62hi)Dt`u+!V%uF*!C]as#M+t*!3#; +5lDZ''<(^+!:'M&".8rb)Z1QV`W%.\*!$Vlq>UKpc2AUb[/Bt%Y5TCHaoDD<V]6\VqtU0lr3?2? +"47(m&H*RN*rl,4r>Ygpq#:BkQMhd'mem(cnKn27"SQdS*96en!V^p>*!%tfr;Qr]1&q:ID#PCZ +7.^HYq"=;#o`#1Qo$gS;s)5IHo)Ae=s1<%Frr_uf`D;'bJcDGDJ,~> +!ouXLrr3!SlMLS^.eEW=!F3J?rrfBBs&7&:rrGd@rr3"fK)#?H3o^/="Gr?B1$eT6!pk9@q#:=7 +rVlt4[Jq9@rrV=od/!\BodB_<"@^r?ZYfX?#PtQEs8R)Bqt^6mdn0N<"!m]c;>^@o_HQp<!$1k7 +!O6G=rr=)<rsRa\$ig7pJueqO6eV87!K`<?rrM"?rVm)U2_"e,J"HZ>!R=I<rr=)3rrXeBdRsN= +!C,E2rrX;A\7GO;!R4Dks+13Ds*t~> +!ouXLrr3!SlMLS^.eEW=!F3J?rrfBBs&7&:rrGd@rr3"fK)#?H3o^/="Gr?B1$eT6!pk9@q#:=7 +rVlt4[Jq9@rrV=od/!\BodB_<"@^r?ZYfX?#PtQEs8R)Bqt^6mdn0N<"!m]c;>^@o_HQp<!$1k7 +!O6G=rr=)<rsRa\$ig7pJueqO6eV87!K`<?rrM"?rVm)U2_"e,J"HZ>!R=I<rr=)3rrXeBdRsN= +!C,E2rrX;A\7GO;!R4Dks+13Ds*t~> +!ouXLrr3!SlMLS^.eEW=!F3J?rrfBBs&7&:rrGd@rr3"fK)#?H3o^/="Gr?B1$eT6!pk9@q#:=7 +rVlt4[Jq9@rrV=od/!\BodB_<"@^r?ZYfX?#PtQEs8R)Bqt^6mdn0N<"!m]c;>^@o_HQp<!$1k7 +!O6G=rr=)<rsRa\$ig7pJueqO6eV87!K`<?rrM"?rVm)U2_"e,J"HZ>!R=I<rr=)3rrXeBdRsN= +!C,E2rrX;A\7GO;!R4Dks+13Ds*t~> +!ouXLrr3!SlMLS^.eEW=!F3J?rt2;Os&7%P[C+B]s*rr+s6>N>q#:@Uir8r\M3Irokl.sigACmN +QA>57!$2%<"D>.B*V99<!9="W!oJ@Aq#:Bf-iO&I7G$o\qu6of@a>#Rc!]u8rrLS?rVm!Gq9)Xm +rj;k&s2%t<rr=)7rrKB?rVlj<rr3DWCt]p0s1Eg>s8TE?q#:AVNW/qYh`^u=#KpH:.KBEtT)S`j +c;+<;!$1_3").AbJ,]HLGGkH=rrp[9]sY8prVlt,s36](rrLA?JcC<$U&TW~> +!ouXLrr3!SlMLS^.eEW=!F3J?rt2;Os&7%P[C+B]s*rr+s6>N>q#:@Uir8r\M3Irokl.sigACmN +QA>57!$2%<"D>.B*V99<!9="W!oJ@Aq#:Bf-iO&I7G$o\qu6of@a>#Rc!]u8rrLS?rVm!Gq9)Xm +rj;k&s2%t<rr=)7rrKB?rVlj<rr3DWCt]p0s1Eg>s8TE?q#:AVNW/qYh`^u=#KpH:.KBEtT)S`j +c;+<;!$1_3").AbJ,]HLGGkH=rrp[9]sY8prVlt,s36](rrLA?JcC<$U&TW~> +!ouXLrr3!SlMLS^.eEW=!F3J?rt2;Os&7%P[C+B]s*rr+s6>N>q#:@Uir8r\M3Irokl.sigACmN +QA>57!$2%<"D>.B*V99<!9="W!oJ@Aq#:Bf-iO&I7G$o\qu6of@a>#Rc!]u8rrLS?rVm!Gq9)Xm +rj;k&s2%t<rr=)7rrKB?rVlj<rr3DWCt]p0s1Eg>s8TE?q#:AVNW/qYh`^u=#KpH:.KBEtT)S`j +c;+<;!$1_3").AbJ,]HLGGkH=rrp[9]sY8prVlt,s36](rrLA?JcC<$U&TW~> +!ouXLrr3!SlMLS^.eEW=%U?jMs6409s&42YAnH;1rVlreMkg%H#s.)Gs4gM9s"TH2Ac[D5rVlrX +KX^^U!$2(="jT<>rtpjsAc[YJrr3)X=&duMrrMd?rr3/<.bF&Ai;T,MkPtS<GF=kBht[3Pdn0Q= +"g\s>b;"YKAcn:t_HQs=!N[(3rrKB?rr38#*WQ/eI*Va4rr3,/Kpe?Lp\u"jNW9%XL->S:_fb#3 +.KBEtT)\ibHqsV>!$1G+!ILR>rruGICM%1'an>Z7btiojJcDGDJ,~> +!ouXLrr3!SlMLS^.eEW=%U?jMs6409s&42YAnH;1rVlreMkg%H#s.)Gs4gM9s"TH2Ac[D5rVlrX +KX^^U!$2(="jT<>rtpjsAc[YJrr3)X=&duMrrMd?rr3/<.bF&Ai;T,MkPtS<GF=kBht[3Pdn0Q= +"g\s>b;"YKAcn:t_HQs=!N[(3rrKB?rr38#*WQ/eI*Va4rr3,/Kpe?Lp\u"jNW9%XL->S:_fb#3 +.KBEtT)\ibHqsV>!$1G+!ILR>rruGICM%1'an>Z7btiojJcDGDJ,~> +!ouXLrr3!SlMLS^.eEW=%U?jMs6409s&42YAnH;1rVlreMkg%H#s.)Gs4gM9s"TH2Ac[D5rVlrX +KX^^U!$2(="jT<>rtpjsAc[YJrr3)X=&duMrrMd?rr3/<.bF&Ai;T,MkPtS<GF=kBht[3Pdn0Q= +"g\s>b;"YKAcn:t_HQs=!N[(3rrKB?rr38#*WQ/eI*Va4rr3,/Kpe?Lp\u"jNW9%XL->S:_fb#3 +.KBEtT)\ibHqsV>!$1G+!ILR>rruGICM%1'an>Z7btiojJcDGDJ,~> +!ouXLrr3!SlMLS^.eEW=%^1>0I=>7;s/UbCs8Sj?rr3&pI\lc<$(cToI=F_Ms-e`BrrI\@rVlo) +C%hQ,NrFG1Il4Y6MO4>B!FNP>rrgr*Jq)eUrrMtIrd=s#,M2<!If=p)Idd<rItE9%jS8`Ul@Jq_ +"b@<^jat#ArrX;AiILoU!J(s[rrLf'rd>''*<4K;aoDA]rr3,:J:`B,p\t98J,Xj)E]sH>JD'tp +.KBF`J,XisBhnU+!$1D*!$2%<##o4*s8Sm?p&>';:P&Oss.TIC~> +!ouXLrr3!SlMLS^.eEW=%^1>0I=>7;s/UbCs8Sj?rr3&pI\lc<$(cToI=F_Ms-e`BrrI\@rVlo) +C%hQ,NrFG1Il4Y6MO4>B!FNP>rrgr*Jq)eUrrMtIrd=s#,M2<!If=p)Idd<rItE9%jS8`Ul@Jq_ +"b@<^jat#ArrX;AiILoU!J(s[rrLf'rd>''*<4K;aoDA]rr3,:J:`B,p\t98J,Xj)E]sH>JD'tp +.KBF`J,XisBhnU+!$1D*!$2%<##o4*s8Sm?p&>';:P&Oss.TIC~> +!ouXLrr3!SlMLS^.eEW=%^1>0I=>7;s/UbCs8Sj?rr3&pI\lc<$(cToI=F_Ms-e`BrrI\@rVlo) +C%hQ,NrFG1Il4Y6MO4>B!FNP>rrgr*Jq)eUrrMtIrd=s#,M2<!If=p)Idd<rItE9%jS8`Ul@Jq_ +"b@<^jat#ArrX;AiILoU!J(s[rrLf'rd>''*<4K;aoDA]rr3,:J:`B,p\t98J,Xj)E]sH>JD'tp +.KBF`J,XisBhnU+!$1D*!$2%<##o4*s8Sm?p&>';:P&Oss.TIC~> +!ouXLrr3!SlMLS^.eET<"h("oZ`A*CrrJm@rr3":Y4V_tWLf]sM3Ii:!J-d?rrV2$`qKE4rViAi +c"FH]rrHK?qu6[t`q]Q6nG]!_fgXN[*kVFO#sI26DSQ5O]l*B8rrD*YSc\%"q>:0o*WQ/qrgj/X +*V]R6f)D6Do,[k1/H0&a$[;WhJ(Xf$TR?M6(!<,>TAMg3LH/dO>n;nos21G"VTqs7rr=)*rrJR? +rr3!uaSu2?Uj;Y5!R4Dks+13Ds*t~> +!ouXLrr3!SlMLS^.eET<"h("oZ`A*CrrJm@rr3":Y4V_tWLf]sM3Ii:!J-d?rrV2$`qKE4rViAi +c"FH]rrHK?qu6[t`q]Q6nG]!_fgXN[*kVFO#sI26DSQ5O]l*B8rrD*YSc\%"q>:0o*WQ/qrgj/X +*V]R6f)D6Do,[k1/H0&a$[;WhJ(Xf$TR?M6(!<,>TAMg3LH/dO>n;nos21G"VTqs7rr=)*rrJR? +rr3!uaSu2?Uj;Y5!R4Dks+13Ds*t~> +!ouXLrr3!SlMLS^.eET<"h("oZ`A*CrrJm@rr3":Y4V_tWLf]sM3Ii:!J-d?rrV2$`qKE4rViAi +c"FH]rrHK?qu6[t`q]Q6nG]!_fgXN[*kVFO#sI26DSQ5O]l*B8rrD*YSc\%"q>:0o*WQ/qrgj/X +*V]R6f)D6Do,[k1/H0&a$[;WhJ(Xf$TR?M6(!<,>TAMg3LH/dO>n;nos21G"VTqs7rr=)*rrJR? +rr3!uaSu2?Uj;Y5!R4Dks+13Ds*t~> +!ouXLrr3!SlMLS^.eEH8!NU5;rro0Ds8Q]>n,EEFPPb@\JXl`>!ROO0rrHc?qu6\(^&.g1<lXb2 +"%Ci/0`D"R4l><[rVlmUkk"fT,l.?;!$1q9!$1Y1!Zh=)rON+H`;cKXrr3#g/G&lDh`_"srji0: +*mOT^!R=I<rr=)*rs&7lJcGaLaSu2?Uj;Y5!R4Dks+13Ds*t~> +!ouXLrr3!SlMLS^.eEH8!NU5;rro0Ds8Q]>n,EEFPPb@\JXl`>!ROO0rrHc?qu6\(^&.g1<lXb2 +"%Ci/0`D"R4l><[rVlmUkk"fT,l.?;!$1q9!$1Y1!Zh=)rON+H`;cKXrr3#g/G&lDh`_"srji0: +*mOT^!R=I<rr=)*rs&7lJcGaLaSu2?Uj;Y5!R4Dks+13Ds*t~> +!ouXLrr3!SlMLS^.eEH8!NU5;rro0Ds8Q]>n,EEFPPb@\JXl`>!ROO0rrHc?qu6\(^&.g1<lXb2 +"%Ci/0`D"R4l><[rVlmUkk"fT,l.?;!$1q9!$1Y1!Zh=)rON+H`;cKXrr3#g/G&lDh`_"srji0: +*mOT^!R=I<rr=)*rs&7lJcGaLaSu2?Uj;Y5!R4Dks+13Ds*t~> +!ouXLrr3!SlMLS^.eEK9"jpfCs)6?brro0Ds(Jn>qYpWa.;\k\"grXDs&/:ars"%Es8VR[iqr`W +cmaeIrre^NoD_,TrrZWAs$?V`!ER5>rrTPVV>C2pI&Hf-0`D"X4l?.@E<#rUZMXY$!gkFQqYp\* +^AcSurVlj<qu6[obPhGBHR[hJrrGL?qu6sCs8VS?WW2u_h>R?T?RbjKrrW-`i;ETUoI9\;!q&\@ +r;Qa;qu6[Y8Flcaa]&6><65(=!Mk#6rrLA?JcC<$U&TW~> +!ouXLrr3!SlMLS^.eEK9"jpfCs)6?brro0Ds(Jn>qYpWa.;\k\"grXDs&/:ars"%Es8VR[iqr`W +cmaeIrre^NoD_,TrrZWAs$?V`!ER5>rrTPVV>C2pI&Hf-0`D"X4l?.@E<#rUZMXY$!gkFQqYp\* +^AcSurVlj<qu6[obPhGBHR[hJrrGL?qu6sCs8VS?WW2u_h>R?T?RbjKrrW-`i;ETUoI9\;!q&\@ +r;Qa;qu6[Y8Flcaa]&6><65(=!Mk#6rrLA?JcC<$U&TW~> +!ouXLrr3!SlMLS^.eEK9"jpfCs)6?brro0Ds(Jn>qYpWa.;\k\"grXDs&/:ars"%Es8VR[iqr`W +cmaeIrre^NoD_,TrrZWAs$?V`!ER5>rrTPVV>C2pI&Hf-0`D"X4l?.@E<#rUZMXY$!gkFQqYp\* +^AcSurVlj<qu6[obPhGBHR[hJrrGL?qu6sCs8VS?WW2u_h>R?T?RbjKrrW-`i;ETUoI9\;!q&\@ +r;Qa;qu6[Y8Flcaa]&6><65(=!Mk#6rrLA?JcC<$U&TW~> +!ouXLrr3'Uh!jt7rrXb3nFZ_[#ZMc`9(r;bp.>6'"D[`3<Z:oV!0I3[!p^7krVm-\*#rScs8VaD +rYu)rqZ$T`48SsYb6i:hrrDop*!Cojs8V9\*!;u6s5<hq!NQ(srrT5,PlC[_h#88rTD\`gb5E:c +^]"31WuN+^r;HWsM[$WhrrBe4*!EqQs89%u*!>!rs0)DA!QtE?rrQs=fDbdMT`,o2f_YUJ/,oPO +q/RGpkPY>]9EP%hrrdon*$4bLrrMaLrr3+B*#pR'rr3)nnF.IqrrF>jo)AmkXapFYbPqMBWIagD +"7krt:P&Oss.TIC~> +!ouXLrr3'Uh!jt7rrXb3nFZ_[#ZMc`9(r;bp.>6'"D[`3<Z:oV!0I3[!p^7krVm-\*#rScs8VaD +rYu)rqZ$T`48SsYb6i:hrrDop*!Cojs8V9\*!;u6s5<hq!NQ(srrT5,PlC[_h#88rTD\`gb5E:c +^]"31WuN+^r;HWsM[$WhrrBe4*!EqQs89%u*!>!rs0)DA!QtE?rrQs=fDbdMT`,o2f_YUJ/,oPO +q/RGpkPY>]9EP%hrrdon*$4bLrrMaLrr3+B*#pR'rr3)nnF.IqrrF>jo)AmkXapFYbPqMBWIagD +"7krt:P&Oss.TIC~> +!ouXLrr3'Uh!jt7rrXb3nFZ_[#ZMc`9(r;bp.>6'"D[`3<Z:oV!0I3[!p^7krVm-\*#rScs8VaD +rYu)rqZ$T`48SsYb6i:hrrDop*!Cojs8V9\*!;u6s5<hq!NQ(srrT5,PlC[_h#88rTD\`gb5E:c +^]"31WuN+^r;HWsM[$WhrrBe4*!EqQs89%u*!>!rs0)DA!QtE?rrQs=fDbdMT`,o2f_YUJ/,oPO +q/RGpkPY>]9EP%hrrdon*$4bLrrMaLrr3+B*#pR'rr3)nnF.IqrrF>jo)AmkXapFYbPqMBWIagD +"7krt:P&Oss.TIC~> +!ouXLrr3(#.k>-.rrZ"H.r+/F!R+C#rrK-?j8T.9PiMcEB=?k#!CbW#rrFA?k5PO+.k=!arrMm@ +h>[RM.k>Ifs+13Ds*t~> +!ouXLrr3(#.k>-.rrZ"H.r+/F!R+C#rrK-?j8T.9PiMcEB=?k#!CbW#rrFA?k5PO+.k=!arrMm@ +h>[RM.k>Ifs+13Ds*t~> +!ouXLrr3(#.k>-.rrZ"H.r+/F!R+C#rrK-?j8T.9PiMcEB=?k#!CbW#rrFA?k5PO+.k=!arrMm@ +h>[RM.k>Ifs+13Ds*t~> +!ouXLf)GgITn2;)!q2;?jSo;DK<jS<!o8"AjSo;1B&htP!m4UAh#@Dd@Y+Q1s+14Gs*t~> +!ouXLf)GgITn2;)!q2;?jSo;DK<jS<!o8"AjSo;1B&htP!m4UAh#@Dd@Y+Q1s+14Gs*t~> +!ouXLf)GgITn2;)!q2;?jSo;DK<jS<!o8"AjSo;1B&htP!m4UAh#@Dd@Y+Q1s+14Gs*t~> +!ouXLf)GdAK&ck3h3[1%!QhG'rrKLBj8T.Pe`6Z1MsB's!-NkmJcC<$q#>j~> +!ouXLf)GdAK&ck3h3[1%!QhG'rrKLBj8T.Pe`6Z1MsB's!-NkmJcC<$q#>j~> +!ouXLf)GdAK&ck3h3[1%!QhG'rrKLBj8T.Pe`6Z1MsB's!-NkmJcC<$q#>j~> +!ouXLL&V1cdZa\2NkPGmp\oXB_RKOFg\u[&hYmHTaMn&V!Q<*2s-Nb9~> +!ouXLL&V1cdZa\2NkPGmp\oXB_RKOFg\u[&hYmHTaMn&V!Q<*2s-Nb9~> +!ouXLL&V1cdZa\2NkPGmp\oXB_RKOFg\u[&hYmHTaMn&V!Q<*2s-Nb9~> +"lqsOs8S>_@fVJerrJ2Co)A`3GfB[_Fl<9$^4G)<rrUAR]C#V#c!t8,r;Qi,A'k5T!S*h3rrSHq +B[m%_G,G3;",$1/N;ih\O(7qad\H:2"b:Cgs2))8rr[EDb,b79"R[8"SC%98#OmHI]"7qAr;L1+ +Xks'Xj8EHfg%PFR`if?(j8]/>S=DXRrVlrKIEMKf!muA@JcD,;J,~> +"lqsOs8S>_@fVJerrJ2Co)A`3GfB[_Fl<9$^4G)<rrUAR]C#V#c!t8,r;Qi,A'k5T!S*h3rrSHq +B[m%_G,G3;",$1/N;ih\O(7qad\H:2"b:Cgs2))8rr[EDb,b79"R[8"SC%98#OmHI]"7qAr;L1+ +Xks'Xj8EHfg%PFR`if?(j8]/>S=DXRrVlrKIEMKf!muA@JcD,;J,~> +"lqsOs8S>_@fVJerrJ2Co)A`3GfB[_Fl<9$^4G)<rrUAR]C#V#c!t8,r;Qi,A'k5T!S*h3rrSHq +B[m%_G,G3;",$1/N;ih\O(7qad\H:2"b:Cgs2))8rr[EDb,b79"R[8"SC%98#OmHI]"7qAr;L1+ +Xks'Xj8EHfg%PFR`if?(j8]/>S=DXRrVlrKIEMKf!muA@JcD,;J,~> +"lqsOs-ArL\-AC]s8U8Gp@J:b^VS_*!V0skrr=(trrJC?r;Qi]\DZcS"6d6nWVlbthRMhLrrK]? +nc&`YPdn,0hZ!V$j8/cV*rc*;$o@/%6N@(IR(-<![:oR>!FYftrs!qIZ=X'*JbK*G*WN'\pAY0] +0)PYRju37"NrT,`rjVu\[,Crbo3D7(!Ft<errf'Bs%:`;rrHK?r;Qe>W;HSqCpAQkR/_[~> +"lqsOs-ArL\-AC]s8U8Gp@J:b^VS_*!V0skrr=(trrJC?r;Qi]\DZcS"6d6nWVlbthRMhLrrK]? +nc&`YPdn,0hZ!V$j8/cV*rc*;$o@/%6N@(IR(-<![:oR>!FYftrs!qIZ=X'*JbK*G*WN'\pAY0] +0)PYRju37"NrT,`rjVu\[,Crbo3D7(!Ft<errf'Bs%:`;rrHK?r;Qe>W;HSqCpAQkR/_[~> +"lqsOs-ArL\-AC]s8U8Gp@J:b^VS_*!V0skrr=(trrJC?r;Qi]\DZcS"6d6nWVlbthRMhLrrK]? +nc&`YPdn,0hZ!V$j8/cV*rc*;$o@/%6N@(IR(-<![:oR>!FYftrs!qIZ=X'*JbK*G*WN'\pAY0] +0)PYRju37"NrT,`rjVu\[,Crbo3D7(!Ft<errf'Bs%:`;rrHK?r;Qe>W;HSqCpAQkR/_[~> +"lqsOs)#">rrKc?rr3#R6HoH1m4[i+!$1%u!l&a@j8T.$WV6>m\mk40"E(CBpa"_r!CYT;rrHE@ +qu7'\l.SK(s(/\>b:?iZrr3!CqXsjm9[NaJ.rFSFrrX;AW-.h6!U_T;rs.[Es,N->ruM+=!JZs! +rrW,+CB"56hYHpG"JU5B9%*Y;!FNP<rrV@pci!eEk$Q\js-`n;~> +"lqsOs)#">rrKc?rr3#R6HoH1m4[i+!$1%u!l&a@j8T.$WV6>m\mk40"E(CBpa"_r!CYT;rrHE@ +qu7'\l.SK(s(/\>b:?iZrr3!CqXsjm9[NaJ.rFSFrrX;AW-.h6!U_T;rs.[Es,N->ruM+=!JZs! +rrW,+CB"56hYHpG"JU5B9%*Y;!FNP<rrV@pci!eEk$Q\js-`n;~> +"lqsOs)#">rrKc?rr3#R6HoH1m4[i+!$1%u!l&a@j8T.$WV6>m\mk40"E(CBpa"_r!CYT;rrHE@ +qu7'\l.SK(s(/\>b:?iZrr3!CqXsjm9[NaJ.rFSFrrX;AW-.h6!U_T;rs.[Es,N->ruM+=!JZs! +rrW,+CB"56hYHpG"JU5B9%*Y;!FNP<rrV@pci!eEk$Q\js-`n;~> +$KOKTs7Z<hs3js?rVlrY6h^6R!_aRerVlol6N.r*EV]V6!p^A$rr3!gf_uj%J,91/m/R*]LB%9= +)?h*#PkY1Xn,44/S,<4+cMedcU\t/Xr>Z3Fr;JVFV]6\]rVt:D*!NkNs8TB>r;QlD*#=n?rrN)2 +r>Yj_rq??mF/f-<"0W[Z[f6:.\m:*j*!#='rrQ^Air/l^DQa$>o)JQDrYuV$o`(\EnkpG]p&C<n +*5aNjp&G&<rYu2-pA^*l#8eFOrVlm\iVWWkoD\^\s8Vfis8MN[s8R!W"<8Cns8VdbrYuMaq#C!a +s8DH\s8PmA,9.\Iq>UBrnc/I[pAY0]0)PYRrU^'aq#C@7rpg2AQiI(9rVm%8_#OG]>5\C+/,u]" +s'!eLdet-g\,H<I&cNaP^A\&Lr>Z*^rr<#op]'m`r;Qe)^&.g1=2t.;!D^pks-`n;~> +$KOKTs7Z<hs3js?rVlrY6h^6R!_aRerVlol6N.r*EV]V6!p^A$rr3!gf_uj%J,91/m/R*]LB%9= +)?h*#PkY1Xn,44/S,<4+cMedcU\t/Xr>Z3Fr;JVFV]6\]rVt:D*!NkNs8TB>r;QlD*#=n?rrN)2 +r>Yj_rq??mF/f-<"0W[Z[f6:.\m:*j*!#='rrQ^Air/l^DQa$>o)JQDrYuV$o`(\EnkpG]p&C<n +*5aNjp&G&<rYu2-pA^*l#8eFOrVlm\iVWWkoD\^\s8Vfis8MN[s8R!W"<8Cns8VdbrYuMaq#C!a +s8DH\s8PmA,9.\Iq>UBrnc/I[pAY0]0)PYRrU^'aq#C@7rpg2AQiI(9rVm%8_#OG]>5\C+/,u]" +s'!eLdet-g\,H<I&cNaP^A\&Lr>Z*^rr<#op]'m`r;Qe)^&.g1=2t.;!D^pks-`n;~> +$KOKTs7Z<hs3js?rVlrY6h^6R!_aRerVlol6N.r*EV]V6!p^A$rr3!gf_uj%J,91/m/R*]LB%9= +)?h*#PkY1Xn,44/S,<4+cMedcU\t/Xr>Z3Fr;JVFV]6\]rVt:D*!NkNs8TB>r;QlD*#=n?rrN)2 +r>Yj_rq??mF/f-<"0W[Z[f6:.\m:*j*!#='rrQ^Air/l^DQa$>o)JQDrYuV$o`(\EnkpG]p&C<n +*5aNjp&G&<rYu2-pA^*l#8eFOrVlm\iVWWkoD\^\s8Vfis8MN[s8R!W"<8Cns8VdbrYuMaq#C!a +s8DH\s8PmA,9.\Iq>UBrnc/I[pAY0]0)PYRrU^'aq#C@7rpg2AQiI(9rVm%8_#OG]>5\C+/,u]" +s'!eLdet-g\,H<I&cNaP^A\&Lr>Z*^rr<#op]'m`r;Qe)^&.g1=2t.;!D^pks-`n;~> +!ouXLrVloJ8c&Gfd7a04!W"#=rrGd@rr3"fK)YcOm3ulNrrG/,rr37\PQ*B's8S[>rr3#d0D,8E +*W?!@JAM6u:&b.n?bQ@:$Wb:Ii!OT+s%^l4-iO&KA)71bZ>079!K<->rrLn@rVlmLnFlk_F/f': +!Gf"?rrTbCPlC[_*W?!JF=H>Os7+ZGP1KO1s.Fc=rt4`Os8REaaoCN]s,`6?39B$\qu6]J7fNDg +7+hD:!Bf?,rrF>?rVlmtaSu2?ZB"_[#"'X1s8S:?n,EFV0(f/D)ZD/q'pnt#5McA>l>"B>s34C< +rs0\GVfi#8c1WL_rrYdBmP"P="$YT'2uWaW<pTGY!FNP;rrH3@qu6[lc@Q"`s*t~> +!ouXLrVloJ8c&Gfd7a04!W"#=rrGd@rr3"fK)YcOm3ulNrrG/,rr37\PQ*B's8S[>rr3#d0D,8E +*W?!@JAM6u:&b.n?bQ@:$Wb:Ii!OT+s%^l4-iO&KA)71bZ>079!K<->rrLn@rVlmLnFlk_F/f': +!Gf"?rrTbCPlC[_*W?!JF=H>Os7+ZGP1KO1s.Fc=rt4`Os8REaaoCN]s,`6?39B$\qu6]J7fNDg +7+hD:!Bf?,rrF>?rVlmtaSu2?ZB"_[#"'X1s8S:?n,EFV0(f/D)ZD/q'pnt#5McA>l>"B>s34C< +rs0\GVfi#8c1WL_rrYdBmP"P="$YT'2uWaW<pTGY!FNP;rrH3@qu6[lc@Q"`s*t~> +!ouXLrVloJ8c&Gfd7a04!W"#=rrGd@rr3"fK)YcOm3ulNrrG/,rr37\PQ*B's8S[>rr3#d0D,8E +*W?!@JAM6u:&b.n?bQ@:$Wb:Ii!OT+s%^l4-iO&KA)71bZ>079!K<->rrLn@rVlmLnFlk_F/f': +!Gf"?rrTbCPlC[_*W?!JF=H>Os7+ZGP1KO1s.Fc=rt4`Os8REaaoCN]s,`6?39B$\qu6]J7fNDg +7+hD:!Bf?,rrF>?rVlmtaSu2?ZB"_[#"'X1s8S:?n,EFV0(f/D)ZD/q'pnt#5McA>l>"B>s34C< +rs0\GVfi#8c1WL_rrYdBmP"P="$YT'2uWaW<pTGY!FNP;rrH3@qu6[lc@Q"`s*t~> +!ouXLrr3#?<Vl^sqPAT4rrMs?rVlmkdf07IRY(>7!BT6>rs4IFs"Wj>s.4]=rrML?o`"n3qYpO9 +rVlt,^&Rp,\cb7;s56$=rr[`)pfIF*!:9^b!O?J:rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1 +@f?<,*VfX@^dT:t7IU9VTR?b='_![Rs*LL?s6a\&OH'9"jki6$s4@7]!M)^ZrrGO?qu6[ZiTpLE +,5V9<!J7$E\cC4RrrGL?rr3"_MXUQGmOn/3!$2(=$&4fHs7.Z>s*^O=rrLA@r;R$Ds/1#>:X/S[ +rVlsif'Y3irrYIAlsB\&!9s+T!FNP;rrH3@qu6[lc@Q"`s*t~> +!ouXLrr3#?<Vl^sqPAT4rrMs?rVlmkdf07IRY(>7!BT6>rs4IFs"Wj>s.4]=rrML?o`"n3qYpO9 +rVlt,^&Rp,\cb7;s56$=rr[`)pfIF*!:9^b!O?J:rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1 +@f?<,*VfX@^dT:t7IU9VTR?b='_![Rs*LL?s6a\&OH'9"jki6$s4@7]!M)^ZrrGO?qu6[ZiTpLE +,5V9<!J7$E\cC4RrrGL?rr3"_MXUQGmOn/3!$2(=$&4fHs7.Z>s*^O=rrLA@r;R$Ds/1#>:X/S[ +rVlsif'Y3irrYIAlsB\&!9s+T!FNP;rrH3@qu6[lc@Q"`s*t~> +!ouXLrr3#?<Vl^sqPAT4rrMs?rVlmkdf07IRY(>7!BT6>rs4IFs"Wj>s.4]=rrML?o`"n3qYpO9 +rVlt,^&Rp,\cb7;s56$=rr[`)pfIF*!:9^b!O?J:rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1 +@f?<,*VfX@^dT:t7IU9VTR?b='_![Rs*LL?s6a\&OH'9"jki6$s4@7]!M)^ZrrGO?qu6[ZiTpLE +,5V9<!J7$E\cC4RrrGL?rr3"_MXUQGmOn/3!$2(=$&4fHs7.Z>s*^O=rrLA@r;R$Ds/1#>:X/S[ +rVlsif'Y3irrYIAlsB\&!9s+T!FNP;rrH3@qu6[lc@Q"`s*t~> +#NS0Qs8T`Ko(r@eT76G4!W"#=rrGd@rr3"fK)#?H3o^/=#`4cF1$el>Spp\=!UVQ4rr=)9rr=)< +rrZWAs-rsq"<kebi&po:!9a;h"c`$Os0?D9rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1@f?<, +*VTL6DQ`s<!MFi>rrqmCs8RG?r;R(bNW2!"h`_"eHN%=R;+CQb!CYT;rrG7@li-u0qY^?nKDo9[ +GKfj^!CPQ>rrJ=@n,EFV0(f/D*WH'FL6qr?pM7=mJ&M?d!R4I=rs0\GVfi#8c1WL_rrYdBmP"P= +"$YT7OoAbhbk(i8?bQ@:!E[;<rrGm?JcD/<J,~> +#NS0Qs8T`Ko(r@eT76G4!W"#=rrGd@rr3"fK)#?H3o^/=#`4cF1$el>Spp\=!UVQ4rr=)9rr=)< +rrZWAs-rsq"<kebi&po:!9a;h"c`$Os0?D9rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1@f?<, +*VTL6DQ`s<!MFi>rrqmCs8RG?r;R(bNW2!"h`_"eHN%=R;+CQb!CYT;rrG7@li-u0qY^?nKDo9[ +GKfj^!CPQ>rrJ=@n,EFV0(f/D*WH'FL6qr?pM7=mJ&M?d!R4I=rs0\GVfi#8c1WL_rrYdBmP"P= +"$YT7OoAbhbk(i8?bQ@:!E[;<rrGm?JcD/<J,~> +#NS0Qs8T`Ko(r@eT76G4!W"#=rrGd@rr3"fK)#?H3o^/=#`4cF1$el>Spp\=!UVQ4rr=)9rr=)< +rrZWAs-rsq"<kebi&po:!9a;h"c`$Os0?D9rrJ(?rr3#S62gfa/F`B5!HY7;rrHo@rr3#1@f?<, +*VTL6DQ`s<!MFi>rrqmCs8RG?r;R(bNW2!"h`_"eHN%=R;+CQb!CYT;rrG7@li-u0qY^?nKDo9[ +GKfj^!CPQ>rrJ=@n,EFV0(f/D*WH'FL6qr?pM7=mJ&M?d!R4I=rs0\GVfi#8c1WL_rrYdBmP"P= +"$YT7OoAbhbk(i8?bQ@:!E[;<rrGm?JcD/<J,~> +#38'Ps0mL>qYpS^L@bEGqBGn<!DCl?rrJR?rr3&lJuSbL!BP?%rs4IFs"Wj>s.4]=rrqdCs8Td\ +q#:=7rVlu-g]&;mrrZWAruM+="hQ>*s56$;rrMt]rVm'jfDkm'J&M6a!K<->rrLn@rVlmLnFlk_ +F/f':!Gf"?rrTbe_>aH7*W?!>Y(H0ArrI#?rVlnkI/a-Ln1=V>H_UH<%Zl\M39B$\s+cm>s7pM$ +rr3*hf`1-5rr3%hJc>$9#9s$Ef"(g]jSo/[Uj;b8!CPQ>rrJ=@pAY3]K!G:S!U_T4rr=)=rrIk@ +rr3)N8",&.rt!@Ns1?e\ruV3<FoP7^p*Tb<"%Ur10E(nQ52PB[rVlngoC`+a?bQC;!kWsAr;Qi- +J*-\/!jdLEJcDGDJ,~> +#38'Ps0mL>qYpS^L@bEGqBGn<!DCl?rrJR?rr3&lJuSbL!BP?%rs4IFs"Wj>s.4]=rrqdCs8Td\ +q#:=7rVlu-g]&;mrrZWAruM+="hQ>*s56$;rrMt]rVm'jfDkm'J&M6a!K<->rrLn@rVlmLnFlk_ +F/f':!Gf"?rrTbe_>aH7*W?!>Y(H0ArrI#?rVlnkI/a-Ln1=V>H_UH<%Zl\M39B$\s+cm>s7pM$ +rr3*hf`1-5rr3%hJc>$9#9s$Ef"(g]jSo/[Uj;b8!CPQ>rrJ=@pAY3]K!G:S!U_T4rr=)=rrIk@ +rr3)N8",&.rt!@Ns1?e\ruV3<FoP7^p*Tb<"%Ur10E(nQ52PB[rVlngoC`+a?bQC;!kWsAr;Qi- +J*-\/!jdLEJcDGDJ,~> +#38'Ps0mL>qYpS^L@bEGqBGn<!DCl?rrJR?rr3&lJuSbL!BP?%rs4IFs"Wj>s.4]=rrqdCs8Td\ +q#:=7rVlu-g]&;mrrZWAruM+="hQ>*s56$;rrMt]rVm'jfDkm'J&M6a!K<->rrLn@rVlmLnFlk_ +F/f':!Gf"?rrTbe_>aH7*W?!>Y(H0ArrI#?rVlnkI/a-Ln1=V>H_UH<%Zl\M39B$\s+cm>s7pM$ +rr3*hf`1-5rr3%hJc>$9#9s$Ef"(g]jSo/[Uj;b8!CPQ>rrJ=@pAY3]K!G:S!U_T4rr=)=rrIk@ +rr3)N8",&.rt!@Ns1?e\ruV3<FoP7^p*Tb<"%Ur10E(nQ52PB[rVlngoC`+a?bQC;!kWsAr;Qi- +J*-\/!jdLEJcDGDJ,~> +"lqsOs(t7(Ad+k-s,iH?o`#2OA.E4Bs8TQHral1Wc2R_Ekl=QZrrG0:ralakeGlXcAnH==_uKc3 +OCi*Ug\CdKUA\[+K]2qOrVlt,^&OGuAd*cC`rFsZr;QfpOo8kmMspZF!L8H=rs7Fm3'([/s7)'H +Ac\"hq#:rOAhHJ`n,NF0Ah-A`o`)KaJ,X$[TDeck=odLZrrI#?rVloOJGs-aBrh:6H_UH<%Zl\M +YOp^8s3H%(AnZ`brr3,.DJ!jtrVlm>rp9XiVe9Uc`rEYjral1UanYl:6eVJ=!L&E7rrUmS@/^*+ +mOn/3!2BI)!IiSurr_\IHHlEg&*o'aK&$D+P@d08Ar5jNOo8koMsgA%rFQ.ko(A%AAc[qbp&>&" +^&7m2FK#*:!Go%<rrQ[1eq*jps*t~> +"lqsOs(t7(Ad+k-s,iH?o`#2OA.E4Bs8TQHral1Wc2R_Ekl=QZrrG0:ralakeGlXcAnH==_uKc3 +OCi*Ug\CdKUA\[+K]2qOrVlt,^&OGuAd*cC`rFsZr;QfpOo8kmMspZF!L8H=rs7Fm3'([/s7)'H +Ac\"hq#:rOAhHJ`n,NF0Ah-A`o`)KaJ,X$[TDeck=odLZrrI#?rVloOJGs-aBrh:6H_UH<%Zl\M +YOp^8s3H%(AnZ`brr3,.DJ!jtrVlm>rp9XiVe9Uc`rEYjral1UanYl:6eVJ=!L&E7rrUmS@/^*+ +mOn/3!2BI)!IiSurr_\IHHlEg&*o'aK&$D+P@d08Ar5jNOo8koMsgA%rFQ.ko(A%AAc[qbp&>&" +^&7m2FK#*:!Go%<rrQ[1eq*jps*t~> +"lqsOs(t7(Ad+k-s,iH?o`#2OA.E4Bs8TQHral1Wc2R_Ekl=QZrrG0:ralakeGlXcAnH==_uKc3 +OCi*Ug\CdKUA\[+K]2qOrVlt,^&OGuAd*cC`rFsZr;QfpOo8kmMspZF!L8H=rs7Fm3'([/s7)'H +Ac\"hq#:rOAhHJ`n,NF0Ah-A`o`)KaJ,X$[TDeck=odLZrrI#?rVloOJGs-aBrh:6H_UH<%Zl\M +YOp^8s3H%(AnZ`brr3,.DJ!jtrVlm>rp9XiVe9Uc`rEYjral1UanYl:6eVJ=!L&E7rrUmS@/^*+ +mOn/3!2BI)!IiSurr_\IHHlEg&*o'aK&$D+P@d08Ar5jNOo8koMsgA%rFQ.ko(A%AAc[qbp&>&" +^&7m2FK#*:!Go%<rrQ[1eq*jps*t~> +"QVjNs4.%T"O[8Lb4G6)!6+rF!7:`F!5e`C!7LiG!r97Jrr3![ir6=cfDbdR]=#&og>`,3"nB". +h#DQp8cls2rVa,+iW&qlrVluIm/Qn\[0>C3mf3"#qu6ZgrNuXkrVlrWI)#[\!:Tlo"7Z?jm/=<m +o(DiO!rDr[rNub%s8V3Z[06@+ldFMd[/g.'rrUNSpAP!le`Zl1!8IL\!4i+/!SQQ3rrM$6rr3;u +a8c1h[C*O9ao25@^pV)XrrKi?li.$p[E\^N!6+rF!7:K?!Qk!5rrM'6pAY3dL1'u["RZ^k8u_Rb +!<2u*!8.5L!UA,1rrVDlh>[E[p9f'B[HRYjo_l0"li7"TrNuaps8VQd[/f[irrgP<8fYPCrrTHY +k5>5\X,-!:rrUWVo7?q8s*t~> +"QVjNs4.%T"O[8Lb4G6)!6+rF!7:`F!5e`C!7LiG!r97Jrr3![ir6=cfDbdR]=#&og>`,3"nB". +h#DQp8cls2rVa,+iW&qlrVluIm/Qn\[0>C3mf3"#qu6ZgrNuXkrVlrWI)#[\!:Tlo"7Z?jm/=<m +o(DiO!rDr[rNub%s8V3Z[06@+ldFMd[/g.'rrUNSpAP!le`Zl1!8IL\!4i+/!SQQ3rrM$6rr3;u +a8c1h[C*O9ao25@^pV)XrrKi?li.$p[E\^N!6+rF!7:K?!Qk!5rrM'6pAY3dL1'u["RZ^k8u_Rb +!<2u*!8.5L!UA,1rrVDlh>[E[p9f'B[HRYjo_l0"li7"TrNuaps8VQd[/f[irrgP<8fYPCrrTHY +k5>5\X,-!:rrUWVo7?q8s*t~> +"QVjNs4.%T"O[8Lb4G6)!6+rF!7:`F!5e`C!7LiG!r97Jrr3![ir6=cfDbdR]=#&og>`,3"nB". +h#DQp8cls2rVa,+iW&qlrVluIm/Qn\[0>C3mf3"#qu6ZgrNuXkrVlrWI)#[\!:Tlo"7Z?jm/=<m +o(DiO!rDr[rNub%s8V3Z[06@+ldFMd[/g.'rrUNSpAP!le`Zl1!8IL\!4i+/!SQQ3rrM$6rr3;u +a8c1h[C*O9ao25@^pV)XrrKi?li.$p[E\^N!6+rF!7:K?!Qk!5rrM'6pAY3dL1'u["RZ^k8u_Rb +!<2u*!8.5L!UA,1rrVDlh>[E[p9f'B[HRYjo_l0"li7"TrNuaps8VQd[/f[irrgP<8fYPCrrTHY +k5>5\X,-!:rrUWVo7?q8s*t~> +!ouXLd/O,-ip?[Fh##J!nC@O>kO7p?!;u]@!<0,#!7o'f!PDh=rrDurd/`FerrK$?h>[KGrm:`; +rVloalMLS^lKj*%QiDR~> +!ouXLd/O,-ip?[Fh##J!nC@O>kO7p?!;u]@!<0,#!7o'f!PDh=rrDurd/`FerrK$?h>[KGrm:`; +rVloalMLS^lKj*%QiDR~> +!ouXLd/O,-ip?[Fh##J!nC@O>kO7p?!;u]@!<0,#!7o'f!PDh=rrDurd/`FerrK$?h>[KGrm:`; +rVloalMLS^lKj*%QiDR~> +!ouXLd/O,5jFR>grrV%Uo[NmAWdB<sJcF[.J,~> +!ouXLd/O,5jFR>grrV%Uo[NmAWdB<sJcF[.J,~> +!ouXLd/O,5jFR>grrV%Uo[NmAWdB<sJcF[.J,~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +#in9Rs8UK[]uSt/!65#O!82r'JcC<$JcE(VJ,~> +#in9Rs8UK[]uSt/!65#O!82r'JcC<$JcE(VJ,~> +#in9Rs8UK[]uSt/!65#O!82r'JcC<$JcE(VJ,~> +$04BSs2f=g?>-n,rrKZDra#VPe:IXNs+13$s0VfV~> +$04BSs2f=g?>-n,rrKZDra#VPe:IXNs+13$s0VfV~> +$04BSs2f=g?>-n,rrKZDra#VPe:IXNs+13$s0VfV~> +$04BSs)#"?s4Kcsrs#$Hqu?]9_L_`<s+13$s0VfV~> +$04BSs)#"?s4Kcsrs#$Hqu?]9_L_`<s+13$s0VfV~> +$04BSs)#"?s4Kcsrs#$Hqu?]9_L_`<s+13$s0VfV~> +%HKfWs)#"?s4Kd>s.n3ErrLQFrr3"HrVca&Rc"$ks2_GEs+C;b!2TVo"=7VnBrV+3!."QX!3UnQ +JcC<$JcE@^J,~> +%HKfWs)#"?s4Kd>s.n3ErrLQFrr3"HrVca&Rc"$ks2_GEs+C;b!2TVo"=7VnBrV+3!."QX!3UnQ +JcC<$JcE@^J,~> +%HKfWs)#"?s4Kd>s.n3ErrLQFrr3"HrVca&Rc"$ks2_GEs+C;b!2TVo"=7VnBrV+3!."QX!3UnQ +JcC<$JcE@^J,~> +%HKfWs(sVe9L2&Gs(&Y=rrKK@rr3!Bqu-O$;p"k[s.ao?JY<"K"H'/XH_gYI"Ga/[Ff55F!J@_0 +s+13$s+13_s*t~> +%HKfWs(sVe9L2&Gs(&Y=rrKK@rr3!Bqu-O$;p"k[s.ao?JY<"K"H'/XH_gYI"Ga/[Ff55F!J@_0 +s+13$s+13_s*t~> +%HKfWs(sVe9L2&Gs(&Y=rrKK@rr3!Bqu-O$;p"k[s.ao?JY<"K"H'/XH_gYI"Ga/[Ff55F!J@_0 +s+13$s+13_s*t~> +'')>\s)!eBc`fe:s5I;>s4Ui>rr3!Bqu-O$;p"k[s.ao?9@Eh>"IarB6JDG="Hn]C3o^/=!U8m# +s+13$s+13_s*t~> +'')>\s)!eBc`fe:s5I;>s4Ui>rr3!Bqu-O$;p"k[s.ao?9@Eh>"IarB6JDG="Hn]C3o^/=!U8m# +s+13$s+13_s*t~> +'')>\s)!eBc`fe:s5I;>s4Ui>rr3!Bqu-O$;p"k[s.ao?9@Eh>"IarB6JDG="Hn]C3o^/=!U8m# +s+13$s+13_s*t~> +$04BSs)#"?s4Kd=rrc$Brle7<rrF;?rVm1&and4]UO)r5df07LRY(Q+gA_*WP)KA)1)q9LJcC<$ +JcC<$])R9~> +$04BSs)#"?s4Kd=rrc$Brle7<rrF;?rVm1&and4]UO)r5df07LRY(Q+gA_*WP)KA)1)q9LJcC<$ +JcC<$])R9~> +$04BSs)#"?s4Kd=rrc$Brle7<rrF;?rVm1&and4]UO)r5df07LRY(Q+gA_*WP)KA)1)q9LJcC<$ +JcC<$])R9~> +$04BSs)#"?s4Kd<rrO\00)Y_[+oD#ss8Q$>qBGs7HN-Xdrr3+iK)\0krr3+aMuPitrr3#fn:CUj +s+13$s1JA^~> +$04BSs)#"?s4Kd<rrO\00)Y_[+oD#ss8Q$>qBGs7HN-Xdrr3+iK)\0krr3+aMuPitrr3#fn:CUj +s+13$s1JA^~> +$04BSs)#"?s4Kd<rrO\00)Y_[+oD#ss8Q$>qBGs7HN-Xdrr3+iK)\0krr3+aMuPitrr3#fn:CUj +s+13$s1JA^~> +$04BSs,i\`^T;JSrrQQ4@f66:=hUV\s8RPD]G\JHS,[`4rkASqU&T,7rkASmW;gY<rkAJeY(?V( +s+13$s1JA^~> +$04BSs,i\`^T;JSrrQQ4@f66:=hUV\s8RPD]G\JHS,[`4rkASqU&T,7rkASmW;gY<rkAJeY(?V( +s+13$s1JA^~> +$04BSs,i\`^T;JSrrQQ4@f66:=hUV\s8RPD]G\JHS,[`4rkASqU&T,7rkASmW;gY<rkAJeY(?V( +s+13$s1JA^~> +#in9Rs8S-b>]flC!,q`6!FC9SrrddS$s].urr@?D>QC;nrr@0?>QCMtrr?s9>QC[Qs+13$s+13^ +s*t~> +#in9Rs8S-b>]flC!,q`6!FC9SrrddS$s].urr@?D>QC;nrr@0?>QCMtrr?s9>QC[Qs+13$s+13^ +s*t~> +#in9Rs8S-b>]flC!,q`6!FC9SrrddS$s].urr@?D>QC;nrr@0?>QCMtrr?s9>QC[Qs+13$s+13^ +s*t~> +!ouXLk5PJY,(]cFs+13$s.TIC~> +!ouXLk5PJY,(]cFs+13$s.TIC~> +!ouXLk5PJY,(]cFs+13$s.TIC~> +!ouXLk5PJY,(]cFs+13$s.TIC~> +!ouXLk5PJY,(]cFs+13$s.TIC~> +!ouXLk5PJY,(]cFs+13$s.TIC~> +!ouXLk5PJ]\q0m4s+13$s.TIC~> +!ouXLk5PJ]\q0m4s+13$s.TIC~> +!ouXLk5PJ]\q0m4s+13$s.TIC~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLq#:A8^4H<8s+13$s,[21~> +!ouXLq#:A8^4H<8s+13$s,[21~> +!ouXLq#:A8^4H<8s+13$s,[21~> +!ouXLq#:A*\:O[2s+13$s,[21~> +!ouXLq#:A*\:O[2s+13$s,[21~> +!ouXLq#:A*\:O[2s+13$s,[21~> +"lqsOs8UXK_?A<es(&Y=rrMNAJcC<$JcC<$PlH7~> +"lqsOs8UXK_?A<es(&Y=rrMNAJcC<$JcC<$PlH7~> +"lqsOs8UXK_?A<es(&Y=rrMNAJcC<$JcC<$PlH7~> +"lqsOs3,K^=UArcs(&Y>q504DJcC<$JcC<$PlH7~> +"lqsOs3,K^=UArcs(&Y>q504DJcC<$JcC<$PlH7~> +"lqsOs3,K^=UArcs(&Y>q504DJcC<$JcC<$PlH7~> +"lqsOs)#">rs68Fs(&X1Lio;?s+13$s+136s*t~> +"lqsOs)#">rs68Fs(&X1Lio;?s+13$s+136s*t~> +"lqsOs)#">rs68Fs(&X1Lio;?s+13$s+136s*t~> +"lqsOs)#">rs$,Ds("oaR=YBhs+13$s,m>3~> +"lqsOs)#">rs$,Ds("oaR=YBhs+13$s,m>3~> +"lqsOs)#">rs$,Ds("oaR=YBhs+13$s,m>3~> +"lqsOs)#">rs$,Ds($Od?%N$,s+13$s,m>3~> +"lqsOs)#">rs$,Ds($Od?%N$,s+13$s,m>3~> +"lqsOs)#">rs$,Ds($Od?%N$,s+13$s,m>3~> +"lqsOs)#">rs68Fs(&Xf^c$1`s+13$s+136s*t~> +"lqsOs)#">rs68Fs(&Xf^c$1`s+13$s+136s*t~> +"lqsOs)#">rs68Fs(&Xf^c$1`s+13$s+136s*t~> +"lqsOs6s7l*!oL2s(8hArT1&)JcC<$JcC<$PlH7~> +"lqsOs6s7l*!oL2s(8hArT1&)JcC<$JcC<$PlH7~> +"lqsOs6s7l*!oL2s(8hArT1&)JcC<$JcC<$PlH7~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +!ouXLJcC<$JcC<$K`?Q~> +"QVjNs/l3<"K)5!R-9,$JcC<$JcCi3J,~> +"QVjNs/l3<"K)5!R-9,$JcC<$JcCi3J,~> +"QVjNs/l3<"K)5!R-9,$JcC<$JcCi3J,~> +"QVjNs3LYE#(Bt[s2&7>JcC<$JcC<$OoKq~> +"QVjNs3LYE#(Bt[s2&7>JcC<$JcC<$OoKq~> +"QVjNs3LYE#(Bt[s2&7>JcC<$JcC<$OoKq~> +!ouXLr;QiX?JPP[!ROMks+13$s+134s*t~> +!ouXLr;QiX?JPP[!ROMks+13$s+134s*t~> +!ouXLr;QiX?JPP[!ROMks+13$s+134s*t~> +!ouXLrVlrn3U6PB!S9bks+13$s+135s*t~> +!ouXLrVlrn3U6PB!S9bks+13$s+135s*t~> +!ouXLrVlrn3U6PB!S9bks+13$s+135s*t~> +%%EndData +showpage +%%Trailer +end +%%EOF diff --git a/lib/stdlib/doc/src/win32reg.xml b/lib/stdlib/doc/src/win32reg.xml new file mode 100644 index 0000000000..d8055047b0 --- /dev/null +++ b/lib/stdlib/doc/src/win32reg.xml @@ -0,0 +1,276 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2000</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>win32reg</title> + <prepared>Bjorn Gustavsson</prepared> + <responsible>NN</responsible> + <docno></docno> + <approved>nobody</approved> + <checked>no</checked> + <date>2000-08-10</date> + <rev>PA1</rev> + <file>win32reg.sgml</file> + </header> + <module>win32reg</module> + <modulesummary>win32reg provides access to the registry on Windows</modulesummary> + <description> + <p><c>win32reg</c> provides read and write access to the + registry on Windows. It is essentially a port driver wrapped around the + Win32 API calls for accessing the registry.</p> + <p>The registry is a hierarchical database, used to store various system + and software information in Windows. It is available in Windows 95 and + Windows NT. It contains installation data, and is updated by installers + and system programs. The Erlang installer updates the registry by adding + data that Erlang needs.</p> + <p>The registry contains keys and values. Keys are like the directories + in a file system, they form a hierarchy. Values are like files, they have + a name and a value, and also a type.</p> + <p>Paths to keys are left to right, with sub-keys to the right and backslash + between keys. (Remember that backslashes must be doubled in Erlang strings.) + Case is preserved but not significant. + Example: <c>"\\\\hkey_local_machine\\\\software\\\\Ericsson\\\\Erlang\\\\5.0"</c> is the key + for the installation data for the latest Erlang release.</p> + <p>There are six entry points in the Windows registry, top level keys. They can be + abbreviated in the <c>win32reg</c> module as:</p> + <pre> +Abbrev. Registry key +======= ============ +hkcr HKEY_CLASSES_ROOT +current_user HKEY_CURRENT_USER +hkcu HKEY_CURRENT_USER +local_machine HKEY_LOCAL_MACHINE +hklm HKEY_LOCAL_MACHINE +users HKEY_USERS +hku HKEY_USERS +current_config HKEY_CURRENT_CONFIG +hkcc HKEY_CURRENT_CONFIG +dyn_data HKEY_DYN_DATA +hkdd HKEY_DYN_DATA</pre> + <p>The key above could be written as <c>"\\\\hklm\\\\software\\\\ericsson\\\\erlang\\\\5.0"</c>.</p> + <p>The <c>win32reg</c> module uses a current key. It works much like the + current directory. From the current key, values can be fetched, sub-keys + can be listed, and so on.</p> + <p>Under a key, any number of named values can be stored. They have name, and + types, and data.</p> + <p>Currently, the <c>win32reg</c> module supports storing only the following + types: REG_DWORD, which is an + integer, REG_SZ which is a string and REG_BINARY which is a binary. + Other types can be read, and will be returned as binaries.</p> + <p>There is also a "default" value, which has the empty string as name. It is read and + written with the atom <c>default</c> instead of the name.</p> + <p>Some registry values are stored as strings with references to environment variables, + e.g. <c>"%SystemRoot%Windows"</c>. <c>SystemRoot</c> is an environment variable, and should be + replaced with its value. A function <c>expand/1</c> is provided, so that environment + variables surrounded in % can be expanded to their values.</p> + <p>For additional information on the Windows registry consult the Win32 + Programmer's Reference.</p> + </description> + <funcs> + <func> + <name>change_key(RegHandle, Key) -> ReturnValue</name> + <fsummary>Move to a key in the registry</fsummary> + <type> + <v>RegHandle = term()</v> + <v>Key = string()</v> + </type> + <desc> + <p>Changes the current key to another key. Works like cd. + The key can be specified as a relative path or as an + absolute path, starting with \\.</p> + </desc> + </func> + <func> + <name>change_key_create(RegHandle, Key) -> ReturnValue</name> + <fsummary>Move to a key, create it if it is not there</fsummary> + <type> + <v>RegHandle = term()</v> + <v>Key = string()</v> + </type> + <desc> + <p>Creates a key, or just changes to it, if it is already there. Works + like a combination of <c>mkdir</c> and <c>cd</c>. Calls the Win32 API function + <c>RegCreateKeyEx()</c>.</p> + <p>The registry must have been opened in write-mode.</p> + </desc> + </func> + <func> + <name>close(RegHandle)-> ReturnValue</name> + <fsummary>Close the registry.</fsummary> + <type> + <v>RegHandle = term()</v> + </type> + <desc> + <p>Closes the registry. After that, the <c>RegHandle</c> cannot + be used.</p> + </desc> + </func> + <func> + <name>current_key(RegHandle) -> ReturnValue</name> + <fsummary>Return the path to the current key.</fsummary> + <type> + <v>RegHandle = term()</v> + <v>ReturnValue = {ok, string()}</v> + </type> + <desc> + <p>Returns the path to the current key. This is the equivalent of <c>pwd</c>.</p> + <p>Note that the current key is stored in the driver, and might be + invalid (e.g. if the key has been removed).</p> + </desc> + </func> + <func> + <name>delete_key(RegHandle) -> ReturnValue</name> + <fsummary>Delete the current key</fsummary> + <type> + <v>RegHandle = term()</v> + <v>ReturnValue = ok | {error, ErrorId}</v> + </type> + <desc> + <p>Deletes the current key, if it is valid. Calls the Win32 API + function <c>RegDeleteKey()</c>. Note that this call does not change the current key, + (unlike <c>change_key_create/2</c>.) This means that after the call, the + current key is invalid.</p> + </desc> + </func> + <func> + <name>delete_value(RegHandle, Name) -> ReturnValue</name> + <fsummary>Delete the named value on the current key.</fsummary> + <type> + <v>RegHandle = term()</v> + <v>ReturnValue = ok | {error, ErrorId}</v> + </type> + <desc> + <p>Deletes a named value on the current key. The atom <c>default</c> is + used for the the default value.</p> + <p>The registry must have been opened in write-mode.</p> + </desc> + </func> + <func> + <name>expand(String) -> ExpandedString</name> + <fsummary>Expand a string with environment variables</fsummary> + <type> + <v>String = string()</v> + <v>ExpandedString = string()</v> + </type> + <desc> + <p>Expands a string containing environment variables between percent + characters. Anything between two % is taken for a environment + variable, and is replaced by the value. Two consecutive % is replaced + by one %.</p> + <p>A variable name that is not in the environment, will result in an error.</p> + </desc> + </func> + <func> + <name>format_error(ErrorId) -> ErrorString</name> + <fsummary>Convert an POSIX errorcode to a string</fsummary> + <type> + <v>ErrorId = atom()</v> + <v>ErrorString = string()</v> + </type> + <desc> + <p>Convert an POSIX errorcode to a string (by calling <c>erl_posix_msg:message</c>).</p> + </desc> + </func> + <func> + <name>open(OpenModeList)-> ReturnValue</name> + <fsummary>Open the registry for reading or writing</fsummary> + <type> + <v>OpenModeList = [OpenMode]</v> + <v>OpenMode = read | write</v> + </type> + <desc> + <p>Opens the registry for reading or writing. The current key will be the root + (<c>HKEY_CLASSES_ROOT</c>). The <c>read</c> flag in the mode list can be omitted.</p> + <p>Use <c>change_key/2</c> with an absolute path after <c>open</c>.</p> + </desc> + </func> + <func> + <name>set_value(RegHandle, Name, Value) -> ReturnValue</name> + <fsummary>Set value at the current registry key with specified name.</fsummary> + <type> + <v>Name = string() | default</v> + <v>Value = string() | integer() | binary()</v> + </type> + <desc> + <p>Sets the named (or default) value to value. Calls the Win32 + API function <c>RegSetValueEx()</c>. The value can be of three types, and + the corresponding registry type will be used. Currently the types supported + are: <c>REG_DWORD</c> for integers, <c>REG_SZ</c> for strings and + <c>REG_BINARY</c> for binaries. Other types cannot currently be added + or changed.</p> + <p>The registry must have been opened in write-mode.</p> + </desc> + </func> + <func> + <name>sub_keys(RegHandle) -> ReturnValue</name> + <fsummary>Get subkeys to the current key.</fsummary> + <type> + <v>ReturnValue = {ok, SubKeys} | {error, ErrorId}</v> + <v>SubKeys = [SubKey]</v> + <v>SubKey = string()</v> + </type> + <desc> + <p>Returns a list of subkeys to the current key. Calls the Win32 + API function <c>EnumRegKeysEx()</c>.</p> + <p>Avoid calling this on the root keys, it can be slow.</p> + </desc> + </func> + <func> + <name>value(RegHandle, Name) -> ReturnValue</name> + <fsummary>Get the named value on the current key.</fsummary> + <type> + <v>Name = string() | default</v> + <v>ReturnValue = {ok, Value}</v> + <v>Value = string() | integer() | binary()</v> + </type> + <desc> + <p>Retrieves the named value (or default) on the current key. + Registry values of type <c>REG_SZ</c>, are returned as strings. Type <c>REG_DWORD</c> + values are returned as integers. All other types are returned as binaries.</p> + </desc> + </func> + <func> + <name>values(RegHandle) -> ReturnValue</name> + <fsummary>Get all values on the current key.</fsummary> + <type> + <v>ReturnValue = {ok, ValuePairs} | {ok, ErrorId}</v> + <v>ValuePairs = [ValuePair]</v> + <v>ValuePair = {Name, Value}</v> + <v>Name = string | default</v> + <v>Value = string() | integer() | binary()</v> + </type> + <desc> + <p>Retrieves a list of all values on the current key. The values + have types corresponding to the registry types, see <c>value</c>. + Calls the Win32 API function <c>EnumRegValuesEx()</c>.</p> + </desc> + </func> + </funcs> + + <section> + <title>SEE ALSO</title> + <p>Win32 Programmer's Reference (from Microsoft)</p> + <p><c>erl_posix_msg</c></p> + <p>The Windows 95 Registry (book from O'Reilly)</p> + </section> +</erlref> + diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml new file mode 100644 index 0000000000..e2ecfec8f0 --- /dev/null +++ b/lib/stdlib/doc/src/zip.xml @@ -0,0 +1,463 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> + <header> + <copyright> + <year>2006</year><year>2009</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>zip</title> + <prepared>Jakob Cederlund</prepared> + <responsible>Jakob Cederlund</responsible> + <docno>1</docno> + <approved></approved> + <checked></checked> + <date>05-11-02</date> + <rev>PA1</rev> + <file>zip.sgml</file> + </header> + <module>zip</module> + <modulesummary>Utility for reading and creating 'zip' archives.</modulesummary> + <description> + <p>The <c>zip</c> module archives and extract files to and from a zip + archive. The zip format is specified by the "ZIP Appnote.txt" file + available on PKWare's website www.pkware.com.</p> + <p>The zip module supports zip archive versions up to 6.1. However, + password-protection and Zip64 is not supported.</p> + <p>By convention, the name of a zip file should end in "<c>.zip</c>". + To abide to the convention, you'll need to add "<c>.zip</c>" yourself + to the name.</p> + <p>Zip archives are created with the + <seealso marker="#zip_2">zip/2</seealso> or the + <seealso marker="#zip_2">zip/3</seealso> function. (They are + also available as <c>create</c>, to resemble the <c>erl_tar</c> + module.)</p> + <p>To extract files from a zip archive, use the + <seealso marker="#unzip_1">unzip/1</seealso> or the + <seealso marker="#unzip_2">unzip/2</seealso> function. (They are + also available as <c>extract</c>.)</p> + <p>To return a list of the files in a zip archive, use the + <seealso marker="#list_dir_1">list_dir/1</seealso> or the + <seealso marker="#list_dir_2">list_dir/2</seealso> function. (They + are also available as <c>table</c>.)</p> + <p>To print a list of files to the Erlang shell, + use either the <seealso marker="#t_1">t/1</seealso> or + <seealso marker="#tt_1">tt/1</seealso> function.</p> + <p>In some cases, it is desirable to open a zip archive, and to + unzip files from it file by file, without having to reopen the + archive. The functions + <seealso marker="#zip_open">zip_open</seealso>, + <seealso marker="#zip_get">zip_get</seealso>, + <seealso marker="#zip_list_dir">zip_list_dir</seealso> and + <seealso marker="#zip_close">zip_close</seealso> do this.</p> + </description> + + <section> + <title>LIMITATIONS</title> + <p>Zip64 archives are not currently supported.</p> + <p>Password-protected and encrypted archives are not currently + supported</p> + <p>Only the DEFLATE (zlib-compression) and the STORE (uncompressed + data) zip methods are supported.</p> + <p>The size of the archive is limited to 2 G-byte (32 bits).</p> + <p>Comments for individual files is not supported when creating zip + archives. The zip archive comment for the whole zip archive is + supported.</p> + <p>There is currently no support for altering an existing zip archive. + To add or remove a file from an archive, the whole archive must be + recreated.</p> + </section> + + <section> + <title>DATA TYPES</title> + <code type="none"> +zip_file() </code> + <p>The record <c>zip_file</c> contains the following fields.</p> + <taglist> + <tag><c>name = string()</c></tag> + <item> + <p>the name of the file</p> + </item> + <tag><c>info = file_info()</c></tag> + <item> + <p>file info as in + <seealso marker="erts:file#read_file_info/1">file:read_file_info/1</seealso></p> + </item> + <tag><c>comment = string()</c></tag> + <item> + <p>the comment for the file in the zip archive</p> + </item> + <tag><c>offset = integer()</c></tag> + <item> + <p>the offset of the file in the zip archive (used internally)</p> + </item> + <tag><c>comp_size = integer()</c></tag> + <item> + <p>the compressed size of the file (the uncompressed size is found + in <c>info</c>)</p> + </item> + </taglist> + <code type="none">zip_comment</code> + <p>The record <c>zip_comment</c> just contains the archive comment for + a zip archive</p> + <taglist> + <tag><c>comment = string()</c></tag> + <item> + <p>the comment for the zip archive</p> + </item> + </taglist> + </section> + <funcs> + <func> + <name>zip(Name, FileList) -> RetValue</name> + <name>zip(Name, FileList, Options) -> RetValue</name> + <name>create(Name, FileList) -> RetValue</name> + <name>create(Name, FileList, Options) -> RetValue</name> + <fsummary>Create a zip archive with options</fsummary> + <type> + <v>Name = filename()</v> + <v>FileList = [FileSpec]</v> + <v>FileSpec = filename() | {filename(), binary()}</v> + <v>Options = [Option]</v> + <v>Option = memory | cooked | verbose | {comment, Comment} | {cwd, CWD} | {compress, What} | {uncompress, What}</v> + <v>What = all | [Extension] | {add, [Extension]} | {del, [Extension]}</v> + <v>Extension = string()</v> + <v>Comment = CWD = string()</v> + <v>RetValue = {ok, Name} | {ok, {Name, binary()}} | {error, Reason}</v> + <v>Reason = term()</v> + </type> + <desc> + <p>The <marker id="zip_2"></marker><c>zip</c> function creates a + zip archive containing the files specified in <c>FileList</c>.</p> + <p>As synonyms, the functions <c>create/2</c> and <c>create/3</c> + are provided, to make it resemble the <c>erl_tar</c> module.</p> + <p>The file-list is a list of files, with paths relative to the + current directory, they will be stored with this path in the + archive. Files may also be specified with data in binaries, + to create an archive directly from data.</p> + <p>Files will be compressed using the DEFLATE compression, as + described in the Appnote.txt file. However, files will be + stored without compression if they already are compressed. + The <c>zip/2</c> and <c>zip/3</c> checks the file extension + to see whether the file should be stored without compression. + Files with the following extensions are not compressed: + <c>.Z</c>, <c>.zip</c>, <c>.zoo</c>, <c>.arc</c>, <c>.lzh</c>, + <c>.arj</c>.</p> + <p>It is possible to override the default behavior and + explicitly control what types of files that should be + compressed by using the <c>{compress, What}</c> and + <c>{uncompress, What}</c> options. It is possible to have + several <c>compress</c> and <c>uncompress</c> options. In + order to trigger compression of a file, its extension must + match with the + <c>compress</c> condition and must not match the + <c>uncompress</c> condition. For example if <c>compress</c> is + set to <c>["gif", "jpg"]</c> and <c>uncompress</c> is set to + <c>["jpg"]</c>, only files with <c>"gif"</c> as extension will + be compressed. No other files will be compressed.</p> + <p>The following options are available:</p> + <taglist> + <tag><c>cooked</c></tag> + <item> + <p>By default, the <c>open/2</c> function will open the + zip file in <c>raw</c> mode, which is faster but does not allow + a remote (erlang) file server to be used. Adding <c>cooked</c> + to the mode list will override the default and open the zip file + without the <c>raw</c> option. The same goes for the files + added.</p> + </item> + <tag><c>verbose</c></tag> + <item> + <p>Print an informational message about each file + being added.</p> + </item> + <tag><c>memory</c></tag> + <item> + <p>The output will not be to a file, but instead as a tuple + <c>{FileName, binary()}</c>. The binary will be a full zip + archive with header, and can be extracted with for instance + <c>unzip/2</c>.</p> + </item> + <tag><c>{comment, Comment}</c></tag> + <item> + <p>Add a comment to the zip-archive.</p> + </item> + <tag><c>{cwd, CWD}</c></tag> + <item> + <p>Use the given directory as current directory, it will be + prepended to file names when adding them, although it will not + be in the zip-archive. (Acting like a file:set_cwd/1, but + without changing the global cwd property.)</p> + </item> + <tag><c>{compress, What}</c></tag> + <item> + <p>Controls what types of files that will be + compressed. It is by default set to <c>all</c>. The + following values of <c>What</c> are allowed:</p> + <taglist> + <tag><c>all</c></tag> + <item><p> means that all files will be compressed (as long + as they pass the <c>uncompress</c> condition).</p></item> + <tag><c>[Extension]</c></tag> + <item><p>means that only files with exactly these extensions + will be compressed.</p></item> + <tag><c>{add,[Extension]}</c></tag> + <item><p>adds these extensions to the list of compress + extensions.</p></item> + <tag><c>{del,[Extension]}</c></tag> + <item><p>deletes these extensions from the list of compress + extensions.</p></item> + </taglist> + </item> + <tag><c>{uncompress, What}</c></tag> + <item> + <p>Controls what types of files that will be uncompressed. It is by + default set to <c>[".Z",".zip",".zoo",".arc",".lzh",".arj"]</c>. + The following values of <c>What</c> are allowed:</p> + <taglist> + <tag><c>all</c></tag> + <item><p> means that no files will be compressed.</p></item> + <tag><c>[Extension]</c></tag> + <item><p>means that files with these extensions will be + uncompressed.</p></item> + <tag><c>{add,[Extension]}</c></tag> + <item><p>adds these extensions to the list of uncompress + extensions.</p></item> + <tag><c>{del,[Extension]}</c></tag> + <item><p>deletes these extensions from the list of uncompress + extensions.</p></item> + </taglist> + </item> + </taglist> + </desc> + </func> + <func> + <name>unzip(Archive) -> RetValue</name> + <name>unzip(Archive, Options) -> RetValue</name> + <name>extract(Archive) -> RetValue</name> + <name>extract(Archive, Options) -> RetValue</name> + <fsummary>Extract files from a zip archive</fsummary> + <type> + <v>Archive = filename() | binary()</v> + <v>Options = [Option]</v> + <v>Option = {file_list, FileList} | keep_old_files | verbose | memory | {file_filter, FileFilter} | {cwd, CWD}</v> + <v>FileList = [filename()]</v> + <v>FileBinList = [{filename(),binary()}]</v> + <v>FileFilter = fun(ZipFile) -> true | false</v> + <v>CWD = string()</v> + <v>ZipFile = zip_file()</v> + <v>RetValue = {ok,FileList} | {ok,FileBinList} | {error, Reason} | {error, {Name, Reason}}</v> + <v>Reason = term()</v> + </type> + <desc> + <p>The <marker id="unzip_1"></marker> +<c>unzip/1</c> function extracts + all files from a zip archive. The + <marker id="unzip_2"></marker> +<c>unzip/2</c> function provides options + to extract some files, and more.</p> + <p>If the <c>Archive</c> argument is given as a binary, + the contents of the binary is assumed to be a zip archive, + otherwise it should be a filename.</p> + <p>The following options are available:</p> + <taglist> + <tag><c>{file_list, FileList}</c></tag> + <item> + <p>By default, all files will be extracted from the zip + archive. With the <c>{file_list,FileList}</c> option, + the <c>unzip/2</c> function will only extract the files + whose names are included in <c>FileList</c>. The full + paths, including the names of all sub directories within + the zip archive, must be specified.</p> + </item> + <tag><c>cooked</c></tag> + <item> + <p>By default, the <c>open/2</c> function will open the + zip file in <c>raw</c> mode, which is faster but does not allow + a remote (erlang) file server to be used. Adding <c>cooked</c> + to the mode list will override the default and open zip file + without the <c>raw</c> option. The same goes for the files + extracted.</p> + </item> + <tag><c>keep_old_files</c></tag> + <item> + <p>By default, all existing files with the same name as file in + the zip archive will be overwritten. With the <c>keep_old_files</c> + option, the <c>unzip/2</c> function will not overwrite any existing + files. Not that even with the <c>memory</c> option given, which + means that no files will be overwritten, files existing will be + excluded from the result.</p> + </item> + <tag><c>verbose</c></tag> + <item> + <p>Print an informational message as each file is being + extracted.</p> + </item> + <tag><c>memory</c></tag> + <item> + <p>Instead of extracting to the current directory, the + <c>memory</c> option will give the result as a list of tuples + <c>{Filename, Binary}</c>, where <c>Binary</c> is a binary + containing the extracted data of the file named <c>Filename</c> + in the zip archive.</p> + </item> + <tag><c>{cwd, CWD}</c></tag> + <item> + <p>Use the given directory as current directory, it will be + prepended to file names when extracting them from the + zip-archive. (Acting like a file:set_cwd/1, but without + changing the global cwd property.)</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>list_dir(Archive) -> RetValue</name> + <name>list_dir(Archive, Options)</name> + <name>table(Archive) -> RetValue</name> + <name>table(Archive, Options)</name> + <fsummary>Retrieve the name of all files in a zip archive</fsummary> + <type> + <v>Archive = filename() | binary()</v> + <v>RetValue = {ok, [Comment, Files]} | {error, Reason}</v> + <v>Comment = zip_comment()</v> + <v>Files = [zip_file()]</v> + <v>Options = [Option]</v> + <v>Option = cooked</v> + <v>Reason = term()</v> + </type> + <desc> + <p>The <marker id="list_dir_1"></marker> +<c>list_dir/1</c> function retrieves + the names of all files in the zip archive <c>Archive</c>. The + <marker id="list_dir_2"></marker> +<c>list_dir/2</c> function provides options.</p> + <p>As synonyms, the functions <c>table/2</c> and <c>table/3</c> + are provided, to make it resemble the <c>erl_tar</c> module.</p> + <p>The result value is the tuple <c>{ok, List}</c>, where <c>List</c> + contains the zip archive comment as the first element.</p> + <p>The following options are available:</p> + <taglist> + <tag><c>cooked</c></tag> + <item> + <p>By default, the <c>open/2</c> function will open the + zip file in <c>raw</c> mode, which is faster but does not allow + a remote (erlang) file server to be used. Adding <c>cooked</c> + to the mode list will override the default and open zip file + without the <c>raw</c> option.</p> + </item> + </taglist> + </desc> + </func> + <func> + <name>t(Archive)</name> + <fsummary>Print the name of each file in a zip archive</fsummary> + <type> + <v>Archive = filename() | binary() | ZipHandle</v> + <v>ZipHandle = pid()</v> + </type> + <desc> + <p>The <marker id="t_1"></marker> +<c>t/1</c> function prints the names + of all files in the zip archive <c>Archive</c> to the Erlang shell. + (Similar to "<c>tar t</c>".)</p> + </desc> + </func> + <func> + <name>tt(Archive)</name> + <fsummary>Print name and information for each file in a zip archive</fsummary> + <type> + <v>Archive = filename() | binary()</v> + </type> + <desc> + <p>The <marker id="tt_1"></marker> +<c>tt/1</c> function prints names and + information about all files in the zip archive <c>Archive</c> to + the Erlang shell. (Similar to "<c>tar tv</c>".)</p> + </desc> + </func> + <func> + <name>zip_open(Archive) -> {ok, ZipHandle} | {error, Reason}</name> + <name>zip_open(Archive, Options) -> {ok, ZipHandle} | {error, Reason}</name> + <fsummary>Open an archive and return a handle to it</fsummary> + <type> + <v>Archive = filename() | binary()</v> + <v>Options = [Option]</v> + <v>Options = cooked | memory | {cwd, CWD}</v> + <v>CWD = string()</v> + <v>ZipHandle = pid()</v> + </type> + <desc> + <p>The <marker id="zip_open"></marker> +<c>zip_open</c> function opens a + zip archive, and reads and saves its directory. This + means that subsequently reading files from the archive will be + faster than unzipping files one at a time with <c>unzip</c>.</p> + <p>The archive must be closed with <c>zip_close/1</c>.</p> + </desc> + </func> + <func> + <name>zip_list_dir(ZipHandle) -> Result | {error, Reason}</name> + <fsummary>Return a table of files in open zip archive</fsummary> + <type> + <v>Result = [ZipComment, ZipFile...]</v> + <v>ZipComment = #zip_comment{}</v> + <v>ZipFile = #zip_file{}</v> + <v>ZipHandle = pid()</v> + </type> + <desc> + <p>The <marker id="zip_list_dir"></marker> +<c>zip_list_dir/1</c> function + returns the file list of an open zip archive.</p> + </desc> + </func> + <func> + <name>zip_get(ZipHandle) -> {ok, [Result]} | {error, Reason}</name> + <name>zip_get(FileName, ZipHandle) -> {ok, Result} | {error, Reason}</name> + <fsummary>Extract files from an open archive</fsummary> + <type> + <v>FileName = filename()</v> + <v>ZipHandle = pid()</v> + <v>Result = filename() | {filename(), binary()}</v> + </type> + <desc> + <p>The <marker id="zip_get"></marker> +<c>zip_get</c> function extracts + one or all files from an open archive.</p> + <p>The files will be unzipped to memory or to file, depending on + the options given to the <c>zip_open</c> function when the + archive was opened.</p> + </desc> + </func> + <func> + <name>zip_close(ZipHandle) -> ok | {error, einval}</name> + <fsummary>Close an open archive</fsummary> + <type> + <v>ZipHandle = pid()</v> + </type> + <desc> + <p>The <marker id="zip_close"></marker> +<c>zip_close/1</c> function closes + a zip archive, previously opened with <c>zip_open</c>. All + resources are closed, and the handle should not be used after + closing.</p> + </desc> + </func> + </funcs> +</erlref> + |