OSDN Git Service

handle regular expression error.
[hmh/hhml.git] / lib / util_string.cc
1 #include "util_string.h"
2 #include "util_const.h"
3 #include "util_random.h"
4 #include "ml.h"
5 #include "mlenv.h"
6 #include "motorenv.h"
7 #include "ustring.h"
8 #include "utf8.h"
9 #include "utf16.h"
10 #include <boost/regex.hpp>
11 #include <boost/regex/pattern_except.hpp>
12 #include <iconv.h>
13 #include <vector>
14 #include <algorithm>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <float.h>
19 #include <ctype.h>
20
21 ustring  c3 (const ustring& str) {
22     bool  qsign = false;
23     static uregex  re ("^[0-9]+");
24     uiterator  b, e;
25     umatch  m;
26
27     b = str.begin ();
28     e = str.end ();
29     if (str[0] == '-' || str[0] == '+') {
30         qsign = true;
31         b = b + 1;
32     }
33     if (usearch (b, e, m, re)) {
34         int  n = m[0].second - m[0].first;
35         int  l = str.size () + n / 3;
36         ustring  ans;
37
38         ans.reserve (l);
39         if (qsign) {
40             ans.append (1, str[0]);
41         }
42         for (; b != m[0].second; b ++) {
43             ans.append (1, *b);
44             if (n > 1 && n % 3 == 1) {
45                 ans.append (CharConst (","));
46             }
47             n --;
48         }
49         for (; b != e; b ++) {
50             ans.append (1, *b);
51         }
52         return ans;
53     } else {
54         return str;
55     }
56 }
57
58 ustring  to_ustring (double val) {
59     char  b[32];
60     return ustring (b, snprintf (b, 32, "%.*g", DBL_DIG, val));
61 }
62
63 static int  hex (char c) {
64     if ('0' <= c && c <= '9') {
65         return (c - '0');
66     } else if ('a' <= c && c <= 'f') {
67         return (c -  'a' + 10);
68     } else if ('A' <= c && c <= 'F') {
69         return (c - 'A' + 10);
70     } else {
71         return 0;
72     }
73 }
74
75 static int  hex (char c1, char c2) {
76     return (hex (c1) * 16 + hex (c2));
77 }
78
79 static char  hexchar (int c) {
80     if (0 <= c && c <= 9)
81         return '0' + c;
82     else if (10 <= c <= 15)
83         return 'a' - 10 + c;
84     else
85         return '0';
86 }
87
88 static ustring  percentHex (int c) {
89     ustring  ans (3, '%');
90
91     ans[1] = hexchar ((c >> 4) & 0x0f);
92     ans[2] = hexchar (c & 0x0f);
93     return ans;
94 }
95
96 ustring  urldecode_nonul (const ustring& str) {
97     ustring  ans;
98     static uregex  re ("(\\+)|%([0-9a-fA-F][0-9a-fA-F])|\\x00");
99     umatch  m;
100     uiterator  b, e;
101
102     ans.reserve (str.size ());
103     b = str.begin ();
104     e = str.end ();
105     while (usearch (b, e, m, re)) {
106         if (b != m[0].first) {
107             ans.append (b, m[0].first);
108         }
109         if (m[1].matched) {
110             ans.append (1, ' ');
111         } else if (m[2].matched) {
112             int  v = hex (*(m[2].first), *(m[2].first + 1));
113             if (v != 0) 
114                 ans.append (1, v);
115         } else {
116         }
117         b = m[0].second;
118     }
119     if (b != e) {
120         ans.append (b, e);
121     }
122
123     return ans;
124 }
125
126 static ustring  omitPattern (const ustring& text, uregex& re) {
127     Splitter  sp (text, re);
128
129     if (sp.next ()) {
130         if (sp.match (0)) {
131             ustring  ans;
132             ans.reserve (text.length ());
133             if (sp.begin () != sp.end ())
134                 ans.append (sp.begin (), sp.end ());
135             while (sp.next ()) {
136                 if (sp.begin () != sp.end ())
137                     ans.append (sp.begin (), sp.end ());
138             }
139             return ans;
140         } else {
141             return text;
142         }
143     } else {
144         return text;
145     }
146 }
147
148 ustring  omitCtrl (const ustring& str) {
149     static uregex  re ("[\\x00-\\x1f\\x7f]+");
150     return omitPattern (str, re);
151 }
152
153 ustring  omitNL (const ustring& str) {
154     return omitPattern (str, re_nl);
155 }
156
157 ustring  omitNonAscii (const ustring& str) {
158     static uregex  re ("[^ -\\x7e]+");
159     return omitPattern (str, re);
160 }
161
162 ustring  omitNonAsciiWord (const ustring& str) {
163     static uregex  re ("[^\\x21-\\x7e]+");
164     return omitPattern (str, re);
165 }
166
167 bool  to_bool (const ustring& v) {
168     if (v.length () == 0 || (v.length () == 1 && v[0] == '0')) {
169         return false;
170     } else {
171         return true;
172     }
173 }
174
175 static ustring  percentEncode (const ustring& text, uregex& re) {
176     /* $1 -> _
177        $2 -> %HEX
178     */
179     umatch  m;
180     uiterator  b, e;
181     ustring  ans;
182
183     b = text.begin ();
184     e = text.end ();
185     if (b != e && usearch (b, e, m, re)) {
186         if (b != m[0].first) {
187             ans.append (ustring (b, m[0].first));
188         }
189         if (m[1].matched) {
190             ans.append (uUScore);
191         } else if (m[2].matched) {
192             ans.append (percentHex (*m[2].first));
193         } else {
194             assert (0);
195         }
196         b = m[0].second;
197         while (b != e && usearch (b, e, m, re)) {
198             if (b != m[0].first) {
199                 ans.append (ustring (b, m[0].first));
200             }
201             if (m[1].matched) {
202                 ans.append (uUScore);
203             } else if (m[2].matched) {
204                 ans.append (percentHex (*m[2].first));
205             } else {
206                 assert (0);
207             }
208             b = m[0].second;
209         }
210         if (b != e) {
211             ans.append (ustring (b, e));
212         }
213         return ans;
214     } else {
215         return text;
216     }
217 }
218
219 ustring  urlencode (const ustring& url) {
220     static uregex  re ("(\\x00)|([^a-zA-Z0-9_.,/-])");
221     
222     return percentEncode (url, re);
223 }
224
225 ustring  cookieencode (const ustring& text) {
226     static uregex  re ("([\\x00-\\x1f\\x7f])|([ ,;%\\x80-\\xff])");
227
228     return percentEncode (text, re);
229 }
230
231 ustring  cookiedecode (const ustring& text) {
232     umatch  m;
233     uiterator  b, e;
234     ustring  ans;
235     int  a;
236     static uregex  re ("%([0-9a-fA-F])([0-9a-fA-F])");
237
238     b = text.begin ();
239     e = text.end ();
240     while (usearch (b, e, m, re)) {
241         if (b != m[0].first)
242             ans.append (ustring (b, m[0].first));
243         a = hex (*m[1].first, *m[2].first);
244         ans.append (1, a);
245         b = m[0].second;
246     }
247     if (b != e)
248         ans.append (ustring (b, e));
249
250     return ans;
251 }
252
253 ustring  clipColon (const ustring& text) {
254     int  i;
255     ustring  ans (text);
256
257     for (i = 0; i < ans.size (); i ++) {
258         if (ans[i] == ':')
259             ans[i] = '_';
260     }
261     return ans;
262 }
263
264 ustring  dirPart (char* path) {
265     char*  e = rindex (path, '/');
266
267     if (e && e != path) {
268         return ustring (path, e - path);
269     } else {
270         return uSlash;
271     }
272 }
273
274 ustring  dirPart (const ustring& path) {
275     ustring::size_type  s = path.rfind ('/', path.size ());
276
277     if (s == ustring::npos) {
278         return uSlash;
279     } else {
280         return ustring (path.begin (), path.begin () + s);
281     }
282 }
283
284 ustring  filePart_osSafe (const ustring& path) {
285     umatch  m;
286     static uregex  re ("[^\\\\/]+$");
287
288     if (usearch (path, m, re)) {
289         return ustring (m[0].first, m[0].second);
290     } else {
291         return uEmpty;
292     }
293 }
294
295 void  split (uiterator b, uiterator e, uregex& re, std::vector<ustring>& ans) {
296     Splitter  sp (b, e, re);
297
298     while (sp.next ()) {
299         ans.push_back (sp.cur ());
300     }
301 }
302
303 bool  splitChar (uiterator b, uiterator e, uiterator::value_type ch, uiterator& m1) {
304     for (; b < e; b ++) {
305         if (*b == ch) {
306             m1 = b;
307             return true;
308         }
309     }
310     m1 = e;
311     return false;
312 }
313
314 static char  Base64Char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
315 ustring  base64Encode (uiterator b, uiterator e) {
316     ustring  ans;
317     size_t  size;
318     int  c0, c1, c2;
319
320     while (b != e) {
321         size = e - b;
322         if (size >= 3) {
323             c0 = *b ++;
324             c1 = *b ++;
325             c2 = *b ++;
326             ans.append (1, Base64Char[(c0 >> 2) & 0x3f]);
327             ans.append (1, Base64Char[((c0 & 0x03) << 4) | ((c1 >> 4) & 0x0f)]);
328             ans.append (1, Base64Char[((c1 & 0x0f) << 2) | ((c2 >> 6) & 0x03)]);
329             ans.append (1, Base64Char[c2 & 0x3f]);
330         } else if (size == 2) {
331             c0 = *b ++;
332             c1 = *b ++;
333             ans.append (1, Base64Char[(c0 >> 2) & 0x3f]);
334             ans.append (1, Base64Char[((c0 & 0x03) << 4) | ((c1 >> 4) & 0x0f)]);
335             ans.append (1, Base64Char[((c1 & 0x0f) << 2)]);
336             ans.append (1, '=');
337         } else if (size == 1) {
338             c0 = *b ++;
339             ans.append (1, Base64Char[(c0 >> 2) & 0x3f]);
340             ans.append (1, Base64Char[((c0 & 0x03) << 4)]);
341             ans.append (1, '=');
342             ans.append (1, '=');
343         } else {
344             break;
345         }
346     }
347     return ans;
348 }
349
350 ustring  escape_re (const ustring& text) {
351     ustring::const_iterator  b, e;
352     umatch  m;
353     ustring  ans;
354     int  c;
355     char  buf[4];
356     static uregex  re ("[^\\x01- !\"#%',/0-9:;<=>@A-Z_`a-z~\\x7f-\\xff-]");
357
358     buf[0] = '\\';
359     buf[1] = 'x';
360     ans.reserve (text.size () + 16);
361     b = text.begin ();
362     e = text.end ();
363     while (b != e && usearch (b, e, m, re)) {
364         if (b != m[0].first)
365             ans.append (b, m[0].first);
366         c = *m[0].first;
367         buf[2] = hexchar ((c >> 4) & 0x0f);
368         buf[3] = hexchar (c & 0x0f);
369         ans.append (buf, 4);
370         b = m[0].second;
371     }
372     if (b != e)
373         ans.append (b, e);
374     return ans;
375 }
376
377 ustring  slashEncode (const ustring& text) {
378     ustring::const_iterator  b, e;
379     umatch  m;
380     ustring  ans;
381     int  c;
382     char  buf[4];
383     static uregex  re ("([\\x00-\\x1f\\x7f])|(\\\\)|(\")");
384
385     buf[0] = '\\';
386     buf[1] = 'x';
387     b = text.begin ();
388     e = text.end ();
389     while (b != e && usearch (b, e, m, re)) {
390         if (b != m[0].first)
391             ans.append (b, m[0].first);
392         if (m[1].matched) {
393             c = *m[0].first;
394             switch (c) {
395             case '\t':
396                 ans.append (CharConst ("\\t"));
397                 break;
398             case '\r':
399                 ans.append (CharConst ("\\r"));
400                 break;
401             case '\n':
402                 ans.append (CharConst ("\\n"));
403                 break;
404             default:
405                 buf[2] = hexchar ((c >> 4) & 0x0f);
406                 buf[3] = hexchar (c & 0x0f);
407                 ans.append (buf, 4);
408             }
409         } else if (m[2].matched) {
410             ans.append (CharConst ("\\\\"));
411         } else if (m[3].matched) {
412             ans.append (CharConst ("\\\""));
413         } else {
414             assert (0);
415         }
416         b = m[0].second;
417     }
418     if (b != e)
419         ans.append (b, e);
420     return ans;
421 }
422
423 ustring  slashDecode (const ustring& text) {
424     ustring::const_iterator  b, e;
425     umatch  m;
426     ustring  ans;
427     int  c;
428     static uregex  re ("\\\\([0-7][0-7][0-7]|[\\x00-\\x7f])");
429
430     b = text.begin ();
431     e = text.end ();
432     while (b != e && usearch (b, e, m, re)) {
433         if (b != m[0].first)
434             ans.append (b, m[0].first);
435         b = m[0].first + 1;
436         c = *b;
437         switch (c) {
438         case 't':
439             ans.append (CharConst ("\t"));
440             break;
441         case 'r':
442             ans.append (CharConst ("\r"));
443             break;
444         case 'n':
445             ans.append (CharConst ("\n"));
446             break;
447         default:
448             if (m[0].second - m[0].first == 4) {
449                 c = (c - '0') * 64;
450                 b ++;
451                 c += (*b - '0') * 8;
452                 b ++;
453                 c += *b - '0';
454                 if (0 < c && c < 0x20)
455                     ans.append (1, c);
456             } else {
457                 ans.append (1, c);
458             }
459         }
460         b = m[0].second;
461     }
462     if (b != e)
463         ans.append (b, e);
464     return ans;
465 }
466
467 unsigned long  strtoul (const ustring& str) {
468     return strtoul (str.c_str (), NULL, 10);
469 }
470
471 unsigned long  strtoul (const uiterator& b) {
472     return strtoul (&*b, NULL, 10);
473 }
474
475 long  strtol (const ustring& str) {
476     return strtol (str.c_str (), NULL, 10);
477 }
478
479 double  strtod (const ustring& str) {
480     return strtod (str.c_str (), NULL);
481 }
482
483 bool  passMatch (const ustring& pass, const ustring& cpass) {
484     if (pass.length () == 0 || cpass.length () == 0)
485         return false;
486     return (strcmp (crypt (pass.c_str (), cpass.c_str ()), cpass.c_str ()) == 0);
487 }
488
489 ustring  passCrypt (const ustring& pass) {
490     ustring  salt = makeSalt ();
491     return ustring (crypt (pass.c_str (), salt.c_str ()));
492 }
493
494 size_t  strLength (const ustring& src) {
495     uiterator  b, e;
496     size_t  n = 0;
497     b = src.begin ();
498     e = src.end ();
499     while (b < e) {
500         n ++;
501         nextChar (b, e);
502     }
503     return n;
504 }
505
506 void  substring (const ustring& src, size_t idx, size_t len, int flen, ustring& ans) {
507     uiterator  b, e, t;
508     size_t  i;
509
510     b = src.begin ();
511     e = src.end ();
512     for (i = 0; i < idx && b < e; i ++)
513         nextChar (b, e);
514     if (flen) {
515         t = b;
516         for (i = 0; i < len && t < e; i ++)
517             nextChar (t, e);
518         ans.assign (b, t);
519     } else {
520         ans.assign (b, e);
521     }
522 }
523
524 ustring  utf16Encode (const ustring& str) {
525     int  i;
526     ustring  u, ans;
527     int  c;
528     char  b[8];
529
530     u = utf8to16 (str);
531     ans.reserve (u.size () * 3);
532     b[0] = '\\';
533     b[1] = 'u';
534     for (i = 0; i < u.size (); i += 2) {
535         c = u[i];
536         b[2] = hexchar ((c >> 4) & 0x0f);
537         b[3] = hexchar (c & 0x0f);
538         c = u[i + 1];
539         b[4] = hexchar ((c >> 4) & 0x0f);
540         b[5] = hexchar (c & 0x0f);
541         ans.append (b, 6);
542     }
543     return ans;
544 }
545
546 ustring  filenameEncode (const ustring& text) {
547     static uregex  re ("([\\x00-\\x1f\\x7f])|([^a-zA-Z0-9._-])|(^\\.+)");
548     Splitter  sp (text, re);
549     ustring  ans;
550     int  c;
551
552     if (text.length () == 0) {
553         throw (ustring (text).append (uErrorBadName));
554     }
555     ans.reserve (text.length () + 16);
556     while (sp.next ()) {
557         if (sp.begin () < sp.end ())
558             ans.append (sp.begin (), sp.end ());
559         if (sp.match (1)) {
560         } else if (sp.match (2)) {
561             c = *sp.matchBegin (2);
562             ans.append (1, ':');
563             ans.append (1, hexchar ((c >> 4) & 0x0f));
564             ans.append (1, hexchar (c & 0x0f));
565         } else if (sp.match (3)) {
566             for (c = sp.matchEnd (3) - sp.matchBegin (3); c > 0; c --) {
567                 ans.append (CharConst (":2e"));
568             }
569         }
570     }
571     if (ans.length () > 250)
572         ans.resize (250);
573     return ans;
574 }
575
576 bool  matchSkip (uiterator& b, uiterator e, const char* t, size_t s) {
577     if (e - b >= s && memcmp (t, &b[0], s) == 0) {
578         b += s;
579         return true;
580     } else {
581         return false;
582     }
583 }
584
585 bool  matchHead (uiterator& b, uiterator e, const char* t, size_t s) {
586     if (e - b >= s && memcmp (t, &b[0], s) == 0) {
587         return true;
588     } else {
589         return false;
590     }
591 }
592
593 bool  matchHead (const ustring& str, const char* t, size_t s) {
594     if (str.length () >= s && memcmp (t, &*str.begin (), s) == 0) {
595         return true;
596     } else {
597         return false;
598     }
599 }
600
601 bool  matchHead (const ustring& str, const ustring& head) {
602     if (str.length () >= head.length () && memcmp (&*str.begin (), &*head.begin (), head.length ()) == 0) {
603         return true;
604     } else {
605         return false;
606     }
607 }
608
609 bool  match (uiterator b, uiterator e, const char* t, size_t s) {
610     if (e - b == s && memcmp (t, &b[0], s) == 0) {
611         return true;
612     } else {
613         return false;
614     }
615 }
616
617 bool  match (const ustring& str, const char* t, size_t s) {
618     if (str.length () == s && memcmp (t, str.data (), s) == 0) {
619         return true;
620     } else {
621         return false;
622     }
623 }
624
625 bool  match (uiterator b, uiterator e, const ustring& str) {
626     if (e - b == str.length () && memcmp (str.data (), &b[0], str.length ()) == 0) {
627         return true;
628     } else {
629         return false;
630     }
631 }
632
633 bool  match (const ustring& str, const char* t, size_t s, const char* t2, size_t s2) {
634     if (match (str, t, s) || match (str, t2, s2)) {
635         return true;
636     } else {
637         return false;
638     }
639 }
640
641 ustring  clipWhite (uiterator b, uiterator e) {
642     while (b < e)
643         if (isblank (*b)) {
644             b ++;
645         } else {
646             break;
647         }
648     while (b < e)
649         if (isblank (*(e - 1))) {
650             e --;
651         } else {
652             break;
653         }
654     return ustring (b, e);
655 }
656 ustring  clipWhite (const ustring& str) {
657     return clipWhite (str.begin (), str.end ());
658 }
659
660 ustring  getenvString (const char* key) {
661     char*  e = getenv (key);
662     if (e) {
663         return ustring (e);
664     } else {
665         return uEmpty;
666     }
667 }
668
669 ustring  zeroPad (int n, const ustring& src) {
670     int  m;
671
672     n = std::min (32, n);
673     m = n - src.length ();
674     if (m > 0) {
675         ustring  ans;
676         ans.reserve (m);
677         ans.append (m, '0');
678         ans.append (src);
679         return ans;
680     } else {
681         return src;
682     }
683 }
684
685 bool  wsearch (const ustring& text, boost::wsmatch& m, const ustring& reg, boost::wregex::flag_type reg_flags, boost::match_flag_type search_flags) {
686     try {
687         std::wstring  wtext = utow (text);
688         std::wstring  wreg = utow (reg);
689         boost::wregex  wre (wreg, reg_flags);
690         return regex_search (wtext, m, wre, search_flags);
691     } catch (boost::regex_error& err) {
692         throw (uErrorRegexp);
693     }
694 }
695
696 bool  wsearch_env (MlEnv* mlenv, const ustring& text, boost::wsmatch& m, const ustring& reg, boost::wregex::flag_type reg_flags, boost::match_flag_type search_flags) {
697     try {
698         mlenv->env->regtext = utow (text);
699         std::wstring  wreg = utow (reg);
700         boost::wregex  wre (wreg, reg_flags);
701         return regex_search (mlenv->env->regtext, m, wre, search_flags);
702     } catch (boost::regex_error& err) {
703         throw (uErrorRegexp);
704     }
705 }
706
707 ustring  uiconv (const ustring& src, const char* tocode, const char* fromcode) {
708     iconv_t  cd;
709     char  buf[4096];
710     const char*  ibuf;
711     char*  obuf;
712     size_t  isize, osize, rsize;
713     ustring  ans;
714
715     cd = iconv_open (tocode, fromcode);
716     if (cd == (iconv_t)(-1))
717         throw (ustring ("bad encoding name."));
718     ibuf = &src.at (0);
719     isize = src.size ();
720     while (isize > 0) {
721         obuf = buf;
722         osize = 4096;
723         rsize = iconv (cd, &ibuf, &isize, &obuf, &osize);
724 //      if (rsize < 0)
725         if (obuf - buf <= 0)
726             break;
727         ans.append (buf, obuf - buf);
728     }
729     iconv_close (cd);
730     return ans;
731 }
732
733 ustring  padEmpty (const ustring& name) {
734     if (name.empty ())
735         return ustring (CharConst ("(null)"));
736     else
737         return name;
738 }
739
740 uint32_t  hextoul (uiterator b, uiterator e) {
741     uint32_t  ans = 0;
742     int  n;
743
744     for (n = 0; n < 8 && b != e; n ++, b ++) {
745         ans = (ans << 4) + hex (*b);
746     }
747     return ans;
748 }
749
750 ustring  toCRLF (const ustring& str) {
751     uiterator  b = str.begin ();
752     uiterator  e = str.end ();
753     umatch  m;
754     ustring  ans;
755
756     while (usearch (b, e, m, re_lf)) {
757         ans.append (b, m[0].first).append (uCRLF);
758         b = m[0].second;
759     }
760     ans.append (b, e);
761     return ans;
762 }
763
764 void  skipSpace (uiterator& b, uiterator e) {
765     while (b < e && *b == ' ') {
766         b ++;
767     }
768 }
769
770 static ustring::value_type  toLower_ustring_value (ustring::value_type v) {
771     if ('A' <= v && v <= 'Z') {
772         return v - 'A' + 'a';
773     } else {
774         return v;
775     }
776 }
777
778 #if 0
779 void  toLower (ustring::iterator* b, ustring::iterator* e) {
780     transform (*b, *e, *b, toLower_ustring_value);
781 }
782 #endif
783
784 ustring  toLower (uiterator b, uiterator e) {
785     ustring::iterator  i;
786     ustring  ans;
787     ans.resize (e - b);
788     i = ans.begin ();
789     for (; b < e; b ++, i++) {
790         *i = toLower_ustring_value (*b);
791     }
792     return ans;
793 }
794
795 static void  format_hex (ustring& ans, MNode* a, std::vector<ustring>& par, bool fcap) {
796     uint32_t  v = 0;
797     char  buf[32];
798
799     if (a)
800         v = to_int (a);
801
802     if (par.size () > 0) {
803         int  p = strtol (par[0]);
804         if (p < 0)
805             p = 1;
806         if (p > 20)
807             p = 20;
808         if (fcap)
809             ans.append (buf, snprintf (buf, 32, "%.*X", p, v));
810         else
811             ans.append (buf, snprintf (buf, 32, "%.*x", p, v));
812     } else {
813         if (fcap)
814             ans.append (buf, snprintf (buf, 32, "%X", v));
815         else
816             ans.append (buf, snprintf (buf, 32, "%x", v));
817     }
818 }
819
820 static void  format_hex (ustring& ans, MNode* a, std::vector<ustring>& par) {
821     format_hex (ans, a, par, false);
822 }
823
824 static void  format_HEX (ustring& ans, MNode* a, std::vector<ustring>& par) {
825     format_hex (ans, a, par, true);
826 }
827
828 static void  format_int_sub (ustring& ans, MNode* a, std::vector<ustring>& par, bool pad0 = false) {
829     int32_t  v = 0;
830     char  buf[32];
831     size_t  s;
832
833     if (a)
834         v = to_int (a);
835
836     if (par.size () > 0) {
837         bool  fclip = false;
838         bool  fzero = pad0;
839         bool  fc3 = false;
840         if (match (par[0], CharConst ("comma")) || match (par[0], CharConst ("c"))) {
841             ans.append (c3 (to_ustring (v)));
842         } else {
843             int  p = strtol (par[0]);
844             if (p < 0)
845                 p = 1;
846             if (p > 20)
847                 p = 20;
848             for (int i = 1; i < par.size (); i ++) {    
849                 if (match (par[i], CharConst ("clip"))) {
850                     fclip = true;
851                 } else if (match (par[i], CharConst ("0"))) {
852                     fzero = true;
853                 } else if (match (par[i], CharConst ("comma")) || match (par[i], CharConst ("c"))) {
854                     fc3 = true;
855                 } else {
856                     throw (par[i] + uErrorBadParam);
857                 }
858             }
859             if (fzero)
860                 s = snprintf (buf, 32, "%.*ld", p, v);
861             else
862                 s = snprintf (buf, 32, "%*ld", p, v);
863             if (fclip && s > p)
864                 ans.append (buf + s - p, p);
865             else if (! fclip && fc3) 
866                 ans.append (c3 (ustring (buf, s)));
867             else
868                 ans.append (buf, s);
869         }
870     } else {
871         ans.append (to_ustring (v));
872     }
873 }
874
875 static void  format_int (ustring& ans, MNode* a, std::vector<ustring>& par) {
876     format_int_sub (ans, a, par);
877 }
878
879 static void  format_int0 (ustring& ans, MNode* a, std::vector<ustring>& par) {
880     format_int_sub (ans, a, par, true);
881 }
882
883 static void  format_int (ustring& ans, MNode* a, int c, bool pad0 = false) {
884     int32_t  v = 0;
885     char  buf[32];
886     size_t  s;
887
888     if (a)
889         v = to_int (a);
890
891     if (c > 0) {
892         if (c > 20)
893             c = 20;
894         if (pad0)
895             s = snprintf (buf, 32, "%.*ld", c, v);
896         else
897             s = snprintf (buf, 32, "%*ld", c, v);
898         if (s > c)
899             ans.append (buf + s - c, c);
900         else
901             ans.append (buf, s);
902     } else {
903         ans.append (to_ustring (v));
904     }
905 }
906
907 static void  format_float (ustring& ans, MNode* a, std::vector<ustring>& par) {
908     int  p1 = 0;
909     int  p2 = 0;
910     char  buf[32];
911
912     if (par.size () > 0)
913         p1 = strtol (par[0]);
914     if (par.size () > 1)
915         p2 = strtol (par[1]);
916     if (p1 < 0)
917         p1 = 0;
918     if (p2 < 0)
919         p2 = 0;
920     if (p1 > 20)
921         p1 = 20;
922     if (p2 > 20)
923         p2 = 20;
924     ans.append (buf, snprintf (buf, 32, "%*.*lf", p1, p2, to_double (a)));
925 }
926
927 static void  format_string (ustring& ans, MNode* a, std::vector<ustring>& par) {
928     int  p = 0;
929     bool  fright = false;
930     ustring  u = to_string (a);
931
932     if (par.size () > 0)
933         p = strtol (par[0]);
934     if (p > 65536)
935         p = 65536;
936     if (par.size () > 1) {
937         if (match (par[1], CharConst ("right")) || match (par[1], CharConst ("r")))
938             fright = true;
939         else
940             throw (par[1] + uErrorBadParam);
941     }
942     if (fright) {
943         if (u.size () < p)
944             ans.append (p - u.size (), ' ').append (u);
945         else
946             ans.append (u);
947     } else {
948         if (u.size () < p)
949             ans.append (u).append (p - u.size (), ' ');
950         else
951             ans.append (u);
952     }
953 }
954
955 static void  format_literal (ustring& ans, MNode* a, const char* list[], int offset, size_t size) {
956     int  v;
957
958     if (a) {
959         v = to_int (a) - offset;
960         if (0 <= v && v < size)
961             ans.append (list[v]);
962     }
963 }
964
965 static void  format_month (ustring& ans, MNode* a, std::vector<ustring>& par) {
966     static const char*  mstr_a[] = {
967         "Jan", "Feb", "Mar", "Apr",
968         "May", "Jun", "Jul", "Aug",
969         "Sep", "Oct", "Nov", "Dec"
970     };
971     format_literal (ans, a, mstr_a, 1, 12);
972 }
973
974 static void  format_Month (ustring& ans, MNode* a, std::vector<ustring>& par) {
975     static const char*  mstr[] = {
976         "January", "February", "March", "April",
977         "May", "June", "July", "August",
978         "September", "October", "November", "December"
979     };
980     format_literal (ans, a, mstr, 1, 12);
981 }
982
983 static void  format_week (ustring& ans, MNode* a, std::vector<ustring>& par) {
984     static const char*  wstr_a[] = {
985         "Sun", "Mon", "Tue", "Wed",
986         "Thu", "Fri", "Sat"
987     };
988     format_literal (ans, a, wstr_a, 0, 7);
989 }
990
991 static void  format_Week (ustring& ans, MNode* a, std::vector<ustring>& par) {
992     static const char*  wstr[] = {
993         "Sunday", "Monday", "Tuesday", "Wednesday",
994         "Thursday", "Friday", "Saturday"
995     };
996     format_literal (ans, a, wstr, 0, 7);
997 }
998
999 ustring  formatString (const ustring& format, boost::ptr_vector<MNodePtr>& par) {
1000     ustring  ans;
1001     uiterator  b, e;
1002     umatch  m;
1003     u_int  i;
1004     MNode*  a;
1005     static uregex  re ("\\$\\{([1-9][0-9]*)(:([a-zA-Z][a-zA-Z0-9]*)(:([0-9a-z.:]+))?)?\\}");
1006     static struct {
1007         const char* name;
1008         size_t  namelen;
1009         void  (*fn)(ustring& ans, MNode* a, std::vector<ustring>& par);
1010     }  formatFunc[] = {
1011         {CharConst ("hex"), format_hex},
1012         {CharConst ("HEX"), format_HEX},
1013         {CharConst ("int"), format_int},
1014         {CharConst ("int0"), format_int0},
1015         {CharConst ("float"), format_float},
1016         {CharConst ("string"), format_string},
1017         {CharConst ("month"), format_month},
1018         {CharConst ("Month"), format_Month},
1019         {CharConst ("week"), format_week},
1020         {CharConst ("Week"), format_Week},
1021         {NULL, 0, NULL}
1022     };
1023
1024     b = format.begin ();
1025     e = format.end ();
1026     while (usearch (b, e, m, re)) {
1027         ans.append (b, m[0].first);
1028         b = m[0].second;
1029         i = strtoul (ustring (m[1].first, m[1].second)) - 1;
1030         if (i < par.size ()) {
1031             a = par[i] ();
1032         } else {
1033             a = NULL;
1034         }
1035         if (! m[2].matched) {
1036             if (a)
1037                 ans.append (to_string (a));
1038         } else {
1039             std::vector<ustring>  fpar;
1040             int  i;
1041             if (m[4].matched)
1042                 split (m[5].first, m[5].second, re_colon, fpar);
1043             for (i = 0; formatFunc[i].name; i ++) {
1044                 if (match (m[3].first, m[3].second, formatFunc[i].name, formatFunc[i].namelen)) {
1045                     (*formatFunc[i].fn) (ans, a, fpar);
1046                     goto Bp1;
1047                 }
1048             }
1049             ans.append (m[0].first, m[0].second);
1050         Bp1:;
1051         }
1052     }
1053     ans.append (b, e);
1054
1055     return ans;
1056 }
1057
1058 /*
1059  ${Y:4}, ${Y:2}
1060  ${M:2}, ${M}
1061  ${D:2}, ${D}
1062  ${h:2}, ${h}
1063  ${m:2}, ${m}
1064  ${s:2}, ${s}
1065  ${W}, ${w}
1066 */
1067 ustring  formatDateString (const ustring& format, boost::ptr_vector<MNodePtr>& par) {
1068     ustring  ans;
1069     uiterator  b, e;
1070     umatch  m;
1071     u_int  i;
1072     MNode*  a;
1073     static uregex  re ("\\$\\{([YMDhmsWw])(:([0-9]))?\\}");
1074
1075     b = format.begin ();
1076     e = format.end ();
1077     while (usearch (b, e, m, re)) {
1078         std::vector<ustring>  fpar;
1079         ans.append (b, m[0].first);
1080         b = m[0].second;
1081         switch (*m[1].first) {
1082         case 'Y':
1083             a = par[0] ();
1084             break;
1085         case 'M':
1086             a = par[1] ();
1087             break;
1088         case 'D':
1089             a = par[2] ();
1090             break;
1091         case 'h':
1092             a = par[3] ();
1093             break;
1094         case 'm':
1095             a = par[4] ();
1096             break;
1097         case 's':
1098             a = par[5] ();
1099             break;
1100         case 'W':
1101         case 'w':
1102             a = par[6] ();
1103             break;
1104         default:
1105             a = NULL;
1106         }
1107
1108         if (! m[2].matched) {
1109             switch (*m[1].first) {
1110             case 'W':
1111                 format_Week (ans, a, fpar);
1112                 break;
1113             case 'w':
1114                 format_week (ans, a, fpar);
1115                 break;
1116             default:
1117                 if (a)
1118                     ans.append (to_string (a));
1119             }
1120         } else {
1121             format_int (ans, a, strtol (ustring (m[3].first, m[3].second)), true);
1122         }
1123     }
1124     ans.append (b, e);
1125
1126     return ans;
1127 }
1128