OSDN Git Service

add neon function.
authorvisor <visor@users.sourceforge.jp>
Wed, 4 Mar 2015 15:17:13 +0000 (00:17 +0900)
committervisor <visor@users.sourceforge.jp>
Wed, 4 Mar 2015 15:17:13 +0000 (00:17 +0900)
20 files changed:
Makefile.src
lib/http.cc
lib/httpconst.h
lib/ml.h
lib/util_string.cc
lib/util_string.h
ml/Makefile
modules/ml-addon.cc
modules/ml-apache.cc
modules/ml-cookielogin.cc
modules/ml-db.cc
modules/ml-http.cc
modules/ml-imagesize.cc
modules/ml-motor.cc
modules/ml-neon.cc [new file with mode: 0644]
modules/ml-neon.h [new file with mode: 0644]
modules/ml-security.cc
modules/ml-sendmail.cc
modules/ml-store.cc
modules/ml-store.h

index b5d296a..1980d01 100644 (file)
@@ -1,3 +1,5 @@
+MSRCS += ml-neon.cc
+MLDADD2 += -lneon
 MSRCS += ml-texp.cc
 MSRCS += ml-imagesize.cc
 MSRCS += ml-security.cc
index 445754a..08d210f 100644 (file)
@@ -135,9 +135,9 @@ void  HTTPResponse::setRandomCookie (MotorEnv* env) {
 
 void  HTTPResponse::standardResponse (MotorOutput* out, const ustring& type, const ustring& charset, MotorEnv* env) {
     if (! charset.empty () && matchHead (type, CharConst ("text/"))) {
-       out->out_raw (CharConst (kRES_TYPE))->out_noCtrl (type)->out_raw (CharConst ("; " kCHARSET))->out_noCtrl (charset)->out_raw (uLF);
+       out->out_raw (CharConst (kRES_TYPE ": "))->out_noCtrl (type)->out_raw (CharConst ("; " kCHARSET))->out_noCtrl (charset)->out_raw (uLF);
     } else {
-       out->out_raw (CharConst (kRES_TYPE))->out_noCtrl (type)->out_raw (uLF);
+       out->out_raw (CharConst (kRES_TYPE ": "))->out_noCtrl (type)->out_raw (uLF);
     }
     printMoreHeader (out, env);
 #ifdef HTTPS_NOCACHE
@@ -155,14 +155,14 @@ void  HTTPResponse::standardResponse (MotorOutput* out, const ustring& type, con
     case FOPT_NONE:
        break;
     case FOPT_DENY:
-       out->out_raw (CharConst (kRES_FRAMEOPT "DENY"))->out_raw (uLF);
+       out->out_raw (CharConst (kRES_FRAMEOPT ": " "DENY"))->out_raw (uLF);
        break;
     case FOPT_SAMEORIGIN:
-       out->out_raw (CharConst (kRES_FRAMEOPT "SAMEORIGIN"))->out_raw (uLF);
+       out->out_raw (CharConst (kRES_FRAMEOPT ": " "SAMEORIGIN"))->out_raw (uLF);
        break;
     case FOPT_ALLOWFROM:
        assert (0);
-       out->out_raw (CharConst (kRES_FRAMEOPT "ALLOW-FROM "));
+       out->out_raw (CharConst (kRES_FRAMEOPT ": " "ALLOW-FROM "));
        out->out_toHTML (foptUri);
        out->out_raw (uLF);
        break;
@@ -172,7 +172,7 @@ void  HTTPResponse::standardResponse (MotorOutput* out, const ustring& type, con
 }
 
 void  HTTPResponse::standardResponse_html (MotorOutput* out, MotorEnv* env) {
-    out->out_raw (CharConst (kRES_TYPE kMIME_HTML));
+    out->out_raw (CharConst (kRES_TYPE ": " kMIME_HTML));
     if (env && env->output) {
        out->out_raw (CharConst ("; " kCHARSET))->out_noCtrl (env->output->charset ())->out_raw (uLF);
     }
@@ -211,9 +211,9 @@ void  HTTPResponse::disposition (MotorOutput* out, bool finline, const ustring&
        }
     }
     if (finline) {
-       out->out_raw (CharConst (kRES_DISP kINLINE));
+       out->out_raw (CharConst (kRES_DISP ": " kINLINE));
     } else {
-       out->out_raw (CharConst (kRES_DISP kATTACHMENT));
+       out->out_raw (CharConst (kRES_DISP ": " kATTACHMENT));
     }
     if (n2.length () > 0) {
        out->out_raw (CharConst ("; filename=\""))->out_noCtrl (n2)->out_raw (uQ2);
@@ -227,7 +227,7 @@ void  HTTPResponse::location (MotorOutput* out, const ustring& url, MotorEnv* en
     out->out_raw (CharConst ("Location: "))
        ->out_noCtrl (url)
        ->out_raw (CharConst ("\n"
-                             kRES_TYPE kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
+                             kRES_TYPE ": " kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
     printCookie (out, env);
 #ifdef NO_KEEPALIVE
     out->out_raw (CharConst (kRES_CONNECTION_CLOSE))->out_raw (uLF);
@@ -239,7 +239,7 @@ void  HTTPResponse::location (MotorOutput* out, const ustring& url, MotorEnv* en
 }
 
 void  HTTPResponse::location_html (MotorOutput* out, const ustring& url, MotorEnv* env) {
-    out->out_raw (CharConst (kRES_TYPE kMIME_HTML "; " kCHARSET kCODE_UTF8 "\n"));
+    out->out_raw (CharConst (kRES_TYPE ": " kMIME_HTML "; " kCHARSET kCODE_UTF8 "\n"));
     printNoCache (out);
     printCookie (out, env);
 #ifdef NO_KEEPALIVE
@@ -268,7 +268,7 @@ void  HTTPResponse::location_html (MotorOutput* out, const ustring& url, MotorEn
 
 void  HTTPResponse::noContentResponse (MotorOutput* out, MotorEnv* env) {
     out->out_raw (CharConst ("Status: 200 No Content\n"
-                            kRES_TYPE kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
+                            kRES_TYPE ": " kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
     printNoCache (out);
     printCookie (out, env);
 #ifdef NO_KEEPALIVE
@@ -280,7 +280,7 @@ void  HTTPResponse::noContentResponse (MotorOutput* out, MotorEnv* env) {
 
 void  HTTPResponse::forbiddenResponse (MotorOutput* out, MotorEnv* env) {
     out->out_raw (CharConst ("Status: 403 Forbidden\n"
-                            kRES_TYPE kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
+                            kRES_TYPE ": " kMIME_TEXT "; " kCHARSET kCODE_UTF8 "\n"));
     printNoCache (out);
     printCookie (out, env);
 #ifdef NO_KEEPALIVE
@@ -313,49 +313,6 @@ void  HTTPResponse::printMoreHeader (MotorOutput* out, MotorEnv* env) {
     }
 }
 
-#if 0
-ustring  HTTPQuery::formString (HTTPSend* o) {
-    MNode*  e;
-    MNode*  a;
-    int  c = 0;
-    ustring  ans;
-
-    e = params ();
-    if (e && e->isCons ()) {
-       if (o) {
-           while (e) {
-               if (a = e->car ()) {
-                   if (c > 0)
-                       ans.append (uAmp);
-                   ans.append (percentEncode (o->cv (to_string (a->car ()))));
-                   if (! isNil (a->cdr ())) {
-                       ans.append (uEq);
-                       ans.append (percentEncode (o->cv (to_string (a->cdr ()))));
-                   }
-                   c ++;
-               }
-               nextNode (e);
-           }
-       } else {
-           while (e) {
-               if (a = e->car ()) {
-                   if (c > 0)
-                       ans.append (uAmp);
-                   ans.append (percentEncode (to_string (a->car ())));
-                   if (! isNil (a->cdr ())) {
-                       ans.append (uEq);
-                       ans.append (percentEncode (to_string (a->cdr ())));
-                   }
-                   c ++;
-               }
-               nextNode (e);
-           }
-       }
-    }
-    return ans;
-}
-#endif
-
 bool  HTTPSend::submit (TcpClient& client, TcpBuf& buf, MlEnv* mlenv) {
     bool  rc;
     ustring  q;
@@ -363,53 +320,36 @@ bool  HTTPSend::submit (TcpClient& client, TcpBuf& buf, MlEnv* mlenv) {
     if (status != HTTP_INIT)
        return false;
 
-#if 0
-    if (host.port == 0) {
-       if (proto == uHttp) {
-           host.port = 80;
-       } else if (proto == uHttps) {
-           host.port = 443;
-       }
-    }
-    rc = client.connect (&host);
-#endif
-    
-//    if (rc) {
-       status = HTTP_OPEN;
-       q = query (mlenv);
-       client.write (&*q.begin (), q.length ());
+    status = HTTP_OPEN;
+    q = query (mlenv);
+    client.write (&*q.begin (), q.length ());
 #ifdef DEBUG2
-       std::cerr << q;
+    std::cerr << q;
 #endif /* DEBUG */
-//     if (fpost) {
-//     if (method == M_POST) {
-       switch (method) {
-       case M_POST:
-           if (formData) {
-               writeFileForm (&client, mlenv);
-           } else if (rawquery.length () > 0) {
-               client.write (&*rawquery.begin (), rawquery.length ());
-           } else if (rawqueryfile.length () > 0) {
-               writeFile (&client, rawqueryfile);
-           } else {
-               writeQueryForm (params (), client);
-           }
-           break;
-       case M_PUT:
-           if (rawquery.length () > 0) {
-               client.write (&*rawquery.begin (), rawquery.length ());
-           } else if (rawqueryfile.length () > 0) {
-               writeFile (&client, rawqueryfile);
-           }
-           break;
-       default:;
+    switch (method) {
+    case M_POST:
+       if (formData) {
+           writeFileForm (&client, mlenv);
+       } else if (rawquery.length () > 0) {
+           client.write (&*rawquery.begin (), rawquery.length ());
+       } else if (rawqueryfile.length () > 0) {
+           writeFile (&client, rawqueryfile);
+       } else {
+           writeQueryForm (params (), client);
        }
-       client.flush_write ();
-       status = HTTP_QUERY;
-//    } else {
-//     return false;
-//    }
-
+       break;
+    case M_PUT:
+       if (rawquery.length () > 0) {
+           client.write (&*rawquery.begin (), rawquery.length ());
+       } else if (rawqueryfile.length () > 0) {
+           writeFile (&client, rawqueryfile);
+       }
+       break;
+    default:;
+    }
+    client.flush_write ();
+    status = HTTP_QUERY;
+    
     return true;
 }
 
index 9f3c6f4..a2b7268 100644 (file)
 #define kMIME_XML              "text/xml"
 #define kMIME_OCTET            "application/octet-stream"
 #define kMIME_URLENCODED       "application/x-www-form-urlencoded"
-#define kRES_TYPE              "Content-type"
-#define kRES_DISP              "Content-Disposition"
+#define kRES_TYPE              "Content-type"
+#define kRES_DISP              "Content-Disposition"
 #define kRES_CONNECTION_CLOSE  "Connection: close"
-#define kRES_FRAMEOPT          "X-Frame-Options"
+#define kRES_FRAMEOPT          "X-Frame-Options"
 #define kCHARSET               "charset="
 #define kATTACHMENT            "attachment"
 #define kINLINE                        "inline"
index 4b07222..eee2c1d 100644 (file)
--- a/lib/ml.h
+++ b/lib/ml.h
@@ -478,5 +478,6 @@ void  nextNode (MNode*& arg);
 void  nextNodeNonNil (MNode*& arg);
 
 #define  evkw(n,v)     (keywords[n] && ! isNil (v = eval (keywords[n], mlenv)))
+#define  evkw_bool(n,v)        (keywords[n] && (v = eval_bool (keywords[n], mlenv)))
 
 #endif /* ML_H */
index 39df2a8..efec261 100644 (file)
@@ -821,9 +821,15 @@ ustring  toCRLF (const ustring& str) {
     return ans;
 }
 
-void  skipSpace (uiterator& b, uiterator e) {
-    while (b < e && *b == ' ') {
-       b ++;
+void  skipChar (uiterator& b, uiterator e, int ch) {
+    while (b < e && *b == ch)
+       ++ b;
+}
+
+void  skipNextToChar (uiterator& b, uiterator e, int ch) {
+    while (b < e) {
+       if (*(b ++) == ch)
+           return;
     }
 }
 
index 5054cf3..e685fa2 100644 (file)
@@ -100,7 +100,9 @@ ustring  zeroPad (int n, const ustring& src);
 ustring  padEmpty (const ustring& name);
 uint32_t  hextoul (uiterator b, uiterator e);
 ustring  toCRLF (const ustring& str);
-void  skipSpace (uiterator& b, uiterator e);
+void  skipChar (uiterator& b, uiterator e, int ch);
+inline void  skipSpace (uiterator& b, uiterator e) {skipChar (b, e, ' ');}
+void  skipNextToChar (uiterator& b, uiterator e, int ch);
 ustring  toLower (uiterator b, uiterator e);
 
 ustring  formatDateString (const ustring& format, struct tm& v);
index d9c6a21..f3f7a76 100644 (file)
@@ -54,7 +54,7 @@ SRCS += japanese-hankaku.c
 .PATH: ../ml ../lib ../modules ../wiki ../ext
 
 .ifdef DEBUG
-CFLAGS = -g
+CFLAGS = -g -O0
 CFLAGS += -DDEBUG
 .ifdef DEBUG2
 CFLAGS += -DDEBUG2
index 1c3efbd..33d2b92 100644 (file)
@@ -55,8 +55,7 @@ public:
     virtual void  setParams (MNode* arg, MlEnv* mlenv) {
        ::setParams (arg, 1, &params, kwlist_addon_t1, &keywords, &rest);
        cmd = eval_str (params[0], mlenv);
-       if (keywords[0])
-           fRawInput = eval_bool (keywords[0], mlenv);
+       evkw_bool (0, fRawInput);
     };
     virtual void  setPars (MlEnv* mlenv) {
        if (fRawInput) {
@@ -104,8 +103,7 @@ public:
        ::setParams (arg, 1, &params, kwlist_addon_t2, &keywords, &rest);
        cmd = eval_str (params[0], mlenv);
        type = eval_asciiword (keywords[1], mlenv);
-       if (keywords[2])
-           fContinue = eval_bool (keywords[2], mlenv);
+       evkw_bool (2, fContinue);
        if (! checkMimeType (type))
            type.resize (0);
     };
index 943517b..9502ab0 100644 (file)
@@ -257,6 +257,7 @@ MNode*  ml_absolute_url (MNode* cell, MlEnv* mlenv) {
     int  n;
     ustring*  ans;
     MNodePtr  t;
+    bool  f;
     static paramList  kwlist[] = {
        {CharConst ("http"), true},
        {CharConst ("https"), true},
@@ -272,11 +273,11 @@ MNode*  ml_absolute_url (MNode* cell, MlEnv* mlenv) {
 
     setParams (arg, 1, &params, kwlist, &keywords, NULL);
     url = eval_text1 (params[0], mlenv);
-    if (keywords[0] && eval_bool (keywords[0], mlenv))
+    if (evkw_bool (0, f))
        proto = PROTO_HTTP;
-    if (keywords[1] && eval_bool (keywords[1], mlenv))
+    if (evkw_bool (1, f))
        proto = PROTO_HTTPS;
-    if (keywords[2] && eval_bool (keywords[2], mlenv))
+    if (evkw_bool (2, f))
        proto = PROTO_NONE;
     if (evkw (3, t)) {
        n = to_int (t ());
index 091b922..ed8bd9f 100644 (file)
@@ -147,8 +147,7 @@ MNode*  ml_cookielogin (MNode* cell, MlEnv* mlenv) {
     setParams (arg, 2, &params, kwlist, &keywords, &rest);
     name = eval_str (params[0], mlenv);
     obj.sessionkey = eval_str (params[1], mlenv);
-    if (keywords[0])
-       errfn = eval (keywords[0], mlenv);
+    evkw (0, errfn);
 
     if (name.size () == 0)
        throw (uErrorFilenameEmpty);
@@ -229,7 +228,7 @@ MNode*  ml_cookielogin_login (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
     cookielimit = eval_int (keywords[5], mlenv);
     if (cookielimit < 0)
        cookielimit = 0;
-    fsecure = eval_bool (keywords[6], mlenv);
+    evkw_bool (6, fsecure);
 
     if (id.size () > 0) {
        // write to the db
@@ -326,7 +325,7 @@ MNode*  ml_cookielogin_check (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
     };
 
     setParams (arg, 0, NULL, kwlist, &keywords, NULL);
-    fsecure = eval_bool (keywords[0], mlenv);
+    evkw_bool (0, fsecure);
 
     key = mlenv->env->http.readCookie (obj->sessionkey);
     obj->opendb ();
index 7468d42..747be53 100644 (file)
@@ -159,13 +159,10 @@ static MNode*  ml_db_sub (MNode* cell, MlEnv* mlenv, MLDb* obj, DBFUNC fn) {
        if (obj->limit > kARRAYMAX)
            obj->limit = kARRAYMAX;
     }
-    if (keywords[1])
-       fxserial = eval_bool (keywords[1], mlenv);
-    if (keywords[2])
-       errfn = eval (keywords[2], mlenv);
+    evkw_bool (1, fxserial);
+    evkw (2, errfn);
 #ifdef DB_XSERIAL_COMPAT
-    if (keywords[3])
-       fxserial = eval_bool (keywords[3], mlenv);
+    evkw_bool (3, fxserial);
 #endif
 
     if (name.size () == 0)
index 5023728..57f32a5 100644 (file)
@@ -895,6 +895,8 @@ MNode*  ml_http_get_http_response_output (MNode* cell, MlEnv* mlenv, MLFunc* mob
     if (keywords[0] && eval_bool (keywords[0], mlenv))
        cflag = true;
 
+    if (! mlenv->env->responseDone)
+       mlenv->env->standardResponse_html ();
     obj->http->readReplyBody (*obj->client, obj->buf, mlenv->env->output);
 
     if (! cflag)
index df9a2f6..d98e155 100644 (file)
@@ -183,7 +183,7 @@ MNode*  ml_image_size (MNode* cell, MlEnv* mlenv) {
     if (keywords[5] && eval_bool (keywords[5], mlenv)) // static
        storetype.setStatic ();
 #endif
-    src = storetype.src (mlenv);
+    src = storetype.src ();
 
     if (src.length () > 0) {
        FileMacro  f;
index 0056a56..347f706 100644 (file)
@@ -130,7 +130,7 @@ MNode*  ml_motor_file (MNode* cell, MlEnv* mlenv) {
     if (keywords[9] && eval_bool (keywords[9], mlenv)) // static
        storetype.setStatic ();
 #endif
-    src = storetype.src (mlenv);
+    src = storetype.src ();
 
     if (src.size () == 0)
        throw (uErrorFilenameEmpty);
diff --git a/modules/ml-neon.cc b/modules/ml-neon.cc
new file mode 100644 (file)
index 0000000..cc28430
--- /dev/null
@@ -0,0 +1,1234 @@
+#include "ml-neon.h"
+#include "config.h"
+#include "ml-http.h"
+#include "ml.h"
+#include "mlenv.h"
+#include "motorenv.h"
+#include "motoroutput.h"
+#include "util_check.h"
+#include "util_string.h"
+#include "util_random.h"
+#include "util_mimetype.h"
+#include "util_file.h"
+#include "util_base64.h"
+#include "http-iconv.h"
+#include "expr.h"
+#include "utf8.h"
+#include "ustring.h"
+#include "filemacro.h"
+#include <fstream>
+#include <neon/ne_session.h>
+#include <neon/ne_request.h>
+#include <neon/ne_utils.h>
+#include <neon/ne_uri.h>
+
+class  NEONInitOnce {
+public:
+    int  count;
+
+    NEONInitOnce () {
+       count = 0;
+    };
+    virtual  ~NEONInitOnce () {
+       if (count > 0) {
+           ne_sock_exit ();
+       }
+    };
+
+    void  init () {
+       if (count == 0) {
+           ne_sock_init ();
+           ++ count;
+#ifdef DEBUG
+           std::cerr << "neon feature:"
+                     << (ne_has_support (NE_FEATURE_SSL) ? " FEATURE_SSL" : "")
+                     << (ne_has_support (NE_FEATURE_ZLIB) ? " FEATURE_ZLIB" : "")
+                     << (ne_has_support (NE_FEATURE_IPV6) ? " FEATURE_IPV6" : "")
+                     << (ne_has_support (NE_FEATURE_LFS) ? " FEATURE_LFS" : "")
+                     << (ne_has_support (NE_FEATURE_SOCKS) ? " FEATURE_SOCKS" : "")
+                     << (ne_has_support (NE_FEATURE_TS_SSL) ? " FEATURE_TS_SSL" : "")
+                     << "\n";
+#endif /* DEBUG */
+       }
+    }
+};
+NEONInitOnce  NeonInit;
+
+//============================================================
+void  NeonPostBodyProvider::pushFile (const ustring& name, const ustring& path) {
+    if (name.length () > 0 && isPlainFile (path))
+       postFile.push_back (std::pair<ustring, ustring> (name, path));
+}
+
+void  NeonPostBodyProvider::makeSeparator () {
+    separator.assign (CharConst ("--------")).append (randomKey ()).append (randomKey ());
+}
+
+ustring  NeonPostBodyProvider::separatorLine () {
+    return ustring (CharConst ("--")).append (separator).append (uCRLF);
+}
+
+ustring  NeonPostBodyProvider::separatorHeader () {
+    return ustring (CharConst (kMIME_FORMDATA "; boundary=")).append (separator);
+}
+
+ustring  NeonPostBodyProvider::textSeparator (const ustring& name) {
+    ustring  ans;
+    ans.assign (CharConst ("--")).append (separator).append (uCRLF);
+    ans.append (CharConst (kRES_DISP ": form-data; name=" kQ2)).append (percentEncode (query->cv (name))).append (CharConst (kQ2 kCRLF kCRLF));
+    return ans;
+}
+
+ustring  NeonPostBodyProvider::fileSeparator (const ustring& name, const ustring& filename) {
+    ustring  ans;
+    ans.assign (CharConst ("--")).append (separator).append (uCRLF);
+    ans.append (CharConst (kRES_DISP ": form-data; name=" kQ2)).append (percentEncode (query->cv (name))).append (CharConst (kQ2 "; filename=" kQ2)).append (slashEncode (filename)).append (CharConst (kCRLF));
+    ans.append (CharConst (kRES_TYPE ": ")).append (mimetype (getExt (filename))).append (CharConst (kCRLF kCRLF));
+    return ans;
+}
+
+ustring  NeonPostBodyProvider::tailSeparator () {
+    ustring  ans;
+    ans.assign (CharConst ("--")).append (separator).append (CharConst ("--" kCRLF));
+    return ans;
+}
+
+ne_off_t  NeonPostBodyProvider::calcLength () {
+    ne_off_t  ans = 0;
+    MNode*  a;
+    ustring  u;
+    off_t  s;
+
+    tp = query->queryParam ();
+    if (isCons (tp)) {
+       while (tp) {
+           a = tp->car ();
+           if (isCons (a)) {
+               ans += textSeparator (to_string (a->car ())).length () + to_string (a->cdr ()).length () + 2;
+           }
+           nextNode (tp);
+       }
+    }
+    bp = postFile.begin ();
+    ep = postFile.end ();
+    for (; bp < ep; ++ bp) {
+       u = filePart_osSafe ((*bp).second);
+       if (! fileSize (u, s))
+           s = 0;
+       ans += fileSeparator ((*bp).first, u).length () + s + 2;
+    }
+    ans += tailSeparator ().length ();
+#ifdef DEBUG
+    std::cerr << "calcLength(): " << ans << "\n";
+#endif /* DEBUG */
+    return ans;
+}
+
+char*  NeonPostBodyProvider::bodyProvider (char* buffer, size_t buflen) {
+    ssize_t  ans = 0;
+    if (buflen == 0) {
+       tp = query->queryParam ();
+       bp = postFile.begin ();
+       ep = postFile.end ();
+       if (isCons (tp) || bp < ep) {
+           state = S_TEXT;
+       } else {
+           state = S_DONE;
+       }
+       offset = 0;
+       // 正常なら0を返す
+    } else {
+#ifdef DEBUG
+       std::cerr << "state:" << state << ", offset:" << offset << ", buflen:" << buflen << "\n";
+#endif /* DEBUG */
+       switch (state) {
+       case S_TEXT:
+           if (offset > 0) {
+               ans = bodyProviderText (buffer, buflen);
+           } else if (isCons (tp)) {
+               MNode*  a = tp->car ();
+               nextNode (tp);
+               ubuf = textSeparator (to_string (a->car ())) + to_string (a->cdr ()) + uCRLF;
+#ifdef DEBUG
+               std::cerr << "ubuf:" << omitNonAscii (ubuf.substr (0, 8)) << "\n";
+#endif /* DEBUG */
+               ans = bodyProviderText (buffer, buflen);
+           } else {
+               state = S_FILEHEAD;
+               ans = bodyProvider (buffer, buflen) - buffer;
+           }
+           break;
+       case S_FILEHEAD:
+           if (offset > 0) {
+               ans = bodyProviderText (buffer, buflen);
+               if (offset == 0)
+                   state = S_FILEBODY;
+           } else if (bp < ep) {
+               ustring  u = filePart_osSafe ((*bp).second);
+               ubuf = fileSeparator ((*bp).first, u);
+#ifdef DEBUG
+               std::cerr << "ubuf:" << omitNonAscii (ubuf.substr (0, 8)) << "\n";
+#endif /* DEBUG */
+               ans = bodyProviderText (buffer, buflen);
+               if (offset == 0)
+                   state = S_FILEBODY;
+           } else {
+               state = S_TAIL;
+               ans = bodyProvider (buffer, buflen) - buffer;
+           }
+           break;
+       case S_FILEBODY:
+           if (offset > 0) {
+               ans = fd.read (buffer, buflen);
+#ifdef DEBUG
+               std::cerr << "read\n";
+#endif /* DEBUG */
+               if (ans <= 0) {
+                   fd.close ();
+#ifdef DEBUG
+                   std::cerr << "close\n";
+#endif /* DEBUG */
+                   offset = 0;
+                   ++ bp;
+                   state = S_FILETERM;
+                   ans = bodyProvider (buffer, buflen) - buffer;
+               } else {
+                   offset += ans;
+               }
+           } else {    // offset == 0
+               ustring  u = filePart_osSafe ((*bp).second);
+#ifdef DEBUG
+               std::cerr << "open:" << (*bp).second << "\n";
+#endif /* DEBUG */
+               if (fd.openRead ((*bp).second.c_str ())) {
+                   ans = fd.read (buffer, buflen);
+                   if (ans <= 0) {
+                       fd.close ();
+#ifdef DEBUG
+                       std::cerr << "close\n";
+#endif /* DEBUG */
+                       ++ bp;
+                       state = S_FILETERM;
+                       ans = bodyProvider (buffer, buflen) - buffer;
+                   } else {
+                       offset = ans;
+                   }
+               } else {
+#ifdef DEBUG
+                   std::cerr << "open failed\n";
+#endif /* DEBUG */
+                   ++ bp;
+                   state = S_FILETERM;
+                   ans = bodyProvider (buffer, buflen) - buffer;
+               }
+           }
+           break;
+       case S_FILETERM:
+           if (offset > 0) {
+               ans = bodyProviderText (buffer, buflen);
+           } else {
+               ubuf = uCRLF;
+#ifdef DEBUG
+               std::cerr << "ubuf:CRLF\n";
+#endif /* DEBUG */
+               ans = bodyProviderText (buffer, buflen);
+           }
+           if (offset == 0)
+               state = S_FILEHEAD;
+           break;
+       case S_TAIL:
+           if (offset > 0) {
+               ans = bodyProviderText (buffer, buflen);
+               if (offset == 0)
+                   state = S_DONE;
+           } else {
+               ubuf = tailSeparator ();
+               ans = bodyProviderText (buffer, buflen);
+               if (offset == 0)
+                   state = S_DONE;
+           }
+           break;
+       case S_DONE:
+           // 0を返す
+           break;
+       default:;
+       }
+    }
+
+    if (ans > 0 && buflen > ans)
+       return bodyProvider (buffer + ans, buflen - ans);
+#ifdef DEBUG
+    std::cerr << "bodyProvider ():" << ans << "\n";
+#endif /* DEBUG */
+    return buffer + ans;
+}
+
+ssize_t  NeonPostBodyProvider::bodyProviderText (char* buffer, size_t buflen) {
+    ssize_t  ans = ubuf.length () - offset;
+#ifdef DEBUG
+    std::cerr << "bodyProviderText: buflen:" << buflen << ", offset:" << offset << ", text:" << omitNonAsciiWord (ubuf.substr (offset, offset + 6)) << "\n";
+#endif /* DEBUG */
+    if (ans <= buflen) {
+       memcpy (buffer, ubuf.data () + offset, ans);
+       offset = 0;
+    } else {
+       memcpy (buffer, ubuf.data () + offset, buflen);
+       offset += buflen;
+       ans = buflen;
+    }
+    return ans;
+}
+
+//============================================================
+static int  ignoreVerifyFn (void* neon, int failures, const ne_ssl_certificate* cert) {
+#ifdef DEBUG2
+    std::cerr << "ignoreVerifyFn ()\n";
+#endif /* DEBUG */
+    return 0;
+}
+
+NeonSession::NeonSession (proto_t _proto, const ustring& host, unsigned int port) {
+    const char*  protoName;
+
+    proto = _proto;
+    switch (proto) {
+    case PROTO_HTTP:
+       protoName = "http";
+       break;
+    case PROTO_HTTPS:
+       protoName = "https";
+       break;
+    default:
+       assert (0);
+    }
+    session = ne_session_create (protoName, host.c_str (), port);
+    if (! session)
+       return;
+    if (proto == PROTO_HTTPS)
+       ne_ssl_trust_default_ca (session);
+#ifdef DEBUG
+    std::cerr << "session flag:"
+             << (ne_get_session_flag (session, NE_SESSFLAG_PERSIST) ? " NE_SESSFLAG_PERSIST" : "")
+             << (ne_get_session_flag (session, NE_SESSFLAG_ICYPROTO) ? " NE_SESSFLAG_ICYPROTO" : "")
+             << (ne_get_session_flag (session, NE_SESSFLAG_SSLv2) ? " NE_SESSFLAG_SSLv2" : "")
+             << (ne_get_session_flag (session, NE_SESSFLAG_RFC4918) ? " NE_SESSFLAG_RFC4918" : "")
+             << (ne_get_session_flag (session, NE_SESSFLAG_CONNAUTH) ? " NE_SESSFLAG_CONNAUTH" : "")
+             << (ne_get_session_flag (session, NE_SESSFLAG_TLS_SNI) ? " NE_SESSFLAG_TLS_SNI" : "")
+             << (ne_get_session_flag (session, NE_SESSFLAG_EXPECT100) ? " NE_SESSFLAG_EXPECT100" : "")
+             << "\n";
+#endif /* DEBUG */
+}
+
+NeonSession::~NeonSession () {
+    ne_session_destroy (session);
+    session = NULL;
+}
+
+void  NeonSession::setNoVerify () {
+    if (proto == PROTO_HTTPS)
+       ne_ssl_set_verify (session, ignoreVerifyFn, this);
+}
+
+void  NeonSession::setProxy (const ustring& host, int port) {
+    if (checkHostname (host) && port > 0 && port < 65536) {
+#ifdef DEBUG2
+       std::cerr << "set proxy " << host << ":" << port << "\n";
+#endif /* DEBUG */
+       ne_session_proxy (session, host.c_str (), port);
+    } else {
+       throw (ustring (CharConst ("bad proxy host.")));
+    }
+}
+
+//============================================================
+void  NeonQuery::closeReq () {
+    if (req) {
+       switch (mode) {
+       case MODE_DISPATCHED:
+           ne_discard_response (req);
+       case MODE_RECEIVED:
+           ne_end_request (req);
+       case MODE_SETUP:;
+       }
+       mode = MODE_SETUP;
+       ne_request_destroy (req);
+       req = NULL;
+    }
+}
+
+void  NeonQuery::setIConv (const char* name) {
+    cv_in.reset (new UIConv (kCODE_UTF8, name));
+    cv_out.reset (new UIConv (name, kCODE_UTF8));
+}
+
+static ssize_t  qbodyProvider (void* userdata, char* buffer, size_t buflen) {
+    NeonPostBodyProvider*  obj = (NeonPostBodyProvider*)userdata;
+    return obj->bodyProvider (buffer, buflen) - buffer;
+}
+
+void  NeonQuery::submit () {
+    FileMacro  fd;
+    ustring  uri = filterPath ();
+    ustring  getQuery = buildGetQuery ();
+
+    errorMsg.resize (0);
+    if (getQuery.length () > 0) {
+       uri.append (CharConst ("?"));
+       uri.append (getQuery);
+    }
+    closeReq ();
+    req = ne_request_create (session, methodStr (), uri.c_str ());
+    buildCookie ();
+    buildHeader ();
+    switch (method) {
+    case METHOD_POST:
+       if (! rawquery.isEmpty ()) {
+           setRawQuery (fd);
+       } else {
+           ustring  data;
+           buildQuery (queryParam (), data);
+           setFormType_urlencoded ();
+           ne_set_request_body_buffer (req, data.c_str (), data.size ());
+       }
+       break;
+    case METHOD_FILE:
+       ne_add_request_header (req, kRES_TYPE, qbody->separatorHeader ().c_str ());
+       ne_set_request_body_provider (req, qbody->calcLength (), qbodyProvider, qbody.get ());
+       break;
+    case METHOD_PUT:
+       if (! rawquery.isEmpty ()) {
+           setRawQuery (fd);
+       }
+       break;
+    default:;
+    }
+    int  rc = ne_begin_request (req);
+    if (rc == NE_OK) {
+       mode = MODE_DISPATCHED;
+    } else {
+       errorMsg.assign (ne_get_error (session));
+#ifdef DEBUG
+       std::cerr << "error: " << errorMsg << "\n";
+#endif /* DEBUG */
+    }
+}
+
+void  NeonQuery::readBody (MotorOutput* out) {
+    if (mode == MODE_DISPATCHED) {
+       char  buf[65536];
+       ssize_t  s;
+       while ((s = ne_read_response_block (req, buf, 65536)) > 0) {
+           out->out_raw (buf, s);
+       }
+       if (s == 0) {           // success
+           mode = MODE_RECEIVED;
+       } else if (s < 0) {     // error
+           mode = MODE_RECEIVED;
+       }
+    }
+}
+
+int  NeonQuery::getStatus () {
+    if (req) {
+       const ne_status*  st = ne_get_status (req);
+       if (st)
+           return st->code;
+    }
+    return 0;                  // error
+}
+
+const char*  NeonQuery::methodStr () {
+    switch (method) {
+    case METHOD_GET:
+       return kMETHOD_GET;
+    case METHOD_POST:
+       return kMETHOD_POST;
+    case METHOD_PUT:
+       return kMETHOD_PUT;
+    case METHOD_DELETE:
+       return kMETHOD_DELETE;
+    case METHOD_HEAD:
+       return kMETHOD_HEAD;
+    case METHOD_FILE:
+       return kMETHOD_POST;
+    default:
+       assert (0);
+    }
+}
+
+ustring  NeonQuery::buildGetQuery () {
+    ustring  ans;
+
+    if (! isNil (queryParamGet ())) {
+       buildQuery (queryParamGet (), ans);
+    } else if (method == METHOD_GET) {
+       if (! rawquery.isEmpty () && rawquery.isText ()) {
+           ans = rawquery.read ();
+       } else if (! isNil (queryParam ())) {
+           buildQuery (queryParam (), ans);
+       }
+    }
+    return ans;
+}
+
+void  NeonQuery::buildQuery (MNode* e, ustring& out) {
+    int  c = 0;
+    MNode*  a;
+
+    if (isCons (e)) {
+       while (e) {
+           a = e->car ();
+           if (isCons (a)) {
+               if (c > 0)
+                   out.append (uAmp);
+               out.append (percentEncode (cv (to_string (a->car ()))));
+               if (! isNil (a->cdr ())) {
+                   out.append (uEq);
+                   out.append (percentEncode (cv (to_string (a->cdr ()))));
+               }
+               ++ c;
+           }
+           nextNode (e);
+       }
+    }
+}
+
+ustring  NeonQuery::buildMimeSeparator_text (const ustring& name) {
+    ustring  ans;
+    ans.assign (qbody->separatorLine ());
+    ans.append (CharConst ("Content-Disposition: form-data; name=" kQ2)).append (percentEncode (cv (name))).append (CharConst (kQ2 kCRLF kCRLF));
+    return ans;
+}
+
+ustring  NeonQuery::buildMimeSeparator_file (const ustring& name, const ustring& filename) {
+    ustring  ans;
+    ans.assign (qbody->separatorLine ());
+    ans.append (CharConst ("Content-Disposition: form-data; name=" kQ2)).append (percentEncode (cv (name))).append (CharConst (kQ2 "; filename=" kQ2)).append (slashEncode (filename)).append (CharConst (kQ2 kCRLF));
+    ans.append (CharConst ("Content-Type: ")).append (mimetype (getExt (filename))).append (CharConst (kCRLF kCRLF));
+    return ans;
+}
+
+ustring  NeonQuery::cv (const ustring& src) {
+    if (cv_out.get ()) {
+       return cv_out->cv (src);
+    } else {
+       return src;
+    }
+}
+
+ustring  NeonQuery::rcv (const ustring& src) {
+    if (cv_in.get ()) {
+       return cv_in->cv (src);
+    } else {
+       return src;
+    }
+}
+
+ustring  NeonQuery::getResponseHeader (const char* name) {
+    const char*  ans = ne_get_response_header (req, name);
+    if (ans)
+       return ustring (ans);
+    else
+       return uEmpty;
+}
+
+MNode*  NeonQuery::getResponseHeaderAll () {
+    MNodeList  ans;
+    void*  csr = NULL;
+    const char*  name;
+    const char*  val;
+    do {
+       csr = ne_response_header_iterate (req, csr, &name, &val);
+       if (csr)
+           ans.append (newMNode_cons (newMNode_str (new ustring (name)), newMNode_str (new ustring (val))));
+       else
+           break;
+    } while (1);
+    return ans.release ();
+}
+
+ustring  NeonQuery::getResponseCookie (const ustring& name) {
+    parseCookie ();
+    for (int i = 0; i < replyCookie.size (); ++ i) {
+       if (replyCookie[i].key == name)
+           return replyCookie[i].value;
+    }
+    return uEmpty;
+}
+
+MNode*  NeonQuery::getResponseCookieAll () {
+    MNodeList  ans;
+    parseCookie ();
+    for (int i = 0; i < replyCookie.size (); ++ i) {
+       ans.append (newMNode_cons (newMNode_str (new ustring (replyCookie[i].key)), newMNode_str (new ustring (replyCookie[i].value))));
+    }
+    return ans.release ();
+}
+
+ustring  NeonQuery::filterPath () {
+    return percentEncode_path (omitCtrl (path));
+}
+
+void  NeonQuery::buildCookie () {
+    MNode*  e = cookie ();
+    MNode*  a;
+    ustring  data;
+    size_t  off = 0;
+    ustring  u;
+
+    if (isCons (e)) {
+       while (e) {
+           a = e->car ();
+           if (isNil (a)) {
+           } else if (isCons (a)) {
+               u.assign (cookieencode (to_string (a->car ()))).append (uEq).append (cookieencode (to_string (a->cdr ())));
+               if (off > 800) {
+                   data.append (CharConst (";" kCRLF " ")).append (u);
+                   off = u.length ();
+               } else if (off > 0) {
+                   data.append (CharConst ("; ")).append (u);
+                   off += u.length () + 2;
+               } else {
+                   data.append (u);
+                   off += u.length ();
+               }
+           } else {
+               throw (cookie ()->dump_string_short () + uErrorBadParam);
+           }
+           nextNode (e);
+       }
+    }
+    if (data.length () > 0)
+       ne_add_request_header (req, "Cookie", data.c_str ());
+}
+
+void  NeonQuery::buildHeader () {
+    MNode*  e = header ();
+    MNode*  a;
+    ustring  key, val;
+    static uregex  re1 ("[\\x00-\\x1f: ]");
+    static uregex  re2 ("[\\x00-\\x1f]");
+
+    if (isCons (e)) {
+       while (e) {
+           a = e->car ();
+           if (isNil (a)) {
+           } else if (a->isCons ()) {
+               key = to_string (a->car ());
+               val = to_string (a->cdr ());
+               if (! checkRe (key, re1) && ! checkRe (val, re2) && key.length () + val.length () < 2048) {
+                   ne_add_request_header (req, key.c_str (), val.c_str ());
+               }
+           } else {
+               throw (cookie ()->dump_string_short () + uErrorBadParam);
+           }
+           nextNode (e);
+       }
+    }
+    if (basicID.length () > 0)
+       buildBasicAuthHeader ();
+}
+
+void  NeonQuery::buildBasicAuthHeader () {
+    ustring  idpw;
+    ustring  auth;
+    idpw.assign (basicID).append (uColon).append (basicPW);
+    auth.assign (CharConst ("Basic ")).append (base64Encode (idpw.begin (), idpw.end ()));
+    ne_add_request_header (req, "Authorization", auth.c_str ());
+}
+
+void  NeonQuery::setFormType () {
+    if (querytype.length () > 0) {
+       ne_add_request_header(req, "Content-type", querytype.c_str ());
+    } else {
+       setFormType_urlencoded ();
+    }
+}
+
+void  NeonQuery::setFormType_urlencoded () {
+    ne_add_request_header(req, "Content-type", kMIME_URLENCODED);
+}
+
+void  NeonQuery::setFormType_formdata () {
+    ne_add_request_header(req, "Content-type", kMIME_FORMDATA);
+}
+
+void  NeonQuery::parseCookie () {
+    if (! replyCookieDone) {
+       replyCookieDone = true;
+       ustring  u = getResponseHeader ("set-cookie");
+       uiterator  b = u.begin ();
+       uiterator  e = u.end ();
+       uregex  re1 ("[=,;]");
+       uregex  re2 ("[,;]");
+       uregex  re3 ("^path=|expires=|domain=|secure");
+       uregex  re4 ("^..., *[0-9]+[^,;]+");
+       umatch  m;
+       while (b < e && usearch (b, e, m, re1)) {       // = | , | ;
+           CookieInfo  info;
+           switch (*m[0].first) {
+           case '=':
+               info.key.assign (b, m[0].first);
+               b = m[0].second;
+               if (usearch (b, e, m, re2)) {   // , | ;
+                   info.value.assign (b, m[0].first);
+                   if (*m[0].first == ';') {
+                       b = m[0].second;
+                       while (b < e) {
+                           if (usearch (b, e, m, re3)) {       // path=,expires=,...
+                               if (*m[0].first == 'e') {
+                                   if (usearch (b, e, m, re4)) {
+                                       b = m[0].second;
+                                       if (*(b - 1) == ',') {
+                                           skipSpace (b, e);
+                                           break;
+                                       } else {        // ;
+                                           skipSpace (b, e);
+                                       }
+                                   } else if (usearch (b, e, m, re2)) {
+                                       b = m[0].second;
+                                       skipSpace (b, e);
+                                       if (*m[0].first == ',')
+                                           break;
+                                   } else {
+                                       b = e;
+                                   }
+                               } else if (usearch (b, e, m, re2)) {
+                                   b = m[0].second;
+                                   skipSpace (b, e);
+                                   if (*m[0].first == ',')
+                                       break;
+                               } else {
+                                   b = e;
+                               }
+                           } else if (usearch (b, e, m, re2)) {        // , | ;
+                               b = m[0].second;
+                               skipSpace (b, e);
+                               if (*m[0].first == ',')
+                                   break;      // while
+                           } else {
+                               b = e;
+                           }
+                       }
+                   }
+               } else {
+                   info.value.assign (b, e);
+               }
+               replyCookie.push_back (info);
+               break;
+           case ';':
+               b = m[0].second;
+               skipNextToChar (b, e, ',');
+               skipSpace (b, e);
+               break;
+           case ',':
+           default:
+               b = m[0].second;
+               skipSpace (b, e);
+           }
+       }
+    }
+}
+
+void  NeonQuery::setRawQuery (FileMacro& fd) {
+    setFormType ();
+    if (rawquery.isText ()) {
+       ne_set_request_body_buffer (req, rawquery.param.c_str (), rawquery.param.size ());
+    } else {
+       ustring  src = rawquery.src ();
+       if (src.length () > 0) {
+           if (fd.openRead (src.c_str ())) {
+               ne_set_request_body_fd (req, fd.fd, 0, fd.size ());
+           }
+       }
+    }
+}
+
+//============================================================
+void  MLNeon::newSession (MlEnv* mlenv) {
+    session.reset (new NeonSession (proto, host, port));
+    // *** User-Agent
+    query.reset (new NeonQuery (session->get (), mlenv));
+}
+
+//============================================================
+/*DOC:
+==neon library==
+
+*/
+/*DOC:
+===$neon==
+ ($neon [#http | #https] Host Port
+       [:proxy '(HOSTNAME . PORT)] [:proxy-user '(ID . PASSWORD)]
+       [:on-error FUNCTION]
+       [#no-verify]
+       [SUBFUNCTION...]) -> LAST VALUE
+
+*/
+//#MFUNC       $neon   ml_neon cMLNeonID
+MNode*  ml_neon (MNode* cell, MlEnv* mlenv) {
+    MNode*  arg = cell->cdr ();
+    NeonInit.init ();
+    MLNeon  obj (mlenv);
+    MNodePtr  errfn;
+    MNodePtr  ans;
+    MNodePtr  t;
+    bool  b;
+    std::vector<MNode*>  params;
+    std::vector<MNode*>  keywords;
+    MNode*  rest;
+    static paramList  kwlist[] = {
+       {CharConst ("http"), true},             // 0
+       {CharConst ("https"), true},            // 1
+       {CharConst ("proxy"), false},           // 2
+       {CharConst ("proxy-user"), false},      // 3
+       {CharConst ("on-error"), false},        // 4
+       {CharConst ("no-verify"), true},        // 5
+       {NULL, 0, 0}
+    };
+
+    setParams (arg, 2, &params, kwlist, &keywords, &rest);
+    obj.host = eval_str (params[0], mlenv);
+    obj.port = eval_int (params[1], mlenv);
+    if (evkw_bool (0, b))              // 0:http
+       obj.proto = NeonSession::PROTO_HTTP;
+    if (evkw_bool (1, b))              // 1:https
+       obj.proto = NeonSession::PROTO_HTTPS;
+    if (evkw (2, t)) {                 // 2:proxy
+       if (isCons (t ())) {
+           obj.proxyhost = to_string (t ()->car ());
+           obj.proxyport = to_int (t ()->cdr ());
+       } else {
+           throw (t ()->dump_string_short () + uErrorBadParam);
+       }
+    }
+    if (evkw (3, t)) {                 // 3:proxy-user
+       if (isCons (t ())) {
+           obj.proxyid = to_string (t ()->car ());
+           obj.proxypw = to_string (t ()->cdr ());
+       } else {
+           throw (t ()->dump_string_short () + uErrorBadParam);
+       }
+    }
+    evkw (4, errfn);                   // 4:on-error
+    evkw_bool (5, obj.fnoverify);      // 5:no-verify
+
+    if (! checkHostname (obj.host))
+       throw (obj.host + ": bad hostname.");
+    if (obj.port <= 0 || obj.port >= 65536)
+       throw (to_ustring (obj.port) + ": bad port number.");
+
+    //****** proxy-userが未実装
+    obj.newSession (mlenv);
+    if (obj.proxyhost.length () > 0)
+       obj.session->setProxy (obj.proxyhost, obj.proxyport);
+    if (obj.fnoverify)
+       obj.session->setNoVerify ();
+
+    mlenv->setMStack (&obj);
+    try {
+       ans = progn (rest, mlenv);
+    } catch (ustring& msg) {
+       if (errfn ()) {
+           onErrorFn (errfn (), mlenv);
+       } else {
+           throw (msg);
+       }
+    }
+    mlenv->stopBreak (cell->car ());
+
+    return ans.release ();
+}
+
+static void  buildFileList (NeonQuery* query, MNode* postFileSerial, MNode* postFileNamed, MNode* postFileStatic, MlEnv* mlenv) {
+    MNode*  e;
+    MNode*  a;
+    ustring  name;
+    ustring  val;
+    ustring  path;
+
+    e = postFileSerial;
+    if (isCons (e)) {
+       while (e) {
+           if ((a = e->car ()) && isCons (a)) {
+               name = to_string (a->car ());
+               val = to_string (a->cdr ());
+               path = mlenv->env->path_store_file (val);
+               query->qbody->pushFile (name, path);
+           }
+           nextNode (e);
+       }
+    }
+    e = postFileNamed;
+    if (isCons (e)) {
+       while (e) {
+           if ((a = e->car ()) && isCons (a)) {
+               name = to_string (a->car ());
+               val = to_string (a->cdr ());
+               path = mlenv->env->path_storage_file (val);
+               query->qbody->pushFile (name, path);
+           }
+           nextNode (e);
+       }
+    }
+    e = postFileStatic;
+    if (isCons (e)) {
+       while (e) {
+           if ((a = e->car ()) && isCons (a)) {
+               name = to_string (a->car ());
+               val = to_string (a->cdr ());
+               path = mlenv->env->path_static_file (val);
+               query->qbody->pushFile (name, path);
+           }
+           nextNode (e);
+       }
+    }
+}
+
+/*DOC:
+===subfunctions of $neon===
+
+*/
+static MNode*  checkConsList (MNode* e) {
+    MNodeList  ans;
+    MNode*  a;
+    if (isCons (e)) {
+       while (e) {
+           if (isCons ((a = e->car ())))
+               ans.append (a);
+           nextNode (e);
+       }
+    }
+    return ans.release ();
+}
+
+/*DOC:
+====http-request====
+ (http-request PATH [#get] [#post] [#put] [#delete] [#head] [#file]
+       [:basic-user '(ID . PASSWORD)]
+       [:query '((NAME . VALUE) ...)] [:get-query '((NAME . VALUE) ...)] [#no-encode]
+       [:post-file-serial '((NAME . FILE) ...)]
+       [:post-file-named '((NAME . FILE) ...)]
+       [:post-file-static '((NAME . FILE) ...)]
+       [:raw-query TEXT] [:raw-file-serial FILE] [:raw-file-named FILE] [:raw-file-static FILE]
+       [:query-type MIMETYPE]
+       [:cookie '((NAME . VALUE) ...)] [:header '((NAME . VALUE) ...)]
+       [#sjis] [#euc-jp] [:iconv NAME]
+*/
+//#SFUNC       http-request    ml_neon_http_request
+MNode*  ml_neon_http_request (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+    MNode*  arg = cell->cdr ();
+    MLNeon*  obj = (MLNeon*)mobj;
+    MNodePtr  postFileSerial;
+    MNodePtr  postFileNamed;
+    MNodePtr  postFileStatic;
+    bool  f;
+    MNodePtr  t;
+    std::vector<MNode*>  params;
+    std::vector<MNode*>  keywords;
+    static paramList  kwlist[] = {
+       {CharConst ("get"), true},                      // 0
+       {CharConst ("post"), true},                     // 1
+       {CharConst ("put"), true},                      // 2
+       {CharConst ("delete"), true},                   // 3
+       {CharConst ("head"), true},                     // 4
+       {CharConst ("file"), true},                     // 5
+       {CharConst ("basic-user"), false},              // 6
+       {CharConst ("query"), false},                   // 7
+       {CharConst ("get-query"), false},               // 8
+       {CharConst ("post-file-serial"), false},        // 9
+       {CharConst ("post-file-named"), false},         // 10
+       {CharConst ("post-file-static"), false},        // 11
+       {CharConst ("raw-query"), false},               // 12
+       {CharConst ("raw-file-serial"), false},         // 13
+       {CharConst ("raw-file-named"), false},          // 14
+       {CharConst ("raw-file-static"), false},         // 15
+       {CharConst ("query-type"), false},              // 16
+       {CharConst ("cookie"), false},                  // 17
+       {CharConst ("header"), false},                  // 18
+       {CharConst ("sjis"), true},                     // 19
+       {CharConst ("euc-jp"), true},                   // 20
+       {CharConst ("iconv"), false},                   // 21
+       {NULL, 0, 0}
+    };
+
+    setParams (arg, 1, &params, kwlist, &keywords, NULL);
+    obj->query->path = eval_str (params[0], mlenv);
+    if (evkw_bool (0, f))      // 0:get
+       obj->query->method = NeonQuery::METHOD_GET;
+    if (evkw_bool (1, f))      // 1:post
+       obj->query->method = NeonQuery::METHOD_POST;
+    if (evkw_bool (2, f))      // 2:put
+       obj->query->method = NeonQuery::METHOD_PUT;
+    if (evkw_bool (3, f))      // 3:delete
+       obj->query->method = NeonQuery::METHOD_DELETE;
+    if (evkw_bool (4, f))      // 4:head
+       obj->query->method = NeonQuery::METHOD_HEAD;
+    if (evkw_bool (5, f))      // 5:file / pseudo method
+       obj->query->method = NeonQuery::METHOD_FILE;
+    if (evkw (6, t)) {         // 6:basic-user
+       if (isCons (t ())) {
+           obj->query->basicID = to_string (t ()->car ());
+           obj->query->basicPW = to_string (t ()->cdr ());
+       } else {
+           throw (t ()->dump_string_short () + uErrorBadParam);
+       }
+    }
+    if (evkw (7, t))                           // 7:query
+       obj->query->queryParam = checkConsList (t ());
+    if (evkw (8, t))                           // 8:get-query
+       obj->query->queryParamGet = checkConsList (t ());
+    if (evkw (9, t))                           // 9:post-file-serial
+       postFileSerial = checkConsList (t ());
+    if (evkw (10, t))                          // 10:post-file-named
+       postFileNamed = checkConsList (t ());
+    if (evkw (11, t))                          // 11:post-file-static
+       postFileStatic = checkConsList (t ());
+    if (evkw (12, t))          // 12:raw-query
+       obj->query->rawquery.srcText (to_string (t ()));
+    if (evkw (13, t))          // 13:raw-file-serial
+       obj->query->rawquery.srcSerial (to_string (t ()));
+    if (evkw (14, t))          // 14:raw-file-named
+       obj->query->rawquery.srcNamed (to_string (t ()));
+    if (evkw (15, t))          // 15:raw-file-static
+       obj->query->rawquery.srcStatic (to_string (t ()));
+    if (evkw (16, t)) {                // 16:query-type
+       obj->query->querytype = to_string (t ());
+       if (!checkASCII (obj->query->querytype))
+           throw (obj->query->querytype + ustring (CharConst (": bad type")));
+    }
+    evkw (17, obj->query->cookie);     // 17:cookie
+    evkw (18, obj->query->header);     // 18:header
+    if (evkw_bool (19, f)) {           // 19:sjis
+       obj->query->setIConv ("SHIFT_JIS");
+    } else if (evkw_bool (20, f)) {    // 20:euc-jp
+       obj->query->setIConv ("EUC-JP");
+    } else if (evkw (21, t)) { // 21:iconv
+       ustring  code = to_string (t ());
+       uregex  re ("^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$");
+       umatch  m;
+       if (usearch (code, m, re)) {
+           obj->query->setIConv (code.c_str ());
+       } else {
+           throw (ustring (code).append (CharConst (": unknown encoding.")));
+       }
+    }
+
+    if (obj->query->method == NeonQuery::METHOD_FILE)
+       buildFileList (obj->query.get (), postFileSerial (), postFileNamed (), postFileStatic (), mlenv);
+
+    obj->query->submit ();
+
+    return NULL;
+}
+
+/*DOC:
+====http-status====
+ (http-status) -> NUMBER
+
+*/
+//#SFUNC       http-status     ml_neon_http_status
+MNode*  ml_neon_http_status (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+    MNode*  arg = cell->cdr ();
+    MLNeon*  obj = (MLNeon*)mobj;
+    
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    return newMNode_num (obj->query->getStatus ());
+}
+
+/*DOC:
+====http-response====
+ (http-response) -> STRING
+
+*/
+//#SFUNC       http-response   ml_neon_http_response
+MNode*  ml_neon_http_response (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+    MNode*  arg = cell->cdr ();
+    MLNeon*  obj = (MLNeon*)mobj;
+    ustring  ans;
+
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    std::stringstream  ostr;
+    MotorOutputOStream  out (&ostr);
+    obj->query->readBody (&out);
+    return newMNode_str (new ustring (fixUTF8 (obj->query->rcv (ostr.str ()))));
+}
+
+/*DOC:
+====http-response-file====
+ (http-response-file FILENAME) -> NIL
+
+*/
+//#SFUNC       http-response-file      ml_neon_http_response_file
+MNode*  ml_neon_http_response_file (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+    MNode*  arg = cell->cdr ();
+    MLNeon*  obj = (MLNeon*)mobj;
+    ustring  name;
+    ustring  tgt, tmp;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+    name = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    tgt = mlenv->env->path_store_file (name);
+    tmp.assign (tgt).append (CharConst ("-tmp")).append (to_ustring (getpid ()));
+    {
+       std::ofstream  stream;
+       MotorOutputOStream  out (&stream);
+       stream.open (tmp.c_str (), std::ios_base::out | std::ios_base::binary);
+       obj->query->readBody (&out);
+       stream.close ();
+       rename (tmp.c_str (), tgt.c_str ());
+    }
+
+    return NULL;
+}
+
+/*DOC:
+====http-response-output====
+ (http-response-output [#continue | :continue BOOL]) -> NIL
+
+*/
+//#SFUNC       http-response-output    ml_neon_http_response_output
+MNode*  ml_neon_http_response_output (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+    MNode*  arg = cell->cdr ();
+    MLNeon*  obj = (MLNeon*)mobj;
+    bool  cflag = false;
+    std::vector<MNode*>  params;
+    std::vector<MNode*>  keywords;
+    static paramList  kwlist[] = {
+       {CharConst ("continue"), true},
+       {NULL, 0, 0}
+    };
+
+    setParams (arg, 0, &params, kwlist, &keywords, NULL);
+    if (keywords[0] && eval_bool (keywords[0], mlenv))
+       cflag = true;
+
+    if (! mlenv->env->responseDone)
+       mlenv->env->standardResponse_html ();
+    obj->query->readBody (mlenv->env->output);
+
+    if (! cflag)
+       mlenv->breakProg ();
+
+    return NULL;
+}
+
+/*DOC:
+====get-cookie====
+ (get-cookie NAME) -> STRING
+
+*/
+//#SFUNC       get-cookie      ml_neon_get_cookie
+MNode*  ml_neon_get_cookie (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+    MNode*  arg = cell->cdr ();
+    MLNeon*  obj = (MLNeon*)mobj;
+    ustring  name;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+    name = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    ustring  ans = obj->query->getResponseCookie (name);
+    if (ans.length () > 0) {
+       return newMNode_str (new ustring (ans));
+    } else {
+       return NULL;
+    }
+}
+
+/*DOC:
+====get-cookie-all====
+ (get-cookie-all) -> LIST of (NAME . VALUE)
+
+*/
+//#SFUNC       get-cookie-all  ml_neon_get_cookie_all
+MNode*  ml_neon_get_cookie_all (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+    MNode*  arg = cell->cdr ();
+    MLNeon*  obj = (MLNeon*)mobj;
+
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    return obj->query->getResponseCookieAll ();
+}
+
+/*DOC:
+====http-content-type====
+ (http-content-type) -> STRING
+
+*/
+//#SFUNC       http-content-type       ml_neon_http_content_type
+MNode*  ml_neon_http_content_type (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+    MNode*  arg = cell->cdr ();
+    MLNeon*  obj = (MLNeon*)mobj;
+    ustring  u = obj->query->getResponseHeader ("content-type");
+
+    if (u.length () > 0) {
+       uiterator  b, e, m;
+       b = u.begin ();
+       e = u.end ();
+       if (splitChar (b, e, ';', m)) {
+           return newMNode_str (new ustring (toLower (b, m)));
+       } else {
+           return newMNode_str (new ustring (toLower (b, e)));
+       }
+    } else {
+       return NULL;
+    }
+}
+
+/*DOC:
+====http-get-header====
+ (http-get-header NAME) -> STRING
+
+*/
+//#SFUNC       http-get-header ml_neon_http_get_header
+MNode*  ml_neon_http_get_header (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+    MNode*  arg = cell->cdr ();
+    MLNeon*  obj = (MLNeon*)mobj;
+    ustring  name;
+    ustring  u;
+
+    if (! arg)
+       throw (uErrorWrongNumber);
+    name = eval_str (arg->car (), mlenv);
+    nextNode (arg);
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    u = obj->query->getResponseHeader (name.c_str ());
+    if (u.length () > 0) {
+       return newMNode_str (new ustring (u));
+    } else {
+       return NULL;
+    }
+}
+
+/*DOC:
+====http-get-header-all====
+ (http-get-header-all) -> LIST of (NAME . VALUE)
+
+*/
+//#SFUNC       http-get-header-all     ml_neon_http_get_header_all
+MNode*  ml_neon_http_get_header_all (MNode* cell, MlEnv* mlenv, MLFunc* mobj) {
+    MNode*  arg = cell->cdr ();
+    MLNeon*  obj = (MLNeon*)mobj;
+
+    if (arg)
+       throw (uErrorWrongNumber);
+
+    return obj->query->getResponseHeaderAll ();
+}
+
diff --git a/modules/ml-neon.h b/modules/ml-neon.h
new file mode 100644 (file)
index 0000000..ecfccba
--- /dev/null
@@ -0,0 +1,202 @@
+#ifndef ML_NEON_H
+#define ML_NEON_H
+
+#include "ml.h"
+#include "ml-id.h"
+#include "ml-store.h"
+#include "http-iconv.h"
+#include "util_string.h"
+#include "filemacro.h"
+#include <boost/scoped_ptr.hpp>
+#include <neon/ne_session.h>
+#include <neon/ne_request.h>
+#include <vector>
+
+class  MNode;
+class  MlEnv;
+class  NeonQuery;
+
+class  NeonPostBodyProvider {
+ public:
+    NeonQuery*  query;
+    std::vector<std::pair<ustring, ustring> >  postFile;
+    size_t  paramsLen;
+    ustring  separator;
+    enum {
+       S_NONE,
+       S_TEXT,
+       S_FILEHEAD,
+       S_FILEBODY,
+       S_FILETERM,
+       S_TAIL,
+       S_DONE,
+    }  state;
+    MNode*  tp;
+    std::vector<std::pair<ustring, ustring> >::iterator  bp;
+    std::vector<std::pair<ustring, ustring> >::iterator  ep;
+    ustring  ubuf;
+    off_t  offset;
+    FileMacro  fd;
+
+    NeonPostBodyProvider (NeonQuery* _query) {
+       query = _query;
+       paramsLen = 0;
+       makeSeparator ();
+       state = S_NONE;
+       tp = NULL;
+       offset = 0;
+    };
+    virtual  ~NeonPostBodyProvider () {};
+
+    void  pushFile (const ustring& name, const ustring& path);
+    void  makeSeparator ();
+    ustring  separatorLine ();
+    ustring  separatorHeader ();
+    ustring  textSeparator (const ustring& name);
+    ustring  fileSeparator (const ustring& name, const ustring& filename);
+    ustring  tailSeparator ();
+    ne_off_t  calcLength ();
+    char*  bodyProvider (char* buffer, size_t buflen);
+ private:
+    ssize_t  bodyProviderText (char* buffer, size_t buflen);
+};
+
+class  NeonSession {
+ public:
+    typedef enum {
+       PROTO_NONE,
+       PROTO_HTTP,
+       PROTO_HTTPS,
+    }  proto_t;
+
+    ne_session*  session;
+    proto_t  proto;
+
+    NeonSession (proto_t _proto, const ustring& host, unsigned int port);
+    virtual  ~NeonSession ();
+    
+    virtual ne_session&  operator * () const {
+       return *session;
+    };
+    virtual ne_session*  operator -> () const {
+       return session;
+    };
+    virtual ne_session*  get () const {
+       return session;
+    };
+    virtual void  setNoVerify ();
+    virtual void  setProxy (const ustring& host, int port);
+};
+
+class  NeonQuery {
+ public:
+    typedef enum {
+       METHOD_NONE,
+       METHOD_GET,
+       METHOD_POST,
+       METHOD_PUT,
+       METHOD_DELETE,
+       METHOD_HEAD,
+       METHOD_FILE,            /* pseudo method */
+    }  method_t;
+
+    ne_request*  req;
+    ne_session*  session;
+    method_t  method;
+    ustring  path;
+    ustring  basicID;
+    ustring  basicPW;
+    MNodePtr  queryParam;
+    MNodePtr  queryParamGet;
+    StoreType  rawquery;
+    ustring  querytype;                /* リクエストヘッダのcontent-type */
+    MNodePtr  cookie;
+    MNodePtr  header;
+    boost::scoped_ptr<NeonPostBodyProvider>  qbody;
+    boost::scoped_ptr<UIConv>  cv_in;
+    boost::scoped_ptr<UIConv>  cv_out;
+    enum {
+       MODE_SETUP,
+       MODE_DISPATCHED,
+       MODE_RECEIVED,
+    }  mode;
+    ustring  errorMsg;
+    std::vector<CookieInfo>  replyCookie;
+    bool  replyCookieDone;
+
+    NeonQuery (ne_session* _session, MlEnv* _mlenv): rawquery (_mlenv) {
+       session = _session;
+       req = NULL;
+       method = METHOD_GET;
+       mode = MODE_SETUP;
+       replyCookieDone = false;
+       qbody.reset (new NeonPostBodyProvider (this));
+    };
+    virtual  ~NeonQuery () {
+       closeReq ();
+    };
+
+    virtual void  closeReq ();
+    virtual void  setIConv (const char* name);
+    virtual void  submit ();
+    virtual void  readBody (MotorOutput* out);
+    virtual int  getStatus ();
+    virtual ustring  cv (const ustring& src);
+    virtual ustring  rcv (const ustring& src);
+    virtual ustring  getResponseHeader (const char* name);
+    virtual MNode*  getResponseHeaderAll ();
+    virtual ustring  getResponseCookie (const ustring& name);
+    virtual MNode*  getResponseCookieAll ();
+ private:
+    virtual const char*  methodStr ();
+    virtual ustring  buildGetQuery ();
+    virtual void  buildQuery (MNode* e, ustring& out);
+    virtual ustring  buildMimeSeparator_text (const ustring& name);
+    virtual ustring  buildMimeSeparator_file (const ustring& name, const ustring& filename);
+    virtual ustring  filterPath ();
+    virtual void  buildCookie ();
+    virtual void  buildHeader ();
+    virtual void  buildBasicAuthHeader ();
+    virtual void  setFormType ();
+    virtual void  setFormType_urlencoded ();
+    virtual void  setFormType_formdata ();
+    virtual void  parseCookie ();
+    virtual void  setRawQuery (FileMacro& fd);
+};
+
+class  MLNeon: public MLFunc {
+ public:
+    ustring  host;
+    int  port;
+    NeonSession::proto_t  proto;
+    ustring  proxyhost;
+    int  proxyport;
+    ustring  proxyid;
+    ustring  proxypw;
+    bool  fnoverify;
+    boost::scoped_ptr<NeonSession>  session;
+    boost::scoped_ptr<NeonQuery>  query;
+
+    MLNeon (MlEnv* _mlenv): MLFunc (cMLNeonID, _mlenv) {
+       proto = NeonSession::PROTO_HTTP;
+       proxyport = 0;
+       fnoverify = false;
+    };
+    virtual  ~MLNeon () {};
+
+    virtual void  newSession (MlEnv* mlenv);
+};
+
+MNode*  ml_neon (MNode* cell, MlEnv* mlenv);
+MNode*  ml_neon_http_request (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode*  ml_neon_http_status (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode*  ml_neon_http_response (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode*  ml_neon_http_response_file (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode*  ml_neon_http_response_output (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode*  ml_neon_get_cookie (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode*  ml_neon_get_cookie_all (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode*  ml_neon_http_content_type (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode*  ml_neon_http_get_header (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+MNode*  ml_neon_http_get_header_all (MNode* cell, MlEnv* mlenv, MLFunc* mobj);
+
+#endif /* ML_NEON_H */
index 08139c1..68adc98 100644 (file)
@@ -56,14 +56,15 @@ MNode*  ml_hmac_sub (const EVP_MD* fn, MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
     ustring  key;
     ustring  text;
-    StoreType  keyType;
-    StoreType  msgType;
+    StoreType  keyType (mlenv);
+    StoreType  msgType (mlenv);
     enum {
        ENC_HEX,
        ENC_BASE64,
     }  encode = ENC_HEX;
     ustring  ans;
     MNodePtr  t;
+    bool  f;
     unsigned char  md[EVP_MAX_MD_SIZE];
     unsigned int  md_len = 0;
     std::vector<MNode*>  params;
@@ -85,9 +86,9 @@ MNode*  ml_hmac_sub (const EVP_MD* fn, MNode* cell, MlEnv* mlenv) {
     setParams (arg, 2, &params, kwlist, &keywords, NULL);
     key = eval_str (params[0], mlenv);
     text = eval_str (params[1], mlenv);
-    if (keywords[0] && eval_bool (keywords[0], mlenv))
+    if (evkw_bool (0, f))
        encode = ENC_HEX;
-    if (keywords[1] && eval_bool (keywords[1], mlenv))
+    if (evkw_bool (1, f))
        encode = ENC_BASE64;
     if (evkw (2, t))
        keyType.srcSerial (t.to_string ());     // :key-serial
@@ -106,10 +107,10 @@ MNode*  ml_hmac_sub (const EVP_MD* fn, MNode* cell, MlEnv* mlenv) {
     if (evkw (9, t))
        msgType.srcText (t.to_string ());       // :message-text
     if (keyType ())
-       key = keyType.read (mlenv);
+       key = keyType.read ();
 
     if (msgType.isText ()) {
-       text = msgType.read (mlenv);
+       text = msgType.read ();
        HMAC (fn, key.c_str (), key.length (), uchar_type (text.c_str ()), text.length (), md, &md_len);
     } else if (! msgType ()) {
        HMAC (fn, key.c_str (), key.length (), uchar_type (text.c_str ()), text.length (), md, &md_len);
@@ -118,7 +119,7 @@ MNode*  ml_hmac_sub (const EVP_MD* fn, MNode* cell, MlEnv* mlenv) {
        FileMacro  f;
        ssize_t  len;
        u_char  buf[S4K];
-       if (f.openRead (msgType.src (mlenv).c_str ())) {
+       if (f.openRead (msgType.src ().c_str ())) {
            HMAC_Init (&hmac, key.c_str (), key.length (), fn);
            while ((len = f.read (buf, S4K)) > 0) {
                HMAC_Update (&hmac, buf, len);
@@ -142,91 +143,6 @@ MNode*  ml_hmac_sub (const EVP_MD* fn, MNode* cell, MlEnv* mlenv) {
     return newMNode_str (new ustring (ans));
 }
 
-#if 0
-/*--DOC:
-===hmac-sha256===
- (hmac-sha256 KEY_STRING TEXT [#hex] [#base64]) => STRING
- (hmac-sha256 [:key-serial FILENAME | :key-named FILENAME | :key-static FILENAME | :key-text TEXT] [:message-serial FILENAME | :message-named FILENAME | :message-static FILENAME | :message-text TEXT] [#hex] [#base64]) => STRING
-
-*/
-//--#AFUNC     hmac-sha256     ml_hmac_sha256
-//--#WIKIFUNC  hmac-sha256
-MNode*  ml_hmac_sha256 (MNode* cell, MlEnv* mlenv) {
-    MNode*  arg = cell->cdr ();
-    ustring  key;
-    ustring  text;
-    StoreType  keyType;
-    StoreType  msgType;
-    enum {
-       ENC_HEX,
-       ENC_BASE64,
-    }  encode = ENC_HEX;
-    ustring  ans;
-    MNodePtr  t;
-    unsigned char  md[EVP_MAX_MD_SIZE];
-    unsigned int  md_len;
-    std::vector<MNode*>  params;
-    std::vector<MNode*>  keywords;
-    static paramList  kwlist[] = {
-       {CharConst ("hex"), true},              // 0
-       {CharConst ("base64"), true},           // 1
-       {CharConst ("key-serial"), false},      // 2
-       {CharConst ("key-named"), false},       // 3
-       {CharConst ("key-static"), false},      // 4
-       {CharConst ("key-text"), false},        // 5
-       {CharConst ("message-serial"), false},  // 6
-       {CharConst ("message-named"), false},   // 7
-       {CharConst ("message-static"), false},  // 8
-       {CharConst ("message-text"), false},    // 9
-       {NULL, 0, 0}
-    };
-
-    setParams (arg, 2, &params, kwlist, &keywords, NULL);
-    key = eval_str (params[0], mlenv);
-    text = eval_str (params[1], mlenv);
-    if (keywords[0] && eval_bool (keywords[0], mlenv))
-       encode = ENC_HEX;
-    if (keywords[1] && eval_bool (keywords[1], mlenv))
-       encode = ENC_BASE64;
-    if (evkw (2, t))
-       keyType.srcSerial (t.to_string ());     // :key-serial
-    if (evkw (3, t))
-       keyType.srcNamed (t.to_string ());      // :key-named
-    if (evkw (4, t))
-       keyType.srcStatic (t.to_string ());     // :key-static
-    if (evkw (5, t))
-       keyType.srcText (t.to_string ());       // :key-text
-    if (evkw (6, t))
-       msgType.srcSerial (t.to_string ());     // :message-serial
-    if (evkw (7, t))
-       msgType.srcNamed (t.to_string ());      // :message-named
-    if (evkw (8, t))
-       msgType.srcStatic (t.to_string ());     // :message-static
-    if (evkw (9, t))
-       msgType.srcText (t.to_string ());       // :message-text
-    if (keyType ())
-       key = keyType.read (mlenv);
-    if (msgType ())
-       text = msgType.read (mlenv);
-
-    HMAC (EVP_sha256 (), key.c_str (), key.length (), uchar_type (text.c_str ()), text.length (), md, &md_len);
-
-    ans.assign (char_type (md), md_len);
-    switch (encode) {
-    case ENC_HEX:
-       ans = hexEncode (ans);
-       break;
-    case ENC_BASE64:
-       ans = base64Encode (ans.begin (), ans.end ());
-       break;
-    default:
-       assert (0);
-    }
-
-    return newMNode_str (new ustring (ans));
-}
-#endif
-
 static ustring  fn_md5 (const ustring& text) {
     MD5_CTX  ctx;
     u_char  buf[16];
@@ -332,13 +248,14 @@ MNode*  ml_sha256 (MNode* cell, MlEnv* mlenv) {
 static MNode*  ml_hash_sub (ustring fn_text (const ustring& text), ustring fn_file (FileMacro& f), MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
     ustring  text;
-    StoreType  msgType;
+    StoreType  msgType (mlenv);
     enum {
        ENC_HEX,
        ENC_BASE64,
     }  encode = ENC_HEX;
     ustring  ans;
     MNodePtr  t;
+    bool  f;
     std::vector<MNode*>  keywords;
     static paramList  kwlist[] = {
        {CharConst ("hex"), true},              // 0
@@ -351,9 +268,9 @@ static MNode*  ml_hash_sub (ustring fn_text (const ustring& text), ustring fn_fi
     };
 
     setParams (arg, 0, NULL, kwlist, &keywords, NULL);
-    if (keywords[0] && eval_bool (keywords[0], mlenv)) // hex
+    if (evkw_bool (0, f))      // 0:hex
        encode = ENC_HEX;
-    if (keywords[1] && eval_bool (keywords[1], mlenv)) // base64
+    if (evkw_bool (1, f))      // 1:base64
        encode = ENC_BASE64;
     if (evkw (2, t))
        msgType.srcSerial (t.to_string ());     // :message-serial
@@ -365,13 +282,13 @@ static MNode*  ml_hash_sub (ustring fn_text (const ustring& text), ustring fn_fi
        msgType.srcText (t.to_string ());       // :message-text
 
     if (msgType.isText ()) {
-       text = msgType.read (mlenv);
+       text = msgType.read ();
        ans = fn_text (text);
     } else if (! msgType ()) {
        // error
     } else {
        FileMacro  f;
-       if (f.openRead (msgType.src (mlenv).c_str ())) {
+       if (f.openRead (msgType.src ().c_str ())) {
            ans = fn_file (f);
        }
     }
@@ -398,6 +315,7 @@ static MNode*  ml_hash_string (MNode* cell, MlEnv* mlenv, ustring fn (const ustr
        ENC_HEX,
        ENC_BASE64,
     }  encode = ENC_HEX;
+    bool  f;
     ustring  ans;
     std::vector<MNode*>  params;
     std::vector<MNode*>  keywords;
@@ -409,9 +327,9 @@ static MNode*  ml_hash_string (MNode* cell, MlEnv* mlenv, ustring fn (const ustr
 
     setParams (arg, 1, &params, kwlist, &keywords, NULL);
     text = eval_str (params[0], mlenv);
-    if (keywords[0] && eval_bool (keywords[0], mlenv)) // hex
+    if (evkw_bool (0, f))      // hex
        encode = ENC_HEX;
-    if (keywords[1] && eval_bool (keywords[1], mlenv)) // base64
+    if (evkw_bool (1, f))      // base64
        encode = ENC_BASE64;
 
     ans = fn (text);
@@ -432,11 +350,12 @@ static MNode*  ml_hash_file (MNode* cell, MlEnv* mlenv, ustring fn (FileMacro& f
     MNode*  arg = cell->cdr ();
     ustring  name;
     ustring  src;
-    StoreType  storetype;
+    StoreType  storetype (mlenv);
     enum {
        ENC_HEX,
        ENC_BASE64,
     }  encode = ENC_HEX;
+    bool  f;
     ustring  ans;
     std::vector<MNode*>  params;
     std::vector<MNode*>  keywords;
@@ -451,17 +370,17 @@ static MNode*  ml_hash_file (MNode* cell, MlEnv* mlenv, ustring fn (FileMacro& f
 
     setParams (arg, 1, &params, kwlist, &keywords, NULL);
     name = eval_str (params[0], mlenv);
-    if (keywords[0] && eval_bool (keywords[0], mlenv)) // serial
+    if (evkw_bool (0, f))      // serial
        storetype.setSerial ();
-    if (keywords[1] && eval_bool (keywords[1], mlenv)) // named
+    if (evkw_bool (1, f))      // named
        storetype.setNamed ();
-    if (keywords[2] && eval_bool (keywords[2], mlenv)) // static
+    if (evkw_bool (2, f))      // static
        storetype.setStatic ();
-    if (keywords[3] && eval_bool (keywords[3], mlenv)) // hex
+    if (evkw_bool (3, f))      // hex
        encode = ENC_HEX;
-    if (keywords[4] && eval_bool (keywords[4], mlenv)) // base64
+    if (evkw_bool (4, f))      // base64
        encode = ENC_BASE64;
-    src = storetype.src (mlenv, name);
+    src = storetype.src (name);
 
     if (src.length () > 0) {
        FileMacro  f;
@@ -566,6 +485,7 @@ MNode*  ml_hmac_sha256_n_string (MNode* cell, MlEnv* mlenv) {
     }  encode = ENC_HEX;
     unsigned char  md[EVP_MAX_MD_SIZE];
     unsigned int  md_len;
+    bool  f;
     std::vector<MNode*>  params;
     std::vector<MNode*>  keywords;
     static paramList  kwlist[] = {
@@ -576,9 +496,9 @@ MNode*  ml_hmac_sha256_n_string (MNode* cell, MlEnv* mlenv) {
 
     setParams (arg, 1, &params, kwlist, &keywords, &rest);
     key = eval_str (params[0], mlenv);
-    if (keywords[0] && eval_bool (keywords[0], mlenv)) // hex
+    if (evkw_bool (0, f))      // hex
        encode = ENC_HEX;
-    if (keywords[1] && eval_bool (keywords[1], mlenv)) // base64
+    if (evkw_bool (1, f))      // base64
        encode = ENC_BASE64;
 
     while (rest) {
index 78fb9eb..6008357 100644 (file)
@@ -185,7 +185,7 @@ static void  sendmail_file (const ustring& file, const ustring& faddr, std::vect
 //#AFUNC       mail    ml_mail
 MNode*  ml_mail (MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
-    StoreType  storetype;      // static
+    StoreType  storetype (mlenv);      // static
     ustring  faddr;
     std::vector<ustring>  taddr;
     MNodePtr  tolist;
@@ -248,7 +248,7 @@ MNode*  ml_mail (MNode* cell, MlEnv* mlenv) {
 
     if (faddr.size () > 0 && taddr.size () > 0) {
        ustring  f;
-       f = storetype.src (mlenv);
+       f = storetype.src ();
        sendmail_file (f, faddr, taddr, mlenv);
     } else {
        if (faddr.size () == 0)
@@ -275,7 +275,7 @@ MNode*  ml_sendmail (MNode* cell, MlEnv* mlenv) {
     ustring  faddr;
     std::vector<ustring>  taddr;
     MNodePtr  tolist;
-    StoreType  storetype;      // static
+    StoreType  storetype (mlenv);      // static
     ustring  u;
     MNodePtr  t;
     std::vector<MNode*>  params;
@@ -335,7 +335,7 @@ MNode*  ml_sendmail (MNode* cell, MlEnv* mlenv) {
            *mlenv->log << "To address is undefined or illegal.\n";
     } else {
        ustring  text;
-       text = storetype.read (mlenv);
+       text = storetype.read ();
        sendmail (text, faddr, taddr, mlenv);
     }
 
index c7f170e..6d93395 100644 (file)
@@ -53,7 +53,8 @@ static MNode*  listFiles (const ustring& dirpath) {
 }
 
 //============================================================
-StoreType::StoreType (MlEnv* mlenv) {
+StoreType::StoreType (MlEnv* _mlenv) {
+    mlenv = _mlenv;
     if (mlenv->env->storagedir.length () > 0) {
        type = F_NAMED;
     } else if (mlenv->env->storedir.length () > 0) {
@@ -63,7 +64,7 @@ StoreType::StoreType (MlEnv* mlenv) {
     }
 }
 
-const ustring  StoreType::src (MlEnv* mlenv, const ustring& name) {
+const ustring  StoreType::src (const ustring& name) {
     if (name.size () == 0)
        throw (uErrorFilenameEmpty);
     switch (type) {
@@ -78,16 +79,16 @@ const ustring  StoreType::src (MlEnv* mlenv, const ustring& name) {
     }
 }
 
-const ustring  StoreType::src (MlEnv* mlenv) {
-    return src (mlenv, param);
+const ustring  StoreType::src () {
+    return src (param);
 }
 
-ustring  StoreType::read (MlEnv* mlenv) {
+ustring  StoreType::read () {
     if (type == F_TEXT) {
        return param;
     } else {
        ustring  ans;
-       if (readFile (src (mlenv, param), ans, cPOSTLIMITHARD)) {
+       if (readFile (src (param), ans, cPOSTLIMITHARD)) {
            if (encoding.size () > 0 && ans.size () > 0) {
                UIConv  cd (kCODE_UTF8, encoding.c_str ());
                ans = cd.cv (ans);
@@ -576,6 +577,7 @@ MNode*  ml_read_file (MNode* cell, MlEnv* mlenv) {
     ustring  encoding;
     ustring  data;
     MNodePtr  t;
+    bool  f;
     std::vector<MNode*>  keywords;
     static paramList  kwlist[] = {
        {CharConst ("code"), false},            // 0
@@ -607,14 +609,14 @@ MNode*  ml_read_file (MNode* cell, MlEnv* mlenv) {
     if (evkw (3, t))                           // :source-static
        storetype.srcStatic (t.to_string ());
 #ifdef SOURCEFILECOMPAT
-    if (keywords[4] && eval_bool (keywords[4], mlenv)) // serial
+    if (evkw_bool (4, f))      // serial
        storetype.setSerial ();
-    if (keywords[5] && eval_bool (keywords[5], mlenv)) // named
+    if (evkw_bool (5, f))      // named
        storetype.setNamed ();
-    if (keywords[6] && eval_bool (keywords[6], mlenv)) // static
+    if (evkw_bool (6, f))      // static
        storetype.setStatic ();
 #endif
-    src = storetype.src (mlenv);
+    src = storetype.src ();
 
     if (readFile (src, data, cPOSTLIMITHARD)) {
        if (encoding.size () > 0 && data.size () > 0) {
@@ -643,6 +645,7 @@ MNode*  ml_write_file (MNode* cell, MlEnv* mlenv) {
     bool  fcrlf = false;
     ustring  data;
     MNodePtr  t;
+    bool  f;
     std::vector<MNode*>  params;
     std::vector<MNode*>  keywords;
     static paramList  kwlist[] = {
@@ -658,13 +661,12 @@ MNode*  ml_write_file (MNode* cell, MlEnv* mlenv) {
     data = eval_str (params[1], mlenv);
     if (evkw (0, t))
        encoding = to_string (t ());
-    if (keywords[1])
-       fcrlf = eval_bool (keywords[1], mlenv);
-    if (keywords[2] && eval_bool (keywords[2], mlenv)) // serial
+    evkw_bool (1, fcrlf);
+    if (evkw_bool (2, f))      // serial
        storetype.setSerial ();
-    if (keywords[3] && eval_bool (keywords[3], mlenv)) // named
+    if (evkw_bool (3, f))      // named
        storetype.setNamed ();
-    tgt = storetype.src (mlenv);
+    tgt = storetype.src ();
 
     if (encoding.size () > 0 && data.size () > 0) {
        UIConv  cd (encoding.c_str (), kCODE_UTF8);
@@ -765,8 +767,7 @@ MNode*  ml_datastore_progn (MNode* cell, MlEnv* mlenv) {
 
     setParams (arg, 1, &params, kwlist, &keywords, &rest);
     name = eval_str (params[0], mlenv);
-    if (keywords[0])
-       errfn = eval (keywords[0], mlenv);
+    evkw (0, errfn);
 
     try {
        oname = mlenv->env->datastore;
@@ -831,8 +832,7 @@ MNode*  ml_set_storage (MNode* cell, MlEnv* mlenv) {
 
     setParams (arg, 1, &params, kwlist, &keywords, NULL);
     name = eval_str (params[0], mlenv);
-    if (keywords[0] && eval_bool (keywords[0], mlenv))
-       fcreate = true;
+    evkw_bool (0, fcreate);
 
     {
        StorageDB  sdb (mlenv);
@@ -975,6 +975,7 @@ MNode*  ml_delete_file (MNode* cell, MlEnv* mlenv) {
     MNodePtr  t;
     ustring  tgt;
     StoreType  storetype (mlenv);
+    bool  f;
     std::vector<MNode*>  keywords;
     static paramList  kwlist[] = {
        {CharConst ("target-serial"), false},   // 1
@@ -999,12 +1000,12 @@ MNode*  ml_delete_file (MNode* cell, MlEnv* mlenv) {
     if (evkw (1, t))
        storetype.srcNamed (t.to_string ());    // :source-named
 #ifdef SOURCEFILECOMPAT
-    if (keywords[2] && eval_bool (keywords[0], mlenv)) // serial
+    if (evkw_bool (2, f))      // serial
        storetype.setSerial ();
-    if (keywords[3] && eval_bool (keywords[1], mlenv)) // named
+    if (evkw_bool (3, f))      // named
        storetype.setNamed ();
 #endif
-    tgt = storetype.src (mlenv);
+    tgt = storetype.src ();
     if (tgt.length () > 0)
        unlink (tgt.c_str ());
 
@@ -1024,6 +1025,7 @@ MNode*  ml_rename_file (MNode* cell, MlEnv* mlenv) {
     ustring  tgt_from;
     ustring  tgt_to;
     StoreType  storetype (mlenv);
+    bool  f;
     std::vector<MNode*>  params;
     std::vector<MNode*>  keywords;
     static paramList  kwlist[] = {
@@ -1035,99 +1037,18 @@ MNode*  ml_rename_file (MNode* cell, MlEnv* mlenv) {
     setParams (arg, 2, &params, kwlist, &keywords, NULL);
     name_from = eval_str (params[0], mlenv);
     name_to = eval_str (params[1], mlenv);
-    if (keywords[0] && eval_bool (keywords[0], mlenv)) // serial
+    if (evkw_bool (0, f))      // serial
        storetype.setSerial ();
-    if (keywords[1] && eval_bool (keywords[1], mlenv)) // named
+    if (evkw_bool (1, f))      // named
        storetype.setNamed ();
 
-    tgt_from = storetype.src (mlenv, name_from);
-    tgt_to = storetype.src (mlenv, name_to);
+    tgt_from = storetype.src (name_from);
+    tgt_to = storetype.src (name_to);
     ::rename (tgt_from.c_str (), tgt_to.c_str ());
 
     return NULL;
 }
 
-#if 0
-class  ResponseParam {
-public:
-    ustring  src;
-    ustring  type;
-    StoreType  storetype;
-    bool  finline;
-    ustring  dispname;
-    bool  cflag;
-
-    ResponseParam () {
-       storetype.setStatic ();
-       finline = false;
-       cflag = false;
-    };
-    ResponseParam (MlEnv* mlenv): storetype (mlenv) {
-       finline = false;
-       cflag = false;
-    };
-    virtual  ~ResponseParam () {};
-    void  proc (MNode* cell, MlEnv* mlenv, bool fmotor) {
-       MNode*  arg = cell->cdr ();
-       ustring  filename;
-       MNodePtr  t;
-       std::vector<MNode*>  params;
-       std::vector<MNode*>  keywords;
-       static paramList  kwlist_motor[] = {
-           {CharConst ("serial"), true},
-           {CharConst ("named"), true},
-           {CharConst ("static"), true},
-           {CharConst ("type"), false},
-           {CharConst ("continue"), true},
-           {NULL, 0, 0}
-       };
-       static paramList  kwlist_file[] = {
-           {CharConst ("serial"), true},
-           {CharConst ("named"), true},
-           {CharConst ("static"), true},
-           {CharConst ("type"), false},
-           {CharConst ("continue"), true},
-           {CharConst ("inline"), true},
-           {CharConst ("name"), false},
-           {NULL, 0, 0}
-       };
-
-       if (fmotor)
-           setParams (arg, 1, &params, kwlist_motor, &keywords, NULL);
-       else
-           setParams (arg, 1, &params, kwlist_file, &keywords, NULL);
-       filename = eval_str (params[0], mlenv);
-       if (keywords[0] && eval_bool (keywords[0], mlenv))      // serial
-           storetype.setSerial ();
-       if (keywords[1] && eval_bool (keywords[1], mlenv))      // named
-           storetype.setNamed ();
-       if (keywords[2] && eval_bool (keywords[2], mlenv))      // static
-           storetype.setStatic ();
-       if (evkw (3, t))                        // type
-           type = to_string (t ());
-       if (keywords[4] && eval_bool (keywords[4], mlenv))      // continue
-           cflag = true;
-       if (! fmotor) {
-           if (keywords[5])
-               finline = eval_bool (keywords[5], mlenv); // inline
-           if (evkw (6, t))
-               dispname = to_text1 (t ());     // name
-       }
-
-       if (type.empty ()) {
-           if (! fmotor && dispname.length () > 0) {
-               type = mimetype (getExt (dispname));
-           } else {
-               type = mimetype (getExt (filename));
-           }
-       } else if (! checkMimeType (type)) {
-           type = mimetype (type);
-       }
-       src = storetype.src (mlenv, filename);
-    };
-};
-#endif
-
 /*DOC:
 ===response-motor===
  (response-motor HTMLFILE [#serial | #named | #static] [:type MIME_TYPE] [#continue]) -> NIL
@@ -1136,23 +1057,13 @@ public:
 */
 //#AFUNC       response-motor  ml_response_motor
 MNode*  ml_response_motor (MNode* cell, MlEnv* mlenv) {
-#if 0
-    ResponseParam  par;
-    par.proc (cell, mlenv, true);
-    if (par.type.size () == 0) {
-       mlenv->env->doMotor (par.src);
-    } else {
-       mlenv->env->doMotor (par.src, par.type);
-    }
-    if (! par.cflag)
-       mlenv->breakProg ();
-#endif
     MNode*  arg = cell->cdr ();
     StoreType  storetype (mlenv);
     ustring  type;
     ustring  src;
     bool  cflag = false;
     MNodePtr  t;
+    bool  f;
     std::vector<MNode*>  keywords;
     static paramList  kwlist[] = {
        {CharConst ("type"), false},            // 0
@@ -1187,14 +1098,14 @@ MNode*  ml_response_motor (MNode* cell, MlEnv* mlenv) {
     if (evkw (4, t))                           // :source-static
        storetype.srcStatic (t.to_string ());
 #ifdef SOURCEFILECOMPAT
-    if (keywords[5] && eval_bool (keywords[5], mlenv)) // serial
+    if (evkw_bool (5, f))      // serial
        storetype.setSerial ();
-    if (keywords[6] && eval_bool (keywords[6], mlenv)) // named
+    if (evkw_bool (6, f))      // named
        storetype.setNamed ();
-    if (keywords[7] && eval_bool (keywords[7], mlenv)) // static
+    if (evkw_bool (7, f))      // static
        storetype.setStatic ();
 #endif
-    src = storetype.src (mlenv);
+    src = storetype.src ();
     
     if (type.empty ()) {
        type = mimetype (getExt (src));
@@ -1228,6 +1139,7 @@ MNode*  ml_response_file (MNode* cell, MlEnv* mlenv) {
     bool  finline = false;
     bool  fbase64 = false;
     MNodePtr  t;
+    bool  f;
     std::vector<MNode*>  keywords;
     static paramList  kwlist[] = {
        {CharConst ("type"), false},            // 0
@@ -1267,16 +1179,15 @@ MNode*  ml_response_file (MNode* cell, MlEnv* mlenv) {
     if (evkw (6, t))                           // :source-static
        storetype.srcStatic (t.to_string ());
 #ifdef SOURCEFILECOMPAT
-    if (keywords[7] && eval_bool (keywords[7], mlenv)) // serial
+    if (evkw_bool (7, f))      // serial
        storetype.setSerial ();
-    if (keywords[8] && eval_bool (keywords[8], mlenv)) // named
+    if (evkw_bool (8, f))      // named
        storetype.setNamed ();
-    if (keywords[9] && eval_bool (keywords[9], mlenv)) // static
+    if (evkw_bool (9, f))      // static
        storetype.setStatic ();
 #endif
-    if (keywords[10])
-       fbase64 = eval_bool (keywords[10], mlenv);      // base64
-    src = storetype.src (mlenv);
+    evkw_bool (10, fbase64);
+    src = storetype.src ();
 
     if (type.empty ()) {
        if (dispname.length () > 0) {
@@ -1310,6 +1221,7 @@ MNode*  ml_filesize (MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
     StoreType  storetype (mlenv);
     MNodePtr  t;
+    bool  f;
     ustring  src;
     off_t  size;
     std::vector<MNode*>  keywords;
@@ -1340,14 +1252,14 @@ MNode*  ml_filesize (MNode* cell, MlEnv* mlenv) {
     if (evkw (2, t))                           // :source-static
        storetype.srcStatic (t.to_string ());
 #ifdef SOURCEFILECOMPAT
-    if (keywords[3] && eval_bool (keywords[3], mlenv)) // serial
+    if (evkw_bool (3, f))      // serial
        storetype.setSerial ();
-    if (keywords[4] && eval_bool (keywords[4], mlenv)) // named
+    if (evkw_bool (4, f))      // named
        storetype.setNamed ();
-    if (keywords[5] && eval_bool (keywords[5], mlenv)) // static
+    if (evkw_bool (5, f))      // static
        storetype.setStatic ();
 #endif
-    src = storetype.src (mlenv);
+    src = storetype.src ();
 
     if (src.length () > 0 && fileSize (src, size)) {
        return newMNode_num (size);
@@ -1366,6 +1278,7 @@ MNode*  ml_list_files (MNode* cell, MlEnv* mlenv) {
     MNode*  arg = cell->cdr ();
     StoreType  storetype (mlenv);
     ustring  src;
+    bool  f;
     std::vector<MNode*>  keywords;
     static paramList  kwlist[] = {
        {CharConst ("serial"), true},
@@ -1375,11 +1288,11 @@ MNode*  ml_list_files (MNode* cell, MlEnv* mlenv) {
     };
 
     setParams (arg, 0, NULL, kwlist, &keywords, NULL);
-    if (keywords[0] && eval_bool (keywords[0], mlenv)) // serial
+    if (evkw_bool (0, f))      // serial
        storetype.setSerial ();
-    if (keywords[1] && eval_bool (keywords[1], mlenv)) // named
+    if (evkw_bool (1, f))      // named
        storetype.setNamed ();
-//    if (keywords[2] && eval_bool (keywords[2], mlenv))       // static
+//    if (evkw_bool (2, f))    // static
 //     storetype.setStatic ();
 
     switch (storetype.type) {
index 45ccdd6..b2be1c0 100644 (file)
@@ -16,13 +16,11 @@ class  StoreType {
        F_TEXT,
     }  type;
 
+    MlEnv*  mlenv;
     ustring  param;
     ustring  encoding;
 
-    StoreType () {
-       type = F_NONE;
-    };
-    StoreType (MlEnv* mlenv);
+    StoreType (MlEnv* _mlenv);
     virtual  ~StoreType () {};
 
     virtual void  setParam (const ustring& name) {
@@ -31,6 +29,9 @@ class  StoreType {
     virtual bool  operator () () {
        return type != F_NONE;
     };
+    virtual bool  isEmpty () {
+       return param.length () == 0;
+    };
     virtual bool  isText () {
        return type == F_TEXT;
     };
@@ -65,9 +66,9 @@ class  StoreType {
     virtual void  srcEncoding (const ustring& name) {
        encoding = name;
     };
-    virtual const ustring  src (MlEnv* mlenv, const ustring& name);
-    virtual const ustring  src (MlEnv* mlenv);
-    virtual ustring  read (MlEnv* mlenv);
+    virtual const ustring  src (const ustring& name);
+    virtual const ustring  src ();
+    virtual ustring  read ();
 };
 
 void  newStoreSerial (MlEnv* mlenv);