tasks a-s
This commit is contained in:
parent
47bf37c096
commit
b83f433714
12433 changed files with 156208 additions and 123 deletions
42
Task/Read-a-configuration-file/0DESCRIPTION
Normal file
42
Task/Read-a-configuration-file/0DESCRIPTION
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
The task is to read a configuration file in standard configuration file, and set variables accordingly. For this task, we have a configuration file as follows:
|
||||
|
||||
# This is a configuration file in standard configuration file format
|
||||
#
|
||||
# Lines begininning with a hash or a semicolon are ignored by the application
|
||||
# program. Blank lines are also ignored by the application program.
|
||||
|
||||
# This is the fullname parameter
|
||||
FULLNAME Foo Barber
|
||||
|
||||
# This is a favourite fruit
|
||||
FAVOURITEFRUIT banana
|
||||
|
||||
# This is a boolean that should be set
|
||||
NEEDSPEELING
|
||||
|
||||
# This boolean is commented out
|
||||
; SEEDSREMOVED
|
||||
|
||||
# Configuration option names are not case sensitive, but configuration parameter
|
||||
# data is case sensitive and may be preserved by the application program.
|
||||
|
||||
# An optional equals sign can be used to separate configuration parameter data
|
||||
# from the option name. This is dropped by the parser.
|
||||
|
||||
# A configuration option may take multiple parameters separated by commas.
|
||||
# Leading and trailing whitespace around parameter names and parameter data fields
|
||||
# are ignored by the application program.
|
||||
|
||||
OTHERFAMILY Rhu Barber, Harry Barber
|
||||
|
||||
For the task we need to set four variables according to the configuration entries as follows:
|
||||
|
||||
*fullname = Foo Barber
|
||||
*favouritefruit = banana
|
||||
*needspeeling = true
|
||||
*seedsremoved = false
|
||||
|
||||
We also have an option that contains multiple parameters. These may be stored in an array.
|
||||
|
||||
* otherfamily(1) = Rhu Barber
|
||||
* otherfamily(2) = Harry Barber
|
||||
2
Task/Read-a-configuration-file/1META.yaml
Normal file
2
Task/Read-a-configuration-file/1META.yaml
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
note: File handling
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
with Ada.Strings.Unbounded;
|
||||
with Config_File_Parser;
|
||||
pragma Elaborate_All (Config_File_Parser);
|
||||
|
||||
package Config is
|
||||
|
||||
function TUS (S : String) return Ada.Strings.Unbounded.Unbounded_String
|
||||
renames Ada.Strings.Unbounded.To_Unbounded_String;
|
||||
-- Convenience rename. TUS is much shorter than To_Unbounded_String.
|
||||
|
||||
type Keys is (
|
||||
FULLNAME,
|
||||
FAVOURITEFRUIT,
|
||||
NEEDSPEELING,
|
||||
SEEDSREMOVED,
|
||||
OTHERFAMILY);
|
||||
-- These are the valid configuration keys.
|
||||
|
||||
type Defaults_Array is
|
||||
array (Keys) of Ada.Strings.Unbounded.Unbounded_String;
|
||||
-- The array type we'll use to hold our default configuration settings.
|
||||
|
||||
Defaults_Conf : Defaults_Array :=
|
||||
(FULLNAME => TUS ("John Doe"),
|
||||
FAVOURITEFRUIT => TUS ("blackberry"),
|
||||
NEEDSPEELING => TUS ("False"),
|
||||
SEEDSREMOVED => TUS ("False"),
|
||||
OTHERFAMILY => TUS ("Daniel Defoe, Ada Byron"));
|
||||
-- Default values for the Program object. These can be overwritten by
|
||||
-- the contents of the rosetta.cfg file(see below).
|
||||
|
||||
package Rosetta_Config is new Config_File_Parser (
|
||||
Keys => Keys,
|
||||
Defaults_Array => Defaults_Array,
|
||||
Defaults => Defaults_Conf,
|
||||
Config_File => "rosetta.cfg");
|
||||
-- Instantiate the Config configuration object.
|
||||
|
||||
end Config;
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
with Ada.Text_IO;
|
||||
with Config; use Config;
|
||||
|
||||
procedure Read_Config is
|
||||
use Ada.Text_IO;
|
||||
use Rosetta_Config;
|
||||
|
||||
begin
|
||||
New_Line;
|
||||
Put_Line ("Reading Configuration File.");
|
||||
Put_Line ("Fullname := " & Get (Key => FULLNAME));
|
||||
Put_Line ("Favorite Fruit := " & Get (Key => FAVOURITEFRUIT));
|
||||
Put_Line ("Other Family := " & Get (Key => OTHERFAMILY));
|
||||
if Has_Value (Key => NEEDSPEELING) then
|
||||
Put_Line ("NEEDSPEELLING := " & Get (Key => NEEDSPEELING));
|
||||
else
|
||||
Put_Line ("NEEDSPEELLING := True");
|
||||
end if;
|
||||
if Has_Value (Key => SEEDSREMOVED) then
|
||||
Put_Line ("SEEDSREMOVED := " & Get (Key => SEEDSREMOVED));
|
||||
else
|
||||
Put_Line ("SEEDSREMOVED := True");
|
||||
end if;
|
||||
end Read_Config;
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
; Author: AlephX, Aug 18 2011
|
||||
data = %A_scriptdir%\rosettaconfig.txt
|
||||
comma := ","
|
||||
|
||||
Loop, Read, %data%
|
||||
{
|
||||
if NOT (instr(A_LoopReadLine, "#") == 1 OR A_LoopReadLine == "")
|
||||
|
||||
{
|
||||
if instr(A_LoopReadLine, ";") == 1
|
||||
{
|
||||
parameter := RegExReplace(Substr(A_LoopReadLine,2), "^[ \s]+|[ \s]+$", "")
|
||||
%parameter% = "1"
|
||||
}
|
||||
else
|
||||
{
|
||||
parameter := RegExReplace(A_LoopReadLine, "^[ \s]+|[ \s]+$", "")
|
||||
|
||||
if instr(parameter, A_Space)
|
||||
{
|
||||
value := substr(parameter, instr(parameter, A_Space)+1,999)
|
||||
parameter := substr(parameter, 1, instr(parameter, A_Space)-1)
|
||||
|
||||
if (instr(value, ",") <> 0)
|
||||
{
|
||||
Loop, Parse, value, %comma% ,%A_Space%
|
||||
%parameter%%A_Index% := A_Loopfield
|
||||
}
|
||||
else
|
||||
%parameter% = %value%
|
||||
}
|
||||
else
|
||||
%parameter% = "0"
|
||||
}
|
||||
}
|
||||
}
|
||||
msgbox, FULLNAME %fullname%`nFAVOURITEFRUIT %FAVOURITEFRUIT%`nNEEDSPEELING %NEEDSPEELING%`nSEEDSREMOVED %SEEDSREMOVED%`nOTHERFAMILY %OTHERFAMILY1% + %OTHERFAMILY2%
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
BOOL = 1
|
||||
NAME = 2
|
||||
ARRAY = 3
|
||||
|
||||
optfile$ = "options.cfg"
|
||||
|
||||
fullname$ = FNoption(optfile$, "FULLNAME", NAME)
|
||||
favouritefruit$ = FNoption(optfile$, "FAVOURITEFRUIT", NAME)
|
||||
needspeeling% = FNoption(optfile$, "NEEDSPEELING", BOOL)
|
||||
seedsremoved% = FNoption(optfile$, "SEEDSREMOVED", BOOL)
|
||||
!^otherfamily$() = FNoption(optfile$, "OTHERFAMILY", ARRAY)
|
||||
|
||||
PRINT "fullname = " fullname$
|
||||
PRINT "favouritefruit = " favouritefruit$
|
||||
PRINT "needspeeling = "; : IF needspeeling% PRINT "true" ELSE PRINT "false"
|
||||
PRINT "seedsremoved = "; : IF seedsremoved% PRINT "true" ELSE PRINT "false"
|
||||
PRINT "otherfamily(1) = " otherfamily$(1)
|
||||
PRINT "otherfamily(2) = " otherfamily$(2)
|
||||
END
|
||||
|
||||
DEF FNoption(file$, key$, type%)
|
||||
LOCAL file%, opt$, comma%, bool%, name$, size%, !^array$()
|
||||
file% = OPENIN(file$)
|
||||
IF file% = 0 THEN = 0
|
||||
WHILE NOT EOF#file%
|
||||
opt$ = GET$#file%
|
||||
WHILE RIGHT$(opt$) = " " opt$ = LEFT$(opt$) : ENDWHILE
|
||||
IF opt$ = key$ OR LEFT$(opt$, LEN(key$)+1) = key$ + " " THEN
|
||||
opt$ = MID$(opt$, LEN(key$) + 1)
|
||||
WHILE LEFT$(opt$,1) = " " opt$ = MID$(opt$,2) : ENDWHILE
|
||||
CASE type% OF
|
||||
WHEN BOOL: bool% = TRUE : EXIT WHILE
|
||||
WHEN NAME: name$ = opt$ : EXIT WHILE
|
||||
WHEN ARRAY:
|
||||
REPEAT
|
||||
comma% = INSTR(opt$, ",", comma%+1)
|
||||
IF comma% size% += 1
|
||||
UNTIL comma% = 0
|
||||
DIM array$(size% + 1)
|
||||
size% = 0
|
||||
REPEAT
|
||||
comma% = INSTR(opt$, ",")
|
||||
IF comma% THEN
|
||||
size% += 1
|
||||
array$(size%) = LEFT$(opt$, comma%-1)
|
||||
opt$ = MID$(opt$, comma%+1)
|
||||
WHILE LEFT$(opt$,1) = " " opt$ = MID$(opt$,2) : ENDWHILE
|
||||
ENDIF
|
||||
UNTIL comma% = 0
|
||||
array$(size% + 1) = opt$
|
||||
EXIT WHILE
|
||||
ENDCASE
|
||||
ENDIF
|
||||
ENDWHILE
|
||||
CLOSE #file%
|
||||
CASE type% OF
|
||||
WHEN BOOL: = bool%
|
||||
WHEN NAME: = name$
|
||||
WHEN ARRAY: = !^array$()
|
||||
ENDCASE
|
||||
= 0
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
#include "stdafx.h"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <boost/tokenizer.hpp>
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
using namespace std;
|
||||
using namespace boost;
|
||||
|
||||
typedef boost::tokenizer<boost::char_separator<char> > Tokenizer;
|
||||
static const char_separator<char> sep(" ","#;,");
|
||||
|
||||
//Assume that the config file represent a struct containing all the parameters to load
|
||||
struct configs{
|
||||
string fullname;
|
||||
string favoritefruit;
|
||||
bool needspelling;
|
||||
bool seedsremoved;
|
||||
vector<string> otherfamily;
|
||||
} conf;
|
||||
|
||||
void parseLine(const string &line, configs &conf)
|
||||
{
|
||||
if (line[0] == '#' || line.empty())
|
||||
return;
|
||||
Tokenizer tokenizer(line, sep);
|
||||
vector<string> tokens;
|
||||
for (Tokenizer::iterator iter = tokenizer.begin(); iter != tokenizer.end(); iter++)
|
||||
tokens.push_back(*iter);
|
||||
if (tokens[0] == ";"){
|
||||
algorithm::to_lower(tokens[1]);
|
||||
if (tokens[1] == "needspeeling")
|
||||
conf.needspelling = false;
|
||||
if (tokens[1] == "seedsremoved")
|
||||
conf.seedsremoved = false;
|
||||
}
|
||||
algorithm::to_lower(tokens[0]);
|
||||
if (tokens[0] == "needspeeling")
|
||||
conf.needspelling = true;
|
||||
if (tokens[0] == "seedsremoved")
|
||||
conf.seedsremoved = true;
|
||||
if (tokens[0] == "fullname"){
|
||||
for (unsigned int i=1; i<tokens.size(); i++)
|
||||
conf.fullname += tokens[i] + " ";
|
||||
conf.fullname.erase(conf.fullname.size() -1, 1);
|
||||
}
|
||||
if (tokens[0] == "favouritefruit")
|
||||
for (unsigned int i=1; i<tokens.size(); i++)
|
||||
conf.favoritefruit += tokens[i];
|
||||
if (tokens[0] == "otherfamily"){
|
||||
unsigned int i=1;
|
||||
string tmp;
|
||||
while (i<=tokens.size()){
|
||||
if ( i == tokens.size() || tokens[i] ==","){
|
||||
tmp.erase(tmp.size()-1, 1);
|
||||
conf.otherfamily.push_back(tmp);
|
||||
tmp = "";
|
||||
i++;
|
||||
}
|
||||
else{
|
||||
tmp += tokens[i];
|
||||
tmp += " ";
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int _tmain(int argc, TCHAR* argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
wstring tmp = argv[0];
|
||||
wcout << L"Usage: " << tmp << L" <configfile.ini>" << endl;
|
||||
return -1;
|
||||
}
|
||||
ifstream file (argv[1]);
|
||||
|
||||
if (file.is_open())
|
||||
while(file.good())
|
||||
{
|
||||
char line[255];
|
||||
file.getline(line, 255);
|
||||
string linestring(line);
|
||||
parseLine(linestring, conf);
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Unable to open the file" << endl;
|
||||
return -2;
|
||||
}
|
||||
|
||||
cout << "Fullname= " << conf.fullname << endl;
|
||||
cout << "Favorite Fruit= " << conf.favoritefruit << endl;
|
||||
cout << "Need Spelling= " << (conf.needspelling?"True":"False") << endl;
|
||||
cout << "Seed Removed= " << (conf.seedsremoved?"True":"False") << endl;
|
||||
string otherFamily;
|
||||
for (unsigned int i = 0; i < conf.otherfamily.size(); i++)
|
||||
otherFamily += conf.otherfamily[i] + ", ";
|
||||
otherFamily.erase(otherFamily.size()-2, 2);
|
||||
cout << "Other Family= " << otherFamily << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
struct confi {
|
||||
std::string fullname;
|
||||
std::string favouritefruit;
|
||||
bool needspeeling;
|
||||
bool seedsremoved;
|
||||
std::vector<std::string> otherfamily;
|
||||
};
|
||||
|
||||
void read_config(std::ifstream& in, confi& out) {
|
||||
in.open("Config.txt");
|
||||
std::string str;
|
||||
out.needspeeling = false;
|
||||
out.seedsremoved = false;
|
||||
while(!in.eof()) {
|
||||
while(getline(in,str)) {
|
||||
std::string::size_type begin = str.find_first_not_of(" \f\t\v");
|
||||
//Skips blank lines
|
||||
if(begin == std::string::npos)
|
||||
continue;
|
||||
//Skips #
|
||||
if(std::string("#").find(str[begin]) != std::string::npos)
|
||||
continue;
|
||||
std::string firstWord;
|
||||
try {
|
||||
firstWord = str.substr(0,str.find(" "));
|
||||
}
|
||||
catch(std::exception& e) {
|
||||
firstWord = str.erase(str.find_first_of(" "),str.find_first_not_of(" "));
|
||||
}
|
||||
std::transform(firstWord.begin(),firstWord.end(),firstWord.begin(), ::toupper);
|
||||
if(firstWord == "FULLNAME")
|
||||
out.fullname = str.substr(str.find(" ")+1,str.length());
|
||||
if(firstWord == "FAVOURITEFRUIT")
|
||||
out.favouritefruit = str.substr(str.find(" ")+1,str.length());
|
||||
if(firstWord == "NEEDSPEELING")
|
||||
out.needspeeling = true;
|
||||
if(firstWord == "SEEDSREMOVED")
|
||||
out.seedsremoved = true;
|
||||
if(firstWord == "OTHERFAMILY") {
|
||||
size_t found = str.find(",");
|
||||
if(found != std::string::npos) {
|
||||
out.otherfamily.push_back(str.substr(str.find_first_of(" ")+1,found-str.find_first_of(" ")-1));
|
||||
out.otherfamily.push_back(str.substr(found+2,str.length()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
std::cout << "Full Name: " << out.fullname << std::endl;
|
||||
std::cout << "Favourite Fruit: " << out.favouritefruit << std::endl;
|
||||
std::cout << "Needs peeling?: ";
|
||||
if(out.needspeeling == true)
|
||||
std::cout << "True" << std::endl;
|
||||
else
|
||||
std::cout << "False" << std::endl;
|
||||
std::cout << "Seeds removed?: ";
|
||||
if(out.seedsremoved == true)
|
||||
std::cout << "True" << std::endl;
|
||||
else
|
||||
std::cout << "False" << std::endl;
|
||||
std::cout << "Other family members: " << out.otherfamily[0] << ", " << out.otherfamily[1] << std::endl;
|
||||
}
|
||||
int main() {
|
||||
std::ifstream inp;
|
||||
confi outp;
|
||||
read_config(inp,outp);
|
||||
}
|
||||
38
Task/Read-a-configuration-file/D/read-a-configuration-file.d
Normal file
38
Task/Read-a-configuration-file/D/read-a-configuration-file.d
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import std.stdio, std.string, std.conv, std.regex, std.getopt;
|
||||
|
||||
template VarName(alias var) {
|
||||
enum VarName = var.stringof.toUpper();
|
||||
}
|
||||
|
||||
void setOpt(alias Var)(in string line) {
|
||||
auto m = match(line, regex(`^` ~ VarName!Var ~ `(\s+(.*))?`));
|
||||
if (!m.empty) {
|
||||
static if (is(typeof(Var) == string))
|
||||
Var = m.captures.length > 2 ? m.captures[2] : "";
|
||||
static if (is(typeof(Var) == bool))
|
||||
Var = true;
|
||||
static if (is(typeof(Var) == int))
|
||||
Var = m.captures.length > 2 ? to!int(m.captures[2]) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void main(string[] args) {
|
||||
string fullName, favouriteFruit, otherFamily;
|
||||
bool needsPeeling, seedsRemoved; // Default false.
|
||||
auto f = File("readcfg.txt", "r");
|
||||
|
||||
foreach (line; f.byLine()) {
|
||||
auto opt = line.strip().idup;
|
||||
setOpt!fullName(opt);
|
||||
setOpt!favouriteFruit(opt);
|
||||
setOpt!needsPeeling(opt);
|
||||
setOpt!seedsRemoved(opt);
|
||||
setOpt!otherFamily(opt);
|
||||
}
|
||||
|
||||
writefln("%14s = %s", VarName!fullName, fullName);
|
||||
writefln("%14s = %s", VarName!favouriteFruit, favouriteFruit);
|
||||
writefln("%14s = %s", VarName!needsPeeling, needsPeeling);
|
||||
writefln("%14s = %s", VarName!seedsRemoved, seedsRemoved);
|
||||
writefln("%14s = %s", VarName!otherFamily, otherFamily);
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
class Main
|
||||
{
|
||||
// remove the given key and an optional '=' from start of line
|
||||
Str removeKey (Str key, Str line)
|
||||
{
|
||||
remainder := line[key.size..-1].trim
|
||||
if (remainder.startsWith("="))
|
||||
{
|
||||
remainder = remainder.replace("=", "").trim
|
||||
}
|
||||
return remainder
|
||||
}
|
||||
|
||||
Void main ()
|
||||
{
|
||||
// define the variables which need configuring
|
||||
fullname := ""
|
||||
favouritefruit := ""
|
||||
needspeeling := false
|
||||
seedsremoved := false
|
||||
Str[] otherfamily := [,]
|
||||
|
||||
// loop through the file, setting variables as needed
|
||||
File(`config.dat`).eachLine |Str line|
|
||||
{
|
||||
line = line.trim
|
||||
if (line.isEmpty || line.startsWith("#") || line.startsWith(";"))
|
||||
{
|
||||
// do nothing for empty and comment lines
|
||||
}
|
||||
else if (line.upper.startsWith("FULLNAME"))
|
||||
{
|
||||
fullname = removeKey("FULLNAME", line)
|
||||
}
|
||||
else if (line.upper.startsWith("FAVOURITEFRUIT"))
|
||||
{
|
||||
favouritefruit = removeKey("FAVOURITEFRUIT", line)
|
||||
}
|
||||
else if (line.upper.startsWith("NEEDSPEELING"))
|
||||
{
|
||||
needspeeling = true
|
||||
}
|
||||
else if (line.upper.startsWith("SEEDSREMOVED"))
|
||||
{
|
||||
seedsremoved = true
|
||||
}
|
||||
else if (line.upper.startsWith("OTHERFAMILY"))
|
||||
{
|
||||
otherfamily = removeKey("OTHERFAMILY", line).split(',')
|
||||
}
|
||||
}
|
||||
|
||||
// report results
|
||||
echo ("Full name is $fullname")
|
||||
echo ("Favourite fruit is $favouritefruit")
|
||||
echo ("Needs peeling is $needspeeling")
|
||||
echo ("Seeds removed is $seedsremoved")
|
||||
echo ("Other family is " + otherfamily.join(", "))
|
||||
}
|
||||
}
|
||||
160
Task/Read-a-configuration-file/Go/read-a-configuration-file-1.go
Normal file
160
Task/Read-a-configuration-file/Go/read-a-configuration-file-1.go
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"fmt"
|
||||
"bytes"
|
||||
"strings"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
var (
|
||||
ENONE = errors.New("Requested value does not exist")
|
||||
EBADTYPE = errors.New("Requested type and actual type do not match")
|
||||
EBADVAL = errors.New("Value and type do not match")
|
||||
)
|
||||
|
||||
type varError struct {
|
||||
err error
|
||||
n string
|
||||
t VarType
|
||||
}
|
||||
|
||||
func (err *varError) Error() string {
|
||||
return fmt.Sprintf("%v: (%q, %v)", err.err, err.n, err.t)
|
||||
}
|
||||
|
||||
type VarType int
|
||||
|
||||
const (
|
||||
Bool VarType = 1 + iota
|
||||
Array
|
||||
String
|
||||
)
|
||||
|
||||
func (t VarType) String() string {
|
||||
switch t {
|
||||
case Bool:
|
||||
return "Bool"
|
||||
case Array:
|
||||
return "Array"
|
||||
case String:
|
||||
return "String"
|
||||
}
|
||||
|
||||
panic("Unknown VarType")
|
||||
}
|
||||
|
||||
type confvar struct {
|
||||
Type VarType
|
||||
Val interface{}
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
m map[string]confvar
|
||||
}
|
||||
|
||||
func Parse(r io.Reader) (c *Config, err error) {
|
||||
c = new(Config)
|
||||
c.m = make(map[string]confvar)
|
||||
|
||||
buf, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
lines := bytes.Split(buf, []byte{'\n'})
|
||||
|
||||
for _, line := range lines {
|
||||
line = bytes.TrimSpace(line)
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
switch line[0] {
|
||||
case '#', ';':
|
||||
continue
|
||||
}
|
||||
|
||||
parts := bytes.SplitN(line, []byte{' '}, 2)
|
||||
nam := string(bytes.ToLower(parts[0]))
|
||||
|
||||
if len(parts) == 1 {
|
||||
c.m[nam] = confvar{Bool, true}
|
||||
continue
|
||||
}
|
||||
|
||||
if strings.Contains(string(parts[1]), ",") {
|
||||
tmpB := bytes.Split(parts[1], []byte{','})
|
||||
for i := range tmpB {
|
||||
tmpB[i] = bytes.TrimSpace(tmpB[i])
|
||||
}
|
||||
tmpS := make([]string, 0, len(tmpB))
|
||||
for i := range tmpB {
|
||||
tmpS = append(tmpS, string(tmpB[i]))
|
||||
}
|
||||
|
||||
c.m[nam] = confvar{Array, tmpS}
|
||||
continue
|
||||
}
|
||||
|
||||
c.m[nam] = confvar{String, string(bytes.TrimSpace(parts[1]))}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Config) Bool(name string) (bool, error) {
|
||||
name = strings.ToLower(name)
|
||||
|
||||
if _, ok := c.m[name]; !ok {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if c.m[name].Type != Bool {
|
||||
return false, &varError{EBADTYPE, name, Bool}
|
||||
}
|
||||
|
||||
v, ok := c.m[name].Val.(bool)
|
||||
if !ok {
|
||||
return false, &varError{EBADVAL, name, Bool}
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (c *Config) Array(name string) ([]string, error) {
|
||||
name = strings.ToLower(name)
|
||||
|
||||
if _, ok := c.m[name]; !ok {
|
||||
return nil, &varError{ENONE, name, Array}
|
||||
}
|
||||
|
||||
if c.m[name].Type != Array {
|
||||
return nil, &varError{EBADTYPE, name, Array}
|
||||
}
|
||||
|
||||
v, ok := c.m[name].Val.([]string)
|
||||
if !ok {
|
||||
return nil, &varError{EBADVAL, name, Array}
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (c *Config) String(name string) (string, error) {
|
||||
name = strings.ToLower(name)
|
||||
|
||||
if _, ok := c.m[name]; !ok {
|
||||
return "", &varError{ENONE, name, String}
|
||||
}
|
||||
|
||||
if c.m[name].Type != String {
|
||||
return "", &varError{EBADTYPE, name, String}
|
||||
}
|
||||
|
||||
v, ok := c.m[name].Val.(string)
|
||||
if !ok {
|
||||
return "", &varError{EBADVAL, name, String}
|
||||
}
|
||||
|
||||
return v, nil
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"fmt"
|
||||
"config"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Printf("Usage: %v <configfile>\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
file, err := os.Open(os.Args[1])
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
conf, err := config.Parse(file)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fullname, err := conf.String("fullname")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
favouritefruit, err := conf.String("favouritefruit")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
needspeeling, err := conf.Bool("needspeeling")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
seedsremoved, err := conf.Bool("seedsremoved")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
otherfamily, err := conf.Array("otherfamily")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
fmt.Printf("FULLNAME: %q\n", fullname)
|
||||
fmt.Printf("FAVOURITEFRUIT: %q\n", favouritefruit)
|
||||
fmt.Printf("NEEDSPEELING: %q\n", needspeeling)
|
||||
fmt.Printf("SEEDSREMOVED: %q\n", seedsremoved)
|
||||
fmt.Printf("OTHERFAMILY: %q\n", otherfamily)
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
import Data.Char
|
||||
import Data.List
|
||||
import Data.List.Split
|
||||
|
||||
main :: IO ()
|
||||
main = readFile "config" >>= (print . parseConfig)
|
||||
|
||||
parseConfig :: String -> Config
|
||||
parseConfig = foldr addConfigValue defaultConfig . clean . lines
|
||||
where clean = filter (not . flip any ["#", ";", "", " "] . (==) . take 1)
|
||||
|
||||
addConfigValue :: String -> Config -> Config
|
||||
addConfigValue raw config = case key of
|
||||
"fullname" -> config {fullName = values}
|
||||
"favouritefruit" -> config {favoriteFruit = values}
|
||||
"needspeeling" -> config {needsPeeling = True}
|
||||
"seedsremoved" -> config {seedsRemoved = True}
|
||||
"otherfamily" -> config {otherFamily = splitOn "," values}
|
||||
_ -> config
|
||||
where (k, vs) = span (/= ' ') raw
|
||||
key = map toLower k
|
||||
values = tail vs
|
||||
|
||||
data Config = Config
|
||||
{ fullName :: String
|
||||
, favoriteFruit :: String
|
||||
, needsPeeling :: Bool
|
||||
, seedsRemoved :: Bool
|
||||
, otherFamily :: [String]
|
||||
} deriving (Show)
|
||||
|
||||
defaultConfig :: Config
|
||||
defaultConfig = Config "" "" False False []
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import Data.ConfigFile
|
||||
import Data.Either.Utils
|
||||
|
||||
getSetting cp x = forceEither $ get cp "Default" x
|
||||
|
||||
cp <- return . forceEither =<< readfile emptyCP "name_of_configuration_file"
|
||||
let username = getSetting cp "username"
|
||||
password = getSetting cp "password"
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
require'regex'
|
||||
set=:4 :'(x)=:y'
|
||||
|
||||
cfgString=:4 :0
|
||||
y set ''
|
||||
(1;&,~'(?i:',y,')\s*(.*)') y&set rxapply x
|
||||
)
|
||||
|
||||
cfgBoolean=:4 :0
|
||||
y set 0
|
||||
(1;&,~'(?i:',y,')\s*(.*)') y&set rxapply x
|
||||
if.-.0-:y do.y set 1 end.
|
||||
)
|
||||
|
||||
taskCfg=:3 :0
|
||||
cfg=: ('[#;].*';'') rxrplc 1!:1<y
|
||||
cfg cfgString 'fullname'
|
||||
cfg cfgString 'favouritefruit'
|
||||
cfg cfgBoolean 'needspeeling'
|
||||
cfg cfgBoolean 'seedsremoved'
|
||||
i.0 0
|
||||
)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
taskCfg 'fruit.conf'
|
||||
(,' = ',]&.do)&>;: 'fullname favouritefruit needspeeling seedsremoved'
|
||||
fullname = Foo Barber
|
||||
favouritefruit = banana
|
||||
needspeeling = 1
|
||||
seedsremoved = 0
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
dim confKeys$(100)
|
||||
dim confValues$(100)
|
||||
|
||||
optionCount = ParseConfiguration("a.txt")
|
||||
|
||||
fullName$ = GetOption$( "FULLNAME", optionCount)
|
||||
favouriteFruit$ = GetOption$( "FAVOURITEFRUIT", optionCount)
|
||||
needsPeeling = HasOption("NEEDSPEELING", optionCount)
|
||||
seedsRemoved = HasOption("SEEDSREMOVED", optionCount)
|
||||
otherFamily$ = GetOption$( "OTHERFAMILY", optionCount) 'it's easier to keep the comma-separated list as a string
|
||||
|
||||
print "Full name: "; fullName$
|
||||
print "likes: "; favouriteFruit$
|
||||
print "needs peeling: "; needsPeeling
|
||||
print "seeds removed: "; seedsRemoved
|
||||
|
||||
print "other family:"
|
||||
otherFamily$ = GetOption$( "OTHERFAMILY", optionCount)
|
||||
counter = 1
|
||||
while word$(otherFamily$, counter, ",") <> ""
|
||||
print counter; ". "; trim$(word$(otherFamily$, counter, ","))
|
||||
counter = counter + 1
|
||||
wend
|
||||
end
|
||||
|
||||
'parses the configuration file, stores the uppercase keys in array confKeys$ and corresponding values in confValues$
|
||||
'returns the number of key-value pairs found
|
||||
function ParseConfiguration(fileName$)
|
||||
count = 0
|
||||
open fileName$ for input as #f
|
||||
while not(eof(#f))
|
||||
line input #f, s$
|
||||
if not(Left$(s$,1) = "#" or Left$( s$,1) = ";" or trim$(s$) = "") then 'ignore empty and comment lines
|
||||
s$ = trim$(s$)
|
||||
key$ = ParseKey$(s$)
|
||||
value$ = trim$(Mid$(s$,len(key$) + 1))
|
||||
if Left$( value$,1) = "=" then value$ = trim$(Mid$(value$,2)) 'optional =
|
||||
count = count + 1
|
||||
confKeys$(count) = upper$(key$)
|
||||
confValues$(count) = value$
|
||||
end if
|
||||
wend
|
||||
close #f
|
||||
ParseConfiguration = count
|
||||
end function
|
||||
|
||||
function ParseKey$(s$)
|
||||
'key is the first word in s$, delimited by whitespace or =
|
||||
s$ = word$(s$, 1)
|
||||
ParseKey$ = trim$(word$(s$, 1, "="))
|
||||
end function
|
||||
|
||||
|
||||
function GetOption$( key$, optionCount)
|
||||
index = Find.confKeys( 1, optionCount, key$)
|
||||
if index > 0 then GetOption$ =(confValues$(index))
|
||||
end function
|
||||
|
||||
|
||||
function HasOption(key$, optionCount)
|
||||
HasOption = Find.confKeys( 1, optionCount, key$) > 0
|
||||
end function
|
||||
|
||||
function Find.confKeys( Start, Finish, value$)
|
||||
Find.confKeys = -1
|
||||
for i = Start to Finish
|
||||
if confKeys$(i) = value$ then Find.confKeys = i : exit for
|
||||
next i
|
||||
end function
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
conf = {}
|
||||
|
||||
fp = io.open( "conf.txt", "r" )
|
||||
|
||||
for line in fp:lines() do
|
||||
line = line:match( "%s*(.+)" )
|
||||
if line and line:sub( 1, 1 ) ~= "#" and line:sub( 1, 1 ) ~= ";" then
|
||||
option = line:match( "%S+" ):lower()
|
||||
value = line:match( "%S*%s*(.*)" )
|
||||
|
||||
if not value then
|
||||
conf[option] = true
|
||||
else
|
||||
if not value:find( "," ) then
|
||||
conf[option] = value
|
||||
else
|
||||
value = value .. ","
|
||||
conf[option] = {}
|
||||
for entry in value:gmatch( "%s*(.-)," ) do
|
||||
conf[option][#conf[option]+1] = entry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
fp:close()
|
||||
|
||||
|
||||
print( "fullname = ", conf["fullname"] )
|
||||
print( "favouritefruit = ", conf["favouritefruit"] )
|
||||
if conf["needspeeling"] then print( "needspeeling = true" ) else print( "needspeeling = false" ) end
|
||||
if conf["seedsremoved"] then print( "seedsremoved = true" ) else print( "seedsremoved = false" ) end
|
||||
if conf["otherfamily"] then
|
||||
print "otherfamily:"
|
||||
for _, entry in pairs( conf["otherfamily"] ) do
|
||||
print( "", entry )
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
function R = readconf(configfile)
|
||||
% READCONF reads configuration file.
|
||||
%
|
||||
% The value of boolean parameters can be tested with
|
||||
% exist(parameter,'var')
|
||||
|
||||
if nargin<1,
|
||||
configfile = 'q.conf';
|
||||
end;
|
||||
|
||||
fid = fopen(configfile);
|
||||
if fid<0, error('cannot open file %s\n',a); end;
|
||||
|
||||
while ~feof(fid)
|
||||
line = strtrim(fgetl(fid));
|
||||
if isempty(line) || all(isspace(line)) || strncmp(line,'#',1) || strncmp(line,';',1),
|
||||
; % no operation
|
||||
else
|
||||
[var,tok] = strtok(line,' \t=');
|
||||
var = upper(var);
|
||||
if any(tok==','),
|
||||
k = 1;
|
||||
while (1)
|
||||
[val, tok]=strtok(tok,',');
|
||||
R.(var){k} = strtrim(val); % return value of function
|
||||
eval(sprintf('%s{%i}=''%s'';',var,k,strtrim(val))); % stores variable in local workspace
|
||||
if isempty(tok), break; end;
|
||||
k=k+1;
|
||||
end;
|
||||
else
|
||||
tok = strtrim(tok);
|
||||
R.(var) = tok; % return value of function
|
||||
eval(sprintf('%s=''%s''; ',var,tok)); % stores variable in local workspace
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
fclose(fid);
|
||||
whos, % shows the parameter in the local workspace
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
#use "topfind"
|
||||
#require "inifiles"
|
||||
open Inifiles
|
||||
|
||||
let print_field ini (label, field) =
|
||||
try
|
||||
let v = ini#getval "params" field in
|
||||
Printf.printf "%s: %s\n" label v
|
||||
with Invalid_element _ ->
|
||||
Printf.printf "%s: not defined\n" label
|
||||
|
||||
let () =
|
||||
let ini = new inifile "./conf.ini" in
|
||||
let lst = [
|
||||
"Full name", "FULLNAME";
|
||||
"likes", "FAVOURITEFRUIT";
|
||||
"needs peeling", "NEEDSPEELING";
|
||||
"seeds removed", "SEEDSREMOVED";
|
||||
] in
|
||||
List.iter (print_field ini) lst;
|
||||
|
||||
let v = ini#getaval "params" "OTHERFAMILY" in
|
||||
print_endline "other family:";
|
||||
List.iter (Printf.printf "- %s\n") v;
|
||||
;;
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
set: procedure options (main);
|
||||
declare text character (100) varying;
|
||||
declare (fullname, favouritefruit) character (100) varying initial ('');
|
||||
declare needspeeling bit (1) static initial ('0'b);
|
||||
declare seedsremoved bit (1) static initial ('0'b);
|
||||
declare otherfamily(10) character (100) varying;
|
||||
declare (i, j) fixed binary;
|
||||
declare in file;
|
||||
|
||||
open file (in) title ( '/RD-CON.DAT,TYPE(TEXT),RECSIZE(200)' );
|
||||
|
||||
on endfile (in) go to variables;
|
||||
|
||||
otherfamily = ''; j = 0;
|
||||
|
||||
do forever;
|
||||
get file (in) edit (text) (L);
|
||||
text = trim(text);
|
||||
|
||||
if length(text) = 0 then iterate;
|
||||
if substr(text, 1, 1) = ';' then iterate;
|
||||
if substr(text, 1, 1) = '#' then iterate;
|
||||
if length(text) >= 9 then
|
||||
if substr(text, 1, 9) = 'FULLNAME ' then
|
||||
fullname = trim( substr(text, 9) );
|
||||
if length(text) >= 15 then
|
||||
if substr(text, 1, 15) = 'FAVOURITEFRUIT ' then
|
||||
favouritefruit = trim( substr(text, 15) );
|
||||
if length(text) >= 12 then
|
||||
if text = 'NEEDSPEELING' then needspeeling = '1'b;
|
||||
if length(text) >= 12 then
|
||||
if text = 'SEEDSREMOVED' then seedsremoved = '1'b;
|
||||
if length(text) >= 12 then
|
||||
if substr(text, 1, 12) = 'OTHERFAMILY ' then
|
||||
do;
|
||||
text = trim(substr(text, 12) );
|
||||
i = index(text, ',');
|
||||
do while (i > 0);
|
||||
j = j + 1;
|
||||
otherfamily(j) = substr(text, 1, i-1);
|
||||
text = trim(substr(text, i+1));
|
||||
i = index(text, ',');
|
||||
end;
|
||||
j = j + 1;
|
||||
otherfamily(j) = trim(text);
|
||||
end;
|
||||
end;
|
||||
|
||||
variables:
|
||||
put skip data (fullname);
|
||||
put skip data (favouritefruit);
|
||||
put skip data (needspeeling);
|
||||
put skip data (seedsremoved);
|
||||
do i = 1 to j;
|
||||
put skip data (otherfamily(i));
|
||||
end;
|
||||
|
||||
end set;
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
#!/usr/bin/instantfpc
|
||||
|
||||
{$if not defined(fpc) or (fpc_fullversion < 20600)}
|
||||
{$error FPC 2.6.0 or greater required}
|
||||
{$endif}
|
||||
|
||||
{$mode objfpc}{$H+}
|
||||
|
||||
uses
|
||||
Classes,SysUtils,gvector,ghashmap;
|
||||
|
||||
type
|
||||
TStrHashCaseInsensitive = class
|
||||
class function hash(s: String; n: Integer): Integer;
|
||||
end;
|
||||
|
||||
class function TStrHashCaseInsensitive.hash(s: String; n: Integer): Integer;
|
||||
var
|
||||
x: Integer;
|
||||
c: Char;
|
||||
begin
|
||||
x := 0;
|
||||
for c in UpCase(s) do Inc(x,Ord(c));
|
||||
Result := x mod n;
|
||||
end;
|
||||
|
||||
type
|
||||
TConfigValues = specialize TVector<String>;
|
||||
TConfigStorage = class(specialize THashMap<String,TConfigValues,TStrHashCaseInsensitive>)
|
||||
destructor Destroy; override;
|
||||
end;
|
||||
|
||||
destructor TConfigStorage.Destroy;
|
||||
var
|
||||
It: TIterator;
|
||||
begin
|
||||
if Size > 0 then begin
|
||||
It := Iterator;
|
||||
repeat
|
||||
It.Value.Free;
|
||||
until not It.Next;
|
||||
It.Free;
|
||||
end;
|
||||
inherited Destroy;
|
||||
end;
|
||||
|
||||
var
|
||||
ConfigStrings,ConfigValues: TStrings;
|
||||
ConfigStorage: TConfigStorage;
|
||||
ConfigLine,ConfigName,ConfigValue: String;
|
||||
SeparatorPos: Integer;
|
||||
begin
|
||||
ConfigStrings := TStringList.Create;
|
||||
ConfigValues := TStringList.Create;
|
||||
ConfigValues.Delimiter := ',';
|
||||
ConfigValues.StrictDelimiter := true;
|
||||
ConfigStorage := TConfigStorage.Create;
|
||||
|
||||
ConfigStrings.LoadFromFile('config.test');
|
||||
for ConfigLine in ConfigStrings do begin
|
||||
if Length(ConfigLine) > 0 then begin
|
||||
case ConfigLine[1] of
|
||||
'#',';': ; // ignore
|
||||
else begin
|
||||
// look for = first
|
||||
SeparatorPos := Pos('=',ConfigLine);
|
||||
// if not found, then look for space
|
||||
if SeparatorPos = 0 then begin
|
||||
SeparatorPos := Pos(' ',ConfigLine);
|
||||
end;
|
||||
// found space
|
||||
if SeparatorPos <> 0 then begin
|
||||
ConfigName := UpCase(Copy(ConfigLine,1,SeparatorPos - 1));
|
||||
ConfigValues.DelimitedText := Copy(ConfigLine,SeparatorPos + 1,Length(ConfigLine) - SeparatorPos);
|
||||
// no = or space found, take the whole line as a key name
|
||||
end else begin
|
||||
ConfigName := UpCase(Trim(ConfigLine));
|
||||
end;
|
||||
if not ConfigStorage.Contains(ConfigName) then begin
|
||||
ConfigStorage[ConfigName] := TConfigValues.Create;
|
||||
end;
|
||||
for ConfigValue in ConfigValues do begin
|
||||
ConfigStorage[ConfigName].PushBack(Trim(ConfigValue));
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
WriteLn('FULLNAME = ' + ConfigStorage['FULLNAME'][0]);
|
||||
WriteLn('FAVOURITEFRUIT = ' + ConfigStorage['FAVOURITEFRUIT'][0]);
|
||||
WriteLn('NEEDSPEELING = ' + BoolToStr(ConfigStorage.Contains('NEEDSPEELING'),true));
|
||||
WriteLn('SEEDSREMOVED = ' + BoolToStr(ConfigStorage.Contains('SEEDSREMOVED'),true));
|
||||
WriteLn('OTHERFAMILY(1) = ' + ConfigStorage['OTHERFAMILY'][0]);
|
||||
WriteLn('OTHERFAMILY(2) = ' + ConfigStorage['OTHERFAMILY'][1]);
|
||||
|
||||
ConfigStorage.Free;
|
||||
ConfigValues.Free;
|
||||
ConfigStrings.Free;
|
||||
end.
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
my $fullname;
|
||||
my $favouritefruit;
|
||||
my $needspeeling = False;
|
||||
my $seedsremoved = False;
|
||||
my @otherfamily;
|
||||
|
||||
grammar ConfFile {
|
||||
token TOP {
|
||||
:my $*linenum = 0;
|
||||
^ <fullline>* [$ || (\N*) { die "Parse failed at $0" } ]
|
||||
}
|
||||
|
||||
token fullline {
|
||||
<?before .>
|
||||
{ ++$*linenum }
|
||||
<line>
|
||||
[ \n || { die "Parse failed at line $*linenum" } ]
|
||||
}
|
||||
|
||||
proto token line() {{*}}
|
||||
|
||||
token line:misc { {} (\S+) { die "Unrecognized word: $0" } }
|
||||
|
||||
token line:sym<comment> { ^^ [ ';' | '#' ] \N* }
|
||||
token line:sym<blank> { ^^ \h* $$ }
|
||||
|
||||
token line:sym<fullname> {:i fullname» <rest> { $fullname = $<rest>[0].trim } }
|
||||
token line:sym<favouritefruit> {:i favouritefruit» <rest> { $favouritefruit = $<rest>[0].trim } }
|
||||
token line:sym<needspeeling> {:i needspeeling» <yes> { $needspeeling = defined $<yes>[0] } }
|
||||
token rest { \h* '='? (\N*) }
|
||||
token yes { :i \h* '='? \h*
|
||||
[
|
||||
|| ([yes|true|1])
|
||||
|| [no|false|0]
|
||||
|| (<?>)
|
||||
] \h*
|
||||
}
|
||||
}
|
||||
|
||||
grammar MyConfFile is ConfFile {
|
||||
token line:sym<otherfamily> {:i otherfamily» <many> { @otherfamily = $<many>[0]».trim} }
|
||||
token many { \h*'='? ([ <![,]> \N ]*) ** ',' }
|
||||
}
|
||||
|
||||
MyConfFile.parsefile('file.cfg');
|
||||
|
||||
.perl.say for
|
||||
:$fullname,
|
||||
:$favouritefruit,
|
||||
:$needspeeling,
|
||||
:$seedsremoved,
|
||||
:@otherfamily;
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
my $fullname;
|
||||
my $favouritefruit;
|
||||
my $needspeeling;
|
||||
my $seedsremoved;
|
||||
my @otherfamily;
|
||||
|
||||
# configuration file definition. See read_conf_file below for explanation.
|
||||
my $conf_definition = {
|
||||
'fullname' => [ 'string', \$fullname ],
|
||||
'favouritefruit' => [ 'string', \$favouritefruit ],
|
||||
'needspeeling' => [ 'boolean', \$needspeeling ],
|
||||
'seedsremoved' => [ 'boolean', \$seedsremoved ],
|
||||
'otherfamily' => [ 'array', \@otherfamily ],
|
||||
};
|
||||
|
||||
my $arg = shift; # take the configuration file name from the command line
|
||||
# (or first subroutine argument if this were in a sub)
|
||||
my $file; # this is going to be a file handle reference
|
||||
open $file, $arg or die "Can't open configuration file '$arg': $!";
|
||||
|
||||
read_conf_file($file, $conf_definition);
|
||||
|
||||
print "fullname = $fullname\n";
|
||||
print "favouritefruit = $favouritefruit\n";
|
||||
print "needspeeling = ", ($needspeeling ? 'true' : 'false'), "\n";
|
||||
print "seedsremoved = ", ($seedsremoved ? 'true' : 'false'), "\n";
|
||||
for (my $i = 0; $i < @otherfamily; ++$i) {
|
||||
print "otherfamily(", $i + 1, ") = ", $otherfamily[$i], "\n";
|
||||
}
|
||||
|
||||
# read_conf_file: Given a file handle opened for reading and a configuration definition,
|
||||
# read the file.
|
||||
# If the configuration file doesn't match the definition, raise an exception with "die".
|
||||
# The configuration definition is (a reference to) an associative array
|
||||
# where the keys are the configuration variable names in all lower case
|
||||
# and the values are references to arrays.
|
||||
# The first element of each of these arrays is the expected type: 'boolean', 'string', or 'array';
|
||||
# the second element is a reference to the variable that should be assigned the data.
|
||||
sub read_conf_file {
|
||||
my ($fh, $def) = @_; # copy parameters
|
||||
|
||||
local $_; # avoid interfering with use of $_ in main program
|
||||
while (<$fh>) { # read a line from $fh into $_ until end of file
|
||||
next if /^#/; # skip "#" comments
|
||||
next if /^;/; # skip ";" comments
|
||||
next if /^$/; # skip blank lines
|
||||
chomp; # strip final newline
|
||||
|
||||
$_ =~ /^\s*(\w+)\s*(.*)$/i or die "Syntax error";
|
||||
my $key = $1;
|
||||
my $rest = $2;
|
||||
$key =~ tr/[A-Z]/[a-z]/; # convert keyword to lower case
|
||||
|
||||
if (!exists $def->{$key}) {
|
||||
die "Unknown keyword: '$key'";
|
||||
}
|
||||
|
||||
if ($def->{$key}[0] eq 'boolean') {
|
||||
if ($rest) {
|
||||
die "Syntax error: extra data following boolean '$key'";
|
||||
}
|
||||
${$def->{$key}[1]} = 1;
|
||||
next; # done with this line, go back to "while"
|
||||
}
|
||||
|
||||
$rest =~ s/\s*$//; # drop trailing whitespace
|
||||
$rest =~ s/^=\s*//; # drop equals sign if present
|
||||
|
||||
if ($def->{$key}[0] eq 'string') {
|
||||
${$def->{$key}[1]} = $rest;
|
||||
} elsif ($def->{$key}[0] eq 'array') {
|
||||
@{$def->{$key}[1]} = split /\s*,\s*/, $rest;
|
||||
} else {
|
||||
die "Internal error (unknown type in configuration definition)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
(de rdConf (File)
|
||||
(pipe (in File (while (echo "#" ";") (till "^J")))
|
||||
(while (read)
|
||||
(set @ (or (line T) T)) ) ) )
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
(off FULLNAME FAVOURITEFRUIT NEEDSPEELING SEEDSREMOVED OTHERFAMILY)
|
||||
(rdConf "conf.txt")
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<@ DEFUDRLIT>__ReadConfigurationFile|
|
||||
<@ LETSCPPNTPARSRC>Data|1</@><@ OMT> read file into locally scope variable</@>
|
||||
<@ LETCGDLSTLLOSCP>List|Data</@><@ OMT> split Data into a list of lines </@>
|
||||
<@ OMT> Remove comment lines, and blank lines </@>
|
||||
<@ ACTOVRBEFLSTLIT>List|;</@>
|
||||
<@ ACTOVRBEFLSTLIT>List|#</@>
|
||||
<@ ACTRMELST>List</@>
|
||||
<@ OMT> Iterate over the lines of the list </@>
|
||||
<@ ITEENULSTLit>List|
|
||||
<@ LETVARUPTVALLSTLIT>key|...| </@>
|
||||
<@ LETVARAFTVALLSTLIT>val|...| </@>
|
||||
<@ OMT> test for an empty key (in the case of a boolean) </@>
|
||||
<@ TSTVARLIT>key|</@>
|
||||
<@ IFE><@ LETPNTVARVARLIT>val|__True</@></@>
|
||||
<@ ELS>
|
||||
<@ TSTGT0ATBVARLIT>val|,</@>
|
||||
<@ IFE><@ ACTEXEEMMCAP><&prot; LETCNDLSTLITLIT>&key;&pipe;&val;&pipe;, </&prot;></@></@>
|
||||
<@ ELS><@ LETPNTVARVARVAR>key|val</@></@>
|
||||
</@>
|
||||
</@>
|
||||
</@>
|
||||
|
||||
<@ ACTUDRLIT>__ReadConfigurationFile|c:\rosetta.config</@>
|
||||
<@ SAYVAR>FAVOURITEFRUIT</@>
|
||||
<@ SAYVAR>FULLNAME</@>
|
||||
<@ SAYVAR>NEEDSPEELING</@>
|
||||
<@ SAYDMPLST>OTHERFAMILY</@>
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
def readconf(fn):
|
||||
ret = {}
|
||||
with file(fn) as fp:
|
||||
for line in fp:
|
||||
# Assume whitespace is ignorable
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'): continue
|
||||
|
||||
boolval = True
|
||||
# Assume leading ";" means a false boolean
|
||||
if line.startswith(';'):
|
||||
# Remove one or more leading semicolons
|
||||
line = line.lstrip(';')
|
||||
# If more than just one word, not a valid boolean
|
||||
if len(line.split()) != 1: continue
|
||||
boolval = False
|
||||
|
||||
bits = line.split(None, 1)
|
||||
if len(bits) == 1:
|
||||
# Assume booleans are just one standalone word
|
||||
k = bits[0]
|
||||
v = boolval
|
||||
else:
|
||||
# Assume more than one word is a string value
|
||||
k, v = bits
|
||||
ret[k.lower()] = v
|
||||
return ret
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
conf = readconf(sys.argv[1])
|
||||
for k, v in sorted(conf.items()):
|
||||
print k, '=', v
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
/*REXX program to read a config file and assign VARs as found within. */
|
||||
signal on syntax; signal on novalue /*handle REXX program errors. */
|
||||
parse arg cFID _ . /*cFID = config file to be read. */
|
||||
if cFID=='' then cFID='CONFIG.DAT' /*Not specified? Use the default*/
|
||||
bad= /*this will contain all bad VARs.*/
|
||||
varList= /*this will contain all the VARs.*/
|
||||
maxLenV=0; blanks=0; hashes=0; semics=0; badVar=0 /*zero 'em.*/
|
||||
|
||||
do j=0 while lines(cFID)\==0 /*J count's the file's lines. */
|
||||
txt=strip(linein(cFID)) /*read a line (record) from file,*/
|
||||
/*& strip leading/trailing blanks*/
|
||||
if txt ='' then do; blanks=blanks+1; iterate; end
|
||||
if left(txt,1)=='#' then do; hashes=hashes+1; iterate; end
|
||||
if left(txt,1)==';' then do; semics=semics+1; iterate; end
|
||||
eqS=pos('=',txt) /*can't use the TRANSLATE bif. */
|
||||
if eqS\==0 then txt=overlay(' ',txt,eqS) /*replace 1st '=' with blank*/
|
||||
parse var txt xxx value; upper xxx /*get the variableName and value.*/
|
||||
value=strip(value) /*strip leading & trailing blanks*/
|
||||
varList=varList xxx /*add it to the list of vARiables*/
|
||||
if value='' then value='true' /*if no value, then use "true". */
|
||||
if symbol(xxx)=='BAD' then do /*can REXX use the variable name?*/
|
||||
badVar=badVar+1; bad=bad xxx; iterate
|
||||
end
|
||||
call value xxx,value /*now, use VALUE to set the var. */
|
||||
maxLenV=max(maxLenV,length(value)) /*maxLen of varNames, pretty disp*/
|
||||
end /*j*/
|
||||
|
||||
vars=words(varList)
|
||||
say #(j) 'record's(j) "were read from file: " cFID
|
||||
if blanks\==0 then say #(blanks) 'blank record's(blanks) "were read."
|
||||
if hashes\==0 then say #(hashes) 'record's(hashes) "ignored that began with a # (hash)."
|
||||
if semics\==0 then say #(semics) 'record's(semics) "ignored that began with a ; (semicolon)."
|
||||
if badVar\==0 then say #(badVar) 'bad variable name's(badVar) 'detected:' bad
|
||||
say; say 'The list of' vars "variable"s(vars) 'and' s(vars,'their',"it's") "value"s(vars) 'follows:'; say
|
||||
|
||||
do k=1 for vars
|
||||
v=word(varList,k)
|
||||
say right(v,maxLenV) '=' value(v)
|
||||
end /*k*/
|
||||
exit /*stick a fork in it, we're done.*/
|
||||
/*───────────────────────────────error handling subroutines and others.─*/
|
||||
s: if arg(1)==1 then return arg(3); return word(arg(2) 's',1)
|
||||
#: return right(arg(1),length(j)+11) /*right justify a number +indent*/
|
||||
err: say; say; say center(' error! ', max(40, linesize()%2), "*"); say
|
||||
do j=1 for arg(); say arg(j); say; end; say; exit 13
|
||||
novalue: syntax: call err 'REXX program' condition('C') "error",,
|
||||
condition('D'),'REXX source statement (line' sigl"):",sourceline(sigl)
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
#!/usr/bin/rexx
|
||||
/*.----------------------------------------------------------------------.*/
|
||||
/*|readconfig: Read keyword value pairs from a configuration file into |*/
|
||||
/*| Rexx variables. |*/
|
||||
/*| |*/
|
||||
/*|Usage: |*/
|
||||
/*| .-~/rosetta.conf-. |*/
|
||||
/*|>>-readconfig-+----------------+------------------------------------><|*/
|
||||
/*| |-configfilename-| |*/
|
||||
/*| |-- -? ----------| |*/
|
||||
/*| |-- -h ----------| |*/
|
||||
/*| '- --help -------' |*/
|
||||
/*| |*/
|
||||
/*|where |*/
|
||||
/*| configfilename |*/
|
||||
/*| is the name of the configuration file to be processed. if not|*/
|
||||
/*| specified, ~/rosetta.conf is used. |*/
|
||||
/*| |*/
|
||||
/*|All values retrieved from the configuration file are stored in |*/
|
||||
/*|compound variables with the stem config. Variables with multiple |*/
|
||||
/*|values have a numeric index appended, and the highest index number |*/
|
||||
/*|is stored in the variable with index 0; e.g. if CONFIG.OTHERFAMILY.1 |*/
|
||||
/*|and CONFIG.OTHERFAMILY.2 have values assigned, CONFIG.OTHERFAMILY.0 = |*/
|
||||
/*|2. |*/
|
||||
/*|-?, -h or --help all cause this documentation to be displayed. |*/
|
||||
/*| |*/
|
||||
/*|This program was tested using Open Object Rexx 4.1.1. It should work |*/
|
||||
/*|with most other dialects as well. |*/
|
||||
/*'----------------------------------------------------------------------'*/
|
||||
call usage arg(1)
|
||||
trace normal
|
||||
signal on any name error
|
||||
|
||||
/* Prepare for processing the configuration file. */
|
||||
keywords = 'FULLNAME FAVOURITEFRUIT NEEDSPEELING SEEDSREMOVED OTHERFAMILY'
|
||||
|
||||
/* Set default values for configuration variables here */
|
||||
config_single?. = 1
|
||||
config. = ''
|
||||
config.NEEDSPEELING = 0
|
||||
config.SEEDSREMOVED = 1
|
||||
|
||||
/* Validate command line inputs. */
|
||||
parse arg configfilename
|
||||
|
||||
if length(configfilename) = 0 then
|
||||
configfilename = '~/rosetta.conf'
|
||||
|
||||
configfile = stream(configfilename,'COMMAND','QUERY EXISTS')
|
||||
|
||||
if length(configfile) = 0 then
|
||||
do
|
||||
say configfilename 'was not found.'
|
||||
exit 28
|
||||
end
|
||||
|
||||
signal on notready /* if an I/O error occurs. */
|
||||
|
||||
/* Open the configuration file. */
|
||||
response = stream(configfile,'COMMAND','OPEN READ SHARED')
|
||||
|
||||
/* Parse the contents of the configuration file into variables. */
|
||||
do while lines(configfile) > 0
|
||||
statement = linein(configfile)
|
||||
|
||||
select
|
||||
when left(statement,1) = '#',
|
||||
| left(statement,1) = ';',
|
||||
| length(strip(statement)) = 0,
|
||||
then /* a comment or a blank line. */
|
||||
nop /* skip it. */
|
||||
|
||||
otherwise
|
||||
do
|
||||
if pos('=',word(statement,1)) > 0,
|
||||
| left(word(statement,2),1) = '=',
|
||||
then /* a keyword/value pair with = between. */
|
||||
parse var statement keyword '=' value
|
||||
|
||||
else /* a keyword/value pair with no =. */
|
||||
parse var statement keyword value
|
||||
|
||||
keyword = translate(strip(keyword)) /* make it uppercase. */
|
||||
single? = pos(',',value) = 0 /* a single value, or multiple values? */
|
||||
call value 'CONFIG_single?.'keyword,single? /* remember. */
|
||||
|
||||
if single? then
|
||||
do
|
||||
if length(value) > 0 then
|
||||
call value 'CONFIG.'keyword,strip(value)
|
||||
end /* strip keeps internal whitespace only. */
|
||||
|
||||
else /* store each value with its index. */
|
||||
do v = 1 by 1 while length(value) > 0
|
||||
parse var value value1 ',' value
|
||||
|
||||
if length(value1) > 0 then
|
||||
do
|
||||
call value 'CONFIG.'keyword'.'v,strip(value1)
|
||||
call value 'CONFIG.'keyword'.0',v /* remember this. */
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
/* Display the values of the configuration variables. */
|
||||
say 'Values associated with configuration file' configfilename':'
|
||||
say
|
||||
|
||||
do while words(keywords) > 0
|
||||
parse var keywords keyword keywords
|
||||
|
||||
if value('CONFIG_single?.'keyword) then
|
||||
say right(keyword,20) '= "'value('CONFIG.'keyword)'"'
|
||||
|
||||
else
|
||||
do
|
||||
lastv = value('CONFIG.'keyword'.0')
|
||||
|
||||
do v = 1 to lastv
|
||||
say right(keyword,20-(length(v)+2))'['v'] = "'value('CONFIG.'keyword'.'v)'"'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
say
|
||||
|
||||
notready: /* I/O errors come here. */
|
||||
filestatus = stream(configfile,'STATE')
|
||||
|
||||
if filestatus \= 'READY' then
|
||||
say 'An I/O error occurred; the file status is' filestatus'.'
|
||||
|
||||
response = stream(configfile,'COMMAND','CLOSE')
|
||||
|
||||
error:
|
||||
/*? = sysdumpvariables() */ /* see everything Rexx used. */
|
||||
exit
|
||||
|
||||
usage: procedure
|
||||
trace normal
|
||||
|
||||
if arg(1) = '-h',
|
||||
| arg(1) = '-?',
|
||||
| arg(1) = '--help'
|
||||
then
|
||||
do
|
||||
line = '/*|'
|
||||
say
|
||||
|
||||
do l = 3 by 1 while line~left(3) = '/*|'
|
||||
line = sourceline(l)
|
||||
parse var line . '/*|' text '|*/' .
|
||||
say text
|
||||
end
|
||||
|
||||
say
|
||||
exit 0
|
||||
end
|
||||
return
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
fullname = favouritefruit = needspeeling = seedsremoved = false
|
||||
|
||||
IO.foreach("fruit.conf") do |line|
|
||||
line.chomp!
|
||||
key, value = line.split(nil, 2)
|
||||
case key
|
||||
when /^([#;]|$)/; # ignore line
|
||||
when "FULLNAME"; fullname = value
|
||||
when "FAVOURITEFRUIT"; favouritefruit = value
|
||||
when "NEEDSPEELING"; needspeeling = true
|
||||
when "SEEDSREMOVED"; seedsremoved = true
|
||||
when /^./; puts "#{key}: unknown key"
|
||||
end
|
||||
end
|
||||
|
||||
puts "fullname = #{fullname}"
|
||||
puts "favouritefruit = #{favouritefruit}"
|
||||
puts "needspeeling = #{needspeeling}"
|
||||
puts "seedsremoved = #{seedsremoved}"
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
$ include "seed7_05.s7i";
|
||||
include "scanfile.s7i";
|
||||
|
||||
var string: fullname is "";
|
||||
var string: favouritefruit is "";
|
||||
var boolean: needspeeling is FALSE;
|
||||
var boolean: seedsremoved is FALSE;
|
||||
var array string: otherfamily is 0 times "";
|
||||
|
||||
const proc: main is func
|
||||
local
|
||||
var file: configFile is STD_NULL;
|
||||
var string: symbol is "";
|
||||
var integer: index is 0;
|
||||
begin
|
||||
configFile := open("readcfg.txt", "r");
|
||||
configFile.bufferChar := getc(configFile);
|
||||
symbol := lower(getWord(configFile));
|
||||
while symbol <> "" do
|
||||
skipSpace(configFile);
|
||||
if symbol = "#" or symbol = ";" then
|
||||
skipLine(configFile);
|
||||
elsif symbol = "fullname" then
|
||||
fullname := getLine(configFile);
|
||||
elsif symbol = "favouritefruit" then
|
||||
favouritefruit := getLine(configFile);
|
||||
elsif symbol = "needspeeling" then
|
||||
needspeeling := TRUE;
|
||||
elsif symbol = "seedsremoved" then
|
||||
seedsremoved := TRUE;
|
||||
elsif symbol = "otherfamily" then
|
||||
otherfamily := split(getLine(configFile), ",");
|
||||
for key index range otherfamily do
|
||||
otherfamily[index] := trim(otherfamily[index]);
|
||||
end for;
|
||||
else
|
||||
writeln(" *** Illegal line " <& literal(getLine(configFile)));
|
||||
end if;
|
||||
symbol := lower(getWord(configFile));
|
||||
end while;
|
||||
close(configFile);
|
||||
writeln("fullname: " <& fullname);
|
||||
writeln("favouritefruit: " <& favouritefruit);
|
||||
writeln("needspeeling: " <& needspeeling);
|
||||
writeln("seedsremoved: " <& seedsremoved);
|
||||
for key index range otherfamily do
|
||||
writeln(("otherfamily[" <& index <& "]:") rpad 16 <& otherfamily[index]);
|
||||
end for;
|
||||
end func;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
dict := Dictionary new.
|
||||
configFile asFilename readingLinesDo:[:line |
|
||||
(line isEmpty or:[ line startsWithAnyOf:#('#' ';') ]) ifFalse:[
|
||||
s := line readStream.
|
||||
(s skipSeparators; atEnd) ifFalse:[
|
||||
|optionName values|
|
||||
optionName := s upToSeparator.
|
||||
values := (s upToEnd asCollectionOfSubstringsSeparatedBy:$,)
|
||||
collect:[:each | each withoutSeparators]
|
||||
thenSelect:[:vals | vals notEmpty].
|
||||
dict at:optionName asLowercase put:(values isEmpty
|
||||
ifTrue:[true]
|
||||
ifFalse:[
|
||||
values size == 1
|
||||
ifTrue:[values first]
|
||||
ifFalse:[values]]).
|
||||
]
|
||||
].
|
||||
]
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
dict keysAndValuesDo:[:eachOption :eachValue |
|
||||
someObject
|
||||
perform:(eachOption,':') asSymbol with:eachValue
|
||||
ifNotUnderstood: [ self error: 'unknown option: ', eachOption ]
|
||||
]
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
fullname := dict at: 'fullname' ifAbsent:false.
|
||||
needspeeling := dict at: 'needspeeling' ifAbsent:false.
|
||||
favouritefruit := dict at: 'favouritefruit' ifAbsent:false.
|
||||
otherfamily := dict at: 'otherfamily' ifAbsent:false.
|
||||
seedsremoved := dict at: 'seedsremoved' ifAbsent:false.
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
@(collect)
|
||||
@ (cases)
|
||||
#@/.*/
|
||||
@ (or)
|
||||
;@/.*/
|
||||
@ (or)
|
||||
@{IDENT /[A-Z_][A-Z_0-9]+/}@/ */
|
||||
@(bind VAL ("true"))
|
||||
@ (or)
|
||||
@{IDENT /[A-Z_][A-Z_0-9]+/}@(coll)@/ */@{VAL /[^,]+/}@/ */@(end)
|
||||
@ (or)
|
||||
@{IDENT /[A-Z_][A-Z_0-9]+/}@(coll)@/ */@{VAL /[^, ]+/}@/,? */@(end)
|
||||
@(flatten VAL)
|
||||
@ (or)
|
||||
@/ */
|
||||
@ (or)
|
||||
@ (throw error "bad configuration syntax")
|
||||
@ (end)
|
||||
@(end)
|
||||
@(output)
|
||||
@ (repeat)
|
||||
@IDENT = @(rep)@VAL, @(first){ @VAL, @(last)@VAL };@(single)@VAL;@(end)
|
||||
@ (end)
|
||||
@(end)
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
proc readConfig {filename {defaults {}}} {
|
||||
global cfg
|
||||
# Read the file in
|
||||
set f [open $filename]
|
||||
set contents [read $f]
|
||||
close $f
|
||||
# Set up the defaults, if supplied
|
||||
foreach {var defaultValue} $defaults {
|
||||
set cfg($var) $defaultValue
|
||||
}
|
||||
# Parse the file's contents
|
||||
foreach line [split $contents "\n"] {
|
||||
set line [string trim $line]
|
||||
# Skip comments
|
||||
if {[string match "#*" $line] || [string match ";*" $line]} continue
|
||||
# Skip blanks
|
||||
if {$line eq ""} continue
|
||||
|
||||
if {[regexp {^\w+$} $line]} {
|
||||
# Boolean case
|
||||
set cfg([string tolower $line]) true
|
||||
} elseif {[regexp {^(\w+)\s+([^,]+)$} $line -> var value]} {
|
||||
# Simple value case
|
||||
set cfg([string tolower $var]) $value
|
||||
} elseif {[regexp {^(\w+)\s+(.+)$} $line -> var listValue]} {
|
||||
# List value case
|
||||
set cfg([string tolower $var]) {}
|
||||
foreach value [split $listValue ","] {
|
||||
lappend cfg([string tolower $var]) [string trim $value]
|
||||
}
|
||||
} else {
|
||||
error "malformatted config file: $filename"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Need to supply some default values due to config file grammar ambiguities
|
||||
readConfig "fruit.cfg" {
|
||||
needspeeling false
|
||||
seedsremoved false
|
||||
}
|
||||
puts "Full name: $cfg(fullname)"
|
||||
puts "Favourite: $cfg(favouritefruit)"
|
||||
puts "Peeling? $cfg(needspeeling)"
|
||||
puts "Unseeded? $cfg(seedsremoved)"
|
||||
puts "Family: $cfg(otherfamily)"
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#11 = 0 // needspeeling = FALSE
|
||||
#12 = 0 // seedsremoved = FALSE
|
||||
Reg_Empty(21) // fullname
|
||||
Reg_Empty(22) // favouritefruit
|
||||
Reg_Empty(23) // otherfamily
|
||||
|
||||
File_Open("|(PATH_ONLY)\example.cfg")
|
||||
|
||||
if (Search("|<FULLNAME|s", BEGIN+ADVANCE+NOERR)) {
|
||||
Match("=", ADVANCE) // skip optional '='
|
||||
Reg_Copy_Block(21, CP, EOL_pos)
|
||||
}
|
||||
if (Search("|<FAVOURITEFRUIT|s", BEGIN+ADVANCE+NOERR)) {
|
||||
Match("=", ADVANCE)
|
||||
Reg_Copy_Block(22, CP, EOL_pos)
|
||||
}
|
||||
if (Search("|<OTHERFAMILY|s", BEGIN+ADVANCE+NOERR)) {
|
||||
Match("=", ADVANCE)
|
||||
Reg_Copy_Block(23, CP, EOL_pos)
|
||||
}
|
||||
if (Search("|<NEEDSPEELING|s", BEGIN+ADVANCE+NOERR)) {
|
||||
#11 = 1
|
||||
}
|
||||
if (Search("|<SEEDSREMOVED|s", BEGIN+ADVANCE+NOERR)) {
|
||||
#12 = 1
|
||||
}
|
||||
|
||||
Buf_Quit(OK) // close .cfg file
|
||||
|
||||
// Display the variables
|
||||
Message("needspeeling = ") Num_Type(#11, LEFT)
|
||||
Message("seedsremoved = ") Num_Type(#12, LEFT)
|
||||
Message("fullname = ") Reg_Type(21) TN
|
||||
Message("favouritefruit = ") Reg_Type(22) TN
|
||||
Message("otherfamily = ") Reg_Type(23) TN
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
' Configuration file parser routines.
|
||||
'
|
||||
' (c) Copyright 1993 - 2011 Mark Hobley
|
||||
'
|
||||
' This configuration parser contains code ported from an application program
|
||||
' written in Microsoft Quickbasic
|
||||
'
|
||||
' This code can be redistributed or modified under the terms of version 1.2 of
|
||||
' the GNU Free Documentation Licence as published by the Free Software Foundation.
|
||||
|
||||
Sub readini()
|
||||
var.filename = btrim$(var.winpath) & ini.inifile
|
||||
var.filebuffersize = ini.inimaxlinelength
|
||||
Call openfileread
|
||||
If flg.error = "Y" Then
|
||||
flg.abort = "Y"
|
||||
Exit Sub
|
||||
End If
|
||||
If flg.exists <> "Y" Then
|
||||
flg.abort = "Y"
|
||||
Exit Sub
|
||||
End If
|
||||
var.inistream = var.stream
|
||||
readinilabela:
|
||||
Call readlinefromfile
|
||||
If flg.error = "Y" Then
|
||||
flg.abort = "Y"
|
||||
Call closestream
|
||||
flg.error = "Y"
|
||||
Exit Sub
|
||||
End If
|
||||
If flg.endoffile <> "Y" Then
|
||||
iniline$ = message$
|
||||
If iniline$ <> "" Then
|
||||
If Left$(iniline$, 1) <> ini.commentchar AND Left$(iniline$, 1) <> ini.ignorechar Then
|
||||
endofinicommand% = 0
|
||||
For l% = 1 To Len(iniline$)
|
||||
If Mid$(iniline$, l%, 1) < " " Then
|
||||
endofinicommand% = l%
|
||||
End If
|
||||
If Not (endofinicommand%) Then
|
||||
If Mid$(iniline$, l%, 1) = " " Then
|
||||
endofinicommand% = l%
|
||||
End If
|
||||
End If
|
||||
If endofinicommand% Then
|
||||
l% = Len(iniline$)
|
||||
End If
|
||||
Next l%
|
||||
iniarg$ = ""
|
||||
If endofinicommand% Then
|
||||
If endofinicommand% <> Len(iniline$) Then
|
||||
iniarg$ = btrim$(Mid$(iniline$, endofinicommand% + 1))
|
||||
If iniarg$ = "" Then
|
||||
GoTo readinilabelb
|
||||
End If
|
||||
inicommand$ = Left$(iniline$, endofinicommand% - 1)
|
||||
End If
|
||||
Else
|
||||
inicommand$ = btrim$(iniline$)
|
||||
End If
|
||||
readinilabelb:
|
||||
'interpret command
|
||||
inicommand$ = UCase$(inicommand$)
|
||||
Select Case inicommand$
|
||||
Case "FULLNAME"
|
||||
If iniarg$ <> "" Then
|
||||
ini.fullname = iniarg$
|
||||
End If
|
||||
Case "FAVOURITEFRUIT"
|
||||
If iniarg$ <> "" Then
|
||||
ini.favouritefruit = iniarg$
|
||||
End If
|
||||
Case "NEEDSPEELING"
|
||||
ini.needspeeling = "Y"
|
||||
Case "SEEDSREMOVED"
|
||||
ini.seedsremoved = "Y"
|
||||
Case "OTHERFAMILY"
|
||||
If iniarg$ <> "" Then
|
||||
ini.otherfamily = iniarg$
|
||||
CALL familyparser
|
||||
End If
|
||||
Case Else
|
||||
'!! error handling required
|
||||
End Select
|
||||
End If
|
||||
End If
|
||||
GoTo readinilabela
|
||||
End If
|
||||
Call closestream
|
||||
Exit Sub
|
||||
readinierror:
|
||||
|
||||
End Sub
|
||||
|
||||
Sub openfileread()
|
||||
flg.streamopen = "N"
|
||||
Call checkfileexists
|
||||
If flg.error = "Y" Then Exit Sub
|
||||
If flg.exists <> "Y" Then Exit Sub
|
||||
Call getfreestream
|
||||
If flg.error = "Y" Then Exit Sub
|
||||
var.errorsection = "Opening File"
|
||||
var.errordevice = var.filename
|
||||
If ini.errortrap = "Y" Then
|
||||
On Local Error GoTo openfilereaderror
|
||||
End If
|
||||
flg.endoffile = "N"
|
||||
Open var.filename For Input As #var.stream Len = var.filebuffersize
|
||||
flg.streamopen = "Y"
|
||||
Exit Sub
|
||||
openfilereaderror:
|
||||
var.errorcode = Err
|
||||
Call errorhandler
|
||||
resume '!!
|
||||
End Sub
|
||||
|
||||
Public Sub checkfileexists()
|
||||
var.errorsection = "Checking File Exists"
|
||||
var.errordevice = var.filename
|
||||
If ini.errortrap = "Y" Then
|
||||
On Local Error GoTo checkfileexistserror
|
||||
End If
|
||||
flg.exists = "N"
|
||||
If Dir$(var.filename, 0) <> "" Then
|
||||
flg.exists = "Y"
|
||||
End If
|
||||
Exit Sub
|
||||
checkfileexistserror:
|
||||
var.errorcode = Err
|
||||
Call errorhandler
|
||||
End Sub
|
||||
|
||||
Public Sub getfreestream()
|
||||
var.errorsection = "Opening Free Data Stream"
|
||||
var.errordevice = ""
|
||||
If ini.errortrap = "Y" Then
|
||||
On Local Error GoTo getfreestreamerror
|
||||
End If
|
||||
var.stream = FreeFile
|
||||
Exit Sub
|
||||
getfreestreamerror:
|
||||
var.errorcode = Err
|
||||
Call errorhandler
|
||||
resume '!!
|
||||
End Sub
|
||||
|
||||
Sub closestream()
|
||||
If ini.errortrap = "Y" Then
|
||||
On Local Error GoTo closestreamerror
|
||||
End If
|
||||
var.errorsection = "Closing Stream"
|
||||
var.errordevice = ""
|
||||
flg.resumenext = "Y"
|
||||
Close #var.stream
|
||||
If flg.error = "Y" Then
|
||||
flg.error = "N"
|
||||
'!! Call unexpectederror
|
||||
End If
|
||||
flg.streamopen = "N"
|
||||
Exit Sub
|
||||
closestreamerror:
|
||||
var.errorcode = Err
|
||||
Call errorhandler
|
||||
resume next
|
||||
End Sub
|
||||
|
||||
Sub readlinefromfile()
|
||||
If ini.errortrap = "Y" Then
|
||||
On Local Error GoTo readlinefromfileerror
|
||||
End If
|
||||
If EOF(var.stream) Then
|
||||
flg.endoffile = "Y"
|
||||
Exit Sub
|
||||
End If
|
||||
Line Input #var.stream, tmp$
|
||||
message$ = tmp$
|
||||
Exit Sub
|
||||
readlinefromfileerror:
|
||||
var.errorcode = Err
|
||||
Call errorhandler
|
||||
resume '!!
|
||||
End Sub
|
||||
|
||||
Public Sub errorhandler()
|
||||
tmp$ = btrim$(var.errorsection)
|
||||
tmp2$ = btrim$(var.errordevice)
|
||||
If tmp2$ <> "" Then
|
||||
tmp$ = tmp$ + " (" + tmp2$ + ")"
|
||||
End If
|
||||
tmp$ = tmp$ + " : " + Str$(var.errorcode)
|
||||
tmp1% = MsgBox(tmp$, 0, "Error!")
|
||||
flg.error = "Y"
|
||||
If flg.resumenext = "Y" Then
|
||||
flg.resumenext = "N"
|
||||
' Resume Next
|
||||
Else
|
||||
flg.error = "N"
|
||||
' Resume
|
||||
End If
|
||||
End Sub
|
||||
|
||||
Public Function btrim$(arg$)
|
||||
btrim$ = LTrim$(RTrim$(arg$))
|
||||
End Function
|
||||
Loading…
Add table
Add a link
Reference in a new issue