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;
     CONST   StdErr     = 1;
the function outputs its text to the user screen.
This was kind of strange, since under DOS the handles were defined as follows:
          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);

   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.
Still, it again took some time to find it out.

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;
      GetString (infile, substr);
      IF StrEq (substr, 'END') = TRUE  THEN  EXIT  END;
      Append (str, substr);
END GetCtrlStr;

PROCEDURE ConfigureSoup () : BOOLEAN;

VAR   InFile		: File;
      ch		: CHAR;
      pos		: CARDINAL;
      Status 		: BOOLEAN;

   Status := TRUE;
   OpenInput (InFile, '/usr/local/soup/soup.rc');
   IF Done () = TRUE THEN
      WriteString ('File opened. Fetching words.');	WriteLn;
      pos := 0;
         GetString (InFile, word);
	 INC (pos, Length (word));
	 IF pos > 78 THEN
	    DEC (pos, 78)
	 WriteString (word);
	 Write (' ');
	 INC (pos)
      UNTIL StrEq (word, 'BEGIN');
      Read (ch);
         GetString (InFile, option);
	 IF StrEq (option, 'END') = TRUE  THEN  EXIT  END;
	 IF StrEq (option, 'PrReset') = TRUE  THEN  
	    GetCtrlStr (InFile, PrReset);
	    WriteString (PrReset);
	 ELSIF StrEq (option, 'PrSetup')    = TRUE  THEN  
	    GetCtrlStr (InFile, PrSetup);
	    WriteString (PrSetup);
	 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)
	    ErrorMessage ('Invalid parameter in "/usr/local/soup/soup.rc".');
	    ErrorMessage ('Line ignored.');
	    Status := FALSE
      Close (InFile)
      ErrorMessage ("No file '/usr/local/soup/soup.rc'. Assuming HP Laserjet IIP.");
   RETURN Status
END ConfigureSoup;

   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;
      ErrorMessage ('Error while reading rc file.')
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.


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.


TopMargin	1
LeftMargin	8
MaxLine		82
MaxPos		120

PrReset		<ESC> E

PrSetup		<ESC> (10U
		<ESC> (s0p16.67h8.5v0s0b0T
		<ESC> &l8D


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 

		<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

In case of problems, contact the maintainer of this executable.

Page created March 2004,