First integration of the new GW_ design more centralized on connector, and does not require specific feature on GW_APPLICATION depending on the connector.
So this is really more flexible this way, and much easier to write application supporting CGI, FCGI, Nino and so on .. as demonstrated in hello_world This is a first version, more will come later, mainly migrating from Eiffel Web Reloaded to this Eiffel Web Framework project.
This commit is contained in:
35
library/text/encoder/encoder-safe.ecf
Normal file
35
library/text/encoder/encoder-safe.ecf
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="encoder" uuid="EE80E648-C64D-4802-8868-C57AAFEACC55" library_target="encoder">
|
||||
<target name="encoder">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
<assertions precondition="true"/>
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
|
||||
<cluster name="src" location="src\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/tests$</exclude>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
|
||||
<target name="tests" extends="encoder" >
|
||||
<root class="ANY" feature="default_create"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all">
|
||||
<assertions precondition="true"/>
|
||||
</option>
|
||||
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
|
||||
<tests name="tests" location="./tests"/>
|
||||
</target>
|
||||
|
||||
</system>
|
||||
35
library/text/encoder/encoder.ecf
Normal file
35
library/text/encoder/encoder.ecf
Normal file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="encoder" uuid="EE80E648-C64D-4802-8868-C57AAFEACC55" library_target="encoder">
|
||||
<target name="encoder">
|
||||
<root all_classes="true"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true">
|
||||
<assertions precondition="true"/>
|
||||
</option>
|
||||
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf"/>
|
||||
<cluster name="src" location="src\" recursive="true">
|
||||
<file_rule>
|
||||
<exclude>/tests$</exclude>
|
||||
</file_rule>
|
||||
</cluster>
|
||||
</target>
|
||||
|
||||
<target name="tests" extends="encoder" >
|
||||
<root class="ANY" feature="default_create"/>
|
||||
<file_rule>
|
||||
<exclude>/.git$</exclude>
|
||||
<exclude>/EIFGENs$</exclude>
|
||||
<exclude>/.svn$</exclude>
|
||||
</file_rule>
|
||||
<option warning="true" full_class_checking="true">
|
||||
<assertions precondition="true"/>
|
||||
</option>
|
||||
<library name="testing" location="$ISE_LIBRARY\library\testing\testing.ecf"/>
|
||||
<tests name="tests" location="./tests"/>
|
||||
</target>
|
||||
|
||||
</system>
|
||||
1
library/text/encoder/license.lic
Normal file
1
library/text/encoder/license.lic
Normal file
@@ -0,0 +1 @@
|
||||
reference:forum2
|
||||
218
library/text/encoder/src/base64.e
Normal file
218
library/text/encoder/src/base64.e
Normal file
@@ -0,0 +1,218 @@
|
||||
note
|
||||
description: "Summary description for {BASE64}."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
BASE64
|
||||
|
||||
inherit
|
||||
ENCODER [STRING_8, STRING_8]
|
||||
redefine
|
||||
valid_encoded_string
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: STRING = "base64"
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_error: BOOLEAN
|
||||
|
||||
valid_encoded_string (v: STRING): BOOLEAN
|
||||
do
|
||||
Result := Precursor (v) and then
|
||||
(v.is_empty or v.count >= 4)
|
||||
end
|
||||
|
||||
feature -- base64 encoder
|
||||
|
||||
encoded_string (s: STRING): STRING_8
|
||||
-- base64 encoded value of `s'.
|
||||
local
|
||||
i,n: INTEGER
|
||||
c: INTEGER
|
||||
f: SPECIAL [BOOLEAN]
|
||||
base64chars: STRING_8
|
||||
do
|
||||
has_error := False
|
||||
base64chars := character_map
|
||||
from
|
||||
n := s.count
|
||||
i := (8 * n) \\ 6
|
||||
if i > 0 then
|
||||
create f.make_filled (False, 8 * n + (6 - i))
|
||||
else
|
||||
create f.make_filled (False, 8 * n)
|
||||
end
|
||||
i := 0
|
||||
until
|
||||
i > n - 1
|
||||
loop
|
||||
c := s.item (i + 1).code
|
||||
f[8 * i + 0] := c.bit_test(7)
|
||||
f[8 * i + 1] := c.bit_test(6)
|
||||
f[8 * i + 2] := c.bit_test(5)
|
||||
f[8 * i + 3] := c.bit_test(4)
|
||||
f[8 * i + 4] := c.bit_test(3)
|
||||
f[8 * i + 5] := c.bit_test(2)
|
||||
f[8 * i + 6] := c.bit_test(1)
|
||||
f[8 * i + 7] := c.bit_test(0)
|
||||
i := i + 1
|
||||
end
|
||||
from
|
||||
i := 0
|
||||
n := f.count
|
||||
create Result.make (n // 6)
|
||||
until
|
||||
i > n - 1
|
||||
loop
|
||||
c := 0
|
||||
if f[i + 0] then c := c + 0x20 end
|
||||
if f[i + 1] then c := c + 0x10 end
|
||||
if f[i + 2] then c := c + 0x8 end
|
||||
if f[i + 3] then c := c + 0x4 end
|
||||
if f[i + 4] then c := c + 0x2 end
|
||||
if f[i + 5] then c := c + 0x1 end
|
||||
Result.extend (base64chars.item (c + 1))
|
||||
i := i + 6
|
||||
end
|
||||
|
||||
i := s.count \\ 3
|
||||
if i > 0 then
|
||||
from until i > 2 loop
|
||||
Result.extend ('=')
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Decoder
|
||||
|
||||
decoded_string (v: STRING): STRING
|
||||
-- base64 decoded value of `s'.
|
||||
local
|
||||
byte_count: INTEGER
|
||||
pos, n: INTEGER
|
||||
byte1, byte2, byte3, byte4, tmp1, tmp2: INTEGER
|
||||
done: BOOLEAN
|
||||
base64chars: STRING_8
|
||||
c: CHARACTER
|
||||
do
|
||||
has_error := False
|
||||
base64chars := character_map
|
||||
n := v.count
|
||||
create Result.make (n)
|
||||
|
||||
from
|
||||
pos := 0
|
||||
invariant
|
||||
n = v.count
|
||||
until
|
||||
(pos >= n) or done
|
||||
loop
|
||||
byte_count := 0
|
||||
|
||||
pos := next_encoded_character_position (v, pos)
|
||||
if pos <= n then
|
||||
byte1 := base64chars.index_of (v[pos], 1) - 1
|
||||
byte_count := byte_count + 1
|
||||
|
||||
pos := next_encoded_character_position (v, pos)
|
||||
if pos <= n then
|
||||
byte2 := base64chars.index_of (v[pos], 1) - 1
|
||||
byte_count := byte_count + 1
|
||||
|
||||
pos := next_encoded_character_position (v, pos)
|
||||
if pos <= n then
|
||||
c := v[pos]
|
||||
if c /= '=' then
|
||||
byte3 := base64chars.index_of (c, 1) - 1
|
||||
byte_count := byte_count + 1
|
||||
end
|
||||
|
||||
pos := next_encoded_character_position (v, pos)
|
||||
if pos <= n then
|
||||
c := v[pos]
|
||||
if c /= '=' then
|
||||
byte4 := base64chars.index_of (c, 1) - 1
|
||||
byte_count := byte_count + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- pos := pos + byte_count
|
||||
|
||||
done := byte_count < 4
|
||||
|
||||
if byte_count > 1 then
|
||||
tmp1 := byte1.bit_shift_left (2) & 0xff
|
||||
tmp2 := byte2.bit_shift_right (4) & 0x03
|
||||
Result.extend ((tmp1 | tmp2).to_character_8)
|
||||
if byte_count > 2 then
|
||||
tmp1 := byte2.bit_shift_left (4) & 0xff
|
||||
tmp2 := byte3.bit_shift_right (2) & 0x0f
|
||||
Result.extend ((tmp1 | tmp2).to_character_8)
|
||||
if byte_count > 3 then
|
||||
Result.extend(
|
||||
((byte4 | byte3.bit_shift_left(6))& 0xff).to_character_8)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
next_encoded_character_position (v: STRING; from_pos: INTEGER): INTEGER
|
||||
-- Next encoded character position from `v' starting after `from_pos' index.
|
||||
-- Result over `v.count' denodes no remaining decodable position
|
||||
--| Mainly to handle base64 encoded text on multiple line
|
||||
--| thus we just skip %N, %R and eventually all blanks
|
||||
require
|
||||
v_attached: v /= Void
|
||||
valid_from_pos: v.valid_index (from_pos + 1)
|
||||
local
|
||||
n: INTEGER
|
||||
l_map: like character_map
|
||||
do
|
||||
l_map := character_map
|
||||
from
|
||||
Result := from_pos + 1
|
||||
n := v.count
|
||||
until
|
||||
in_character_map (v[Result]) or Result > n
|
||||
loop
|
||||
Result := Result + 1
|
||||
end
|
||||
ensure
|
||||
result_after_from_pos: Result > from_pos
|
||||
end
|
||||
|
||||
in_character_map (c: CHARACTER): BOOLEAN
|
||||
-- Is a character map element?
|
||||
do
|
||||
inspect c
|
||||
when 'A' .. 'Z', 'a' .. 'z', '0'..'9', '+', '/', '=' then
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Constants
|
||||
|
||||
character_map: STRING = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
73
library/text/encoder/src/encoder.e
Normal file
73
library/text/encoder/src/encoder.e
Normal file
@@ -0,0 +1,73 @@
|
||||
note
|
||||
description: "Summary description for {ENCODER}."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
deferred class
|
||||
ENCODER [U -> STRING_GENERAL, E -> STRING_GENERAL] --| U:unencoded type, E:encoded type
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: STRING
|
||||
-- Encoding name.
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_error: BOOLEAN
|
||||
-- Error occurred
|
||||
deferred
|
||||
end
|
||||
|
||||
feature -- Assertion helpers
|
||||
|
||||
valid_unencoded_string (s: U): BOOLEAN
|
||||
-- Is `s' a valid unencoded string ?
|
||||
do
|
||||
Result := s /= Void
|
||||
end
|
||||
|
||||
valid_encoded_string (v: E): BOOLEAN
|
||||
-- Is `v' a valid encoded string ?
|
||||
do
|
||||
Result := v /= Void
|
||||
end
|
||||
|
||||
feature -- Encoder
|
||||
|
||||
encoded_string (s: U): E
|
||||
-- Encoded value of `s'.
|
||||
require
|
||||
valid_unencoded_string: valid_unencoded_string (s)
|
||||
deferred
|
||||
ensure
|
||||
unchanged: s ~ (old s)
|
||||
valid_encoded_string: valid_encoded_string (Result)
|
||||
end
|
||||
|
||||
feature -- Decoder
|
||||
|
||||
decoded_string (v: E): U
|
||||
-- Decoded value of `v'.
|
||||
require
|
||||
valid_encoded_string: valid_encoded_string (v)
|
||||
deferred
|
||||
ensure
|
||||
unchanged: v ~ (old v)
|
||||
valid_unencoded_string: valid_unencoded_string (Result)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
267
library/text/encoder/src/html_encoder.e
Normal file
267
library/text/encoder/src/html_encoder.e
Normal file
@@ -0,0 +1,267 @@
|
||||
note
|
||||
description: "[
|
||||
Summary description for {HTML_ENCODER}.
|
||||
|
||||
see: http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
|
||||
]"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
HTML_ENCODER
|
||||
|
||||
inherit
|
||||
ENCODER [STRING_32, STRING_8]
|
||||
|
||||
PLATFORM
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: STRING = "HTML-encoded"
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_error: BOOLEAN
|
||||
|
||||
feature -- Encoder
|
||||
|
||||
encoded_string (s: STRING_32): STRING_8
|
||||
-- HTML-encoded value of `s'.
|
||||
local
|
||||
i, n: INTEGER
|
||||
uc: CHARACTER_32
|
||||
c: CHARACTER_8
|
||||
do
|
||||
has_error := False
|
||||
create Result.make (s.count + s.count // 10)
|
||||
n := s.count
|
||||
from i := 1 until i > n loop
|
||||
uc := s.item (i)
|
||||
if uc.is_character_8 then
|
||||
c := uc.to_character_8
|
||||
inspect c
|
||||
when '%"' then Result.append_string (""")
|
||||
when '&' then Result.append_string ("&")
|
||||
when '%'' then Result.append_string ("'")
|
||||
when '<' then Result.append_string ("<")
|
||||
when '>' then Result.append_string (">")
|
||||
else
|
||||
Result.extend (c)
|
||||
end
|
||||
else
|
||||
Result.append ("&#")
|
||||
Result.append (uc.code.out)
|
||||
Result.extend (';')
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Decoder
|
||||
|
||||
decoded_string (v: STRING_8): STRING_32
|
||||
-- The HTML-encoded equivalent of the given string
|
||||
local
|
||||
i, n: INTEGER
|
||||
c: CHARACTER
|
||||
cl_i: CELL [INTEGER]
|
||||
do
|
||||
n := v.count
|
||||
create Result.make (n)
|
||||
create cl_i.put (0)
|
||||
from i := 1 until i > n loop
|
||||
c := v.item (i)
|
||||
if c = '&' then
|
||||
cl_i.replace (i)
|
||||
Result.append_string (next_entity (v, cl_i))
|
||||
i := cl_i.item
|
||||
else
|
||||
Result.append_character (c.to_character_32)
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: decoder
|
||||
|
||||
next_entity (v: STRING_8; cl_i: CELL [INTEGER]): STRING_32
|
||||
-- Return next entity value
|
||||
-- move index
|
||||
local
|
||||
i: INTEGER
|
||||
c: CHARACTER
|
||||
is_char: BOOLEAN
|
||||
is_hexa: BOOLEAN
|
||||
s: STRING_32
|
||||
do
|
||||
i := cl_i.item
|
||||
create s.make_empty
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
if c = '#' then
|
||||
is_char := True
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
if c = 'x' then
|
||||
is_hexa := True
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
end
|
||||
end
|
||||
if is_char then
|
||||
if is_hexa then
|
||||
from
|
||||
until
|
||||
not c.is_hexa_digit or c = ';'
|
||||
loop
|
||||
s.append_character (c)
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
end
|
||||
else
|
||||
from
|
||||
until
|
||||
not c.is_digit or c = ';'
|
||||
loop
|
||||
s.append_character (c)
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
end
|
||||
end
|
||||
else
|
||||
from
|
||||
until
|
||||
not valid_entity_character (c) or c = ';'
|
||||
loop
|
||||
s.append_character (c)
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
end
|
||||
end
|
||||
if c = ';' then
|
||||
if is_char then
|
||||
if is_hexa then
|
||||
-- not yet implemented
|
||||
s.prepend_character ('x')
|
||||
s.prepend_character ('#')
|
||||
s.prepend_character ('&')
|
||||
s.append_character (';')
|
||||
Result := s
|
||||
elseif s.is_integer then
|
||||
create Result.make (1)
|
||||
Result.append_code (s.to_natural_32)
|
||||
else
|
||||
s.prepend_character ('&')
|
||||
s.append_character (';')
|
||||
Result := s
|
||||
end
|
||||
else
|
||||
resolve_entity (s)
|
||||
Result := s
|
||||
end
|
||||
cl_i.replace (i + 1)
|
||||
else
|
||||
cl_i.replace (cl_i.item + 1)
|
||||
s.prepend_character ('&')
|
||||
has_error := True -- ("Invalid entity syntax " + s)
|
||||
Result := s
|
||||
end
|
||||
end
|
||||
|
||||
resolve_entity (s: STRING_32)
|
||||
-- Resolve `s' as an entity
|
||||
--| Hardcoding the xml entities " & ' < and >
|
||||
require
|
||||
s_attached: s /= Void
|
||||
local
|
||||
l_resolved: BOOLEAN
|
||||
do
|
||||
inspect s[1].as_lower
|
||||
when 'a' then
|
||||
if
|
||||
s.count = 3 and then
|
||||
s[2].as_lower = 'm' and then
|
||||
s[3].as_lower = 'p'
|
||||
then -- &
|
||||
l_resolved := True
|
||||
s.wipe_out
|
||||
s.append_character ('&')
|
||||
elseif -- '
|
||||
s.count = 4 and then
|
||||
s[2].as_lower = 'p' and then
|
||||
s[3].as_lower = 'o' and then
|
||||
s[4].as_lower = 's'
|
||||
then
|
||||
l_resolved := True
|
||||
s.wipe_out
|
||||
s.append_character ('%'')
|
||||
end
|
||||
when 'q' then
|
||||
if
|
||||
s.count = 4 and then
|
||||
s[2].as_lower = 'u' and then
|
||||
s[3].as_lower = 'o' and then
|
||||
s[4].as_lower = 't'
|
||||
then -- "
|
||||
l_resolved := True
|
||||
s.wipe_out
|
||||
s.append_character ('%"')
|
||||
end
|
||||
when 'l' then
|
||||
if
|
||||
s.count = 2 and then
|
||||
s[2].as_lower = 't'
|
||||
then -- "
|
||||
l_resolved := True
|
||||
s.wipe_out
|
||||
s.append_character ('<')
|
||||
end
|
||||
when 'g' then
|
||||
if
|
||||
s.count = 2 and then
|
||||
s[2].as_lower = 't'
|
||||
then -- "
|
||||
l_resolved := True
|
||||
s.wipe_out
|
||||
s.append_character ('>')
|
||||
end
|
||||
else
|
||||
end
|
||||
if not l_resolved then
|
||||
s.prepend_character ('&')
|
||||
s.append_character (';')
|
||||
end
|
||||
end
|
||||
|
||||
valid_entity_character (c: CHARACTER): BOOLEAN
|
||||
-- Is `c' a valid character in html entity value?
|
||||
--| such as &
|
||||
do
|
||||
inspect
|
||||
c
|
||||
when 'a'..'z' then
|
||||
Result := True
|
||||
when 'A'..'Z' then
|
||||
Result := True
|
||||
when '0'..'9' then
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
321
library/text/encoder/src/url_encoder.e
Normal file
321
library/text/encoder/src/url_encoder.e
Normal file
@@ -0,0 +1,321 @@
|
||||
note
|
||||
description: "Summary description for {URL_ENCODER}."
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
URL_ENCODER
|
||||
|
||||
inherit
|
||||
ENCODER [STRING_32, STRING_8]
|
||||
|
||||
PLATFORM
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: STRING = "URL-encoded"
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_error: BOOLEAN
|
||||
|
||||
feature -- Encoder
|
||||
|
||||
encoded_string (s: STRING_32): STRING_8
|
||||
-- URL-encoded value of `s'.
|
||||
local
|
||||
i, n: INTEGER
|
||||
uc: CHARACTER_32
|
||||
c: CHARACTER_8
|
||||
do
|
||||
has_error := False
|
||||
create Result.make (s.count + s.count // 10)
|
||||
n := s.count
|
||||
from i := 1 until i > n loop
|
||||
uc := s.item (i)
|
||||
if uc.is_character_8 then
|
||||
c := uc.to_character_8
|
||||
inspect c
|
||||
when
|
||||
'A' .. 'Z',
|
||||
'a' .. 'z', '0' .. '9',
|
||||
'.', '-', '~', '_'
|
||||
then
|
||||
Result.extend (c)
|
||||
when ' ' then
|
||||
Result.extend ('+')
|
||||
else
|
||||
Result.append (url_encoded_char (uc))
|
||||
end
|
||||
else
|
||||
Result.append (url_encoded_char (uc))
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- encoder character
|
||||
|
||||
url_encoded_char (uc: CHARACTER_32): STRING_8
|
||||
do
|
||||
create Result.make (3)
|
||||
if uc.is_character_8 then
|
||||
Result.extend ('%%')
|
||||
Result.append (uc.code.to_hex_string)
|
||||
from
|
||||
until
|
||||
Result.count < 2 or else Result[2] /= '0'
|
||||
loop
|
||||
Result.remove (2)
|
||||
end
|
||||
else
|
||||
has_error := True --| Non-ascii escape not currently supported
|
||||
end
|
||||
ensure
|
||||
exists: Result /= Void
|
||||
end
|
||||
|
||||
feature -- Decoder
|
||||
|
||||
decoded_string (v: STRING_8): STRING_32
|
||||
-- The URL-encoded equivalent of the given string
|
||||
local
|
||||
i, n: INTEGER
|
||||
c: CHARACTER
|
||||
pr: CELL [INTEGER]
|
||||
do
|
||||
n := v.count
|
||||
create Result.make (n)
|
||||
from i := 1
|
||||
until i > n
|
||||
loop
|
||||
c := v.item (i)
|
||||
inspect c
|
||||
when '+' then
|
||||
Result.append_character ({CHARACTER_32}' ')
|
||||
when '%%' then
|
||||
-- An escaped character ?
|
||||
if i = n then
|
||||
Result.append_character (c.to_character_32)
|
||||
else
|
||||
create pr.put (i)
|
||||
Result.append (url_decoded_char (v, pr))
|
||||
i := pr.item
|
||||
end
|
||||
else
|
||||
Result.append_character (c.to_character_32)
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- decoded character
|
||||
|
||||
url_decoded_char (buf: STRING_8; posr: CELL [INTEGER]): STRING_32
|
||||
-- Character(s) resulting from decoding the URL-encoded string
|
||||
require
|
||||
stream_exists: buf /= Void
|
||||
posr_exists: posr /= Void
|
||||
valid_start: posr.item <= buf.count
|
||||
local
|
||||
c: CHARACTER
|
||||
i, n, nb: INTEGER
|
||||
not_a_digit: BOOLEAN
|
||||
ascii_pos, ival: INTEGER
|
||||
pos: INTEGER
|
||||
do
|
||||
--| pos is index in stream of escape character ('%')
|
||||
pos := posr.item
|
||||
create Result.make (4)
|
||||
if buf.item (pos + 1) = 'u' then
|
||||
-- An escaped Unicode (ucs2) value, from ECMA scripts
|
||||
-- Has the form: %u<n> where <n> is the UCS value
|
||||
-- of the character (two byte integer, one to 4 chars
|
||||
-- after escape sequence).
|
||||
-- UTF-8 result can be 1 to 4 characters
|
||||
n := buf.count
|
||||
from i := pos + 2
|
||||
until (i > n) or not_a_digit
|
||||
loop
|
||||
c := buf.item (i)
|
||||
if c.is_hexa_digit then
|
||||
ival := ival * 16
|
||||
if c.is_digit then
|
||||
ival := ival + (c |-| '0')
|
||||
else
|
||||
ival := ival + (c.upper |-| 'A') + 10
|
||||
end
|
||||
i := i + 1
|
||||
else
|
||||
not_a_digit := True
|
||||
end
|
||||
end
|
||||
posr.replace (i)
|
||||
-- ival is now UCS2 value; needs conversion to UTF8
|
||||
Result.append_code (ival.as_natural_32)
|
||||
nb := utf8_bytes_in_sequence (buf, pos)
|
||||
else
|
||||
-- ASCII char?
|
||||
ascii_pos := hex_to_integer_32 (buf.substring (pos+1, pos+2))
|
||||
if ascii_pos >= 0x80 and ascii_pos <= 0xff then
|
||||
-- Might be improperly escaped
|
||||
Result.append_code (ascii_pos.as_natural_32)
|
||||
posr.replace (pos + 2)
|
||||
else
|
||||
Result.append_code (ascii_pos.as_natural_32)
|
||||
posr.replace (pos + 2)
|
||||
end
|
||||
end
|
||||
ensure
|
||||
exists: Result /= Void
|
||||
end
|
||||
|
||||
feature {NONE} -- UTF8
|
||||
|
||||
utf8_bytes_in_sequence (s: STRING_8; spos: INTEGER): INTEGER
|
||||
-- If the given character is a legal first byte element in a
|
||||
-- utf8 byte sequence (aka character), then return the number
|
||||
-- of bytes in that sequence
|
||||
-- Result of zero means it's not a utf8 first byte
|
||||
require
|
||||
exists: s /= Void
|
||||
long_enough: s.count >= spos
|
||||
do
|
||||
Result := bytes_in_utf8_char (s.item (spos))
|
||||
end
|
||||
|
||||
bytes_in_utf8_char (v: CHARACTER_8): INTEGER
|
||||
-- If the given byte a legal first byte element in a utf8 sequence,
|
||||
-- then the number of bytes in that character
|
||||
-- Zero denotes an error, i.e. not a legal UTF8 char
|
||||
--
|
||||
-- The first byte of a UTF8 encodes the length
|
||||
local
|
||||
c: NATURAL_8
|
||||
do
|
||||
c := v.code.to_natural_8
|
||||
Result := 1 -- 7 bit ASCII
|
||||
if (c & 0x80) /= 0 then
|
||||
-- Hi bit means not ASCII
|
||||
Result := 0
|
||||
if (c & 0xe0) = 0xc0 then
|
||||
-- If we see a first byte as b110xxxxx
|
||||
-- then we expect a two-byte character
|
||||
Result := 2
|
||||
elseif (c & 0xf0) = 0xe0 then
|
||||
-- If we see a first byte as b1110xxxx
|
||||
-- then we expect a three-byte character
|
||||
Result := 3
|
||||
elseif (c & 0xf8) = 0xf0 then
|
||||
-- If we see a first byte as b11110xxx
|
||||
-- then we expect a four-byte character
|
||||
Result := 4
|
||||
elseif (c & 0xfc) = 0xf8 then
|
||||
-- If we see a first byte as b111110xx
|
||||
-- then we expect a five-byte character
|
||||
Result := 5
|
||||
elseif (c & 0xfe) = 0xfc then
|
||||
-- If we see a first byte as b1111110x
|
||||
-- then we expect a six-byte character
|
||||
Result := 6
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Hexadecimal and strings
|
||||
|
||||
hex_to_integer_32 (s: STRING): INTEGER_32
|
||||
-- Hexadecimal string `s' converted to INTEGER_32 value
|
||||
require
|
||||
s_not_void: s /= Void
|
||||
local
|
||||
i, nb: INTEGER;
|
||||
char: CHARACTER
|
||||
do
|
||||
nb := s.count
|
||||
|
||||
if nb >= 2 and then s.item (2) = 'x' then
|
||||
i := 3
|
||||
else
|
||||
i := 1
|
||||
end
|
||||
|
||||
from
|
||||
until
|
||||
i > nb
|
||||
loop
|
||||
Result := Result * 16
|
||||
char := s.item (i)
|
||||
if char >= '0' and then char <= '9' then
|
||||
Result := Result + (char |-| '0')
|
||||
else
|
||||
Result := Result + (char.lower |-| 'a' + 10)
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
hex_to_integer_64 (s: STRING): INTEGER_64
|
||||
-- Hexadecimal string `s' converted to INTEGER_64 value
|
||||
require
|
||||
s_not_void: s /= Void
|
||||
local
|
||||
i, nb: INTEGER;
|
||||
char: CHARACTER
|
||||
do
|
||||
nb := s.count
|
||||
|
||||
if nb >= 2 and then s.item (2) = 'x' then
|
||||
i := 3
|
||||
else
|
||||
i := 1
|
||||
end
|
||||
|
||||
from
|
||||
until
|
||||
i > nb
|
||||
loop
|
||||
Result := Result * 16
|
||||
char := s.item (i)
|
||||
if char >= '0' and then char <= '9' then
|
||||
Result := Result + (char |-| '0')
|
||||
else
|
||||
Result := Result + (char.lower |-| 'a' + 10)
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
hex_to_pointer (s: STRING): POINTER
|
||||
-- Hexadecimal string `s' converted to POINTER value
|
||||
require
|
||||
s_not_void: s /= Void
|
||||
local
|
||||
val_32: INTEGER_32
|
||||
val_64: INTEGER_64
|
||||
do
|
||||
if Pointer_bytes = Integer_64_bytes then
|
||||
val_64 := hex_to_integer_64 (s)
|
||||
($Result).memory_copy ($val_64, Pointer_bytes)
|
||||
else
|
||||
val_32 := hex_to_integer_32 (s)
|
||||
($Result).memory_copy ($val_32, Pointer_bytes)
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
267
library/text/encoder/src/xml_encoder.e
Normal file
267
library/text/encoder/src/xml_encoder.e
Normal file
@@ -0,0 +1,267 @@
|
||||
note
|
||||
description: "[
|
||||
Summary description for {XML_ENCODER}.
|
||||
|
||||
see: http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references
|
||||
]"
|
||||
legal: "See notice at end of class."
|
||||
status: "See notice at end of class."
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
|
||||
class
|
||||
XML_ENCODER
|
||||
|
||||
inherit
|
||||
ENCODER [STRING_32, STRING_8]
|
||||
|
||||
PLATFORM
|
||||
export
|
||||
{NONE} all
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
name: STRING = "XML-encoded"
|
||||
|
||||
feature -- Status report
|
||||
|
||||
has_error: BOOLEAN
|
||||
|
||||
feature -- Encoder
|
||||
|
||||
encoded_string (s: STRING_32): STRING_8
|
||||
-- XML-encoded value of `s'.
|
||||
local
|
||||
i, n: INTEGER
|
||||
uc: CHARACTER_32
|
||||
c: CHARACTER_8
|
||||
do
|
||||
has_error := False
|
||||
create Result.make (s.count + s.count // 10)
|
||||
n := s.count
|
||||
from i := 1 until i > n loop
|
||||
uc := s.item (i)
|
||||
if uc.is_character_8 then
|
||||
c := uc.to_character_8
|
||||
inspect c
|
||||
when '%"' then Result.append_string (""")
|
||||
when '&' then Result.append_string ("&")
|
||||
when '%'' then Result.append_string ("'")
|
||||
when '<' then Result.append_string ("<")
|
||||
when '>' then Result.append_string (">")
|
||||
else
|
||||
Result.extend (c)
|
||||
end
|
||||
else
|
||||
Result.append ("&#")
|
||||
Result.append (uc.code.out)
|
||||
Result.extend (';')
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
|
||||
feature -- Decoder
|
||||
|
||||
decoded_string (v: STRING_8): STRING_32
|
||||
-- The XML-encoded equivalent of the given string
|
||||
local
|
||||
i, n: INTEGER
|
||||
c: CHARACTER
|
||||
cl_i: CELL [INTEGER]
|
||||
do
|
||||
n := v.count
|
||||
create Result.make (n)
|
||||
create cl_i.put (0)
|
||||
from i := 1 until i > n loop
|
||||
c := v.item (i)
|
||||
if c = '&' then
|
||||
cl_i.replace (i)
|
||||
Result.append_string (next_entity (v, cl_i))
|
||||
i := cl_i.item
|
||||
else
|
||||
Result.append_character (c.to_character_32)
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation: decoder
|
||||
|
||||
next_entity (v: STRING_8; cl_i: CELL [INTEGER]): STRING_32
|
||||
-- Return next entity value
|
||||
-- move index
|
||||
local
|
||||
i: INTEGER
|
||||
c: CHARACTER
|
||||
is_char: BOOLEAN
|
||||
is_hexa: BOOLEAN
|
||||
s: STRING_32
|
||||
do
|
||||
i := cl_i.item
|
||||
create s.make_empty
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
if c = '#' then
|
||||
is_char := True
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
if c = 'x' then
|
||||
is_hexa := True
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
end
|
||||
end
|
||||
if is_char then
|
||||
if is_hexa then
|
||||
from
|
||||
until
|
||||
not c.is_hexa_digit or c = ';'
|
||||
loop
|
||||
s.append_character (c)
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
end
|
||||
else
|
||||
from
|
||||
until
|
||||
not c.is_digit or c = ';'
|
||||
loop
|
||||
s.append_character (c)
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
end
|
||||
end
|
||||
else
|
||||
from
|
||||
until
|
||||
not valid_entity_character (c) or c = ';'
|
||||
loop
|
||||
s.append_character (c)
|
||||
i := i + 1
|
||||
c := v[i]
|
||||
end
|
||||
end
|
||||
if c = ';' then
|
||||
if is_char then
|
||||
if is_hexa then
|
||||
-- not yet implemented
|
||||
s.prepend_character ('x')
|
||||
s.prepend_character ('#')
|
||||
s.prepend_character ('&')
|
||||
s.append_character (';')
|
||||
Result := s
|
||||
elseif s.is_integer then
|
||||
create Result.make (1)
|
||||
Result.append_code (s.to_natural_32)
|
||||
else
|
||||
s.prepend_character ('&')
|
||||
s.append_character (';')
|
||||
Result := s
|
||||
end
|
||||
else
|
||||
resolve_entity (s)
|
||||
Result := s
|
||||
end
|
||||
cl_i.replace (i + 1)
|
||||
else
|
||||
cl_i.replace (cl_i.item + 1)
|
||||
s.prepend_character ('&')
|
||||
has_error := True -- ("Invalid entity syntax " + s)
|
||||
Result := s
|
||||
end
|
||||
end
|
||||
|
||||
resolve_entity (s: STRING_32)
|
||||
-- Resolve `s' as an entity
|
||||
--| Hardcoding the xml entities " & ' < and >
|
||||
require
|
||||
s_attached: s /= Void
|
||||
local
|
||||
l_resolved: BOOLEAN
|
||||
do
|
||||
inspect s[1].as_lower
|
||||
when 'a' then
|
||||
if
|
||||
s.count = 3 and then
|
||||
s[2].as_lower = 'm' and then
|
||||
s[3].as_lower = 'p'
|
||||
then -- &
|
||||
l_resolved := True
|
||||
s.wipe_out
|
||||
s.append_character ('&')
|
||||
elseif -- '
|
||||
s.count = 4 and then
|
||||
s[2].as_lower = 'p' and then
|
||||
s[3].as_lower = 'o' and then
|
||||
s[4].as_lower = 's'
|
||||
then
|
||||
l_resolved := True
|
||||
s.wipe_out
|
||||
s.append_character ('%'')
|
||||
end
|
||||
when 'q' then
|
||||
if
|
||||
s.count = 4 and then
|
||||
s[2].as_lower = 'u' and then
|
||||
s[3].as_lower = 'o' and then
|
||||
s[4].as_lower = 't'
|
||||
then -- "
|
||||
l_resolved := True
|
||||
s.wipe_out
|
||||
s.append_character ('%"')
|
||||
end
|
||||
when 'l' then
|
||||
if
|
||||
s.count = 2 and then
|
||||
s[2].as_lower = 't'
|
||||
then -- "
|
||||
l_resolved := True
|
||||
s.wipe_out
|
||||
s.append_character ('<')
|
||||
end
|
||||
when 'g' then
|
||||
if
|
||||
s.count = 2 and then
|
||||
s[2].as_lower = 't'
|
||||
then -- "
|
||||
l_resolved := True
|
||||
s.wipe_out
|
||||
s.append_character ('>')
|
||||
end
|
||||
else
|
||||
end
|
||||
if not l_resolved then
|
||||
s.prepend_character ('&')
|
||||
s.append_character (';')
|
||||
end
|
||||
end
|
||||
|
||||
valid_entity_character (c: CHARACTER): BOOLEAN
|
||||
-- Is `c' a valid character in html entity value?
|
||||
--| such as &
|
||||
do
|
||||
inspect
|
||||
c
|
||||
when 'a'..'z' then
|
||||
Result := True
|
||||
when 'A'..'Z' then
|
||||
Result := True
|
||||
when '0'..'9' then
|
||||
Result := True
|
||||
else
|
||||
end
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
49
library/text/encoder/tests/test_base64.e
Normal file
49
library/text/encoder/tests/test_base64.e
Normal file
@@ -0,0 +1,49 @@
|
||||
note
|
||||
description: "[
|
||||
Eiffel tests that can be executed by testing tool.
|
||||
]"
|
||||
author: "EiffelStudio test wizard"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
testing: "type/manual"
|
||||
|
||||
class
|
||||
TEST_BASE64
|
||||
|
||||
inherit
|
||||
EQA_TEST_SET
|
||||
|
||||
feature -- Test routines
|
||||
|
||||
test_base64_encoder
|
||||
note
|
||||
testing: "base64"
|
||||
do
|
||||
test_base64_encoding ("Il <20>tait une fois !")
|
||||
end
|
||||
|
||||
test_base64_encoding (s: STRING_8)
|
||||
local
|
||||
u: STRING_8
|
||||
e: STRING_8
|
||||
b: BASE64
|
||||
do
|
||||
create b
|
||||
e := b.encoded_string (s)
|
||||
u := b.decoded_string (e)
|
||||
assert ("decoded encoded string is same", u ~ s)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
|
||||
|
||||
49
library/text/encoder/tests/test_url_encoder.e
Normal file
49
library/text/encoder/tests/test_url_encoder.e
Normal file
@@ -0,0 +1,49 @@
|
||||
note
|
||||
description: "[
|
||||
Eiffel tests that can be executed by testing tool.
|
||||
]"
|
||||
author: "EiffelStudio test wizard"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
testing: "type/manual"
|
||||
|
||||
class
|
||||
TEST_URL_ENCODER
|
||||
|
||||
inherit
|
||||
EQA_TEST_SET
|
||||
|
||||
feature -- Test routines
|
||||
|
||||
test_url_encoded_encoder
|
||||
note
|
||||
testing: "url-encoded"
|
||||
do
|
||||
test_url_encoded_encoding ("http://domain.tld/foo/bar/script.php?test='toto'&foo=bar&title=il <20>tait une fois")
|
||||
end
|
||||
|
||||
test_url_encoded_encoding (s: STRING_32)
|
||||
local
|
||||
u: STRING_32
|
||||
e: STRING_8
|
||||
b: URL_ENCODER
|
||||
do
|
||||
create b
|
||||
e := b.encoded_string (s)
|
||||
u := b.decoded_string (e)
|
||||
assert ("decoded encoded string is same", u ~ s)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
|
||||
|
||||
47
library/text/encoder/tests/text_xml_encoder.e
Normal file
47
library/text/encoder/tests/text_xml_encoder.e
Normal file
@@ -0,0 +1,47 @@
|
||||
note
|
||||
description: "[
|
||||
Eiffel tests that can be executed by testing tool.
|
||||
]"
|
||||
author: "EiffelStudio test wizard"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
testing: "type/manual"
|
||||
|
||||
class
|
||||
TEST_XML_ENCODER
|
||||
|
||||
inherit
|
||||
EQA_TEST_SET
|
||||
|
||||
feature -- Test routines
|
||||
|
||||
test_xml_encoded_encoder
|
||||
note
|
||||
testing: "xml-encoded"
|
||||
do
|
||||
test_xml_encoded_encoding ({STRING_32}"il était une fois Ni & Hao (你好)")
|
||||
end
|
||||
|
||||
test_xml_encoded_encoding (s: STRING_32)
|
||||
local
|
||||
u: STRING_32
|
||||
e: STRING_8
|
||||
b: XML_ENCODER
|
||||
do
|
||||
create b
|
||||
e := b.encoded_string (s)
|
||||
u := b.decoded_string (e)
|
||||
assert ("decoded encoded string is same", u ~ s)
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2011, Eiffel Software and others"
|
||||
license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
Website http://www.eiffel.com
|
||||
Customer support http://support.eiffel.com
|
||||
]"
|
||||
end
|
||||
Reference in New Issue
Block a user