Code

Merge from trunk.
[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 <stdexcept>
42 #include <sstream>
43 #include <string>
44 #include <list>
45 #include <map>                  // for multimap
47 namespace UStringPrivate
48 {
49   // the actual composition class - using String::ucompose is cleaner, so we
50   // hide it here
51   class Composition
52   {
53   public:
54     // initialize and prepare format string on the form "text %1 text %2 etc."
55     explicit Composition(std::string fmt);
57     // supply an replacement argument starting from %1
58     template <typename T>
59     Composition &arg(const T &obj);
61     // compose and return string
62     Glib::ustring str() const;
64   private:
65   
66     //This is standard, not GCC-specific like wostringstream
67     std::basic_ostringstream<wchar_t> os;
68     
69     int arg_no;
71     // we store the output as a list - when the output string is requested, the
72     // list is concatenated to a string; this way we can keep iterators into
73     // the list instead of into a string where they're possibly invalidated
74     // when inserting a specification string
75     typedef std::list<std::string> output_list;
76     output_list output;
78     // the initial parse of the format string fills in the specification map
79     // with positions for each of the various %?s
80     typedef std::multimap<int, output_list::iterator> specification_map;
81     specification_map specs;
83     template <typename T>
84     std::string stringify(T obj);
85   };
87   // helper for converting spec string numbers
88   inline int char_to_int(char c)
89   {
90     switch (c) {
91     case '0': return 0;
92     case '1': return 1;
93     case '2': return 2;
94     case '3': return 3;
95     case '4': return 4;
96     case '5': return 5;
97     case '6': return 6;
98     case '7': return 7;
99     case '8': return 8;
100     case '9': return 9;
101     default: return -1000;
102     }
103   }
105   inline bool is_number(int n)
106   {
107     switch (n) {
108     case '0':
109     case '1':
110     case '2':
111     case '3':
112     case '4':
113     case '5':
114     case '6':
115     case '7':
116     case '8':
117     case '9':
118       return true;
119     
120     default:
121       return false;
122     }
123   }
125   template <typename T>
126   inline std::string Composition::stringify(T obj)
127   {
128     os << obj;
130     std::wstring str = os.str();
131     
132     return Glib::convert(std::string(reinterpret_cast<const char *>(str.data()),
133                                      str.size() * sizeof(wchar_t)),
134                          "UTF-8", "WCHAR_T");
135   }
137   // specialisations for the common string types
138   template <>
139   inline std::string
140   Composition::stringify<std::string>(std::string obj)
141   {
142     return obj;
143   }
144   
145   template <>
146   inline std::string
147   Composition::stringify<Glib::ustring>(Glib::ustring obj)
148   {
149     return obj;
150   }
151   
152   template <>
153   inline std::string
154   Composition::stringify<const char *>(const char *obj)
155   {
156     return obj;
157   }
158   
159   // implementation of class Composition
160   template <typename T>
161   inline Composition &Composition::arg(const T &obj)
162   {
163     Glib::ustring rep = stringify(obj);
164     
165     if (!rep.empty()) {         // manipulators don't produce output
166       for (specification_map::const_iterator i = specs.lower_bound(arg_no),
167              end = specs.upper_bound(arg_no); i != end; ++i) {
168         output_list::iterator pos = i->second;
169         ++pos;
170       
171         output.insert(pos, rep);
172       }
173     
174       os.str(std::wstring());
175       //os.clear();
176       ++arg_no;
177     }
178   
179     return *this;
180   }
182   inline Composition::Composition(std::string fmt)
183     : arg_no(1)
184   {
185 #if __GNUC__ >= 3
186     try {
187         os.imbue(std::locale("")); // use the user's locale for the stream
188     } 
189     catch (std::runtime_error& e) { // fallback to classic if it failed
190         os.imbue(std::locale::classic());
191     }
192 #endif
193     std::string::size_type b = 0, i = 0;
194   
195     // fill in output with the strings between the %1 %2 %3 etc. and
196     // fill in specs with the positions
197     while (i < fmt.length()) {
198       if (fmt[i] == '%' && i + 1 < fmt.length()) {
199         if (fmt[i + 1] == '%') { // catch %%
200           fmt.replace(i, 2, "%");
201           ++i;
202         }
203         else if (is_number(fmt[i + 1])) { // aha! a spec!
204           // save string
205           output.push_back(fmt.substr(b, i - b));
206         
207           int n = 1;            // number of digits
208           int spec_no = 0;
210           do {
211             spec_no += char_to_int(fmt[i + n]);
212             spec_no *= 10;
213             ++n;
214           } while (i + n < fmt.length() && is_number(fmt[i + n]));
216           spec_no /= 10;
217           output_list::iterator pos = output.end();
218           --pos;                // safe since we have just inserted a string
219         
220           specs.insert(specification_map::value_type(spec_no, pos));
221         
222           // jump over spec string
223           i += n;
224           b = i;
225         }
226         else
227           ++i;
228       }
229       else
230         ++i;
231     }
232   
233     if (i - b > 0)              // add the rest of the string
234       output.push_back(fmt.substr(b, i - b));
235   }
237   inline Glib::ustring Composition::str() const
238   {
239     // assemble string
240     std::string str;
241   
242     for (output_list::const_iterator i = output.begin(), end = output.end();
243          i != end; ++i)
244       str += *i;
245   
246     return str;
247   }
251 namespace String 
253   // a series of functions which accept a format string on the form "text %1
254   // more %2 less %3" and a number of templated parameters and spits out the
255   // composited string
256   template <typename T1>
257   inline Glib::ustring ucompose(const Glib::ustring &fmt, const T1 &o1)
258   {
259     UStringPrivate::Composition c(fmt);
260     c.arg(o1);
261     return c.str();
262   }
264   template <typename T1, typename T2>
265   inline Glib::ustring ucompose(const Glib::ustring &fmt,
266                                 const T1 &o1, const T2 &o2)
267   {
268     UStringPrivate::Composition c(fmt);
269     c.arg(o1).arg(o2);
270     return c.str();
271   }
273   template <typename T1, typename T2, typename T3>
274   inline Glib::ustring ucompose(const Glib::ustring &fmt,
275                                 const T1 &o1, const T2 &o2, const T3 &o3)
276   {
277     UStringPrivate::Composition c(fmt);
278     c.arg(o1).arg(o2).arg(o3);
279     return c.str();
280   }
282   template <typename T1, typename T2, typename T3, typename T4>
283   inline Glib::ustring ucompose(const Glib::ustring &fmt,
284                                 const T1 &o1, const T2 &o2, const T3 &o3,
285                                 const T4 &o4)
286   {
287     UStringPrivate::Composition c(fmt);
288     c.arg(o1).arg(o2).arg(o3).arg(o4);
289     return c.str();
290   }
292   template <typename T1, typename T2, typename T3, typename T4, typename T5>
293   inline Glib::ustring ucompose(const Glib::ustring &fmt,
294                                 const T1 &o1, const T2 &o2, const T3 &o3,
295                                 const T4 &o4, const T5 &o5)
296   {
297     UStringPrivate::Composition c(fmt);
298     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5);
299     return c.str();
300   }
302   template <typename T1, typename T2, typename T3, typename T4, typename T5,
303             typename T6>
304   inline Glib::ustring ucompose(const Glib::ustring &fmt,
305                                 const T1 &o1, const T2 &o2, const T3 &o3,
306                                 const T4 &o4, const T5 &o5, const T6 &o6)
307   {
308     UStringPrivate::Composition c(fmt);
309     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6);
310     return c.str();
311   }
313   template <typename T1, typename T2, typename T3, typename T4, typename T5,
314             typename T6, typename T7>
315   inline Glib::ustring ucompose(const Glib::ustring &fmt,
316                                 const T1 &o1, const T2 &o2, const T3 &o3,
317                                 const T4 &o4, const T5 &o5, const T6 &o6,
318                                 const T7 &o7)
319   {
320     UStringPrivate::Composition c(fmt);
321     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7);
322     return c.str();
323   }
325   template <typename T1, typename T2, typename T3, typename T4, typename T5,
326             typename T6, typename T7, typename T8>
327   inline Glib::ustring ucompose(const Glib::ustring &fmt,
328                                 const T1 &o1, const T2 &o2, const T3 &o3,
329                                 const T4 &o4, const T5 &o5, const T6 &o6,
330                                 const T7 &o7, const T8 &o8)
331   {
332     UStringPrivate::Composition c(fmt);
333     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8);
334     return c.str();
335   }
337   template <typename T1, typename T2, typename T3, typename T4, typename T5,
338             typename T6, typename T7, typename T8, typename T9>
339   inline Glib::ustring ucompose(const Glib::ustring &fmt,
340                                 const T1 &o1, const T2 &o2, const T3 &o3,
341                                 const T4 &o4, const T5 &o5, const T6 &o6,
342                                 const T7 &o7, const T8 &o8, const T9 &o9)
343   {
344     UStringPrivate::Composition c(fmt);
345     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9);
346     return c.str();
347   }
349   template <typename T1, typename T2, typename T3, typename T4, typename T5,
350             typename T6, typename T7, typename T8, typename T9, typename T10>
351   inline Glib::ustring ucompose(const Glib::ustring &fmt,
352                                 const T1 &o1, const T2 &o2, const T3 &o3,
353                                 const T4 &o4, const T5 &o5, const T6 &o6,
354                                 const T7 &o7, const T8 &o8, const T9 &o9,
355                                 const T10 &o10)
356   {
357     UStringPrivate::Composition c(fmt);
358     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
359       .arg(o10);
360     return c.str();
361   }
362   
363   template <typename T1, typename T2, typename T3, typename T4, typename T5,
364             typename T6, typename T7, typename T8, typename T9, typename T10,
365             typename T11>
366   inline Glib::ustring ucompose(const Glib::ustring &fmt,
367                                 const T1 &o1, const T2 &o2, const T3 &o3,
368                                 const T4 &o4, const T5 &o5, const T6 &o6,
369                                 const T7 &o7, const T8 &o8, const T9 &o9,
370                                 const T10 &o10, const T11 &o11)
371   {
372     UStringPrivate::Composition c(fmt);
373     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
374       .arg(o10).arg(o11);
375     return c.str();
376   }
378   template <typename T1, typename T2, typename T3, typename T4, typename T5,
379             typename T6, typename T7, typename T8, typename T9, typename T10,
380             typename T11, typename T12>
381   inline Glib::ustring ucompose(const Glib::ustring &fmt,
382                                 const T1 &o1, const T2 &o2, const T3 &o3,
383                                 const T4 &o4, const T5 &o5, const T6 &o6,
384                                 const T7 &o7, const T8 &o8, const T9 &o9,
385                                 const T10 &o10, const T11 &o11, const T12 &o12)
386   {
387     UStringPrivate::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);
390     return c.str();
391   }
393   template <typename T1, typename T2, typename T3, typename T4, typename T5,
394             typename T6, typename T7, typename T8, typename T9, typename T10,
395             typename T11, typename T12, typename T13>
396   inline Glib::ustring ucompose(const Glib::ustring &fmt,
397                                 const T1 &o1, const T2 &o2, const T3 &o3,
398                                 const T4 &o4, const T5 &o5, const T6 &o6,
399                                 const T7 &o7, const T8 &o8, const T9 &o9,
400                                 const T10 &o10, const T11 &o11, const T12 &o12,
401                                 const T13 &o13)
402   {
403     UStringPrivate::Composition c(fmt);
404     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
405       .arg(o10).arg(o11).arg(o12).arg(o13);
406     return c.str();
407   }
409   template <typename T1, typename T2, typename T3, typename T4, typename T5,
410             typename T6, typename T7, typename T8, typename T9, typename T10,
411             typename T11, typename T12, typename T13, typename T14>
412   inline Glib::ustring ucompose(const Glib::ustring &fmt,
413                                 const T1 &o1, const T2 &o2, const T3 &o3,
414                                 const T4 &o4, const T5 &o5, const T6 &o6,
415                                 const T7 &o7, const T8 &o8, const T9 &o9,
416                                 const T10 &o10, const T11 &o11, const T12 &o12,
417                                 const T13 &o13, const T14 &o14)
418   {
419     UStringPrivate::Composition c(fmt);
420     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
421       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14);
422     return c.str();
423   }
425   template <typename T1, typename T2, typename T3, typename T4, typename T5,
426             typename T6, typename T7, typename T8, typename T9, typename T10,
427             typename T11, typename T12, typename T13, typename T14,
428             typename T15>
429   inline Glib::ustring ucompose(const Glib::ustring &fmt,
430                                 const T1 &o1, const T2 &o2, const T3 &o3,
431                                 const T4 &o4, const T5 &o5, const T6 &o6,
432                                 const T7 &o7, const T8 &o8, const T9 &o9,
433                                 const T10 &o10, const T11 &o11, const T12 &o12,
434                                 const T13 &o13, const T14 &o14, const T15 &o15)
435   {
436     UStringPrivate::Composition c(fmt);
437     c.arg(o1).arg(o2).arg(o3).arg(o4).arg(o5).arg(o6).arg(o7).arg(o8).arg(o9)
438       .arg(o10).arg(o11).arg(o12).arg(o13).arg(o14).arg(o15);
439     return c.str();
440   }
444 #endif // STRING_UCOMPOSE_HPP