[ttssh2-commit] [9706] cygterm を整理

Back to archive index
scmno****@osdn***** scmno****@osdn*****
2022年 1月 29日 (土) 01:36:06 JST


Revision: 9706
          https://osdn.net/projects/ttssh2/scm/svn/commits/9706
Author:   zmatsuo
Date:     2022-01-29 01:36:06 +0900 (Sat, 29 Jan 2022)
Log Message:
-----------
cygterm を整理

- teraterm/common/ の関数を利用するようにした
- 設定に関する部分を cygterm_cfg.cc,h に分離した
  - cygterm.cfgの読み書きを集める
- teraterm/common/ を調整
  - cygwinでビルドできるよう修正
  - ttlib_static_dirs.cpp を追加
    - ttlib_static_cpp.cpp から一部を移動
  - ttlib.h
    - Microsoft SAL が MSC 以外に入っていたので削除

Modified Paths:
--------------
    branches/cygterm/.editorconfig
    branches/cygterm/cygwin/cygterm/CMakeLists.txt
    branches/cygterm/cygwin/cygterm/Makefile
    branches/cygterm/cygwin/cygterm/cygterm.cc
    branches/cygterm/teraterm/common/CMakeLists.txt
    branches/cygterm/teraterm/common/asprintf.cpp
    branches/cygterm/teraterm/common/codeconv.cpp
    branches/cygterm/teraterm/common/common_static.v16.vcxproj
    branches/cygterm/teraterm/common/compat_win.cpp
    branches/cygterm/teraterm/common/dllutil.cpp
    branches/cygterm/teraterm/common/ttknownfolders.c
    branches/cygterm/teraterm/common/ttlib.h
    branches/cygterm/teraterm/common/ttlib_static_cpp.cpp
    branches/cygterm/teraterm/common/win32helper.cpp

Added Paths:
-----------
    branches/cygterm/cygwin/cygterm/cygterm_cfg.cc
    branches/cygterm/cygwin/cygterm/cygterm_cfg.h
    branches/cygterm/teraterm/common/ttlib_static_dirs.cpp

-------------- next part --------------
Modified: branches/cygterm/.editorconfig
===================================================================
--- branches/cygterm/.editorconfig	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/.editorconfig	2022-01-28 16:36:06 UTC (rev 9706)
@@ -4,7 +4,7 @@
 indent_style = tab
 indent_size = 4
 
-[*.{cpp,c,h}]
+[*.{cpp,c,h,cc}]
 indent_style = tab
 indent_size = 4
 end_of_line = crlf

Modified: branches/cygterm/cygwin/cygterm/CMakeLists.txt
===================================================================
--- branches/cygterm/cygwin/cygterm/CMakeLists.txt	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/cygwin/cygterm/CMakeLists.txt	2022-01-28 16:36:06 UTC (rev 9706)
@@ -21,8 +21,28 @@
   ${PACKAGE_NAME}
   cygterm.cc
   cygterm.rc
+  cygterm_cfg.cc
+  cygterm_cfg.h
   )
 
+target_sources(
+  ${PACKAGE_NAME}
+  PRIVATE
+  ../../teraterm/common/ttlib.h
+#  ../../teraterm/common/ttlib_static_cpp.cpp
+  ../../teraterm/common/ttlib_static_dirs.cpp
+  ../../teraterm/common/asprintf.cpp
+  ../../teraterm/common/asprintf.h
+  ../../teraterm/common/win32helper.cpp
+  ../../teraterm/common/win32helper.h
+  ../../teraterm/common/compat_win.cpp
+  ../../teraterm/common/ttknownfolders.c
+  ../../teraterm/common/dllutil.cpp
+  ../../teraterm/common/dllutil.h
+  ../../teraterm/common/codeconv.cpp
+  ../../teraterm/common/codeconv.h
+  )
+
 if (MSYS2TERM)
   target_compile_definitions(
     ${PACKAGE_NAME}
@@ -42,8 +62,15 @@
   PRIVATE
   -D_GNU_SOURCE
   -fno-exceptions
+  -Wall -Wextra
   )
 
+target_include_directories(
+  ${PACKAGE_NAME}
+  PRIVATE
+  ../../teraterm/common
+  )
+
 target_link_options(
   ${PACKAGE_NAME}
   PRIVATE
@@ -50,6 +77,13 @@
   -mwindows
   )
 
+target_link_libraries(
+  ${PACKAGE_NAME}
+  PRIVATE
+  shell32
+  ole32
+  )
+
 install(
   TARGETS ${PACKAGE_NAME}
   DESTINATION .

Modified: branches/cygterm/cygwin/cygterm/Makefile
===================================================================
--- branches/cygterm/cygwin/cygterm/Makefile	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/cygwin/cygterm/Makefile	2022-01-28 16:36:06 UTC (rev 9706)
@@ -3,12 +3,21 @@
 BINDIR = $(HOME)/bin
 
 CC = gcc
-CFLAGS = -D_GNU_SOURCE -O2 -fno-exceptions
+CFLAGS = -D_GNU_SOURCE -O2 -fno-exceptions -I ../../teraterm/common
 #CFLAGS = -g -fno-exceptions
 LDFLAGS = -mwindows
 
 EXE = cygterm.exe
-SRC = $(EXE:.exe=.cc)
+SRC = \
+	$(EXE:.exe=.cc) \
+	cygterm_cfg.cc \
+	../../teraterm/common/ttlib_static_dirs.cpp \
+	../../teraterm/common/asprintf.cpp \
+	../../teraterm/common/win32helper.cpp \
+	../../teraterm/common/compat_win.cpp \
+	../../teraterm/common/ttknownfolders.c \
+	../../teraterm/common/dllutil.cpp \
+	../../teraterm/common/codeconv.cpp
 CFG = $(EXE:.exe=.cfg)
 RES = $(EXE:.exe=.res)
 ICO = $(EXE:.exe=.ico)
@@ -20,14 +29,16 @@
 all : $(EXE) $(ARCHIVE)
 
 $(EXE) : $(SRC) $(ICO) $(RC)
-	windres -O coff -o $(RES) $(RC)
   ifeq (0, $(shell nm /usr/lib/crt0.o | grep -c WinMainCRTStartup))
 	$(CC) $(CFLAGS) $(LDFLAGS) -DNO_WIN_MAIN -o $(EXE) $(SRC) $(RES)
   else
-	$(CC) $(CFLAGS) $(LDFLAGS) -o $(EXE) $(SRC) $(RES)
+	$(CC) $(CFLAGS) $(LDFLAGS) -o $(EXE) $(SRC) $(RES) -lole32
   endif
 	strip $(EXE)
 
+$(RES): $(RC)
+	windres -O coff -o $(RES) $(RC)
+
 $(RC):
 	echo 'icon ICON $(ICO)' > $(RC)
 

Modified: branches/cygterm/cygwin/cygterm/cygterm.cc
===================================================================
--- branches/cygterm/cygwin/cygterm/cygterm.cc	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/cygwin/cygterm/cygterm.cc	2022-01-28 16:36:06 UTC (rev 9706)
@@ -1,7 +1,7 @@
 /////////////////////////////////////////////////////////////////////////////
 // CygTerm+ - yet another Cygwin console
 // Copyright (C) 2000-2006 NSym.
-// (C) 2006-2016 TeraTerm Project
+// (C) 2006- TeraTerm Project
 //---------------------------------------------------------------------------
 // This program is free software; you can redistribute it and/or modify it
 // under the terms of the GNU General Public License (GPL) as published by
@@ -22,18 +22,20 @@
 // CygTerm+ - yet another Cygwin console
 //
 //   Using Cygwin with a terminal emulator.
-//   
+//
 //   Writtern by TeraTerm Project.
 //            https://ttssh2.osdn.jp/
-//   
+//
 //   Original written by NSym.
-//                         *** Web Pages ***
-//  (English) http://www.dd.iij4u.or.jp/~nsym/cygwin/cygterm/index-e.html
-// (Japanese) http://www.dd.iij4u.or.jp/~nsym/cygwin/cygterm/index.html
 //
 
+#if !defined(__CYGWIN__)
+#error check compiler
+#endif
+
+// MessageBox\x82̃^\x83C\x83g\x83\x8B\x82Ŏg\x97p TODO exe\x83t\x83@\x83C\x83\x8B\x96\xBC\x82ɕύX
 static char Program[] = "CygTerm+";
-static char Version[] = "version 1.07_30_beta (2021/11/14)";
+//static char Version[] = "version 1.07_30_beta (2021/11/14)";
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -57,6 +59,11 @@
 #include <sys/select.h>
 #include <wchar.h>
 
+#include "ttlib.h"
+#include "codeconv.h"
+
+#include "cygterm_cfg.h"
+
 // pageant support (ssh-agent proxy)
 //----------------------------------
 #define AGENT_COPYDATA_ID 0x804e50ba
@@ -70,92 +77,55 @@
 
 // TCP port for TELNET
 //--------------------
-int port_start = 20000;  // default lowest port number
-int port_range = 40;     // default number of ports
+#define PORT_START_DEFAULT 20000  // default lowest port number
+#define PORT_RANGE_DEFAULT 40     // default number of ports
 
-// command lines of a terminal-emulator and a shell
-//-------------------------------------------------
-char cmd_term[256] = "";
-char cmd_termopt[256] = "";
-char cmd_shell[128] = "";
-char pw_shell[128] = "";
-char change_dir[256] = "";
-
 // TCP port for connection to another terminal application
 //--------------------------------------------------------
 int cl_port = 0;
+u_short listen_port;
 
 // telnet socket timeout
 //----------------------
-int telsock_timeout = 5;    // timeout 5 sec
+#define TELSOCK_TIMEOUT_DEFAULT 5   // timeout 5 sec
 
-// dumb terminal flag
-//-------------------
-bool dumb = false;
-
 // chdir to HOME
 //--------------
-bool home_chdir = false;
+#define HOME_CHDIR_DEFAULT false
 
 // login shell flag
 //-----------------
-bool enable_loginshell = false;
+#define ENABLE_LOGINSHELL_DEFAULT false
 
 // ssh agent proxy
 //----------------
-bool enable_agent_proxy = false;
+#define ENABLE_AGENT_PROXY_DEFAULT false
 
-// terminal type & size
-//---------------------
-char term_type[41] = "";
-struct winsize win_size = {0,0,0,0};
-
 // debug mode
 //-----------
-bool debug_flag = false;
+#define DEBUG_FLAG_DEFAULT false;
+bool debug_flag = DEBUG_FLAG_DEFAULT;
 
-// additional env vars given to a shell
-//-------------------------------------
-struct sh_env_t {
-    struct sh_env_t* next;
-    char env[1];
-} sh_env = {NULL, ""};
+// "cygterm.cfg"
+static char *cfg_base;          // "cygterm.cfg"
+static char *cfg_exe;           // [exe directory]/cygterm.cfg
+static char *conf_appdata_full; // $APPDATA/teraterm5/cygterm.cfg
+static char *sys_conf;          // /etc/cygterm.conf
+static char *usr_conf;          // ~/cygtermrc  $HOME/cygtermrc
 
-sh_env_t* sh_envp = &sh_env;
-
-int add_env(sh_env_t** envp, const char* str, const char* str2)
+extern "C" BOOL IsWindowsXPOrLater(void)
 {
-	int len;
-	sh_env_t* e;
-
-	len = strlen(str);
-	if (str2) {
-		len += strlen(str2) + 1;
-	}
-
-	e = (sh_env_t*)malloc(sizeof(sh_env_t) + len);
-	if (e) {
-		if (str2) {
-			snprintf(e->env, len + 1, "%s=%s", str, str2);
-		}
-		else {
-			strcpy(e->env, str);
-		}
-		e->next = NULL;
-		*envp = ((*envp)->next = e);
-		return 1;
-	}
-	else {
-		return 0;
-	}
+	return TRUE;
 }
 
 //================//
 // message output //
 //----------------//
+// msg \x82\xCD ANSI\x95\xB6\x8E\x9A\x83R\x81[\x83h (UTF8\x82͉\xBB\x82\xAF\x82\xE9)
 void msg_print(const char* msg)
 {
-    MessageBox(NULL, msg, Program, MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
+    OutputDebugStringA(msg);
+    MessageBoxA(NULL, msg, Program, MB_OK | MB_ICONINFORMATION | MB_TOPMOST);
 }
 
 //=========================//
@@ -191,99 +161,23 @@
 //======================//
 // debug message output //
 //======================//
-void debug_msg_print(const char* msg)
+void debug_msg_print(const char* msg, ...)
 {
-    if (debug_flag) {
-        msg_print(msg);
-    }
-}
+	if (debug_flag) {
+		char *tmp1;
+		va_list arg;
+		va_start(arg, msg);
+		vasprintf(&tmp1, msg, arg);
+		va_end(arg);
 
-//==================================//
-// parse line in configuration file //
-//----------------------------------//
-void parse_cfg_line(char *buf)
-{
-    // "KEY = VALUE" format in each line.
-    // skip leading/trailing blanks. KEY is not case-sensitive.
-    char* p1;
-    for (p1 = buf; isspace(*p1); ++p1);
-    if (!isalpha(*p1)) {
-        return; // comment line with non-alphabet 1st char
-    }
-    char* name = p1;
-    for (++p1; isalnum(*p1) || *p1 == '_'; ++p1);
-    char* p2;
-    for (p2 = p1; isspace(*p2); ++p2);
-    if (*p2 != '=') {
-        return; // igonore line without '='
-    }
-    for (++p2; isspace(*p2); ++p2);
-    char* val = p2;
-    for (p2 += strlen(p2); isspace(*(p2-1)); --p2);
-    *p1 = *p2 = 0;
-
-    if (!strcasecmp(name, "TERM")) {
-        // terminal emulator command line (host:%s, port#:%d)
-        strncpy(cmd_term, val, sizeof(cmd_term)-1);
-        cmd_term[sizeof(cmd_term)-1] = 0;
-    }
-    else if (!strcasecmp(name, "SHELL")) {
-        // shell command line
-        if (strcasecmp(val, "AUTO") != 0) {
-            strncpy(cmd_shell, val, sizeof(cmd_shell)-1);
-        }
-	else {
-	    strncpy(cmd_shell, pw_shell, sizeof(cmd_shell)-1);
+		char *tmp2;
+		unsigned long pid = GetCurrentProcessId();
+		asprintf(&tmp2, "dbg %lu: %s\n", pid, tmp1);
+		OutputDebugStringA(tmp2);
+		// printf("%s", tmp2);
+		free(tmp2);
+		free(tmp1);
 	}
-	cmd_shell[sizeof(cmd_shell)-1] = 0;
-    }
-    else if (!strcasecmp(name, "PORT_START")) {
-        // minimum port# for TELNET
-        port_start = atoi(val);
-    }
-    else if (!strcasecmp(name, "PORT_RANGE")) {
-        // number of ports for TELNET
-        port_range = atoi(val);
-    }
-    else if (!strcasecmp(name, "TERM_TYPE")) {
-        // terminal type name (maybe overridden by TELNET negotiation.)
-        strncpy(term_type, val, sizeof(term_type)-1);
-        term_type[sizeof(term_type)-1] = 0;
-    }
-    else if (!strncasecmp(name, "ENV_", 4)) {
-        // additional env vars given to a shell
-	add_env(&sh_envp, val, NULL);
-    }
-    else if (!strcasecmp(name, "HOME_CHDIR")) {
-        // change directory to home
-        if (strchr("YyTt", *val) != NULL || atoi(val) > 0) {
-            home_chdir = true;
-        }
-    }
-    else if (!strcasecmp(name, "LOGIN_SHELL")) {
-        // execute a shell as a login shell
-        if (strchr("YyTt", *val) != NULL || atoi(val) > 0) {
-            enable_loginshell = true;
-        }
-    }
-    else if (!strcasecmp(name, "SOCKET_TIMEOUT")) {
-        // telnet socket timeout
-        telsock_timeout = atoi(val);
-    }
-    else if (!strcasecmp(name, "SSH_AGENT_PROXY")) {
-        // ssh-agent proxy
-        if (strchr("YyTt", *val) != NULL || atoi(val) > 0) {
-            enable_agent_proxy = true;
-        }
-    }
-    else if (!strcasecmp(name, "DEBUG")) {
-        // debug mode
-        if (strchr("YyTt", *val) != NULL || atoi(val) > 0) {
-            debug_flag = true;
-        }
-    }
-
-    return;
 }
 
 // '\\' -> '/'
@@ -310,164 +204,105 @@
     }
 }
 
-// wchar -> utf8
-char *convert_utf8_from_wchar(const wchar_t *strW)
-{
-    size_t mb_len = ::WideCharToMultiByte(CP_UTF8, 0, strW, -1, NULL, 0, NULL, NULL);
-    char *u8 = (char *)malloc(sizeof(wchar_t) * mb_len);
-    ::WideCharToMultiByte(CP_UTF8, 0, strW, -1, u8, mb_len, NULL, NULL);
-    return u8;
-}
-
 // $APPDATA
 char *get_appdata_dir()
 {
-#if 0
-	// link error :-(
-    wchar_t *home_pathW;
-    SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &home_pathW);
-    convert_bsW(home_pathW);
-    char *home_pathU8 = convert_utf8_from_wchar(home_pathW);
-    CoTaskMemFree(home_pathW);
-    return home_pathU8;
-#endif
-#if 1
-    char *appdata = strdup(getenv("APPDATA"));
-    convert_bs(appdata);
-    return appdata;
-#endif
+	wchar_t *homeW = GetHomeDirW(NULL);
+	convert_bsW(homeW);
+	char *homeU8 = ToU8W(homeW);
+	free(homeW);
+	return homeU8;
 }
 
-void get_cfg_filenames(char **cfg_exe_full, char **cfg_appdata_full, char **cfg)
+static void get_cfg_filenames(const char *argv0)
 {
-    wchar_t win_conf[MAX_PATH];
+	// cfg base filename "cygterm.cfg"
+	char *p = strrchr(argv0, '/') + 1;
+	cfg_base = (char *)malloc(strlen(p) + 5);
+	strcpy(cfg_base, p);
+	strcat(cfg_base, ".cfg");
 
-    // get cfg path from exe path
-    if (GetModuleFileNameW(NULL, win_conf, MAX_PATH) <= 0) {
-        *cfg_exe_full = NULL;
-        *cfg = NULL;
-        return;
-    }
+	// exe path
+	cfg_exe = (char *)malloc(strlen(argv0) + strlen(cfg_base));
+	strcpy(cfg_exe, argv0);
+	p = strrchr(cfg_exe, '/') + 1;
+	strcpy(p, cfg_base);
 
-    convert_bsW(win_conf);
+	// home	 $HOME/cygtermrc
+	const char *home = getenv("HOME");
+	usr_conf = (char *)malloc(strlen(home) + strlen(cfg_base) + 2);
+	strcpy(usr_conf, home);
+	strcat(usr_conf, "/.");
+	strcat(usr_conf, cfg_base);
+	p = strrchr(usr_conf, '.');		// ".cfg" -> "rc"
+	strcpy(p, "rc");
 
-    wchar_t* bcW = wcsrchr(win_conf, '/');
-    if (bcW != NULL) {
-        wchar_t* dot = wcsrchr(bcW, '.');
-        if (dot == NULL) {
-            wcscat(bcW, L".cfg");
-        } else {
-            wcscpy(dot, L".cfg");
-        }
-    }
-    char *u8 = convert_utf8_from_wchar(win_conf);
-    *cfg_exe_full = u8;
+	// system
+	sys_conf = (char *)malloc(sizeof("/etc/") + strlen(cfg_base) + 2);
+	strcpy(sys_conf, "/etc/");
+	strcat(sys_conf, cfg_base);
+	p = strrchr(sys_conf, '.');
+	strcpy(p, ".conf");		// ".cfg" -> ".conf"
 
-    char *bs = strrchr(u8, '/');
-    *cfg = strdup(bs+1);
+	// $APPDATA/teraterm5/cygterm.cfg
+	char *appdata = get_appdata_dir();
+	size_t len = strlen(appdata) + 1 + strlen(cfg_base) + 1;
+	conf_appdata_full = (char *)malloc(sizeof(char) * len);
+	strcpy(conf_appdata_full, appdata);
+	strcat(conf_appdata_full, "/");
+	strcat(conf_appdata_full, cfg_base);
+	free(appdata);
+}
 
-    char *appdata = get_appdata_dir();
-    const char *teraterm = "/teraterm5/";
-    size_t len = strlen(appdata) + strlen(teraterm) + strlen(*cfg) + 1;
-    *cfg_appdata_full = (char *)malloc(sizeof(wchar_t) * len);
-    strcpy(*cfg_appdata_full, appdata);
-    strcat(*cfg_appdata_full, teraterm);
-    strcat(*cfg_appdata_full, *cfg);
-    free(appdata);
+/**
+ *  read /etc/passwd
+ *  get user name from getlogin().  if it fails, use $USERNAME instead.
+ *  and get /etc/passwd information by getpwnam(3) with user name,
+ */
+static void get_username_and_shell(cfg_data_t *cfg)
+{
+	const char* username = getlogin();
+	if (username == NULL)
+		username = getenv("USERNAME");
+	if (username != NULL) {
+		struct passwd* pw_ent = getpwnam(username);
+		if (pw_ent != NULL) {
+			free(cfg->shell);
+			cfg->shell = strdup(pw_ent->pw_shell);
+			free(cfg->username);
+			cfg->username = strdup(pw_ent->pw_name);
+		}
+		else {
+			free(cfg->username);
+			cfg->username = strdup(username);
+		}
+	}
 }
 
 //====================//
 // load configuration //
 //--------------------//
-void load_cfg()
+static void load_cfg(cfg_data_t *cfg)
 {
-    // configuration file (.cfg) path
-    char *conf_exe_full;
-    char *conf_appdata_full;
-    char *conf_base;
-    get_cfg_filenames(&conf_exe_full, &conf_appdata_full, &conf_base);
+	char *conf_path[] = {
+		cfg_exe,	  // [exe directory]/cygterm.cfg
+		sys_conf,			// /etc/cygterm.conf
+		conf_appdata_full,	// $APPDATA/teraterm5/cygterm.cfg
+		usr_conf			// ~/cygtermrc
+	};
+	for (int i = 0; i < (int)(sizeof(conf_path)/sizeof(conf_path[0])); i++) {
+		const char *fname = conf_path[i];
+		debug_msg_print("load %s", fname);
+		// ignore empty configuration file path
+		if (fname == NULL || strcmp(fname, "") == 0) {
+			debug_msg_print("  pass");
+			continue;
+		}
 
-    char sys_conf[] = "/etc/cygterm.conf";
-
-    // user configuration file (~/.*rc) path
-    char usr_conf[MAX_PATH] = "";
-
-    // auto generated configuration file path
-    char tmp_conf[MAX_PATH] = "/tmp/cygtermrc.XXXXXX";
-
-    // get user name from getlogin().  if it fails, use $USERNAME instead.
-    // and get /etc/passwd information by getpwnam(3) with user name,
-    // and generate temporary configuration file by mktemp(3).
-    const char* username = getlogin();
-    if (username == NULL)
-        username = getenv("USERNAME");
-    if (username != NULL) {
-        struct passwd* pw_ent = getpwnam(username);
-        if (pw_ent != NULL) {
-            strncpy(pw_shell, pw_ent->pw_shell, sizeof(pw_shell)-1);
-            pw_shell[sizeof(pw_shell)-1] = 0;
-
-            strcpy(usr_conf, pw_ent->pw_dir);
-            strcat(usr_conf, "/.");
-            strcat(usr_conf, conf_base);
-            char* dot = strrchr(usr_conf, '.');
-            if (dot == NULL) {
-                strcat(usr_conf, "rc");
-            } else {
-                strcpy(dot, "rc");
-            }
-        }
-        int fd = mkstemp(tmp_conf);
-        FILE* fp = fdopen(fd, "w");
-        if (fp != NULL) {
-            if (pw_ent != NULL) {
-                fprintf(fp, "ENV_1=USER=%s\n",  pw_ent->pw_name);
-                fprintf(fp, "ENV_2=SHELL=%s\n", pw_ent->pw_shell);
-                fprintf(fp, "SHELL=%s\n", pw_ent->pw_shell);
-            } else {
-                fprintf(fp, "ENV_1=USER=%s\n",       username);
-            }
-            fclose(fp);
-        }
-    }
-
-    if (strcmp(usr_conf, "") == 0) {
-        strcpy(usr_conf, "");
-        strcpy(tmp_conf, "");
-    }
-
-    char const *conf_path[] = {
-        tmp_conf,
-        conf_exe_full,      // [exe directory]/cygterm.cfg
-        sys_conf,           // /etc/cygterm.conf
-        conf_appdata_full,  // $APPDATA/teraterm5/cygterm.cfg
-        usr_conf            // ~/cygtermrc
-    };
-    for (int i = 0; i < sizeof(conf_path)/sizeof(conf_path[0]); i++) {
-        // ignore empty configuration file path
-        if (strcmp(conf_path[i], "") == 0) {
-            continue;
-        }
-        // read each setting parameter
-        FILE* fp;
-        if ((fp = fopen(conf_path[i], "r")) == NULL) {
-            continue;
-        }
-        char buf[BUFSIZ];
-        while (fgets(buf, sizeof(buf), fp) != NULL) {
-            parse_cfg_line(buf);
-        }
-        fclose(fp);
-    }
-
-    // remove temporary configuration file, if it was generated.
-    if (strcmp(tmp_conf, "") != 0) {
-        unlink(tmp_conf);
-    }
-
-    free(conf_base);
-    free(conf_exe_full);
-    free(conf_appdata_full);
+		bool r = cfg->load(cfg, fname);
+		debug_msg_print("  %s", r ? "ok" : "ng");
+		cfg->dump(cfg, debug_msg_print);
+	}
 }
 
 void quote_cut(char *dst, size_t len, char *src) {
@@ -483,87 +318,80 @@
 //=======================//
 // commandline arguments //
 //-----------------------//
-void get_args(int argc, char** argv)
+void get_args(char** argv, cfg_data_t *cfg)
 {
-    char tmp[sizeof(cmd_termopt)];
-
     for (++argv; *argv != NULL; ++argv) {
         if (!strcmp(*argv, "-t")) {             // -t <terminal emulator>
             if (*++argv == NULL)
                 break;
-            strncpy(cmd_term, *argv, sizeof(cmd_term)-1);
-            cmd_term[sizeof(cmd_term)-1] = '\0';
+            free(cfg->term);
+            cfg->term = strdup(*argv);
         }
         else if (!strcmp(*argv, "-p")) {        // -p <port#>
             if (*(argv+1) != NULL) {
-                ++argv, cl_port = atoi(*argv);
+                ++argv;
+                cfg->cl_port = atoi(*argv);
             }
         }
         else if (!strcmp(*argv, "-dumb")) {     // -dumb
-            dumb = true;
-            strcpy(term_type, "dumb");
+            cfg->dumb = 1;
+            free(cfg->term_type);
+            cfg->term_type = strdup("dumb");
         }
         else if (!strcmp(*argv, "-s")) {        // -s <shell>
             if (*++argv == NULL)
                 break;
-	    if (strcasecmp(*argv, "AUTO") != 0) {
-		strncpy(cmd_shell, *argv, sizeof(cmd_shell)-1);
-	    }
-	    else {
-		strncpy(cmd_shell, pw_shell, sizeof(cmd_shell)-1);
-	    }
-            cmd_shell[sizeof(cmd_shell)-1] = '\0';
+            if (strcasecmp(*argv, "AUTO") != 0) {
+                free(cfg->shell);
+                cfg->shell = strdup(*argv);
+            }
         }
         else if (!strcmp(*argv, "-cd")) {       // -cd
-            home_chdir = true;
+            cfg->home_chdir = true;
         }
         else if (!strcmp(*argv, "-nocd")) {     // -nocd
-            home_chdir = false;
+            cfg->home_chdir = false;
         }
         else if (!strcmp(*argv, "+cd")) {       // +cd
-            home_chdir = false;
+            cfg->home_chdir = false;
         }
         else if (!strcmp(*argv, "-ls")) {       // -ls
-            enable_loginshell = true;
+            cfg->enable_loginshell = true;
         }
         else if (!strcmp(*argv, "-nols")) {     // -nols
-            enable_loginshell = false;
+            cfg->enable_loginshell = false;
         }
         else if (!strcmp(*argv, "+ls")) {       // +ls
-            enable_loginshell = false;
+            cfg->enable_loginshell = false;
         }
         else if (!strcmp(*argv, "-A")) {       // -A
-            enable_agent_proxy = true;
+            cfg->enable_agent_proxy = true;
         }
         else if (!strcmp(*argv, "-a")) {       // -a
-            enable_agent_proxy = false;
+            cfg->enable_agent_proxy = false;
         }
         else if (!strcmp(*argv, "-v")) {        // -v <additional env var>
             if (*(argv+1) != NULL) {
+                sh_env_t *sh_env = cfg->sh_env;
                 ++argv;
-		add_env(&sh_envp, *argv, NULL);
+                sh_env->add1(sh_env, *argv);
             }
         }
         else if (!strcmp(*argv, "-d")) {        // -d <exec directory>
             if (*++argv == NULL)
                 break;
+            char change_dir[256] = "";
             quote_cut(change_dir, sizeof(change_dir), *argv);
+            cfg->change_dir = strdup(change_dir);
         }
         else if (!strcmp(*argv, "-o")) {        // -o <additional option for terminal>
             if (*++argv == NULL)
                 break;
-            if (cmd_termopt[0] == '\0') {
-                strncpy(cmd_termopt, *argv, sizeof(cmd_termopt)-1);
-                cmd_termopt[sizeof(cmd_termopt)-1] = '\0';
-            }
-            else {
-                snprintf(tmp, sizeof(tmp), "%s %s", cmd_termopt, *argv);
-                strncpy(cmd_termopt, tmp, sizeof(cmd_termopt)-1);
-                cmd_termopt[sizeof(cmd_termopt)-1] = '\0';
-            }
+            free(cfg->termopt);
+            cfg->termopt = strdup(*argv);
         }
         else if (!strcmp(*argv, "-debug")) {    // -debug
-            debug_flag = true;
+            cfg->debug_flag = true;
         }
     }
 }
@@ -650,6 +478,7 @@
 }
 
 void sighandler(int sig) {
+	(void)sig;
 	unlink(sockname);
 	rmdir(sockdir);
 	exit(0);
@@ -707,9 +536,7 @@
 {
 	int sock, asock, ret;
 	long len;
-	unsigned long reqlen;
 	struct sockaddr_un addr;
-	unsigned char tmpbuff[AGENT_MAX_MSGLEN];
 	struct connList connections, *new_conn, *prev, *cur;
 	fd_set readfds, writefds, rfds, wfds;
 	struct sigaction act;
@@ -863,17 +690,16 @@
 	exit(0);
 }
 
-int exec_agent_proxy()
+static int exec_agent_proxy(sh_env_t *sh_env)
 {
 	int pid;
-	int malloc_size;
 
 	if (mkdtemp(sockdir) == NULL) {
 		return -1;
 	}
-	snprintf(sockname, sizeof(sockname), "%s/agent.%ld", sockdir, getpid());
+	snprintf(sockname, sizeof(sockname), "%s/agent.%ld", sockdir, (long)getpid());
 
-	if (!add_env(&sh_envp, "SSH_AUTH_SOCK", sockname)) {
+	if (sh_env->add(sh_env, "SSH_AUTH_SOCK", sockname)) {
 		return -1;
 	}
 
@@ -890,8 +716,19 @@
 //=============================//
 // terminal emulator execution //
 //-----------------------------//
-DWORD WINAPI term_thread(LPVOID)
+DWORD WINAPI term_thread(LPVOID param)
 {
+    cfg_data_t *cfg = (cfg_data_t *)param;
+
+    in_addr addr;
+    addr.s_addr = htonl(INADDR_LOOPBACK);
+    char term[256];
+    snprintf(term, sizeof(term), cfg->term, inet_ntoa(addr), (int)ntohs(listen_port));
+    if (cfg->termopt != NULL) {
+        strcat(term, " ");
+        strcat(term, cfg->termopt);
+    }
+
     STARTUPINFO si;
     PROCESS_INFORMATION pi;
     FillMemory(&si, sizeof(si), 0);
@@ -899,10 +736,12 @@
     si.dwFlags = STARTF_USESHOWWINDOW;
     si.wShowWindow = SW_SHOW;
     DWORD flag = 0;
+
+    debug_msg_print("CreateProcess '%s'", term);
     if (!CreateProcess(
-         NULL, cmd_term, NULL, NULL, FALSE, flag, NULL, NULL, &si, &pi))
+            NULL, term, NULL, NULL, FALSE, flag, NULL, NULL, &si, &pi))
     {
-        api_error(cmd_term);
+        api_error(term);
         return 0;
     }
     WaitForSingleObject(pi.hProcess, INFINITE);
@@ -911,19 +750,19 @@
     return 0;
 }
 
-//============================-==========//
+//=======================================//
 // thread creation for terminal emulator //
 //---------------------------------------//
-HANDLE exec_term()
+HANDLE exec_term(cfg_data_t *cfg)
 {
     DWORD id;
-    return CreateThread(NULL, 0, term_thread, NULL, 0, &id);
+    return CreateThread(NULL, 0, term_thread, cfg, 0, &id);
 }
 
 //=======================================//
 // listener socket for TELNET connection //
 //---------------------------------------//
-int listen_telnet(u_short* port)
+int listen_telnet(u_short* port, cfg_data_t *cfg)
 {
     int lsock;
     if ((lsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
@@ -933,13 +772,13 @@
     addr.sin_family = AF_INET;
     addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
     int i;
-    for (i = 0; i < port_range; ++i) { // find an unused port#
-        addr.sin_port = htons(port_start + i);
+    for (i = 0; i < cfg->port_range; ++i) { // find an unused port#
+        addr.sin_port = htons(cfg->port_start + i);
         if (bind(lsock, (struct sockaddr *)&addr, sizeof(addr)) == 0) {
             break;
         }
     }
-    if (i == port_range) {
+    if (i == cfg->port_range) {
         shutdown(lsock, 2);
         close(lsock);
         return -1;
@@ -956,13 +795,13 @@
 //=============================//
 // accept of TELNET connection //
 //-----------------------------//
-int accept_telnet(int lsock)
+int accept_telnet(int lsock, cfg_data_t *cfg)
 {
     fd_set rbits;
     FD_ZERO(&rbits);
     FD_SET(lsock, &rbits);
     struct timeval tm;
-    tm.tv_sec = telsock_timeout;
+    tm.tv_sec = cfg->telsock_timeout;
     tm.tv_usec = 0;
     if (select(FD_SETSIZE, &rbits, 0, 0, &tm) <= 0) {
         c_error("accept_telnet: select failed");
@@ -1057,9 +896,8 @@
 //=================//
 // shell execution //
 //-----------------//
-int exec_shell(int* sh_pid)
+static int exec_shell(int* sh_pid, cfg_data_t *cfg)
 {
-    char env_term[64];
     // open pty master
     int master;
     if ((master = open(DEVPTY, O_RDWR)) < 0) {
@@ -1098,26 +936,31 @@
             }
         }
         // set env vars
-        if (*term_type != 0) {
+        if (cfg->term_type != 0) {
             // set terminal type to $TERM
-            sprintf(env_term, "TERM=%s", term_type);
-            putenv(env_term);
+            setenv("TERM", cfg->term_type, 1);
         }
         // set other additional env vars
-        sh_env_t* e;
-        for (e = sh_env.next; e != NULL; e = e->next) {
-            putenv(e->env);
+        int i = 0;
+        sh_env_t *sh_env = cfg->sh_env;
+        while(1) {
+            char *value;
+            const char *env = sh_env->get(sh_env, i++, &value);
+            if (env == NULL) {
+                break;
+            }
+            setenv(env, value, 1);
         }
-	// change directory
-        if (change_dir[0] != 0) {
-	    if (chdir(change_dir) < 0) {
-		char tmp[256];
-		snprintf(tmp, 256, "exec_shell: Can't chdir to \"%s\".", change_dir);
-		tmp[255] = 0;
-		c_error(tmp);
-	    }
+        // change directory
+        if (cfg->change_dir != NULL) {
+            if (chdir(cfg->change_dir) < 0) {
+                char tmp[256];
+                snprintf(tmp, 256, "exec_shell: Can't chdir to \"%s\".", cfg->change_dir);
+                tmp[255] = 0;
+                c_error(tmp);
+            }
         }
-        else if (home_chdir) {
+        else if (cfg->home_chdir) {
             // chdir to home directory
             const char *home_dir = getenv("HOME");
             // ignore chdir(2) system-call error.
@@ -1125,21 +968,23 @@
         }
         // execute a shell
         char *argv[32];
+        char *cmd_shell = cfg->shell;
         get_argv(argv, 32, cmd_shell);
-        if (enable_loginshell) {
-                char shell_path[128];
-                char *pos;
-                strcpy(shell_path, argv[0]);
-                if ((pos = strrchr(argv[0], '/')) != NULL) {
-                        *pos = '-';
-                        argv[0] = pos;
-                }
-                debug_msg_print(shell_path);
-                execv(shell_path, argv);
+        cfg->shell = strdup(cmd_shell);
+        if (cfg->enable_loginshell) {
+            char shell_path[128];
+            char *pos;
+            strcpy(shell_path, argv[0]);
+            if ((pos = strrchr(argv[0], '/')) != NULL) {
+                *pos = '-';
+                argv[0] = pos;
+            }
+            debug_msg_print("execv '%s' (login shell)", shell_path);
+            execv(shell_path, argv);
         }
         else {
-                debug_msg_print(argv[0]);
-                execv(argv[0], argv);
+            debug_msg_print("execv '%s'", argv[0]);
+            execv(argv[0], argv);
         }
         // no error, exec() doesn't return
         c_error(argv[0]);
@@ -1231,6 +1076,15 @@
 bool c_will_term = false;
 bool c_will_naws = false;
 
+// terminal type & size
+//---------------------
+char *term_type;
+struct winsize win_size = {0,0,0,0};
+
+// dumb terminal flag
+//-------------------
+bool dumb = false;
+
 u_char telnet_cmd(IOBuf* te)
 {
     u_char cmd, c;
@@ -1416,60 +1270,87 @@
 //---------------------------------------------------------//
 int main(int argc, char** argv)
 {
+    (void)argc;
     int listen_sock = -1;
-    u_short listen_port;
     int te_sock = -1;
     int sh_pty = -1;
     HANDLE hTerm = NULL;
     int sh_pid, agent_pid = 0;
 
+
+    // configuration file (.cfg) path
+    get_cfg_filenames(argv[0]);
+    debug_msg_print("cfg_base %s", cfg_base);
+    debug_msg_print("cfg_exe %s", cfg_exe);
+    debug_msg_print("conf_appdata_full %s", conf_appdata_full);
+    debug_msg_print("sys_conf %s", sys_conf);
+    debug_msg_print("usr_conf %s", usr_conf);
+
+
+    // set default values
+    cfg_data_t *cfg = create_cfg();
+    cfg->port_start = PORT_START_DEFAULT;
+    cfg->port_range = PORT_RANGE_DEFAULT;
+    cfg->telsock_timeout = TELSOCK_TIMEOUT_DEFAULT;
+    cfg->home_chdir = HOME_CHDIR_DEFAULT;
+    cfg->enable_loginshell = ENABLE_LOGINSHELL_DEFAULT;
+    cfg->enable_agent_proxy = ENABLE_AGENT_PROXY_DEFAULT;
+    cfg->debug_flag = DEBUG_FLAG_DEFAULT;
+
     // load configuration
-    load_cfg();
+    get_username_and_shell(cfg);	// from /etc/passwd
+    cfg->dump(cfg, debug_msg_print);
+    load_cfg(cfg);
+    sh_env_t *sh_env = cfg->sh_env;
+    sh_env->add(sh_env, "SHELL", cfg->shell);
+    sh_env->add(sh_env, "USER", cfg->username);
+    debug_msg_print("loginshell %d", cfg->enable_loginshell);
+    cfg->dump(cfg, debug_msg_print);
 
     // read commandline arguments
-    get_args(argc, argv);
+    get_args(argv, cfg);
+    cfg->dump(cfg, debug_msg_print);
 
-    if (cmd_shell[0] == 0) {
+    // restore values
+    debug_flag = cfg->debug_flag;
+
+    if (cfg->shell == NULL) {
         msg_print("missing shell");
         return 0;
     }
-    if (cmd_term[0] == 0 && cl_port <= 0) {
+    if (cfg->term == NULL && cl_port <= 0) {
         msg_print("missing terminal");
         return 0;
     }
 
-    if (change_dir[0] != 0) {
-	home_chdir = false;
-	if (enable_loginshell) {
-	    add_env(&sh_envp, "CHERE_INVOKING=y", NULL);
-	}
+    if (cfg->change_dir != NULL) {
+        cfg->home_chdir = false;
+        if (cfg->enable_loginshell) {
+            sh_env->add(sh_env, "CHERE_INVOKING", "y");
+        }
     }
 
     // terminal side connection
-    if (cl_port > 0) {
+    if (cfg->cl_port > 0) {
         // connect to the specified TCP port
+        cl_port = cfg->cl_port;
         if ((te_sock = connect_client()) < 0) {
             goto cleanup;
         }
     } else {
         // prepare a TELNET listener socket
-        if ((listen_sock = listen_telnet(&listen_port)) < 0) {
+        if ((listen_sock = listen_telnet(&listen_port, cfg)) < 0) {
             goto cleanup;
         }
-        in_addr addr;
-        addr.s_addr = htonl(INADDR_LOOPBACK);
-        char tmp[256];
         debug_msg_print("execute terminal");
-        snprintf(tmp, sizeof(tmp), cmd_term, inet_ntoa(addr), (int)ntohs(listen_port));
-        snprintf(cmd_term, sizeof(cmd_term), "%s %s", tmp, cmd_termopt);
 
         // execute a terminal emulator
-        if ((hTerm = exec_term()) == NULL) {
+        if ((hTerm = exec_term(cfg)) == NULL) {
             api_error("exec_term failed");
             goto cleanup;
         }
         // accept connection from the terminal emulator
-        if ((te_sock = accept_telnet(listen_sock)) < 0) {
+        if ((te_sock = accept_telnet(listen_sock, cfg)) < 0) {
             goto cleanup;
         }
         shutdown(listen_sock, 2);
@@ -1477,18 +1358,20 @@
         listen_sock = -1;
     }
     // TELNET negotiation
+    term_type = cfg->term_type;
+    dumb = cfg->dumb;
     if (!dumb) {
         telnet_nego(te_sock);
     }
 
     // execute ssh-agent proxy
-    if (enable_agent_proxy) {
-        agent_pid = exec_agent_proxy();
+    if (cfg->enable_agent_proxy) {
+        agent_pid = exec_agent_proxy(sh_env);
     }
 
     // execute a shell
     debug_msg_print("execute shell");
-    if ((sh_pty = exec_shell(&sh_pid)) < 0) {
+    if ((sh_pty = exec_shell(&sh_pid, cfg)) < 0) {
         debug_msg_print("exec_shell failed");
         goto cleanup;
     }

Added: branches/cygterm/cygwin/cygterm/cygterm_cfg.cc
===================================================================
--- branches/cygterm/cygwin/cygterm/cygterm_cfg.cc	                        (rev 0)
+++ branches/cygterm/cygwin/cygterm/cygterm_cfg.cc	2022-01-28 16:36:06 UTC (rev 9706)
@@ -0,0 +1,406 @@
+/*
+ * (C) 2022- TeraTerm Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "cygterm_cfg.h"
+
+// #define DUMP_ENABLE	1
+
+// additional env vars given to a shell
+//-------------------------------------
+
+typedef struct sh_env_data_t {
+	struct sh_env_data_t* next;
+	char *name;
+	char *value;
+} sh_env_data_t;
+
+typedef struct sh_env_private_tag {
+	sh_env_data_t *envp;
+} sh_env_private_t;
+
+static bool env_add(sh_env_t *envp, const char* name, const char* value)
+{
+	sh_env_private_t *pr_data = (sh_env_private_t *)envp->private_data;
+	sh_env_data_t* e;
+
+	if (name[0] == 0) {
+		return true;
+	}
+	e = (sh_env_data_t*)malloc(sizeof(*e));
+	if (e == NULL) {
+		return false;
+	}
+
+	e->name = strdup(name);
+	e->value = strdup(value);
+	e->next = NULL;
+
+	if (pr_data->envp == NULL) {
+		pr_data->envp = e;
+		return true;
+	}
+	sh_env_data_t* env_data = pr_data->envp;
+	sh_env_data_t* prev_env = NULL;
+	while(1) {
+		if (strcmp(env_data->name, name) == 0) {
+			// \x93\xAF\x82\xB6\x96\xBC\x91O -> \x93\xFC\x82\xEA\x91ւ\xA6
+			if (prev_env == NULL) {
+				pr_data->envp = e;
+			} else {
+				prev_env->next = e;
+				e->next = prev_env->next;
+			}
+			free(env_data->name);
+			free(env_data->value);
+			free(env_data);
+			break;
+		}
+		if (env_data->next == NULL) {
+			// \x8DŌ\xE3\x82܂ŗ\x88\x82\xBD
+			env_data->next = e;
+			break;
+		}
+		prev_env = env_data;
+		env_data = env_data->next;
+	}
+
+	return true;
+}
+
+static bool env_add1(sh_env_t *envp, const char* name_value)
+{
+	if (name_value[0] == 0) {
+		return true;
+	}
+	char *name = strdup(name_value);
+	char *p = strchr(name, '=');
+	char *value;
+	if (p == NULL) {
+		value = NULL;
+	}
+	else {
+		*p = 0;
+		value = strdup(p+1);
+	}
+	bool r = env_add(envp, name, value);
+	free(value);
+	free(name);
+	return r;
+}
+
+static char *env_get(sh_env_t *envp, int index, char **value)
+{
+	sh_env_private_t *pr_data = (sh_env_private_t *)envp->private_data;
+	sh_env_data_t* e = pr_data->envp;
+	if (e == NULL) {
+		return NULL;
+	}
+	while(1) {
+		if (index == 0) {
+			*value = e->value;
+			return e->name;;
+		}
+		if (e->next == NULL) {
+			*value = NULL;
+			return NULL;
+		}
+		index--;
+		e = e->next;
+	}
+}
+
+static void env_destry_all(sh_env_t *envp)
+{
+	sh_env_private_t *pr_data = (sh_env_private_t *)envp->private_data;
+	sh_env_data_t* e = pr_data->envp;
+	if (e == NULL) {
+		return;
+	}
+	pr_data->envp = NULL;
+	while(1) {
+		sh_env_data_t* e_next = e->next;
+		e->next = NULL;
+		free(e);
+		e = e_next;
+		if (e == NULL) {
+			break;
+		}
+	}
+}
+
+static void env_destry(sh_env_t *envp)
+{
+	sh_env_private_t *pr_data = (sh_env_private_t *)envp->private_data;
+	env_destry_all(envp);
+	free(pr_data);
+	envp->private_data = NULL;
+	free(envp);
+}
+
+sh_env_t *create_sh_env(void)
+{
+	sh_env_t *sh_env = (sh_env_t *)calloc(sizeof(*sh_env), 1);
+	if (sh_env == NULL) {
+		return NULL;
+	}
+	sh_env_private_t *pr_data = (sh_env_private_t *)calloc(sizeof(*pr_data), 1);
+	if (pr_data == NULL) {
+		free(sh_env);
+		return NULL;
+	}
+	sh_env->private_data = pr_data;
+	sh_env->destroy = env_destry;
+	sh_env->add = env_add;
+	sh_env->add1 = env_add1;
+	sh_env->get = env_get;
+
+	return sh_env;
+}
+
+static bool is_bool_string(const char *s)
+{
+	if (strchr("YyTt", *s) != NULL)
+		return true;
+	if (atoi(s) > 0)
+		return true;
+
+	return false;
+}
+
+//==================================//
+// parse line in configuration file //
+//----------------------------------//
+static void parse_cfg_line(char *buf, cfg_data_t *cfg)
+{
+	// "KEY = VALUE" format in each line.
+	// skip leading/trailing blanks. KEY is not case-sensitive.
+	char* p1;
+	for (p1 = buf; isspace(*p1); ++p1);
+	if (!isalpha(*p1)) {
+		return; // comment line with non-alphabet 1st char
+	}
+	char* name = p1;
+	for (++p1; isalnum(*p1) || *p1 == '_'; ++p1);
+	char* p2;
+	for (p2 = p1; isspace(*p2); ++p2);
+	if (*p2 != '=') {
+		return; // igonore line without '='
+	}
+	for (++p2; isspace(*p2); ++p2);
+	char* val = p2;
+	for (p2 += strlen(p2); isspace(*(p2-1)); --p2);
+	*p1 = *p2 = 0;
+
+	if (!strcasecmp(name, "TERM")) {
+		// terminal emulator command line (host:%s, port#:%d)
+		free(cfg->term);
+		cfg->term = strdup(val);
+	}
+	else if (!strcasecmp(name, "SHELL")) {
+		// shell command line
+		if (strcasecmp(val, "AUTO") != 0) {
+			free(cfg->shell);
+			cfg->shell = strdup(val);
+		}
+	}
+	else if (!strcasecmp(name, "PORT_START")) {
+		// minimum port# for TELNET
+		cfg->port_start = atoi(val);
+	}
+	else if (!strcasecmp(name, "PORT_RANGE")) {
+		// number of ports for TELNET
+		cfg->port_range = atoi(val);
+	}
+	else if (!strcasecmp(name, "TERM_TYPE")) {
+		// terminal type name (maybe overridden by TELNET negotiation.)
+		free(cfg->term_type);
+		cfg->term_type = strdup(val);
+	}
+	else if (!strncasecmp(name, "ENV_", 4)) {
+		// additional env vars given to a shell
+		sh_env_t *sh_env = cfg->sh_env;
+		sh_env->add1(sh_env, val);
+	}
+	else if (!strcasecmp(name, "HOME_CHDIR")) {
+		// change directory to home
+		if (is_bool_string(val)) {
+			cfg->home_chdir = true;
+		}
+	}
+	else if (!strcasecmp(name, "LOGIN_SHELL")) {
+		// execute a shell as a login shell
+		if (is_bool_string(val)) {
+			cfg->enable_loginshell = true;
+		}
+	}
+	else if (!strcasecmp(name, "SOCKET_TIMEOUT")) {
+		// telnet socket timeout
+		cfg->telsock_timeout = atoi(val);
+	}
+	else if (!strcasecmp(name, "SSH_AGENT_PROXY")) {
+		// ssh-agent proxy
+		if (is_bool_string(val)) {
+			cfg->enable_agent_proxy = true;
+		}
+	}
+	else if (!strcasecmp(name, "DEBUG")) {
+		// debug mode
+		if (is_bool_string(val)) {
+			cfg->debug_flag = true;
+		}
+	}
+}
+
+typedef struct {
+	sh_env_data_t *env;
+} cfg_private_data_t;
+
+static void destroy(cfg_data_t *cfg_data)
+{
+//	env_destry_all(cfg_data);
+	sh_env_t *sh_env = cfg_data->sh_env;
+	sh_env->destroy(sh_env);
+	cfg_private_data_t *pr_data = (cfg_private_data_t *)cfg_data->private_data;
+	free(pr_data);
+	free(cfg_data);
+}
+
+// read each setting parameter
+// configuration file (.cfg) path
+static bool load_cfg(cfg_data_t *cfg_data, const char *conf)
+{
+	FILE* fp = fopen(conf, "r");
+	if (fp == NULL) {
+		return false;
+	}
+
+	char buf[BUFSIZ];
+	while (fgets(buf, sizeof(buf), fp) != NULL) {
+		parse_cfg_line(buf, cfg_data);
+	}
+	fclose(fp);
+
+	return true;
+}
+
+#if !defined(offsetof)
+#define offsetof(s,m) ((size_t)&(((s*)0)->m))
+#endif
+
+#if DUMP_ENABLE
+static void dump(cfg_data_t *cfg_data, void (*print)(const char* msg, ...))
+{
+	const static struct {
+		const char *name;
+		size_t offset;
+		char type;
+	} list[] = {
+		{ "username", offsetof(cfg_data_t, username), 's' },
+		{ "term", offsetof(cfg_data_t, term), 's' },
+		{ "termopt", offsetof(cfg_data_t, termopt), 's' },
+		{ "shell", offsetof(cfg_data_t, shell), 's' },
+		{ "term_type", offsetof(cfg_data_t, term_type), 's' },
+		{ "change_dir", offsetof(cfg_data_t, change_dir), 's' },
+		{ "port_start", offsetof(cfg_data_t, port_start), 'i' },
+		{ "port_range", offsetof(cfg_data_t, port_range), 'i' },
+		{ "cl_port", offsetof(cfg_data_t, cl_port), 'i' },
+		{ "home_chdir", offsetof(cfg_data_t, home_chdir), 'b' },
+		{ "enable_loginshell", offsetof(cfg_data_t, enable_loginshell), 'b' },
+		{ "telsock_timeout", offsetof(cfg_data_t, telsock_timeout), 'i' },
+		{ "enable_agent_proxy", offsetof(cfg_data_t, enable_agent_proxy), 'b' },
+		{ "dumb", offsetof(cfg_data_t, dumb), 'b' },
+		{ "debug_flag", offsetof(cfg_data_t, debug_flag), 'b' },
+	};
+	for (int i = 0; i < (int)(sizeof(list)/sizeof(list[0])); i++) {
+		uint8_t *p = (uint8_t *)cfg_data + list[i].offset;
+		switch (list[i].type) {
+		case 's': {
+			char *str = *(char **)p;
+			print("%s=%s", list[i].name, str == NULL ? "NULL" : str);
+			break;
+		}
+		case 'i': {
+			int i2 = *(int *)p;
+			print("%s=%d(0x%x)", list[i].name, i2, i2);
+			break;
+		}
+		case 'b': {
+			bool b = *(bool *)p;
+			print("%s=%i(%s)", list[i].name, b, b ? "true" : "false");
+			break;
+		}
+		default:
+			print("?");
+			break;
+		}
+	}
+
+	sh_env_t *sh_env = cfg_data->sh_env;
+	for(int i = 0;;i++) {
+		char *value;
+		const char *env = sh_env->get(sh_env, i, &value);
+		if (env == NULL) {
+			break;
+		}
+		print("env %d %s=%s", i, env, value);
+	}
+}
+#else
+static void dump(cfg_data_t *cfg_data, void (*print)(const char* msg, ...))
+{
+	(void)cfg_data;
+	(void)print;
+}
+#endif
+
+cfg_data_t *create_cfg(void)
+{
+	cfg_data_t *cfg_data = (cfg_data_t *)calloc(sizeof(*cfg_data), 1);
+	if (cfg_data == NULL) {
+		return NULL;
+	}
+	cfg_private_data_t *pr_data = (cfg_private_data_t *)calloc(sizeof(*pr_data), 1);
+	if (pr_data == NULL) {
+		free(cfg_data);
+		return NULL;
+	}
+
+	// data, func
+	cfg_data->private_data = pr_data;
+	cfg_data->sh_env = create_sh_env();
+	cfg_data->destroy = destroy;
+	cfg_data->load = load_cfg;
+	cfg_data->dump = dump;
+
+	return cfg_data;
+}

Added: branches/cygterm/cygwin/cygterm/cygterm_cfg.h
===================================================================
--- branches/cygterm/cygwin/cygterm/cygterm_cfg.h	                        (rev 0)
+++ branches/cygterm/cygwin/cygterm/cygterm_cfg.h	2022-01-28 16:36:06 UTC (rev 9706)
@@ -0,0 +1,74 @@
+/*
+ * (C) 2022- TeraTerm Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct sh_env_tag {
+	void (*destroy)(struct sh_env_tag *sh_env_tag);
+	bool (*add)(struct sh_env_tag *sh_env_tag, const char *name, const char *value);
+	bool (*add1)(struct sh_env_tag *sh_env_tag, const char *namevalue);
+	char *(*get)(struct sh_env_tag *sh_env_tag, int index, char **value);
+	void *private_data;
+} sh_env_t;
+
+sh_env_t *create_sh_env(void);
+
+typedef struct cfg_data_tag {
+	char *username;
+	char *term;					// ex. "ttermpro.exe %s %d"
+	char *termopt;				// ex. "/KR-UTF8"
+	char *shell;				// ex. "/usr/bin/bash"
+	char *term_type;			// terminal type ex. "vt100"
+	char *change_dir;			// cd \x82\xB5\x82\xBD\x8C\xE3\x81A\x83V\x83F\x83\x8B\x8BN\x93\xAE
+	int port_start;				// default lowest port number
+	int port_range;				// default number of ports
+	int cl_port;
+	bool home_chdir;			// chdir to HOME
+	bool enable_loginshell;		// login shell flag
+	int telsock_timeout;		// telnet socket timeout
+	bool enable_agent_proxy;	// ssh agent proxy
+	bool dumb;
+	bool debug_flag;			// debug mode
+	bool (*save)(struct cfg_data_tag *cfg_data_tag, const char *fname);
+	bool (*load)(struct cfg_data_tag *cfg_data_tag, const char *fname);
+	void (*destroy)(struct cfg_data_tag *cfg_data_tag);
+	void (*dump)(struct cfg_data_tag *cfg_data_tag, void (*print)(const char* msg, ...));
+	sh_env_t *sh_env;
+	void *private_data;
+} cfg_data_t;
+
+cfg_data_t *load_cfg(const char *cfg);
+cfg_data_t *create_cfg(void);
+
+#ifdef __cplusplus
+}
+#endif

Modified: branches/cygterm/teraterm/common/CMakeLists.txt
===================================================================
--- branches/cygterm/teraterm/common/CMakeLists.txt	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/teraterm/common/CMakeLists.txt	2022-01-28 16:36:06 UTC (rev 9706)
@@ -38,6 +38,7 @@
   ttlib.h
   ttlib_static.c
   ttlib_static_cpp.cpp
+  ttlib_static_dirs.cpp
   ttlib_charset.h
   ttlib_charset.cpp
   win32helper.cpp

Modified: branches/cygterm/teraterm/common/asprintf.cpp
===================================================================
--- branches/cygterm/teraterm/common/asprintf.cpp	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/teraterm/common/asprintf.cpp	2022-01-28 16:36:06 UTC (rev 9706)
@@ -29,7 +29,9 @@
 #include <stdio.h>
 #define _CRTDBG_MAP_ALLOC
 #include <stdlib.h>
+#if defined(_MSC_VER) || defined(__MINGW32__)
 #include <crtdbg.h>
+#endif
 #include <assert.h>
 #include <string.h>
 #include <wchar.h>
@@ -41,6 +43,11 @@
 #define _Printf_format_string_
 #endif
 
+#if defined(__CYGWIN__)
+#define _wcsdup(p)	wcsdup(p)
+#endif
+
+#if !defined(__CYGWIN__)
 /**
  *	\x97̈\xE6\x82\xF0\x8Am\x95ۂ\xB5\x82āA\x95\xB6\x8E\x9A\x97\xF1\x82\xF0\x83t\x83H\x81[\x83}\x83b\x83g\x82\xB5\x82āA\x83|\x83C\x83\x93\x83^\x95Ԃ\xB7
  *	\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7 free() \x82\xB7\x82邱\x82\xC6
@@ -140,6 +147,7 @@
 	va_end(ap);
 	return r;
 }
+#endif //!defined(__CYGWIN__)
 
 /**
  *	\x95\xB6\x8E\x9A\x97\xF1\x82\xF0\x98A\x8C\x8B\x82\xB7\x82\xE9

Modified: branches/cygterm/teraterm/common/codeconv.cpp
===================================================================
--- branches/cygterm/teraterm/common/codeconv.cpp	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/teraterm/common/codeconv.cpp	2022-01-28 16:36:06 UTC (rev 9706)
@@ -35,10 +35,14 @@
 #define _CRTDBG_MAP_ALLOC
 #endif
 #include <stdlib.h>
+#if defined(_MSC_VER) || defined(__MINGW32__)
 #include <crtdbg.h>
+#endif
 #if (defined(_MSC_VER) && (_MSC_VER >= 1600)) || !defined(_MSC_VER)
 #include <stdint.h>
 #endif
+#include <wchar.h>
+
 #include "codemap.h"
 #include "codeconv.h"
 #include "ttcstd.h"
@@ -46,6 +50,12 @@
 // cp932\x95ϊ\xB7\x8E\x9E\x81AWindows API \x82\xE6\x82\xE8 Tera Term \x82̕ϊ\xB7\x83e\x81[\x83u\x83\x8B\x82\xF0\x97D\x90悷\x82\xE9
 //#define PRIORITY_CP932_TABLE
 
+#if defined(__CYGWIN__)
+#define _wcsdup(p1)	wcsdup(p1)
+#define _strdup(p1)	strdup(p1)
+#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
+#endif
+
 /*
  *	\x8C\xA9\x82‚\xA9\x82\xE7\x82Ȃ\xA2\x8Fꍇ\x82\xCD 0 \x82\xF0\x95Ԃ\xB7
  */

Modified: branches/cygterm/teraterm/common/common_static.v16.vcxproj
===================================================================
--- branches/cygterm/teraterm/common/common_static.v16.vcxproj	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/teraterm/common/common_static.v16.vcxproj	2022-01-28 16:36:06 UTC (rev 9706)
@@ -151,6 +151,7 @@
     <ClCompile Include="ttlib_charset.cpp" />
     <ClCompile Include="ttlib_static.c" />
     <ClCompile Include="ttlib_static_cpp.cpp" />
+    <ClCompile Include="ttlib_static_dirs.cpp" />
     <ClCompile Include="win32helper.cpp" />
   </ItemGroup>
   <ItemGroup>

Modified: branches/cygterm/teraterm/common/compat_win.cpp
===================================================================
--- branches/cygterm/teraterm/common/compat_win.cpp	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/teraterm/common/compat_win.cpp	2022-01-28 16:36:06 UTC (rev 9706)
@@ -31,6 +31,10 @@
 #include <windows.h>
 #include <windns.h>
 #include <assert.h>
+#include <wchar.h>
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include <crtdbg.h>
+#endif
 
 #include "compat_win.h"
 #include "compat_windns.h"
@@ -38,6 +42,11 @@
 #include "dllutil.h"
 #include "codeconv.h"
 
+#if defined(__CYGWIN__)
+#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
+#define _wcsdup(p) wcsdup(p)
+#endif
+
 // for debug
 //#define UNICODE_API_DISABLE	1
 

Modified: branches/cygterm/teraterm/common/dllutil.cpp
===================================================================
--- branches/cygterm/teraterm/common/dllutil.cpp	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/teraterm/common/dllutil.cpp	2022-01-28 16:36:06 UTC (rev 9706)
@@ -26,12 +26,16 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#define __STDC_WANT_LIB_EXT1__
 #include <windows.h>
 #include <assert.h>
 #if !defined(_CRTDBG_MAP_ALLOC)
 #define _CRTDBG_MAP_ALLOC
 #endif
+#if defined(_MSC_VER) || defined(__MINGW32__)
 #include <crtdbg.h>
+#endif
+#include <wchar.h>
 
 #include "compat_win.h"
 #include "ttlib.h"	// for IsWindowsXPOrLater()
@@ -38,6 +42,11 @@
 
 #include "dllutil.h"
 
+#if defined(__CYGWIN__)
+#define _countof(_Array) (sizeof(_Array) / sizeof(_Array[0]))
+#define _wcsdup(p) wcsdup(p)
+#endif
+
 typedef struct {
 	const wchar_t *fname;
 	BOOL NeedFreeLibrary;
@@ -48,6 +57,14 @@
 static HandleList_t *HandleList;
 static int HandleListCount;
 
+#if defined(__CYGWIN__) && !defined(__STDC_LIB_EXT1__)
+static void wcscat_s(wchar_t *dest, rsize_t size, const wchar_t *src)
+{
+	(void)size;
+	wcscat(dest, src);
+}
+#endif
+
 static HMODULE GetHandle(const wchar_t *fname, DLLLoadFlag LoadFlag)
 {
 	HMODULE module;

Modified: branches/cygterm/teraterm/common/ttknownfolders.c
===================================================================
--- branches/cygterm/teraterm/common/ttknownfolders.c	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/teraterm/common/ttknownfolders.c	2022-01-28 16:36:06 UTC (rev 9706)
@@ -28,7 +28,8 @@
 
 #include <windows.h>
 
-#if !defined(NTDDI_VERSION) || (NTDDI_VERSION < NTDDI_VISTA)
+//#if !defined(NTDDI_VERSION) || (NTDDI_VERSION < NTDDI_VISTA)
+#if 1
 // FOLDERID_* \x82\xAASDK\x93\xE0\x82ɒ\xE8\x8B`\x82\xB3\x82\xEA\x82Ă\xA2\x82Ȃ\xA2
 // \x82\xB1\x82̃t\x83@\x83C\x83\x8B(*.obj)\x82Ɏ\xC0\x91̂\xF0\x92u\x82\xAD
 #define INITGUID

Modified: branches/cygterm/teraterm/common/ttlib.h
===================================================================
--- branches/cygterm/teraterm/common/ttlib.h	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/teraterm/common/ttlib.h	2022-01-28 16:36:06 UTC (rev 9706)
@@ -29,6 +29,8 @@
 
 /* useful routines */
 
+#include <time.h>	// for time_t
+
 #pragma once
 
 #include "i18n.h"
@@ -108,7 +110,7 @@
 DllExport void OutputDebugPrintf(_Printf_format_string_ const char *fmt, ...);
 void OutputDebugPrintfW(_Printf_format_string_ const wchar_t *fmt, ...);
 #elif defined(__GNUC__)
-DllExport void OutputDebugPrintf(_Printf_format_string_ const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+DllExport void OutputDebugPrintf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
 void OutputDebugPrintfW(const wchar_t *fmt, ...); // __attribute__ ((format (wprintf, 1, 2)));
 #else
 DllExport void OutputDebugPrintf(const char *fmt, ...);

Modified: branches/cygterm/teraterm/common/ttlib_static_cpp.cpp
===================================================================
--- branches/cygterm/teraterm/common/ttlib_static_cpp.cpp	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/teraterm/common/ttlib_static_cpp.cpp	2022-01-28 16:36:06 UTC (rev 9706)
@@ -36,7 +36,9 @@
 #define _CRTDBG_MAP_ALLOC
 #endif
 #include <stdlib.h>
+#if defined(_MSC_VER) || defined(__MINGW32__)
 #include <crtdbg.h>
+#endif
 #include <assert.h>
 #include <wchar.h>
 #include <shlobj.h>
@@ -735,59 +737,6 @@
 }
 
 /**
- *	\x83t\x83@\x83C\x83\x8B\x96\xBC(\x83p\x83X\x96\xBC)\x82\xF0\x89\xF0\x90͂\xB7\x82\xE9
- *	GetFileNamePos() \x82\xCC wchar_t\x94\xC5
- *
- *	@param[in]	PathName	\x83t\x83@\x83C\x83\x8B\x96\xBC\x81A\x83t\x83\x8B\x83p\x83X
- *	@param[out]	DirLen		\x96\x96\x94\xF6\x82̃X\x83\x89\x83b\x83V\x83\x85\x82\xF0\x8A܂ރf\x83B\x83\x8C\x83N\x83g\x83\x8A\x83p\x83X\x92\xB7
- *							NULL\x82̂Ƃ\xAB\x92l\x82\xF0\x95Ԃ\xB3\x82Ȃ\xA2
- *	@param[out]	FNPos		\x83t\x83@\x83C\x83\x8B\x96\xBC\x82ւ\xCCindex
- *							&PathName[FNPos] \x82\xAA\x83t\x83@\x83C\x83\x8B\x96\xBC
- *							NULL\x82̂Ƃ\xAB\x92l\x82\xF0\x95Ԃ\xB3\x82Ȃ\xA2
- *	@retval		FALSE		PathName\x82\xAA\x95s\x90\xB3
- */
-BOOL GetFileNamePosW(const wchar_t *PathName, size_t *DirLen, size_t *FNPos)
-{
-	const wchar_t *Ptr;
-	const wchar_t *DirPtr;
-	const wchar_t *FNPtr;
-	const wchar_t *PtrOld;
-
-	if (DirLen != NULL) *DirLen = 0;
-	if (FNPos != NULL) *FNPos = 0;
-
-	if (PathName==NULL)
-		return FALSE;
-
-	if ((wcslen(PathName)>=2) && (PathName[1]==L':'))
-		Ptr = &PathName[2];
-	else
-		Ptr = PathName;
-	if (Ptr[0]=='\\' || Ptr[0]=='/')
-		Ptr++;
-
-	DirPtr = Ptr;
-	FNPtr = Ptr;
-	while (Ptr[0]!=0) {
-		wchar_t b = Ptr[0];
-		PtrOld = Ptr;
-		Ptr++;
-		switch (b) {
-			case L':':
-				return FALSE;
-			case L'/':	/* FALLTHROUGH */
-			case L'\\':
-				DirPtr = PtrOld;
-				FNPtr = Ptr;
-				break;
-		}
-	}
-	if (DirLen != NULL) *DirLen = DirPtr-PathName;
-	if (FNPos != NULL) *FNPos = FNPtr-PathName;
-	return TRUE;
-}
-
-/**
  *	ConvHexCharW() \x82\xCC wchar_t \x94\xC5
  */
 BYTE ConvHexCharW(wchar_t b)
@@ -849,100 +798,7 @@
 	return (int)j;
 }
 
-/**
- *	ExtractFileName() \x82\xCC wchar_t \x94\xC5
- *	\x83t\x83\x8B\x83p\x83X\x82\xA9\x82\xE7\x83t\x83@\x83C\x83\x8B\x96\xBC\x95\x94\x95\xAA\x82\xF0\x8E\xE6\x82\xE8\x8Fo\x82\xB7
- *
- *	@return	\x83t\x83@\x83C\x83\x8B\x96\xBC\x95\x94\x95\xAA(\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7free()\x82\xB7\x82\xE9)
- */
-wchar_t *ExtractFileNameW(const wchar_t *PathName)
-{
-	size_t i;
-	if (!GetFileNamePosW(PathName, NULL, &i))
-		return NULL;
-	wchar_t *filename = _wcsdup(&PathName[i]);
-	return filename;
-}
-
-/**
- *	ExtractDirName() \x82\xCC wchar_t \x94\xC5
- *
- *	@return	\x83f\x83B\x83\x8C\x83N\x83g\x83\x8A\x96\xBC\x95\x94\x95\xAA(\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7free()\x82\xB7\x82\xE9)
- */
-wchar_t *ExtractDirNameW(const wchar_t *PathName)
-{
-	size_t i;
-	wchar_t *DirName = _wcsdup(PathName);
-	if (!GetFileNamePosW(DirName, &i, NULL))
-		return NULL;
-	DirName[i] = 0;
-	return DirName;
-}
-
 /*
- * Get Exe(exe,dll) directory
- *	ttermpro.exe, \x83v\x83\x89\x83O\x83C\x83\x93\x82\xAA\x82\xA0\x82\xE9\x83t\x83H\x83\x8B\x83_
- *	ttypes.ExeDirW \x82Ɠ\xAF\x88\xEA
- *	\x82\xE0\x82Ƃ\xCD GetHomeDirW() \x82\xBE\x82\xC1\x82\xBD
- *
- * @param[in]		hInst		WinMain()\x82\xCC HINSTANCE \x82܂\xBD\x82\xCD NULL
- * @return			ExeDir		\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7 free() \x82\xB7\x82邱\x82\xC6
- */
-wchar_t *GetExeDirW(HINSTANCE hInst)
-{
-	wchar_t *TempW;
-	wchar_t *dir;
-	DWORD error = hGetModuleFileNameW(hInst, &TempW);
-	if (error != NO_ERROR) {
-		// \x83p\x83X\x82̎擾\x82Ɏ\xB8\x94s\x82\xB5\x82\xBD\x81B\x92v\x96\xBD\x93I\x81Aabort() \x82\xB7\x82\xE9\x81B
-		abort();
-	}
-	dir = ExtractDirNameW(TempW);
-	free(TempW);
-	return dir;
-}
-
-/*
- * Get home directory
- *		\x8Cl\x97p\x90ݒ\xE8\x83t\x83@\x83C\x83\x8B\x83t\x83H\x83\x8B\x83_\x8E擾
- *		ttypes.HomeDirW \x82Ɠ\xAF\x88\xEA
- *		TERATERM.INI \x82Ȃǂ\xAA\x82\xA8\x82\xA2\x82Ă\xA0\x82\xE9\x83t\x83H\x83\x8B\x83_
- *		ttermpro.exe \x82\xAA\x82\xA0\x82\xE9\x83t\x83H\x83\x8B\x83_\x82\xCD GetExeDirW() \x82Ŏ擾
- *		%APPDATA%\teraterm5 (%USERPROFILE%\AppData\Roaming\teraterm5)
- *
- * @param[in]		hInst		WinMain()\x82\xCC HINSTANCE \x82܂\xBD\x82\xCD NULL
- * @return			HomeDir		\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7 free() \x82\xB7\x82邱\x82\xC6
- */
-wchar_t *GetHomeDirW(HINSTANCE hInst)
-{
-	wchar_t *path;
-	_SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &path);
-	wchar_t *ret = NULL;
-	awcscats(&ret, path, L"\\teraterm5", NULL);
-	free(path);
-	return ret;
-}
-
-/*
- * Get log directory
- *		\x83\x8D\x83O\x95ۑ\xB6\x83t\x83H\x83\x8B\x83_\x8E擾
- *		ttypes.LogDirW \x82Ɠ\xAF\x88\xEA
- *		%LOCALAPPDATA%\teraterm5 (%USERPROFILE%\AppData\Local\teraterm5)
- *
- * @param[in]		hInst		WinMain()\x82\xCC HINSTANCE \x82܂\xBD\x82\xCD NULL
- * @return			LogDir		\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7 free() \x82\xB7\x82邱\x82\xC6
- */
-wchar_t* GetLogDirW(void)
-{
-	wchar_t *path;
-	_SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path);
-	wchar_t *ret = NULL;
-	awcscats(&ret, path, L"\\teraterm5", NULL);
-	free(path);
-	return ret;
-}
-
-/*
  *	UILanguageFile\x82̃t\x83\x8B\x83p\x83X\x82\xF0\x8E擾\x82\xB7\x82\xE9
  *
  *	@param[in]		HomeDir					exe,dll\x82̑\xB6\x8D݂\xB7\x82\xE9\x83t\x83H\x83\x8B\x83_ GetExeDir()\x82Ŏ擾\x82ł\xAB\x82\xE9

Added: branches/cygterm/teraterm/common/ttlib_static_dirs.cpp
===================================================================
--- branches/cygterm/teraterm/common/ttlib_static_dirs.cpp	                        (rev 0)
+++ branches/cygterm/teraterm/common/ttlib_static_dirs.cpp	2022-01-28 16:36:06 UTC (rev 9706)
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2020- TeraTerm Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* C99\x95\x97\x82ɋL\x8Fq\x82ł\xAB\x82\xE9\x82悤\x82\xC9cpp\x82Ƃ\xB5\x82\xBD */
+/* Visual Studio 2005 \x82\xAA C89 */
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#if !defined(_CRTDBG_MAP_ALLOC)
+#define _CRTDBG_MAP_ALLOC
+#endif
+#include <stdlib.h>
+#if defined(_MSC_VER) || defined(__MINGW32__)
+#include <crtdbg.h>
+#endif
+#include <assert.h>
+#include <wchar.h>
+#include <shlobj.h>
+#include <malloc.h>
+#include <time.h>
+
+#include "i18n.h"
+#include "asprintf.h"
+#include "win32helper.h"
+#include "codeconv.h"
+#include "compat_win.h"
+#include "fileread.h"
+
+#include "ttlib.h"
+
+#if defined(__CYGWIN__)
+#define _wcsdup(p1) wcsdup(p1)
+#endif
+
+/**
+ *	\x83|\x81[\x83^\x83u\x83\x8B\x94łƎw\x92蓮\x8D삷\x82邩
+ *
+ *	@retval		TRUE		\x83|\x81[\x83^\x83u\x83\x8B\x94\xC5
+ *	@retval		FALSE		\x92ʏ\xED\x83C\x83\x93\x83X\x83g\x81[\x83\x8B\x94\xC5
+ */
+BOOL IsPortableMode(void)
+{
+	return FALSE;
+}
+
+/**
+ *	\x83t\x83@\x83C\x83\x8B\x96\xBC(\x83p\x83X\x96\xBC)\x82\xF0\x89\xF0\x90͂\xB7\x82\xE9
+ *	GetFileNamePos() \x82\xCC wchar_t\x94\xC5
+ *
+ *	@param[in]	PathName	\x83t\x83@\x83C\x83\x8B\x96\xBC\x81A\x83t\x83\x8B\x83p\x83X
+ *	@param[out]	DirLen		\x96\x96\x94\xF6\x82̃X\x83\x89\x83b\x83V\x83\x85\x82\xF0\x8A܂ރf\x83B\x83\x8C\x83N\x83g\x83\x8A\x83p\x83X\x92\xB7
+ *							NULL\x82̂Ƃ\xAB\x92l\x82\xF0\x95Ԃ\xB3\x82Ȃ\xA2
+ *	@param[out]	FNPos		\x83t\x83@\x83C\x83\x8B\x96\xBC\x82ւ\xCCindex
+ *							&PathName[FNPos] \x82\xAA\x83t\x83@\x83C\x83\x8B\x96\xBC
+ *							NULL\x82̂Ƃ\xAB\x92l\x82\xF0\x95Ԃ\xB3\x82Ȃ\xA2
+ *	@retval		FALSE		PathName\x82\xAA\x95s\x90\xB3
+ */
+BOOL GetFileNamePosW(const wchar_t *PathName, size_t *DirLen, size_t *FNPos)
+{
+	const wchar_t *Ptr;
+	const wchar_t *DirPtr;
+	const wchar_t *FNPtr;
+	const wchar_t *PtrOld;
+
+	if (DirLen != NULL) *DirLen = 0;
+	if (FNPos != NULL) *FNPos = 0;
+
+	if (PathName==NULL)
+		return FALSE;
+
+	if ((wcslen(PathName)>=2) && (PathName[1]==L':'))
+		Ptr = &PathName[2];
+	else
+		Ptr = PathName;
+	if (Ptr[0]=='\\' || Ptr[0]=='/')
+		Ptr++;
+
+	DirPtr = Ptr;
+	FNPtr = Ptr;
+	while (Ptr[0]!=0) {
+		wchar_t b = Ptr[0];
+		PtrOld = Ptr;
+		Ptr++;
+		switch (b) {
+			case L':':
+				return FALSE;
+			case L'/':	/* FALLTHROUGH */
+			case L'\\':
+				DirPtr = PtrOld;
+				FNPtr = Ptr;
+				break;
+		}
+	}
+	if (DirLen != NULL) *DirLen = DirPtr-PathName;
+	if (FNPos != NULL) *FNPos = FNPtr-PathName;
+	return TRUE;
+}
+
+/**
+ *	ExtractFileName() \x82\xCC wchar_t \x94\xC5
+ *	\x83t\x83\x8B\x83p\x83X\x82\xA9\x82\xE7\x83t\x83@\x83C\x83\x8B\x96\xBC\x95\x94\x95\xAA\x82\xF0\x8E\xE6\x82\xE8\x8Fo\x82\xB7
+ *
+ *	@return	\x83t\x83@\x83C\x83\x8B\x96\xBC\x95\x94\x95\xAA(\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7free()\x82\xB7\x82\xE9)
+ */
+wchar_t *ExtractFileNameW(const wchar_t *PathName)
+{
+	size_t i;
+	if (!GetFileNamePosW(PathName, NULL, &i))
+		return NULL;
+	wchar_t *filename = _wcsdup(&PathName[i]);
+	return filename;
+}
+
+/**
+ *	ExtractDirName() \x82\xCC wchar_t \x94\xC5
+ *
+ *	@return	\x83f\x83B\x83\x8C\x83N\x83g\x83\x8A\x96\xBC\x95\x94\x95\xAA(\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7free()\x82\xB7\x82\xE9)
+ */
+wchar_t *ExtractDirNameW(const wchar_t *PathName)
+{
+	size_t i;
+	wchar_t *DirName = _wcsdup(PathName);
+	if (!GetFileNamePosW(DirName, &i, NULL))
+		return NULL;
+	DirName[i] = 0;
+	return DirName;
+}
+
+/*
+ * Get Exe(exe,dll) directory
+ *	ttermpro.exe, \x83v\x83\x89\x83O\x83C\x83\x93\x82\xAA\x82\xA0\x82\xE9\x83t\x83H\x83\x8B\x83_
+ *	ttypes.ExeDirW \x82Ɠ\xAF\x88\xEA
+ *	\x82\xE0\x82Ƃ\xCD GetHomeDirW() \x82\xBE\x82\xC1\x82\xBD
+ *
+ * @param[in]		hInst		WinMain()\x82\xCC HINSTANCE \x82܂\xBD\x82\xCD NULL
+ * @return			ExeDir		\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7 free() \x82\xB7\x82邱\x82\xC6
+ */
+wchar_t *GetExeDirW(HINSTANCE hInst)
+{
+	wchar_t *TempW;
+	wchar_t *dir;
+	DWORD error = hGetModuleFileNameW(hInst, &TempW);
+	if (error != NO_ERROR) {
+		// \x83p\x83X\x82̎擾\x82Ɏ\xB8\x94s\x82\xB5\x82\xBD\x81B\x92v\x96\xBD\x93I\x81Aabort() \x82\xB7\x82\xE9\x81B
+		abort();
+	}
+	dir = ExtractDirNameW(TempW);
+	free(TempW);
+	return dir;
+}
+
+/*
+ * Get home directory
+ *		\x8Cl\x97p\x90ݒ\xE8\x83t\x83@\x83C\x83\x8B\x83t\x83H\x83\x8B\x83_\x8E擾
+ *		ttypes.HomeDirW \x82Ɠ\xAF\x88\xEA
+ *		TERATERM.INI \x82Ȃǂ\xAA\x82\xA8\x82\xA2\x82Ă\xA0\x82\xE9\x83t\x83H\x83\x8B\x83_
+ *		ttermpro.exe \x82\xAA\x82\xA0\x82\xE9\x83t\x83H\x83\x8B\x83_\x82\xCD GetExeDirW() \x82Ŏ擾
+ *		%APPDATA%\teraterm5 (%USERPROFILE%\AppData\Roaming\teraterm5)
+ *
+ * @param[in]		hInst		WinMain()\x82\xCC HINSTANCE \x82܂\xBD\x82\xCD NULL
+ * @return			HomeDir		\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7 free() \x82\xB7\x82邱\x82\xC6
+ */
+wchar_t *GetHomeDirW(HINSTANCE hInst)
+{
+	if (IsPortableMode()) {
+		wchar_t *path;
+		_SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &path);
+		wchar_t *ret = NULL;
+		awcscats(&ret, path, L"\\teraterm5", NULL);
+		free(path);
+		return ret;
+	}
+	else {
+		return GetExeDirW(hInst);
+	}
+}
+
+/*
+ * Get log directory
+ *		\x83\x8D\x83O\x95ۑ\xB6\x83t\x83H\x83\x8B\x83_\x8E擾
+ *		ttypes.LogDirW \x82Ɠ\xAF\x88\xEA
+ *		%LOCALAPPDATA%\teraterm5 (%USERPROFILE%\AppData\Local\teraterm5)
+ *
+ * @param[in]		hInst		WinMain()\x82\xCC HINSTANCE \x82܂\xBD\x82\xCD NULL
+ * @return			LogDir		\x95s\x97v\x82ɂȂ\xC1\x82\xBD\x82\xE7 free() \x82\xB7\x82邱\x82\xC6
+ */
+wchar_t* GetLogDirW(void)
+{
+	if (IsPortableMode()) {
+		wchar_t *path;
+		_SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, NULL, &path);
+		wchar_t *ret = NULL;
+		awcscats(&ret, path, L"\\teraterm5", NULL);
+		free(path);
+		return ret;
+	}
+	else {
+		wchar_t *path;
+		_SHGetKnownFolderPath(FOLDERID_Documents, 0, NULL, &path);
+		return path;
+	}
+}

Modified: branches/cygterm/teraterm/common/win32helper.cpp
===================================================================
--- branches/cygterm/teraterm/common/win32helper.cpp	2022-01-28 16:34:34 UTC (rev 9705)
+++ branches/cygterm/teraterm/common/win32helper.cpp	2022-01-28 16:36:06 UTC (rev 9706)
@@ -29,12 +29,19 @@
 #include <windows.h>
 #define _CRTDBG_MAP_ALLOC
 #include <stdlib.h>
+#if defined(_MSC_VER) || defined(__MINGW32__)
 #include <crtdbg.h>
+#endif
+#include <wchar.h>
 
 #include "asprintf.h"
 
 #include "win32helper.h"
 
+#if defined(__CYGWIN__)
+#define _wcsdup(p1)	wcsdup(p1)
+#endif
+
 /**
  *	GetModuleFileNameW() \x82̓\xAE\x93I\x83o\x83b\x83t\x83@\x94\xC5
  *


ttssh2-commit メーリングリストの案内
Back to archive index