Permalink
Browse files

initialization commit

Working reader with test
  • Loading branch information...
Ajnasz committed Sep 29, 2010
0 parents commit 4df136510038b09b88d8b2f9a6cdfde65f8aad44
Showing with 640 additions and 0 deletions.
  1. +339 −0 COPYING.GPLv2
  2. +14 −0 README
  3. +193 −0 inireader.js
  4. +14 −0 ize-dos.ini
  5. +1 −0 ize-mac.ini
  6. +14 −0 ize-unix.ini
  7. +65 −0 test.js

Large diffs are not rendered by default.

Oops, something went wrong.
14 README
@@ -0,0 +1,14 @@
+IniReader is a small module for nodejs. You can parse .ini configuration files with it.
+
+// include
+var iniReader = require('./inireader');
+// initialize
+var parser = new iniReader.IniReader('./myconf.ini');
+// get the whole config tree
+parser.getBlock();
+// get only a sub section
+parser.getBlock('blockname');
+// get a config value. The blockname is mandantory
+parser.getValue('blockname', 'key');
+
+
@@ -0,0 +1,193 @@
+
+/**
+ * A simple function to get the file content
+ * line by line
+ */
+var getLines = function(file) {
+ var fs, fd, pos, lines, line;
+
+ fs = require('fs');
+ fd = fs.openSync(file, 0400);
+ pos = 0;
+ lines = [];
+
+ var getLine = function() {
+ var char,
+ line = '';
+
+ do {
+ char = fs.readSync(fd, 1, pos);
+ line += char[0];
+ pos += 1;
+ } while(char[0] !== '\n' && char[0] !== '\r' && char[1]);
+
+ return line;
+ };
+
+ do {
+ line = getLine();
+ lines.push(line);
+ } while(line !== '');
+ fs.closeSync(fd);
+
+ return lines;
+};
+
+/**
+ * If a string is inside quotes, the quotes will be removed
+ * Very simple and not foolproof yet. It doesn't care about
+ * escaped/not escaped strings. So you can have thing like this;
+ * "lorem ipsum" dolor sit"
+ * and you will receive:
+ * lorem ipsum" dolor sit
+ *
+ * FIXME
+ * is it a bug?
+ */
+var fixQuoted = function(str) {
+ if(
+ (str[0] == '"' && str[str.length - 1] == '"') ||
+ (str[0] == "'" && str[str.length - 1] == "'")
+ ) {
+
+ return str.substr(1, str.length - 2);
+ }
+
+ return str;
+
+};
+
+/**
+ * Parses a .ini file and convert's it's content to a JS object
+ * Parser regexps are from the Config::Simple Perl module
+ * @class IniReader
+ * @constructor
+ */
+var IniReader = function(file) {
+ this.lines = getLines(file);
+ this.values = this.parseFile();
+};
+
+IniReader.prototype = {
+ /**
+ * Regexp to get the group names
+ */
+ groupRex: /^\s*\[\s*([^\]]+)\s*\]$/,
+
+ /**
+ * Tries to find a group name in a line
+ * @method groupMatch
+ * @type {String|False}
+ * @returns the group name if found or false
+ */
+ groupMatch: function(line) {
+ var groupMatch = line.match(this.groupRex);
+ return groupMatch ? groupMatch[1] : false;
+ },
+
+ /**
+ * Regexp to get key/value pairs
+ */
+ keyValueRex: /^\s*([^=]*\w)\s*=\s*(.*)\s*$/,
+
+ /**
+ * Tries to find a key/value pair in a line
+ * @method groupMatch
+ * @type {Object|False}
+ * @returns the key value pair in an object ({key: 'key', value;'value'}) if found or false
+ */
+ keyValueMatch: function(line) {
+ var keyValMatch = line.match(this.keyValueRex);
+ return keyValMatch ? {key: keyValMatch[1], value: keyValMatch[2]} : false;
+ },
+
+ /**
+ * Parses an init file, and extracts blocks with keys and values
+ * @method parseFile
+ * @returns the conf tree
+ * @type Object
+ */
+ parseFile: function() {
+
+ var output, lines, skipLineRex, chompRex, trimRex, nonWhitespaceRex,
+ groupName, keyVal, line, currentSection, lineNumber;
+
+ output = {};
+ lines = this.lines;
+
+ // regular expressions to clear, validate and get the values
+ skipLineRex = /^\s*(\n|\#|;)/ ;
+ chompRex = /(?:\n|\r)$/;
+ trimRex = /^\s+|\s+$/g;
+ nonWhitespaceRex = /\S/;
+
+ lineNumber = 0;
+
+ while(line = lines.shift()) {
+
+ lineNumber += 1;
+ // skip comments and empty lines
+ if(skipLineRex.test(line) || !nonWhitespaceRex.test(line)) {
+ continue;
+ }
+
+ line = line.replace(chompRex, '');
+ line = line.replace(trimRex, '');
+
+ // block name
+ groupName = this.groupMatch(line);
+ if(groupName) {
+ currentSection = groupName;
+ if(!output[currentSection]) {
+ output[currentSection] = {};
+ }
+ continue;
+ }
+
+ // key/value pairs
+ keyVal = this.keyValueMatch(line);
+ if(keyVal) {
+ if(currentSection) {
+ output[currentSection][keyVal.key] = fixQuoted(keyVal.value);
+ continue;
+ }
+ }
+
+ // if we came this far, the syntax couldn't be validated
+ throw new Error("syntax error in line " + lineNumber);
+
+ };
+ return output;
+
+ },
+ /**
+ * @method getBlock
+ * @returns A block of the conf tree
+ * @type Object
+ */
+ getBlock: function(block) {
+ return typeof block == 'string' ?
+ this.values[block] :
+ this.values;
+ },
+ /**
+ * @method getValue
+ * @returns the value of the key
+ * @param String block The name of the block where the key should be defined
+ * @param String key The name of the key which value should be returned
+ */
+ getValue: function(block, key) {
+
+ if(typeof(block) != 'string') {
+ throw new Error('block is not a string');
+ }
+
+ var sec = this.getBlock(block);
+
+ if(sec === this.values || typeof(sec) == 'undefined') {
+ throw new Error('block ' + block + ' is undefined');
+ }
+ return sec[key];
+ }
+};
+exports.IniReader = IniReader;
@@ -0,0 +1,14 @@
+
+
+[foo]
+lorem = ipsum
+ipus = foo bar baz
+dolor=sit
+amet=
+
+[bar]
+asdfas=fooobar
+ 1="lorem ipsum"
+2=" lorem ipsum"
+3='lorem ipsum'
+4='lorem ipsum '
@@ -0,0 +1 @@
+[foo]lorem = ipsumipus = foo bar bazdolor=sitamet=[bar]asdfas=fooobar 1= "lorem ipsum"2=" lorem ipsum"3='lorem ipsum'4='lorem ipsum '
@@ -0,0 +1,14 @@
+
+
+[foo]
+lorem = ipsum
+ipus = foo bar baz
+dolor=sit
+amet=
+
+[bar]
+asdfas=fooobar
+ 1= "lorem ipsum"
+2=" lorem ipsum"
+3='lorem ipsum'
+4='lorem ipsum '
65 test.js
@@ -0,0 +1,65 @@
+var assert = require('assert');
+var sys = require('sys');
+var inireader = require('./inireader');
+
+
+var izeConf = new inireader.IniReader('./ize-unix.ini');
+
+assert.equal(typeof(izeConf.getBlock('doesntexists')), 'undefined', 'non existing key doesn\'t returned undefined');
+assert.equal(typeof(izeConf.getBlock('foo')), 'object', 'existing key doesn\'t returned an object');
+assert.equal(typeof(izeConf.getBlock('bar')), 'object', 'existing key doesn\'t returned an object');
+
+assert.deepEqual(izeConf.getValue('foo', 'lorem'), 'ipsum', 'lorem\'s key value in foo conf is not ipsum');
+assert.deepEqual(izeConf.getValue('foo', 'amet'), '', 'amet\'s value should be an empty string');
+assert.equal(typeof(izeConf.getValue('foo', 'doesntexists')), 'undefined', 'value which should not exist returned something else then undefined');
+
+
+assert.deepEqual(izeConf.getValue('bar', 'asdfas'), 'fooobar', 'bad value');
+assert.deepEqual(izeConf.getValue('bar', '1'), 'lorem ipsum');
+assert.deepEqual(izeConf.getValue('bar', '2'), ' lorem ipsum');
+assert.deepEqual(izeConf.getValue('bar', '3'), 'lorem ipsum');
+assert.deepEqual(izeConf.getValue('bar', '4'), 'lorem ipsum ');
+
+sys.puts('unix tests finished');
+
+
+var izeConf = new inireader.IniReader('./ize-dos.ini');
+
+assert.equal(typeof(izeConf.getBlock('doesntexists')), 'undefined', 'non existing key doesn\'t returned undefined');
+assert.equal(typeof(izeConf.getBlock('foo')), 'object', 'existing key doesn\'t returned an object');
+assert.equal(typeof(izeConf.getBlock('bar')), 'object', 'existing key doesn\'t returned an object');
+
+assert.deepEqual(izeConf.getValue('foo', 'lorem'), 'ipsum', 'lorem\'s key value in foo conf is not ipsum');
+assert.deepEqual(izeConf.getValue('foo', 'amet'), '', 'amet\'s value should be an empty string');
+assert.equal(typeof(izeConf.getValue('foo', 'doesntexists')), 'undefined', 'value which should not exist returned something else then undefined');
+
+
+assert.deepEqual(izeConf.getValue('bar', 'asdfas'), 'fooobar', 'bad value');
+assert.deepEqual(izeConf.getValue('bar', '1'), 'lorem ipsum');
+assert.deepEqual(izeConf.getValue('bar', '2'), ' lorem ipsum');
+assert.deepEqual(izeConf.getValue('bar', '3'), 'lorem ipsum');
+assert.deepEqual(izeConf.getValue('bar', '4'), 'lorem ipsum ');
+
+sys.puts('dos tests finished');
+
+
+
+
+var izeConf = new inireader.IniReader('./ize-mac.ini');
+
+assert.equal(typeof(izeConf.getBlock('doesntexists')), 'undefined', 'non existing key doesn\'t returned undefined');
+assert.equal(typeof(izeConf.getBlock('foo')), 'object', 'existing key doesn\'t returned an object');
+assert.equal(typeof(izeConf.getBlock('bar')), 'object', 'existing key doesn\'t returned an object');
+
+assert.deepEqual(izeConf.getValue('foo', 'lorem'), 'ipsum', 'lorem\'s key value in foo conf is not ipsum');
+assert.deepEqual(izeConf.getValue('foo', 'amet'), '', 'amet\'s value should be an empty string');
+assert.equal(typeof(izeConf.getValue('foo', 'doesntexists')), 'undefined', 'value which should not exist returned something else then undefined');
+
+
+assert.deepEqual(izeConf.getValue('bar', 'asdfas'), 'fooobar', 'bad value');
+assert.deepEqual(izeConf.getValue('bar', '1'), 'lorem ipsum');
+assert.deepEqual(izeConf.getValue('bar', '2'), ' lorem ipsum');
+assert.deepEqual(izeConf.getValue('bar', '3'), 'lorem ipsum');
+assert.deepEqual(izeConf.getValue('bar', '4'), 'lorem ipsum ');
+
+sys.puts('mac tests finished');

0 comments on commit 4df1365

Please sign in to comment.