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 Jan 17, 2024
1 parent 2d64c33 commit b262cc8
Show file tree
Hide file tree
Showing 13 changed files with 208 additions and 90 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
1 change: 1 addition & 0 deletions autogen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ gnulib_hash="a007cf68f0ee224d1d88cd6907f5dbea0ad5c149"

modules="
canonicalize-lgpl
fsync
futimens
getdelim
getline
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.4-20240113"

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=false # always fails
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
2 changes: 1 addition & 1 deletion src/browser.c
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ char *browse_in(const char *inpath)
path = free_and_assign(path, strip_last_component(path));

if (stat(path, &fileinfo) == -1 || !S_ISDIR(fileinfo.st_mode)) {
path = free_and_assign(path, realpath(".", NULL));
path = free_and_assign(path, _fullpath(NULL, ".", 0));

if (path == NULL) {
statusline(ALERT, _("The working directory has disappeared"));
Expand Down
71 changes: 35 additions & 36 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,32 +148,21 @@ 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))
return FALSE;

/* Create the lock file -- do not accept an existing one. */
fd = open(lockfilename, O_WRONLY|O_CREAT|O_EXCL, RW_FOR_ALL);
fd = open(lockfilename, O_WRONLY|O_CREAT|O_EXCL|_O_BINARY, RW_FOR_ALL);

if (fd > 0)
filestream = fdopen(fd, "wb");
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 @@ -259,7 +247,7 @@ char *do_lockfile(const char *filename, bool ask_the_user)
int lockfd, lockpid, choice;
ssize_t readamt;

if ((lockfd = open(lockfilename, O_RDONLY)) < 0) {
if ((lockfd = open(lockfilename, O_RDONLY | _O_BINARY)) < 0) {
statusline(ALERT, _("Error opening lock file %s: %s"),
lockfilename, strerror(errno));
free(lockfilename);
Expand Down Expand Up @@ -353,7 +341,7 @@ bool has_valid_path(const char *filename)
bool gone = FALSE;

if (strcmp(parentdir, ".") == 0) {
char *currentdir = realpath(".", NULL);
char *currentdir = _fullpath(NULL, ".", 0);

gone = (currentdir == NULL && errno == ENOENT);
free(currentdir);
Expand All @@ -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 @@ -904,7 +892,7 @@ int open_file(const char *filename, bool new_one, FILE **f)
#endif

/* Try opening the file. */
fd = open(full_filename, O_RDONLY);
fd = open(full_filename, O_RDONLY | _O_BINARY);

#ifndef NANO_TINY
restore_handler_for_Ctrl_C();
Expand Down Expand Up @@ -1396,14 +1384,14 @@ char *get_full_path(const char *origpath)
return NULL;

untilded = real_dir_from_tilde(origpath);
target = realpath(untilded, NULL);
target = _fullpath(NULL, untilded, 0);
slash = strrchr(untilded, '/');

/* If realpath() returned NULL, try without the last component,
* as this can be a file that does not exist yet. */
if (!target && slash && slash[1]) {
*slash = '\0';
target = realpath(untilded, NULL);
target = _fullpath(NULL, untilded, 0);

/* Upon success, re-add the last component of the original path. */
if (target) {
Expand All @@ -1421,6 +1409,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 @@ -1446,7 +1440,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 @@ -1460,7 +1454,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 @@ -1613,7 +1607,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 @@ -1642,7 +1636,7 @@ bool make_backup_of(char *realname)
creation_flags = O_WRONLY|O_CREAT|(ISSET(INSECURE_BACKUP) ? O_TRUNC : O_EXCL);

/* Create the backup file (or truncate the existing one). */
descriptor = open(backupname, creation_flags, S_IRUSR|S_IWUSR);
descriptor = open(backupname, creation_flags|_O_BINARY, S_IRUSR|S_IWUSR);

retry:
if (descriptor >= 0)
Expand Down Expand Up @@ -1853,7 +1847,7 @@ bool write_file(const char *name, FILE *thefile, bool normal,
#endif

/* Now open the file. Use O_EXCL for an emergency file. */
fd = open(realname, O_WRONLY | O_CREAT | ((method == APPEND) ?
fd = open(realname, O_WRONLY | O_CREAT | _O_BINARY | ((method == APPEND) ?
O_APPEND : (normal ? O_TRUNC : O_EXCL)), permissions);

#ifndef NANO_TINY
Expand Down Expand Up @@ -2399,6 +2393,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 @@ -2507,7 +2506,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
Loading

0 comments on commit b262cc8

Please sign in to comment.