// -*- c++ -*- /* * Jakelib2 - General purpose C++ library * Copyright (C) 2001 Florian Wolff (florian@donuz.de) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: Properties.jlc,v 1.7 2006-01-16 11:16:31 florian Exp $ */ #include "jakelib2.h" #include "jakelib2/util/Properties.h" #include "jakelib2/io/OutputStreamWriter.h" #include "jakelib2/io/BufferedReader.h" #include "jakelib2/io/BufferedWriter.h" #include "jakelib2/io/FileInputStream.h" #include "jakelib2/io/InputStreamReader.h" #include "jakelib2/io/OutputStreamWriter.h" #include "jakelib2/util/HashEntry.h" #include "jakelib2/lang/Character.h" #include "jakelib2/lang/Integer.h" using namespace jakelib::util; using namespace jakelib::lang; using namespace jakelib::io; JAKELIB_IMPLEMENT_CLASS("jakelib.util.Properties", Properties, Hashtable) #pragma javasyntax /*****************************************************************************\ * Properties | *****************************************************************************/ Properties::Properties() : Hashtable(100, 0.75F) { defaults = null; } Properties::Properties(Properties* defaults) : Hashtable(100, 0.75F) { this->defaults = defaults; } /*****************************************************************************\ * getProperty | *****************************************************************************/ String* Properties::getProperty(String* key) { String* ret = (String*) get(key); if (ret == null) { if (defaults != null) return defaults->getProperty(key); else return null; } else { return ret; } } String* Properties::getProperty(char* key) { String keyStr = String(key); String* ret = getProperty(&keyStr); if (ret == null && defaults != null) { return defaults->getProperty(&keyStr); } else return ret; } String* Properties::getProperty(char* key, char* defaultValue) { String keyStr = String(key); String* ret = getProperty(&keyStr); if (ret == null) { if (defaults != null) { ret = defaults->getProperty(&keyStr); } if (ret == null) return new String(defaultValue); else return ret; } else { return ret; } } String* Properties::getProperty(String* key, String* defaultValue) { String* ret = (String*) get(key); if (ret == null) { String* ret = null; if (defaults != null) ret = defaults->getProperty(key); if (ret == null) return defaultValue; else return ret; } else return ret; } /*****************************************************************************\ * setProperty | *****************************************************************************/ void Properties::setProperty(String* key, String* value) { put(key, value); } void Properties::setProperty(char* key, char* value) { put(new String(key), new String(value)); } /*****************************************************************************\ * load | *****************************************************************************/ void Properties::load(BufferedReader* reader) { String* line; while ((line = reader->readLine()) != null) { jchar c = 0; int pos = 0; // If empty line or begins with a comment character, skip this line. if (line->length() == 0 || line->charAt(0) == '#' || line->charAt(0) == '!') continue; while (pos < line->length() && Character::isWhitespace(c = line->charAt(pos))) pos++; // If line is empty skip this line. if (pos == line->length()) continue; // The characters up to the next Whitespace, ':', or '=' // describe the key. But look for escape sequences. StringBuffer* key = new StringBuffer(); while (pos < line->length() && ! Character::isWhitespace(c = line->charAt(pos++)) && c != '=' && c != ':') { if (c == '\\') { if (pos == line->length()) { // The line continues on the next line. line = reader->readLine(); pos = 0; while (pos < line->length() && Character::isWhitespace(c = line->charAt(pos))) pos++; } else { c = line->charAt(pos++); switch (c) { case 'n': key->append('\n'); break; case 't': key->append('\t'); break; case 'r': key->append('\r'); break; case 'u': if (pos + 4 <= line->length()) { jchar uni = (jchar) Integer::parseInt(line->substring(pos, pos + 4), 16); key->append(uni); pos += 4; } // else throw exception? break; default: key->append(c); break; } } } else { key->append(c); } } jboolean isDelim = (c == ':' || c == '='); while (pos < line->length() && Character::isWhitespace(c = line->charAt(pos))) pos++; if (! isDelim && (c == ':' || c == '=')) { pos++; while (pos < line->length() && Character::isWhitespace(c = line->charAt(pos))) pos++; } StringBuffer* element = new StringBuffer(line->length() - pos); while (pos < line->length()) { c = line->charAt(pos++); if (c == '\\') { if (pos == line->length()) { // The line continues on the next line. line = reader->readLine(); // We might have seen a backslash at the end of // the file. The JDK ignores the backslash in // this case, so we follow for compatibility. if (line == null) break; pos = 0; while (pos < line->length() && Character::isWhitespace(c = line->charAt(pos))) pos++; element->ensureCapacity(line->length() - pos + element->length()); } else { c = line->charAt(pos++); switch (c) { case 'n': element->append('\n'); break; case 't': element->append('\t'); break; case 'r': element->append('\r'); break; case 'u': if (pos + 4 <= line->length()) { char uni = (char) Integer::parseInt (line->substring(pos, pos + 4), 16); element->append(uni); pos += 4; } // else throw exception? break; default: element->append(c); break; } } } else { element->append(c); } } put(key->toString(), element->toString()); } } void Properties::load(char* filename) { FileInputStream input(filename); InputStreamReader streamReader(&input, "latin1"); BufferedReader reader(&streamReader); load(&reader); } void Properties::load(String* filename) { load(filename->latin1()); } /*****************************************************************************\ * store | *****************************************************************************/ void Properties::store(OutputStream* out, String* header) { String* key; String* value; HashEntry* e; OutputStreamWriter writer(out); BufferedWriter bw = BufferedWriter(&writer); bw.write("# "); bw.write(header); bw.newLine(); bw.write("#"); bw.newLine(); bw.newLine(); for (int idx = 0; idx < capacity; idx++) { e = table[idx]; if (e != null) { key = (String*) e->key; value = (String*) e->value; bw.write(key); bw.write(`" = "`); bw.write(value->toCppString()); //bw.write('\"'); bw.newLine(); } } bw.close(); } /*****************************************************************************\ * getBoolean | *****************************************************************************/ jboolean Properties::getBoolean(char* key, jboolean defaultValue) { String* value = getProperty(key); if (value == null) { return defaultValue; } else { String* v = value->toLowerCase(); if (v->equals("1") || v->equals("true") || v->equals("on") || v->equals("yes")) { return true; } else { return false; } } } jboolean Properties::getBoolean(String* key, jboolean defaultValue) { return getBoolean(key->latin1(), defaultValue); } /*****************************************************************************\ * getInt | *****************************************************************************/ int Properties::getInt(char* key, int defaultValue) { String* value = getProperty(key); if (value == null) { return defaultValue; } else { return value->toInt(); } } int Properties::getInt(String* key, int defaultValue) { return getInt(key->latin1(), defaultValue); }