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 : 4so 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,