complete implementation of config file parsing
Stefan Schuermans

Stefan Schuermans commited on 2017-06-10 21:21:50
Showing 6 changed files, with 270 additions and 15 deletions.

... ...
@@ -18,19 +18,23 @@
18 18
  */
19 19
 
20 20
 #include <algorithm>
21
+#include <arpa/inet.h>
21 22
 #include <cctype>
22 23
 #include <cmath>
23 24
 #include <cstdlib>
24 25
 #include <functional>
25 26
 #include <fstream>
26 27
 #include <map>
28
+#include <netinet/in.h>
27 29
 #include <stdexcept>
28 30
 #include <sstream>
29 31
 #include <string>
32
+#include <sys/socket.h>
30 33
 
31 34
 #include "config.h"
32 35
 #include "distri.h"
33 36
 #include "mapping.h"
37
+#include "pixel.h"
34 38
 
35 39
 /**
36 40
  * @brief constructor
... ...
@@ -265,6 +269,48 @@ void Config::str2d3(std::string const &str,
265 269
   }
266 270
 }
267 271
 
272
+/**
273
+ * @brief convert string to IPv4/port address
274
+ * @param[in] str string containing IPv4/port address
275
+ * @throws std::exception in case of error
276
+ */
277
+void Config::str2addr(std::string const &str, struct sockaddr_in &addr)
278
+{
279
+  // split address into IPv4 and port
280
+  std::vector<std::string> fields;
281
+  split_chr(str, ':', fields);
282
+  if (fields.size() != 2) {
283
+    std::stringstream msg;
284
+    msg << "expected \"<IPv4>:<port>\", found \"" << str << "\"";
285
+    throw std::runtime_error(msg.str());
286
+  }
287
+  std::string &strIPv4 = fields[0], &strPort = fields[1];
288
+
289
+  // parse IPv4 address
290
+  if (! inet_aton(strIPv4.c_str(), &addr.sin_addr)) {
291
+    std::stringstream msg;
292
+    msg << "invalid IPv4 \"" << strIPv4 << "\"";
293
+    throw std::runtime_error(msg.str());
294
+  }
295
+
296
+  // parse port
297
+  unsigned long port;
298
+  try {
299
+    port = str2ul(strPort);
300
+    if (port == 0 || port > 65535) {
301
+      throw std::runtime_error("port number out of range");
302
+    }
303
+  } catch (std::exception &ex) {
304
+    std::stringstream msg;
305
+    msg << "invalid port number \"" << strPort << "\": " << ex.what();
306
+    throw std::runtime_error(msg.str());
307
+  }
308
+  addr.sin_port = htons(port);
309
+
310
+  // fin in remaining fields of address structure
311
+  addr.sin_family = AF_INET;
312
+}
313
+
268 314
 /**
269 315
  * @brief read config file
270 316
  * @param[in] configFile name of config file
... ...
@@ -470,7 +516,18 @@ void Config::proc_distributorAddr(std::vector<std::string> const &setFields,
470 516
   }
471 517
 
472 518
   // parse address
473
-  // TODO
519
+  struct sockaddr_in addr;
520
+  try {
521
+    str2addr(valFields[0], addr);
522
+  } catch (std::exception &ex) {
523
+    std::stringstream msg;
524
+    msg << "invalid value for \"mdistributorAddr " << distri.getNo() << "\": "
525
+        << ex.what();
526
+    throw std::runtime_error(msg.str());
527
+  }
528
+
529
+  // set address
530
+  distri.setAddr(addr);
474 531
 }
475 532
 
476 533
 /**
... ...
@@ -595,19 +652,20 @@ void Config::proc_output(std::vector<std::string> const &setFields,
595 652
     throw std::runtime_error(msg.str());
596 653
   }
597 654
 
655
+  // add output to distributor
656
+  try {
657
+    distri.addOutput(outno);
658
+  } catch (std::exception &ex) {
659
+    std::stringstream msg;
660
+    msg << "cannot add output " << outno << " to distributor " << distno
661
+        << ": " << ex.what();
662
+    throw std::runtime_error(msg.str());
663
+  }
664
+
598 665
   // parse all pixels
599
-  unsigned long pixels = distri.getPixels();
600 666
   std::vector<std::string>::const_iterator pix;
601 667
   unsigned long p;
602 668
   for (pix = valFields.begin(), p = 0; pix != valFields.end(); ++pix, ++p) {
603
-    // check maximum number of pixels
604
-    if (p >= pixels) {
605
-      std::stringstream msg;
606
-      msg << "too many pixels (" << (p + 1) << ")"
607
-          << p << " for output " << outno << " of distributor " << distno
608
-          << ": only " << pixels << " pixels supported";
609
-      throw std::runtime_error(msg.str());
610
-    }
611 669
     // parse pixel description
612 670
     double x, y, r;
613 671
     try {
... ...
@@ -620,10 +678,15 @@ void Config::proc_output(std::vector<std::string> const &setFields,
620 678
       throw std::runtime_error(msg.str());
621 679
     }
622 680
     // add pixel
623
-    // TODO
624
-    (void)x;
625
-    (void)y;
626
-    (void)r;
681
+    try {
682
+      distri.addPixel(outno, Pixel(x, y, r));
683
+    } catch (std::exception &ex) {
684
+      std::stringstream msg;
685
+      msg << "cannot add pixel \"" << *pix << "\" (pixel "
686
+          << p << ") to output " << outno << " of distributor " << distno
687
+          << ": " << ex.what();
688
+      throw std::runtime_error(msg.str());
689
+    }
627 690
   } // for pixel
628 691
 }
629 692
 
... ...
@@ -20,6 +20,7 @@
20 20
 #ifndef CONFIG_H
21 21
 #define CONFIG_H
22 22
 
23
+#include <arpa/inet.h>
23 24
 #include <map>
24 25
 #include <string>
25 26
 #include <vector>
... ...
@@ -100,6 +101,13 @@ protected:
100 101
   static void str2d3(std::string const &str,
101 102
                      double &d1, double &d2, double &d3);
102 103
 
104
+  /**
105
+   * @brief convert string to IPv4/port address
106
+   * @param[in] str string containing IPv4/port address
107
+   * @throws std::exception in case of error
108
+   */
109
+  static void str2addr(std::string const &str, struct sockaddr_in &addr);
110
+
103 111
   /**
104 112
    * @brief read config file
105 113
    * @param[in] configFile name of config file
... ...
@@ -17,16 +17,23 @@
17 17
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
+#include <arpa/inet.h>
21
+#include <map>
20 22
 #include <sstream>
21 23
 #include <stdexcept>
24
+#include <vector>
22 25
 
23 26
 #include "distri.h"
27
+#include "mapping.h"
28
+#include "pixel.h"
24 29
 
25 30
 /// constructor
26 31
 Distri::Distri():
27 32
   m_distno(0),
28 33
   m_outputs(0),
29
-  m_pixels(0)
34
+  m_pixels(0),
35
+  m_mappings(),
36
+  m_outputMap()
30 37
 {
31 38
 }
32 39
 
... ...
@@ -44,6 +51,15 @@ void Distri::init(unsigned long distno, unsigned long outputs,
44 51
   m_pixels = pixels;
45 52
 }
46 53
 
54
+/**
55
+ * @brief set network address
56
+ * @param[in] addr IPv4/port network address (UDP)
57
+ */
58
+void Distri::setAddr(struct sockaddr_in const &addr)
59
+{
60
+  m_addr = addr;
61
+}
62
+
47 63
 /**
48 64
  * @brief get mapping
49 65
  * @param[in] chan color channel
... ...
@@ -76,3 +92,52 @@ void Distri::setMapping(Mapping::Channel chan, Mapping const &mapping)
76 92
   m_mappings[chan] = mapping;
77 93
 }
78 94
 
95
+/**
96
+ * @brief add output to distributor
97
+ * @param[in] outno number of output
98
+ * @throws std::exception in case of error
99
+ */
100
+void Distri::addOutput(unsigned long outno)
101
+{
102
+  if (outno >= m_outputs) {
103
+    std::stringstream msg;
104
+    msg << "invalid output number " << outno << ": only " << m_outputs
105
+        << " outputs supported";
106
+    throw std::runtime_error(msg.str());
107
+  }
108
+
109
+  if (m_outputMap.find(outno) != m_outputMap.end()) {
110
+    std::stringstream msg;
111
+    msg << "output " << outno << " already exists";
112
+    throw std::runtime_error(msg.str());
113
+  }
114
+
115
+  m_outputMap[outno];
116
+}
117
+
118
+/**
119
+ * @brief add pixel to output of distributor
120
+ * @param[in] outno number of output
121
+ * @param[in] pixel pixel object to add
122
+ * @throws std::exception in case of error
123
+ */
124
+void Distri::addPixel(unsigned long outno, Pixel const &pixel)
125
+{
126
+  if (m_outputMap.find(outno) == m_outputMap.end()) {
127
+    std::stringstream msg;
128
+    msg << "output " << outno << " does not exist";
129
+    throw std::runtime_error(msg.str());
130
+  }
131
+
132
+  Output &output = m_outputMap[outno];
133
+
134
+  if (output.m_pixels.size() >= m_pixels) {
135
+    std::stringstream msg;
136
+    msg << "cannot add pixel to output " << outno << ": already " << m_pixels
137
+        << " pixels at this output (this is the maximum)";
138
+    throw std::runtime_error(msg.str());
139
+  }
140
+
141
+  output.m_pixels.push_back(pixel);
142
+}
143
+
... ...
@@ -20,7 +20,12 @@
20 20
 #ifndef DISTRI_H
21 21
 #define DISTRI_H
22 22
 
23
+#include <arpa/inet.h>
24
+#include <map>
25
+#include <vector>
26
+
23 27
 #include "mapping.h"
28
+#include "pixel.h"
24 29
 
25 30
 /// distributor
26 31
 class Distri
... ...
@@ -46,6 +51,12 @@ public:
46 51
   /// get number of pixels at each output
47 52
   unsigned long getPixels() const { return m_pixels; }
48 53
 
54
+  /**
55
+   * @brief set network address
56
+   * @param[in] addr IPv4/port network address (UDP)
57
+   */
58
+  void setAddr(struct sockaddr_in const &addr);
59
+
49 60
   /**
50 61
    * @brief get mapping
51 62
    * @param[in] chan color channel
... ...
@@ -62,6 +73,30 @@ public:
62 73
    */
63 74
   void setMapping(Mapping::Channel chan, Mapping const &mapping);
64 75
 
76
+  /**
77
+   * @brief add output to distributor
78
+   * @param[in] outno number of output
79
+   * @throws std::exception in case of error
80
+   */
81
+  void addOutput(unsigned long outno);
82
+
83
+  /**
84
+   * @brief add pixel to output of distributor
85
+   * @param[in] outno number of output
86
+   * @param[in] pixel pixel object to add
87
+   * @throws std::exception in case of error
88
+   */
89
+  void addPixel(unsigned long outno, Pixel const &pixel);
90
+
91
+protected:
92
+  /// output data
93
+  struct Output {
94
+    std::vector<Pixel> m_pixels; ///< pixels at this output
95
+  };
96
+
97
+  /// map out outputs: output number -> output data
98
+  typedef std::map<unsigned long, Output> OutputMap;
99
+
65 100
 protected:
66 101
   /// distributor number
67 102
   unsigned long m_distno;
... ...
@@ -69,8 +104,12 @@ protected:
69 104
   unsigned long m_outputs;
70 105
   /// number of pixels per output
71 106
   unsigned long m_pixels;
107
+  /// network address
108
+  struct sockaddr_in m_addr;
72 109
   /// mappings of color channels
73 110
   Mapping m_mappings[Mapping::ChannelCount];
111
+  /// outputs
112
+  OutputMap m_outputMap;
74 113
 };
75 114
 
76 115
 #endif // #ifndef DISTRI_H
... ...
@@ -0,0 +1,37 @@
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 "pixel.h"
21
+
22
+/// default constructor
23
+Pixel::Pixel():
24
+  m_x(0.5),
25
+  m_y(0.5),
26
+  m_r(0.0)
27
+{
28
+}
29
+
30
+/// constructor based on coordinates and radius
31
+Pixel::Pixel(double x, double y, double r):
32
+  m_x(x),
33
+  m_y(y),
34
+  m_r(r)
35
+{
36
+}
37
+
... ...
@@ -0,0 +1,43 @@
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
+#ifndef PIXEL_H
21
+#define PIXEL_H
22
+
23
+/// a simulated pixel
24
+class Pixel
25
+{
26
+public:
27
+  /// default constructor
28
+  Pixel();
29
+
30
+  /// constructor based on coordinates and radius
31
+  Pixel(double x, double y, double r);
32
+
33
+protected:
34
+   /// parameters of pixel
35
+   //@{
36
+   double m_x; ///< x coordinate
37
+   double m_y; ///< y coordinate
38
+   double m_r; ///< radius
39
+   //@}
40
+};
41
+
42
+#endif // #ifndef PIXEL_H
43
+
0 44