OSDN Git Service

baaa19adb2e81155ae06bfa411780715125c3ad5
[hmh/hhml.git] / lib / util_string.cc
1 #include "config.h"
2 #include "util_string.h"
3 #include "util_const.h"
4 #include "util_random.h"
5 #include "util_splitter.h"
6 #include "ustring.h"
7 #include "utf8.h"
8 #include "utf16.h"
9 #include <boost/regex.hpp>
10 #include <boost/regex/pattern_except.hpp>
11 #include <boost/algorithm/string.hpp>
12 #include <vector>
13 #include <algorithm>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <time.h>
18 #include <float.h>
19 #include <ctype.h>
20
21 UIConv::UIConv (const char* in, const char* out) {
22     cd = iconv_open (in, out);
23     if (cd == ICONV_ERR) {
24         throw (ustring (in).append (CharConst (", ")).append (ustring (out)).append (CharConst (": unknown encoding.")));
25     }
26 }
27
28 ustring  UIConv::cv (const ustring& text, bool flush) {
29     ustring  ans;
30
31     if (cd != ICONV_ERR) {
32         char*  buf = new char[4096];
33         const char*  ibuf;
34         char*  obuf;
35         size_t  isize, osize, rsize;
36
37         ibuf = text.begin ().base ();
38         isize = text.size ();
39         while (isize > 0) {
40             obuf = buf;
41             osize = 4096;
42             rsize = ::iconv (cd, (char**)&ibuf, &isize, &obuf, &osize);
43             if (rsize == -1) {
44                 if (errno == EILSEQ) {
45                     ibuf ++;    
46                     isize --;
47                     ans.append (CharConst ("_"));
48                 } else if (errno == EINVAL) {
49                 } else if (errno == E2BIG) {
50                 } else {
51                     break;
52                 }
53             }
54             if (obuf > buf)
55                 ans.append (buf, obuf - buf);
56         }
57         if (flush) {
58             obuf = buf;
59             osize = 4096;
60             rsize = ::iconv (cd, NULL, NULL, &obuf, &osize);
61             if (obuf > buf)
62                 ans.append (buf, obuf - buf);
63         }
64         delete buf;
65     }
66     return ans;
67 }
68
69 ///////////////////////////////////////////////////////////////////////
70 static bool  isDigit (int c) {
71     return '0' <= c && c <= '9';
72 }
73
74 ustring  c3 (const ustring& str) {
75     bool  qsign = false;
76     uiterator  b, e, t;
77
78     b = str.begin ();
79     e = str.end ();
80     if (str[0] == '-' || str[0] == '+') {
81         qsign = true;
82         b = b + 1;
83     }
84     t = b;
85     if (matchHeadFn (t, e, isDigit)) {
86         int  n = t - b;
87         int  l = str.size () + n / 3;
88         ustring  ans;
89         ans.reserve (l);
90         if (qsign) {
91             ans.append (1, str[0]);
92         }
93         for (; b < t; ++ b) {
94             ans.append (1, *b);
95             if (n > 1 && n % 3 == 1) {
96                 ans.append (CharConst (","));
97             }
98             n --;
99         }
100         for (; b != e; b ++) {
101             ans.append (1, *b);
102         }
103         return ans;
104     } else {
105         return str;
106     }
107 }
108
109 ustring  to_ustring (int32_t v) {
110     return boost::lexical_cast<ustring> (v);
111 }
112
113 ustring  to_ustring (uint32_t v) {
114     return boost::lexical_cast<ustring> (v);
115 }
116
117 ustring  to_ustring (long int v) {
118     return boost::lexical_cast<ustring> (v);
119 }
120
121 ustring  to_ustring (unsigned long int v) {
122     return boost::lexical_cast<ustring> (v);
123 }
124
125 ustring  to_ustring (long long int v) {
126     return boost::lexical_cast<ustring> (v);
127 }
128
129 ustring  to_ustring (unsigned long long int v) {
130     return boost::lexical_cast<ustring> (v);
131 }
132
133 ustring  to_ustring (double val) {
134     char  b[32];
135     return ustring (b, snprintf (b, 32, "%.*g", DBL_DIG, val));
136 }
137
138 int32_t  to_int32 (const ustring& v) {
139     return boost::lexical_cast<int32_t> (v);
140 }
141
142 uint32_t  to_uint32 (const ustring& v) {
143     return boost::lexical_cast<uint32_t> (v);
144 }
145
146 uint64_t  to_uint64 (const ustring& v) {
147     return boost::lexical_cast<uint64_t> (v);
148 }
149
150 static int  shex (char c) {
151     if ('0' <= c && c <= '9') {
152         return (c - '0');
153     } else if ('a' <= c && c <= 'f') {
154         return (c -  'a' + 10);
155     } else if ('A' <= c && c <= 'F') {
156         return (c - 'A' + 10);
157     } else {
158         return -1;
159     }
160 }
161
162 static int  hex (char c) {
163     if ('0' <= c && c <= '9') {
164         return (c - '0');
165     } else if ('a' <= c && c <= 'f') {
166         return (c -  'a' + 10);
167     } else if ('A' <= c && c <= 'F') {
168         return (c - 'A' + 10);
169     } else {
170         return 0;
171     }
172 }
173
174 static int  hex (char c1, char c2) {
175     return (hex (c1) * 16 + hex (c2));
176 }
177
178 static char  hexchar (int c) {
179     if (0 <= c && c <= 9)
180         return '0' + c;
181     else if (10 <= c && c <= 15)
182         return 'a' - 10 + c;
183     else
184         return '0';
185 }
186
187 static char  hexchar_c (int c) {
188     if (0 <= c && c <= 9)
189         return '0' + c;
190     else if (10 <= c && c <= 15)
191         return 'A' - 10 + c;
192     else
193         return '0';
194 }
195
196 static ustring  percentHex (int c) {
197     ustring  ans (3, '%');
198
199     ans[1] = hexchar ((c >> 4) & 0x0f);
200     ans[2] = hexchar (c & 0x0f);
201     return ans;
202 }
203
204 ustring  percentHEX (int c) {
205     ustring  ans (3, '%');
206
207     ans[1] = hexchar_c ((c >> 4) & 0x0f);
208     ans[2] = hexchar_c (c & 0x0f);
209     return ans;
210 }
211
212 ustring  urldecode_nonul (const ustring& str) {
213     ustring  ans;
214     static uregex  re ("(\\+)|%([0-9a-fA-F][0-9a-fA-F])|\\x00");
215     umatch  m;
216     uiterator  b, e;
217
218     ans.reserve (str.size ());
219     b = str.begin ();
220     e = str.end ();
221     while (usearch (b, e, m, re)) {
222         if (b != m[0].first) {
223             ans.append (b, m[0].first);
224         }
225         if (m[1].matched) {
226             ans.append (1, ' ');
227         } else if (m[2].matched) {
228             int  v = hex (*(m[2].first), *(m[2].first + 1));
229             if (v != 0) 
230                 ans.append (1, v);
231         } else {
232         }
233         b = m[0].second;
234     }
235     if (b != e) {
236         ans.append (b, e);
237     }
238
239     return ans;
240 }
241
242 static ustring  omitPattern (const ustring& text, int (*fn)(int)) {
243     uiterator  b = text.begin ();
244     uiterator  e = text.end ();
245     uiterator  p = b;
246     for (; p < e; ++ p) {
247         if (fn (*p))
248             break;
249     }
250     if (p == e) {
251         return text;
252     } else {
253         ustring  ans;
254         ans.reserve (text.length ());
255         ans.assign (b, p);
256         ++ p;
257         for (; p < e; ++ p) {
258             if (! fn (*p))
259                 ans.append (1, *p);
260         }
261         return ans;
262     }
263 }
264
265 ustring  omitCtrl (const ustring& str) {
266     return omitPattern (str, iscntrl);
267 }
268
269 static int  iscntrlx (int c) {
270     static char  table_ctrlx[] = {
271         1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 
272         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
273         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
274         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
275         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
276         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
277         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
278         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 
279     };
280     if (0 <= c && c < 128)
281         return table_ctrlx[c];
282     return 0;
283 }
284
285 ustring  omitCtrlX (const ustring& str) {
286     return omitPattern (str, iscntrlx);
287 }
288
289 static int  isNUL (int c) {
290     return c == 0;
291 }
292
293 ustring  omitNul (const ustring& str) {
294     return omitPattern (str, isNUL);
295 }
296
297 static int  iscrlfchar (int c) {
298     return c == 0x0a || c == 0x0d;
299 }
300
301 ustring  omitNL (const ustring& str) {
302     return omitPattern (str, iscrlfchar);
303 }
304
305 static int  isnonasciichar (int c) {
306     return c < 0x20 || c > 0x7e;
307 }
308
309 ustring  omitNonAscii (const ustring& str) {
310     return omitPattern (str, isnonasciichar);
311 }
312
313 static int  isnonasciiword (int c) {
314     return c < 0x21 || c > 0x7e;
315 }
316
317 ustring  omitNonAsciiWord (const ustring& str) {
318     return omitPattern (str, isnonasciiword);
319 }
320
321 static ustring  percentEncode (Splitter& sp) {
322     ustring  ans;
323     int  c;
324     while (sp.nextSep ()) {
325         if (sp.preSize () > 0)
326             ans.append (sp.pre ());
327         c = *sp.matchBegin ();
328         if (c == '\0') {
329             ans.append (uUScore);
330         } else {
331             ans.append (percentHEX (c));
332         }
333     }
334     if (sp.preSize () > 0)
335         ans.append (sp.pre ());
336     return ans;
337 }
338
339 static bool  findPercentChar (uiterator& b, uiterator e, uiterator& u) {
340     static char  table_percentchar[] = {                // (\x00)|([^A-Za-z0-9_.~\-])
341         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
342         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
343         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 
344         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 
345         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
346         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 
347         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
348         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 
349     };
350     int  c;
351     for (; b < e; ++ b) {
352         c = *b;
353         if (c < 0 || c >= 128 || table_percentchar[c]) {
354             u = b + 1;
355             return true;
356         }
357     }
358     u = e;
359     return false;
360 }
361
362 ustring  percentEncode (uiterator b, uiterator e) {
363 //    static uregex  re ("(\\x00)|([^A-Za-z0-9_.~-])");
364     SplitterFn  sp (b, e, findPercentChar);
365     return percentEncode (sp);
366 }
367
368 static bool  findPercentPathChar (uiterator& b, uiterator e, uiterator& u) {
369     static char  table_percentpathchar[] = {            // (\x00)|([^A-Za-z0-9_\/.~\-])
370         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
371         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
372         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 
373         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 
374         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
375         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 
376         1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
377         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 
378     };
379     int  c;
380     for (; b < e; ++ b) {
381         c = *b;
382         if (c < 0 || c >= 128 || table_percentpathchar[c]) {
383             u = b + 1;
384             return true;
385         }
386     }
387     u = e;
388     return false;
389 }
390
391 ustring  percentEncode_path (uiterator b, uiterator e) {
392 //    static uregex  re ("(\\x00)|([^A-Za-z0-9_/.~-])");
393     SplitterFn  sp (b, e, findPercentPathChar);
394     return percentEncode (sp);
395 }
396
397 ustring  percentDecode (const ustring& str) {
398     ustring  ans;
399     static uregex  re ("%([0-9a-fA-F][0-9a-fA-F])|\\x00");
400     umatch  m;
401     uiterator  b, e;
402
403     b = str.begin ();
404     e = str.end ();
405     while (usearch (b, e, m, re)) {
406         if (b != m[0].first) {
407             ans.append (b, m[0].first);
408         }
409         if (m[1].matched) {
410             int  v = hex (*(m[1].first), *(m[1].first + 1));
411             if (v != 0) 
412                 ans.append (1, v);
413         } else {
414         }
415         b = m[0].second;
416     }
417     if (b != e) {
418         ans.append (b, e);
419     }
420
421     return fixUTF8 (ans);
422 }
423
424 static bool  findCookieEncChar (uiterator& b, uiterator e, uiterator& u) {
425     static char  table_cookieencode[] = {               // ([\\x00-\\x1f\\x7f])|([ ,;%\\x80-\\xff])
426         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
427         1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
428         1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 
429         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 
430         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
431         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
432         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
433         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 
434     };
435     int  c;
436     for (; b < e; ++ b) {
437         c = *b;
438         if (c < 0 || c >= 128 || table_cookieencode[c]) {
439             u = b + 1;
440             return true;
441         }
442     }
443     u = e;
444     return false;
445 }
446
447 ustring  cookieencode (const ustring& text) {
448 //    static uregex  re ("([\\x00-\\x1f\\x7f])|([ ,;%\\x80-\\xff])");
449     SplitterFn  sp (text.begin (), text.end (), findCookieEncChar);
450     return percentEncode (sp);
451 }
452
453 ustring  cookiedecode (const ustring& text) {
454     umatch  m;
455     uiterator  b, e;
456     ustring  ans;
457     int  a;
458     static uregex  re ("%([0-9a-fA-F])([0-9a-fA-F])");
459
460     b = text.begin ();
461     e = text.end ();
462     while (usearch (b, e, m, re)) {
463         if (b != m[0].first)
464             ans.append (ustring (b, m[0].first));
465         a = hex (*m[1].first, *m[2].first);
466         ans.append (1, a);
467         b = m[0].second;
468     }
469     if (b != e)
470         ans.append (ustring (b, e));
471
472     return ans;
473 }
474
475 ustring  clipColon (const ustring& text) {
476     int  i;
477     ustring  ans (text);
478
479     for (i = 0; i < ans.size (); i ++) {
480         if (ans[i] == ':')
481             ans[i] = '_';
482     }
483     return ans;
484 }
485
486 ustring  dirPart (const ustring& path) {
487     ustring::size_type  s = path.rfind ('/', path.size ());
488
489     if (s == ustring::npos) {
490 //      return uSlash;
491         return uDot;
492     } else {
493         return ustring (path.begin (), path.begin () + s);
494     }
495 }
496
497 ustring  filePart_osSafe (const ustring& path) {
498     umatch  m;
499     static uregex  re ("[^\\\\/]+$");
500
501     if (usearch (path, m, re)) {
502         return ustring (m[0].first, m[0].second);
503     } else {
504         return uEmpty;
505     }
506 }
507
508 void  split (uiterator b, uiterator e, uregex& re, std::vector<ustring>& ans) {
509     SplitterRe  sp (b, e, re);
510
511     while (sp.next ()) {
512         ans.push_back (sp.pre ());
513     }
514 }
515
516 void  split (uiterator b, uiterator e, int ch, std::vector<ustring>& ans) {
517     SplitterCh  sp (b, e, ch);
518
519     while (sp.next ()) {
520         ans.push_back (sp.pre ());
521     }
522 }
523
524 void  splitE (uiterator b, uiterator e, uregex& re, std::vector<ustring>& ans) {
525     SplitterRe  sp (b, e, re);
526
527     if (b < e) {
528         while (sp.nextSep ()) {
529             ans.push_back (sp.pre ());
530         }
531         ans.push_back (sp.pre ());
532     }
533 }
534
535 void  splitE (uiterator b, uiterator e, int ch, std::vector<ustring>& ans) {
536     SplitterCh  sp (b, e, ch);
537
538     if (b < e) {
539         while (sp.nextSep ()) {
540             ans.push_back (sp.pre ());
541         }
542         ans.push_back (sp.pre ());
543     }
544 }
545
546 bool  splitChar (uiterator b, uiterator e, uiterator::value_type ch, uiterator& m1) {
547     for (; b < e; b ++) {
548         if (*b == ch) {
549             m1 = b;
550             return true;
551         }
552     }
553     m1 = e;
554     return false;
555 }
556
557 ustring  escape_re (const ustring& text) {
558     ustring::const_iterator  b, e;
559     umatch  m;
560     ustring  ans;
561     int  c;
562     char  buf[4];
563     static uregex  re ("[^\\x01- !\"#%',/0-9:;<=>@A-Z_`a-z~\\x7f-\\xff-]");
564
565     buf[0] = '\\';
566     buf[1] = 'x';
567     ans.reserve (text.size () + 16);
568     b = text.begin ();
569     e = text.end ();
570     while (b != e && usearch (b, e, m, re)) {
571         if (b != m[0].first)
572             ans.append (b, m[0].first);
573         c = *m[0].first;
574         buf[2] = hexchar ((c >> 4) & 0x0f);
575         buf[3] = hexchar (c & 0x0f);
576         ans.append (buf, 4);
577         b = m[0].second;
578     }
579     if (b != e)
580         ans.append (b, e);
581     return ans;
582 }
583
584 ustring  slashEncode (const ustring& text) {
585     ustring::const_iterator  b, e;
586     umatch  m;
587     ustring  ans;
588     int  c;
589     char  buf[4];
590     static uregex  re ("([\\x00-\\x1f\\x7f])|(\\\\)|(\")");
591
592     buf[0] = '\\';
593     buf[1] = 'x';
594     b = text.begin ();
595     e = text.end ();
596     while (b != e && usearch (b, e, m, re)) {
597         if (b != m[0].first)
598             ans.append (b, m[0].first);
599         if (m[1].matched) {
600             c = *m[0].first;
601             switch (c) {
602             case '\t':
603                 ans.append (CharConst ("\\t"));
604                 break;
605             case '\r':
606                 ans.append (CharConst ("\\r"));
607                 break;
608             case '\n':
609                 ans.append (CharConst ("\\n"));
610                 break;
611             default:
612                 buf[2] = hexchar ((c >> 4) & 0x0f);
613                 buf[3] = hexchar (c & 0x0f);
614                 ans.append (buf, 4);
615             }
616         } else if (m[2].matched) {
617             ans.append (CharConst ("\\\\"));
618         } else if (m[3].matched) {
619             ans.append (CharConst ("\\\""));
620         } else {
621             assert (0);
622         }
623         b = m[0].second;
624     }
625     if (b != e)
626         ans.append (b, e);
627     return ans;
628 }
629
630 ustring  slashDecode (const ustring& text) {
631     ustring::const_iterator  b, e;
632     umatch  m;
633     ustring  ans;
634     int  c;
635     static uregex  re ("\\\\([0-7][0-7][0-7]|[\\x00-\\x7f])");
636
637     b = text.begin ();
638     e = text.end ();
639     while (b != e && usearch (b, e, m, re)) {
640         if (b != m[0].first)
641             ans.append (b, m[0].first);
642         b = m[0].first + 1;
643         c = *b;
644         switch (c) {
645         case 't':
646             ans.append (CharConst ("\t"));
647             break;
648         case 'r':
649             ans.append (CharConst ("\r"));
650             break;
651         case 'n':
652             ans.append (CharConst ("\n"));
653             break;
654         default:
655             if (m[0].second - m[0].first == 4) {
656                 c = (c - '0') * 64;
657                 b ++;
658                 c += (*b - '0') * 8;
659                 b ++;
660                 c += *b - '0';
661                 if (0 < c && c < 0x20)
662                     ans.append (1, c);
663             } else {
664                 ans.append (1, c);
665             }
666         }
667         b = m[0].second;
668     }
669     if (b != e)
670         ans.append (b, e);
671     return ans;
672 }
673
674 unsigned long  strtoul (const ustring& str) {
675     return strtoul (str.c_str (), NULL, 10);
676 }
677
678 unsigned long  strtoul (const uiterator& b) {
679     return strtoul (&*b, NULL, 10);
680 }
681
682 long  strtol (const ustring& str) {
683     return strtol (str.c_str (), NULL, 10);
684 }
685
686 double  strtod (const ustring& str) {
687     return strtod (str.c_str (), NULL);
688 }
689
690 bool  passMatch (const ustring& pass, const ustring& cpass) {
691     if (pass.length () == 0 || cpass.length () == 0)
692         return false;
693     return (strcmp (crypt (pass.c_str (), cpass.c_str ()), cpass.c_str ()) == 0);
694 }
695
696 ustring  passCrypt (const ustring& pass, passCryptFormat format) {
697     // XXX not thread safe.
698     ustring  salt;
699     switch (format) {
700     case FORMAT_MD5:
701         salt = makeSalt ('1', 8);
702         break;
703 //    case FORMAT_BF:
704 //      salt = makeSalt ('2', 16);
705 //      break;
706     case FORMAT_SHA256:
707         salt = makeSalt ('5', 16);
708         break;
709     case FORMAT_SHA512:
710         salt = makeSalt ('6', 16);
711         break;
712     default:
713         assert (0);
714     }
715     return ustring (crypt (pass.c_str (), salt.c_str ()));
716 }
717
718 size_t  strLength (const ustring& src) {
719     uiterator  b, e;
720     size_t  n = 0;
721     b = src.begin ();
722     e = src.end ();
723     while (b < e) {
724         n ++;
725         nextChar (b, e);
726     }
727     return n;
728 }
729
730 void  substring (const ustring& src, size_t idx, size_t len, int flen, ustring& ans) {
731     uiterator  b, e, t;
732     size_t  i;
733
734     b = src.begin ();
735     e = src.end ();
736     for (i = 0; i < idx && b < e; i ++)
737         nextChar (b, e);
738     if (flen) {
739         t = b;
740         for (i = 0; i < len && t < e; i ++)
741             nextChar (t, e);
742         ans.assign (b, t);
743     } else {
744         ans.assign (b, e);
745     }
746 }
747
748 static bool  jssafe[] = {
749     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,            // 0--15
750     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,            // 16--31
751     1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,            // 32--47
752     1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,            // 48--63
753     0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,            // 64--79
754     1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,            // 80--95
755     0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,            // 96--111
756     1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,            // 112--127
757 };
758
759 ustring  jsEncode (const ustring& str) {
760     int  i;
761     ustring  u, ans;
762     int  c, d;
763     char  b[8];
764
765     u = utf8to16 (str);
766     ans.reserve (u.size () * 3);
767     b[0] = '\\';
768     b[1] = 'u';
769     for (i = 0; i < u.size (); i += 2) {
770         c = u[i];
771         d = u[i + 1];
772         if (c == 0 && 0 < d && d < 127 && jssafe[d]) {
773             ans.append (1, d);
774         } else {
775             b[2] = hexchar ((c >> 4) & 0x0f);
776             b[3] = hexchar (c & 0x0f);
777             b[4] = hexchar ((d >> 4) & 0x0f);
778             b[5] = hexchar (d & 0x0f);
779             ans.append (b, 6);
780         }
781     }
782     return ans;
783 }
784
785 ustring  filenameEncode (const ustring& text) {
786     static uregex  re ("([\\x00-\\x1f\\x7f])|([^a-zA-Z0-9._-])|(^\\.+)");
787     SplitterRe  sp (text, re);
788     ustring  ans;
789     int  c;
790
791     if (text.length () == 0) {
792         throw (ustring (text).append (uErrorBadName));
793     }
794     ans.reserve (text.length () + 16);
795     while (sp.next ()) {
796         if (sp.begin () < sp.end ())
797             ans.append (sp.begin (), sp.end ());
798         if (sp.match (1)) {
799         } else if (sp.match (2)) {
800             c = *sp.matchBegin (2);
801             ans.append (1, ':');
802             ans.append (1, hexchar ((c >> 4) & 0x0f));
803             ans.append (1, hexchar (c & 0x0f));
804         } else if (sp.match (3)) {
805             for (c = sp.matchEnd (3) - sp.matchBegin (3); c > 0; c --) {
806                 ans.append (CharConst (":2e"));
807             }
808         }
809     }
810     if (ans.length () > 250)
811         ans.resize (250);
812     return ans;
813 }
814
815 ustring  filenameDecode (const ustring& text) {
816     static uregex  re (":([0-9a-fA-F][0-9a-fA-F])");
817     SplitterRe  sp (text, re);
818     ustring  ans;
819     int  c;
820
821     ans.reserve (text.length ());
822     while (sp.next ()) {
823         if (sp.begin () < sp.end ())
824             ans.append (sp.begin (), sp.end ());
825         if (sp.match (1)) {
826             c = hex (*(sp.matchBegin (1))) * 16 + hex (*(sp.matchBegin (1) + 1));
827             if (32 <= c && c < 256)
828                 ans.append (1, c);
829         }
830     }
831     return ans;
832 }
833
834 bool  matchSkip (uiterator& b, uiterator e, const char* t, size_t s) {
835     if (e - b >= s && memcmp (t, &b[0], s) == 0) {
836         b += s;
837         return true;
838     } else {
839         return false;
840     }
841 }
842
843 bool  matchHead (uiterator& b, uiterator e, const char* t, size_t s) {
844     if (e - b >= s && memcmp (t, &b[0], s) == 0) {
845         return true;
846     } else {
847         return false;
848     }
849 }
850
851 bool  matchHead (const ustring& str, const char* t, size_t s) {
852     if (str.length () >= s && memcmp (t, &*str.begin (), s) == 0) {
853         return true;
854     } else {
855         return false;
856     }
857 }
858
859 bool  matchHead (const ustring& str, const ustring& head) {
860     if (str.length () >= head.length () && memcmp (&*str.begin (), &*head.begin (), head.length ()) == 0) {
861         return true;
862     } else {
863         return false;
864     }
865 }
866
867 bool  match (uiterator b, uiterator e, const char* t, size_t s) {
868     if (e - b == s && memcmp (t, &b[0], s) == 0) {
869         return true;
870     } else {
871         return false;
872     }
873 }
874
875 bool  match (const ustring& str, const char* t, size_t s) {
876     if (str.length () == s && memcmp (t, str.data (), s) == 0) {
877         return true;
878     } else {
879         return false;
880     }
881 }
882
883 bool  match (uiterator b, uiterator e, const ustring& str) {
884     if (e - b == str.length () && memcmp (str.data (), &b[0], str.length ()) == 0) {
885         return true;
886     } else {
887         return false;
888     }
889 }
890
891 bool  match (const ustring& str, const char* t, size_t s, const char* t2, size_t s2) {
892     if (match (str, t, s) || match (str, t2, s2)) {
893         return true;
894     } else {
895         return false;
896     }
897 }
898
899 ustring  clipWhite (uiterator b, uiterator e) {
900     while (b < e)
901         if (isblank (*b)) {
902             b ++;
903         } else {
904             break;
905         }
906     while (b < e)
907         if (isblank (*(e - 1))) {
908             e --;
909         } else {
910             break;
911         }
912     return ustring (b, e);
913 }
914 ustring  clipWhite (const ustring& str) {
915     return clipWhite (str.begin (), str.end ());
916 }
917
918 ustring  getenvString (const char* key) {
919     char*  e = getenv (key);
920     if (e) {
921         return ustring (e);
922     } else {
923         return uEmpty;
924     }
925 }
926
927 ustring  zeroPad (int n, const ustring& src) {
928     int  m;
929
930     n = std::min (32, n);
931     m = n - src.length ();
932     if (m > 0) {
933         ustring  ans;
934         ans.reserve (m);
935         ans.append (m, '0');
936         ans.append (src);
937         return ans;
938     } else {
939         return src;
940     }
941 }
942
943 ustring  padEmpty (const ustring& name) {
944     if (name.empty ())
945         return ustring (CharConst ("(null)"));
946     else
947         return name;
948 }
949
950 uint32_t  hextoul (uiterator b, uiterator e) {
951     uint32_t  ans = 0;
952     int  n;
953
954     for (n = 0; n < 8 && b != e; n ++, b ++) {
955         ans = (ans << 4) + hex (*b);
956     }
957     return ans;
958 }
959
960 double  hextod (uiterator b, uiterator e, int base) {
961     double  ans = 0.0;
962     int  n;
963     int  c;
964
965     for (n = 0; b < e; n ++, b ++) {
966         c = shex (*b);
967         if (c < 0 || c >= base)
968             return ans;
969         ans = ans * 16. + c;
970     }
971     return ans;
972 }
973
974 ustring  dtohex (double e, int pad, int base, bool upcase) {
975     double  a, b;
976     int  r;
977     ustring  ans;
978     char  d[128];
979     int  pos;
980     const char*  digs;
981     static const char  xdigsLower[] = "0123456789abcdef";
982     static const char  xdigsUpper[] = "0123456789ABCDEF";
983
984     pos = 128;
985     b = base;
986     if (upcase)
987         digs = xdigsUpper;
988     else
989         digs = xdigsLower;
990     if (e >= 0) {
991         e = floor (e);
992         while (pos > 0 && e > 0) {
993             a = floor (e / b);
994             r = e - a * b;
995             e = a;
996             if (r < 0) {
997                 r = 0;
998             } else if (r >= base) {
999                 r = base - 1;
1000             }
1001             d[--pos] = digs[r];
1002         }
1003         if (pad > 0) {
1004             for (int i = 128 - pos; i < pad; i ++) {
1005                 d[--pos] = '0';
1006             }
1007         }
1008         ans.assign (d + pos, 128 - pos);
1009     } else {
1010     }
1011     return ans;
1012 }
1013
1014 ustring  toCRLF (const ustring& str) {
1015     uiterator  b = str.begin ();
1016     uiterator  e = str.end ();
1017     uiterator  p;
1018     ustring  ans;
1019
1020     p = b;
1021     while (findChar (b, e, '\n')) {
1022         ans.append (p, b).append (uCRLF);
1023         p = ++ b;
1024     }
1025     if (p < e)
1026         ans.append (p, e);
1027     return ans;
1028 }
1029
1030 void  skipChar (uiterator& b, uiterator e, int ch) {
1031     while (b < e && *b == ch)
1032         ++ b;
1033 }
1034
1035 void  skipNextToChar (uiterator& b, uiterator e, int ch) {
1036     while (b < e) {
1037         if (*(b ++) == ch)
1038             return;
1039     }
1040 }
1041
1042 static ustring::value_type  toLower_ustring_value (ustring::value_type v) {
1043     if ('A' <= v && v <= 'Z') {
1044         return v - 'A' + 'a';
1045     } else {
1046         return v;
1047     }
1048 }
1049
1050 ustring  toLower (uiterator b, uiterator e) {
1051     ustring::iterator  i;
1052     ustring  ans;
1053     ans.resize (e - b);
1054     i = ans.begin ();
1055     for (; b < e; b ++, i++) {
1056         *i = toLower_ustring_value (*b);
1057     }
1058     return ans;
1059 }
1060
1061 static ustring  colpad0 (int n, const ustring& src) {
1062     int  m;
1063
1064     if (n > 0) {
1065         n = std::min (32, n);
1066         m = n - src.length ();
1067         if (m > 0) {
1068             ustring  ans;
1069             ans.reserve (n);
1070             ans.append (m, '0');
1071             ans.append (src);
1072             return ans;
1073         } else if (m == 0) {
1074             return src;
1075         } else {
1076             return ustring (src.end () - n, src.end ());
1077         }
1078     } else {
1079         return src;
1080     }
1081 }
1082
1083 /*
1084  ${Y:4}, ${Y:2}
1085  ${M:2}, ${M}, ${M:name}, ${M:ab}
1086  ${D:2}, ${D}
1087  ${h:2}, ${h}
1088  ${m:2}, ${m}
1089  ${s:2}, ${s}
1090  ${W}, ${w}
1091  ${o}
1092 */
1093 ustring  formatDateString (const ustring& format, struct tm& v) {
1094     ustring  ans;
1095     uiterator  b, e;
1096     umatch  m;
1097     int  pc;
1098     static uregex  re ("\\$\\{(([YMDhmsWwo])(:([0-9]))?|M:((name)|(ab)|(abname)))\\}");
1099     std::vector<ustring>  fpar;
1100
1101     b = format.begin ();
1102     e = format.end ();
1103     while (usearch (b, e, m, re)) {
1104         ans.append (b, m[0].first);
1105         b = m[0].second;
1106         if (m[5].matched) {
1107             if (m[6].matched) { // name
1108                 ans.append (MStr[v.tm_mon]);
1109             } else if (m[7].matched || m[8].matched) { // abname
1110                 ans.append (MStr_a[v.tm_mon]);
1111             }
1112         } else {
1113             if (m[3].matched) {
1114                 pc = strtol (ustring (m[4].first, m[4].second));
1115             } else {
1116                 pc = 0;
1117             }
1118             switch (*m[2].first) {
1119             case 'Y':
1120                 ans.append (colpad0 (pc, to_ustring (v.tm_year + 1900)));
1121                 break;
1122             case 'M':
1123                 ans.append (colpad0 (pc, to_ustring (v.tm_mon + 1)));
1124                 break;
1125             case 'D':
1126                 ans.append (colpad0 (pc, to_ustring (v.tm_mday)));
1127                 break;
1128             case 'h':
1129                 ans.append (colpad0 (pc, to_ustring (v.tm_hour)));
1130                 break;
1131             case 'm':
1132                 ans.append (colpad0 (pc, to_ustring (v.tm_min)));
1133                 break;
1134             case 's':
1135                 ans.append (colpad0 (pc, to_ustring (v.tm_sec)));
1136                 break;
1137             case 'W':
1138                 ans.append (WStr [v.tm_wday]);
1139                 break;
1140             case 'w':
1141                 ans.append (WStr_a [v.tm_wday]);
1142                 break;
1143             case 'o':
1144                 {
1145                     int  h, m;
1146                     if (v.tm_gmtoff < 0) {
1147                         h = - v.tm_gmtoff / 60;
1148                         m = h % 60;
1149                         h = h / 60;
1150                         ans.append (CharConst ("-")).append (colpad0 (4, to_ustring (h * 100 + m)));
1151                     } else {
1152                         h = v.tm_gmtoff / 60;
1153                         m = h % 60;
1154                         h = h / 60;
1155                         ans.append (CharConst ("+")).append (colpad0 (4, to_ustring (h * 100 + m)));
1156                     }
1157                 }
1158                 break;
1159             }
1160         }
1161     }
1162     ans.append (b, e);
1163
1164     return ans;
1165 }
1166
1167 ustring  toLower (const ustring& str) {
1168     return boost::to_lower_copy (str);
1169 }
1170
1171 ustring  toUpper (const ustring& str) {
1172     return boost::to_upper_copy (str);
1173 }
1174
1175 ustring  hexEncode (const ustring& data) {
1176     ustring  ans;
1177     uiterator  b, e;
1178
1179     ans.reserve (data.length () * 2);
1180     b = data.begin ();
1181     e = data.end ();
1182     for (; b < e; b ++) {
1183         ans.append (1, hexchar ((*b >> 4) & 0x0f));
1184         ans.append (1, hexchar (*b & 0x0f));
1185     }
1186     return ans;
1187 }
1188
1189 ustring  hexDecode (const ustring& data) {
1190     ustring  ans;
1191     uiterator  b, e;
1192     int  c;
1193
1194     ans.reserve (data.length () / 2);
1195     b = data.begin ();
1196     e = data.end ();
1197     for (; b < e; b ++) {
1198         c = *b ++;
1199         if (b < e) {
1200             ans.append (1, hex (c, *b));
1201         }
1202     }
1203     return ans;
1204 }
1205
1206 int  octchar (uiterator b) {    // 3bytes
1207     int  ans = 0;
1208     ans = *b - '0';
1209     ++ b;
1210     ans = ans * 8 + *b - '0';
1211     ++ b;
1212     ans = ans * 8 + *b - '0';
1213     return ans;
1214 }
1215
1216 ustring  octchar (int c) {
1217     ustring  ans (3, 0);
1218     ans[2] = (c & 0x7) + '0';
1219     c >>= 3;
1220     ans[1] = (c & 0x7) + '0';
1221     c >>= 3;
1222     ans[0] = (c & 0x3) + '0';
1223     return ans;
1224 }
1225
1226 bool  findNL (uiterator& b, uiterator e, uiterator& u) {
1227     for (; b < e; ++ b) {
1228         if (*b == '\n') {
1229             u = b + 1;
1230             return true;
1231         } else if (*b == '\r') {
1232             u = b + 1;
1233             if (u < e && *u == '\n')
1234                 ++ u;
1235             return true;
1236         }
1237     }
1238     u = e;
1239     return false;
1240 }
1241
1242 bool  findNLb (uiterator& b, uiterator e) {
1243     for (; b < e; ++ b) {
1244         if (*b == '\n') {
1245             ++ b;
1246             return true;
1247         } else if (*b == '\r') {
1248             ++ b;
1249             if (b < e && *b == '\n')
1250                 ++ b;
1251             return true;
1252         }
1253     }
1254     return false;
1255 }
1256
1257 bool  findChar (uiterator& b, uiterator e, int ch) {
1258     for (; b < e; ++ b) {
1259         if (*b == ch) {
1260             return true;
1261         }
1262     }
1263     return false;
1264 }
1265
1266 bool  findChars (uiterator& b, uiterator e, const ustring& pattern) {
1267     for (; b < e; ++ b) {
1268         if (pattern.find (*b) != ustring::npos) {
1269             return true;
1270         }
1271     }
1272     return false;
1273 }
1274
1275 bool  findCharFn (uiterator& b, uiterator e, bool (*fn)(int)) {
1276     for (; b < e; ++ b) {
1277         if (fn (*b))
1278             return true;
1279     }
1280     return false;
1281 }
1282
1283 bool  findSepColon (uiterator& b, uiterator e, uiterator& u) {
1284     // " *; *"を探索する。bは進む
1285     uiterator  p = b;
1286     if (findChar (b, e, ';')) {
1287         u = b + 1;
1288         while (p < b && *(b - 1) == ' ')
1289             -- b;
1290         while (u < e && *u == ' ')
1291             ++ u;
1292         return true;
1293     }
1294     u = e;
1295     return false;
1296 }
1297
1298 bool  matchHeadFn (uiterator& b, uiterator e, bool (*fn)(int)) {
1299     if (b < e && fn (*b)) {
1300         do {
1301             ++ b;
1302         } while (b < e && fn (*b));
1303         return true;
1304     }
1305     return false;
1306 }
1307
1308 bool  matchWordTbl (uiterator b, uiterator e, char* tbl) {
1309     int  c;
1310     if (b < e) {
1311         do {
1312             c = *b;
1313             if (0 <= c && c < 128 && tbl[c]) {  // 128〜はfalse
1314             } else {
1315                 return false;
1316             }
1317             ++ b;
1318         } while (b < e);
1319         return true;
1320     } else {
1321         return false;
1322     }
1323 }
1324
1325 bool  matchWordFn (uiterator b, uiterator e, bool (*fn)(int)) {
1326     int  c;
1327     if (b < e) {
1328         do {
1329             c = *b;
1330             if (0 <= c && c < 128 && fn (c)) {
1331             } else {
1332                 return false;
1333             }
1334             ++ b;
1335         } while (b < e);
1336         return true;
1337     } else {
1338         return false;
1339     }
1340 }