OSDN Git Service

hex-to-dec function.
[hmh/hhml.git] / modules / ml-string.cc
index 359d8a7..b06d6f2 100644 (file)
@@ -1,5 +1,6 @@
 #include "ml-string.h"
 #include "ml.h"
+#include "ml-texp.h"
 #include "mlenv.h"
 #include "motorenv.h"
 #include "motoroutput.h"
 
 */
 /*DOC:
+===eq===
+ (eq STRING STRING...) -> 1 or NIL
+ (string-eq STRING STRING...) -> 1 or NIL
+
+全てのSTRINGが同じ時、1を返す。
+
+*/
+//#AFUNC       eq      ml_string_eq
+//#AFUNC       string-eq       ml_string_eq
+//#WIKIFUNC    eq
+//#WIKIFUNC    string-eq
+MNode*  ml_string_eq (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    ustring  v1, v2;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+
+    v1 = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    while (arg) {
+       v2 = eval_str (arg->car (), mlenv);
+       if (v1 == v2) {
+       } else {
+           return newMNode_bool (false);
+       }
+       nextNode (arg);
+    }
+    return newMNode_bool (true);
+}
+
+/*DOC:
+===ne===
+ (ne STRING STRING) -> 1 or NIL
+ (string-ne STRING STRING) -> 1 or NIL
+
+STRINGが異なる時、1を返す。
+
+*/
+//#AFUNC       ne      ml_string_ne
+//#AFUNC       string-ne       ml_string_ne
+//#WIKIFUNC    ne
+//#WIKIFUNC    string-ne
+MNode*  ml_string_ne (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    ustring  v1, v2;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+
+    v1 = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    if (! arg)
+       throw (uErrorWrongNumber);
+    v2 = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    return newMNode_bool (v1 != v2);
+}
+
+//#AFUNC       lt      ml_string_lt
+//#AFUNC       string-lt       ml_string_lt
+//#WIKIFUNC    lt
+//#WIKIFUNC    string-lt
+MNode*  ml_string_lt (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    ustring  v1, v2;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+    v1 = eval_str (arg->car (), mlenv);
+    nextNodeNonNil (arg);
+    v2 = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    return newMNode_bool (v1 < v2);
+}
+
+//#AFUNC       le      ml_string_le
+//#AFUNC       string-le       ml_string_le
+//#WIKIFUNC    le
+//#WIKIFUNC    string-le
+MNode*  ml_string_le (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    ustring  v1, v2;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+    v1 = eval_str (arg->car (), mlenv);
+    nextNodeNonNil (arg);
+    v2 = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    return newMNode_bool (v1 <= v2);
+}
+
+//#AFUNC       gt      ml_string_gt
+//#AFUNC       string-gt       ml_string_gt
+//#WIKIFUNC    gt
+//#WIKIFUNC    string-gt
+MNode*  ml_string_gt (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    ustring  v1, v2;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+    v1 = eval_str (arg->car (), mlenv);
+    nextNodeNonNil (arg);
+    v2 = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    return newMNode_bool (v1 > v2);
+}
+
+//#AFUNC       ge      ml_string_ge
+//#AFUNC       string-ge       ml_string_ge
+//#WIKIFUNC    ge
+//#WIKIFUNC    string-ge
+MNode*  ml_string_ge (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    ustring  v1, v2;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+    v1 = eval_str (arg->car (), mlenv);
+    nextNodeNonNil (arg);
+    v2 = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    return newMNode_bool (v1 >= v2);
+}
+
+/*DOC:
+===emptyp===
+ (emptyp TEXT...) -> 1 or NIL
+
+文字列TEXTの長さが0の時、1を返す。
+
+*/
+//#AFUNC       emptyp  ml_emptyp
+//#WIKIFUNC    emptyp
+MNode*  ml_emptyp (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    ustring  u;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+
+    while (arg) {
+       u = eval_str (arg->car (), mlenv);
+       nextNode (arg);
+       if (u.size () > 0)
+           return newMNode_bool (false);
+    }
+    return newMNode_bool (true);
+}
+
+/*DOC:
+===not-emptyp===
+ (not-emptyp TEXT...) -> 1 or NIL
+
+文字列TEXTの長さが0でない時、1を返す。
+
+*/
+//#AFUNC       not-emptyp      ml_not_emptyp
+//#WIKIFUNC    not-emptyp
+MNode*  ml_not_emptyp (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    ustring  u;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+
+    while (arg) {
+       u = eval_str (arg->car (), mlenv);
+       nextNode (arg);
+       if (u.size () == 0)
+           return newMNode_bool (false);
+    }
+    return newMNode_bool (true);
+}
+
+/*DOC:
 ===concat===
  (concat STRING...) -> STRING
-パラメータの文字列を連結して一つの文字列を返す。
+パラメータの文字列STRINGを連結して一つの文字列を返す。
 
 */
 //#AFUNC       concat  ml_concat
@@ -47,6 +241,8 @@ MNode*  ml_concat (MNode* cell, MlEnv* mlenv) {
 ===megabyte===
  (megabyte NUMBER) -> STRING
 
+数値NUMBERをK、M、G、T、P単位(1024の倍数)の文字列に変換する。
+
 */
 //#AFUNC       megabyte        ml_megabyte
 //#WIKIFUNC    megabyte
@@ -101,6 +297,8 @@ MNode*  ml_megabyte (MNode* cell, MlEnv* mlenv) {
 ===c3===
  (c3 INTEGER) -> STRING
 
+数値INTEGERを3桁ごとにカンマ区切りの文字列に変換する。
+
 */
 //#AFUNC       c3      ml_c3
 //#WIKIFUNC    c3
@@ -145,7 +343,7 @@ MNode*  ml_regexp_match (MNode* cell, MlEnv* mlenv) {
     if (keywords[0] && eval_bool (keywords[0], mlenv))
        f |= boost::regex_constants::icase;
 
-    ans = wsearch_env (mlenv, text, reg, f);
+    ans = wsearch_env (mlenv->regenv, text, reg, f);
 
     return newMNode_bool (ans);
 }
@@ -169,8 +367,8 @@ MNode*  ml_match_string (MNode* cell, MlEnv* mlenv) {
     if (arg)
        throw (uErrorWrongNumber);
 
-    if (0 <= n && n < mlenv->regmatch.size ()) {
-       ans = newMNode_str (new ustring (wtou (std::wstring (mlenv->regmatch[n].first, mlenv->regmatch[n].second))));
+    if (0 <= n && n < mlenv->regenv.regmatch.size ()) {
+       ans = newMNode_str (new ustring (wtou (std::wstring (mlenv->regenv.regmatch[n].first, mlenv->regenv.regmatch[n].second))));
     }
 
     return ans;
@@ -186,12 +384,12 @@ MNode*  ml_match_string (MNode* cell, MlEnv* mlenv) {
 MNode*  ml_prematch (MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
     MNode*  ans = NULL;
-    std::wstring::const_iterator  b = mlenv->regtext.begin ();
+    std::wstring::const_iterator  b = mlenv->regenv.regtext.begin ();
 
     if (arg)
        throw (uErrorWrongNumber);
 
-    ans = newMNode_str (new ustring (wtou (std::wstring (b, mlenv->regmatch[0].first))));
+    ans = newMNode_str (new ustring (wtou (std::wstring (b, mlenv->regenv.regmatch[0].first))));
 
     return ans;
 }
@@ -206,12 +404,12 @@ MNode*  ml_prematch (MNode* cell, MlEnv* mlenv) {
 MNode*  ml_postmatch (MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
     MNode*  ans = NULL;
-    std::wstring::const_iterator  e = mlenv->regtext.end ();
+    std::wstring::const_iterator  e = mlenv->regenv.regtext.end ();
 
     if (arg)
        throw (uErrorWrongNumber);
 
-    ans = newMNode_str (new ustring (wtou (std::wstring (mlenv->regmatch[0].second, e))));
+    ans = newMNode_str (new ustring (wtou (std::wstring (mlenv->regenv.regmatch[0].second, e))));
 
     return ans;
 }
@@ -244,13 +442,16 @@ MNode*  ml_string_filter (MNode* cell, MlEnv* mlenv) {
     if (keywords[0] && eval_bool (keywords[0], mlenv))
        f |= boost::regex_constants::icase;
     if (evkw (1, t)) {
-       max = to_int (t ());
-       if (max < 0)
+       int  num = to_int (t ());
+       if (num < 0) {
            max = 0;
+       } else {
+           max = num;
+       }
     }
 
-    if (wsearch_env (mlenv, text, reg, f)) {
-       ustring  ans = wtou (std::wstring (mlenv->regmatch[0].first, mlenv->regmatch[0].second));
+    if (wsearch_env (mlenv->regenv, text, reg, f)) {
+       ustring  ans = wtou (std::wstring (mlenv->regenv.regmatch[0].first, mlenv->regenv.regmatch[0].second));
        if (max > 0) {
            substring (ans, 0, max, true, ans);
        }
@@ -329,11 +530,11 @@ MNode*  ml_regexp_split (MNode* cell, MlEnv* mlenv) {
     if (keywords[0] && eval_bool (keywords[0], mlenv))
        f |= boost::regex_constants::icase;
 
-    if (wsearch_env (mlenv, text, reg, f)) {
-       std::wstring::const_iterator  b = mlenv->regtext.begin ();
-       std::wstring::const_iterator  e = mlenv->regtext.end ();
-       ans.append (newMNode_str (new ustring (wtou (std::wstring (b, mlenv->regmatch[0].first)))));
-       ans.append (newMNode_str (new ustring (wtou (std::wstring (mlenv->regmatch[0].second, e)))));
+    if (wsearch_env (mlenv->regenv, text, reg, f)) {
+       std::wstring::const_iterator  b = mlenv->regenv.regtext.begin ();
+       std::wstring::const_iterator  e = mlenv->regenv.regtext.end ();
+       ans.append (newMNode_str (new ustring (wtou (std::wstring (b, mlenv->regenv.regmatch[0].first)))));
+       ans.append (newMNode_str (new ustring (wtou (std::wstring (mlenv->regenv.regmatch[0].second, e)))));
     } else {
        ans.append (newMNode_str (new ustring (text)));
        ans.append (NULL);
@@ -344,7 +545,8 @@ MNode*  ml_regexp_split (MNode* cell, MlEnv* mlenv) {
 
 /*DOC:
 ===split===
- (split REGEX STRING) -> STRING_LIST
+ (split REGEX STRING [#keep] [#i]) -> STRING_LIST
+ (split REGEX STRING #vector [#keep] [#i]) -> STRING_VECTOR
 
 */
 //#AFUNC       split   ml_split
@@ -352,42 +554,73 @@ MNode*  ml_regexp_split (MNode* cell, MlEnv* mlenv) {
 MNode*  ml_split (MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
     ustring  reg;
-    ustring  t;
-    MNodeList  ans;
-
-    if (! arg)
-       throw (uErrorWrongNumber);
-
-    reg = eval_str (arg->car (), mlenv);
-    nextNodeNonNil (arg);
-    t = eval_str (arg->car (), mlenv);
-    nextNode (arg);
-
-    if (arg)
-       throw (uErrorWrongNumber);
-
-    try {
-       std::wstring  wt = utow (t);
-       std::wstring  wreg = utow (reg);
-       boost::wregex  wre (wreg);
-       WSplitter  sp (wt, wre);
-       size_t  m = wt.length () + 1;
+    ustring  text;
+    bool  flagKeep = false;
+    bool  flagVector = false;
+    ListMakerPtr  ans;
+    std::vector<MNode*>  params;
+    std::vector<MNode*>  keywords;
+    static paramList  kwlist[] = {
+       {CharConst ("keep"), true}, // 空フィールドの削除をしない
+       {CharConst ("vector"), true},
+//     {CharConst ("i"), true},
+       {NULL, 0, 0}
+    };
 
-       while (sp.next ()) {
-           ans.append (newMNode_str (new ustring (sp.cur ())));
-           m --;
-           if (m == 0)
-               throw (uErrorRegexp);
+    setParams (arg, 2, &params, kwlist, &keywords, NULL);
+    reg = eval_str (params[0], mlenv);
+    text = eval_str (params[1], mlenv);
+    if (keywords[0] && eval_bool (keywords[0], mlenv))
+       flagKeep = true;
+    if (keywords[1] && eval_bool (keywords[1], mlenv))
+       flagVector = true;
+//    if (keywords[1] && eval_bool (keywords[1], mlenv))
+//     flagReg |= boost::regex_constants::icase;
+    if (flagVector)
+       ans = new ListMakerVector;
+    else
+       ans = new ListMakerList;
+
+    if (reg.length () == 0) {
+       uiterator  b = text.begin ();
+       uiterator  e = text.end ();
+       uiterator  s;
+       while (b < e) {
+           s = b;
+           nextChar (b, e);
+           ans.append (newMNode_str (new ustring (s, b)));
+       }
+    } else {
+       try {
+           std::wstring  wt = utow (text);
+           std::wstring  wreg = utow (reg);
+           boost::wregex  wre (wreg);
+           WSplitter  sp (wt, wre);
+           size_t  m = wt.length () + 1;
+           
+           bool  (WSplitter::*nfn)();
+           if (flagKeep)
+               nfn = &WSplitter::nextSep;
+           else
+               nfn = &WSplitter::next;
+           while ((sp.*nfn) ()) {
+               ans.append (newMNode_str (new ustring (sp.cur ())));
+               m --;
+               if (m == 0)
+                   throw (uErrorRegexp);
+           }
+           if (flagKeep)
+               ans.append (newMNode_str (new ustring (sp.cur ())));
+       } catch (boost::regex_error& err) {
+           throw (uErrorRegexp);
        }
-    } catch (boost::regex_error& err) {
-       throw (uErrorRegexp);
     }
     return ans.release ();
 }
 
 /*DOC:
 ===string-join===
- (string-join TEXT [STRING | ARRAY | LIST]...) -> STRING
+ (string-join TEXT [STRING | ARRAY | LIST | VECTOR]...) -> STRING
 
 */
 //#AFUNC       string-join     ml_string_join
@@ -436,6 +669,16 @@ MNode*  ml_string_join (MNode* cell, MlEnv* mlenv) {
                    if (! isNil (a->car ()))
                        ans.append (a->car ()->to_string ());
                }
+           } else if (val ()->isVector ()) {
+               size_t  n = val ()->vectorSize ();
+               size_t  i;
+               for (i = 0; i < n; ++ i) {
+                   if (i > 0)
+                       ans.append (sep);
+                   MNode*  a = val ()->vectorGet (i);
+                   if (! isNil (a))
+                       ans.append (a->to_string ());
+               }
            } else {
                var = val ()->to_string ();
                if (c == 0)
@@ -475,7 +718,9 @@ MNode*  ml_password_match (MNode* cell, MlEnv* mlenv) {
 
 /*DOC:
 ===password-crypt===
- (password-crypt PASSWORD) -> STRING
+ (password-crypt PASSWORD [#md5 | #sha256 | #sha512]) -> STRING
+
+deprecated.
 
 */
 //#AFUNC       password-crypt  ml_password_crypt
@@ -483,15 +728,30 @@ MNode*  ml_password_match (MNode* cell, MlEnv* mlenv) {
 MNode*  ml_password_crypt (MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
     ustring  pass;
+    passCryptFormat  format;
+    std::vector<MNode*>  params;
+    std::vector<MNode*>  keywords;
+    static paramList  kwlist[] = {
+       {CharConst ("md5"), true},
+       {CharConst ("sha256"), true},
+       {CharConst ("sha512"), true},
+//     {CharConst ("bf"), true},
+       {NULL, 0, 0}
+    };
 
-    if (! arg)
-       throw (uErrorWrongNumber);
-    pass = eval_str (arg->car (), mlenv);
-    nextNode (arg);
-    if (arg)
-       throw (uErrorWrongNumber);
+    format = FORMAT_MD5;
+    setParams (arg, 1, &params, kwlist, &keywords, NULL);
+    pass = eval_str (params[0], mlenv);
+    if (keywords[0] && eval_bool (keywords[0], mlenv))
+       format = FORMAT_MD5;
+    if (keywords[1] && eval_bool (keywords[1], mlenv))
+       format = FORMAT_SHA256;
+    if (keywords[2] && eval_bool (keywords[2], mlenv))
+       format = FORMAT_SHA512;
+//    if (keywords[3] && eval_bool (keywords[3], mlenv))
+//     format = FORMAT_BF;
 
-    return newMNode_str (new ustring (passCrypt (pass)));
+    return newMNode_str (new ustring (passCrypt (pass, format)));
 }
 
 /*DOC:
@@ -499,6 +759,8 @@ MNode*  ml_password_crypt (MNode* cell, MlEnv* mlenv) {
  (substring STR INDEX LENGTH) -> STRING
  (substring STR INDEX) -> STRING
 
+INDEX number of the first character of STR is 0.
+
 */
 //#AFUNC       substring       ml_substring
 //#WIKIFUNC    substring
@@ -531,6 +793,48 @@ MNode*  ml_substring (MNode* cell, MlEnv* mlenv) {
 }
     
 /*DOC:
+===tail-substring===
+ (tail-substring STR INDEX LENGTH) -> STRING
+ (tail-substring STR INDEX) -> STRING
+
+INDEX number of the last character of STR is 0.
+
+*/
+//#AFUNC       tail-substring  ml_tail_substring
+//#WIKIFUNC    tail-substring
+MNode*  ml_tail_substring (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    ustring  str;
+    size_t  index;
+    size_t  length;
+    int  mode;
+    ustring  ans;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+    str = eval_str (arg->car (), mlenv);
+    nextNodeNonNil (arg);
+    index = eval_int (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg) {
+       mode = 3;
+       length = eval_int (arg->car (), mlenv);
+       nextNode (arg);
+    } else {
+       mode = 2;
+    }
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    size_t  s = strLength (str);
+    if (mode == 3)
+       substring (str, s - index - 1, length, 1, ans);
+    else
+       substring (str, s - index - 1, 0, 0, ans);
+    return newMNode_str (new ustring (ans));
+}
+    
+/*DOC:
 ===length===
  (length STRING) -> NUMBER
 
@@ -554,6 +858,29 @@ MNode*  ml_length (MNode* cell, MlEnv* mlenv) {
 }
 
 /*DOC:
+===byte-length===
+ (byte-length STRING) -> NUMBER
+
+*/
+//#AFUNC       byte-length     ml_byte_length
+//#WIKIFUNC    byte-length
+MNode*  ml_byte_length (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    ustring  str;
+    size_t  ans;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+    str = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    ans = str.length ();
+    return newMNode_num (ans);
+}
+
+/*DOC:
 ===pad0===
  (pad0 NUMBER STRING) -> STRING
  (pad0 NUMBER STRING_LIST) -> STRING_LIST
@@ -786,24 +1113,55 @@ MNode*  ml_to_string (MNode* cell, MlEnv* mlenv) {
 }
 
 /*DOC:
-===dump-to-sexp===
+===to-symbol===
+ (to-symbol STRING) -> SYMBOL
+
+*/
+//#AFUNC       to-symbol       ml_to_symbol
+//#WIKIFUNC    to-symbol
+MNode*  ml_to_symbol (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    MNodePtr  text;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+    text = eval (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    if (text ()) {
+       if (text ()->isSym ()) {
+           return text.release ();
+       } else {
+           return newMNode_sym (new ustring (text ()->to_string ()));
+       }
+    } else {
+       return NULL;
+    }
+}
+
+/*DOC:
+===dump-to-texp, dump-to-sexp===
+ (dump-to-texp OBJECT...) -> STRING
  (dump-to-sexp OBJECT...) -> STRING
 
 */
-//#AFUNC       dump-to-sexp    ml_dump_to_sexp
+//#AFUNC       dump-to-texp    ml_dump_to_texp
+//#AFUNC       dump-to-sexp    ml_dump_to_texp
+//#WIKIFUNC    dump-to-texp
 //#WIKIFUNC    dump-to-sexp
-MNode*  ml_dump_to_sexp (MNode* cell, MlEnv* mlenv) {
+MNode*  ml_dump_to_texp (MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
     MNodePtr  e;
     ustring  text;
 
     while (arg) {
-//     text = eval_str (arg->car (), mlenv);
        e = eval (arg->car (), mlenv);
        nextNode (arg);
        if (text.length () > 0)
            text.append (CharConst (" "));
-       text.append (dump_to_sexp (e ()));
+       text.append (dump_to_texp (e ()));
     }
     return newMNode_str (new ustring (text));
 }
@@ -811,19 +1169,21 @@ MNode*  ml_dump_to_sexp (MNode* cell, MlEnv* mlenv) {
 /*DOC:
 //===to-sexp===
 // (to-sexp STRING) -> OBJECT
-===read-sexp===
+===read-texp, read-sexp===
  (read-sexp STRING) -> OBJECT
+ (read-texp STRING) -> OBJECT
 
 */
 //  //#AFUNC   to-sexp ml_to_sexp
 //  //#WIKIFUNC        to-sexp
-//#AFUNC       read-sexp       ml_read_sexp
+//#AFUNC       read-texp       ml_read_texp
+//#AFUNC       read-sexp       ml_read_texp
+//#WIKIFUNC    read-texp
 //#WIKIFUNC    read-sexp
-//MNode*  ml_to_sexp (MNode* cell, MlEnv* mlenv) {
-MNode*  ml_read_sexp (MNode* cell, MlEnv* mlenv) {
+MNode*  ml_read_texp (MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
     ustring  text;
-    MotorSexp ml (NULL);
+    MotorTexp  ml (NULL);
 
     if (! arg)
        throw (uErrorWrongNumber);
@@ -859,7 +1219,8 @@ MNode*  ml_is_ascii63 (MNode* cell, MlEnv* mlenv) {
     if (arg)
        throw (uErrorWrongNumber);
 
-    ans = checkASCII (text);
+//    ans = checkASCII (text);
+    ans = matchASCII (text.begin (), text.end ());
 
     return newMNode_bool (ans);
 }
@@ -1010,3 +1371,26 @@ MNode*  ml_to_lower (MNode* cell, MlEnv* mlenv) {
 
     return newMNode_str (new ustring (toLower (text)));
 }
+
+/*DOC:
+===hex-to-dec===
+ (hex-to-dec STRING) -> NUMBER
+
+*/
+//#AFUNC       hex-to-dec      ml_hex_to_dec
+//#WIKIFUNC    hex-to-dec
+MNode*  ml_hex_to_dec (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    ustring  text;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+    text = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg)
+       throw (uErrorWrongNumber);
+    if (text.length () > 8)
+       throw (uErrorBadArg);
+
+    return newMNode_num (hextoul (text.begin (), text.end ()));
+}