Starting from XDS v2.0 the general purpose modules used in XDS compilers and utilities, which are portable between all versions of XDS on all platforms, are included in the utility library. If you use the ISO library only, your program may be portable to any ISO compliant Modula-2 compiler. However, there are some essential features which are omitted in the ISO library. The utility library covers some of those omissions.
Note: Some library modules are written in Oberon-2, others in Modula-2. In general, any library can be used from both languages. However, do not forget that Oberon modules use implicit memory deallocation scheme and require garbage collection. Refer to the Multilangauge programming Chapter of the XDS User’s Guide.
The following modules are provided in the utility library (implementation language is pointed out in parentheses):
FileName | (M2) | Creating and parsing file names |
FileSys | (M2) | Common file operations |
FormOut | (M2) | Generic module for formatting output |
FormStr | (M2) | Formatting output to strings |
Printf | (M2) | C style formatting output precedures |
ProgEnv | (M2) | Access to program environment |
TimeConv | (M2) | Operations on time and date values |
DStrings | (O2) | Dynamic strings |
FilePath | (O2) | File search operations |
RegComp | (O2) | Regular expressions |
The module provides operations for parsing and constructing file names. A file name consists of three parts: the directory, name and extension.
All the procedures that construct a string value (Get, GetDir, GetName, GetExt, Convert, Create), have the common behaviour: if the length of a constructed string value exceeds capacity of a variable parameter, a truncated value is assigned. If the length of a constructed string value is less than the capacity of a variable parameter, a string terminator is appended.
TYPE Format = RECORD ok: BOOLEAN; (* directory position and length: *) dirPos, dirLen : CARDINAL; (* name position and length: *) namePos,nameLen: CARDINAL; (* extension position and length: *) extPos, extLen : CARDINAL; END;
Module FileName
PROCEDURE GetFormat(str: ARRAY OF CHAR; VAR f: Format);
Module FileName
The GetFormat procedure writes the position and length of file name parts to a Format type record passed in f. If f.ok = FALSE, vaues of all other fields are undefined.
PROCEDURE GetDir (fname: ARRAY OF CHAR; VAR dir: ARRAY OF CHAR); PROCEDURE GetName(fname: ARRAY OF CHAR; VAR name: ARRAY OF CHAR); PROCEDURE GetExt (fname: ARRAY OF CHAR; VAR ext: ARRAY OF CHAR); PROCEDURE Get(fname: ARRAY OF CHAR; VAR dir,name,ext: ARRAY OF CHAR);
Module FileName
These procedures return corresponding file name parts.
PROCEDURE Convert(str: ARRAY OF CHAR; VAR fname: ARRAY OF CHAR);
Module FileName
Converts a string to a file name according to the conventions of the underlying file system.
PROCEDURE ConvertExt(VAR ext: ARRAY OF CHAR);
Module FileName
Converts an extension according to the conventions of the underlying file system.
PROCEDURE Length(dir,name,ext: CARDINAL): CARDINAL;
Module FileName
Using the lengths of the directory, name and extension returns an estimated file name length which is greater than or equal to the length of the name generated by the Create procedure call.
PROCEDURE Create(dir,name,ext: ARRAY OF CHAR; VAR fname: ARRAY OF CHAR);
Module FileName
Creates a file name from its parts.
The following procedure can be used to change file name extension:
PROCEDURE ChangeExt(VAR fname: ARRAY OF CHAR; newext: ARRAY OF CHAR); CONST Len = 64; VAR dir,name: ARRAY [0..Len-1] OF CHAR; f: FileName.Format; len: CARDINAL; BEGIN FileName.GetFormat(fname,f); IF NOT f.ok THEN Error("wrong format") ELSIF (f.dirLen > Len) OR (f.nameLen > Len) THEN Error("too long part"); ELSE len:=FileName.Length(f.dirLen,f.nameLen,LENGTH(newext)); IF len-1 > HIGH(fname) THEN Error("cannot create file name") ELSE FileName.Create(dir,name,newext,fname); END; END; END ChangeExt;
When programming in Oberon-2 dynamic strings can be used to create strings of a required length:
PROCEDURE ChangeExt(VAR fname: ARRAY OF CHAR; newext: ARRAY OF CHAR); VAR dir,name: DStrings.String; f: FileName.Format; BEGIN FileName.GetFormat(fname,f); IF NOT f.ok THEN Error("wrong format") ELSE NEW(dir,f.dirLen+1); NEW(name,f.nameLen+1); ... END; END; END ChangeExt;
The module provides file common operations.
PROCEDURE Exists(fname: ARRAY OF CHAR): BOOLEAN;
Module FileSys
Returns TRUE, if file fname exists.
PROCEDURE ModifyTime(fname: ARRAY OF CHAR; VAR time: LONGCARD; VAR exists: BOOLEAN);
Module FileSys
Returns a file modification time; time is valid only if exists=TRUE.
PROCEDURE Rename(fname,newname: ARRAY OF CHAR; VAR done: BOOLEAN);
Module FileSys
Renames the file fname to newname.
PROCEDURE Remove(fname: ARRAY OF CHAR; VAR done: BOOLEAN);
Module FileSys
Removes a file.
The FormOut module implements a generic formatted output procedure which outputs its arguments according to the format parameter. The syntax of a format string is similar to one used by the printf family of C functions; some useful extensions are provided as well.
Format = { character | Specifier }. Specifier = "%" Modifier Width [ "." Precision [ "." Start ] ] Base. Modifier = "+" | "-" | "|" | "0" | "$" | "#". Width = [ unsigned number | "*" ]. Precision = [ unsigned number | "*" ]. Start = [ unsigned number | "*" ]. Base = "c" | "d" | "i" | "u" | "o" | "x" | "X" | "e" | "f" | "g" | "s" | "{}"
The following pairs of symbols starting from the backslash are recognized in Format string (but not in strings printed using "%s" specifier):
Input | Output |
\n | the line separator |
\r | CR (15C) |
\f | FF (14C) |
\t | TAB (11C) |
\\ | backslash |
Base characters and their meanings are listed in the following table:
Base | Argument | Output format |
c | CHAR | single character |
d, i | integer | signed decimal integer |
u | integer | unsigned decimal integer |
o | integer | unsigned octal integer |
X, x | integer | unsigned hexadecimal integer |
E, e | real | floating-point real |
f, | real | fixed-point real |
G, g | real | either as "f" or "e" |
s | string | string |
{} | BITSET | bitset, e.g. {1,3..5} |
Modifier meanings are as follows:
Modifier | Meaning | Default |
"+" | always print a sign for numbers | only for negative |
"-" | justify the result to the left | right-justify |
"|" | center the result | |
"0" | print leading zeroes for numbers | spaces |
"$" | the same as "0" | |
"#" | print a base character ("H" or "B") | no base character |
for "o", "x" and "X" bases only |
Width is used to specify the minimum number of characters in the output value. Shorter values are padded with blanks or zeroes to the left and/or to the right, depending on whether a "-", "|", "0", or "$" modifier is present. Specifying Width never causes longer values to be truncated; if it is not given or is less than the number of characters in the output value, all characters will be output. In some cases, Precision may be used for truncation.
If Width is set to an asterisk ("*"), its actual value will be retrieved from the argument list. It has to be specified before the value being formatted.
Precision specifies the number of characters to output or the number of decimal places. Unlike Width, it may cause the output value to be truncated or rounded.
If Precision is set to an asterisk ("*"), its actual value will be taken from the argument list. It has to be specified before the value being formatted, but after the actual value for Width, if the latter is also set to "*".
Precision value is interpreted depending upon the Base, and specifies:
Start may be used with the "s" (string) base only and specifies an initial offset in the string being formatted. If Start is set to an asterisk ("*"), the actual value will be taken from the argument list. It has to be specified before the value being formatted, but after the actual values for Width and/or Precision, if either of them is also set to "*".
Notes:
TYPE writeProc = PROCEDURE( (*handle:*) SYSTEM.ADDRESS, (*string:*) ARRAY OF CHAR, (*length:*) INTEGER );
Module FormOut
A procedure of this type is passed to the format procedure which uses that procedure to perform output.
PROCEDURE format(handle : SYSTEM.ADDRESS; write : writeProc; fmt : ARRAY OF CHAR; linesep: CHAR; args : SYSTEM.ADDRESS; size : CARDINAL);
Module FormOut
The format procedure forms a string and outputs it via the write procedure parameter. The handle parameter is passed to the procedure write and provides a useful method to pass any information between the caller and the write procedure (e.g. output channel or something like it). The (args, size) pair denotes the address and size of the parameter block. The linesep parameter determines the line separator character sequence corresponding to "\n". Several standard values of the parameter are defined in the definition module:
default | default line separator for binary files |
text | default line separator for text files |
crlf | CR LF character sequence |
If the linesep is not equal to any of the values above, its value will be used as a line separator.
PROCEDURE LineSeparator(nl: ARRAY OF CHAR);
Module FormOut
Sets the default line separator for binary files. The correct value for the given platform is set in the module initializaion.
PROCEDURE TextSeparator(nl: ARRAY OF CHAR);
Module FormOut
Sets the default line separator for text files. The correct value for the given platform is set in the module initializaion.
The following example shows the implementation of a procedure which produces a format output to an ISO channel.
PROCEDURE ChanWrite(handle: SYSTEM.ADDRESS; str: ARRAY OF CHAR; len: INTEGER); VAR chan: IOChan.ChanId; pos: INTEGER; BEGIN chan:=SYSTEM.CAST(IOChan.ChanId,handle); pos:=0; WHILE len > 0 DO IF str[pos] = ASCII.LF THEN IOChan.WriteLn ELSE IOChan.TextWrite(chan,SYSTEM.ADR(str[pos]),1) END; INC(pos); DEC(len); END; END ChanWrite; PROCEDURE Print(chan: IOChan.ChanId; format: ARRAY OF CHAR; SEQ args: SYSTEM.BYTE); BEGIN FormOut.format(chan,ChanWrite,format,FormOut.text, SYSTEM.ADR(args),SIZE(args)); END Print;
The procedure printf prints to the standard output channel:
PROCEDURE printf(f: ARRAY OF CHAR; SEQ x: SYSTEM.BYTE); BEGIN Print(StdChans.StdOutChan(),f,x); END printf;
The procedure printf can be used in the conventional for C programmers way, e.g. the call
printf("%d! = %d\n",5,Factorial(5));
will produce the line /Provided that the implementation of the procedure Factorial corresponds to its name./
5! = 120
The Printf module implements C-like procedures printf, sprintf, and fprintf.
Call | Output |
printf("%5.3s","abcdef") | abc |
printf("%-5.3s","abcdef") | abc |
printf("%|5.3s","abcdef") | abc |
printf("%..3s","abcdef") | def |
printf("pos=%3d",13) | pos= 13 |
printf("%$3o",13) | 015 |
printf("%04X",33C) | 001B |
printf("%{}",13) | {0,2..3} |
WARNING:
Language extensions are used in the interface of this module.
All your modules importing this one may be non-portable to other compilers.
A string is an array of characters of an arbitrary length. The procedures print, append and image guarantee the presence of the string terminator (0C) in the resulting string. See the FormOut module overview for the format string syntax.
PROCEDURE print(VAR str: ARRAY OF CHAR; format: ARRAY OF CHAR; SEQ args: SYSTEM.BYTE);
Module FormStr
Constructs a string specified by the pair (format,args) and places it into str.
PROCEDURE append( VAR str: ARRAY OF CHAR; format: ARRAY OF CHAR; SEQ args: SYSTEM.BYTE);
Module FormStr
Appends a string specified by the pair (format,args) to the end of the string str.
PROCEDURE image( VAR str: ARRAY OF CHAR; VAR pos: LONGINT; format: ARRAY OF CHAR; SEQ args: SYSTEM.BYTE);
Module FormStr
Places a string specified by the pair (format,args) in the string str starting from the position pos. After the procedure call, pos points to the 0C or to the position next to the end of the string.
PROCEDURE iscan( VAR num: INTEGER; str: ARRAY OF CHAR; VAR pos: CARDINAL; VAR done: BOOLEAN);
Module FormStr
Reads an integer value from the string str starting from the position pos. After the procedure call:
The number may be represented in any form permitted in Modula-2. In case of an integer overflow done=FALSE.
The Printf module provides C-like formatted output procedures fprintf, printf, and sprintf,
This module is based on the FormOut module and is provided for convenience.
TYPE ChanId = IOChan.ChanId;
The type IOChan.ChanId, which is used in ISO Modula-2 library to identify I/O channels, is reexported.
PROCEDURE fprintf(file : ChanId; format : ARRAY OF CHAR; SEQ args : SYSTEM.BYTE);
Module Printf
The procedure fprintf formats and outputs a series of characters and values to the channel identified by file. Each argument in args is converted and written to file according to the corresponding format specification in format.
See FormOut module for a description of the format specification and the argument list.
PROCEDURE printf(format : ARRAY OF CHAR; SEQ args : SYSTEM.BYTE);
Module Printf
The procedure printf formats and outputs a series of characters and values to the current standard output channel. Each argument in args is converted and written to the standard output according to the corresponding format specification in format.
See FormOut module for a description of the format specification and the argument list.
PROCEDURE sprintf(VAR buf : ARRAY OF CHAR; format : ARRAY OF CHAR; SEQ args : SYSTEM.BYTE);
Module Printf
The procedure sprintf formats and stores a series of characters and values in the array buf. Each argument in args is converted and put out according to the corresponding format specification in format.
See FormOut module for a description of the format specification and the argument list.
The ProgEnv module provides access to the program name, arguments, and environment strings.
PROCEDURE ArgNumber(): CARDINAL;
Module ProgEnv
Returns the number of arguments (0 if there is no arguments).
PROCEDURE GetArg(n: CARDINAL; VAR arg: ARRAY OF CHAR);
Module ProgEnv
Copies n-th argument (n >= 0) to arg, or empties it if n >= ArgNumber().
PROCEDURE ArgLength(n: CARDINAL): CARDINAL;
Module ProgEnv
Returns the length of the n-th argument, or 0 if n>=ArgNumber().
PROCEDURE ProgramName(VAR name: ARRAY OF CHAR);
Module ProgEnv
Copies a program name to name.
PROCEDURE ProgramNameLength(): CARDINAL;
Module ProgEnv
Returns the length of the program name.
PROCEDURE String(name: ARRAY OF CHAR; VAR str: ARRAY OF CHAR);
Module ProgEnv
Copies a value of the environment variable name to str (empty string if the variable is undefined).
PROCEDURE StringLength(name: ARRAY OF CHAR): CARDINAL;
Module ProgEnv
Returns the length of the environment variable name (0 if the variable is undefined).
The following procedure (in Oberon-2) prints all program arguments:
PROCEDURE ShowArgs; VAR str: POINTER TO ARRAY OF CHAR; i,args: LONGINT; BEGIN i:=0; args:=ProgEnv.ArgNumber(); FOR i:=0 TO args-1 DO NEW(str,ProgEnv.ArgLength(i)+1); ProgEnv.GetArg(i,str^); STextIO.WriteString(str^); STextIO.WriteLn; END; END ShowArgs;
The Modula-2 module TimeConv provides operations on values of type SysClock.DateTime.
TYPE DateTime = SysClock.DateTime;
Module TimeConv
The SysClock.DateTime type is re-exported for convenience.
PROCEDURE Compare(dl,dr: DateTime): INTEGER;
Module TimeConv
The function procedure Compare returns:
Note: If either dl or dr is invalid, zero is returned.
PROCEDURE SubDateDays(dl,dr: DateTime): CARDINAL;
Module TimeConv
The function procedure SubDateDays returns the number of days passed from dr to dl.
Note: If one of the parameters is invalid or if dl is before dr, zero is returned.
PROCEDURE SubDateSecs(dl,dr: DateTime): CARDINAL;
Module TimeConv
The function procedure SubDateSecs returns the number of seconds passed from dr to dl.
Note: If one of the parameters is invalid or if dl is before dr, zero is returned.
PROCEDURE AddDateDays(d: DateTime; days: CARDINAL; VAR res: DateTime);
Module TimeConv
The procedure AddDateDays adds days days to date d and assigns the resulting date to res.
Note: If "d" is invalid, "res" is assigned the first valid date.
PROCEDURE AddDateSecs(d: DateTime; secs: CARDINAL; VAR res: DateTime);
Module TimeConv
The procedure AddDateSecs adds secs seconds to date d and assigns the resulting date to res.
Note: If "d" is invalid, "res" is assigned the first valid date.
PROCEDURE TheDayNumber(d: DateTime): CARDINAL;
Module TimeConv
The function procedure TheDayNumber returns the ordinal number of the day for the date d.
Note: If d is invalid, zero is returned.
PROCEDURE TheFractionNumber(d: DateTime): CARDINAL;
Module TimeConv
The function procedure TheFractionNumber returns the number of fractions passed from time 0:00:00.00 of the day for the date d.
Note: If d is invalid, zero is returned.
PROCEDURE WeekDay(d: DateTime): CARDINAL;
Module TimeConv
The function procedure WeekDay returns day of the week for the date d. 0 represents Sunday, 1 - Monday, etc.
Note: If d is invalid, zero is returned.
PROCEDURE millisecs(): CARDINAL;
Module TimeConv
The function procedure millisecs returns the number of milliseconds passed from the time 0:00:00.00 of current date as known to the system.
Note: This procedure is system-dependent.
PROCEDURE time(): CARDINAL;
Module TimeConv
The function procedure time returns the number of seconds passed from the time 0:00:00.00 at first valid date for the system.
Note: This procedure is system-dependent.
PROCEDURE unpack(VAR d: DateTime; secs: CARDINAL);
Module TimeConv
The procedure unpack assigns to d the value corresponding to date/time which is secs seconds later than the first valid time/date for the system.
This procedure can be used to examine the first system time/date as follows:
unpack(firstDateTime,0);
Note: This procedure is system-dependent.
PROCEDURE pack(d: DateTime; VAR secs: CARDINAL);
Module TimeConv
The procedure pack assigns to secs the number of seconds passed from a first valid system date/time to d. Its effect is opposite to the pack procedure.
Note: This procedure is system-dependent.
PROCEDURE weekday(t: CARDINAL): CARDINAL;
Module TimeConv
The function procedure weekday behaves exactly the same as if it contains the following code:
unpack(tmpDateTime,t); RETURN WeekDay(tmpDateTime);
Note: This procedure is system-dependent.
The module DStrings (written in Oberon-2) defines a dynamic string type and provides some conventional operations.
TYPE String* = POINTER TO ARRAY OF CHAR;
Module DStrings
PROCEDURE Assign*(s: ARRAY OF CHAR; VAR d: String);
Module DStrings
Allocates a new dynamic string and copies string s to it. The resulting string always contains a terminator character (0C).
PROCEDURE Append*(s: ARRAY OF CHAR; VAR d: String);
Module DStrings
Appends the string s to d. d is extended if necessary. The resulting string always contains the string terminator (0C).
The FilePath module (written in Oberon-2) provides directory search facilities. In the following procedures path is a list of directories separated by semicolons, e.g.
.\SYM;C:\LIB\SYM;C:\XDS\LIB\SYM;. (Windows) ./sym;~/lib/sym;/usr/bin/xds/sym;. (Unix)
PROCEDURE IsSimpleName*(name: ARRAY OF CHAR): BOOLEAN;
Module FilePath
Returns TRUE, if name contains a file name only (without directories).
PROCEDURE Lookup*(path,name: ARRAY OF CHAR; VAR fname: DStrings.String; VAR n: INTEGER);
Module FilePath
Builds a filename using the search path. After a call:
n = -1 | if name is not simple (fname = name) |
n = 0 | file is not found (the first directory is used) |
n > 0 | file is found in the n-th directory |
PROCEDURE UseFirst*(path,name: ARRAY OF CHAR; VAR fname: DStrings.String);
Module FilePath
Builds a filename using the first directory from the search path.
This module (written in Oberon-2) implements a comparison of a string with regular expression.
A regular expression is a string which may contain certain special symbols:
Sequence | Denotes |
* | an arbitrary sequence of any characters, possibly empty |
(equivalent to {\000-\377} expression) | |
? | any single character |
(equivalent to [\000-\377] expression) | |
[...] | one of the listed characters |
{...} | an arbitrary sequence of the listed characters, possibly empty |
\nnn | the ASCII character with octal code nnn, where n is [0-7] |
& | the logical operation AND |
| | the logical operation OR |
^ | the logical operation NOT |
(...) | the priority of operations |
$digit | subexpression number (see below) |
A sequence of the form a-b used within either [] or {} brackets denotes all characters from a to b.
$digit may follow *, ?, [], {}, or () subexpression. For a string matching a regular expression, it represents the corresponding substring.
If you need to use any special symbol as an ordinary symbol, you should precede it with a backslash (\), which suppresses interpretation of the following symbol.
{0-9A-F} defines set of hexadecimal numbers
[a-zA-z_] defines a single small or capital letter or an underscore character.
(({0-9A-Fa-f})$1|({a-zA-Z_})$2))$3 matches both hexadecimal numbers and Modula-2 identifiers. After a successful match, a program may access the hexadecimal number by the $1 reference, the identifier by the $2 reference and either of them by the $3 reference.
\\\$\{\}\[\]\*\? represents the string \${}[]*?.
TYPE Expr* = POINTER TO ExprDesc; ExprDesc = RECORD END;
Module RegComp
PROCEDURE Compile*(expr: ARRAY OF CHAR; VAR reg: Expr; VAR res: LONGINT);
Module RegComp
Compiles a regular expression to an internal form.
Value of res | Meaning |
res≤0 | error in position ABS(res) |
res > 0 | done |
PROCEDURE Const*(re: Expr): BOOLEAN;
Module RegComp
Returns TRUE, if the expression does not contain wildcards.
PROCEDURE Match*(re: Expr; s: ARRAY OF CHAR; pos: LONGINT): BOOLEAN;
Module RegComp
Returns TRUE, if the expression matches the string s starting from the position pos.
PROCEDURE Len*(re: Expr; n: INTEGER): LONGINT;
Module RegComp
Returns the length of the substring which corresponds to $n in the last call of the Match procedure with the parameter re.
PROCEDURE Pos*(re: Expr; n: INTEGER): LONGINT;
Module RegComp
Returns the position of the substring which corresponds to $n in the last call of the Match procedure with the parameter re.
PROCEDURE Substitute*(re: Expr; s,m: ARRAY OF CHAR; VAR d: ARRAY OF CHAR);
Module RegComp
The substrings of s which matched re are substituted instead of $digit into m and the result string is copied into d.
Note: The Match(re,s,0) call should be issued and tested for success prior to a call to Substitute.
After the following sequence of calls
Compile("{a-z}$1{0-9}$2",re,res); IF Match(re,"abcdef153",0) THEN Substitute(re,"abcdef153","tail: $2 head: $1",dest); END;
the dest string will contain
"tail: 153 head: abcdef"