Skip to content

Commit

Permalink
New patch for mingw-w64
Browse files Browse the repository at this point in the history
Signed-off-by: LIU Hao <lh_mouse@126.com>
  • Loading branch information
lhmouse committed Dec 21, 2024
1 parent 5b7ea33 commit d35d775
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 78 deletions.
15 changes: 15 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,18 @@ core
/m4/.gitignore
/m4/gnulib-cache.m4
/snippet/

/nano.spec
/src/nano
/src/revision.h

/ncurses-*
/build_*-w64-mingw32
/*-w64-mingw32
/nano-*.7z
/.nanorc
*.exe
*.dll
share
bin
lib
38 changes: 38 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -1,3 +1,41 @@
-=* GNU nano for Windows *=-

Overview

Here is the source code for a ported, standalone version of GNU nano,
a famous, easy-to-use and handy text editor on Linux.

The script "build_nano-win.sh" can be run in MSYS2 with the mingw-w64
toolchains installed. That script statically links the executable,
nano.exe, so that it does not require any third-party .DLL files to run,
including any Microsoft Visual C++ Redistributable packages.

Enhancements

+ .nanorc is loaded from "%USERPROFILE%\.nanorc" with normal privilege
and from "%ALLUSERSPROFILE%\.nanorc" with elevated privilege.
+ Systemwide nanorc is loaded from "%ALLUSERSPROFILE%\nanorc".
+ Added C++11 keywords and identifiers with special meaning
(That is, override and final) in "doc/syntax/c.nanorc".
+ Vim-style locking files have been enabled.

Features Removed

+ Spell checker (This requires the infamous `fork()` syscall. )
+ Stop and continue (This requires the `SIGSTOP` signal. )
+ Native language support (This requires hard-coding the path to
the directory containing locale files in the executable. )

Workarounds

+ Left `Alt` key can be used as a `Meta` key.
+ UNIX style end-of-line handling by default.
+ Standard-conforming `sprintf()` function from mingw-w64.
+ UTF-8 support with UCRT (This is available only with 64-bit builds
and requires the 'Beta: Use Unicode UTF-8 for worldwide language
support' option in Windows 10 Region Settings.)

===============================================================================

GNU nano -- a simple editor, inspired by Pico

Expand Down
2 changes: 2 additions & 0 deletions autogen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ gnulib_hash="4631e9b4d5d3bd5ba42864c7001cf3509a00c7b3"

modules="
canonicalize-lgpl
fsync
futimens
getcwd
getdelim
getline
getopt-gnu
Expand Down
9 changes: 9 additions & 0 deletions build_nano-win.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@echo off

call mingw ucrt64
bash build_nano-win.sh x86_64

call mingw 32
bash build_nano-win.sh i686

bash package_nano-win.sh
47 changes: 47 additions & 0 deletions build_nano-win.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/bash -e

_build="$(gcc -v 2>&1 | sed -En 's/^Target: (.*)$/\1/;T;p')"
_host="${1:-x86_64}-w64-mingw32"
_pwd="$(cygpath -am $(pwd) || readlink -f $(pwd))"
_nproc="$(nproc)"
_prefix="$(cygpath -au $(pwd) || readlink -f $(pwd))/pkg_${_host}"
_ncurses_ver="6.5-20240928"

export CPPFLAGS="-D__USE_MINGW_ANSI_STDIO -I\"${_prefix}/include\""
export CFLAGS="-O2 -g -masm=att"
export LDFLAGS="-L\"${_prefix}/lib/\" -static"
export LIBS="-lshlwapi"

export PKG_CONFIG=true
export NCURSESW_CFLAGS="-I\"${_prefix}/include/ncursesw\" -DNCURSES_STATIC"
export NCURSESW_LIBS="-lncursesw"

wget -c "https://invisible-island.net/archives/ncurses/current/ncurses-${_ncurses_ver}.tgz"
tar -xzvf ncurses-${_ncurses_ver}.tgz
./autogen.sh

mkdir -p "${_pwd}/build_${_host}"
pushd "${_pwd}/build_${_host}"

mkdir -p "ncurses"
pushd "ncurses"
../../ncurses-${_ncurses_ver}/configure \
--build="${_build}" --host="${_host}" --prefix="${_prefix}" \
--disable-dependency-tracking \
--enable-{widec,sp-funcs,termcap,term-driver,interop} \
--disable-{shared,database,rpath,home-terminfo,db-install,getcap} \
--without-{ada,cxx-binding,manpages,pthread,debug,tests,libtool,progs}
make -j"${_nproc}"
make install
popd

mkdir -p "nano"
pushd "nano"
touch roll-a-release.sh # enable use of `git describe`
../../configure \
--build="${_build}" --host="${_host}" --prefix="${_prefix}" \
--disable-dependency-tracking \
--enable-{color,utf8,nanorc} --disable-{nls,speller,threads,rpath}
make -j"${_nproc}"
make install-strip
popd
11 changes: 11 additions & 0 deletions package_nano-win.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash -e

_pkgversion="$(git describe --tags || echo "v0.0.0-0-unknown")"
_revision="$(git rev-list --count HEAD)"

strip -s pkg_{i686,x86_64}-w64-mingw32/bin/nano.exe
cp doc/sample.nanorc.in .nanorc
7z a -aoa -mmt"$(nproc)" -- \
"nano-win_${_revision}_${_pkgversion}.7z" \
pkg_{i686,x86_64}-w64-mingw32/{bin/nano.exe,share/{nano,doc}/} \
.nanorc
55 changes: 27 additions & 28 deletions src/files.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,13 @@
#endif
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#include <shlobj.h>
#include <shlwapi.h>

#define RW_FOR_ALL (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)

#ifndef HAVE_FSYNC
# define fsync(...) 0
#endif

/* Add an item to the circular list of openfile structs. */
void make_new_buffer(void)
{
Expand Down Expand Up @@ -149,25 +148,14 @@ bool write_lockfile(const char *lockfilename, const char *filename, bool modifie
{
#if defined(HAVE_PWD_H) && defined(HAVE_GETEUID)
pid_t mypid = getpid();
uid_t myuid = geteuid();
struct passwd *mypwuid = getpwuid(myuid);
char myhostname[32];
char myhostname[32] = "localhost";
int fd;
FILE *filestream = NULL;
char *lockdata;
size_t wroteamt;

if (mypwuid == NULL) {
/* TRANSLATORS: Keep the next seven messages at most 76 characters. */
statusline(MILD, _("Couldn't determine my identity for lock file"));
return FALSE;
}

if (gethostname(myhostname, 31) < 0 && errno != ENAMETOOLONG) {
statusline(MILD, _("Couldn't determine hostname: %s"), strerror(errno));
return FALSE;
} else
myhostname[31] = '\0';
DWORD usernamelen = 32;
char myusername[32] = "";
GetUserNameA(myusername, &usernamelen);

/* First make sure to remove an existing lock file. */
if (!delete_lockfile(lockfilename))
Expand Down Expand Up @@ -213,7 +201,7 @@ bool write_lockfile(const char *lockfilename, const char *filename, bool modifie
lockdata[25] = (mypid / 256) % 256;
lockdata[26] = (mypid / (256 * 256)) % 256;
lockdata[27] = mypid / (256 * 256 * 256);
strncpy(&lockdata[28], mypwuid->pw_name, 16);
strncpy(&lockdata[28], myusername, 16);
strncpy(&lockdata[68], myhostname, 32);
strncpy(&lockdata[108], filename, 768);
lockdata[1007] = (modified) ? 0x55 : 0x00;
Expand Down Expand Up @@ -369,7 +357,7 @@ bool has_valid_path(const char *filename)
statusline(ALERT, _("Path '%s': %s"), parentdir, strerror(errno));
} else if (!S_ISDIR(parentinfo.st_mode))
statusline(ALERT, _("Path '%s' is not a directory"), parentdir);
else if (access(parentdir, X_OK) == -1)
else if (access(parentdir, R_OK) == -1)
statusline(ALERT, _("Path '%s' is not accessible"), parentdir);
#ifndef NANO_TINY
else if (ISSET(LOCKING) && !ISSET(VIEW_MODE) && access(parentdir, W_OK) < 0)
Expand Down Expand Up @@ -427,7 +415,7 @@ bool open_buffer(const char *filename, bool new_one)
}
#elif defined(HAVE_GETEUID)
if (new_one && !(fileinfo.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) &&
geteuid() == ROOT_UID)
IsUserAnAdmin())
statusline(ALERT, _("%s is meant to be read-only"), realname);
#endif
}
Expand Down Expand Up @@ -771,7 +759,7 @@ void read_file(FILE *f, int fd, const char *filename, bool undoable)

/* When reading from stdin, restore the terminal and reenter curses mode. */
if (isendwin()) {
if (!isatty(STDIN_FILENO))
if (GetConsoleWindow() == NULL)
reconnect_and_store_state();
terminal_init();
doupdate();
Expand Down Expand Up @@ -1423,6 +1411,12 @@ char *get_full_path(const char *origpath)

free(untilded);

/* Replace backslashes with forwardslashes. */
if(target)
for(slash = target; *slash; ++slash)
if(*slash == '\\')
*slash = '/';

return target;
}

Expand All @@ -1448,7 +1442,7 @@ char *check_writable_directory(const char *path)
* file stream opened in read-write mode. On error, return NULL. */
char *safe_tempfile(FILE **stream)
{
const char *env_dir = getenv("TMPDIR");
const char *env_dir = getenv("TMP");
char *tempdir = NULL, *tempfile_name = NULL;
char *extension;
int descriptor;
Expand All @@ -1462,7 +1456,7 @@ char *safe_tempfile(FILE **stream)
tempdir = check_writable_directory(P_tmpdir);

if (tempdir == NULL)
tempdir = copy_of("/tmp/");
tempdir = copy_of("C:/Windows/Temp/");

extension = strrchr(openfile->filename, '.');

Expand Down Expand Up @@ -1615,7 +1609,7 @@ bool make_backup_of(char *realname)
* just use the file-name portion of the given path. */
if (thename) {
for (int i = 0; thename[i] != '\0'; i++)
if (thename[i] == '/')
if (strchr("<>:\"/\\|?*", thename[i]))
thename[i] = '!';
} else
thename = copy_of(tail(realname));
Expand Down Expand Up @@ -2412,6 +2406,11 @@ char *real_dir_from_tilde(const char *path)

free(tilded);

/* Replace backslashes with forwardslashes. */
for(tilded = retval; *tilded; ++tilded)
if(*tilded == '\\')
*tilded = '/';

return retval;
}

Expand Down Expand Up @@ -2520,7 +2519,7 @@ char **filename_completion(const char *morsel, size_t *num_matches)
*slash = '\0';
dirname = real_dir_from_tilde(dirname);
/* A non-absolute path is relative to the current browser directory. */
if (dirname[0] != '/') {
if (PathIsRelativeA(dirname)) {
dirname = nrealloc(dirname, strlen(present_path) + strlen(wasdirname) + 1);
sprintf(dirname, "%s%s", present_path, wasdirname);
}
Expand Down
37 changes: 18 additions & 19 deletions src/nano.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
#ifdef __linux__
#include <sys/vt.h>
#endif
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
#include <shlobj.h>

#ifdef ENABLE_MULTIBUFFER
#define read_them_all TRUE
Expand Down Expand Up @@ -230,10 +233,6 @@ void restore_terminal(void)
{
curs_set(1);
endwin();
#ifndef NANO_TINY
printf("\x1B[?2004l");
fflush(stdout);
#endif
tcsetattr(STDIN_FILENO, TCSANOW, &original_state);
}

Expand Down Expand Up @@ -848,7 +847,7 @@ void restore_handler_for_Ctrl_C(void)
/* Reconnect standard input to the tty, and store its state. */
void reconnect_and_store_state(void)
{
int thetty = open("/dev/tty", O_RDONLY);
int thetty = open("CONIN$", O_RDONLY);

if (thetty < 0 || dup2(thetty, STDIN_FILENO) < 0)
die(_("Could not reconnect stdin to keyboard\n"));
Expand All @@ -864,18 +863,22 @@ void reconnect_and_store_state(void)
bool scoop_stdin(void)
{
FILE *stream;
int fd;

restore_terminal();

/* When input comes from a terminal, show a helpful message. */
if (isatty(STDIN_FILENO))
if (GetConsoleWindow() != NULL)
fprintf(stderr, _("Reading data from keyboard; "
"type ^D or ^D^D to finish.\n"));
"type ^Z to finish.\n"));

/* Open standard input. */
stream = fopen("/dev/stdin", "rb");
fd = dup(0);
stream = fdopen(fd, "rb");
if (stream == NULL) {
int errnumber = errno;
if(fd != -1)
close(fd);

terminal_init();
doupdate();
Expand Down Expand Up @@ -1241,12 +1244,6 @@ void terminal_init(void)
enable_flow_control();

disable_kb_interrupt();

#ifndef NANO_TINY
/* Tell the terminal to enable bracketed pastes. */
printf("\x1B[?2004h");
fflush(stdout);
#endif
}

/* Ask ncurses for a keycode, or assign a default one. */
Expand Down Expand Up @@ -1843,6 +1840,9 @@ int main(int argc, char **argv)
{NULL, 0, NULL, 0}
};

/* Set default file mode to binary, as on Linux. */
_set_fmode(_O_BINARY);

#ifdef __linux__
struct vt_stat dummy;

Expand All @@ -1863,7 +1863,7 @@ int main(int argc, char **argv)
#ifdef ENABLE_UTF8
/* If setting the locale is successful and it uses UTF-8, we will
* need to use the multibyte functions for text processing. */
if (setlocale(LC_ALL, "") && strcmp(nl_langinfo(CODESET), "UTF-8") == 0)
if (setlocale(LC_ALL, ".65001") && GetConsoleCP() == 65001)
utf8_init();
#else
setlocale(LC_ALL, "");
Expand Down Expand Up @@ -2150,9 +2150,8 @@ int main(int argc, char **argv)
}
}

/* Curses needs TERM; if it is unset, try falling back to a VT220. */
if (getenv("TERM") == NULL)
putenv("TERM=vt220");
/* Always use the Windows console driver. */
putenv("TERM=#win32con");

/* Enter into curses mode. Abort if this fails. */
if (initscr() == NULL)
Expand Down Expand Up @@ -2604,7 +2603,7 @@ int main(int argc, char **argv)
UNSET(NOREAD_MODE);

/* Nano is a hands-on editor -- it needs a keyboard. */
if (!isatty(STDIN_FILENO))
if (GetConsoleWindow() == NULL)
die(_("Standard input is not a terminal\n"));

/* If no filenames were given, or all of them were invalid things like
Expand Down
Loading

0 comments on commit d35d775

Please sign in to comment.