Code

util/ucompose.hpp: catch exception thrown when user has an unsupported
[inkscape.git] / src / util / ucompose.hpp
1 /* Defines String::ucompose(fmt, arg...) for easy, i18n-friendly
2  * composition of strings with Gtkmm >= 1.3.* (see www.gtkmm.org).
3  * Uses Glib::ustring instead of std::string which doesn't work with
4  * Gtkmm due to character encoding troubles with stringstreams.
5  *
6  * Version 1.0.4.
7  *
8  * Copyright (c) 2002, 03, 04 Ole Laursen <olau@hardworking.dk>.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * as published by the Free Software Foundation; either version 2.1 of
13  * the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23  * USA.
24  */
26 //
27 // Basic usage is like
28 //
29 //   String::ucompose("This is a %1x%2 matrix.", rows, cols);
30 //
31 // See http://www.cs.aau.dk/~olau/compose/ or the included
32 // README.compose for more details.
33 //
35 #ifndef STRING_UCOMPOSE_HPP
36 #define STRING_UCOMPOSE_HPP
38 #include <glibmm/ustring.h>
39 #include <glibmm/convert.h>
41 #include <sstream>
42 #include <string>
43 #include <list>
44 #include <map>                  // for multimap
46 namespace UStringPrivate
47 {
48   // the actual composition class - using String::ucompose is cleaner, so we
49   // hide it here
50   class Composition
51   {
52   public:
53     // initialize and prepare format string on the form "text %1 text %2 etc."
54     explicit Composition(std::string fmt);
56     // supply an replacement argument starting from %1
57     template <typename T>
58     Composition &arg(const T &obj);
60     // compose and return string
61     Glib::ustring str() const;
63   private:
64   
65     //This is standard, not GCC-specific like wostringstream
66     std::basic_ostringstream<wchar_t> os;
67     
68     int arg_no;
70     // we store the output as a list - when the output string is requested, the
71     // list is concatenated to a string; this way we can keep iterators into
72     // the list instead of into a string where they're possibly invalidated
73     // when inserting a specification string
74     typedef std::list<std::string> output_list;
75     output_list output;
77     // the initial parse of the format string fills in the specification map
78     // with positions for each of the various %?s
79     typedef std::multimap<int, output_list::iterator> specification_map;
80     specification_map specs;
82     template <typename T>
83     std::string stringify(T obj);
84   };
86   // helper for converting spec string numbers
87   inline int char_to_int(char c)
88   {
89     switch (c) {
90     case '0': return 0;
91     case '1': return 1;
92     case '2': return 2;
93     case '3': return 3;
94     case '4': return 4;
95     case '5': return 5;
96     case '6': return 6;
97     case '7': return 7;
98     case '8': return 8;
99     case '9': return 9;
100     default: return -1000;
101     }
102   }
104   inline bool is_number(int n)
105   {
106     switch (n) {
107     case '0':
108     case '1':
109     case '2':
110     case '3':
111     case '4':
112     case '5':
113     case '6':
114     case '7':
115     case '8':
116     case '9':
117       return true;
118     
119     default:
120       return false;
121     }
122   }
124   template <typename T>
125   inline std::string Composition::stringify(T obj)
126   {
127     os << obj;
129     std::wstring str = os.str();
130     
131     return Glib::convert(std::string(reinterpret_cast<const char *>(str.data()),
132                                      str.size() * sizeof(wchar_t)),
133                          "UTF-8", "WCHAR_T");
134   }
136   // specialisations for the common string types
137   template <>
138   inline std::string
139   Composition::stringify<std::string>(std::string obj)
140   {
141     return obj;
142   }
143   
144   template <>
145   inline std::string
146   Composition::stringify<Glib::ustring>(Glib::ustring obj)
147   {
148     return obj;
149   }
150   
151   template <>
152   inline std::string
153   Composition::stringify<const char *>(const char *obj)
154   {
155     return obj;
156   }
157   
158   // implementation of class Composition
159   template <typename T>
160   inline Composition &Composition::arg(const T &obj)
161   {
162     Glib::ustring rep = stringify(obj);
163     
164     if (!rep.empty()) {         // manipulators don't produce output
165       for (specification_map::const_iterator i = specs.lower_bound(arg_no),
166              end = specs.upper_bound(arg_no); i != end; ++i) {
167         output_list::iterator pos = i->second;
168         ++pos;
169       
170         output.insert(pos, rep);
171       }
172     
173       os.str(std::wstring());
174       //os.clear();
175       ++arg_no;
176     }
177   
178     return *this;
179   }
181   inline Composition::Composition(std::string fmt)
182     : arg_no(1)
183   {
184 #if __GNUC__ >= 3
185     try {
186         os.imbue(std::locale("")); // use the user's locale for the stream
187     } 
188     catch (std::runtime_error& e) { // fallback to classic if it failed
189         os.imbue(std::locale::classic());
190     }
191 #endif
192     std::string::size_type b = 0, i = 0;
193   
194     // fill in output with the strings between the %1 %2 %3 etc. and
195     // fill in specs with the positions
196     while (i < fmt.length()) {
197       if (fmt[i] == '%' && i + 1 < fmt.length()) {
198         if (fmt[i + 1] == '%') { // catch %%
199           fmt.replace(i, 2, "%");
200           ++i;
201         }
202         else if (is_number(fmt[i + 1])) { // aha! a spec!
203           // save string
204           output.push_back(fmt.substr(b, i - b));
205         
206           int n = 1;            // number of digits
207           int spec_no = 0;
209           do {
210             spec_no += char_to_int(fmt[i + n]);
211             spec_no *= 10;
212             ++n;
213           } while (i + n < fmt.length() && is_number(fmt[i + n]));
215           spec_no /= 10;
216           output_list::iterator pos = output.end();
217           --pos;                // safe since we have just inserted a string
218         
219           specs.insert(specification_map::value_type(spec_no, pos));
220         
221           // jump over spec string
222           i += n;
223           b = i;
224         }
225         else
226           ++i;
227       }
228       else
229         ++i;
230     }
231   
232     if (i - b > 0)              // add the rest of the string
233       output.push_back(fmt.substr(b, i - b));
234   }
236   inline Glib::ustring Composition::str() const
237   {
238     // assemble string
239     std::string str;
240   
241     for (output_list::const_iterator i = output.begin(), end = output.end();
242          i != end; ++i)
243       str += *i;
244   
245     return str;
246   }
250 namespace String 
252   // a series of functions which accept a format string on the form "text %1
253   // more %2 less %3" and a number of templated parameters and spits out the
254   // composited string
255   template <typename T1>
256   inline Glib::ustring ucompose(const Glib::ustring &fmt, const T1 &o1)
257   {
258     UStringPrivate::Composition c(fmt);
259     c.arg(o1);
260     return c.str();
261   }
263   template <typename T1, typename T2>
264   inline Glib::ustring ucompose(const Glib::ustring &fmt,
265                                 const T1 &o1, const T2 &o2)
266   {
267     UStringPrivate::Composition c(fmt);
268     c.arg(o1).arg(o2);
269     return c.str();
270   }
272   template <typename T1, typename T2, typename T3>
273   inline Glib::ustring ucompose(const Glib::ustring &fmt,
274                                 const T1 &o1, const T2 &o2, const T3 &o3)
275   {
276     UStringPrivate::Composition c(fmt);
277     c.arg(o1).arg(o2).arg(o3);
278     return c.str();
279   }
281   template <typename T1, typename T2, typename T3, typename T4>
282   inline Glib::ustring ucompose(const Glib::ustring &fmt,
283                                 const T1 &o1, const T2 &o2, const T3 &o3,
284                                 const T4 &o4)
285   {
286     UStringPrivate::Composition c(fmt);
287     c.arg(o1).arg(o2).arg(o3).arg(o4);
288     return c.str();
289   }
291   template <typename T1, typename T2, typename T3, typename T4, typename T5>
292   inline Glib::ustring ucompose(const Glib::ustring &fmt,
293                                 const T1 &o1, const T2 &o2, const T3 &o3,
294                                 const T4 &o4, const T5 &o5)
295   {
296     UStringPrivate::Composition c(fmt);
297     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
298     return c.str();
299   }
301   template <typename T1, typename T2, typename T3, typename T4, typename T5,
302             typename T6>
303   inline Glib::ustring ucompose(const Glib::ustring &fmt,
304                                 const T1 &o1, const T2 &o2, const T3 &o3,
305                                 const T4 &o4, const T5 &o5, const T6 &o6)
306   {
307     UStringPrivate::Composition c(fmt);
308     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
309     return c.str();
310   }
312   template <typename T1, typename T2, typename T3, typename T4, typename T5,
313             typename T6, typename T7>
314   inline Glib::ustring ucompose(const Glib::ustring &fmt,
315                                 const T1 &o1, const T2 &o2, const T3 &o3,
316                                 const T4 &o4, const T5 &o5, const T6 &o6,
317                                 const T7 &o7)
318   {
319     UStringPrivate::Composition c(fmt);
320     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
321     return c.str();
322   }
324   template <typename T1, typename T2, typename T3, typename T4, typename T5,
325             typename T6, typename T7, typename T8>
326   inline Glib::ustring ucompose(const Glib::ustring &fmt,
327                                 const T1 &o1, const T2 &o2, const T3 &o3,
328                                 const T4 &o4, const T5 &o5, const T6 &o6,
329                                 const T7 &o7, const T8 &o8)
330   {
331     UStringPrivate::Composition c(fmt);
332     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
333     return c.str();
334   }
336   template <typename T1, typename T2, typename T3, typename T4, typename T5,
337             typename T6, typename T7, typename T8, typename T9>
338   inline Glib::ustring ucompose(const Glib::ustring &fmt,
339                                 const T1 &o1, const T2 &o2, const T3 &o3,
340                                 const T4 &o4, const T5 &o5, const T6 &o6,
341                                 const T7 &o7, const T8 &o8, const T9 &o9)
342   {
343     UStringPrivate::Composition c(fmt);
344     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
345     return c.str();
346   }
348   template <typename T1, typename T2, typename T3, typename T4, typename T5,
349             typename T6, typename T7, typename T8, typename T9, typename T10>
350   inline Glib::ustring ucompose(const Glib::ustring &fmt,
351                                 const T1 &o1, const T2 &o2, const T3 &o3,
352                                 const T4 &o4, const T5 &o5, const T6 &o6,
353                                 const T7 &o7, const T8 &o8, const T9 &o9,
354                                 const T10 &o10)
355   {
356     UStringPrivate::Composition c(fmt);
357     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
358       .arg(o10);
359     return c.str();
360   }
361   
362   template <typename T1, typename T2, typename T3, typename T4, typename T5,
363             typename T6, typename T7, typename T8, typename T9, typename T10,
364             typename T11>
365   inline Glib::ustring ucompose(const Glib::ustring &fmt,
366                                 const T1 &o1, const T2 &o2, const T3 &o3,
367                                 const T4 &o4, const T5 &o5, const T6 &o6,
368                                 const T7 &o7, const T8 &o8, const T9 &o9,
369                                 const T10 &o10, const T11 &o11)
370   {
371     UStringPrivate::Composition c(fmt);
372     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
373       .arg(o10).arg(o11);
374     return c.str();
375   }
377   template <typename T1, typename T2, typename T3, typename T4, typename T5,
378             typename T6, typename T7, typename T8, typename T9, typename T10,
379             typename T11, typename T12>
380   inline Glib::ustring ucompose(const Glib::ustring &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   {
386     UStringPrivate::Composition c(fmt);
387     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
388       .arg(o10).arg(o11).arg(o12);
389     return c.str();
390   }
392   template <typename T1, typename T2, typename T3, typename T4, typename T5,
393             typename T6, typename T7, typename T8, typename T9, typename T10,
394             typename T11, typename T12, typename T13>
395   inline Glib::ustring ucompose(const Glib::ustring &fmt,
396                                 const T1 &o1, const T2 &o2, const T3 &o3,
397                                 const T4 &o4, const T5 &o5, const T6 &o6,
398                                 const T7 &o7, const T8 &o8, const T9 &o9,
399                                 const T10 &o10, const T11 &o11, const T12 &o12,
400                                 const T13 &o13)
401   {
402     UStringPrivate::Composition c(fmt);
403     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
404       .arg(o10).arg(o11).arg(o12).arg(o13);
405     return c.str();
406   }
408   template <typename T1, typename T2, typename T3, typename T4, typename T5,
409             typename T6, typename T7, typename T8, typename T9, typename T10,
410             typename T11, typename T12, typename T13, typename T14>
411   inline Glib::ustring ucompose(const Glib::ustring &fmt,
412                                 const T1 &o1, const T2 &o2, const T3 &o3,
413                                 const T4 &o4, const T5 &o5, const T6 &o6,
414                                 const T7 &o7, const T8 &o8, const T9 &o9,
415                                 const T10 &o10, const T11 &o11, const T12 &o12,
416                                 const T13 &o13, const T14 &o14)
417   {
418     UStringPrivate::Composition c(fmt);
419     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
420       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
421     return c.str();
422   }
424   template <typename T1, typename T2, typename T3, typename T4, typename T5,
425             typename T6, typename T7, typename T8, typename T9, typename T10,
426             typename T11, typename T12, typename T13, typename T14,
427             typename T15>
428   inline Glib::ustring ucompose(const Glib::ustring &fmt,
429                                 const T1 &o1, const T2 &o2, const T3 &o3,
430                                 const T4 &o4, const T5 &o5, const T6 &o6,
431                                 const T7 &o7, const T8 &o8, const T9 &o9,
432                                 const T10 &o10, const T11 &o11, const T12 &o12,
433                                 const T13 &o13, const T14 &o14, const T15 &o15)
434   {
435     UStringPrivate::Composition c(fmt);
436     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
437       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
438     return c.str();
439   }
443 #endif // STRING_UCOMPOSE_HPP