2 #include "util_string.h"
3 #include "util_const.h"
4 #include "util_random.h"
5 #include "util_splitter.h"
9 #include <boost/regex.hpp>
10 #include <boost/regex/pattern_except.hpp>
11 #include <boost/algorithm/string.hpp>
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.")));
28 ustring UIConv::cv (const ustring& text, bool flush) {
31 if (cd != ICONV_ERR) {
32 char* buf = new char[4096];
35 size_t isize, osize, rsize;
37 ibuf = text.begin ().base ();
42 rsize = ::iconv (cd, (char**)&ibuf, &isize, &obuf, &osize);
44 if (errno == EILSEQ) {
47 ans.append (CharConst ("_"));
48 } else if (errno == EINVAL) {
49 } else if (errno == E2BIG) {
55 ans.append (buf, obuf - buf);
60 rsize = ::iconv (cd, NULL, NULL, &obuf, &osize);
62 ans.append (buf, obuf - buf);
69 ///////////////////////////////////////////////////////////////////////
70 static bool isDigit (int c) {
71 return '0' <= c && c <= '9';
74 ustring c3 (const ustring& str) {
80 if (str[0] == '-' || str[0] == '+') {
85 if (matchHeadFn (t, e, isDigit)) {
87 int l = str.size () + n / 3;
91 ans.append (1, str[0]);
95 if (n > 1 && n % 3 == 1) {
96 ans.append (CharConst (","));
100 for (; b != e; b ++) {
109 ustring to_ustring (int32_t v) {
110 return boost::lexical_cast<ustring> (v);
113 ustring to_ustring (uint32_t v) {
114 return boost::lexical_cast<ustring> (v);
117 ustring to_ustring (long int v) {
118 return boost::lexical_cast<ustring> (v);
121 ustring to_ustring (unsigned long int v) {
122 return boost::lexical_cast<ustring> (v);
125 ustring to_ustring (long long int v) {
126 return boost::lexical_cast<ustring> (v);
129 ustring to_ustring (unsigned long long int v) {
130 return boost::lexical_cast<ustring> (v);
133 ustring to_ustring (double val) {
135 return ustring (b, snprintf (b, 32, "%.*g", DBL_DIG, val));
138 int32_t to_int32 (const ustring& v) {
139 return boost::lexical_cast<int32_t> (v);
142 uint32_t to_uint32 (const ustring& v) {
143 return boost::lexical_cast<uint32_t> (v);
146 uint64_t to_uint64 (const ustring& v) {
147 return boost::lexical_cast<uint64_t> (v);
150 static int shex (char c) {
151 if ('0' <= c && c <= '9') {
153 } else if ('a' <= c && c <= 'f') {
154 return (c - 'a' + 10);
155 } else if ('A' <= c && c <= 'F') {
156 return (c - 'A' + 10);
162 static int hex (char c) {
163 if ('0' <= c && c <= '9') {
165 } else if ('a' <= c && c <= 'f') {
166 return (c - 'a' + 10);
167 } else if ('A' <= c && c <= 'F') {
168 return (c - 'A' + 10);
174 static int hex (char c1, char c2) {
175 return (hex (c1) * 16 + hex (c2));
178 static char hexchar (int c) {
179 if (0 <= c && c <= 9)
181 else if (10 <= c && c <= 15)
187 static char hexchar_c (int c) {
188 if (0 <= c && c <= 9)
190 else if (10 <= c && c <= 15)
196 static ustring percentHex (int c) {
197 ustring ans (3, '%');
199 ans[1] = hexchar ((c >> 4) & 0x0f);
200 ans[2] = hexchar (c & 0x0f);
204 ustring percentHEX (int c) {
205 ustring ans (3, '%');
207 ans[1] = hexchar_c ((c >> 4) & 0x0f);
208 ans[2] = hexchar_c (c & 0x0f);
212 ustring urldecode_nonul (const ustring& str) {
214 static uregex re ("(\\+)|%([0-9a-fA-F][0-9a-fA-F])|\\x00");
218 ans.reserve (str.size ());
221 while (usearch (b, e, m, re)) {
222 if (b != m[0].first) {
223 ans.append (b, m[0].first);
227 } else if (m[2].matched) {
228 int v = hex (*(m[2].first), *(m[2].first + 1));
242 static ustring omitPattern (const ustring& text, int (*fn)(int)) {
243 uiterator b = text.begin ();
244 uiterator e = text.end ();
246 for (; p < e; ++ p) {
254 ans.reserve (text.length ());
257 for (; p < e; ++ p) {
265 ustring omitCtrl (const ustring& str) {
266 return omitPattern (str, iscntrl);
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,
280 if (0 <= c && c < 128)
281 return table_ctrlx[c];
285 ustring omitCtrlX (const ustring& str) {
286 return omitPattern (str, iscntrlx);
289 static int isNUL (int c) {
293 ustring omitNul (const ustring& str) {
294 return omitPattern (str, isNUL);
297 static int iscrlfchar (int c) {
298 return c == 0x0a || c == 0x0d;
301 ustring omitNL (const ustring& str) {
302 return omitPattern (str, iscrlfchar);
305 static int isnonasciichar (int c) {
306 return c < 0x20 || c > 0x7e;
309 ustring omitNonAscii (const ustring& str) {
310 return omitPattern (str, isnonasciichar);
313 static int isnonasciiword (int c) {
314 return c < 0x21 || c > 0x7e;
317 ustring omitNonAsciiWord (const ustring& str) {
318 return omitPattern (str, isnonasciiword);
321 static ustring percentEncode (Splitter& sp) {
324 while (sp.nextSep ()) {
325 if (sp.preSize () > 0)
326 ans.append (sp.pre ());
327 c = *sp.matchBegin ();
329 ans.append (uUScore);
331 ans.append (percentHEX (c));
334 if (sp.preSize () > 0)
335 ans.append (sp.pre ());
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,
351 for (; b < e; ++ b) {
353 if (c < 0 || c >= 128 || table_percentchar[c]) {
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);
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,
380 for (; b < e; ++ b) {
382 if (c < 0 || c >= 128 || table_percentpathchar[c]) {
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);
397 ustring percentDecode (const ustring& str) {
399 static uregex re ("%([0-9a-fA-F][0-9a-fA-F])|\\x00");
405 while (usearch (b, e, m, re)) {
406 if (b != m[0].first) {
407 ans.append (b, m[0].first);
410 int v = hex (*(m[1].first), *(m[1].first + 1));
421 return fixUTF8 (ans);
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,
436 for (; b < e; ++ b) {
438 if (c < 0 || c >= 128 || table_cookieencode[c]) {
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);
453 ustring cookiedecode (const ustring& text) {
458 static uregex re ("%([0-9a-fA-F])([0-9a-fA-F])");
462 while (usearch (b, e, m, re)) {
464 ans.append (ustring (b, m[0].first));
465 a = hex (*m[1].first, *m[2].first);
470 ans.append (ustring (b, e));
475 ustring clipColon (const ustring& text) {
479 for (i = 0; i < ans.size (); i ++) {
486 ustring dirPart (const ustring& path) {
487 ustring::size_type s = path.rfind ('/', path.size ());
489 if (s == ustring::npos) {
493 return ustring (path.begin (), path.begin () + s);
497 ustring filePart_osSafe (const ustring& path) {
499 static uregex re ("[^\\\\/]+$");
501 if (usearch (path, m, re)) {
502 return ustring (m[0].first, m[0].second);
508 void split (uiterator b, uiterator e, uregex& re, std::vector<ustring>& ans) {
509 SplitterRe sp (b, e, re);
512 ans.push_back (sp.pre ());
516 void split (uiterator b, uiterator e, int ch, std::vector<ustring>& ans) {
517 SplitterCh sp (b, e, ch);
520 ans.push_back (sp.pre ());
524 void splitE (uiterator b, uiterator e, uregex& re, std::vector<ustring>& ans) {
525 SplitterRe sp (b, e, re);
528 while (sp.nextSep ()) {
529 ans.push_back (sp.pre ());
531 ans.push_back (sp.pre ());
535 void splitE (uiterator b, uiterator e, int ch, std::vector<ustring>& ans) {
536 SplitterCh sp (b, e, ch);
539 while (sp.nextSep ()) {
540 ans.push_back (sp.pre ());
542 ans.push_back (sp.pre ());
546 bool splitChar (uiterator b, uiterator e, uiterator::value_type ch, uiterator& m1) {
547 for (; b < e; b ++) {
557 ustring escape_re (const ustring& text) {
558 ustring::const_iterator b, e;
563 static uregex re ("[^\\x01- !\"#%',/0-9:;<=>@A-Z_`a-z~\\x7f-\\xff-]");
567 ans.reserve (text.size () + 16);
570 while (b != e && usearch (b, e, m, re)) {
572 ans.append (b, m[0].first);
574 buf[2] = hexchar ((c >> 4) & 0x0f);
575 buf[3] = hexchar (c & 0x0f);
584 ustring slashEncode (const ustring& text) {
585 ustring::const_iterator b, e;
590 static uregex re ("([\\x00-\\x1f\\x7f])|(\\\\)|(\")");
596 while (b != e && usearch (b, e, m, re)) {
598 ans.append (b, m[0].first);
603 ans.append (CharConst ("\\t"));
606 ans.append (CharConst ("\\r"));
609 ans.append (CharConst ("\\n"));
612 buf[2] = hexchar ((c >> 4) & 0x0f);
613 buf[3] = hexchar (c & 0x0f);
616 } else if (m[2].matched) {
617 ans.append (CharConst ("\\\\"));
618 } else if (m[3].matched) {
619 ans.append (CharConst ("\\\""));
630 ustring slashDecode (const ustring& text) {
631 ustring::const_iterator b, e;
635 static uregex re ("\\\\([0-7][0-7][0-7]|[\\x00-\\x7f])");
639 while (b != e && usearch (b, e, m, re)) {
641 ans.append (b, m[0].first);
646 ans.append (CharConst ("\t"));
649 ans.append (CharConst ("\r"));
652 ans.append (CharConst ("\n"));
655 if (m[0].second - m[0].first == 4) {
661 if (0 < c && c < 0x20)
674 unsigned long strtoul (const ustring& str) {
675 return strtoul (str.c_str (), NULL, 10);
678 unsigned long strtoul (const uiterator& b) {
679 return strtoul (&*b, NULL, 10);
682 long strtol (const ustring& str) {
683 return strtol (str.c_str (), NULL, 10);
686 double strtod (const ustring& str) {
687 return strtod (str.c_str (), NULL);
690 bool passMatch (const ustring& pass, const ustring& cpass) {
691 if (pass.length () == 0 || cpass.length () == 0)
693 return (strcmp (crypt (pass.c_str (), cpass.c_str ()), cpass.c_str ()) == 0);
696 ustring passCrypt (const ustring& pass, passCryptFormat format) {
697 // XXX not thread safe.
701 salt = makeSalt ('1', 8);
704 // salt = makeSalt ('2', 16);
707 salt = makeSalt ('5', 16);
710 salt = makeSalt ('6', 16);
715 return ustring (crypt (pass.c_str (), salt.c_str ()));
718 size_t strLength (const ustring& src) {
730 void substring (const ustring& src, size_t idx, size_t len, int flen, ustring& ans) {
736 for (i = 0; i < idx && b < e; i ++)
740 for (i = 0; i < len && t < e; i ++)
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
759 ustring jsEncode (const ustring& str) {
766 ans.reserve (u.size () * 3);
769 for (i = 0; i < u.size (); i += 2) {
772 if (c == 0 && 0 < d && d < 127 && jssafe[d]) {
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);
785 ustring filenameEncode (const ustring& text) {
786 static uregex re ("([\\x00-\\x1f\\x7f])|([^a-zA-Z0-9._-])|(^\\.+)");
787 SplitterRe sp (text, re);
791 if (text.length () == 0) {
792 throw (ustring (text).append (uErrorBadName));
794 ans.reserve (text.length () + 16);
796 if (sp.begin () < sp.end ())
797 ans.append (sp.begin (), sp.end ());
799 } else if (sp.match (2)) {
800 c = *sp.matchBegin (2);
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"));
810 if (ans.length () > 250)
815 ustring filenameDecode (const ustring& text) {
816 static uregex re (":([0-9a-fA-F][0-9a-fA-F])");
817 SplitterRe sp (text, re);
821 ans.reserve (text.length ());
823 if (sp.begin () < sp.end ())
824 ans.append (sp.begin (), sp.end ());
826 c = hex (*(sp.matchBegin (1))) * 16 + hex (*(sp.matchBegin (1) + 1));
827 if (32 <= c && c < 256)
834 bool matchSkip (uiterator& b, uiterator e, const char* t, size_t s) {
835 if (e - b >= s && memcmp (t, &b[0], s) == 0) {
843 bool matchHead (uiterator& b, uiterator e, const char* t, size_t s) {
844 if (e - b >= s && memcmp (t, &b[0], s) == 0) {
851 bool matchHead (const ustring& str, const char* t, size_t s) {
852 if (str.length () >= s && memcmp (t, &*str.begin (), s) == 0) {
859 bool matchHead (const ustring& str, const ustring& head) {
860 if (str.length () >= head.length () && memcmp (&*str.begin (), &*head.begin (), head.length ()) == 0) {
867 bool match (uiterator b, uiterator e, const char* t, size_t s) {
868 if (e - b == s && memcmp (t, &b[0], s) == 0) {
875 bool match (const ustring& str, const char* t, size_t s) {
876 if (str.length () == s && memcmp (t, str.data (), s) == 0) {
883 bool match (uiterator b, uiterator e, const ustring& str) {
884 if (e - b == str.length () && memcmp (str.data (), &b[0], str.length ()) == 0) {
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)) {
899 ustring clipWhite (uiterator b, uiterator e) {
907 if (isblank (*(e - 1))) {
912 return ustring (b, e);
914 ustring clipWhite (const ustring& str) {
915 return clipWhite (str.begin (), str.end ());
918 ustring getenvString (const char* key) {
919 char* e = getenv (key);
927 ustring zeroPad (int n, const ustring& src) {
930 n = std::min (32, n);
931 m = n - src.length ();
943 ustring padEmpty (const ustring& name) {
945 return ustring (CharConst ("(null)"));
950 uint32_t hextoul (uiterator b, uiterator e) {
954 for (n = 0; n < 8 && b != e; n ++, b ++) {
955 ans = (ans << 4) + hex (*b);
960 double hextod (uiterator b, uiterator e, int base) {
965 for (n = 0; b < e; n ++, b ++) {
967 if (c < 0 || c >= base)
974 ustring dtohex (double e, int pad, int base, bool upcase) {
981 static const char xdigsLower[] = "0123456789abcdef";
982 static const char xdigsUpper[] = "0123456789ABCDEF";
992 while (pos > 0 && e > 0) {
998 } else if (r >= base) {
1004 for (int i = 128 - pos; i < pad; i ++) {
1008 ans.assign (d + pos, 128 - pos);
1014 ustring toCRLF (const ustring& str) {
1015 uiterator b = str.begin ();
1016 uiterator e = str.end ();
1021 while (findChar (b, e, '\n')) {
1022 ans.append (p, b).append (uCRLF);
1030 void skipChar (uiterator& b, uiterator e, int ch) {
1031 while (b < e && *b == ch)
1035 void skipNextToChar (uiterator& b, uiterator e, int ch) {
1042 static ustring::value_type toLower_ustring_value (ustring::value_type v) {
1043 if ('A' <= v && v <= 'Z') {
1044 return v - 'A' + 'a';
1050 ustring toLower (uiterator b, uiterator e) {
1051 ustring::iterator i;
1055 for (; b < e; b ++, i++) {
1056 *i = toLower_ustring_value (*b);
1061 static ustring colpad0 (int n, const ustring& src) {
1065 n = std::min (32, n);
1066 m = n - src.length ();
1070 ans.append (m, '0');
1073 } else if (m == 0) {
1076 return ustring (src.end () - n, src.end ());
1085 ${M:2}, ${M}, ${M:name}, ${M:ab}
1093 ustring formatDateString (const ustring& format, struct tm& v) {
1098 static uregex re ("\\$\\{(([YMDhmsWwo])(:([0-9]))?|M:((name)|(ab)|(abname)))\\}");
1099 std::vector<ustring> fpar;
1101 b = format.begin ();
1103 while (usearch (b, e, m, re)) {
1104 ans.append (b, m[0].first);
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]);
1114 pc = strtol (ustring (m[4].first, m[4].second));
1118 switch (*m[2].first) {
1120 ans.append (colpad0 (pc, to_ustring (v.tm_year + 1900)));
1123 ans.append (colpad0 (pc, to_ustring (v.tm_mon + 1)));
1126 ans.append (colpad0 (pc, to_ustring (v.tm_mday)));
1129 ans.append (colpad0 (pc, to_ustring (v.tm_hour)));
1132 ans.append (colpad0 (pc, to_ustring (v.tm_min)));
1135 ans.append (colpad0 (pc, to_ustring (v.tm_sec)));
1138 ans.append (WStr [v.tm_wday]);
1141 ans.append (WStr_a [v.tm_wday]);
1146 if (v.tm_gmtoff < 0) {
1147 h = - v.tm_gmtoff / 60;
1150 ans.append (CharConst ("-")).append (colpad0 (4, to_ustring (h * 100 + m)));
1152 h = v.tm_gmtoff / 60;
1155 ans.append (CharConst ("+")).append (colpad0 (4, to_ustring (h * 100 + m)));
1167 ustring toLower (const ustring& str) {
1168 return boost::to_lower_copy (str);
1171 ustring toUpper (const ustring& str) {
1172 return boost::to_upper_copy (str);
1175 ustring hexEncode (const ustring& data) {
1179 ans.reserve (data.length () * 2);
1182 for (; b < e; b ++) {
1183 ans.append (1, hexchar ((*b >> 4) & 0x0f));
1184 ans.append (1, hexchar (*b & 0x0f));
1189 ustring hexDecode (const ustring& data) {
1194 ans.reserve (data.length () / 2);
1197 for (; b < e; b ++) {
1200 ans.append (1, hex (c, *b));
1206 int octchar (uiterator b) { // 3bytes
1210 ans = ans * 8 + *b - '0';
1212 ans = ans * 8 + *b - '0';
1216 ustring octchar (int c) {
1218 ans[2] = (c & 0x7) + '0';
1220 ans[1] = (c & 0x7) + '0';
1222 ans[0] = (c & 0x3) + '0';
1226 bool findNL (uiterator& b, uiterator e, uiterator& u) {
1227 for (; b < e; ++ b) {
1231 } else if (*b == '\r') {
1233 if (u < e && *u == '\n')
1242 bool findNLb (uiterator& b, uiterator e) {
1243 for (; b < e; ++ b) {
1247 } else if (*b == '\r') {
1249 if (b < e && *b == '\n')
1257 bool findChar (uiterator& b, uiterator e, int ch) {
1258 for (; b < e; ++ b) {
1266 bool findChars (uiterator& b, uiterator e, const ustring& pattern) {
1267 for (; b < e; ++ b) {
1268 if (pattern.find (*b) != ustring::npos) {
1275 bool findCharFn (uiterator& b, uiterator e, bool (*fn)(int)) {
1276 for (; b < e; ++ b) {
1283 bool findSepColon (uiterator& b, uiterator e, uiterator& u) {
1284 // " *; *"を探索する。bは進む
1286 if (findChar (b, e, ';')) {
1288 while (p < b && *(b - 1) == ' ')
1290 while (u < e && *u == ' ')
1298 bool matchHeadFn (uiterator& b, uiterator e, bool (*fn)(int)) {
1299 if (b < e && fn (*b)) {
1302 } while (b < e && fn (*b));
1308 bool matchWordTbl (uiterator b, uiterator e, char* tbl) {
1313 if (0 <= c && c < 128 && tbl[c]) { // 128〜はfalse
1325 bool matchWordFn (uiterator b, uiterator e, bool (*fn)(int)) {
1330 if (0 <= c && c < 128 && fn (c)) {