From 3180f56c81e3d3540e0413f861f1ddfc7b47c555 Mon Sep 17 00:00:00 2001
From: nishi <nishi@d27a3e52-49c5-7645-884c-6793ebffc270>
Date: Tue, 6 Feb 2024 07:16:57 +0000
Subject: [PATCH] Tcl binding

git-svn-id: file:///raid/svn-main/nishi-libw3/trunk@174 d27a3e52-49c5-7645-884c-6793ebffc270
---
 Library/Makefile |   4 ++
 Library/Tcl.c    | 138 +++++++++++++++++++++++++++++++++++++++++++++++
 Library/W3Tcl.h  |   9 ++++
 Makefile         |  13 +++--
 W3Version.h.p    |   2 +-
 5 files changed, 162 insertions(+), 4 deletions(-)
 create mode 100644 Library/Tcl.c
 create mode 100644 Library/W3Tcl.h

diff --git a/Library/Makefile b/Library/Makefile
index 4a3eda1..e93619f 100644
--- a/Library/Makefile
+++ b/Library/Makefile
@@ -3,6 +3,10 @@
 
 OBJS = ./Core.o ./Util.o ./DNS.o ./HTTP.o ./Gopher.o ./POP3.o ./File.o ./URL.o ./Tag.o
 
+ifeq ($(TCL),YES)
+OBJS += ./Tcl.o
+endif
+
 ifeq ($(WINDOWS),YES)
 ./w3.dll: $(OBJS)
 	$(CC) $(LDFLAGS) -fstack-protector -L../openssl/lib/mingw/$(WINARCH) -shared -Wl,--out-implib,./w3.lib -o $@ $^ $(LIBS)
diff --git a/Library/Tcl.c b/Library/Tcl.c
new file mode 100644
index 0000000..e402968
--- /dev/null
+++ b/Library/Tcl.c
@@ -0,0 +1,138 @@
+/* $Id$ */
+#include "W3Tcl.h"
+
+#include <tcl.h>
+
+#include "W3Util.h"
+#include "W3Core.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+extern int strcasecmp(const char* s1, const char* s2);
+
+void** __dictionary;
+
+int Tcl_W3Cmd(ClientData dummy, Tcl_Interp* interp, int objc, Tcl_Obj* CONST objv[]){
+	if(objc < 2){
+		const char* errmsg = "argument error: arguments should be \"w3 subcommand arg1 arg2 ...\"";
+		Tcl_SetObjResult(interp, Tcl_NewStringObj(errmsg, strlen(errmsg)));
+		return TCL_ERROR;
+	}
+	char* subcommand = Tcl_GetString(objv[1]);
+	if(strcasecmp(subcommand, "create") == 0){
+		if(objc != 6){
+			const char* errmsg = "argument error: arguments should be \"w3 create name protocol hostname port\"";
+			Tcl_SetObjResult(interp, Tcl_NewStringObj(errmsg, strlen(errmsg)));
+			return TCL_ERROR;
+		}
+		char* name = Tcl_GetString(objv[2]);
+		char* protocol = Tcl_GetString(objv[3]);
+		char* hostname = Tcl_GetString(objv[4]);
+		int port = atoi(Tcl_GetString(objv[5]));
+		struct W3* w3 = W3_Create(protocol, hostname, port);
+		if(w3 == NULL){
+			const char* errmsg = "connect error: failed to connect";
+			Tcl_SetObjResult(interp, Tcl_NewStringObj(errmsg, strlen(errmsg)));
+			return TCL_ERROR;
+		}else{
+			int len = 0;
+			if(__dictionary == NULL) {
+				__dictionary = malloc(sizeof(*__dictionary) * (len + 3));
+				__dictionary[len] = __W3_Strdup(name);
+				__dictionary[len + 1] = w3;
+				int i;
+				for(i = 0; ((char*)__dictionary[len])[i] != 0; i++) {
+					((char*)__dictionary[len])[i] = tolower(((char*)__dictionary[len])[i]);
+				}
+				__dictionary[len + 2] = NULL;
+			} else {
+				for(len = 0; __dictionary[len] != NULL; len++)
+					;
+				void** __dictionary2 = __dictionary;
+				__dictionary = malloc(sizeof(*__dictionary) * (len + 3));
+				for(len = 0; __dictionary2[len] != NULL; len++) {
+					__dictionary[len] = __dictionary2[len];
+				}
+				__dictionary[len] = __W3_Strdup(name);
+				__dictionary[len + 1] = w3;
+				__dictionary[len + 2] = NULL;
+				int i;
+				for(i = 0; ((char*)__dictionary[len])[i] != 0; i++) {
+					((char*)__dictionary[len])[i] = tolower(((char*)__dictionary[len])[i]);
+				}
+				free(__dictionary2);
+			}
+			Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
+		}
+	}else if(strcasecmp(subcommand, "set_method") == 0 || strcasecmp(subcommand, "set_path") == 0){
+		if(objc != 4){
+			if(strcasecmp(subcommand, "set_method") == 0){
+				const char* errmsg = "argument error: arguments should be \"w3 set_method name method\"";
+				Tcl_SetObjResult(interp, Tcl_NewStringObj(errmsg, strlen(errmsg)));
+			}else{
+				const char* errmsg = "argument error: arguments should be \"w3 set_path name path\"";
+				Tcl_SetObjResult(interp, Tcl_NewStringObj(errmsg, strlen(errmsg)));
+			}
+			return TCL_ERROR;
+		}
+		char* name = Tcl_GetString(objv[2]);
+		if(__dictionary == NULL){
+			const char* errmsg = "argument error: a client named that does not exist";
+			Tcl_SetObjResult(interp, Tcl_NewStringObj(errmsg, strlen(errmsg)));
+		}else{
+			int i;
+			for(i = 0; __dictionary[i] != NULL; i += 2){
+				if(strcasecmp((char*)__dictionary[i], name) == 0){
+					if(strcasecmp(subcommand, "set_method") == 0){
+						W3_Set_Method(__dictionary[i + 1], Tcl_GetString(objv[3]));
+					}else{
+						W3_Set_Path(__dictionary[i + 1], Tcl_GetString(objv[3]));
+					}
+					Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
+					return TCL_OK;
+				}
+			}
+			const char* errmsg = "argument error: a client named that does not exist";
+			Tcl_SetObjResult(interp, Tcl_NewStringObj(errmsg, strlen(errmsg)));
+		}
+	}else if(strcasecmp(subcommand, "send_request") == 0){
+		if(objc != 3){
+			const char* errmsg = "argument error: arguments should be \"w3 send_request name\"";
+			Tcl_SetObjResult(interp, Tcl_NewStringObj(errmsg, strlen(errmsg)));
+			return TCL_ERROR;
+		}
+		char* name = Tcl_GetString(objv[2]);
+		if(__dictionary == NULL){
+			const char* errmsg = "argument error: a client named that does not exist";
+			Tcl_SetObjResult(interp, Tcl_NewStringObj(errmsg, strlen(errmsg)));
+		}else{
+			int i;
+			for(i = 0; __dictionary[i] != NULL; i += 2){
+				if(strcasecmp((char*)__dictionary[i], name) == 0){
+					W3_Send_Request(__dictionary[i + 1]);
+					Tcl_SetObjResult(interp, Tcl_NewIntObj(0));
+					return TCL_OK;
+				}
+			}
+			const char* errmsg = "argument error: a client named that does not exist";
+			Tcl_SetObjResult(interp, Tcl_NewStringObj(errmsg, strlen(errmsg)));
+		}
+	}else{
+		const char* errmsg = "argument error: invalid subcommand";
+		Tcl_SetObjResult(interp, Tcl_NewStringObj(errmsg, strlen(errmsg)));
+		return TCL_ERROR;
+	}
+	return TCL_OK;
+}
+
+int W3_Init(Tcl_Interp* interp){
+	__W3_Debug("Tcl", "Initializing the binding");
+	W3_Library_Init();
+	__dictionary = malloc(sizeof(*__dictionary));
+	__dictionary[0] = NULL;
+	Tcl_CreateObjCommand(interp, "w3", Tcl_W3Cmd, NULL, NULL);
+	__W3_Debug("Tcl", "Initialized the binding");
+	return TCL_OK;
+}
diff --git a/Library/W3Tcl.h b/Library/W3Tcl.h
new file mode 100644
index 0000000..f935ec5
--- /dev/null
+++ b/Library/W3Tcl.h
@@ -0,0 +1,9 @@
+/* $Id$ */
+#ifndef __W3URL_H__
+#define __W3URL_H__
+
+#include <tcl.h>
+
+int W3_Init(Tcl_Interp* interp);
+
+#endif
diff --git a/Makefile b/Makefile
index 816f19e..91c9b3f 100644
--- a/Makefile
+++ b/Makefile
@@ -33,6 +33,13 @@ WINDOWS := YES
 WINARCH := x64
 endif
 
+PKGCONF := pkg-config
+
+ifeq ($(TCL),YES)
+CFLAGS += $(shell $(PKGCONF) --cflags tcl) -DTCL_BINDING
+LIBS += $(shell $(PKGCONF) --libs tcl)
+endif
+
 ifeq ($(WINDOWS),YES)
 LIBS += -lws2_32
 endif
@@ -58,7 +65,7 @@ ALL := ./Library/w3.dll ./Example
 all: ./Library/W3Version.h ./w3.pc $(ALL)
 
 ./Library/w3.dll:
-	$(MAKE) -C ./Library CC=$(CC) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBS="$(LIBS)" WINDOWS=YES WINARCH=$(WINARCH)
+	$(MAKE) -C ./Library CC=$(CC) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBS="$(LIBS)" WINDOWS=YES WINARCH=$(WINARCH) TCL=$(TCL)
 
 ./Example: ./Library/w3.dll
 	$(MAKE) -C ./Example CC=$(CC) examples SUFFIX=.exe
@@ -75,10 +82,10 @@ ALL := ./Library/libw3.so ./Library/libw3.a ./Example
 all: ./Library/W3Version.h ./w3.pc $(ALL)
 
 ./Library/libw3.so:
-	$(MAKE) -C ./Library CC=$(CC) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBS="$(LIBS)" ./libw3.so
+	$(MAKE) -C ./Library CC=$(CC) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBS="$(LIBS)" TCL=$(TCL) ./libw3.so
 
 ./Library/libw3.a:
-	$(MAKE) -C ./Library CC=$(CC) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBS="$(LIBS)" ./libw3.a
+	$(MAKE) -C ./Library CC=$(CC) CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" LIBS="$(LIBS)" TCL=$(TCL) ./libw3.a
 
 ./Example: ./Library/libw3.so
 	$(MAKE) -C ./Example CC=$(CC) examples
diff --git a/W3Version.h.p b/W3Version.h.p
index a9d56ea..ddd3c0b 100644
--- a/W3Version.h.p
+++ b/W3Version.h.p
@@ -6,7 +6,7 @@
 extern "C" {
 #endif
 
-#define LIBW3_VERSION "2.2P" \
+#define LIBW3_VERSION "2.3" \
 SUFFIX
 
 #ifdef __cplusplus
-- 
2.43.0