Showing posts with label Unicode. Show all posts
Showing posts with label Unicode. Show all posts

Friday, September 21, 2012

[JScript] Another Config library


I've been doing a fair bit of JScript of late, and as I find working with Registry for runtime configuration a bit tiresome, I've cooked up a Config object. It's defined using the prototype approach to object definition. Config files are, in this case, ANSI or Unicode (UTF16LE) files, in the form
key=value
Creating an instance of the object involves passing in the name of the config file. I've hit upon the following technique for tying the config file to the script, using the FileSystemObject and the WScript object.
var oFSO = new ActiveXObject("Scripting.FileSystemObject"),
    sHere = oFSO.GetParentFolderName(WScript.ScriptFullName),
    sConfig = oFSO.BuildPath(sHere, 
        oFSO.GetBaseName(WScript.ScriptName) + ".config");
That way one may always be sure that (for example) Melchizedek.js will have a Melchizedek.config next to it.

First, the main function

function Config(sFile) {
    this.kind = "";
    this.oFSO = new ActiveXObject("Scripting.FileSystemObject");
    this.text = "";
    var resp = [];
    this.file = sFile;
    if (this.oFSO.FileExists(sFile)) {
        resp = function(oFSO, sFilename) {
            var forReading = 1;
            var asUnicode = -1;
            var asANSI = 0;
            var resp = [];
            if (oFSO.FileExists(sFilename)) {
                var handle = oFSO.OpenTextFile(sFilename, forReading, false,
                        asANSI);
                var BOM = handle.Read(2);
                handle.Close();
                if (BOM.charCodeAt(0) == 0xFF && BOM.charCodeAt(1) == 0xFE) {
                    handle = oFSO.OpenTextFile(sFilename, forReading, false,
                            asUnicode);
                    resp[0] = "unicode";
                } else {
                    handle = oFSO.OpenTextFile(sFilename, forReading, false,
                            asANSI);
                    resp[0] = "ansi";
                }
                resp[1] = handle.ReadAll();
                handle.Close();
                return resp;
            } else {
                return resp;
            }
        }(this.oFSO, sFile);
        this.kind = resp[0];
        this.text = resp[1];
        this.name = sFile;
        this.filefound = true;
    } else {
        this.filefound = false;
    }
    return this.filefound;
}
Note that the code, in an attempt to deal appropriately with config files being in ANSI or UTF-16LE format, reads the first two bytes of the config file. If the UTF16LE BOM is there, it reads the file as Unicode. Otherwise, it reads as ANSI.

A few other things are set so that the other methods will work, namely for exists, name and kind.

Config.prototype.name = function() {
        return this.name;
};

Config.prototype.exists = function() {
        return this.filefound;
};

Config.prototype.kind = function () {
        return this.kind;
};
Next come the main workhorses of the object: define, retrieve and save.
Config.prototype.retrieve = function(sName) {
        if (arguments.length > 1) {
                var sDefault = arguments[1];
        } else {
                sDefault = null;
        }

        var re = new RegExp("^" + sName + "=(.*?)$", "m");
        var arr = re.exec(this.text);
        if (arr === null) {
                return sDefault;
        } else {
                return RegExp.$1;
        }
};

Config.prototype.define = function(sName, sValue) {
        var sNew = sName + "=" + sValue;
        var re = new RegExp("^" + sName + "=(.*?)$", "m");
        var arr = re.exec(this.text);
        if (arr === null) {
                this.text = this.text + "\n" + sNew;
        } else {
                this.text = this.text.replace(re, sNew);
        }
};

Config.prototype.save = function() {
        var sFile = "";
        var handle = "";
        // allow for save to a different file
        if (arguments.length > 0) {
                sFile = arguments[0];
        } else {
                sFile = this.file;
        }
        if (this.kind === "ansi") {
                handle = this.oFSO.CreateTextFile(sFile, true, false);
        } else {
                handle = this.oFSO.CreateTextFile(sFile, true, true);                
        }
        handle.Write(this.text);
        handle.Close();
};
retrieve accepts two parameters: the key in the config store, and the default (in the event that the key is not found.) Rather than using a Scripting.Dictionary, the config data is stored as a string, and regular expressions are used to extract and update it.

define accepts two parameters: the key in the config file, and the value to be associated with it. If the key is not found in the stored keys and values, it is appended to it.

save accepts one optional parameter: the name of the file into which to write the stored string of keys and values. If no name is given, the filename given when Config() was first called is used.

The code may be used as follows:

var c = new Config("dog.cfg");
'the define() will either add or update the store to 
'    sound=bark
c.define("sound","bark");
'the save() will write the store to dog.cfg
c.save();

'Config reloads dog.cfg
var c = new Config("dog.cfg");
'if "sound" is a key in dog.cfg, the associated value will be displayed
'otherwise the default.
WScript.Echo(c.retrieve("sound","woof"));

'display the kind (ansi or unicode)
WScript.Echo(c.kind);
'... whether the file exists
WScript.Echo(c.exists());
'... and what its name is
WScript.Echo(c.name);
The result of running the above code (from within SciTE):
>cscript /nologo Config.js
 bark
 unicode
 -1
 dog.cfg
 >Exit code: 0
I have recently pushed this code through Google's Closure Compiler and the difference in code size is significant -- the result is about 50% smaller than the original. I expect it runs faster too, though I haven't bothered to check it out thoroughly.
function Config(a) {
  this.kind = "";
  this.oFSO = new ActiveXObject("Scripting.FileSystemObject");
  this.text = "";
  var b = [];
  this.file = a;
  if(this.oFSO.FileExists(a)) {
    var b = this.oFSO, d = [];
    if(b.FileExists(a)) {
      var c = b.OpenTextFile(a, 1, !1, 0), e = c.Read(2);
      c.Close();
      255 == e.charCodeAt(0) && 254 == e.charCodeAt(1) ? (c = b.OpenTextFile(a, 1, !1, -1), d[0] = "unicode") : (c = b.OpenTextFile(a, 1, !1, 0), d[0] = "ansi");
      d[1] = c.ReadAll();
      c.Close()
    }
    b = d;
    this.kind = b[0];
    this.text = b[1];
    this.name = a;
    this.filefound = !0
  }else {
    this.filefound = !1
  }
  return this.filefound
}
Config.prototype.name = function() {
  return this.name
};
Config.prototype.exists = function() {
  return this.filefound
};
Config.prototype.kind = function() {
  return this.kind
};
Config.prototype.retrieve = function(a) {
  var b = 1 < arguments.length ? arguments[1] : null;
  return null === RegExp("^" + a + "=(.*?)$", "m").exec(this.text) ? b : RegExp.$1
};
Config.prototype.define = function(a, b) {
  var d = a + "=" + b, c = RegExp("^" + a + "=(.*?)$", "m");
  this.text = null === c.exec(this.text) ? this.text + "\n" + d : this.text.replace(c, d)
};
Config.prototype.save = function() {
  var a = "", a = "", a = 0 < arguments.length ? arguments[0] : this.file, a = "ansi" === this.kind ? this.oFSO.CreateTextFile(a, !0, !1) : this.oFSO.CreateTextFile(a, !0, !0);
  a.Write(this.text);
  a.Close()
};

Enjoy!
© Copyright Bruce M. Axtens, 2012

Tuesday, June 10, 2008

[VBScript] StandardLibrary.zip

For those interested, who haven't been able to download it recently, here's the latest iteration of StandardLibrary.vbs. Now it's called stdlib.vbs and can be obtained from my boost account at the Perth Linux Users Group.

There have been a few changes, mostly additional functions and the odd tweak in favour of better functionality.

Significant in the additions are a few functions for sending emails: Blat, BlatAttachment, ErrorEmail, ErrorEmailApp, RedemptionSend and ThunderbirdSend. If I remember correctly, ErrorEmail has been around for a while, but is included here for completeness sake.













A while back Derek Parnell wrote a replacement for
Euphoria's print function which would show the structure of arrays. ShowStructure and a support routine AsString make this available to the VBScript programmer. By the way, in case you haven't heard, Euphoria is now open-source!



The output, then, from code such as this:
would be
which maybe leads on toward data serialisation ...

There've been some additions to the file handling space, with the addition of routines to read and write unicode files (ReadFileU, WriteFileU, ReadFirstLineU and its ANSI equivalent, ReadFirstLine.)

Logging has been worked on. It's something I'm unlikely to be totally happy with, but there's now a SetLog and a ClearLog as well as the standard Log (and, given the possibility of confusion with the logarithm system, maybe I should change it to Trace (oh man, how many scripts that would break!))

What else? Well, BuildTree builds a directory tree. FirstLineOf returns the first vbNewLine-delimited line from a string (useful where you've used ReadFile or ReadFileU to inhale an entire file.) LastLineOf does what FirstLineOf does but for the end of the file, and NthLineOf gets you the ... nth ... line.

I've actually forgotten what I wrote UpToAndAfter for, but it's included anyway.

IsOnLine uses the ResolveIP function with the IP address 198.182.196.48 (which points somewhere on linux.org) to see if you are still on line.

SetPriority uses the same code as used in BOOST to set process priority.

StrInArray finds a string in an array of strings, with optional case sensitivity.

StringMap scans a string for the presence of items in one array and swaps them for the equivalently indexed elements in the second array. If the second array is a string, they get swapped for that string.

Doze wraps WSCript.Sleep and HTASleep, so that it can be used in .VBS files and .HTA files.

ModalThing2 shows a modal dialog (only works in .HTA files)

And, finally, SoundMessage:


Obviously, if you see something that needs to be fixed, fix it. And tell me to fix it so that it can be fixed in the distribution and your name can be added to the list of contributors.

© Copyright Bruce M. Axtens, 2008

Monday, December 10, 2007

[Ada (GNAT)] A 32bit GNAT.Spitbol.*

It is said that, "a wise man knows his own turnips." In my case, I've run into some difficulty converting GNAT.Spitbol to UTF-32. The compiler error messages are marvellously helpful, but I'm a newbie to Ada and ... yeah, well, you get the idea.

The source code is up on Box.net, if you feel so inclined as to download it and tell me where I'm going wrong.