/******************************************************************************* * Copyright (c) 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Zend Technologies *******************************************************************************/ package org.eclipse.php.internal.debug.core.phpIni; import java.io.*; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * This class is used for modifying INI file. At the end {@link #close()} must * be called, otherwise the file will be leaved unmodified. * * @author michael */ public class INIFileModifier { private static final String GLOBAL_SECTION = "__global__"; //$NON-NLS-1$ private static final Pattern SECTION_PATTERN = Pattern.compile("\\[([^\\]]+)\\]"); //$NON-NLS-1$ private static final Pattern NAME_VAL_PATTERN = Pattern .compile("([\\w]+)\\p{javaWhitespace}*=\\p{javaWhitespace}*(.*)"); //$NON-NLS-1$ class INIFileSection { String name; List<String> lines; public INIFileSection(String name) { this.name = name; this.lines = new LinkedList<String>(); } } private File configFile; private List<INIFileSection> sections; /** * Create new INI file modifier class instance. If provided INI file doesn't * exist - it will be created. * * @param configFile * INI file path * @throws IOException */ public INIFileModifier(String configFile) throws IOException { this(new File(configFile)); } /** * Create new INI file modifier class instance. If provided INI file doesn't * exist - it will be created. * * @param configFile * INI file object * @throws IOException */ public INIFileModifier(File configFile) throws IOException { this.configFile = configFile; this.sections = new LinkedList<INIFileSection>(); read(); } /** * Adds new entry to the INI file. New entry will be added to the default * (unnamed) section * * @param name * Entry name * @param value * Value name * @param replace * Whether to replace the old entry */ public void addEntry(String name, String value, boolean replace) { addEntry(GLOBAL_SECTION, name, value, replace, null); } /** * Adds new entry to the INI file. New entry will be added to the default * (unnamed) section, no old entries will be replaced * * @param name * Entry name * @param value * Value name */ public void addEntry(String name, String value) { addEntry(GLOBAL_SECTION, name, value, false, null); } /** * Adds new entry to the INI file. New entry will be added to the given * section, no old entries will be replaced * * @param sectionName * Section name * @param name * Entry name * @param value * Value name */ public void addEntry(String sectionName, String name, String value) { addEntry(sectionName, name, value, false, null); } /** * Adds new entry to the INI file. If <code>replace</code> is * <code>true</code> the old entry will be replaced, otherwise - add a new * one. * * @param sectionName * Section name * @param name * Entry name * @param value * Value name * @param replace * Whether to replace the old entry or add a new one * @param replacePattern * Pattern to check against existing entry value, before * replacing it. If <code>replacePattern</code> is * <code>null</code> - every entry that matches the given name * will be replaced */ public void addEntry(String sectionName, String name, String value, boolean replace, String replacePattern) { if (sectionName == null || name == null || value == null) { throw new NullPointerException(); } for (INIFileSection section : sections) { if (section.name.equals(sectionName)) { if (replace) { for (int i = 0; i < section.lines.size(); ++i) { Matcher m = NAME_VAL_PATTERN.matcher(section.lines.get(i)); if (m.matches()) { String oldName = m.group(1); String oldValue = m.group(2); if (oldName.equals(name) && (replacePattern == null || oldValue.matches(replacePattern))) { section.lines.set(i, name + '=' + quoteString(value)); } } } } else { section.lines.add(name + '=' + quoteString(value)); } break; } } } /** * Removes entry from the INI file from the global section. * * @param name * Entry name * @param removePattern * Pattern to check against existing entry value, before removing * it. If <code>removePattern</code> is <code>null</code> every * entry that matches the given name will be removed. * @return <code>true</code> if some entry was removed, otherwise - false */ public boolean removeEntry(String name, String removePattern) { return removeEntry(GLOBAL_SECTION, name, removePattern); } /** * Removes all entries from the INI file from all sections. Same as * <code>removeEntry(null, name, null)</code>. * * @param name * Entry name * @return <code>true</code> if some entry was removed, otherwise - false * @see #removeEntry(String, String, String) */ public boolean removeAllEntries(String name) { return removeEntry(null, name, null); } /** * Removes all entries from the INI file from all sections. Same as * <code>removeEntry(null, name, removePattern)</code>. * * @param name * Entry name * @param removePattern * Pattern to check against existing entry value, before removing * it. If <code>removePattern</code> is <code>null</code> every * entry that matches the given name will be removed. * * @return <code>true</code> if some entry was removed, otherwise - false * @see #removeEntry(String, String, String) */ public boolean removeAllEntries(String name, String removePattern) { return removeEntry(null, name, removePattern); } /** * Removes entry from the INI file from the given section. * * @param sectionName * Section name. If <code>sectionName</code> is <code>null</code> * , matching entries from all sections will be removed. * * @param name * Entry name * @param removePattern * Pattern to check against existing entry value, before removing * it. If <code>removePattern</code> is <code>null</code> every * entry that matches the given name will be removed. * @return <code>true</code> if some entry was removed, otherwise - false */ public boolean removeEntry(String sectionName, String name, String removePattern) { if (name == null) { throw new NullPointerException(); } boolean removed = false; for (INIFileSection section : sections) { if (sectionName == null || section.name.equals(sectionName)) { for (int i = 0; i < section.lines.size(); ++i) { Matcher m = NAME_VAL_PATTERN.matcher(section.lines.get(i)); if (m.matches()) { String oldName = m.group(1); String oldValue = m.group(2); if (oldName.equals(name) && (removePattern == null || oldValue.matches(removePattern))) { section.lines.remove(i--); removed = true; } } } if (sectionName != null) { break; } } } return removed; } /** * Removes entry from the INI file from the global section. * * @param name * Entry name * @param commentPattern * Pattern to check against existing entry value, before removing * it. If <code>commentPattern</code> is <code>null</code> every * entry that matches the given name will be commented. */ public void commentEntry(String name, String commentPattern) { commentEntry(GLOBAL_SECTION, name, commentPattern); } /** * Removes entry from the INI file from all sections. Same as * <code>commentEntry(null, name, commentPattern)</code>. * * @param name * Entry name * @param commentPattern * Pattern to check against existing entry value, before removing * it. If <code>commentPattern</code> is <code>null</code> every * entry that matches the given name will be commented. * * @see #commentEntry(String, String, String) */ public void commentAllEntries(String name, String commentPattern) { commentEntry(null, name, commentPattern); } /** * Removes entry from the INI file from the given section. * * @param sectionName * Section name. If <code>sectionName</code> is <code>null</code> * , matching entries from all sections will be commented. * * @param name * Entry name * @param commentPattern * Pattern to check against existing entry value, before removing * it. If <code>commentPattern</code> is <code>null</code> every * entry that matches the given name will be commented. */ public void commentEntry(String sectionName, String name, String commentPattern) { if (name == null) { throw new NullPointerException(); } for (INIFileSection section : sections) { if (sectionName == null || section.name.equals(sectionName)) { for (int i = 0; i < section.lines.size(); ++i) { String line = section.lines.get(i); Matcher m = NAME_VAL_PATTERN.matcher(line); if (m.matches()) { String oldName = m.group(1); String oldValue = m.group(2); if (!line.startsWith(";") //$NON-NLS-1$ && oldName.equals(name) && (commentPattern == null || oldValue.matches(commentPattern))) { section.lines.set(i, ';' + line); } } } if (sectionName != null) { break; } } } } /** * Checks if the entry with given key name exists in any of available * sections. * * @param sectionName * @return <code>true</code> if entry already exists, <code>false</code> * otherwise */ public boolean hasEntry(String name) { for (INIFileSection section : sections) { if (hasEntry(section, name)) { return true; } } return false; } /** * Checks if the entry with given key name exists in the named section. * * @param sectionName * @param name * @return */ public boolean hasEntry(String sectionName, String name) { for (INIFileSection section : sections) { if (section.name.equals(sectionName) && hasEntry(section, name)) { return true; } } return false; } /** * Writes all changes to the INI configuration file * * @throws IOException */ public void close() throws IOException { flush(); } /** * Reads INI file contents * * @throws IOException */ protected void read() throws IOException { BufferedReader r = new BufferedReader(new FileReader(configFile)); String line; INIFileSection currentSection = new INIFileSection(GLOBAL_SECTION); sections.add(currentSection); while ((line = r.readLine()) != null) { line = line.trim(); Matcher m = SECTION_PATTERN.matcher(line); if (m.matches()) { String sectionName = m.group(1); currentSection = new INIFileSection(sectionName); sections.add(currentSection); } else { currentSection.lines.add(line); } } r.close(); } /** * Writes INI file contents back to the file * * @throws IOException */ protected void flush() throws IOException { PrintWriter w = new PrintWriter(new FileWriter(configFile)); for (INIFileSection section : sections) { if (section.name != GLOBAL_SECTION) { w.println('[' + section.name + ']'); } for (String line : section.lines) { w.println(line); } } w.close(); } /** * Puts quotes around the given string * * @param str * String * @return result string */ private String quoteString(String str) { if (str.startsWith("\"") && str.endsWith("\"") || str.startsWith("'") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ && str.endsWith("'")) { //$NON-NLS-1$ return str; } return '"' + str + '"'; } private boolean hasEntry(INIFileSection section, String name) { for (int i = 0; i < section.lines.size(); ++i) { Matcher m = NAME_VAL_PATTERN.matcher(section.lines.get(i)); if (m.matches()) { String entryName = m.group(1); if (entryName.equals(name)) return true; } } return false; } }