//# 2 errors, 461 messages
//#
/*
    //#ConfigFile.java:1:1: class: com.dmdirc.util.ConfigFile
    //#ConfigFile.java:1:1: method: com.dmdirc.util.ConfigFile.com.dmdirc.util.ConfigFile__static_init
 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.dmdirc.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Reads and writes a standard DMDirc config file.
 *
 * @author chris
 */
public class ConfigFile extends TextFile {

    /** A list of domains in this config file. */
    private final List<String> domains = new ArrayList<String>();

    /** The values associated with each flat domain. */
    private final MapList<String, String> flatdomains = new MapList<String, String>();

    /** The key/value sets associated with each key domain. */
    private final Map<String, Map<String, String>> keydomains
            = new HashMap<String, Map<String, String>>();
    
    /** Whether or not we should automatically create domains. */
    private boolean automake;

    /**
     * Creates a new read-only Config File from the specified input stream.
     * 
     * @param is The input stream to read
     */
    public ConfigFile(final InputStream is) {
        super(is, Charset.forName("UTF-8"));
    //#ConfigFile.java:62: method: void com.dmdirc.util.ConfigFile.com.dmdirc.util.ConfigFile(InputStream)
    //#input(void com.dmdirc.util.ConfigFile(InputStream)): is
    //#input(void com.dmdirc.util.ConfigFile(InputStream)): this
    //#output(void com.dmdirc.util.ConfigFile(InputStream)): new ArrayList(ConfigFile#1) num objects
    //#output(void com.dmdirc.util.ConfigFile(InputStream)): new HashMap(ConfigFile#3) num objects
    //#output(void com.dmdirc.util.ConfigFile(InputStream)): new HashMap(MapList#1) num objects
    //#output(void com.dmdirc.util.ConfigFile(InputStream)): new MapList(ConfigFile#2) num objects
    //#output(void com.dmdirc.util.ConfigFile(InputStream)): this.flatdomains.__Tag
    //#output(void com.dmdirc.util.ConfigFile(InputStream)): this.flatdomains.map
    //#output(void com.dmdirc.util.ConfigFile(InputStream)): this.charset
    //#output(void com.dmdirc.util.ConfigFile(InputStream)): this.domains
    //#output(void com.dmdirc.util.ConfigFile(InputStream)): this.flatdomains
    //#output(void com.dmdirc.util.ConfigFile(InputStream)): this.is
    //#output(void com.dmdirc.util.ConfigFile(InputStream)): this.keydomains
    //#new obj(void com.dmdirc.util.ConfigFile(InputStream)): new ArrayList(ConfigFile#1)
    //#new obj(void com.dmdirc.util.ConfigFile(InputStream)): new HashMap(ConfigFile#3)
    //#new obj(void com.dmdirc.util.ConfigFile(InputStream)): new HashMap(MapList#1)
    //#new obj(void com.dmdirc.util.ConfigFile(InputStream)): new MapList(ConfigFile#2)
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): init'ed(this.charset)
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): this.domains == &new ArrayList(ConfigFile#1)
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): this.flatdomains == &new MapList(ConfigFile#2)
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): this.is == is
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): init'ed(this.is)
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): this.keydomains == &new HashMap(ConfigFile#3)
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): new ArrayList(ConfigFile#1) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): new HashMap(ConfigFile#3) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): new HashMap(MapList#1) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): new MapList(ConfigFile#2) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): this.flatdomains.__Tag == com/dmdirc/util/MapList
    //#post(void com.dmdirc.util.ConfigFile(InputStream)): this.flatdomains.map == &new HashMap(MapList#1)
    //#unanalyzed(void com.dmdirc.util.ConfigFile(InputStream)): Effects-of-calling:java.util.HashMap
    }
    //#ConfigFile.java:63: end of method: void com.dmdirc.util.ConfigFile.com.dmdirc.util.ConfigFile(InputStream)

    /**
     * Creates a new Config File from the specified file.
     * 
     * @param file The file to read/write
     */
    public ConfigFile(final File file) {
        super(file, Charset.forName("UTF-8"));
    //#ConfigFile.java:71: method: void com.dmdirc.util.ConfigFile.com.dmdirc.util.ConfigFile(File)
    //#input(void com.dmdirc.util.ConfigFile(File)): file
    //#input(void com.dmdirc.util.ConfigFile(File)): this
    //#output(void com.dmdirc.util.ConfigFile(File)): new ArrayList(ConfigFile#1) num objects
    //#output(void com.dmdirc.util.ConfigFile(File)): new HashMap(ConfigFile#3) num objects
    //#output(void com.dmdirc.util.ConfigFile(File)): new HashMap(MapList#1) num objects
    //#output(void com.dmdirc.util.ConfigFile(File)): new MapList(ConfigFile#2) num objects
    //#output(void com.dmdirc.util.ConfigFile(File)): this.flatdomains.__Tag
    //#output(void com.dmdirc.util.ConfigFile(File)): this.flatdomains.map
    //#output(void com.dmdirc.util.ConfigFile(File)): this.charset
    //#output(void com.dmdirc.util.ConfigFile(File)): this.domains
    //#output(void com.dmdirc.util.ConfigFile(File)): this.file
    //#output(void com.dmdirc.util.ConfigFile(File)): this.flatdomains
    //#output(void com.dmdirc.util.ConfigFile(File)): this.keydomains
    //#new obj(void com.dmdirc.util.ConfigFile(File)): new ArrayList(ConfigFile#1)
    //#new obj(void com.dmdirc.util.ConfigFile(File)): new HashMap(ConfigFile#3)
    //#new obj(void com.dmdirc.util.ConfigFile(File)): new HashMap(MapList#1)
    //#new obj(void com.dmdirc.util.ConfigFile(File)): new MapList(ConfigFile#2)
    //#post(void com.dmdirc.util.ConfigFile(File)): init'ed(this.charset)
    //#post(void com.dmdirc.util.ConfigFile(File)): this.domains == &new ArrayList(ConfigFile#1)
    //#post(void com.dmdirc.util.ConfigFile(File)): this.file == file
    //#post(void com.dmdirc.util.ConfigFile(File)): init'ed(this.file)
    //#post(void com.dmdirc.util.ConfigFile(File)): this.flatdomains == &new MapList(ConfigFile#2)
    //#post(void com.dmdirc.util.ConfigFile(File)): this.keydomains == &new HashMap(ConfigFile#3)
    //#post(void com.dmdirc.util.ConfigFile(File)): new ArrayList(ConfigFile#1) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(File)): new HashMap(ConfigFile#3) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(File)): new HashMap(MapList#1) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(File)): new MapList(ConfigFile#2) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(File)): this.flatdomains.__Tag == com/dmdirc/util/MapList
    //#post(void com.dmdirc.util.ConfigFile(File)): this.flatdomains.map == &new HashMap(MapList#1)
    //#unanalyzed(void com.dmdirc.util.ConfigFile(File)): Effects-of-calling:java.util.HashMap
    }
    //#ConfigFile.java:72: end of method: void com.dmdirc.util.ConfigFile.com.dmdirc.util.ConfigFile(File)

    /**
     * Creates a new Config File from the specified file.
     * 
     * @param filename The name of the file to read/write
     */
    public ConfigFile(final String filename) {
        this(new File(filename));
    //#ConfigFile.java:80: method: void com.dmdirc.util.ConfigFile.com.dmdirc.util.ConfigFile(String)
    //#input(void com.dmdirc.util.ConfigFile(String)): filename
    //#input(void com.dmdirc.util.ConfigFile(String)): this
    //#output(void com.dmdirc.util.ConfigFile(String)): new ArrayList(ConfigFile#1) num objects
    //#output(void com.dmdirc.util.ConfigFile(String)): new File(ConfigFile#1) num objects
    //#output(void com.dmdirc.util.ConfigFile(String)): new HashMap(ConfigFile#3) num objects
    //#output(void com.dmdirc.util.ConfigFile(String)): new HashMap(MapList#1) num objects
    //#output(void com.dmdirc.util.ConfigFile(String)): new MapList(ConfigFile#2) num objects
    //#output(void com.dmdirc.util.ConfigFile(String)): new MapList(ConfigFile#2).__Tag
    //#output(void com.dmdirc.util.ConfigFile(String)): new MapList(ConfigFile#2).map
    //#output(void com.dmdirc.util.ConfigFile(String)): this.charset
    //#output(void com.dmdirc.util.ConfigFile(String)): this.domains
    //#output(void com.dmdirc.util.ConfigFile(String)): this.file
    //#output(void com.dmdirc.util.ConfigFile(String)): this.flatdomains
    //#output(void com.dmdirc.util.ConfigFile(String)): this.keydomains
    //#new obj(void com.dmdirc.util.ConfigFile(String)): new ArrayList(ConfigFile#1)
    //#new obj(void com.dmdirc.util.ConfigFile(String)): new File(ConfigFile#1)
    //#new obj(void com.dmdirc.util.ConfigFile(String)): new HashMap(ConfigFile#3)
    //#new obj(void com.dmdirc.util.ConfigFile(String)): new HashMap(MapList#1)
    //#new obj(void com.dmdirc.util.ConfigFile(String)): new MapList(ConfigFile#2)
    //#post(void com.dmdirc.util.ConfigFile(String)): init'ed(this.charset)
    //#post(void com.dmdirc.util.ConfigFile(String)): this.domains == &new ArrayList(ConfigFile#1)
    //#post(void com.dmdirc.util.ConfigFile(String)): this.file == &new File(ConfigFile#1)
    //#post(void com.dmdirc.util.ConfigFile(String)): this.flatdomains == &new MapList(ConfigFile#2)
    //#post(void com.dmdirc.util.ConfigFile(String)): this.keydomains == &new HashMap(ConfigFile#3)
    //#post(void com.dmdirc.util.ConfigFile(String)): new ArrayList(ConfigFile#1) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(String)): new File(ConfigFile#1) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(String)): new HashMap(ConfigFile#3) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(String)): new HashMap(MapList#1) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(String)): new MapList(ConfigFile#2) num objects == 1
    //#post(void com.dmdirc.util.ConfigFile(String)): new MapList(ConfigFile#2).__Tag == com/dmdirc/util/MapList
    //#post(void com.dmdirc.util.ConfigFile(String)): new MapList(ConfigFile#2).map == &new HashMap(MapList#1)
    //#unanalyzed(void com.dmdirc.util.ConfigFile(String)): Effects-of-calling:java.nio.charset.Charset:forName
    //#unanalyzed(void com.dmdirc.util.ConfigFile(String)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void com.dmdirc.util.ConfigFile(String)): Effects-of-calling:java.util.HashMap
    }
    //#ConfigFile.java:81: end of method: void com.dmdirc.util.ConfigFile.com.dmdirc.util.ConfigFile(String)

    /**
     * Sets the "automake" value of this config file. If automake is set to
     * true, any calls to getKeyDomain will automatically create the domain
     * if it did not previously exist.
     * 
     * @param automake The new value of the automake setting of this file
     */
    public void setAutomake(final boolean automake) {
        this.automake = automake;
    //#ConfigFile.java:91: method: void com.dmdirc.util.ConfigFile.setAutomake(bool)
    //#input(void setAutomake(bool)): automake
    //#input(void setAutomake(bool)): this
    //#output(void setAutomake(bool)): this.automake
    //#post(void setAutomake(bool)): this.automake == automake
    //#post(void setAutomake(bool)): init'ed(this.automake)
    }
    //#ConfigFile.java:92: end of method: void com.dmdirc.util.ConfigFile.setAutomake(bool)

    /**
     * Reads the data from the file.
     * 
     * @throws FileNotFoundException if the file is not found
     * @throws IOException if an i/o exception occured when reading
     * @throws InvalidConfigFileException if the config file isn't valid
     */
    public void read() throws FileNotFoundException, IOException, InvalidConfigFileException {
        String domain = null;
    //#ConfigFile.java:102: method: void com.dmdirc.util.ConfigFile.read()
    //#ConfigFile.java:102: Warning: suspicious precondition
    //#    The precondition for this.flatdomains.__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.util.ConfigFile
    //#    method: void read()
    //#    suspicious precondition index: [7]
    //#input(void read()): "Unknown or unexpected line encountered: "._tainted
    //#input(void read()): __Descendant_Table[com/dmdirc/util/ConfigFile]
    //#input(void read()): __Descendant_Table[others]
    //#input(void read()): __Dispatch_Table.getLines()Ljava/util/List;
    //#input(void read()): __Dispatch_Table.readLines()V
    //#input(void read()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void read()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void read()): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void read()): com/dmdirc/util/MapList.__Dispatch_Table.add(Ljava/lang/Object;)V
    //#input(void read()): com/dmdirc/util/MapList.__Dispatch_Table.add(Ljava/lang/Object;Ljava/lang/Object;)V
    //#input(void read()): com/dmdirc/util/MapList.__Dispatch_Table.clear()V
    //#input(void read()): com/dmdirc/util/MapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void read()): com/dmdirc/util/MapList.__Dispatch_Table.containsValue(Ljava/lang/Object;Ljava/lang/Object;)Z
    //#input(void read()): com/dmdirc/util/MapList.__Dispatch_Table.safeGet(Ljava/lang/Object;)Ljava/util/List;
    //#input(void read()): com/dmdirc/util/TextFile.__Descendant_Table[com/dmdirc/util/ConfigFile]
    //#input(void read()): com/dmdirc/util/TextFile.__Descendant_Table[com/dmdirc/util/TextFile]
    //#input(void read()): com/dmdirc/util/TextFile.__Descendant_Table[others]
    //#input(void read()): com/dmdirc/util/TextFile.__Dispatch_Table.readLines()V
    //#input(void read()): com/dmdirc/util/WeakMapList.__Dispatch_Table.add(Ljava/lang/Object;)V
    //#input(void read()): com/dmdirc/util/WeakMapList.__Dispatch_Table.add(Ljava/lang/Object;Ljava/lang/Object;)V
    //#input(void read()): com/dmdirc/util/WeakMapList.__Dispatch_Table.clear()V
    //#input(void read()): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void read()): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsValue(Ljava/lang/Object;Ljava/lang/Object;)Z
    //#input(void read()): com/dmdirc/util/WeakMapList.__Dispatch_Table.safeGet(Ljava/lang/Object;)Ljava/util/List;
    //#input(void read()): this
    //#input(void read()): this.__Tag
    //#input(void read()): this.charset
    //#input(void read()): this.domains
    //#input(void read()): this.file
    //#input(void read()): this.flatdomains
    //#input(void read()): this.flatdomains.__Tag
    //#input(void read()): this.flatdomains.map
    //#input(void read()): this.is
    //#input(void read()): this.keydomains
    //#output(void read()): new ArrayList(readLines#4) num objects
    //#output(void read()): this.lines
    //#new obj(void read()): new ArrayList(readLines#4)
    //#pre[4] (void read()): this.domains != null
    //#pre[5] (void read()): init'ed(this.file)
    //#pre[6] (void read()): this.flatdomains != null
    //#pre[7] (void read()): this.flatdomains.__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[8] (void read()): this.flatdomains.map != null
    //#pre[10] (void read()): this.keydomains != null
    //#pre[2] (void read()): (soft) this.__Tag == com/dmdirc/util/ConfigFile
    //#pre[9] (void read()): (soft) init'ed(this.is)
    //#presumption(void read()): java.util.Iterator:next(...)@112 != null
    //#presumption(void read()): java.util.Map:get(...)@142 != null
    //#post(void read()): this.lines == &new ArrayList(readLines#4)
    //#post(void read()): new ArrayList(readLines#4) num objects == 1
    //#post(void read()): new ArrayList(readLines#4) num objects == 0
    //#unanalyzed(void read()): Effects-of-calling:java.lang.String:length
    //#unanalyzed(void read()): Effects-of-calling:java.lang.String:charAt
    //#unanalyzed(void read()): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void read()): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void read()): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void read()): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void read()): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void read()): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void read()): Effects-of-calling:java.util.Map:put
    //#unanalyzed(void read()): Effects-of-calling:java.util.Map:clear
    //#unanalyzed(void read()): Effects-of-calling:java.io.FileInputStream
    //#unanalyzed(void read()): Effects-of-calling:java.io.InputStreamReader
    //#unanalyzed(void read()): Effects-of-calling:java.io.BufferedReader
    //#unanalyzed(void read()): Effects-of-calling:java.io.BufferedReader:readLine
    //#unanalyzed(void read()): Effects-of-calling:java.util.List:add
    //#unanalyzed(void read()): Effects-of-calling:java.io.BufferedReader:close
    //#unanalyzed(void read()): Effects-of-calling:java.util.List:contains
    //#unanalyzed(void read()): Effects-of-calling:java.lang.Exception
    //#test_vector(void read()): java.lang.String:charAt(...)@115: {9}, {0..8, 10..65_535}
    //#test_vector(void read()): java.lang.String:charAt(...)@115: {0..31, 33..65_535}, {32}
    //#test_vector(void read()): java.lang.String:endsWith(...)@122: {0}, {1}
    //#test_vector(void read()): java.lang.String:endsWith(...)@122: {1}, {0}
    //#test_vector(void read()): java.lang.String:indexOf(...)@120: {0}, {-2_147_483_648..-1, 1..4_294_967_295}
    //#test_vector(void read()): java.lang.String:isEmpty(...)@115: {1}, {0}
    //#test_vector(void read()): java.lang.String:isEmpty(...)@120: {0}, {1}
    //#test_vector(void read()): java.util.Iterator:hasNext(...)@112: {0}, {1}
    //#test_vector(void read()): java.util.Map:containsKey(...)@132: {1}, {0}
    //#test_vector(void read()): java.util.Map:containsKey(...)@84: {1}, {0}
        boolean keydomain = false;
        int offset;
        
        keydomains.clear();
        flatdomains.clear();
        domains.clear();
        
        readLines();

        for (String line : getLines()) {
            String tline = line;
            
            while (!tline.isEmpty() && (tline.charAt(0) == '\t' || 
                    tline.charAt(0) == ' ')) {
                tline = tline.substring(1);
            }

            if (tline.indexOf('#') == 0 || tline.isEmpty()) {
                continue;
            } else if (
                    (tline.endsWith(":") && !tline.endsWith("\\:"))
                    && findEquals(tline) == -1) {
                domain = unescape(tline.substring(0, tline.length() - 1));

                domains.add(domain);

                keydomain = keydomains.containsKey(domain)
                        || flatdomains.containsValue("keysections", domain);
                
                if (keydomain && !keydomains.containsKey(domain)) {
                    keydomains.put(domain, new HashMap<String, String>());
                } else if (!keydomain && !flatdomains.containsKey(domain)) {
                    flatdomains.add(domain);
                }
            } else if (domain != null && keydomain
                    && (offset = findEquals(tline)) != -1) {
                final String key = unescape(tline.substring(0, offset));
                final String value = unescape(tline.substring(offset + 1));

                keydomains.get(domain).put(key, value);
            } else if (domain != null && !keydomain) {
                flatdomains.add(domain, unescape(tline));
            } else {
                throw new InvalidConfigFileException("Unknown or unexpected" +
    //#ConfigFile.java:146: ?conditional throw
    //#    domain != null
    //#    severity: MEDIUM
    //#    class: com.dmdirc.util.ConfigFile
    //#    method: void read()
    //#    basic block: bb_28
    //#    assertion: domain != null
    //#    VN: domain == null
    //#    Expected: {-Inf..0, 2..+Inf}
    //#    Bad: {1}
    //#    Attribs:  Int  Bad singleton  Bad overlaps +/-1000  Bad > Exp
    //#ConfigFile.java:146: ?conditional throw
    //#    keydomain == 0
    //#    severity: LOW
    //#    class: com.dmdirc.util.ConfigFile
    //#    method: void read()
    //#    basic block: bb_29
    //#    assertion: keydomain == 0
    //#    VN: keydomain
    //#    Expected: {0}
    //#    Bad: {1}
    //#    Attribs:  Int  Exp in +/-1000  Exp singleton  Bad singleton  Bad overlaps +/-1000  Bad > Exp
                        " line encountered: " + tline);
            }
        }
    }
    //#ConfigFile.java:150: end of method: void com.dmdirc.util.ConfigFile.read()

    /**
     * Writes the contents of this ConfigFile to disk.
     * 
     * @throws IOException if the write operation fails
     */
    public void write() throws IOException {
        if (!isWritable()) {
    //#ConfigFile.java:158: method: void com.dmdirc.util.ConfigFile.write()
    //#ConfigFile.java:158: Warning: suspicious precondition
    //#    The precondition for this.flatdomains.__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.util.ConfigFile
    //#    method: void write()
    //#    suspicious precondition index: [6]
    //#    Attribs:  Soft
    //#input(void write()): "  "._tainted
    //#input(void write()): "# Written on: "._tainted
    //#input(void write()): "="._tainted
    //#input(void write()): __Descendant_Table[com/dmdirc/util/ConfigFile]
    //#input(void write()): __Descendant_Table[others]
    //#input(void write()): __Dispatch_Table.isWritable()Z
    //#input(void write()): __Dispatch_Table.writeLines(Ljava/util/List;)V
    //#input(void write()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void write()): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void write()): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void write()): com/dmdirc/util/MapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void write()): com/dmdirc/util/MapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void write()): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(void write()): com/dmdirc/util/WeakMapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(void write()): this
    //#input(void write()): this.__Tag
    //#input(void write()): this.domains
    //#input(void write()): this.file
    //#input(void write()): this.flatdomains
    //#input(void write()): this.flatdomains.__Tag
    //#input(void write()): this.flatdomains.map
    //#input(void write()): this.keydomains
    //#pre[2] (void write()): this.__Tag == com/dmdirc/util/ConfigFile
    //#pre[3] (void write()): this.domains != null
    //#pre[4] (void write()): this.file != null
    //#pre[5] (void write()): (soft) this.flatdomains != null
    //#pre[6] (void write()): (soft) this.flatdomains.__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[7] (void write()): (soft) this.flatdomains.map != null
    //#pre[8] (void write()): (soft) this.keydomains != null
    //#presumption(void write()): java.util.GregorianCalendar:getTime(...)@166 != null
    //#presumption(void write()): java.util.Iterator:next(...)@170 != null
    //#presumption(void write()): java.util.Iterator:next(...)@180 != null
    //#presumption(void write()): java.util.Iterator:next(...)@184 != null
    //#presumption(void write()): java.util.Map:entrySet(...)@184 != null
    //#presumption(void write()): java.util.Map:get(...)@107 != null
    //#presumption(void write()): java.util.Map:get(...)@184 != null
    //#presumption(void write()): java.util.Map_Entry:getKey(...)@185 != null
    //#presumption(void write()): java.util.Map_Entry:getValue(...)@185 != null
    //#unanalyzed(void write()): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void write()): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void write()): Effects-of-calling:java.util.List:add
    //#unanalyzed(void write()): Effects-of-calling:java.util.List:iterator
    //#unanalyzed(void write()): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void write()): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void write()): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void write()): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void write()): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void write()): Effects-of-calling:java.lang.String:replaceAll
    //#unanalyzed(void write()): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void write()): Effects-of-calling:java.io.FileWriter
    //#unanalyzed(void write()): Effects-of-calling:java.io.BufferedWriter
    //#unanalyzed(void write()): Effects-of-calling:java.io.BufferedWriter:write
    //#unanalyzed(void write()): Effects-of-calling:java.io.BufferedWriter:newLine
    //#unanalyzed(void write()): Effects-of-calling:java.io.BufferedWriter:close
    //#test_vector(void write()): java.lang.String:equals(...)@171: {0}, {1}
    //#test_vector(void write()): java.util.Iterator:hasNext(...)@170: {0}, {1}
    //#test_vector(void write()): java.util.Iterator:hasNext(...)@184: {0}, {1}
    //#test_vector(void write()): java.util.Map:containsKey(...)@84: {0}, {1}
            throw new UnsupportedOperationException("Cannot write to a file "
                    + "that isn't writable");
        }
        
        final List<String> lines = new ArrayList<String>();

        lines.add("# This is a DMDirc configuration file.");
        lines.add("# Written on: " + new GregorianCalendar().getTime().toString());

        writeMeta(lines);

        for (String domain : domains) {
            if ("keysections".equals(domain)) {
                continue;
            }

            lines.add("");

            lines.add(escape(domain) + ':');

            if (flatdomains.containsKey(domain)) {
                for (String entry : flatdomains.get(domain)) {
                    lines.add("  " + escape(entry));
                }
            } else {
                for (Map.Entry<String, String> entry : keydomains.get(domain).entrySet()) {
                    lines.add("  " + escape(entry.getKey()) + "="
                            + escape(entry.getValue()));
                }
            }
        }

        writeLines(lines);
    }
    //#ConfigFile.java:192: end of method: void com.dmdirc.util.ConfigFile.write()
    
    /**
     * Appends the meta-data (keysections) to the specified list of lines.
     * 
     * @param lines The set of lines to be appended to
     */
    private void writeMeta(final List<String> lines) {
        lines.add("");
    //#ConfigFile.java:200: method: void com.dmdirc.util.ConfigFile.writeMeta(List)
    //#input(void writeMeta(List)): "  "._tainted
    //#input(void writeMeta(List)): lines
    //#input(void writeMeta(List)): this
    //#input(void writeMeta(List)): this.domains
    //#input(void writeMeta(List)): this.keydomains
    //#pre[1] (void writeMeta(List)): lines != null
    //#pre[3] (void writeMeta(List)): this.domains != null
    //#pre[4] (void writeMeta(List)): (soft) this.keydomains != null
    //#test_vector(void writeMeta(List)): java.lang.String:equals(...)@207: {0}, {1}
    //#test_vector(void writeMeta(List)): java.util.Iterator:hasNext(...)@206: {0}, {1}
    //#test_vector(void writeMeta(List)): java.util.Map:containsKey(...)@209: {0}, {1}
        lines.add("# This section indicates which sections below take key/value");
        lines.add("# pairs, rather than a simple list. It should be placed above");
        lines.add("# any sections that take key/values.");
        lines.add("keysections:");

        for (String domain : domains) {
            if ("keysections".equals(domain)) {
                continue;
            } else if (keydomains.containsKey(domain)) {
                lines.add("  " + domain);
            }
        }
    }
    //#ConfigFile.java:213: end of method: void com.dmdirc.util.ConfigFile.writeMeta(List)
    
    /**
     * Retrieves all the key domains for this config file.
     * 
     * @return This config file's key domains
     */
    public Map<String, Map<String, String>> getKeyDomains() {
        return keydomains;
    //#ConfigFile.java:221: method: Map com.dmdirc.util.ConfigFile.getKeyDomains()
    //#input(Map getKeyDomains()): this
    //#input(Map getKeyDomains()): this.keydomains
    //#output(Map getKeyDomains()): return_value
    //#post(Map getKeyDomains()): return_value == this.keydomains
    //#post(Map getKeyDomains()): init'ed(return_value)
    //#ConfigFile.java:221: end of method: Map com.dmdirc.util.ConfigFile.getKeyDomains()
    }
    
    /**
     * Retrieves the key/values of the specified key domain.
     * 
     * @param domain The domain to be retrieved
     * @return A map of keys to values in the specified domain
     */
    public Map<String, String> getKeyDomain(final String domain) {
        if (automake && !isKeyDomain(domain)) {
    //#ConfigFile.java:231: method: Map com.dmdirc.util.ConfigFile.getKeyDomain(String)
    //#input(Map getKeyDomain(String)): __Descendant_Table[com/dmdirc/util/ConfigFile]
    //#input(Map getKeyDomain(String)): __Descendant_Table[others]
    //#input(Map getKeyDomain(String)): __Dispatch_Table.isKeyDomain(Ljava/lang/String;)Z
    //#input(Map getKeyDomain(String)): domain
    //#input(Map getKeyDomain(String)): this
    //#input(Map getKeyDomain(String)): this.__Tag
    //#input(Map getKeyDomain(String)): this.automake
    //#input(Map getKeyDomain(String)): this.domains
    //#input(Map getKeyDomain(String)): this.keydomains
    //#output(Map getKeyDomain(String)): return_value
    //#pre[4] (Map getKeyDomain(String)): init'ed(this.automake)
    //#pre[6] (Map getKeyDomain(String)): this.keydomains != null
    //#pre[3] (Map getKeyDomain(String)): (soft) this.__Tag == com/dmdirc/util/ConfigFile
    //#pre[5] (Map getKeyDomain(String)): (soft) this.domains != null
    //#post(Map getKeyDomain(String)): init'ed(return_value)
    //#unanalyzed(Map getKeyDomain(String)): Effects-of-calling:java.util.Map:containsKey
    //#test_vector(Map getKeyDomain(String)): this.automake: {0}, {1}
    //#test_vector(Map getKeyDomain(String)): java.util.Map:containsKey(...)@267: {1}, {0}
            domains.add(domain);
            keydomains.put(domain, new HashMap<String, String>());
        }
        
        return keydomains.get(domain);
    //#ConfigFile.java:236: end of method: Map com.dmdirc.util.ConfigFile.getKeyDomain(String)
    }
    
    /**
     * Retrieves the content of the specified flat domain.
     * 
     * @param domain The domain to be retrieved
     * @return A list of lines in the specified domain
     */
    public List<String> getFlatDomain(final String domain) {
        return flatdomains.get(domain);
    //#ConfigFile.java:246: method: List com.dmdirc.util.ConfigFile.getFlatDomain(String)
    //#ConfigFile.java:246: Warning: suspicious precondition
    //#    The precondition for this.flatdomains.__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.util.ConfigFile
    //#    method: List getFlatDomain(String)
    //#    suspicious precondition index: [4]
    //#input(List getFlatDomain(String)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(List getFlatDomain(String)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(List getFlatDomain(String)): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(List getFlatDomain(String)): com/dmdirc/util/MapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(List getFlatDomain(String)): com/dmdirc/util/WeakMapList.__Dispatch_Table.get(Ljava/lang/Object;)Ljava/util/List;
    //#input(List getFlatDomain(String)): domain
    //#input(List getFlatDomain(String)): this
    //#input(List getFlatDomain(String)): this.flatdomains
    //#input(List getFlatDomain(String)): this.flatdomains.__Tag
    //#input(List getFlatDomain(String)): this.flatdomains.map
    //#output(List getFlatDomain(String)): return_value
    //#pre[3] (List getFlatDomain(String)): this.flatdomains != null
    //#pre[4] (List getFlatDomain(String)): this.flatdomains.__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[5] (List getFlatDomain(String)): this.flatdomains.map != null
    //#post(List getFlatDomain(String)): init'ed(return_value)
    //#unanalyzed(List getFlatDomain(String)): Effects-of-calling:java.util.Map:get
    //#ConfigFile.java:246: end of method: List com.dmdirc.util.ConfigFile.getFlatDomain(String)
    }
    
    /**
     * Determines if this config file has the specified domain.
     * 
     * @param domain The domain to check for
     * @return True if the domain is known, false otherwise
     */
    public boolean hasDomain(final String domain) {
        return keydomains.containsKey(domain) || flatdomains.containsKey(domain);
    //#ConfigFile.java:256: method: bool com.dmdirc.util.ConfigFile.hasDomain(String)
    //#ConfigFile.java:256: Warning: suspicious precondition
    //#    The precondition for this.flatdomains.__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.util.ConfigFile
    //#    method: bool hasDomain(String)
    //#    suspicious precondition index: [4]
    //#    Attribs:  Soft
    //#input(bool hasDomain(String)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(bool hasDomain(String)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(bool hasDomain(String)): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(bool hasDomain(String)): com/dmdirc/util/MapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(bool hasDomain(String)): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(bool hasDomain(String)): domain
    //#input(bool hasDomain(String)): this
    //#input(bool hasDomain(String)): this.flatdomains
    //#input(bool hasDomain(String)): this.flatdomains.__Tag
    //#input(bool hasDomain(String)): this.flatdomains.map
    //#input(bool hasDomain(String)): this.keydomains
    //#output(bool hasDomain(String)): return_value
    //#pre[6] (bool hasDomain(String)): this.keydomains != null
    //#pre[3] (bool hasDomain(String)): (soft) this.flatdomains != null
    //#pre[4] (bool hasDomain(String)): (soft) this.flatdomains.__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[5] (bool hasDomain(String)): (soft) this.flatdomains.map != null
    //#post(bool hasDomain(String)): init'ed(return_value)
    //#unanalyzed(bool hasDomain(String)): Effects-of-calling:java.util.Map:containsKey
    //#ConfigFile.java:256: end of method: bool com.dmdirc.util.ConfigFile.hasDomain(String)
    }

    /**
     * Determines if this config file has the specified domain, and the domain
     * is a key domain.
     * 
     * @param domain The domain to check for
     * @return True if the domain is known and keyed, false otherwise
     */
    public boolean isKeyDomain(final String domain) {
        return keydomains.containsKey(domain);
    //#ConfigFile.java:267: method: bool com.dmdirc.util.ConfigFile.isKeyDomain(String)
    //#input(bool isKeyDomain(String)): domain
    //#input(bool isKeyDomain(String)): this
    //#input(bool isKeyDomain(String)): this.keydomains
    //#output(bool isKeyDomain(String)): return_value
    //#pre[3] (bool isKeyDomain(String)): this.keydomains != null
    //#post(bool isKeyDomain(String)): init'ed(return_value)
    //#ConfigFile.java:267: end of method: bool com.dmdirc.util.ConfigFile.isKeyDomain(String)
    }

    /**
     * Determines if this config file has the specified domain, and the domain
     * is a flat domain.
     * 
     * @param domain The domain to check for
     * @return True if the domain is known and flat, false otherwise
     */
    public boolean isFlatDomain(final String domain) {
        return flatdomains.containsKey(domain);
    //#ConfigFile.java:278: method: bool com.dmdirc.util.ConfigFile.isFlatDomain(String)
    //#ConfigFile.java:278: Warning: suspicious precondition
    //#    The precondition for this.flatdomains.__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.util.ConfigFile
    //#    method: bool isFlatDomain(String)
    //#    suspicious precondition index: [4]
    //#input(bool isFlatDomain(String)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(bool isFlatDomain(String)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(bool isFlatDomain(String)): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(bool isFlatDomain(String)): com/dmdirc/util/MapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(bool isFlatDomain(String)): com/dmdirc/util/WeakMapList.__Dispatch_Table.containsKey(Ljava/lang/Object;)Z
    //#input(bool isFlatDomain(String)): domain
    //#input(bool isFlatDomain(String)): this
    //#input(bool isFlatDomain(String)): this.flatdomains
    //#input(bool isFlatDomain(String)): this.flatdomains.__Tag
    //#input(bool isFlatDomain(String)): this.flatdomains.map
    //#output(bool isFlatDomain(String)): return_value
    //#pre[3] (bool isFlatDomain(String)): this.flatdomains != null
    //#pre[4] (bool isFlatDomain(String)): this.flatdomains.__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[5] (bool isFlatDomain(String)): this.flatdomains.map != null
    //#post(bool isFlatDomain(String)): init'ed(return_value)
    //#unanalyzed(bool isFlatDomain(String)): Effects-of-calling:java.util.Map:containsKey
    //#ConfigFile.java:278: end of method: bool com.dmdirc.util.ConfigFile.isFlatDomain(String)
    }
    
    /**
     * Adds a new flat domain to this config file.
     * 
     * @param name The name of the domain to be added
     * @param data The content of the domain
     */
    public void addDomain(final String name, final List<String> data) {
        domains.add(name);
    //#ConfigFile.java:288: method: void com.dmdirc.util.ConfigFile.addDomain(String, List)
    //#ConfigFile.java:288: Warning: suspicious precondition
    //#    The precondition for this.flatdomains.__Tag is not a contiguous range of values
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.util.ConfigFile
    //#    method: void addDomain(String, List)
    //#    suspicious precondition index: [6]
    //#input(void addDomain(String, List)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/MapList]
    //#input(void addDomain(String, List)): com/dmdirc/util/MapList.__Descendant_Table[com/dmdirc/util/WeakMapList]
    //#input(void addDomain(String, List)): com/dmdirc/util/MapList.__Descendant_Table[others]
    //#input(void addDomain(String, List)): com/dmdirc/util/MapList.__Dispatch_Table.add(Ljava/lang/Object;Ljava/util/Collection;)V
    //#input(void addDomain(String, List)): com/dmdirc/util/MapList.__Dispatch_Table.safeGet(Ljava/lang/Object;)Ljava/util/List;
    //#input(void addDomain(String, List)): com/dmdirc/util/WeakMapList.__Dispatch_Table.add(Ljava/lang/Object;Ljava/util/Collection;)V
    //#input(void addDomain(String, List)): com/dmdirc/util/WeakMapList.__Dispatch_Table.safeGet(Ljava/lang/Object;)Ljava/util/List;
    //#input(void addDomain(String, List)): data
    //#input(void addDomain(String, List)): name
    //#input(void addDomain(String, List)): this
    //#input(void addDomain(String, List)): this.domains
    //#input(void addDomain(String, List)): this.flatdomains
    //#input(void addDomain(String, List)): this.flatdomains.__Tag
    //#input(void addDomain(String, List)): this.flatdomains.map
    //#pre[4] (void addDomain(String, List)): this.domains != null
    //#pre[5] (void addDomain(String, List)): this.flatdomains != null
    //#pre[6] (void addDomain(String, List)): this.flatdomains.__Tag in {com/dmdirc/util/MapList, com/dmdirc/util/WeakMapList}
    //#pre[7] (void addDomain(String, List)): this.flatdomains.map != null
    //#unanalyzed(void addDomain(String, List)): Effects-of-calling:java.util.Map:containsKey
    //#unanalyzed(void addDomain(String, List)): Effects-of-calling:java.util.Map:get
    //#unanalyzed(void addDomain(String, List)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void addDomain(String, List)): Effects-of-calling:java.util.Map:put
    //#unanalyzed(void addDomain(String, List)): Effects-of-calling:java.util.List:addAll
        flatdomains.add(name, data);
    }
    //#ConfigFile.java:290: end of method: void com.dmdirc.util.ConfigFile.addDomain(String, List)

    /**
     * Adds a new key domain to this config file.
     * 
     * @param name The name of the domain to be added
     * @param data The content of the domain
     */    
    public void addDomain(final String name, final Map<String, String> data) {
        domains.add(name);
    //#ConfigFile.java:299: method: void com.dmdirc.util.ConfigFile.addDomain(String, Map)
    //#input(void addDomain(String, Map)): data
    //#input(void addDomain(String, Map)): name
    //#input(void addDomain(String, Map)): this
    //#input(void addDomain(String, Map)): this.domains
    //#input(void addDomain(String, Map)): this.keydomains
    //#pre[4] (void addDomain(String, Map)): this.domains != null
    //#pre[5] (void addDomain(String, Map)): this.keydomains != null
        keydomains.put(name, data);
    }
    //#ConfigFile.java:301: end of method: void com.dmdirc.util.ConfigFile.addDomain(String, Map)
    
    /**
     * Unescapes any escaped characters in the specified input string.
     * 
     * @param input The string to unescape
     * @return The string with all escape chars (\) resolved
     */
    protected static String unescape(final String input) {
        boolean escaped = false;
    //#ConfigFile.java:310: method: String com.dmdirc.util.ConfigFile.unescape(String)
    //#input(String unescape(String)): input
    //#output(String unescape(String)): java.lang.StringBuilder:toString(...)._tainted
    //#output(String unescape(String)): return_value
    //#new obj(String unescape(String)): java.lang.StringBuilder:toString(...)
    //#pre[1] (String unescape(String)): input != null
    //#post(String unescape(String)): java.lang.StringBuilder:toString(...)._tainted == 0
    //#post(String unescape(String)): return_value == &java.lang.StringBuilder:toString(...)
    //#test_vector(String unescape(String)): java.lang.String:charAt(...)@314: {110}, {92}, {114}
        final StringBuilder temp = new StringBuilder();

        for (int i = 0; i < input.length(); i++) {
            final char ch = input.charAt(i);

            if (escaped) {
                if (ch == 'n') {
                    temp.append('\n');
                } else if (ch == 'r') {
                    temp.append('\r');
                } else {
                    temp.append(ch);
                }
                
                escaped = false;
            } else if (ch == '\\') {
                escaped = true;
            } else {
                temp.append(ch);
            }
        }
        
        return temp.toString();
    //#ConfigFile.java:333: end of method: String com.dmdirc.util.ConfigFile.unescape(String)
    }
    
    /**
     * Escapes the specified input string by prefixing all occurances of
     * \, \n, \r, =, # and : with backslashes.
     * 
     * @param input The string to be escaped
     * @return A backslash-armoured version of the string
     */
    protected static String escape(final String input) {
        return input.replaceAll("\\\\", "\\\\\\\\").replaceAll("\n", "\\\\n")
    //#ConfigFile.java:344: method: String com.dmdirc.util.ConfigFile.escape(String)
    //#input(String escape(String)): input
    //#output(String escape(String)): return_value
    //#pre[1] (String escape(String)): input != null
    //#post(String escape(String)): return_value != null
    //#ConfigFile.java:344: end of method: String com.dmdirc.util.ConfigFile.escape(String)
                .replaceAll("\r", "\\\\r").replaceAll("=", "\\\\=")
                .replaceAll(":", "\\\\:").replaceAll("#", "\\\\#");
    }
    
    /**
     * Finds the first non-escaped instance of '=' in the specified string.
     * 
     * @param input The string to be searched
     * @return The offset of the first non-escaped instance of '=', or -1.
     */
    protected static int findEquals(final String input) {
        boolean escaped = false;
    //#ConfigFile.java:356: method: int com.dmdirc.util.ConfigFile.findEquals(String)
    //#input(int findEquals(String)): input
    //#output(int findEquals(String)): return_value
    //#pre[1] (int findEquals(String)): input != null
    //#post(int findEquals(String)): return_value in {-1..4_294_967_294}
    //#test_vector(int findEquals(String)): java.lang.String:charAt(...)@361: {0..91, 93..65_535}, {92}
    //#test_vector(int findEquals(String)): java.lang.String:charAt(...)@363: {0..60, 62..65_535}, {61}
        
        for (int i = 0; i < input.length(); i++) {
            if (escaped) {
                escaped = false;
            } else if (input.charAt(i) == '\\') {
                escaped = true;
            } else if (input.charAt(i) == '=') {
                return i;
            }
        }
        
        return -1;
    //#ConfigFile.java:368: end of method: int com.dmdirc.util.ConfigFile.findEquals(String)
    }
}    //#output(com.dmdirc.util.ConfigFile__static_init): __Descendant_Table[com/dmdirc/util/ConfigFile]
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.addDomain(Ljava/lang/String;Ljava/util/List;)V
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.addDomain(Ljava/lang/String;Ljava/util/Map;)V
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.delete()V
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.getFile()Ljava/io/File;
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.getFlatDomain(Ljava/lang/String;)Ljava/util/List;
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.getKeyDomain(Ljava/lang/String;)Ljava/util/Map;
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.getKeyDomains()Ljava/util/Map;
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.getLines()Ljava/util/List;
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.hasDomain(Ljava/lang/String;)Z
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.isFlatDomain(Ljava/lang/String;)Z
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.isKeyDomain(Ljava/lang/String;)Z
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.isWritable()Z
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.read()V
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.readLines()V
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.setAutomake(Z)V
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.write()V
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.writeLines(Ljava/util/List;)V
    //#output(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.writeMeta(Ljava/util/List;)V
    //#output(com.dmdirc.util.ConfigFile__static_init): com/dmdirc/util/TextFile.__Descendant_Table[com/dmdirc/util/ConfigFile]
    //#post(com.dmdirc.util.ConfigFile__static_init): __Descendant_Table[com/dmdirc/util/ConfigFile] == &__Dispatch_Table
    //#post(com.dmdirc.util.ConfigFile__static_init): com/dmdirc/util/TextFile.__Descendant_Table[com/dmdirc/util/ConfigFile] == &__Dispatch_Table
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.addDomain(Ljava/lang/String;Ljava/util/List;)V == &addDomain
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.addDomain(Ljava/lang/String;Ljava/util/Map;)V == &addDomain
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.delete()V == &com/dmdirc/util/TextFile.delete
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.getFile()Ljava/io/File; == &com/dmdirc/util/TextFile.getFile
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.getFlatDomain(Ljava/lang/String;)Ljava/util/List; == &getFlatDomain
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.getKeyDomain(Ljava/lang/String;)Ljava/util/Map; == &getKeyDomain
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.getKeyDomains()Ljava/util/Map; == &getKeyDomains
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.getLines()Ljava/util/List; == &com/dmdirc/util/TextFile.getLines
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.hasDomain(Ljava/lang/String;)Z == &hasDomain
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.isFlatDomain(Ljava/lang/String;)Z == &isFlatDomain
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.isKeyDomain(Ljava/lang/String;)Z == &isKeyDomain
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.isWritable()Z == &com/dmdirc/util/TextFile.isWritable
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.read()V == &read
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.readLines()V == &com/dmdirc/util/TextFile.readLines
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.setAutomake(Z)V == &setAutomake
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.write()V == &write
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.writeLines(Ljava/util/List;)V == &com/dmdirc/util/TextFile.writeLines
    //#post(com.dmdirc.util.ConfigFile__static_init): __Dispatch_Table.writeMeta(Ljava/util/List;)V == &writeMeta
    //#ConfigFile.java:: end of method: com.dmdirc.util.ConfigFile.com.dmdirc.util.ConfigFile__static_init
    //#ConfigFile.java:: end of class: com.dmdirc.util.ConfigFile
