5c70d9d85a6f690ae5c591b7d884677efad7fbaa
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

1) /*
2)  * EtherPix simulator
3)  *
4)  * Copyright 2017 Stefan Schuermans <stefan schuermans info>
5)  *
6)  * This program is free software: you can redistribute it and/or modify
7)  * it under the terms of the GNU General Public License as published by
8)  * the Free Software Foundation, version 3 of the License.
9)  *
10)  *
11)  * This program is distributed in the hope that it will be useful,
12)  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13)  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14)  * GNU General Public License for more details.
15)  *
16)  * You should have received a copy of the GNU Lesser General Public License
17)  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18)  */
19) 
20) #include <algorithm>
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

21) #include <arpa/inet.h>
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

22) #include <cctype>
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

23) #include <cmath>
24) #include <cstdlib>
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

25) #include <functional>
26) #include <fstream>
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

27) #include <map>
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

28) #include <netinet/in.h>
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

29) #include <stdexcept>
30) #include <sstream>
31) #include <string>
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

32) #include <sys/socket.h>
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

33) 
Stefan Schuermans implement drawing pixels

Stefan Schuermans authored 7 years ago

34) #include "bbox.h"
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

35) #include "config.h"
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

36) #include "distri.h"
37) #include "mapping.h"
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

38) #include "pixel.h"
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

39) 
40) /**
41)  * @brief constructor
42)  * @param[in] configFile name of config file
43)  */
Stefan Schuermans implement drawing pixels

Stefan Schuermans authored 7 years ago

44) Config::Config(std::string const &configFile):
45)   m_distriMap(),
46)   m_bb()
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

47) {
48)   readFile(configFile);
49) }
50) 
Stefan Schuermans implement receiving packets

Stefan Schuermans authored 7 years ago

51) /**
52)  * @brief create sockets and listen for incoming packets
53)  * @throws std::exception in case of error
54)  */
55) void Config::start()
56) {
57)   try {
58)     DistriMap::iterator dist;
59)     for (dist = m_distriMap.begin(); dist != m_distriMap.end(); ++dist) {
60)       Distri &distri = dist->second;
61)       distri.start();
62)     }
63)   } catch (...) {
64)     stop();
65)     throw;
66)   }
67) }
68) 
69) /**
70)  * @brief stop listening for incoming packets and close sockets
71)  */
72) void Config::stop()
73) {
74)   DistriMap::iterator dist;
75)   for (dist = m_distriMap.begin(); dist != m_distriMap.end(); ++dist) {
76)     Distri &distri = dist->second;
77)     distri.stop();
78)   }
79) }
80) 
81) /// get and reset packet counter of all distributors
82) unsigned long Config::getPacketCounterAndReset()
83) {
84)   unsigned long sum = 0;
85)   DistriMap::iterator dist;
86)   for (dist = m_distriMap.begin(); dist != m_distriMap.end(); ++dist) {
87)     Distri &distri = dist->second;
88)     sum += distri.getPacketCounterAndReset();
89)   }
90)   return sum;
91) }
92) 
Stefan Schuermans implement drawing pixels

Stefan Schuermans authored 7 years ago

93) /**
94)  * @brief draw pixels of all distributors
95)  * @param[in] cairo cairo context for drawing
96)  * @param[in] tf coordinate transformation
97)  */
98) void Config::draw(Cairo::RefPtr<Cairo::Context> &cairo,
99)                   Transform const &tf) const
100) {
101)   DistriMap::const_iterator dist;
102)   for (dist = m_distriMap.begin(); dist != m_distriMap.end(); ++dist) {
103)     Distri const &distri = dist->second;
104)     distri.draw(cairo, tf);
105)   }
106) }
107) 
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

108) /**
109)  * @brief remove whitespace at beging and end of string
110)  * @param[in,out] str string to process
111)  */
112) void Config::trim(std::string &str)
113) {
114)   // remove leading whitespace
115)   str.erase(str.begin(),
116)             std::find_if(str.begin(), str.end(),
117)                          std::not1(std::ptr_fun<int, int>(std::isspace))));
118) 
119)   // remove trailing whitespace
120)   str.erase(std::find_if(str.rbegin(), str.rend(),
121)                          std::not1(std::ptr_fun<int, int>(std::isspace))).base(),
122)             str.end());
123) }
124) 
125) /**
126)  * @brief split string at sequences of whitespace
127)  * @param[in] str string to split
128)  * @param[out] fields fields of string
129)  */
130) void Config::split(std::string const &str, std::vector<std::string> &fields)
131) {
132)   std::stringstream strm(str);
133)   fields.clear();
134)   while (! strm.eof()) {
135)     std::string field;
136)     strm >> field;
137)     if (! field.empty()) {
138)       fields.push_back(field);
139)     }
140)   }
141) }
142) 
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

143) /**
144)  * @brief split string at specific character
145)  * @param[in] str string to split
146)  * @param[in] delim delimiter character
147)  * @param[out] fields fields of string
148)  */
149) void Config::split_chr(std::string const &str, char delim,
150)                        std::vector<std::string> &fields)
151) {
152)   std::string::size_type pos = 0, end;
153)   fields.clear();
154)   while ((end = str.find(delim, pos)) != std::string::npos) {
155)     fields.push_back(str.substr(pos, end - pos));
156)     pos = end + 1;
157)   }
158)   fields.push_back(str.substr(pos));
159) }
160) 
161) /**
162)  * @brief convert string to unsigned long
163)  * @param[in] str string to convert
164)  * @return unsigned long parsed from string
165)  * @throws std::exception in case of error
166)  */
167) unsigned long Config::str2ul(std::string const &str)
168) {
169)   char const *sz = str.c_str();
170)   char *end;
171)   unsigned long ul = strtoul(sz, &end, 0);
172)   if (end == sz || *end != 0) {
173)     std::stringstream msg;
174)     msg << "invalid unsigned integer \"" << str << "\"";
175)     throw std::runtime_error(msg.str());
176)   }
177)   return ul;
178) }
179) 
180) /**
181)  * @brief convert string to two unsigned longs
182)  * @param[in] str string containing two comma-separated unsigned integers
183)  * @param[out] ul1 first unsigned long parsed from string
184)  * @param[out] ul2 second unsigned long parsed from string
185)  * @throws std::exception in case of error
186)  */
187) void Config::str2ul2(std::string const &str,
188)                      unsigned long &ul1, unsigned long &ul2)
189) {
190)   std::vector<std::string> fields;
191)   split_chr(str, ',', fields);
192)   if (fields.size() != 2) {
193)     std::stringstream msg;
194)     msg << "expected two comma-separated unsigned integers, found \""
195)         << str << "\"";
196)     throw std::runtime_error(msg.str());
197)   }
198)   try {
199)     ul1 = str2ul(fields[0]);
200)     ul2 = str2ul(fields[1]);
201)   } catch (std::exception &ex) {
202)     std::stringstream msg;
203)     msg << "invalid unsigned integer pair \"" << str << "\": " << ex.what();
204)     throw std::runtime_error(msg.str());
205)   }
206) }
207) 
208) /**
209)  * @brief convert string to double (using the decimal dot for any locale)
210)  * @param[in] str string to convert
211)  * @return double parsed from string
212)  * @throws std::exception in case of error
213)  */
214) double Config::str2d(std::string const &str)
215) {
216)   char const *sz = str.c_str();
217) 
218)   // skip leading whitespace
219)   while (isspace(*sz)) {
220)     ++sz;
221)   }
222) 
223)   // start processing after leading whitespace
224)   char const *ptr = sz;
225) 
226)   // read optional sign
227)   double sign = 1.0;
228)   if (*ptr == '+') {
229)     sign = 1.0;
230)     ++ptr;
231)   } else if (*ptr == '-') {
232)     sign = -1.0;
233)     ++ptr;
234)   }
235) 
236)   // read digits before dot
237)   double value = 0.0;
238)   while (*ptr >= '0' && *ptr <= '9') {
239)     value = value * 10.0 + (double)(*ptr - '0');
240)     ++ptr;
241)   }
242) 
243)   // read dot and digits after it
244)   double weight = 0.1;
245)   if (*ptr == '.') {
246)     ++ptr;
247) 
248)     /* read digits after dot */
249)     while (*ptr >= '0' && *ptr <= '9') {
250)       value += weight * (double)(*ptr - '0');
251)       weight *= 0.1;
252)       ++ptr;
253)     }
254) 
255)   } // if (*ptr == '.')
256) 
257)   // merge sign into value
258)   value *= sign;
259) 
260)   // read exponent
261)   if (*ptr == 'E' || *ptr == 'e') {
262)     ++ptr;
263) 
264)     /* read optional sign */
265)     int exp_sign = 1;
266)     if (*ptr == '+') {
267)       exp_sign = 1;
268)       ++ptr;
269)     } else if (*ptr == '-') {
270)       exp_sign = -1;
271)       ++ptr;
272)     }
273) 
274)     /* read digits */
275)     int exp_value = 0;
276)     while (*ptr >= '0' && *ptr <= '9') {
277)       exp_value = exp_value * 10 + (int)(*ptr - '0');
278)       ++ptr;
279)     }
280) 
281)     /* merge exponent into value */
282)     value *= pow(10.0, exp_sign * exp_value);
283) 
284)   } // if (*nptr == 'E' || *nptr == 'e')
285) 
286)   // skip trailing whitespace
287)   while (isspace(*ptr)) {
288)     ++ptr;
289)   }
290) 
291)   // leftover characters -> error */
292)   if (ptr == sz || *ptr != 0) {
293)     std::stringstream msg;
294)     msg << "invalid floating point value \"" << str << "\"";
295)     throw std::runtime_error(msg.str());
296)   }
297) 
298)   // return value
299)   return value;
300) }
301) 
302) /**
303)  * @brief convert string to three doubles (decimal dot for any locale)
304)  * @param[in] str string containing three comma-separated doubles
305)  * @param[out] d1 first double parsed from string
306)  * @param[out] d2 second double parsed from string
307)  * @param[out] d3 third double parsed from string
308)  * @throws std::exception in case of error
309)  */
310) void Config::str2d3(std::string const &str,
311)                     double &d1, double &d2, double &d3)
312) {
313)   std::vector<std::string> fields;
314)   split_chr(str, ',', fields);
315)   if (fields.size() != 3) {
316)     std::stringstream msg;
317)     msg << "expected three comma-separated floating point values, found \""
318)         << str << "\"";
319)     throw std::runtime_error(msg.str());
320)   }
321)   try {
322)     d1 = str2d(fields[0]);
323)     d2 = str2d(fields[1]);
324)     d3 = str2d(fields[2]);
325)   } catch (std::exception &ex) {
326)     std::stringstream msg;
327)     msg << "invalid floating point triplet \"" << str << "\": " << ex.what();
328)     throw std::runtime_error(msg.str());
329)   }
330) }
331) 
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

332) /**
333)  * @brief convert string to IPv4/port address
334)  * @param[in] str string containing IPv4/port address
335)  * @throws std::exception in case of error
336)  */
337) void Config::str2addr(std::string const &str, struct sockaddr_in &addr)
338) {
339)   // split address into IPv4 and port
340)   std::vector<std::string> fields;
341)   split_chr(str, ':', fields);
342)   if (fields.size() != 2) {
343)     std::stringstream msg;
344)     msg << "expected \"<IPv4>:<port>\", found \"" << str << "\"";
345)     throw std::runtime_error(msg.str());
346)   }
347)   std::string &strIPv4 = fields[0], &strPort = fields[1];
348) 
349)   // parse IPv4 address
350)   if (! inet_aton(strIPv4.c_str(), &addr.sin_addr)) {
351)     std::stringstream msg;
352)     msg << "invalid IPv4 \"" << strIPv4 << "\"";
353)     throw std::runtime_error(msg.str());
354)   }
355) 
356)   // parse port
357)   unsigned long port;
358)   try {
359)     port = str2ul(strPort);
360)     if (port == 0 || port > 65535) {
361)       throw std::runtime_error("port number out of range");
362)     }
363)   } catch (std::exception &ex) {
364)     std::stringstream msg;
365)     msg << "invalid port number \"" << strPort << "\": " << ex.what();
366)     throw std::runtime_error(msg.str());
367)   }
368)   addr.sin_port = htons(port);
369) 
370)   // fin in remaining fields of address structure
371)   addr.sin_family = AF_INET;
372) }
373) 
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

374) /**
375)  * @brief read config file
376)  * @param[in] configFile name of config file
377)  * @throws std::exception in case of error
378)  */
379) void Config::readFile(std::string const &configFile)
380) {
381)   // open file
382)   std::ifstream cf(configFile.c_str(), std::ios::in);
383)   if (! cf.is_open()) {
384)     std::stringstream msg;
385)     msg << "cannot open config file \"" << configFile <<  "\" for reading";
386)     throw std::runtime_error(msg.str());
387)   }
388) 
389)   // read lines and process them
390)   std::string line;
391)   size_t no;
392)   for (no = 1; std::getline(cf, line); ++no) {
393)     // process line
394)     try {
395)       procLine(line);
396)     } catch (std::exception &ex) {
397)       std::stringstream msg;
398)       msg << "error in line " << no << " of config file \"" << configFile
399)           << "\": " << ex.what();
400)       throw std::runtime_error(msg.str());
401)     }
402)   }
403) 
404)   // close file
405)   cf.close();
Stefan Schuermans implement drawing pixels

Stefan Schuermans authored 7 years ago

406) 
407)   // update internal data
408)   update();
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

409) }
410) 
411) /**
412)  * @brief process line from config file
413)  * @param[in] line line to process
414)  * @throws std::exception in case of error
415)  */
416) void Config::procLine(std::string line)
417) {
418)   // remove comment ("# ...")
419)   size_t commentStart = line.find("#");
420)   if (commentStart != std::string::npos) {
421)     line.erase(commentStart);
422)   }
423) 
424)   trim(line);
425) 
426)   // ignore empty lines
427)   if (line.empty()) {
428)     return;
429)   }
430) 
431)   // split line at equal sign
432)   size_t equalSign = line.find("=");
433)   if (equalSign == std::string::npos) {
434)     std::stringstream msg;
435)     msg << "no equal sign found in \"" << line << "\"";
436)     throw std::runtime_error(msg.str());
437)   }
438)   std::string setting = line.substr(0, equalSign);
439)   std::string value = line.substr(equalSign + 1);
440)   trim(setting);
441)   trim(value);
442) 
443)   procSetting(setting, value);
444) }
445) 
446) /**
447)  * @brief process setting from config file
448)  * @param[in] setting name of the setting
449)  * @param[in] value value for setting
450)  * @throws std::exception in case of error
451)  */
452) void Config::procSetting(std::string const &setting, std::string const &value)
453) {
454)   std::vector<std::string> setFields, valFields;
455)   split(setting, setFields);
456)   split(value, valFields);
457) 
458)   // empty setting
459)   if (setFields.size() < 1) {
460)     throw std::runtime_error("empty setting name");
461)   }
462) 
463)   // distributor
464)   if (setFields[0] == "distributor") {
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

465)     proc_distributor(setFields, valFields);
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

466)   }
467)   // distributor address
468)   else if (setFields[0] == "distributorAddr") {
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

469)     proc_distributorAddr(setFields, valFields);
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

470)   }
471)   // mapping
472)   else if (setFields[0] == "mapping") {
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

473)     proc_mapping(setFields, valFields);
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

474)   }
475)   // output
476)   else if (setFields[0] == "output") {
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

477)     proc_output(setFields, valFields);
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

478)   }
479)   // unknown setting
480)   else {
481)     std::stringstream msg;
482)     msg << "unknown setting \"" << setting << "\"";
483)     throw std::runtime_error(msg.str());
484)   }
485) }
486) 
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

487) /**
488)  * @brief process distributor line from config file
489)  * @param[in] setFields fields of the setting parts
490)  * @param[in] valFields fields of the value part
491)  * @throws std::exception in case of error
492)  */
493) void Config::proc_distributor(std::vector<std::string> const &setFields,
494)                               std::vector<std::string> const &valFields)
495) {
496)   // check number of setting fields
497)   if (setFields.size() != 2) {
498)     std::stringstream msg;
499)     msg << "invalid \"distributor\" setting with " << setFields.size()
500)         << " fields, expected \"distributor <distno>\"";
501)     throw std::runtime_error(msg.str());
502)   }
503) 
504)   // get and check distributor number
505)   unsigned long distno;
506)   try {
507)     distno = str2ul(setFields[1]);
508)   } catch (std::exception &ex) {
509)     std::stringstream msg;
510)     msg << "invalid distributor number \"" << setFields[1] << "\": "
511)         << ex.what();
512)     throw std::runtime_error(msg.str());
513)   }
514)   if (m_distriMap.find(distno) != m_distriMap.end()) {
515)     std::stringstream msg;
516)     msg << "duplicate \"distributor " << distno << "\" setting";
517)     throw std::runtime_error(msg.str());
518)   }
519) 
520)   // check number of value fields
521)   if (valFields.size() != 1) {
522)     std::stringstream msg;
523)     msg << "invalid value for \"distributor " << distno << "\": "
524)         << setFields.size() << " fields, expected \"<outputs>,<pixels>\"";
525)     throw std::runtime_error(msg.str());
526)   }
527) 
528)   // get and check outputs and pixels per output
529)   unsigned long outputs, pixels;
530)   try {
531)     str2ul2(valFields[0], outputs, pixels);
532)     if (outputs < 1) {
533)       std::stringstream msg;
534)       msg << "invalid number of outputs \"" << outputs << "\"";
535)       throw std::runtime_error(msg.str());
536)     }
537)     if (pixels < 1) {
538)       std::stringstream msg;
539)       msg << "invalid number of pixels per output \"" << pixels << "\"";
540)       throw std::runtime_error(msg.str());
541)     }
542)   } catch (std::exception &ex) {
543)     std::stringstream msg;
544)     msg << "invalid value for \"distributor " << distno << "\": "
545)         << ex.what();
546)     throw std::runtime_error(msg.str());
547)   }
548) 
549)   // create distributor
550)   m_distriMap[distno].init(distno, outputs, pixels);
551) }
552) 
553) /**
554)  * @brief process distributorAddr line from config file
555)  * @param[in] setFields fields of the setting parts
556)  * @param[in] valFields fields of the value part
557)  * @throws std::exception in case of error
558)  */
559) void Config::proc_distributorAddr(std::vector<std::string> const &setFields,
560)                                   std::vector<std::string> const &valFields)
561) {
562)   // check number of setting fields
563)   if (setFields.size() != 2) {
564)     std::stringstream msg;
565)     msg << "invalid \"distributorAddr\" setting with " << setFields.size()
566)         << " fields, expected \"distributorAddr <distno>\"";
567)     throw std::runtime_error(msg.str());
568)   }
569) 
570)   // get distributor
571)   Distri &distri = getDistri(setFields[1]);
572) 
573)   // check number of value fields
574)   if (valFields.size() != 1) {
575)     std::stringstream msg;
576)     msg << "invalid value for \"distributorAddr " << distri.getNo() << "\": "
577)         << setFields.size() << " fields, expected \"<IPv4>:<port>\"";
578)     throw std::runtime_error(msg.str());
579)   }
580) 
581)   // parse address
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

582)   struct sockaddr_in addr;
583)   try {
584)     str2addr(valFields[0], addr);
585)   } catch (std::exception &ex) {
586)     std::stringstream msg;
587)     msg << "invalid value for \"mdistributorAddr " << distri.getNo() << "\": "
588)         << ex.what();
589)     throw std::runtime_error(msg.str());
590)   }
591) 
592)   // set address
593)   distri.setAddr(addr);
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

594) }
595) 
596) /**
597)  * @brief process mapping line from config file
598)  * @param[in] setFields fields of the setting parts
599)  * @param[in] valFields fields of the value part
600)  * @throws std::exception in case of error
601)  */
602) void Config::proc_mapping(std::vector<std::string> const &setFields,
603)                           std::vector<std::string> const &valFields)
604) {
605)   // check number of setting fields
606)   if (setFields.size() != 3) {
607)     std::stringstream msg;
608)     msg << "invalid \"mapping\" setting with " << setFields.size()
609)         << " fields, expected \"mapping <distno> [red|green|blue]\"";
610)     throw std::runtime_error(msg.str());
611)   }
612) 
613)   // get distributor
614)   Distri &distri = getDistri(setFields[1]);
615) 
616)   // get channel
617)   std::string strColor = setFields[2];
618)   Mapping::Channel channel;
619)   if (strColor == "red" ) {
620)     channel = Mapping::Red;
621)   } else if (strColor == "green" ) {
622)     channel = Mapping::Green;
623)   } else if (strColor == "blue" ) {
624)     channel = Mapping::Blue;
625)   } else {
626)     std::stringstream msg;
627)     msg << "invalid \"mapping\" setting: unknown color \"" << strColor
628)         << "\" fields, expected \"red\", \"green\" or \"blue\"";
629)     throw std::runtime_error(msg.str());
630)   }
631) 
632)   // check number of value fields
633)   if (valFields.size() != 3) {
634)     std::stringstream msg;
635)     msg << "invalid value for \"mapping " << distri.getNo() << " "
636)         << strColor << "\": " << setFields.size()
637)         << " fields, expected \"<base> <factor> <gamma>\"";
638)     throw std::runtime_error(msg.str());
639)   }
640) 
641)   // parse value fields
642)   double base, factor, gamma;
643)   try {
644)     base = str2d(valFields[0]);
645)   } catch (std::exception &ex) {
646)     std::stringstream msg;
647)     msg << "invalid value for \"mapping " << distri.getNo() << " "
648)             << strColor << "\": invalid value \"" << valFields[0]
649)             << "\"for \"base\": " << ex.what();
650)     throw std::runtime_error(msg.str());
651)   }
652)   try {
653)     factor = str2d(valFields[1]);
654)   } catch (std::exception &ex) {
655)     std::stringstream msg;
656)     msg << "invalid value for \"mapping " << distri.getNo() << " "
657)             << strColor << "\": invalid value \"" << valFields[1]
658)             << "\"for \"factor\": " << ex.what();
659)     throw std::runtime_error(msg.str());
660)   }
661)   try {
662)     gamma = str2d(valFields[2]);
663)     if (gamma <= 0.0) {
664)       throw std::runtime_error("gamma value must be positive");
665)     }
666)   } catch (std::exception &ex) {
667)     std::stringstream msg;
668)     msg << "invalid value for \"mapping " << distri.getNo() << " "
669)             << strColor << "\": invalid value \"" << valFields[2]
670)             << "\"for \"base\": " << ex.what();
671)     throw std::runtime_error(msg.str());
672)   }
673) 
674)   // set mapping of distributor
675)   distri.setMapping(channel, Mapping(base, factor, gamma));
676) }
677) 
678) /**
679)  * @brief process output line from config file
680)  * @param[in] setFields fields of the setting parts
681)  * @param[in] valFields fields of the value part
682)  * @throws std::exception in case of error
683)  */
684) void Config::proc_output(std::vector<std::string> const &setFields,
685)                          std::vector<std::string> const &valFields)
686) {
687)   // check number of setting fields
688)   if (setFields.size() != 2) {
689)     std::stringstream msg;
690)     msg << "invalid \"output\" setting with " << setFields.size()
691)         << " fields, expected \"output <distno>,<outno>\"";
692)     throw std::runtime_error(msg.str());
693)   }
694) 
695)   // parse distributor and output numbers
696)   unsigned long distno, outno;
697)   try {
698)     str2ul2(setFields[1], distno, outno);
699)   } catch (std::exception &ex) {
700)     std::stringstream msg;
701)     msg << "invalid output specifier \"" << setFields[1]
702)         << "\": expected \"<distno>,<outno>\": " << ex.what();
703)     throw std::runtime_error(msg.str());
704)   }
705) 
706)   // get distributor
707)   Distri &distri = getDistri(distno);
708) 
709)   // check output number
710)   unsigned long outputs = distri.getOutputs();
711)   if (outno > outputs) {
712)     std::stringstream msg;
713)     msg << "invalid output number " << outno << " for distributor " << distno
714)         << ": only " << outputs << " outputs available";
715)     throw std::runtime_error(msg.str());
716)   }
717) 
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

718)   // add output to distributor
719)   try {
720)     distri.addOutput(outno);
721)   } catch (std::exception &ex) {
722)     std::stringstream msg;
723)     msg << "cannot add output " << outno << " to distributor " << distno
724)         << ": " << ex.what();
725)     throw std::runtime_error(msg.str());
726)   }
727) 
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

728)   // parse all pixels
729)   std::vector<std::string>::const_iterator pix;
730)   unsigned long p;
731)   for (pix = valFields.begin(), p = 0; pix != valFields.end(); ++pix, ++p) {
732)     // parse pixel description
733)     double x, y, r;
734)     try {
735)       str2d3(*pix, x, y, r);
736)     } catch (std::exception &ex) {
737)       std::stringstream msg;
738)       msg << "invalid pixel description \"" << *pix << "\" for pixel "
739)           << p << " at output " << outno << " of distributor " << distno
740)           << ": expected \"<x>,<y>,<r>\": " << ex.what();
741)       throw std::runtime_error(msg.str());
742)     }
743)     // add pixel
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

744)     try {
745)       distri.addPixel(outno, Pixel(x, y, r));
746)     } catch (std::exception &ex) {
747)       std::stringstream msg;
748)       msg << "cannot add pixel \"" << *pix << "\" (pixel "
749)           << p << ") to output " << outno << " of distributor " << distno
750)           << ": " << ex.what();
751)       throw std::runtime_error(msg.str());
752)     }
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

753)   } // for pixel
754) }
755) 
756) /**
757)  * @brief get distributor
758)  * @param[in] strDistno distributor number as string
759)  * @return reference to distributor object in map
760)  * @throws std::exception in case of error
761)  */
762) Distri & Config::getDistri(std::string const &strDistno)
763) {
764)   unsigned long distno;
765)   try {
766)     distno = str2ul(strDistno);
767)   } catch (std::exception &ex) {
768)     std::stringstream msg;
769)     msg << "invalid distributor number \"" << strDistno << "\": "
770)         << ex.what();
771)     throw std::runtime_error(msg.str());
772)   }
773)   return getDistri(distno);
774) }
775) 
776) /**
777)  * @brief get distributor
778)  * @param[in] distno distributor number
779)  * @return reference to distributor object in map
780)  * @throws std::exception in case of error
781)  */
782) Distri & Config::getDistri(unsigned long distno)
783) {
784)   DistriMap::iterator distri = m_distriMap.find(distno);
785)   if (distri == m_distriMap.end()) {
786)     std::stringstream msg;
787)     msg << "no distributor with number \"" << distno << "\" found";
788)     throw std::runtime_error(msg.str());
789)   }
790)   return distri->second;
791) }
792)