Try to fix some warnings when libdcp include asdcplib.
[dcpomatic.git] / src / lib / compose.hpp
1 /* -*- c-basic-offset: 2 -*-
2  * Defines String::compose(fmt, arg...) for easy, i18n-friendly
3  * composition of strings.
4  *
5  * Version 1.0.
6  *
7  * Copyright (c) 2002 Ole Laursen <olau@hardworking.dk>.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22  * USA.
23  */
24
25 //
26 // Basic usage is like
27 //
28 //   std::cout << String::compose("This is a %1x%2 matrix.", rows, cols);
29 //
30 // See http://www.cs.aau.dk/~olau/compose/ or the included README.compose for
31 // more details.
32 //
33
34 #ifndef DCPOMATIC_STRING_COMPOSE_H
35 #define DCPOMATIC_STRING_COMPOSE_H
36
37 #include "warnings.h"
38 DCPOMATIC_DISABLE_WARNINGS
39 #include <dcp/locale_convert.h>
40 DCPOMATIC_ENABLE_WARNINGS
41 #include <boost/filesystem.hpp>
42 #include <string>
43 #include <list>
44 #include <map>
45 #include <inttypes.h>
46 #include <cstdio>
47
48 namespace StringPrivate
49 {
50   // the actual composition class - using string::compose is cleaner, so we
51   // hide it here
52   class Composition
53   {
54   public:
55     // initialize and prepare format string on the form "text %1 text %2 etc."
56     explicit Composition(std::string fmt);
57
58     // supply an replacement argument starting from %1
59     template <typename T>
60     Composition &arg(const T &obj);
61
62     // compose and return string
63     std::string str() const;
64
65   private:
66     std::string os;
67     int arg_no;
68
69     // we store the output as a list - when the output string is requested, the
70     // list is concatenated to a string; this way we can keep iterators into
71     // the list instead of into a string where they're possibly invalidated on
72     // inserting a specification string
73     typedef std::list<std::string> output_list;
74     output_list output;
75
76     // the initial parse of the format string fills in the specification map
77     // with positions for each of the various %?s
78     typedef std::multimap<int, output_list::iterator> specification_map;
79     specification_map specs;
80   };
81
82   // helper for converting spec string numbers
83   inline int char_to_int(char c)
84   {
85     switch (c) {
86     case '0': return 0;
87     case '1': return 1;
88     case '2': return 2;
89     case '3': return 3;
90     case '4': return 4;
91     case '5': return 5;
92     case '6': return 6;
93     case '7': return 7;
94     case '8': return 8;
95     case '9': return 9;
96     default: return -1000;
97     }
98   }
99
100   inline bool is_number(int n)
101   {
102     switch (n) {
103     case '0':
104     case '1':
105     case '2':
106     case '3':
107     case '4':
108     case '5':
109     case '6':
110     case '7':
111     case '8':
112     case '9':
113       return true;
114
115     default:
116       return false;
117     }
118   }
119
120   // implementation of class Composition
121   template <typename T>
122   inline Composition &Composition::arg(const T &obj)
123   {
124     os += dcp::locale_convert<std::string>(obj);
125
126     if (!os.empty()) {          // manipulators don't produce output
127       for (specification_map::const_iterator i = specs.lower_bound(arg_no), end = specs.upper_bound(arg_no); i != end; ++i) {
128         output_list::iterator pos = i->second;
129         ++pos;
130
131         output.insert(pos, os);
132       }
133
134       os = "";
135       ++arg_no;
136     }
137
138     return *this;
139   }
140
141   inline Composition::Composition(std::string fmt)
142     : arg_no(1)
143   {
144     std::string::size_type b = 0, i = 0;
145
146     // fill in output with the strings between the %1 %2 %3 etc. and
147     // fill in specs with the positions
148     while (i < fmt.length()) {
149       if (fmt[i] == '%' && i + 1 < fmt.length()) {
150         if (fmt[i + 1] == '%') {        // catch %%
151           fmt.replace(i, 2, "%");
152           ++i;
153         }
154         else if (is_number(fmt[i + 1])) { // aha! a spec!
155           // save string
156           output.push_back(fmt.substr(b, i - b));
157
158           int n = 1;            // number of digits
159           int spec_no = 0;
160
161           do {
162             spec_no += char_to_int(fmt[i + n]);
163             spec_no *= 10;
164             ++n;
165           } while (i + n < fmt.length() && is_number(fmt[i + n]));
166
167           spec_no /= 10;
168           output_list::iterator pos = output.end();
169           --pos;                // safe since we have just inserted a string>
170
171           specs.insert(specification_map::value_type(spec_no, pos));
172
173           // jump over spec string
174           i += n;
175           b = i;
176         }
177         else
178           ++i;
179       }
180       else
181         ++i;
182     }
183
184     if (i - b > 0)              // add the rest of the string
185       output.push_back(fmt.substr(b, i - b));
186   }
187
188   inline std::string Composition::str() const
189   {
190     // assemble string
191     std::string str;
192
193     for (output_list::const_iterator i = output.begin(), end = output.end();
194          i != end; ++i)
195       str += *i;
196
197     return str;
198   }
199 }
200
201 // now for the real thing(s)
202 namespace String
203 {
204   // a series of functions which accept a format string on the form "text %1
205   // more %2 less %3" and a number of templated parameters and spits out the
206   // composited string
207   template <typename T1>
208   inline std::string compose(const std::string &fmt, const T1 &o1)
209   {
210     StringPrivate::Composition c(fmt);
211     c.arg(o1);
212     return c.str();
213   }
214
215   template <typename T1, typename T2>
216   inline std::string compose(const std::string &fmt,
217                              const T1 &o1, const T2 &o2)
218   {
219     StringPrivate::Composition c(fmt);
220     c.arg(o1).arg(o2);
221     return c.str();
222   }
223
224   template <typename T1, typename T2, typename T3>
225   inline std::string compose(const std::string &fmt,
226                              const T1 &o1, const T2 &o2, const T3 &o3)
227   {
228     StringPrivate::Composition c(fmt);
229     c.arg(o1).arg(o2).arg(o3);
230     return c.str();
231   }
232
233   template <typename T1, typename T2, typename T3, typename T4>
234   inline std::string compose(const std::string &fmt,
235                              const T1 &o1, const T2 &o2, const T3 &o3,
236                              const T4 &o4)
237   {
238     StringPrivate::Composition c(fmt);
239     c.arg(o1).arg(o2).arg(o3).arg(o4);
240     return c.str();
241   }
242
243   template <typename T1, typename T2, typename T3, typename T4, typename T5>
244   inline std::string compose(const std::string &fmt,
245                              const T1 &o1, const T2 &o2, const T3 &o3,
246                              const T4 &o4, const T5 &o5)
247   {
248     StringPrivate::Composition c(fmt);
249     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
250     return c.str();
251   }
252
253   template <typename T1, typename T2, typename T3, typename T4, typename T5,
254             typename T6>
255   inline std::string compose(const std::string &fmt,
256                              const T1 &o1, const T2 &o2, const T3 &o3,
257                              const T4 &o4, const T5 &o5, const T6 &o6)
258   {
259     StringPrivate::Composition c(fmt);
260     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
261     return c.str();
262   }
263
264   template <typename T1, typename T2, typename T3, typename T4, typename T5,
265             typename T6, typename T7>
266   inline std::string compose(const std::string &fmt,
267                              const T1 &o1, const T2 &o2, const T3 &o3,
268                              const T4 &o4, const T5 &o5, const T6 &o6,
269                              const T7 &o7)
270   {
271     StringPrivate::Composition c(fmt);
272     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
273     return c.str();
274   }
275
276   template <typename T1, typename T2, typename T3, typename T4, typename T5,
277             typename T6, typename T7, typename T8>
278   inline std::string compose(const std::string &fmt,
279                              const T1 &o1, const T2 &o2, const T3 &o3,
280                              const T4 &o4, const T5 &o5, const T6 &o6,
281                              const T7 &o7, const T8 &o8)
282   {
283     StringPrivate::Composition c(fmt);
284     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
285     return c.str();
286   }
287
288   template <typename T1, typename T2, typename T3, typename T4, typename T5,
289             typename T6, typename T7, typename T8, typename T9>
290   inline std::string compose(const std::string &fmt,
291                              const T1 &o1, const T2 &o2, const T3 &o3,
292                              const T4 &o4, const T5 &o5, const T6 &o6,
293                              const T7 &o7, const T8 &o8, const T9 &o9)
294   {
295     StringPrivate::Composition c(fmt);
296     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
297     return c.str();
298   }
299
300   template <typename T1, typename T2, typename T3, typename T4, typename T5,
301             typename T6, typename T7, typename T8, typename T9, typename T10>
302   inline std::string compose(const std::string &fmt,
303                              const T1 &o1, const T2 &o2, const T3 &o3,
304                              const T4 &o4, const T5 &o5, const T6 &o6,
305                              const T7 &o7, const T8 &o8, const T9 &o9,
306                              const T10 &o10)
307   {
308     StringPrivate::Composition c(fmt);
309     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
310       .arg(o10);
311     return c.str();
312   }
313
314   template <typename T1, typename T2, typename T3, typename T4, typename T5,
315             typename T6, typename T7, typename T8, typename T9, typename T10,
316             typename T11>
317   inline std::string compose(const std::string &fmt,
318                              const T1 &o1, const T2 &o2, const T3 &o3,
319                              const T4 &o4, const T5 &o5, const T6 &o6,
320                              const T7 &o7, const T8 &o8, const T9 &o9,
321                              const T10 &o10, const T11 &o11)
322   {
323     StringPrivate::Composition c(fmt);
324     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
325       .arg(o10).arg(o11);
326     return c.str();
327   }
328
329   template <typename T1, typename T2, typename T3, typename T4, typename T5,
330             typename T6, typename T7, typename T8, typename T9, typename T10,
331             typename T11, typename T12>
332   inline std::string compose(const std::string &fmt,
333                              const T1 &o1, const T2 &o2, const T3 &o3,
334                              const T4 &o4, const T5 &o5, const T6 &o6,
335                              const T7 &o7, const T8 &o8, const T9 &o9,
336                              const T10 &o10, const T11 &o11, const T12 &o12)
337   {
338     StringPrivate::Composition c(fmt);
339     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
340       .arg(o10).arg(o11).arg(o12);
341     return c.str();
342   }
343
344   template <typename T1, typename T2, typename T3, typename T4, typename T5,
345             typename T6, typename T7, typename T8, typename T9, typename T10,
346             typename T11, typename T12, typename T13>
347   inline std::string compose(const std::string &fmt,
348                              const T1 &o1, const T2 &o2, const T3 &o3,
349                              const T4 &o4, const T5 &o5, const T6 &o6,
350                              const T7 &o7, const T8 &o8, const T9 &o9,
351                              const T10 &o10, const T11 &o11, const T12 &o12,
352                              const T13 &o13)
353   {
354     StringPrivate::Composition c(fmt);
355     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
356       .arg(o10).arg(o11).arg(o12).arg(o13);
357     return c.str();
358   }
359
360   template <typename T1, typename T2, typename T3, typename T4, typename T5,
361             typename T6, typename T7, typename T8, typename T9, typename T10,
362             typename T11, typename T12, typename T13, typename T14>
363   inline std::string compose(const std::string &fmt,
364                              const T1 &o1, const T2 &o2, const T3 &o3,
365                              const T4 &o4, const T5 &o5, const T6 &o6,
366                              const T7 &o7, const T8 &o8, const T9 &o9,
367                              const T10 &o10, const T11 &o11, const T12 &o12,
368                              const T13 &o13, const T14 &o14)
369   {
370     StringPrivate::Composition c(fmt);
371     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
372       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
373     return c.str();
374   }
375
376   template <typename T1, typename T2, typename T3, typename T4, typename T5,
377             typename T6, typename T7, typename T8, typename T9, typename T10,
378             typename T11, typename T12, typename T13, typename T14,
379             typename T15>
380   inline std::string compose(const std::string &fmt,
381                              const T1 &o1, const T2 &o2, const T3 &o3,
382                              const T4 &o4, const T5 &o5, const T6 &o6,
383                              const T7 &o7, const T8 &o8, const T9 &o9,
384                              const T10 &o10, const T11 &o11, const T12 &o12,
385                              const T13 &o13, const T14 &o14, const T15 &o15)
386   {
387     StringPrivate::Composition c(fmt);
388     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
389       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
390     return c.str();
391   }
392 }
393
394
395 #endif // STRING_COMPOSE_H