Archive for the ‘C’ Tag

UTF-8 版 newLISP.dll を Visual C++ で使う

 前回は、newLISP.dll をコンソール アプリケーションで使いました。
 Visual C++(私の使っているのは、Express Edition) のコンソール アプリケーションには、Win32 の Win32 コンソール アプリケーション (前回のコンソール アプリケーション)の他に、CLR コンソール アプリケーション があります。
 何が違うかというと、日本語コードが UTF-8 になります。
 Visual C++ の開発環境で、

新規作成 → 新しいプロジェクト → CLR → CLR コンソール アプリケーション

 という風に進めて、新規プロジェクト CLR-newLISP を作成すると、

// CLR-newLISP.cpp : メイン プロジェクト ファイルです。

#include "stdafx.h"

using namespace System;

int main(array<System::String ^> ^args)
{
    Console::WriteLine(L"Hello World");
    return 0;
}

 といった具合にテンプレートが出てきます。
 CLR コンソール アプリケーション だと、見ての通り、文字列に String が使えます。
 日本語版Visual C++ の String の文字コードは、UTF-8 です。
 つまり、UTF-8版newlisp.dll を使うには、最適(笑)!
 ということで、以下コードです。

// CLR-newLISP.cpp : メイン プロジェクト ファイルです。

#include "stdafx.h"
#include <windows.h>
using namespace System;
using namespace System::Text;
using namespace System::Runtime::InteropServices;

	int String2char(String^ str, char* text)
	{
		Encoding^ utf8 = Encoding::GetEncoding(L"UTF-8");
		array<Byte>^ utf8Array;//
		utf8Array = utf8->GetBytes(str);
		Marshal::Copy(utf8Array, 0, (IntPtr)text, utf8Array->Length);
		text[utf8Array->Length] = '¥0';
		return utf8Array->Length;
	}
	String^ char2String (char* text) {
		int len = strlen(text);
		Encoding^ utf8 = Encoding::GetEncoding(L"UTF-8");
		array<Byte>^ utf8Array = gcnew array<Byte>(len);
		array<Char>^ utf8Chars;
		Marshal::Copy((IntPtr)text, utf8Array, 0, len);
		utf8Chars = utf8->GetChars(utf8Array);
		return gcnew String( utf8Chars);
	}
#define MAXBYTES	512
typedef int (__stdcall *newlispAPI)(IN LPCSTR script);

int main(array<System::String ^> ^args)
{
	String^	readdata;
	static newlispAPI newlispEvalStr = NULL;
	char script[MAXBYTES];
	char* res;
	int len;
	HMODULE hnewLISP = LoadLibrary(TEXT("newlisp.dll"));
	if (hnewLISP) {
	    Console::WriteLine(L"Hello newLISP World");
		newlispEvalStr = (newlispAPI)GetProcAddress(hnewLISP, "newlispEvalStr");
		Console::Write("> ");
		while ((readdata = Console::ReadLine()) != "(exit)") {
			len = String2char(readdata, script);
			res = (char *)newlispEvalStr((LPCSTR) script);
			Console::Write(char2String(res) + "> ");
		}
		Console::WriteLine("Press Enter key!");
		Console::ReadLine();
		if (hnewLISP) FreeLibrary(hnewLISP);
	} else {
		Console::WriteLine("newlisp.dll is not found.");
		Console::WriteLine("Press Enter key!");
		Console::ReadLine();
	}
	return 0;
}

 コードの解説は、、、ここは、newLISP の blog なので、割愛(笑)。
 これをコンパイルして実行すると

 こんな感じ。もちろん、UTF-8版newlisp.dll を用意しておく必要があります。
 newLISP インストール・ディレクトリに PATH が通っているなら、CLR-newLISP.exe と同じディレクトリに置いておく必要があります。
 これなら、Windows 環境の newLISP で普通に UTF-8 が使えます。
 なんせ Windows 環境の コンソール(DOS窓)は、Shift-JIS コードが標準ですから、UTF-8版newlisp.exe では、うまく日本が使えませんでした。chcp とかも試したのですが、、、
 しかし、これからは、Windows でも、UTF-8版newLISP が使える?
 それなら、Linux 用コードと分けなくて済む?(笑)

 以上、如何でしょうか?

newLISP.dll を C で使う

 Windows では、実行ファイル newlisp.exe の他に newlisp.dll があります。
 Unix の newlisp.so には、C 言語からの呼び出し例がマニュアルに載っていますが、newlisp.dll の項目 には、C 言語からの呼び出し例は載っていません。
 そこで、作ってみました(笑)。

 コンパイラが bcc の場合、

/* libdemo.c - demo for importing newlisp.dll
 *
 * use:
 *
 *    libdemo "(+ 3 4)"
 *    libdemo "(symbols)"
 *
 */
#include <stdio.h>
#include <windows.h>

typedef int (__stdcall *newlispAPI)(IN char* script);

int main(int argc, char* argv[])
{
	HMODULE hLibrary;
	newlispAPI func;

	if ((hLibrary = LoadLibrary("newlisp.dll")) == 0) {
	    printf("cannot import library\n");
		exit(-1);
	}

	func = (newlispAPI)GetProcAddress(hLibrary, "newlispEvalStr");

 	if (argc > 1) {
		printf("%s\n", argv[1]);
		printf("%s\n", func(argv[1]));
	}

	return(0);
}

 マニュアルにある Unix 版とほぼ同じ動作ですが、コマンドライン引数も出力するようにしてあります。
 また、引数は、"(ダブル・クォート)で囲みます。

 ついでに、Visual C++ の場合、こうなります。

#include "stdafx.h"
#include <stdio.h>
#include <windows.h>

typedef int (__stdcall *newlispAPI)(IN LPCSTR script);

int main(int argc, char* argv[])
{
	HMODULE hLibrary;
	newlispAPI func;

	if ((hLibrary = LoadLibrary(L"newlisp.dll")) == 0) {
	    printf("cannot import library\n");
		exit(-1);
	}

	func = (newlispAPI)GetProcAddress(hLibrary, "newlispEvalStr");

 	if (argc > 1) {
		printf("%s\n", argv[1]);
		printf("%s\n", func((LPCSTR) argv[1]));
	}

	return(0);
}

 キャストが微妙に違っています(笑)が、基本動作は同じです。

 さて、newlisp.dll の組込シンボルを symbols 使って見てみると、

Class
Tree
module

 の三つがありません。いずれも、予約変数または関数で、newlisp.exe にはあります。
定義がマニュアルにありますので、困ることはないでしょうが、ご使用の際は、ご注意を。

 以上、如何でしょうか?