OSDN Git Service

948bd2c796cfba10db7079a354eb9d50a7d3d7ca
[hmh/hhml.git] / lib / util_string.cc
1 #include "util_string.h"
2 #include "util_const.h"
3 #include "util_random.h"
4 #include "util_splitter.h"
5 #include "ustring.h"
6 #include "utf8.h"
7 #include "utf16.h"
8 #include <boost/regex.hpp>
9 #include <boost/regex/pattern_except.hpp>
10 #include <boost/algorithm/string.hpp>
11 #include <vector>
12 #include <algorithm>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <string.h>
16 #include <time.h>
17 #include <float.h>
18 #include <ctype.h>
19
20 UIConv::UIConv (const char* in, const char* out) {
21     cd = iconv_open (in, out);
22     if (cd == ICONV_ERR) {
23         throw (ustring (in).append (CharConst (", ")).append (ustring (out)).append (CharConst (": unknown encoding.")));
24     }
25 }
26
27 ustring  UIConv::cv (const ustring& text) {
28     ustring  ans;
29
30     if (cd != ICONV_ERR) {
31         char*  buf = new char[4096];
32         const char*  ibuf;
33         char*  obuf;
34         size_t  isize, osize, rsize;
35
36         ibuf = text.begin ().base ();
37         isize = text.size ();
38         while (isize > 0) {
39             obuf = buf;
40             osize = 4096;
41 #ifdef Linux
42             rsize = ::iconv (cd, (char**)&ibuf, &isize, &obuf, &osize);
43 #else
44             rsize = ::iconv (cd, &ibuf, &isize, &obuf, &osize);
45 #endif
46             if (rsize == -1) {
47                 if (errno == EILSEQ) {
48                     ibuf ++;    
49                     isize --;
50                     ans.append (CharConst ("_"));
51                 } else if (errno == EINVAL) {
52                 } else if (errno == E2BIG) {
53                 } else {
54                     break;
55                 }
56             }
57             if (obuf > buf)
58                 ans.append (buf, obuf - buf);
59         }
60         delete buf;
61     }
62     return ans;
63 }
64
65 ustring  c3 (const ustring& str) {
66     bool  qsign = false;
67     static uregex  re ("^[0-9]+");
68     uiterator  b, e;
69     umatch  m;
70
71     b = str.begin ();
72     e = str.end ();
73     if (str[0] == '-' || str[0] == '+') {
74         qsign = true;
75         b = b + 1;
76     }
77     if (usearch (b, e, m, re)) {
78         int  n = m[0].second - m[0].first;
79         int  l = str.size () + n / 3;
80         ustring  ans;
81
82         ans.reserve (l);
83         if (qsign) {
84             ans.append (1, str[0]);
85         }
86         for (; b != m[0].second; b ++) {
87             ans.append (1, *b);
88             if (n > 1 && n % 3 == 1) {
89                 ans.append (CharConst (","));
90             }
91             n --;
92         }
93         for (; b != e; b ++) {
94             ans.append (1, *b);
95         }
96         return ans;
97     } else {
98         return str;
99     }
100 }
101
102 ustring  to_ustring (double val) {
103     char  b[32];
104     return ustring (b, snprintf (b, 32, "%.*g", DBL_DIG, val));
105 }
106
107 static int  hex (char c) {
108     if ('0' <= c && c <= '9') {
109         return (c - '0');
110     } else if ('a' <= c && c <= 'f') {
111         return (c -  'a' + 10);
112     } else if ('A' <= c && c <= 'F') {
113         return (c - 'A' + 10);
114     } else {
115         return 0;
116     }
117 }
118
119 static int  hex (char c1, char c2) {
120     return (hex (c1) * 16 + hex (c2));
121 }
122
123 static char  hexchar (int c) {
124     if (0 <= c && c <= 9)
125         return '0' + c;
126     else if (10 <= c && c <= 15)
127         return 'a' - 10 + c;
128     else
129         return '0';
130 }
131
132 static char  hexchar_c (int c) {
133     if (0 <= c && c <= 9)
134         return '0' + c;
135     else if (10 <= c && c <= 15)
136         return 'A' - 10 + c;
137     else
138         return '0';
139 }
140
141 static ustring  percentHex (int c) {
142     ustring  ans (3, '%');
143
144     ans[1] = hexchar ((c >> 4) & 0x0f);
145     ans[2] = hexchar (c & 0x0f);
146     return ans;
147 }
148
149 ustring  percentHEX (int c) {
150     ustring  ans (3, '%');
151
152     ans[1] = hexchar_c ((c >> 4) & 0x0f);
153     ans[2] = hexchar_c (c & 0x0f);
154     return ans;
155 }
156
157 ustring  urldecode_nonul (const ustring& str) {
158     ustring  ans;
159     static uregex  re ("(\\+)|%([0-9a-fA-F][0-9a-fA-F])|\\x00");
160     umatch  m;
161     uiterator  b, e;
162
163     ans.reserve (str.size ());
164     b = str.begin ();
165     e = str.end ();
166     while (usearch (b, e, m, re)) {
167         if (b != m[0].first) {
168             ans.append (b, m[0].first);
169         }
170         if (m[1].matched) {
171             ans.append (1, ' ');
172         } else if (m[2].matched) {
173             int  v = hex (*(m[2].first), *(m[2].first + 1));
174             if (v != 0) 
175                 ans.append (1, v);
176         } else {
177         }
178         b = m[0].second;
179     }
180     if (b != e) {
181         ans.append (b, e);
182     }
183
184     return ans;
185 }
186
187 ustring  omitPattern (const ustring& text, uregex& re) {
188     Splitter  sp (text, re);
189
190     if (sp.next ()) {
191         if (sp.match (0)) {
192             ustring  ans;
193             ans.reserve (text.length ());
194             if (sp.begin () != sp.end ())
195                 ans.append (sp.begin (), sp.end ());
196             while (sp.next ()) {
197                 if (sp.begin () != sp.end ())
198                     ans.append (sp.begin (), sp.end ());
199             }
200             return ans;
201         } else {
202             return text;
203         }
204     } else {
205         return text;
206     }
207 }
208
209 ustring  omitCtrl (const ustring& str) {
210     static uregex  re ("[\\x00-\\x1f\\x7f]+");
211     return omitPattern (str, re);
212 }
213
214 ustring  omitCtrlX (const ustring& str) {
215     static uregex  re ("[^\\x09\\x0a\\x20-\\x7e\\x80-\\xff]+");
216     return omitPattern (str, re);
217 }
218
219 ustring  omitNul (const ustring& str) {
220     static uregex  re ("[\\x00]+");
221     return omitPattern (str, re);
222 }
223
224 ustring  omitNL (const ustring& str) {
225     return omitPattern (str, re_nl);
226 }
227
228 ustring  omitNonAscii (const ustring& str) {
229     static uregex  re ("[^ -\\x7e]+");
230     return omitPattern (str, re);
231 }
232
233 ustring  omitNonAsciiWord (const ustring& str) {
234     static uregex  re ("[^\\x21-\\x7e]+");
235     return omitPattern (str, re);
236 }
237
238 static ustring  percentEncode (uiterator b, uiterator e, const uregex& re) {
239     // $1 -> _
240     // $2 -> %HEX
241     umatch  m;
242     ustring  ans;
243
244     while (b < e && usearch (b, e, m, re)) {
245         if (b < m[0].first)
246             ans.append (b, m[0].first);
247         if (m[1].matched) {
248             ans.append (uUScore);
249         } else if (m[2].matched) {
250             ans.append (percentHEX (*m[2].first));
251         } else {
252             assert (0);
253         }
254         b = m[0].second;
255     }
256     if (b < e)
257         ans.append (b, e);
258
259     return ans;
260 }
261
262 ustring  percentEncode (uiterator b, uiterator e) {
263     static uregex  re ("(\\x00)|([^A-Za-z0-9_.~-])");
264
265     return percentEncode (b, e, re);
266 }
267
268 ustring  percentEncode_path (uiterator b, uiterator e) {
269     static uregex  re ("(\\x00)|([^A-Za-z0-9_/.~-])");
270
271     return percentEncode (b, e, re);
272 }
273
274 ustring  percentEncode (const ustring& str) {
275     return percentEncode (str.begin (), str.end ());
276 }
277
278 ustring  percentEncode_path (const ustring& str) {
279     return percentEncode_path (str.begin (), str.end ());
280 }
281
282 #if 0
283 ustring  percentEncode_path (uiterator b, uiterator e) {
284     uiterator  i;
285     ustring  ans;
286
287     for (i = b; i < e; i ++) {
288         if (*i == '/') {
289             if (b < i)
290                 ans.append (percentEncode (b, i));
291             ans.append (uSlash);
292             b = i + 1;
293         }
294     }
295     if (b < e)
296         ans.append (percentEncode (b, e));
297
298     return ans;
299 }
300
301 ustring  percentEncode_path (const ustring& str) {
302     return percentEncode_path (str.begin (), str.end ());
303 }
304 #endif
305
306 ustring  percentDecode (const ustring& str) {
307     ustring  ans;
308     static uregex  re ("%([0-9a-fA-F][0-9a-fA-F])|\\x00");
309     umatch  m;
310     uiterator  b, e;
311
312     b = str.begin ();
313     e = str.end ();
314     while (usearch (b, e, m, re)) {
315         if (b != m[0].first) {
316             ans.append (b, m[0].first);
317         }
318         if (m[1].matched) {
319             int  v = hex (*(m[1].first), *(m[1].first + 1));
320             if (v != 0) 
321                 ans.append (1, v);
322         } else {
323         }
324         b = m[0].second;
325     }
326     if (b != e) {
327         ans.append (b, e);
328     }
329
330     return fixUTF8 (ans);
331 }
332
333 ustring  cookieencode (const ustring& text) {
334     static uregex  re ("([\\x00-\\x1f\\x7f])|([ ,;%\\x80-\\xff])");
335
336     return percentEncode (text.begin (), text.end (), re);
337 }
338
339 ustring  cookiedecode (const ustring& text) {
340     umatch  m;
341     uiterator  b, e;
342     ustring  ans;
343     int  a;
344     static uregex  re ("%([0-9a-fA-F])([0-9a-fA-F])");
345
346     b = text.begin ();
347     e = text.end ();
348     while (usearch (b, e, m, re)) {
349         if (b != m[0].first)
350             ans.append (ustring (b, m[0].first));
351         a = hex (*m[1].first, *m[2].first);
352         ans.append (1, a);
353         b = m[0].second;
354     }
355     if (b != e)
356         ans.append (ustring (b, e));
357
358     return ans;
359 }
360
361 ustring  clipColon (const ustring& text) {
362     int  i;
363     ustring  ans (text);
364
365     for (i = 0; i < ans.size (); i ++) {
366         if (ans[i] == ':')
367             ans[i] = '_';
368     }
369     return ans;
370 }
371
372 ustring  dirPart (const ustring& path) {
373     ustring::size_type  s = path.rfind ('/', path.size ());
374
375     if (s == ustring::npos) {
376 //      return uSlash;
377         return uDot;
378     } else {
379         return ustring (path.begin (), path.begin () + s);
380     }
381 }
382
383 ustring  filePart_osSafe (const ustring& path) {
384     umatch  m;
385     static uregex  re ("[^\\\\/]+$");
386
387     if (usearch (path, m, re)) {
388         return ustring (m[0].first, m[0].second);
389     } else {
390         return uEmpty;
391     }
392 }
393
394 void  split (uiterator b, uiterator e, uregex& re, std::vector<ustring>& ans) {
395     Splitter  sp (b, e, re);
396
397     while (sp.next ()) {
398         ans.push_back (sp.cur ());
399     }
400 }
401
402 void  splitE (uiterator b, uiterator e, uregex& re, std::vector<ustring>& ans) {
403     Splitter  sp (b, e, re);
404
405     if (b != e) {
406         while (sp.nextSep ()) {
407             ans.push_back (sp.cur ());
408         }
409         ans.push_back (ustring (sp.begin (), sp.eol ()));
410     }
411 }
412
413 bool  splitChar (uiterator b, uiterator e, uiterator::value_type ch, uiterator& m1) {
414     for (; b < e; b ++) {
415         if (*b == ch) {
416             m1 = b;
417             return true;
418         }
419     }
420     m1 = e;
421     return false;
422 }
423
424 ustring  escape_re (const ustring& text) {
425     ustring::const_iterator  b, e;
426     umatch  m;
427     ustring  ans;
428     int  c;
429     char  buf[4];
430     static uregex  re ("[^\\x01- !\"#%',/0-9:;<=>@A-Z_`a-z~\\x7f-\\xff-]");
431
432     buf[0] = '\\';
433     buf[1] = 'x';
434     ans.reserve (text.size () + 16);
435     b = text.begin ();
436     e = text.end ();
437     while (b != e && usearch (b, e, m, re)) {
438         if (b != m[0].first)
439             ans.append (b, m[0].first);
440         c = *m[0].first;
441         buf[2] = hexchar ((c >> 4) & 0x0f);
442         buf[3] = hexchar (c & 0x0f);
443         ans.append (buf, 4);
444         b = m[0].second;
445     }
446     if (b != e)
447         ans.append (b, e);
448     return ans;
449 }
450
451 ustring  slashEncode (const ustring& text) {
452     ustring::const_iterator  b, e;
453     umatch  m;
454     ustring  ans;
455     int  c;
456     char  buf[4];
457     static uregex  re ("([\\x00-\\x1f\\x7f])|(\\\\)|(\")");
458
459     buf[0] = '\\';
460     buf[1] = 'x';
461     b = text.begin ();
462     e = text.end ();
463     while (b != e && usearch (b, e, m, re)) {
464         if (b != m[0].first)
465             ans.append (b, m[0].first);
466         if (m[1].matched) {
467             c = *m[0].first;
468             switch (c) {
469             case '\t':
470                 ans.append (CharConst ("\\t"));
471                 break;
472             case '\r':
473                 ans.append (CharConst ("\\r"));
474                 break;
475             case '\n':
476                 ans.append (CharConst ("\\n"));
477                 break;
478             default:
479                 buf[2] = hexchar ((c >> 4) & 0x0f);
480                 buf[3] = hexchar (c & 0x0f);
481                 ans.append (buf, 4);
482             }
483         } else if (m[2].matched) {
484             ans.append (CharConst ("\\\\"));
485         } else if (m[3].matched) {
486             ans.append (CharConst ("\\\""));
487         } else {
488             assert (0);
489         }
490         b = m[0].second;
491     }
492     if (b != e)
493         ans.append (b, e);
494     return ans;
495 }
496
497 ustring  slashDecode (const ustring& text) {
498     ustring::const_iterator  b, e;
499     umatch  m;
500     ustring  ans;
501     int  c;
502     static uregex  re ("\\\\([0-7][0-7][0-7]|[\\x00-\\x7f])");
503
504     b = text.begin ();
505     e = text.end ();
506     while (b != e && usearch (b, e, m, re)) {
507         if (b != m[0].first)
508             ans.append (b, m[0].first);
509         b = m[0].first + 1;
510         c = *b;
511         switch (c) {
512         case 't':
513             ans.append (CharConst ("\t"));
514             break;
515         case 'r':
516             ans.append (CharConst ("\r"));
517             break;
518         case 'n':
519             ans.append (CharConst ("\n"));
520             break;
521         default:
522             if (m[0].second - m[0].first == 4) {
523                 c = (c - '0') * 64;
524                 b ++;
525                 c += (*b - '0') * 8;
526                 b ++;
527                 c += *b - '0';
528                 if (0 < c && c < 0x20)
529                     ans.append (1, c);
530             } else {
531                 ans.append (1, c);
532             }
533         }
534         b = m[0].second;
535     }
536     if (b != e)
537         ans.append (b, e);
538     return ans;
539 }
540
541 unsigned long  strtoul (const ustring& str) {
542     return strtoul (str.c_str (), NULL, 10);
543 }
544
545 unsigned long  strtoul (const uiterator& b) {
546     return strtoul (&*b, NULL, 10);
547 }
548
549 long  strtol (const ustring& str) {
550     return strtol (str.c_str (), NULL, 10);
551 }
552
553 double  strtod (const ustring& str) {
554     return strtod (str.c_str (), NULL);
555 }
556
557 bool  passMatch (const ustring& pass, const ustring& cpass) {
558     if (pass.length () == 0 || cpass.length () == 0)
559         return false;
560     return (strcmp (crypt (pass.c_str (), cpass.c_str ()), cpass.c_str ()) == 0);
561 }
562
563 ustring  passCrypt (const ustring& pass) {
564     ustring  salt = makeSalt ();
565     return ustring (crypt (pass.c_str (), salt.c_str ()));
566 }
567
568 size_t  strLength (const ustring& src) {
569     uiterator  b, e;
570     size_t  n = 0;
571     b = src.begin ();
572     e = src.end ();
573     while (b < e) {
574         n ++;
575         nextChar (b, e);
576     }
577     return n;
578 }
579
580 void  substring (const ustring& src, size_t idx, size_t len, int flen, ustring& ans) {
581     uiterator  b, e, t;
582     size_t  i;
583
584     b = src.begin ();
585     e = src.end ();
586     for (i = 0; i < idx && b < e; i ++)
587         nextChar (b, e);
588     if (flen) {
589         t = b;
590         for (i = 0; i < len && t < e; i ++)
591             nextChar (t, e);
592         ans.assign (b, t);
593     } else {
594         ans.assign (b, e);
595     }
596 }
597
598 static bool  jssafe[] = {
599     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,            // 0--15
600     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,            // 16--31
601     1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,            // 32--47
602     1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,            // 48--63
603     0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,            // 64--79
604     1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,            // 80--95
605     0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,            // 96--111
606     1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,            // 112--127
607 };
608
609 ustring  jsEncode (const ustring& str) {
610     int  i;
611     ustring  u, ans;
612     int  c, d;
613     char  b[8];
614
615     u = utf8to16 (str);
616     ans.reserve (u.size () * 3);
617     b[0] = '\\';
618     b[1] = 'u';
619     for (i = 0; i < u.size (); i += 2) {
620         c = u[i];
621         d = u[i + 1];
622         if (c == 0 && 0 < d && d < 127 && jssafe[d]) {
623             ans.append (1, d);
624         } else {
625             b[2] = hexchar ((c >> 4) & 0x0f);
626             b[3] = hexchar (c & 0x0f);
627             b[4] = hexchar ((d >> 4) & 0x0f);
628             b[5] = hexchar (d & 0x0f);
629             ans.append (b, 6);
630         }
631     }
632     return ans;
633 }
634
635 ustring  filenameEncode (const ustring& text) {
636     static uregex  re ("([\\x00-\\x1f\\x7f])|([^a-zA-Z0-9._-])|(^\\.+)");
637     Splitter  sp (text, re);
638     ustring  ans;
639     int  c;
640
641     if (text.length () == 0) {
642         throw (ustring (text).append (uErrorBadName));
643     }
644     ans.reserve (text.length () + 16);
645     while (sp.next ()) {
646         if (sp.begin () < sp.end ())
647             ans.append (sp.begin (), sp.end ());
648         if (sp.match (1)) {
649         } else if (sp.match (2)) {
650             c = *sp.matchBegin (2);
651             ans.append (1, ':');
652             ans.append (1, hexchar ((c >> 4) & 0x0f));
653             ans.append (1, hexchar (c & 0x0f));
654         } else if (sp.match (3)) {
655             for (c = sp.matchEnd (3) - sp.matchBegin (3); c > 0; c --) {
656                 ans.append (CharConst (":2e"));
657             }
658         }
659     }
660     if (ans.length () > 250)
661         ans.resize (250);
662     return ans;
663 }
664
665 ustring  filenameDecode (const ustring& text) {
666     static uregex  re (":([0-9a-fA-F][0-9a-fA-F])");
667     Splitter  sp (text, re);
668     ustring  ans;
669     int  c;
670
671     ans.reserve (text.length ());
672     while (sp.next ()) {
673         if (sp.begin () < sp.end ())
674             ans.append (sp.begin (), sp.end ());
675         if (sp.match (1)) {
676             c = hex (*(sp.matchBegin (1))) * 16 + hex (*(sp.matchBegin (1) + 1));
677             if (32 <= c && c < 256)
678                 ans.append (1, c);
679         }
680     }
681     return ans;
682 }
683
684 bool  matchSkip (uiterator& b, uiterator e, const char* t, size_t s) {
685     if (e - b >= s && memcmp (t, &b[0], s) == 0) {
686         b += s;
687         return true;
688     } else {
689         return false;
690     }
691 }
692
693 bool  matchHead (uiterator& b, uiterator e, const char* t, size_t s) {
694     if (e - b >= s && memcmp (t, &b[0], s) == 0) {
695         return true;
696     } else {
697         return false;
698     }
699 }
700
701 bool  matchHead (const ustring& str, const char* t, size_t s) {
702     if (str.length () >= s && memcmp (t, &*str.begin (), s) == 0) {
703         return true;
704     } else {
705         return false;
706     }
707 }
708
709 bool  matchHead (const ustring& str, const ustring& head) {
710     if (str.length () >= head.length () && memcmp (&*str.begin (), &*head.begin (), head.length ()) == 0) {
711         return true;
712     } else {
713         return false;
714     }
715 }
716
717 bool  match (uiterator b, uiterator e, const char* t, size_t s) {
718     if (e - b == s && memcmp (t, &b[0], s) == 0) {
719         return true;
720     } else {
721         return false;
722     }
723 }
724
725 bool  match (const ustring& str, const char* t, size_t s) {
726     if (str.length () == s && memcmp (t, str.data (), s) == 0) {
727         return true;
728     } else {
729         return false;
730     }
731 }
732
733 bool  match (uiterator b, uiterator e, const ustring& str) {
734     if (e - b == str.length () && memcmp (str.data (), &b[0], str.length ()) == 0) {
735         return true;
736     } else {
737         return false;
738     }
739 }
740
741 bool  match (const ustring& str, const char* t, size_t s, const char* t2, size_t s2) {
742     if (match (str, t, s) || match (str, t2, s2)) {
743         return true;
744     } else {
745         return false;
746     }
747 }
748
749 ustring  clipWhite (uiterator b, uiterator e) {
750     while (b < e)
751         if (isblank (*b)) {
752             b ++;
753         } else {
754             break;
755         }
756     while (b < e)
757         if (isblank (*(e - 1))) {
758             e --;
759         } else {
760             break;
761         }
762     return ustring (b, e);
763 }
764 ustring  clipWhite (const ustring& str) {
765     return clipWhite (str.begin (), str.end ());
766 }
767
768 ustring  getenvString (const char* key) {
769     char*  e = getenv (key);
770     if (e) {
771         return ustring (e);
772     } else {
773         return uEmpty;
774     }
775 }
776
777 ustring  zeroPad (int n, const ustring& src) {
778     int  m;
779
780     n = std::min (32, n);
781     m = n - src.length ();
782     if (m > 0) {
783         ustring  ans;
784         ans.reserve (m);
785         ans.append (m, '0');
786         ans.append (src);
787         return ans;
788     } else {
789         return src;
790     }
791 }
792
793 ustring  padEmpty (const ustring& name) {
794     if (name.empty ())
795         return ustring (CharConst ("(null)"));
796     else
797         return name;
798 }
799
800 uint32_t  hextoul (uiterator b, uiterator e) {
801     uint32_t  ans = 0;
802     int  n;
803
804     for (n = 0; n < 8 && b != e; n ++, b ++) {
805         ans = (ans << 4) + hex (*b);
806     }
807     return ans;
808 }
809
810 ustring  toCRLF (const ustring& str) {
811     uiterator  b = str.begin ();
812     uiterator  e = str.end ();
813     umatch  m;
814     ustring  ans;
815
816     while (usearch (b, e, m, re_lf)) {
817         ans.append (b, m[0].first).append (uCRLF);
818         b = m[0].second;
819     }
820     ans.append (b, e);
821     return ans;
822 }
823
824 void  skipChar (uiterator& b, uiterator e, int ch) {
825     while (b < e && *b == ch)
826         ++ b;
827 }
828
829 void  skipNextToChar (uiterator& b, uiterator e, int ch) {
830     while (b < e) {
831         if (*(b ++) == ch)
832             return;
833     }
834 }
835
836 static ustring::value_type  toLower_ustring_value (ustring::value_type v) {
837     if ('A' <= v && v <= 'Z') {
838         return v - 'A' + 'a';
839     } else {
840         return v;
841     }
842 }
843
844 ustring  toLower (uiterator b, uiterator e) {
845     ustring::iterator  i;
846     ustring  ans;
847     ans.resize (e - b);
848     i = ans.begin ();
849     for (; b < e; b ++, i++) {
850         *i = toLower_ustring_value (*b);
851     }
852     return ans;
853 }
854
855 static ustring  colpad0 (int n, const ustring& src) {
856     int  m;
857
858     if (n > 0) {
859         n = std::min (32, n);
860         m = n - src.length ();
861         if (m > 0) {
862             ustring  ans;
863             ans.reserve (n);
864             ans.append (m, '0');
865             ans.append (src);
866             return ans;
867         } else if (m == 0) {
868             return src;
869         } else {
870             return ustring (src.end () - n, src.end ());
871         }
872     } else {
873         return src;
874     }
875 }
876
877 /*
878  ${Y:4}, ${Y:2}
879  ${M:2}, ${M}, ${M:name}, ${M:ab}
880  ${D:2}, ${D}
881  ${h:2}, ${h}
882  ${m:2}, ${m}
883  ${s:2}, ${s}
884  ${W}, ${w}
885  ${o}
886 */
887 //ustring  formatDateString (const ustring& format, time_t tm) {
888 ustring  formatDateString (const ustring& format, struct tm& v) {
889     ustring  ans;
890 //    struct tm  v;
891     uiterator  b, e;
892     umatch  m;
893     int  pc;
894 //    static uregex  re ("\\$\\{([YMDhmsWw])(:([0-9]))?\\}");
895     static uregex  re ("\\$\\{(([YMDhmsWwo])(:([0-9]))?|M:((name)|(ab)|(abname)))\\}");
896     std::vector<ustring>  fpar;
897
898 //    localtime_r (&tm, &v);
899     b = format.begin ();
900     e = format.end ();
901     while (usearch (b, e, m, re)) {
902         ans.append (b, m[0].first);
903         b = m[0].second;
904         if (m[5].matched) {
905             if (m[6].matched) { // name
906                 ans.append (MStr[v.tm_mon]);
907             } else if (m[7].matched || m[8].matched) { // abname
908                 ans.append (MStr_a[v.tm_mon]);
909             }
910         } else {
911 //          if (m[2].matched) {
912             if (m[3].matched) {
913 //              pc = strtol (ustring (m[3].first, m[3].second));
914                 pc = strtol (ustring (m[4].first, m[4].second));
915             } else {
916                 pc = 0;
917             }
918 //          switch (*m[1].first) {
919             switch (*m[2].first) {
920             case 'Y':
921                 ans.append (colpad0 (pc, to_ustring (v.tm_year + 1900)));
922                 break;
923             case 'M':
924                 ans.append (colpad0 (pc, to_ustring (v.tm_mon + 1)));
925                 break;
926             case 'D':
927                 ans.append (colpad0 (pc, to_ustring (v.tm_mday)));
928                 break;
929             case 'h':
930                 ans.append (colpad0 (pc, to_ustring (v.tm_hour)));
931                 break;
932             case 'm':
933                 ans.append (colpad0 (pc, to_ustring (v.tm_min)));
934                 break;
935             case 's':
936                 ans.append (colpad0 (pc, to_ustring (v.tm_sec)));
937                 break;
938             case 'W':
939                 ans.append (WStr [v.tm_wday]);
940                 break;
941             case 'w':
942                 ans.append (WStr_a [v.tm_wday]);
943                 break;
944             case 'o':
945                 {
946                     int  h, m;
947                     if (v.tm_gmtoff < 0) {
948                         h = - v.tm_gmtoff / 60;
949                         m = h % 60;
950                         h = h / 60;
951                         ans.append (CharConst ("-")).append (colpad0 (4, to_ustring (h * 100 + m)));
952                     } else {
953                         h = v.tm_gmtoff / 60;
954                         m = h % 60;
955                         h = h / 60;
956                         ans.append (CharConst ("+")).append (colpad0 (4, to_ustring (h * 100 + m)));
957                     }
958                 }
959                 break;
960             }
961         }
962     }
963     ans.append (b, e);
964
965     return ans;
966 }
967
968 ustring  toLower (const ustring& str) {
969     return boost::to_lower_copy (str);
970 }
971
972 ustring  toUpper (const ustring& str) {
973     return boost::to_upper_copy (str);
974 }
975
976 ustring  hexEncode (const ustring& data) {
977     ustring  ans;
978     uiterator  b, e;
979
980     ans.reserve (data.length () * 2);
981     b = data.begin ();
982     e = data.end ();
983     for (; b < e; b ++) {
984         ans.append (1, hexchar ((*b >> 4) & 0x0f));
985         ans.append (1, hexchar (*b & 0x0f));
986     }
987     return ans;
988 }
989
990 int  octchar (uiterator b) {    // 3bytes
991     int  ans = 0;
992     ans = *b - '0';
993     ++ b;
994     ans = ans * 8 + *b - '0';
995     ++ b;
996     ans = ans * 8 + *b - '0';
997     return ans;
998 }
999
1000 ustring  octchar (int c) {
1001     ustring  ans (3, 0);
1002     ans[2] = (c & 0x7) + '0';
1003     c >>= 3;
1004     ans[1] = (c & 0x7) + '0';
1005     c >>= 3;
1006     ans[0] = (c & 0x3) + '0';
1007     return ans;
1008 }