5bca604f0c06d7d3c0c8d746e2aabefb53d2bb43
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 drawing pixels

Stefan Schuermans authored 7 years ago

51) /**
52)  * @brief draw pixels of all distributors
53)  * @param[in] cairo cairo context for drawing
54)  * @param[in] tf coordinate transformation
55)  */
56) void Config::draw(Cairo::RefPtr<Cairo::Context> &cairo,
57)                   Transform const &tf) const
58) {
59)   DistriMap::const_iterator dist;
60)   for (dist = m_distriMap.begin(); dist != m_distriMap.end(); ++dist) {
61)     Distri const &distri = dist->second;
62)     distri.draw(cairo, tf);
63)   }
64) }
65) 
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

66) /**
67)  * @brief remove whitespace at beging and end of string
68)  * @param[in,out] str string to process
69)  */
70) void Config::trim(std::string &str)
71) {
72)   // remove leading whitespace
73)   str.erase(str.begin(),
74)             std::find_if(str.begin(), str.end(),
75)                          std::not1(std::ptr_fun<int, int>(std::isspace))));
76) 
77)   // remove trailing whitespace
78)   str.erase(std::find_if(str.rbegin(), str.rend(),
79)                          std::not1(std::ptr_fun<int, int>(std::isspace))).base(),
80)             str.end());
81) }
82) 
83) /**
84)  * @brief split string at sequences of whitespace
85)  * @param[in] str string to split
86)  * @param[out] fields fields of string
87)  */
88) void Config::split(std::string const &str, std::vector<std::string> &fields)
89) {
90)   std::stringstream strm(str);
91)   fields.clear();
92)   while (! strm.eof()) {
93)     std::string field;
94)     strm >> field;
95)     if (! field.empty()) {
96)       fields.push_back(field);
97)     }
98)   }
99) }
100) 
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

101) /**
102)  * @brief split string at specific character
103)  * @param[in] str string to split
104)  * @param[in] delim delimiter character
105)  * @param[out] fields fields of string
106)  */
107) void Config::split_chr(std::string const &str, char delim,
108)                        std::vector<std::string> &fields)
109) {
110)   std::string::size_type pos = 0, end;
111)   fields.clear();
112)   while ((end = str.find(delim, pos)) != std::string::npos) {
113)     fields.push_back(str.substr(pos, end - pos));
114)     pos = end + 1;
115)   }
116)   fields.push_back(str.substr(pos));
117) }
118) 
119) /**
120)  * @brief convert string to unsigned long
121)  * @param[in] str string to convert
122)  * @return unsigned long parsed from string
123)  * @throws std::exception in case of error
124)  */
125) unsigned long Config::str2ul(std::string const &str)
126) {
127)   char const *sz = str.c_str();
128)   char *end;
129)   unsigned long ul = strtoul(sz, &end, 0);
130)   if (end == sz || *end != 0) {
131)     std::stringstream msg;
132)     msg << "invalid unsigned integer \"" << str << "\"";
133)     throw std::runtime_error(msg.str());
134)   }
135)   return ul;
136) }
137) 
138) /**
139)  * @brief convert string to two unsigned longs
140)  * @param[in] str string containing two comma-separated unsigned integers
141)  * @param[out] ul1 first unsigned long parsed from string
142)  * @param[out] ul2 second unsigned long parsed from string
143)  * @throws std::exception in case of error
144)  */
145) void Config::str2ul2(std::string const &str,
146)                      unsigned long &ul1, unsigned long &ul2)
147) {
148)   std::vector<std::string> fields;
149)   split_chr(str, ',', fields);
150)   if (fields.size() != 2) {
151)     std::stringstream msg;
152)     msg << "expected two comma-separated unsigned integers, found \""
153)         << str << "\"";
154)     throw std::runtime_error(msg.str());
155)   }
156)   try {
157)     ul1 = str2ul(fields[0]);
158)     ul2 = str2ul(fields[1]);
159)   } catch (std::exception &ex) {
160)     std::stringstream msg;
161)     msg << "invalid unsigned integer pair \"" << str << "\": " << ex.what();
162)     throw std::runtime_error(msg.str());
163)   }
164) }
165) 
166) /**
167)  * @brief convert string to double (using the decimal dot for any locale)
168)  * @param[in] str string to convert
169)  * @return double parsed from string
170)  * @throws std::exception in case of error
171)  */
172) double Config::str2d(std::string const &str)
173) {
174)   char const *sz = str.c_str();
175) 
176)   // skip leading whitespace
177)   while (isspace(*sz)) {
178)     ++sz;
179)   }
180) 
181)   // start processing after leading whitespace
182)   char const *ptr = sz;
183) 
184)   // read optional sign
185)   double sign = 1.0;
186)   if (*ptr == '+') {
187)     sign = 1.0;
188)     ++ptr;
189)   } else if (*ptr == '-') {
190)     sign = -1.0;
191)     ++ptr;
192)   }
193) 
194)   // read digits before dot
195)   double value = 0.0;
196)   while (*ptr >= '0' && *ptr <= '9') {
197)     value = value * 10.0 + (double)(*ptr - '0');
198)     ++ptr;
199)   }
200) 
201)   // read dot and digits after it
202)   double weight = 0.1;
203)   if (*ptr == '.') {
204)     ++ptr;
205) 
206)     /* read digits after dot */
207)     while (*ptr >= '0' && *ptr <= '9') {
208)       value += weight * (double)(*ptr - '0');
209)       weight *= 0.1;
210)       ++ptr;
211)     }
212) 
213)   } // if (*ptr == '.')
214) 
215)   // merge sign into value
216)   value *= sign;
217) 
218)   // read exponent
219)   if (*ptr == 'E' || *ptr == 'e') {
220)     ++ptr;
221) 
222)     /* read optional sign */
223)     int exp_sign = 1;
224)     if (*ptr == '+') {
225)       exp_sign = 1;
226)       ++ptr;
227)     } else if (*ptr == '-') {
228)       exp_sign = -1;
229)       ++ptr;
230)     }
231) 
232)     /* read digits */
233)     int exp_value = 0;
234)     while (*ptr >= '0' && *ptr <= '9') {
235)       exp_value = exp_value * 10 + (int)(*ptr - '0');
236)       ++ptr;
237)     }
238) 
239)     /* merge exponent into value */
240)     value *= pow(10.0, exp_sign * exp_value);
241) 
242)   } // if (*nptr == 'E' || *nptr == 'e')
243) 
244)   // skip trailing whitespace
245)   while (isspace(*ptr)) {
246)     ++ptr;
247)   }
248) 
249)   // leftover characters -> error */
250)   if (ptr == sz || *ptr != 0) {
251)     std::stringstream msg;
252)     msg << "invalid floating point value \"" << str << "\"";
253)     throw std::runtime_error(msg.str());
254)   }
255) 
256)   // return value
257)   return value;
258) }
259) 
260) /**
261)  * @brief convert string to three doubles (decimal dot for any locale)
262)  * @param[in] str string containing three comma-separated doubles
263)  * @param[out] d1 first double parsed from string
264)  * @param[out] d2 second double parsed from string
265)  * @param[out] d3 third double parsed from string
266)  * @throws std::exception in case of error
267)  */
268) void Config::str2d3(std::string const &str,
269)                     double &d1, double &d2, double &d3)
270) {
271)   std::vector<std::string> fields;
272)   split_chr(str, ',', fields);
273)   if (fields.size() != 3) {
274)     std::stringstream msg;
275)     msg << "expected three comma-separated floating point values, found \""
276)         << str << "\"";
277)     throw std::runtime_error(msg.str());
278)   }
279)   try {
280)     d1 = str2d(fields[0]);
281)     d2 = str2d(fields[1]);
282)     d3 = str2d(fields[2]);
283)   } catch (std::exception &ex) {
284)     std::stringstream msg;
285)     msg << "invalid floating point triplet \"" << str << "\": " << ex.what();
286)     throw std::runtime_error(msg.str());
287)   }
288) }
289) 
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

290) /**
291)  * @brief convert string to IPv4/port address
292)  * @param[in] str string containing IPv4/port address
293)  * @throws std::exception in case of error
294)  */
295) void Config::str2addr(std::string const &str, struct sockaddr_in &addr)
296) {
297)   // split address into IPv4 and port
298)   std::vector<std::string> fields;
299)   split_chr(str, ':', fields);
300)   if (fields.size() != 2) {
301)     std::stringstream msg;
302)     msg << "expected \"<IPv4>:<port>\", found \"" << str << "\"";
303)     throw std::runtime_error(msg.str());
304)   }
305)   std::string &strIPv4 = fields[0], &strPort = fields[1];
306) 
307)   // parse IPv4 address
308)   if (! inet_aton(strIPv4.c_str(), &addr.sin_addr)) {
309)     std::stringstream msg;
310)     msg << "invalid IPv4 \"" << strIPv4 << "\"";
311)     throw std::runtime_error(msg.str());
312)   }
313) 
314)   // parse port
315)   unsigned long port;
316)   try {
317)     port = str2ul(strPort);
318)     if (port == 0 || port > 65535) {
319)       throw std::runtime_error("port number out of range");
320)     }
321)   } catch (std::exception &ex) {
322)     std::stringstream msg;
323)     msg << "invalid port number \"" << strPort << "\": " << ex.what();
324)     throw std::runtime_error(msg.str());
325)   }
326)   addr.sin_port = htons(port);
327) 
328)   // fin in remaining fields of address structure
329)   addr.sin_family = AF_INET;
330) }
331) 
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

332) /**
333)  * @brief read config file
334)  * @param[in] configFile name of config file
335)  * @throws std::exception in case of error
336)  */
337) void Config::readFile(std::string const &configFile)
338) {
339)   // open file
340)   std::ifstream cf(configFile.c_str(), std::ios::in);
341)   if (! cf.is_open()) {
342)     std::stringstream msg;
343)     msg << "cannot open config file \"" << configFile <<  "\" for reading";
344)     throw std::runtime_error(msg.str());
345)   }
346) 
347)   // read lines and process them
348)   std::string line;
349)   size_t no;
350)   for (no = 1; std::getline(cf, line); ++no) {
351)     // process line
352)     try {
353)       procLine(line);
354)     } catch (std::exception &ex) {
355)       std::stringstream msg;
356)       msg << "error in line " << no << " of config file \"" << configFile
357)           << "\": " << ex.what();
358)       throw std::runtime_error(msg.str());
359)     }
360)   }
361) 
362)   // close file
363)   cf.close();
Stefan Schuermans implement drawing pixels

Stefan Schuermans authored 7 years ago

364) 
365)   // update internal data
366)   update();
Stefan Schuermans begin of config file parsing

Stefan Schuermans authored 7 years ago

367) }
368) 
369) /**
370)  * @brief process line from config file
371)  * @param[in] line line to process
372)  * @throws std::exception in case of error
373)  */
374) void Config::procLine(std::string line)
375) {
376)   // remove comment ("# ...")
377)   size_t commentStart = line.find("#");
378)   if (commentStart != std::string::npos) {
379)     line.erase(commentStart);
380)   }
381) 
382)   trim(line);
383) 
384)   // ignore empty lines
385)   if (line.empty()) {
386)     return;
387)   }
388) 
389)   // split line at equal sign
390)   size_t equalSign = line.find("=");
391)   if (equalSign == std::string::npos) {
392)     std::stringstream msg;
393)     msg << "no equal sign found in \"" << line << "\"";
394)     throw std::runtime_error(msg.str());
395)   }
396)   std::string setting = line.substr(0, equalSign);
397)   std::string value = line.substr(equalSign + 1);
398)   trim(setting);
399)   trim(value);
400) 
401)   procSetting(setting, value);
402) }
403) 
404) /**
405)  * @brief process setting from config file
406)  * @param[in] setting name of the setting
407)  * @param[in] value value for setting
408)  * @throws std::exception in case of error
409)  */
410) void Config::procSetting(std::string const &setting, std::string const &value)
411) {
412)   std::vector<std::string> setFields, valFields;
413)   split(setting, setFields);
414)   split(value, valFields);
415) 
416)   // empty setting
417)   if (setFields.size() < 1) {
418)     throw std::runtime_error("empty setting name");
419)   }
420) 
421)   // distributor
422)   if (setFields[0] == "distributor") {
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

424)   }
425)   // distributor address
426)   else if (setFields[0] == "distributorAddr") {
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

428)   }
429)   // mapping
430)   else if (setFields[0] == "mapping") {
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

432)   }
433)   // output
434)   else if (setFields[0] == "output") {
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

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

Stefan Schuermans authored 7 years ago

436)   }
437)   // unknown setting
438)   else {
439)     std::stringstream msg;
440)     msg << "unknown setting \"" << setting << "\"";
441)     throw std::runtime_error(msg.str());
442)   }
443) }
444) 
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

445) /**
446)  * @brief process distributor line from config file
447)  * @param[in] setFields fields of the setting parts
448)  * @param[in] valFields fields of the value part
449)  * @throws std::exception in case of error
450)  */
451) void Config::proc_distributor(std::vector<std::string> const &setFields,
452)                               std::vector<std::string> const &valFields)
453) {
454)   // check number of setting fields
455)   if (setFields.size() != 2) {
456)     std::stringstream msg;
457)     msg << "invalid \"distributor\" setting with " << setFields.size()
458)         << " fields, expected \"distributor <distno>\"";
459)     throw std::runtime_error(msg.str());
460)   }
461) 
462)   // get and check distributor number
463)   unsigned long distno;
464)   try {
465)     distno = str2ul(setFields[1]);
466)   } catch (std::exception &ex) {
467)     std::stringstream msg;
468)     msg << "invalid distributor number \"" << setFields[1] << "\": "
469)         << ex.what();
470)     throw std::runtime_error(msg.str());
471)   }
472)   if (m_distriMap.find(distno) != m_distriMap.end()) {
473)     std::stringstream msg;
474)     msg << "duplicate \"distributor " << distno << "\" setting";
475)     throw std::runtime_error(msg.str());
476)   }
477) 
478)   // check number of value fields
479)   if (valFields.size() != 1) {
480)     std::stringstream msg;
481)     msg << "invalid value for \"distributor " << distno << "\": "
482)         << setFields.size() << " fields, expected \"<outputs>,<pixels>\"";
483)     throw std::runtime_error(msg.str());
484)   }
485) 
486)   // get and check outputs and pixels per output
487)   unsigned long outputs, pixels;
488)   try {
489)     str2ul2(valFields[0], outputs, pixels);
490)     if (outputs < 1) {
491)       std::stringstream msg;
492)       msg << "invalid number of outputs \"" << outputs << "\"";
493)       throw std::runtime_error(msg.str());
494)     }
495)     if (pixels < 1) {
496)       std::stringstream msg;
497)       msg << "invalid number of pixels per output \"" << pixels << "\"";
498)       throw std::runtime_error(msg.str());
499)     }
500)   } catch (std::exception &ex) {
501)     std::stringstream msg;
502)     msg << "invalid value for \"distributor " << distno << "\": "
503)         << ex.what();
504)     throw std::runtime_error(msg.str());
505)   }
506) 
507)   // create distributor
508)   m_distriMap[distno].init(distno, outputs, pixels);
509) }
510) 
511) /**
512)  * @brief process distributorAddr line from config file
513)  * @param[in] setFields fields of the setting parts
514)  * @param[in] valFields fields of the value part
515)  * @throws std::exception in case of error
516)  */
517) void Config::proc_distributorAddr(std::vector<std::string> const &setFields,
518)                                   std::vector<std::string> const &valFields)
519) {
520)   // check number of setting fields
521)   if (setFields.size() != 2) {
522)     std::stringstream msg;
523)     msg << "invalid \"distributorAddr\" setting with " << setFields.size()
524)         << " fields, expected \"distributorAddr <distno>\"";
525)     throw std::runtime_error(msg.str());
526)   }
527) 
528)   // get distributor
529)   Distri &distri = getDistri(setFields[1]);
530) 
531)   // check number of value fields
532)   if (valFields.size() != 1) {
533)     std::stringstream msg;
534)     msg << "invalid value for \"distributorAddr " << distri.getNo() << "\": "
535)         << setFields.size() << " fields, expected \"<IPv4>:<port>\"";
536)     throw std::runtime_error(msg.str());
537)   }
538) 
539)   // parse address
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

540)   struct sockaddr_in addr;
541)   try {
542)     str2addr(valFields[0], addr);
543)   } catch (std::exception &ex) {
544)     std::stringstream msg;
545)     msg << "invalid value for \"mdistributorAddr " << distri.getNo() << "\": "
546)         << ex.what();
547)     throw std::runtime_error(msg.str());
548)   }
549) 
550)   // set address
551)   distri.setAddr(addr);
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

552) }
553) 
554) /**
555)  * @brief process mapping line from config file
556)  * @param[in] setFields fields of the setting parts
557)  * @param[in] valFields fields of the value part
558)  * @throws std::exception in case of error
559)  */
560) void Config::proc_mapping(std::vector<std::string> const &setFields,
561)                           std::vector<std::string> const &valFields)
562) {
563)   // check number of setting fields
564)   if (setFields.size() != 3) {
565)     std::stringstream msg;
566)     msg << "invalid \"mapping\" setting with " << setFields.size()
567)         << " fields, expected \"mapping <distno> [red|green|blue]\"";
568)     throw std::runtime_error(msg.str());
569)   }
570) 
571)   // get distributor
572)   Distri &distri = getDistri(setFields[1]);
573) 
574)   // get channel
575)   std::string strColor = setFields[2];
576)   Mapping::Channel channel;
577)   if (strColor == "red" ) {
578)     channel = Mapping::Red;
579)   } else if (strColor == "green" ) {
580)     channel = Mapping::Green;
581)   } else if (strColor == "blue" ) {
582)     channel = Mapping::Blue;
583)   } else {
584)     std::stringstream msg;
585)     msg << "invalid \"mapping\" setting: unknown color \"" << strColor
586)         << "\" fields, expected \"red\", \"green\" or \"blue\"";
587)     throw std::runtime_error(msg.str());
588)   }
589) 
590)   // check number of value fields
591)   if (valFields.size() != 3) {
592)     std::stringstream msg;
593)     msg << "invalid value for \"mapping " << distri.getNo() << " "
594)         << strColor << "\": " << setFields.size()
595)         << " fields, expected \"<base> <factor> <gamma>\"";
596)     throw std::runtime_error(msg.str());
597)   }
598) 
599)   // parse value fields
600)   double base, factor, gamma;
601)   try {
602)     base = str2d(valFields[0]);
603)   } catch (std::exception &ex) {
604)     std::stringstream msg;
605)     msg << "invalid value for \"mapping " << distri.getNo() << " "
606)             << strColor << "\": invalid value \"" << valFields[0]
607)             << "\"for \"base\": " << ex.what();
608)     throw std::runtime_error(msg.str());
609)   }
610)   try {
611)     factor = str2d(valFields[1]);
612)   } catch (std::exception &ex) {
613)     std::stringstream msg;
614)     msg << "invalid value for \"mapping " << distri.getNo() << " "
615)             << strColor << "\": invalid value \"" << valFields[1]
616)             << "\"for \"factor\": " << ex.what();
617)     throw std::runtime_error(msg.str());
618)   }
619)   try {
620)     gamma = str2d(valFields[2]);
621)     if (gamma <= 0.0) {
622)       throw std::runtime_error("gamma value must be positive");
623)     }
624)   } catch (std::exception &ex) {
625)     std::stringstream msg;
626)     msg << "invalid value for \"mapping " << distri.getNo() << " "
627)             << strColor << "\": invalid value \"" << valFields[2]
628)             << "\"for \"base\": " << ex.what();
629)     throw std::runtime_error(msg.str());
630)   }
631) 
632)   // set mapping of distributor
633)   distri.setMapping(channel, Mapping(base, factor, gamma));
634) }
635) 
636) /**
637)  * @brief process output line from config file
638)  * @param[in] setFields fields of the setting parts
639)  * @param[in] valFields fields of the value part
640)  * @throws std::exception in case of error
641)  */
642) void Config::proc_output(std::vector<std::string> const &setFields,
643)                          std::vector<std::string> const &valFields)
644) {
645)   // check number of setting fields
646)   if (setFields.size() != 2) {
647)     std::stringstream msg;
648)     msg << "invalid \"output\" setting with " << setFields.size()
649)         << " fields, expected \"output <distno>,<outno>\"";
650)     throw std::runtime_error(msg.str());
651)   }
652) 
653)   // parse distributor and output numbers
654)   unsigned long distno, outno;
655)   try {
656)     str2ul2(setFields[1], distno, outno);
657)   } catch (std::exception &ex) {
658)     std::stringstream msg;
659)     msg << "invalid output specifier \"" << setFields[1]
660)         << "\": expected \"<distno>,<outno>\": " << ex.what();
661)     throw std::runtime_error(msg.str());
662)   }
663) 
664)   // get distributor
665)   Distri &distri = getDistri(distno);
666) 
667)   // check output number
668)   unsigned long outputs = distri.getOutputs();
669)   if (outno > outputs) {
670)     std::stringstream msg;
671)     msg << "invalid output number " << outno << " for distributor " << distno
672)         << ": only " << outputs << " outputs available";
673)     throw std::runtime_error(msg.str());
674)   }
675) 
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

676)   // add output to distributor
677)   try {
678)     distri.addOutput(outno);
679)   } catch (std::exception &ex) {
680)     std::stringstream msg;
681)     msg << "cannot add output " << outno << " to distributor " << distno
682)         << ": " << ex.what();
683)     throw std::runtime_error(msg.str());
684)   }
685) 
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

686)   // parse all pixels
687)   std::vector<std::string>::const_iterator pix;
688)   unsigned long p;
689)   for (pix = valFields.begin(), p = 0; pix != valFields.end(); ++pix, ++p) {
690)     // parse pixel description
691)     double x, y, r;
692)     try {
693)       str2d3(*pix, x, y, r);
694)     } catch (std::exception &ex) {
695)       std::stringstream msg;
696)       msg << "invalid pixel description \"" << *pix << "\" for pixel "
697)           << p << " at output " << outno << " of distributor " << distno
698)           << ": expected \"<x>,<y>,<r>\": " << ex.what();
699)       throw std::runtime_error(msg.str());
700)     }
701)     // add pixel
Stefan Schuermans complete implementation of...

Stefan Schuermans authored 7 years ago

702)     try {
703)       distri.addPixel(outno, Pixel(x, y, r));
704)     } catch (std::exception &ex) {
705)       std::stringstream msg;
706)       msg << "cannot add pixel \"" << *pix << "\" (pixel "
707)           << p << ") to output " << outno << " of distributor " << distno
708)           << ": " << ex.what();
709)       throw std::runtime_error(msg.str());
710)     }
Stefan Schuermans continue implementing confi...

Stefan Schuermans authored 7 years ago

711)   } // for pixel
712) }
713) 
714) /**
715)  * @brief get distributor
716)  * @param[in] strDistno distributor number as string
717)  * @return reference to distributor object in map
718)  * @throws std::exception in case of error
719)  */
720) Distri & Config::getDistri(std::string const &strDistno)
721) {
722)   unsigned long distno;
723)   try {
724)     distno = str2ul(strDistno);
725)   } catch (std::exception &ex) {
726)     std::stringstream msg;
727)     msg << "invalid distributor number \"" << strDistno << "\": "
728)         << ex.what();
729)     throw std::runtime_error(msg.str());
730)   }
731)   return getDistri(distno);
732) }
733) 
734) /**
735)  * @brief get distributor
736)  * @param[in] distno distributor number
737)  * @return reference to distributor object in map
738)  * @throws std::exception in case of error
739)  */
740) Distri & Config::getDistri(unsigned long distno)
741) {
742)   DistriMap::iterator distri = m_distriMap.find(distno);
743)   if (distri == m_distriMap.end()) {
744)     std::stringstream msg;
745)     msg << "no distributor with number \"" << distno << "\" found";
746)     throw std::runtime_error(msg.str());
747)   }
748)   return distri->second;
749) }
750)