The ECS standard library defines modules supporting application development
with the ECS Oberon compiler, including:
- Modules for basic types : Char, Integer, Cardinal, Real, ArrayOfChar, ArrayOfByte & ArrayOfSet .
- Modules for string handling : String & StringPattern.
- Module for date and time support : DateTime.
- Module for container and alogrithms : ADTStream, ADTDictionary, ADTList, ADTSet, ADTPair, ADTRingBuffer, ADTTree & ADTVector.
- Module for cross platform basic OS support : OS, OSDir, OSFile, OSPath & OSStream.
- Module for testing & benchmark : O2Testing & O2Timing.
- Modules for data handling: DataLZ4 & DataConfig .
- Module for coroutines : Coroutine.
- Module for memory allocation on embedded platforms : SysMem.
The Const module defines constants reused throughout the library.
The stream concept is used throughout the modules to support formatting, reading and writing of data.
The module Type defines the basic stream type interface.
OS support is covered for the Windows and Linux platforms.
In addition for embedded platform basic support is added for the ARMv7M platform using
the semihost interface to the host computer.
The library is tested with about 750 unit tests.
These tests also can be inspected for basic usage where the documentation is not clear.
The ECS Oberon compiler is implemented according to the original Oberon-2 report with modernizing extensions.
Build instructions here are for a current ArchLinux version, but should be possible to adapt to other Linux distributions.
Windows MSYS2 also can follow these instructions and is known to work well, but is much slower than on Linux.
Alternative on the Windows platform is just to download the official installer.
# Build and install patched version of ECS
pacman -S base-devel gcc wget # Windows : run from MSYS2 shell
wget https://software.openbrace.org/attachments/download/418/ecs-2026.08.10.tar.gz
wget https://software.openbrace.org/attachments/download/420/install.patch
wget https://software.openbrace.org/attachments/download/421/msys.patch
tar -xavf ecs-2026.08.10.tar.gz
cd ecs
patch -p0 < ../install.patch
patch -p0 < ../msys.patch
make all # adjust -j argument to your CPU core count for faster compilation
make prefix=~/.local install
make clean
# add to PATH variable (adapt to your shell and setup)
echo 'export PATH=~/.local/bin/:~/.local/lib/ecs/tools/:$PATH' >> ~/.bashrc
echo 'export ECSBASE=~/.local/lib/ecs/' >> ~/.bashrc
cd ..
# Build and install ECSStdLib
git clone https://github.com/tenko/ECSStdLib.git
cd ECSStdLib
# Build native library
make
make PREFIX=~/.local install # install to ~/.local/lib
make TestMain # run library tests (use TestMain.exe on Windows)This example showcase of many library features by implementing a top 10 word counter utility.
Test.mod:
MODULE test;
IN Std IMPORT ArrayOfChar, String, StringPattern, OS, OSStream, ADTStream;
IN Std IMPORT PairStrInt := ADTPair(String.STRING, LENGTH);
IN Std IMPORT TreePair := ADTTree(PairStrInt.Pair, PairStrInt.Compare);
IN Std IMPORT DictStrInt := ADTDictionary(String.STRING, LENGTH, String.Hash, String.Equal);
PROCEDURE PairCompare(fl-, fr- : String.STRING; sl-, sr- : LENGTH): INTEGER;
BEGIN
IF (sl = sr) OR (sl < sr) THEN RETURN -1 END; (* If we return 0, pairs would be overwritten *)
RETURN 1;
END PairCompare;
PROCEDURE ProcessFile(VAR fh : ADTStream.Stream);
VAR
dict : DictStrInt.Dictionary;
dit : DictStrInt.Iterator;
tree : TreePair.Tree;
tit : TreePair.Iterator;
pair : PairStrInt.Pair;
pat : StringPattern.Pattern;
s, line, word: String.STRING;
idx, pos, len, cnt : LENGTH;
BEGIN
PairStrInt.compare := PairCompare;
dict.Init(256);
dict.duplicateKey := String.Duplicate; (* Dictionary insert copies of strings *)
dict.disposeKey := String.Dispose; (* Dictionary disposes of strings *)
WHILE fh.ReadLine(line) DO
idx := 0;
WHILE pat.Find("%w+", line^, idx) # -1 DO
IGNORE(pat.Capture(0, pos, len));
String.Extract(word, line^, pos, len);
ArrayOfChar.LowerCase(word^);
IF ~dict.Get(word, cnt) THEN cnt := 0 END;
dict.Set(word, cnt + 1);
idx := pos + len + 1;
END;
END;
tree.Init();
dict.First(dit);
WHILE dit.NextItem(s, cnt) DO
pair.first := s;
pair.second := cnt;
tree.Insert(pair);
END;
tree.Last(tit);
cnt := 0;
WHILE tit.Next(pair) & (cnt < 10) DO
OSStream.StdOut.FormatInteger(pair.second, 3, {});
OSStream.StdOut.WriteString(" : ");
OSStream.StdOut.WriteString(pair.first^);
OSStream.StdOut.WriteNL;
INC(cnt);
END;
String.Dispose(line);
String.Dispose(word);
dict.Dispose();
tree.Dispose();
END ProcessFile;
PROCEDURE Run;
VAR
fh : OSStream.File;
s : String.STRING;
BEGIN
IF OS.Args() = 1 THEN
ProcessFile(OSStream.StdIn);
ELSIF OS.Args() = 2 THEN
OS.Arg(s, 1);
IF ~fh.Open(s^, OSStream.AccessRead) THEN
OSStream.StdErr.WriteString("Failed to open file"); OSStream.StdErr.WriteNL;
String.Dispose(s);
OS.Exit(1);
END;
ProcessFile(fh);
String.Dispose(s);
fh.Close();
ELSE
OSStream.StdErr.WriteString("Usage : test [filename]"); OSStream.StdErr.WriteNL;
OS.Exit(1);
END;
END Run;
BEGIN
Run;
END test.Running (Windows)
ecsd -r std.lib -r win64api.obf Test.mod # Remove -r win64api.obf on other platforms
./test.exe README.md
36 : https
34 : std
32 : github
32 : ecsstdlib
32 : tenko
31 : mod
30 : html
30 : src
29 : io
24 : string
Complete API Documentation: Link