Page 1 of 2

IniFile

Posted: Tue Nov 21, 2006 9:18 pm
by xbytor
Here's my code for working with ini files. I use this all the time and it works well for me. Enjoy!
Code: Select all//
// IniFile.jsx
//
// $Id: IniFile.jsx,v 1.1 2006/11/21 21:15:09 anonymous Exp $
// Contact: xbytor@gmail.com
//

//
// IniFile is a set of functions for reading and writing ini files
// in a consistent fashion across a broad number of scripts.
//
function IniFile(fptr) {
};

//
// Return fptr if its a File or Folder, if not, make it one
//
IniFile.convertFptr = function(fptr) {
  var f;
  if (fptr.constructor == String) {
    f = File(fptr);
  } else if (fptr instanceof File || fptr instanceof Folder) {
    f = fptr;
  } else {
    throw IOError("Bad file \"" + fptr + "\" specified.");
  }
  return f;
};

//
// Return an ini string to an object. Use 'ini' as the object if it's specified
//
IniFile.iniFromString = function(str, ini) {
  var lines = str.split(/\r|\n/);
  var rexp = new RegExp(/([^:]+):(.*)$/);

  if (!ini) {
    ini = {};
  }
   
  for (var i = 0; i < lines.length; i++) {
    var line = IniFile.trim(lines);
    if (!line || line.charAt(0) == '#') {
      continue;
    }
    var ar = rexp.exec(line);
    if (!ar) {
      alert("Bad line in config: \"" + line + "\"");
      return undefined;
    }
    ini[IniFile.trim(ar[1])] = IniFile.trim(ar[2]);
  }

  return ini;
};


//
// Return an ini file to an object. Use 'ini' as the object if it's specified
//
IniFile.read = function(iniFile, ini) {
  if (!ini) {
    ini = {};
  }
  if (!iniFile) {
    return ini;
  }
  var file = IniFile.convertFptr(iniFile);

  if (!file) {
    throw "Bad ini file specified: \"" + iniFile + "\".";
  }

  if (!file.exists) {
  }
  if (file.exists && file.open("r")) {
    var str = file.read();
    ini = IniFile.iniFromString(str, ini);
    file.close();
  }
  return ini;
};

//
// Return an ini string coverted from an object
//
IniFile.iniToString = function(ini) {
  var str = '';
  for (var idx in ini) {
    if (idx.charAt(0) == '_') {         // private stuff
      continue;
    }
    if (idx == 'typename') {
      continue;
    }
    var val = ini[idx];
   
    if (val.constructor == String ||
        val.constructor == Number ||
        val.constructor == Boolean ||
        typeof(val) == "object") {
      str += (idx + ": " + val.toString() + "\n");
    }
  }
  return str;
};

//
// Write an object to an ini file overwriting whatever was there before
//
IniFile.overwrite = function(iniFile, ini) {
  if (!ini || !iniFile) {
    return;
  }
  var file = IniFile.convertFptr.iniFileToFile(iniFile);

  if (!file) {
    throw "Bad ini file specified: \"" + iniFile + "\".";
  }
 
  if (!file.open("w")) {
    throw "Unable to open ini file " + file + ": " + file.error;
  }

  var str = IniString.iniToString(ini);
  file.write(str);
  file.close();

  return ini;
};
IniFile.trim = function(value) {
   return value.replace(/^[\s]+|[\s]+$/g, '');
};


//
// Updating the ini file retains the ini file layout including any externally
// add comments, blank lines, and the property sequence
//
IniFile.update = function(iniFile, ini) {
  if (!ini || !iniFile) {
    return;
  }
  var file = IniFile.convertFptr(iniFile);

  // we can only update the file if it exists
  var update = file.exists;
  var str = '';

  if (update) {
    file.open("r");
    str = file.read();
    file.close();
   
    for (var idx in ini) {
      if (idx.charAt(0) == '_') {         // private stuff
        continue;
      }
      if (idx == "typename") {
        continue;
      }

      var val = ini[idx];

      if (val == undefined) {
        val = '';
      }
     
      if (typeof val == "string" ||
          typeof val == "number" ||
          typeof val == "boolean" ||
          typeof val == "object") {
        idx += ':';
        var re = RegExp('^' + idx, 'm');

        if (re.test(str)) {
          re = RegExp('^' + idx + '[^\n]+', 'm');
          str = str.replace(re, idx + ' ' + val);
        } else {
          str += '\n' + idx + ' ' + val;
        }
      }
    }
  } else {
    str = IniFile.iniToString(ini);
  }

  if (str) {
    if (!file.open("w")) {
      throw "Unable to open ini file " + file + ": " + file.error;
    }
    file.write(str);
    file.close();
  }

  return ini;
};

// By default, I update ini files instead of overwriting them.
IniFile.write = IniFile.update;


// convert an object into an easy-to-read string
listProps = function(obj) {
  var s = '';
  for (var x in obj) {
    s += x + ":\t";
    try {
      var o = obj[x];
      s += (typeof o == "function") ? "[function]" : o;
    } catch (e) {
    }
    s += "\r\n";
  }
  return s;
};


// a simple demo of the INI functions
IniFile.demo1 = function() {
  var obj  = {
    name: "bob",
    age: 24
  };
 
  alert(listProps(obj));

  IniFile.write("~/testfile.ini", obj);

  var z = IniFile.read("~/testfile.ini", obj);

  alert(listProps(z));
};

// a simple demo of the INI functions
IniFile.demo2 = function() {
  var f = new File("~/testfile.ini");

  var obj = {};
  obj.city = "singapore";

  IniFile.read(f, obj);
  var z = IniFile.write(f, obj);

  alert(listProps(z));
};

// IniFile.demo1();
// IniFile.demo2();

"IniFile.jsx";

// EOF

IniFile

Posted: Tue Nov 21, 2006 10:20 pm
by Patrick
Thanks a lot for posting this, I have been wanting to use them for awhile but have been procrastinating on learning how.

Patrick

IniFile

Posted: Wed Nov 22, 2006 7:01 am
by v.bampton
Thanks X. It definitely works on Mac and PC, CS and CS2, so I'm off to study it in detail now!!

IniFile

Posted: Wed Nov 22, 2006 7:45 am
by v.bampton
When I tried to use the Overwrite instead of Update option, I came up with errors on line 115 and 125, missing a couple of functions.

It seems to be fixed by the following, but I haven't studied it in great detail yet - is this right?

It's changed
var file = IniFile.convertFptr.iniFileToFile(iniFile);
to
var file = IniFile.convertFptr(iniFile);
as it didn't recognise iniFileToFile

and
var str = IniString.iniToString(ini);
to
var str = IniFile.iniToString(ini);
as it was missing IniString.

I've just borrowed bits from IniFile.Update, and it works on CS ok - or have I missed the point completely?

Code: Select all//
// Write an object to an ini file overwriting whatever was there before
//
IniFile.overwrite = function(iniFile, ini) {
  if (!ini || !iniFile) {
    return;
  }
  var file = IniFile.convertFptr(iniFile);

  if (!file) {
    throw "Bad ini file specified: \"" + iniFile + "\".";
  }
 
  if (!file.open("w")) {
    throw "Unable to open ini file " + file + ": " + file.error;
  }

  var str = IniFile.iniToString(ini);
  file.write(str);
  file.close();

  return ini;
};
IniFile.trim = function(value) {
   return value.replace(/^[\s]+|[\s]+$/g, '');
};

IniFile

Posted: Wed Nov 22, 2006 8:24 am
by xbytor
Your changes are correct. I extracted this code from another script, renamed and reorganized it, but didn't test 'overwrite' in the process. Thanks for finding these. I'll make the changes to my script.

-X

IniFile

Posted: Wed Nov 22, 2006 8:36 am
by v.bampton
Wow! You mean I got it right!! Excellent!

Thanks for the script X, it's working great!

IniFile

Posted: Sat Dec 09, 2006 8:10 pm
by v.bampton
X, how you do get it to remember checkbox values?

It's working brilliantly on text fields, but it marks all checkboxes as true - any ideas?

IniFile

Posted: Sun Dec 10, 2006 1:11 am
by xbytor
You have to remember that all values are strings. If you need to use them as booleans or numbers, you have to convert them. These are the two functions that I use for this purpose:

Code: Select allfunction toBoolean(s) {
  if (s == undefined) return false;
  if (s.constructor == Boolean) return s.valueOf();
  if (s.constructor == String)  return s.toLowerCase() == "true";
  return Boolean(s);
};

function toNumber(s) {
  if (s == undefined) return NaN;
  if (s.constructor == Number) return s.valueOf();
  return Number(s.toString());
};



If you are trying to set a checkbox value like this:

Code: Select allchk.value = ini.chk;

it will be true if you have "true" or "false" in the ini file. You have to convert it like this:

Code: Select allchk.value = toBoolean(ini.chk);

In scripts where I have a lot of ini settings, I typically have a function called 'rationalize'. This function takes the ini object that I've just read in from the ini file and does all of the conversions to numbers, booleans, Files, Colors, Fonts, or whatever. If I don't do it like this, I'll eventually forget to do the conversion in my code somewhere and I'll wonder when the checkbox is always true.

If you want to take a look at a script that uses these techniques to the extreme, take a look at CSX. Much of what's in IniFile was built in response to the needs of that script.

-X

IniFile

Posted: Sun Dec 10, 2006 1:27 am
by Mike Hale
Here is the lite version

Code: Select allvar b = false
var bStr = b.toString()
!!bStr.match('true')

IniFile

Posted: Sun Dec 10, 2006 8:24 am
by v.bampton
That makes much more sense - thanks for explaining WHY it was happening, as well as how to solve it!