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 - * \x8Cl\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 + * \x8Cl\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 *