Reading configuration files with Mocka.
This text is about reading from a file, by means of the TextIO library. The fact that we use TextIO here is of
less importance: the general idea remains the same with other file access functions, with the possible
exception that 'OpenInput' does not require access directions. OpenInput always tries to open for Input.
There is a corresponding 'OpenOutput' function, but we won't be needing that one here. We will cover it in a
later chapter.
Also in this source is a means of writing messages to the Standard Error console (StdErr, in another, not
mentioned, programming language). The procedure is appropriately called ErrorMessage. It's syntax is simple.
The only surprise was, that the program refused to run in the first few attempts.
The cause of the error seemed to be the ErrorMessage routine. But closer inspection and some tests showed that
the function worked. When I changed the
CONST StdErr = 2;
into
CONST StdErr = 1;
the function outputs its text to the user screen.
StdIn : 0
StdOut : 1
StdErr : 2
Aux : 3
LPT1 : 4
so I expected that Unix had somewhat the same handle definitions. Hay, gates stole it from someone, so why not
from Unix?
One more try however, revealed that StdErr under Unix is handle 0.
For the rest this program is not very difficult. It reads and interprets the configuration file for our soup
program. Consult the navigation bar on the right for more details about soup.
'Readcfg' simply reads the first segment of 'soup.rc' and then prints out each word to the screen. This way I
could see which progress the software made and where the errors popped up.
After the header is read in, the program finds the 'BEGIN' statement and next waits for the user to press a
key. After that, the program starts interpreting the configuration part of the file.
When done, the file is closed, control is handed over to the Main procedure and a message is printed if needed.
Textfile reading with Mocka.
MODULE readcfg;
(* Testprogram for finding out how to read and process files. May 5, 2003 *)
FROM TextIO IMPORT File, PutString, PutLn, OpenInput, Close, GetChar,
OpenOutput, GetCard, GetString, Done, EOF;
FROM InOut IMPORT Read, Write, WriteString, WriteLn, WriteBf, WriteCard;
FROM Strings IMPORT Append, StrEq, Length;
CONST StdErr = 0;
VAR word, option, PrReset, PrSetup : ARRAY [0..63] OF CHAR;
MaxLine, MaxPos, LeftMargin, TopMargin : CARDINAL;
ch : CHAR;
PROCEDURE ErrorMessage (mess : ARRAY OF CHAR);
BEGIN
PutString (StdErr, mess);
PutLn (StdErr)
END ErrorMessage;
This is where the strange behaviour popped up with the assigned handle numbers. Of course, assigning handle 0
to the error device is much smarte than assigning handle 2, since a simple nulled handle variable defaults to
zero and hence the StdErr device.
The IMPORT list was copied from another source and hence is much too big. Just ignore it.
The 'GetCtrlStr' function is not as it should be. But the main emphasis of this section was about reading text files.
PROCEDURE GetCtrlStr (infile : File ; VAR str : ARRAY OF CHAR);
VAR i, j : CARDINAL;
ch : CHAR;
substr : ARRAY [0..63] OF CHAR;
BEGIN
LOOP
GetString (infile, substr);
IF StrEq (substr, 'END') = TRUE THEN EXIT END;
Append (str, substr);
END
END GetCtrlStr;
PROCEDURE ConfigureSoup () : BOOLEAN;
VAR InFile : File;
ch : CHAR;
pos : CARDINAL;
Status : BOOLEAN;
BEGIN
Status := TRUE;
OpenInput (InFile, '/usr/local/soup/soup.rc');
IF Done () = TRUE THEN
WriteString ('File opened. Fetching words.'); WriteLn;
pos := 0;
REPEAT
GetString (InFile, word);
INC (pos, Length (word));
IF pos > 78 THEN
WriteLn;
DEC (pos, 78)
END;
WriteString (word);
Write (' ');
INC (pos)
UNTIL StrEq (word, 'BEGIN');
WriteLn;
Read (ch);
LOOP
GetString (InFile, option);
IF StrEq (option, 'END') = TRUE THEN EXIT END;
IF StrEq (option, 'PrReset') = TRUE THEN
GetCtrlStr (InFile, PrReset);
WriteString (PrReset);
WriteLn
ELSIF StrEq (option, 'PrSetup') = TRUE THEN
GetCtrlStr (InFile, PrSetup);
WriteString (PrSetup);
WriteLn
ELSIF StrEq (option, 'LeftMargin') = TRUE THEN GetCard (InFile, LeftMargin)
ELSIF StrEq (option, 'TopMargin') = TRUE THEN GetCard (InFile, TopMargin)
ELSIF StrEq (option, 'MaxPos') = TRUE THEN GetCard (InFile, MaxPos)
ELSIF StrEq (option, 'MaxLine') = TRUE THEN GetCard (InFile, MaxLine)
ELSE
ErrorMessage ('Invalid parameter in "/usr/local/soup/soup.rc".');
ErrorMessage ('Line ignored.');
Status := FALSE
END
END;
Close (InFile)
ELSE
ErrorMessage ("No file '/usr/local/soup/soup.rc'. Assuming HP Laserjet IIP.");
RETURN FALSE
END;
RETURN Status
END ConfigureSoup;
BEGIN
IF ConfigureSoup () = TRUE THEN
WriteString ('MaxPos :'); WriteCard (MaxPos, 7); WriteLn;
WriteString ('MaxLine :'); WriteCard (MaxLine, 7); WriteLn;
WriteString ('LeftMargin :'); WriteCard (LeftMargin, 7); WriteLn;
WriteString ('TopMargin :'); WriteCard (TopMargin, 7); WriteLn;
ELSE
ErrorMessage ('Error while reading rc file.')
END
END readcfg.
My favorite configuration files.
This is my favorite way of constructing configuration files. The concept of the BEGIN and END statements is
flexible and it leaves lots of room for adding remarks and comments.
This kind of cfg file works best for small files. The XF86Config file would be too big and too complex to
handle with BEGIN/END statements. Anyway, readcfg enables us to read an 'rc' file, and that was what we set
out to do.
Below you will see the contents of 'soup.rc' The file is self explanatory.
Soup.rc
This is the configuration file for the program 'soup'.
All parameters in this file are entered between the 'BEGIN' and 'END'
statements below. All text before 'BEGIN' and after 'END' will be ignored.
Please retain the syntax of the parameter settings. The strings can be of
arbitrary length for different printers. Therefore the parameters PrReset
and PrSetup are considered as 'compound statements'. The keyword starts the
interpretation of the string and it is terminated by the first encountered
'END' statement.
Do not place comments in the section between BEGIN/END. If you need to
supply comments, clarifications or (even worse): names, please do so
outside the 'payload' of this configuration file.
BEGIN
TopMargin 1
LeftMargin 8
MaxLine 82
MaxPos 120
PrReset <ESC> E
END
PrSetup <ESC> (10U
<ESC> (s0p16.67h8.5v0s0b0T
<ESC> &l8D
END
END
TopMargin nr of lines to skip at top of page
LeftMargin nr of spaces to insert at start of each line
MaxLine when this line is reached, soup initiates a SKIP procedure
MaxPos if a very long line is encountered, and this horizontal
position is reached, then a line wrap is forced, but WITH
the specified indentation
PrReset Freeform string to initiate a printer RESET by software
This string must be ended by an END statement.
PrSetup Free form string to setup the printer for the desired font
and lettertype.
This string can be any length and hence must be ended by
an END statement.
If you need special tokens, make a choice from the following
list:
<ESC> = ASCII Escape character (27)
^X = Control character where X = '@..Z' and '[\]^_'
The '^' token is 'Shift 6' and must be entered as
such in this file. The 'X' is just an example.
^@ = 0 ^H = 8 ^P = 16 ^X = 24
^A = 1 ^I = 9 ^Q = 17 ^Y = 25
^B = 2 ^J = 10 ^R = 18 ^Z = 26
^C = 3 ^K = 11 ^S = 19 ^[ = 27
^D = 4 ^L = 12 ^T = 20 ^\ = 28
^E = 5 ^M = 13 ^U = 21 ^] = 29
^F = 6 ^N = 14 ^V = 22 ^^ = 30
^G = 7 ^O = 15 ^W = 23 ^_ = 31
This is the end of the configuration file for soup, which should be located as
/usr/local/soup/soup.rc
In case of problems, contact the maintainer of this executable.
Page created March 2004,
Page equipped with FroogleBuster technology