BlinkenArea - GitList
Repositories
Blog
Wiki
JEtherPix
Code
Commits
Branches
Tags
Search
Tree:
3a6f6fd
Branches
Tags
master
JEtherPix
org
blinkenarea
JFlexiPix
Config.java
remaining parts of config parser implemented
Stefan Schuermans
commited
3a6f6fd
at 2011-09-11 10:46:13
Config.java
Blame
History
Raw
/* JFlexiPix - Java implementation of FlexiPix output library * * Copyright 2010-2011 Stefan Schuermans <stefan blinkenarea org> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, version 3 of the License. * * * This program 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 General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.blinkenarea.JFlexiPix; import java.io.*; import java.net.*; import java.util.*; import java.util.regex.*; /// configuration parser class Config { /** * @brief constructor * @param[in] display display to configure * @param[in] messageIf message interface to report messages to or null */ Config(Display display, MessageIf messageIf) { // save constructor parameters m_display = display; m_messageIf = messageIf; // compile regular expression patterns // empty lines: " # comment" m_patternEmpty = Pattern.compile("^" + "\\s*" + "(?:#.*)?" + "$"); // extract setting and value from " setting = value # comment" m_patternLine = Pattern.compile("^" + "\\s*" + "([^\\s=#](?:[^=#]*[^\\s=#])?)" + "\\s*=\\s*" + "([^\\s=#](?:[^=#]*[^\\s=#])?)" + "\\s*" + "(?:#.*)?" + "$"); } /** * @brief process distributor from config file * * @param[in] settingPart2 second half of setting to process * @param[in] value value of setting */ void procDistri(String settingPart2, String value) throws Exception { int dist, out, pix; Pixel px; // get distributor number try { dist = Integer.parseInt(settingPart2); } catch (NumberFormatException e) { dist = Constants.distriMaxCnt; // force error in next line } if (dist >= Constants.distriMaxCnt) errorExc("invalid distributor number \"" + settingPart2 + "\"" + String.format(" in line %d of config file", m_lineNo)); // get number of outputs and pixels px = PixelParser.parsePixel(value); // abuse for "outputs,pixels" if (px == null) errorExc("invalid distributor size \"" + value + "\"" + String.format(" in line %d of config file", m_lineNo)); out = px.m_x; if (out >= Constants.outputMaxCnt) errorExc(String.format("invalid number of outputs \"%d\"" + " in line %d of config file", out, m_lineNo)); pix = px.m_y; if (pix >= Constants.pixelMaxCnt) errorExc(String.format("invalid number of pixels \"%d\"" + " in line %d of config file", pix, m_lineNo)); // check if distributor is already present if (m_display.m_distris[dist] != null) errorExc(String.format("duplicate definition of distributor \"%d\"" + " in line %d of config file", dist, m_lineNo)); // create new distributor m_display.m_distris[dist] = new Distri(dist, out, pix); // count distributors m_display.m_distriCnt++; } /** * @brief process mapping from config file * * @param[in] settingPart2 second half of setting to process * @param[in] value value of setting */ void procMapping(String settingPart2, String value) throws Exception { Pattern pattern; Matcher matcher; String strDistri, strChannel, strBase, strFactor, strGamma; int dist; Distri distri; Mapping mapping = null; double base = 0.0, factor = 1.0, gamma = 1.0; // split setting part 2 into distributor and channel pattern = Pattern.compile("^([0-9]+) +([a-z]+)$"); matcher = pattern.matcher(settingPart2); if (!matcher.find()) errorExc("invalid mapping specifier \"" + settingPart2 + "\"" + String.format(" in line %d of config file", m_lineNo)); strDistri = matcher.group(1); strChannel = matcher.group(2); // get distributor number try { dist = Integer.parseInt(strDistri); } catch (NumberFormatException e) { dist = Constants.distriMaxCnt; // force error in next line } if (dist >= Constants.distriMaxCnt) errorExc("invalid distributor number \"" + strDistri + "\"" + String.format(" in line %d of config file", m_lineNo)); // get distributor distri = m_display.m_distris[dist]; if (distri == null) errorExc(String.format("no distributor with number \"%d\"" + " in line %d of config file", dist, m_lineNo)); // get channel if (strChannel.equals("red")) mapping = distri.m_mapRed; else if (strChannel.equals("green")) mapping = distri.m_mapGreen; else if (strChannel.equals("blue")) mapping = distri.m_mapBlue; else errorExc("invalid channel \"" + strChannel + "\"" + String.format(" in line %d of config file", m_lineNo)); // split mapping parameters pattern = Pattern.compile("^([-+.eE0-9]+) +([-+.eE0-9]+) +([-+.eE0-9]+)$"); matcher = pattern.matcher(value); if (!matcher.find()) errorExc("invalid mapping parameters \"" + value + "\"" + String.format(" in line %d of config file", m_lineNo)); strBase = matcher.group(1); strFactor = matcher.group(2); strGamma = matcher.group(3); // parse mapping parameters try { base = Double.parseDouble(strBase); factor = Double.parseDouble(strFactor); gamma = Double.parseDouble(strGamma); } catch (NumberFormatException e) { errorExc("invalid mapping parameters \"" + value + "\"" + String.format(" in line %d of config file", m_lineNo), e); } if (gamma <= 0.0) errorExc(String.format("invalid gamma value \"%f\"" + " in line %d of config file", gamma, m_lineNo)); // update mapping parameters mapping.set(base, factor, gamma); } /** * @brief process pixel from config file * * @param[in] txtPixel text of pixel to process * @param[in] distri distributor * @param[in] dist number of distributor * @param[in] out number of output * @param[in] pix number of pixel * @param return if parsing was successful */ boolean procPixel(String txtPixel, Distri distri, int dist, int out, int pix) { Pixel pixel; int idx; // get coordinates of pixel pixel = PixelParser.parsePixel(txtPixel); if (pixel == null) { error("invalid pixel \"" + txtPixel + "\"" + String.format(" in line %d of config file", m_lineNo)); return false; } // check pixel number if (pix >= Constants.pixelMaxCnt || pix >= distri.m_pixelCnt) { error(String.format("too many pixels (more than %d)" + " in line %d of config file", distri.m_pixelCnt, m_lineNo)); return false; } // check that pixel is not yet set idx = out * distri.m_pixelCnt + pix; if (distri.m_pixels[idx] != null) { error(String.format("pixel %d of output %d of distributor %d" + " already set to pixel %d,%d" + " in line %d of config file", pix, out, dist, distri.m_pixels[idx].m_x, distri.m_pixels[idx].m_y, m_lineNo)); return false; } // create pixel distri.m_pixels[idx] = pixel; // count pixels in total m_display.m_pixelCnt++; return true; } /** * @brief process output from config file * * @param[in] settingPart2 second half of setting to process * @param[in] value value of setting */ void procOutput(String settingPart2, String value) throws Exception { Pixel px; int dist, out, pix; Distri distri; String [] pixels; boolean err; // get number of distributor and output px = PixelParser.parsePixel(settingPart2); // abuse for "dist,out" if (px == null) errorExc("invalid output specifier \"" + settingPart2 + "\"" + String.format(" in line %d of config file", m_lineNo)); dist = px.m_x; if (dist >= Constants.distriMaxCnt) errorExc(String.format("invalid distributor number \"%d\"" + " in line %d of config file", dist, m_lineNo)); out = px.m_y; if (out >= Constants.outputMaxCnt) errorExc(String.format("invalid output number \"%d\"" + " in line %d of config file", out, m_lineNo)); // get distributor distri = m_display.m_distris[dist]; if (distri == null) errorExc(String.format("no distributor with number \"%d\"" + " in line %d of config file", dist, m_lineNo)); // check output number if (out >= distri.m_outputCnt) errorExc(String.format("no output with output number \"%d\"" + " in line %d of config file", out, m_lineNo)); // count outputs m_display.m_outputCnt++; // process pixels pixels = value.split("\\s+"); err = false; for (pix = 0; pix < pixels.length; ++pix) if (!procPixel(pixels[pix], distri, dist, out, pix)) err = true; if (err) errorExc(String.format("invalid pixels in line %d of config file", m_lineNo)); } /** * @brief process setting from config file * * @param[in] setting setting to process * @param[in] value value of setting */ void procSetting(String setting, String value) throws Exception { InetSocketAddress addr; Pixel pix; // replace all whitespace in setting with spaces setting = setting.replace('\t', ' ').replace('\r', ' ') .replace('\n', ' ').replace('\f', ' '); // bind address of UDP output if (setting.equals("bindAddr")) { addr = AddrParser.parseAddr(value); if (addr == null) { errorExc("invalid addess \"" + value + "\" for \"" + setting + String.format(" in line %d of config file", m_lineNo)); } info("bind address: " + addr.toString()); m_display.m_bindAddr = addr; return; } // size of display if (setting.equals("size")) { pix = PixelParser.parsePixel(value); if (pix == null || pix.m_x <= 0 || pix.m_y <= 0) { errorExc("invalid value \"" + value + "\" for \"" + setting + String.format(" in line %d of config file", m_lineNo)); } m_display.m_size = pix; return; } // distributor if (setting.startsWith("distributor ")) { procDistri(setting.substring(12), value); return; } // mapping if (setting.startsWith("mapping ")) { procMapping(setting.substring(8), value); return; } // distributor if (setting.startsWith("output ")) { procOutput(setting.substring(7), value); return; } // unknown setting warning("unknown setting \"" + setting + "\"" + String.format(" in line %d of config file", m_lineNo) + ", ignored"); } /** * @brief process line from config file * * @param[in] line line to process */ void procLine(String line) throws Exception { Matcher matcher; String setting, value; // ignore empty lines: " # comment" matcher = m_patternEmpty.matcher(line); if (matcher.find()) return; // extract setting and value from " setting = value # comment" matcher = m_patternLine.matcher(line); if (!matcher.find()) { // line cannot be parsed if (m_messageIf != null) m_messageIf.message(MsgType.Warn, String.format("invalid line %d in config file," + " ignored\n", m_lineNo)); return; } setting = matcher.group(1); value = matcher.group(2); // process setting procSetting(setting, value); } /** * @brief process config file * * @param[in] configFileName name of config file to read */ void procFile(String configFileName) throws Exception { FileReader fr = null; BufferedReader br = null; String line; // check file name if (configFileName.length() == 0) errorExc("no config file specified"); info("using config file \"" + configFileName + "\""); // open file try { fr = new FileReader(configFileName); br = new BufferedReader(fr); } catch (FileNotFoundException e) { errorExc("cannot open config file \"" + configFileName + "\" for reading", e); } // read lines and process them m_lineNo = 1; while ((line = br.readLine()) != null) { procLine(line); ++m_lineNo; } // close file br.close(); fr.close(); info(String.format("%dx%d input format, ", m_display.m_size.m_x, m_display.m_size.m_y) + String.format("%d distributors, ", m_display.m_distriCnt ) + String.format("%d outputs, ", m_display.m_outputCnt ) + String.format("%d pixels\n", m_display.m_pixelCnt)); } /** * @brief report error message * @param[in] txt error text */ private void error(String txt) { if (m_messageIf != null) m_messageIf.message(MsgType.Err, txt + "\n"); } /** * @brief report error message and throw exception * @param[in] txt error text */ private void errorExc(String txt) throws Exception { error(txt); throw new Exception(txt); } /** * @brief report error message and throw exception * @param[in] txt error text * @param[in] e reason for error */ private void errorExc(String txt, Exception e) throws Exception { error(txt + ": " + e.getMessage()); throw new Exception(txt, e); } /** * @brief report warning message * @param[in] txt warning text */ private void warning(String txt) { if (m_messageIf != null) m_messageIf.message(MsgType.Warn, txt + "\n"); } /** * @brief report information message * @param[in] txt information text */ private void info(String txt) { if (m_messageIf != null) m_messageIf.message(MsgType.Info, txt + "\n"); } Display m_display; ///< display to configure MessageIf m_messageIf; ///< message interface to report messages to or null int m_lineNo; ///< current line in config file Pattern m_patternEmpty; ///< empty lines Pattern m_patternLine; ///< setting lines }