mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-14 10:00:25 -08:00
Update Android port
* .gitignore: Add new files.
* INSTALL.android: Explain how to build Emacs for ancient
versions of Android.
* admin/merge-gnulib (GNULIB_MODULES): Add getdelim.
* build-aux/config.guess (timestamp, version):
* build-aux/config.sub (timestamp, version): Autoupdate.
* configure.ac (BUILD_DETAILS, ANDROID_MIN_SDK):
(ANDROID_STUBIFY): Allow specifying CFLAGS via ANDROID_CFLAGS.
Add new configure tests for Android API version when not
explicitly specified.
* doc/emacs/android.texi (Android): Add reference to ``Other
Input Devices''.
(Android File System): Remove restrictions on directory-files on
the assets directory.
* doc/emacs/emacs.texi (Top): Add Other Input Devices to menu.
* doc/emacs/input.texi (Other Input Devices): New node.
* doc/lispref/commands.texi (Touchscreen Events): Document
changes to touchscreen input events.
* doc/lispref/frames.texi (Pop-Up Menus): Likewise.
* etc/NEWS: Announce changes.
* java/Makefile.in: Use lib-src/asset-directory-tool to generate
an `directory-tree' file placed in /assets.
* java/debug.sh: Large adjustments to support Android 2.2 and
later.
* java/org/gnu/emacs/EmacsContextMenu.java (inflateMenuItems):
* java/org/gnu/emacs/EmacsCopyArea.java (perform):
* java/org/gnu/emacs/EmacsDialog.java (toAlertDialog):
* java/org/gnu/emacs/EmacsDrawLine.java (perform):
* java/org/gnu/emacs/EmacsDrawRectangle.java (perform):
* java/org/gnu/emacs/EmacsDrawable.java (EmacsDrawable):
* java/org/gnu/emacs/EmacsFillPolygon.java (perform):
* java/org/gnu/emacs/EmacsFillRectangle.java (perform):
* java/org/gnu/emacs/EmacsGC.java (EmacsGC):
* java/org/gnu/emacs/EmacsPixmap.java (EmacsPixmap):
(destroyHandle):
* java/org/gnu/emacs/EmacsSdk7FontDriver.java (draw): Avoid
redundant canvas saves and restores.
* java/org/gnu/emacs/EmacsService.java (run):
* java/org/gnu/emacs/EmacsView.java (EmacsView):
(handleDirtyBitmap):
* java/org/gnu/emacs/EmacsWindow.java (changeWindowBackground)
(EmacsWindow): Make compatible with Android 2.2 and later.
* lib-src/Makefile.in (DONT_INSTALL): Add asset-directory-tool
on Android.:(asset-directory-tool{EXEEXT}): New target.
* lib-src/asset-directory-tool.c (struct directory_tree, xmalloc)
(main_1, main_2, main): New file.
* lib, m4: Merge from gnulib. This will be reverted before
merging to master.
* lisp/button.el (button-map):
(push-button):
* lisp/frame.el (display-popup-menus-p): Improve touchscreen
support.
* lisp/subr.el (event-start):
(event-end): Handle touchscreen events.
* lisp/touch-screen.el (touch-screen-handle-timeout):
(touch-screen-handle-point-update):
(touch-screen-handle-point-up):
(touch-screen-track-tap):
(touch-screen-track-drag):
(touch-screen-drag-mode-line-1):
(touch-screen-drag-mode-line): New functions.
([mode-line touchscreen-begin]):
([bottom-divider touchscreen-begin]): Bind new events.
* lisp/wid-edit.el (widget-event-point):
(widget-keymap):
(widget-event-start):
(widget-button--check-and-call-button):
(widget-button-click): Improve touchscreen support.
* src/alloc.c (make_lisp_symbol): Avoid ICE on Android NDK GCC.
(mark_pinned_symbols): Likewise.
* src/android.c (struct android_emacs_window): New struct.
(window_class): New variable.
(android_run_select_thread): Add workaround for Android platform
bug.
(android_extract_long, android_scan_directory_tree): New
functions.
(android_file_access_p): Use those functions instead.
(android_init_emacs_window): New function.
(android_init_emacs_gc_class): Update signature of `markDirty'.
(android_change_gc, android_set_clip_rectangles): Tell the GC
whether or not clip rects were dirtied.
(android_swap_buffers): Do not look up method every time.
(struct android_dir): Adjust for new directory tree lookup.
(android_opendir, android_readdir, android_closedir): Likewise.
(android_four_corners_bilinear): Fix coding style.
(android_ftruncate): New function.
* src/android.h: Update prototypes. Replace ftruncate with
android_ftruncate when necessary.
* src/androidterm.c (handle_one_android_event): Pacify GCC. Fix
touch screen tool bar bug.
* src/emacs.c (using_utf8): Fix compilation error.
* src/fileio.c (Ffile_system_info): Return Qnil when fsusage.o
is not built.
* src/filelock.c (BOOT_TIME_FILE): Fix definition for Android.
* src/frame.c (Fx_parse_geometry): Fix uninitialized variable
uses.
* src/keyboard.c (lispy_function_keys): Fix `back'.
* src/menu.c (x_popup_menu_1): Handle touch screen events.
(Fx_popup_menu): Document changes.
* src/sfnt.c (main): Improve tests.
* src/sfntfont-android.c (sfntfont_android_put_glyphs): Fix
minor problem.
(init_sfntfont_android): Check for
HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL.
* src/sfntfont.c (struct sfnt_font_desc): New fields `adstyle'
and `languages'.
(sfnt_parse_style): Append tokens to adstyle.
(sfnt_parse_languages): New function.
(sfnt_enum_font_1): Parse supported languages and adstyle.
(sfntfont_list_1): Handle new fields.
(sfntfont_text_extents): Fix uninitialized variable use.
(syms_of_sfntfont, mark_sfntfont): Adjust accordingly.
This commit is contained in:
parent
6253e7e742
commit
a496509ced
81 changed files with 4111 additions and 621 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -231,6 +231,7 @@ ID
|
||||||
# Executables.
|
# Executables.
|
||||||
*.exe
|
*.exe
|
||||||
a.out
|
a.out
|
||||||
|
lib-src/asset-directory-tool
|
||||||
lib-src/be-resources
|
lib-src/be-resources
|
||||||
lib-src/blessmail
|
lib-src/blessmail
|
||||||
lib-src/ctags
|
lib-src/ctags
|
||||||
|
|
@ -253,6 +254,7 @@ nextstep/GNUstep/Emacs.base/Resources/Info-gnustep.plist
|
||||||
src/bootstrap-emacs
|
src/bootstrap-emacs
|
||||||
src/emacs
|
src/emacs
|
||||||
src/emacs-[0-9]*
|
src/emacs-[0-9]*
|
||||||
|
src/sfnt
|
||||||
src/Emacs
|
src/Emacs
|
||||||
src/temacs
|
src/temacs
|
||||||
src/dmpstruct.h
|
src/dmpstruct.h
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,41 @@ built for.
|
||||||
The generated package can be uploaded onto an SD card (or similar
|
The generated package can be uploaded onto an SD card (or similar
|
||||||
medium) and installed on-device.
|
medium) and installed on-device.
|
||||||
|
|
||||||
|
BUILDING WITH OLD NDK VERSIONS
|
||||||
|
|
||||||
|
Building Emacs with an old version of the Android NDK requires special
|
||||||
|
setup. This is because there is no separate C compiler binary for
|
||||||
|
each version of Android in those versions of the NDK.
|
||||||
|
|
||||||
|
Before running `configure', you must identify three variables:
|
||||||
|
|
||||||
|
- What kind of Android system you are building Emacs for.
|
||||||
|
|
||||||
|
- The minimum API version of Android you want to build Emacs for.
|
||||||
|
|
||||||
|
- The locations of the system root and include files for that
|
||||||
|
version of Android in the NDK.
|
||||||
|
|
||||||
|
That information must then be specified as arguments to the NDK C
|
||||||
|
compiler. For example:
|
||||||
|
|
||||||
|
./configure [...] \
|
||||||
|
ANDROID_CC="i686-linux-android-gcc \
|
||||||
|
--sysroot=/path/to/ndk/platforms/android-14/arch-x86/"
|
||||||
|
ANDROID_CFLAGS="-isystem /path/to/ndk/sysroot/usr/include \
|
||||||
|
-isystem /path/to/ndk/sysroot/usr/include/i686-linux-android \
|
||||||
|
-D__ANDROID_API__=14"
|
||||||
|
|
||||||
|
Where __ANDROID_API__ and the version identifier in
|
||||||
|
"platforms/android-14" defines the version of Android you are building
|
||||||
|
for, and the include directories specify the paths to the relevant
|
||||||
|
Android headers. In addition, it may be necessary to specify
|
||||||
|
"-gdwarf-2", due to a bug in the Android NDK.
|
||||||
|
|
||||||
|
Emacs is known to build for Android 2.2 (API version 8) or later, and
|
||||||
|
run on Android 2.3 or later. It is supposed to run on Android 2.2 as
|
||||||
|
well.
|
||||||
|
|
||||||
|
|
||||||
This file is part of GNU Emacs.
|
This file is part of GNU Emacs.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ GNULIB_MODULES='
|
||||||
fchmodat fcntl fcntl-h fdopendir file-has-acl
|
fchmodat fcntl fcntl-h fdopendir file-has-acl
|
||||||
filemode filename filevercmp flexmember fpieee
|
filemode filename filevercmp flexmember fpieee
|
||||||
free-posix fstatat fsusage fsync futimens
|
free-posix fstatat fsusage fsync futimens
|
||||||
getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog
|
getline getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog
|
||||||
ieee754-h ignore-value intprops largefile libgmp lstat
|
ieee754-h ignore-value intprops largefile libgmp lstat
|
||||||
manywarnings memmem-simple mempcpy memrchr memset_explicit
|
manywarnings memmem-simple mempcpy memrchr memset_explicit
|
||||||
minmax mkostemp mktime
|
minmax mkostemp mktime
|
||||||
|
|
@ -141,7 +141,7 @@ cp -- "$gnulib_srcdir"/lib/af_alg.h \
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
|
|
||||||
# Finally, update the files in lib/ to xcompile/lib.
|
# Finally, update the files in lib/ to xcompile/lib.
|
||||||
rsync "$src"/lib "$src"/xcompile
|
rsync -r "$src"/lib "$src"/xcompile
|
||||||
|
|
||||||
# Remove unnecessary files.
|
# Remove unnecessary files.
|
||||||
rm -f "$src"/xcompile/lib/*.mk.in "$src"/xcompile/lib/Makefile.in
|
rm -f "$src"/xcompile/lib/*.mk.in "$src"/xcompile/lib/Makefile.in
|
||||||
|
|
|
||||||
6
build-aux/config.guess
vendored
6
build-aux/config.guess
vendored
|
|
@ -1,10 +1,10 @@
|
||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Attempt to guess a canonical system name.
|
# Attempt to guess a canonical system name.
|
||||||
# Copyright 1992-2022 Free Software Foundation, Inc.
|
# Copyright 1992-2023 Free Software Foundation, Inc.
|
||||||
|
|
||||||
# shellcheck disable=SC2006,SC2268 # see below for rationale
|
# shellcheck disable=SC2006,SC2268 # see below for rationale
|
||||||
|
|
||||||
timestamp='2022-09-17'
|
timestamp='2023-01-01'
|
||||||
|
|
||||||
# This file is free software; you can redistribute it and/or modify it
|
# This file is free software; you can redistribute it and/or modify it
|
||||||
# under the terms of the GNU General Public License as published by
|
# under the terms of the GNU General Public License as published by
|
||||||
|
|
@ -60,7 +60,7 @@ version="\
|
||||||
GNU config.guess ($timestamp)
|
GNU config.guess ($timestamp)
|
||||||
|
|
||||||
Originally written by Per Bothner.
|
Originally written by Per Bothner.
|
||||||
Copyright 1992-2022 Free Software Foundation, Inc.
|
Copyright 1992-2023 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This is free software; see the source for copying conditions. There is NO
|
This is free software; see the source for copying conditions. There is NO
|
||||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||||
|
|
|
||||||
6
build-aux/config.sub
vendored
6
build-aux/config.sub
vendored
|
|
@ -1,10 +1,10 @@
|
||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
# Configuration validation subroutine script.
|
# Configuration validation subroutine script.
|
||||||
# Copyright 1992-2022 Free Software Foundation, Inc.
|
# Copyright 1992-2023 Free Software Foundation, Inc.
|
||||||
|
|
||||||
# shellcheck disable=SC2006,SC2268 # see below for rationale
|
# shellcheck disable=SC2006,SC2268 # see below for rationale
|
||||||
|
|
||||||
timestamp='2022-09-17'
|
timestamp='2023-01-01'
|
||||||
|
|
||||||
# This file is free software; you can redistribute it and/or modify it
|
# This file is free software; you can redistribute it and/or modify it
|
||||||
# under the terms of the GNU General Public License as published by
|
# under the terms of the GNU General Public License as published by
|
||||||
|
|
@ -76,7 +76,7 @@ Report bugs and patches to <config-patches@gnu.org>."
|
||||||
version="\
|
version="\
|
||||||
GNU config.sub ($timestamp)
|
GNU config.sub ($timestamp)
|
||||||
|
|
||||||
Copyright 1992-2022 Free Software Foundation, Inc.
|
Copyright 1992-2023 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This is free software; see the source for copying conditions. There is NO
|
This is free software; see the source for copying conditions. There is NO
|
||||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
|
||||||
|
|
|
||||||
158
configure.ac
158
configure.ac
|
|
@ -31,8 +31,19 @@ if test "$XCONFIGURE" = "android"; then
|
||||||
# Android!
|
# Android!
|
||||||
AC_MSG_NOTICE([called to recursively configure Emacs \
|
AC_MSG_NOTICE([called to recursively configure Emacs \
|
||||||
for Android.])
|
for Android.])
|
||||||
# Set CC to ANDROID_CC.
|
# Set CC to ANDROID_CC and CFLAGS to ANDROID_CFLAGS.
|
||||||
CC=$ANDROID_CC
|
CC=$ANDROID_CC
|
||||||
|
# Set -Wno-implicit-function-declaration. Building Emacs for older
|
||||||
|
# versions of Android requires configure tests to fail if the
|
||||||
|
# functions are not defined, as the Android library in the NDK
|
||||||
|
# defines subroutines that are not available in the headers being
|
||||||
|
# used.
|
||||||
|
CFLAGS="$ANDROID_CFLAGS -Werror=implicit-function-declaration"
|
||||||
|
# Don't explicitly enable support for large files unless Emacs is
|
||||||
|
# being built for API 21 or later. Otherwise, mmap does not work.
|
||||||
|
if test "$ANDROID_SDK" -lt "21"; then
|
||||||
|
enable_largefile=no
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
dnl Set emacs_config_options to the options of 'configure', quoted for the shell,
|
dnl Set emacs_config_options to the options of 'configure', quoted for the shell,
|
||||||
|
|
@ -758,7 +769,10 @@ tools such as aapt, dx, and aidl):
|
||||||
|
|
||||||
The cross-compiler should then be specified:
|
The cross-compiler should then be specified:
|
||||||
|
|
||||||
ANDROID_CC=/path/to/armv7a-linux-androideabi19-clang])
|
ANDROID_CC=/path/to/armv7a-linux-androideabi19-clang
|
||||||
|
|
||||||
|
In addition, you may pass any special arguments to the cross-compiler
|
||||||
|
via the ANDROID_CFLAGS environment variable.])
|
||||||
elif test "$with_android" = "no" || test "$with_android" = ""; then
|
elif test "$with_android" = "no" || test "$with_android" = ""; then
|
||||||
ANDROID=no
|
ANDROID=no
|
||||||
else
|
else
|
||||||
|
|
@ -808,6 +822,29 @@ EOF
|
||||||
a valid path to android.jar. See config.log for more details.])
|
a valid path to android.jar. See config.log for more details.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AC_CACHE_CHECK([whether or not android.jar is new enough],
|
||||||
|
[emacs_cv_android_s_or_later],
|
||||||
|
AS_IF([rm -f conftest.class
|
||||||
|
cat << EOF > conftest.java
|
||||||
|
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
class conftest
|
||||||
|
{
|
||||||
|
private static int test = Build.VERSION_CODES.S;
|
||||||
|
}
|
||||||
|
|
||||||
|
EOF
|
||||||
|
("$JAVAC" -classpath "$with_android" -target 1.7 -source 1.7 conftest.java \
|
||||||
|
-d . >&AS_MESSAGE_LOG_FD 2>&1) && test -s conftest.class && rm -f conftest.class],
|
||||||
|
[emacs_cv_android_s_or_later=yes],
|
||||||
|
[emacs_cv_android_s_or_later=no]))
|
||||||
|
|
||||||
|
if test "$emacs_cv_android_s_or_later" = "no"; then
|
||||||
|
AC_MSG_ERROR([Emacs must be built with an android.jar file produced for \
|
||||||
|
Android 13 (S) or later.])
|
||||||
|
fi
|
||||||
|
|
||||||
ANDROID_JAR="$with_android"
|
ANDROID_JAR="$with_android"
|
||||||
|
|
||||||
AC_PATH_PROGS([AAPT], [aapt], [], "${SDK_BUILD_TOOLS}:$PATH")
|
AC_PATH_PROGS([AAPT], [aapt], [], "${SDK_BUILD_TOOLS}:$PATH")
|
||||||
|
|
@ -845,6 +882,7 @@ for your machine. For example:
|
||||||
AC_MSG_CHECKING([for the kind of Android system Emacs is being built for])
|
AC_MSG_CHECKING([for the kind of Android system Emacs is being built for])
|
||||||
cc_target=`${ANDROID_CC} -v 2>&1 | sed -n 's/Target: //p'`
|
cc_target=`${ANDROID_CC} -v 2>&1 | sed -n 's/Target: //p'`
|
||||||
case "$cc_target" in
|
case "$cc_target" in
|
||||||
|
[
|
||||||
*i[3-6]86*) android_abi=x86
|
*i[3-6]86*) android_abi=x86
|
||||||
;;
|
;;
|
||||||
*x86_64*) android_abi=x86_64
|
*x86_64*) android_abi=x86_64
|
||||||
|
|
@ -857,10 +895,13 @@ for your machine. For example:
|
||||||
;;
|
;;
|
||||||
*arm*) android_abi=armeabi
|
*arm*) android_abi=armeabi
|
||||||
;;
|
;;
|
||||||
|
]
|
||||||
*) AC_MSG_ERROR([configure could not determine the type of Android \
|
*) AC_MSG_ERROR([configure could not determine the type of Android \
|
||||||
binary Emacs is being configured for. Please port this configure script \
|
binary Emacs is being configured for. Please port this configure script \
|
||||||
to your Android system, or verify that you specified the correct compiler \
|
to your Android system, or verify that you specified the correct compiler \
|
||||||
in the ANDROID_CC variable when you ran configure.])
|
in the ANDROID_CC variable when you ran configure.
|
||||||
|
|
||||||
|
The compiler target is: $cc_target])
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
AC_MSG_RESULT([$android_abi])
|
AC_MSG_RESULT([$android_abi])
|
||||||
|
|
@ -878,19 +919,122 @@ in the ANDROID_CC variable when you ran configure.])
|
||||||
android_sdk=`echo "$android_sdk" | sed -n 's/android//p'`
|
android_sdk=`echo "$android_sdk" | sed -n 's/android//p'`
|
||||||
AC_MSG_RESULT([$android_sdk])
|
AC_MSG_RESULT([$android_sdk])
|
||||||
ANDROID_MIN_SDK=$android_sdk
|
ANDROID_MIN_SDK=$android_sdk
|
||||||
|
else
|
||||||
|
# This is probably GCC.
|
||||||
|
[ cat << EOF > conftest.c
|
||||||
|
#include <android/api-level.h>
|
||||||
|
extern const char *foo;
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
#if __ANDROID_API__ < 7
|
||||||
|
foo = "emacs_api_6";
|
||||||
|
#elif __ANDROID_API__ < 8
|
||||||
|
foo = "emacs_api_7";
|
||||||
|
#elif __ANDROID_API__ < 9
|
||||||
|
foo = "emacs_api_8";
|
||||||
|
#elif __ANDROID_API__ < 10
|
||||||
|
foo = "emacs_api_9";
|
||||||
|
#elif __ANDROID_API__ < 11
|
||||||
|
foo = "emacs_api_10";
|
||||||
|
#elif __ANDROID_API__ < 12
|
||||||
|
foo = "emacs_api_11";
|
||||||
|
#elif __ANDROID_API__ < 13
|
||||||
|
foo = "emacs_api_12";
|
||||||
|
#elif __ANDROID_API__ < 14
|
||||||
|
foo = "emacs_api_13";
|
||||||
|
#elif __ANDROID_API__ < 15
|
||||||
|
foo = "emacs_api_14";
|
||||||
|
#elif __ANDROID_API__ < 16
|
||||||
|
foo = "emacs_api_15";
|
||||||
|
#elif __ANDROID_API__ < 17
|
||||||
|
foo = "emacs_api_16";
|
||||||
|
#elif __ANDROID_API__ < 18
|
||||||
|
foo = "emacs_api_17";
|
||||||
|
#elif __ANDROID_API__ < 19
|
||||||
|
foo = "emacs_api_18";
|
||||||
|
#elif __ANDROID_API__ < 20
|
||||||
|
foo = "emacs_api_19";
|
||||||
|
#elif __ANDROID_API__ < 21
|
||||||
|
foo = "emacs_api_20";
|
||||||
|
#elif __ANDROID_API__ < 22
|
||||||
|
foo = "emacs_api_21";
|
||||||
|
#elif __ANDROID_API__ < 23
|
||||||
|
foo = "emacs_api_22";
|
||||||
|
#elif __ANDROID_API__ < 24
|
||||||
|
foo = "emacs_api_23";
|
||||||
|
#elif __ANDROID_API__ < 25
|
||||||
|
foo = "emacs_api_24";
|
||||||
|
#elif __ANDROID_API__ < 26
|
||||||
|
foo = "emacs_api_25";
|
||||||
|
#elif __ANDROID_API__ < 27
|
||||||
|
foo = "emacs_api_26";
|
||||||
|
#elif __ANDROID_API__ < 28
|
||||||
|
foo = "emacs_api_27";
|
||||||
|
#elif __ANDROID_API__ < 29
|
||||||
|
foo = "emacs_api_28";
|
||||||
|
#elif __ANDROID_API__ < 30
|
||||||
|
foo = "emacs_api_29";
|
||||||
|
#elif __ANDROID_API__ < 31
|
||||||
|
foo = "emacs_api_30";
|
||||||
|
#elif __ANDROID_API__ < 32
|
||||||
|
foo = "emacs_api_31";
|
||||||
|
#elif __ANDROID_API__ < 33
|
||||||
|
foo = "emacs_api_32";
|
||||||
|
#elif __ANDROID_API__ < 34
|
||||||
|
foo = "emacs_api_33";
|
||||||
|
#else
|
||||||
|
foo = "emacs_api_future";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
EOF]
|
||||||
|
|
||||||
|
AC_CACHE_VAL([emacs_cv_android_api],
|
||||||
|
[$ANDROID_CC $ANDROID_CFLAGS -c conftest.c -o conftest.o \
|
||||||
|
&& emacs_cv_android_api=`grep -ao -E \
|
||||||
|
"emacs_api_([[0-9][0-9]]?|future)" conftest.o`])
|
||||||
|
android_sdk="$emacs_cv_android_api"
|
||||||
|
rm -rf conftest.c conftest.o
|
||||||
|
|
||||||
|
# If this version of the NDK requires __ANDROID_API__ to be
|
||||||
|
# specified, then complain to the user.
|
||||||
|
if test "$android_sdk" = "emacs_api_future"; then
|
||||||
|
AC_MSG_ERROR([The version of Android to build for was not specified.
|
||||||
|
You must tell the Android compiler what version of Android to build for,
|
||||||
|
by defining the __ANDROID_API__ preprocessor macro in ANDROID_CC, like so:
|
||||||
|
|
||||||
|
ANDROID_CC="/path/to/ndk/arm-linux-android-gcc -D__ANDROID_API__=8"])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -n "$android_sdk"; then
|
||||||
|
android_sdk=`echo $android_sdk | sed -n 's/emacs_api_//p'`
|
||||||
|
AC_MSG_RESULT([$android_sdk])
|
||||||
|
ANDROID_MIN_SDK=$android_sdk
|
||||||
else
|
else
|
||||||
AC_MSG_RESULT([unknown ($cc_target); assuming 8])
|
AC_MSG_RESULT([unknown ($cc_target); assuming 8])
|
||||||
AC_MSG_WARN([configure could not determine the versions of Android \
|
AC_MSG_ERROR([configure could not determine the versions of Android \
|
||||||
a binary built with this compiler will run on. The generated application \
|
a binary built with this compiler will run on. The generated application \
|
||||||
package will likely install on older systems but crash on startup.])
|
package will likely install on older systems but crash on startup.])
|
||||||
|
android_sdk=8
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
AC_SUBST([ANDROID_MIN_SDK])
|
AC_SUBST([ANDROID_MIN_SDK])
|
||||||
|
|
||||||
|
# Now tell java/Makefile if Emacs is being built for Android 4.3 or
|
||||||
|
# earlier.
|
||||||
|
ANDROID_SDK_18_OR_EARLIER=
|
||||||
|
if test "$android_sdk" -lt "18"; then
|
||||||
|
ANDROID_SDK_18_OR_EARLIER=yes
|
||||||
|
fi
|
||||||
|
AC_SUBST([ANDROID_SDK_18_OR_EARLIER])
|
||||||
|
|
||||||
# Save confdefs.h and config.log for now.
|
# Save confdefs.h and config.log for now.
|
||||||
mv -f confdefs.h _confdefs.h
|
mv -f confdefs.h _confdefs.h
|
||||||
mv -f config.log _config.log
|
mv -f config.log _config.log
|
||||||
|
|
||||||
AS_IF([XCONFIGURE=android ANDROID_CC="$ANDROID_CC" $0], [],
|
AS_IF([XCONFIGURE=android ANDROID_CC="$ANDROID_CC" \
|
||||||
|
ANDROID_SDK="$android_sdk" $0], [],
|
||||||
[AC_MSG_ERROR([Failed to cross-configure Emacs for android.])])
|
[AC_MSG_ERROR([Failed to cross-configure Emacs for android.])])
|
||||||
|
|
||||||
# Now set ANDROID to yes.
|
# Now set ANDROID to yes.
|
||||||
|
|
@ -1989,7 +2133,6 @@ AC_CACHE_CHECK([for math library],
|
||||||
d = frexp (d, &i);
|
d = frexp (d, &i);
|
||||||
d = ldexp (d, i);
|
d = ldexp (d, i);
|
||||||
d = log (d);
|
d = log (d);
|
||||||
d = log2 (d);
|
|
||||||
d = log10 (d);
|
d = log10 (d);
|
||||||
d = pow (d, d);
|
d = pow (d, d);
|
||||||
d = rint (d);
|
d = rint (d);
|
||||||
|
|
@ -2283,6 +2426,9 @@ for Android, but all API calls need to be stubbed out])
|
||||||
# Link with the sfnt font library and sfntfont.o, along with
|
# Link with the sfnt font library and sfntfont.o, along with
|
||||||
# sfntfont-android.o.
|
# sfntfont-android.o.
|
||||||
ANDROID_OBJ="$ANDROID_OBJ sfnt.o sfntfont.o sfntfont-android.o"
|
ANDROID_OBJ="$ANDROID_OBJ sfnt.o sfntfont.o sfntfont-android.o"
|
||||||
|
|
||||||
|
# Check for some functions not always present in the NDK.
|
||||||
|
AC_CHECK_DECLS([android_get_device_api_level])
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
@c This is part of the Emacs manual.
|
@c This is part of the Emacs manual.
|
||||||
@c Copyright (C) 2021--2023 Free Software Foundation, Inc.
|
@c Copyright (C) 2023 Free Software Foundation, Inc.
|
||||||
@c See file emacs.texi for copying conditions.
|
@c See file emacs.texi for copying conditions.
|
||||||
@node Android
|
@node Android
|
||||||
@appendix Emacs and Android
|
@appendix Emacs and Android
|
||||||
|
|
@ -9,6 +9,10 @@
|
||||||
Alliance. This section describes the peculiarities of using Emacs on
|
Alliance. This section describes the peculiarities of using Emacs on
|
||||||
an Android device running Android 2.2 or later.
|
an Android device running Android 2.2 or later.
|
||||||
|
|
||||||
|
Android devices commonly rely on user input through a touch screen
|
||||||
|
or digitizer device. For more information about using them with
|
||||||
|
Emacs, @pxref{other Input Devices}.
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* What is Android?:: Preamble.
|
* What is Android?:: Preamble.
|
||||||
* Android Startup:: Starting up Emacs on Android.
|
* Android Startup:: Starting up Emacs on Android.
|
||||||
|
|
@ -108,11 +112,6 @@ There are no @file{.} and @file{..} directories inside the
|
||||||
@item
|
@item
|
||||||
Files in the @file{/assets} directory are always read only, and have
|
Files in the @file{/assets} directory are always read only, and have
|
||||||
to be completely read in to memory each time they are opened.
|
to be completely read in to memory each time they are opened.
|
||||||
|
|
||||||
@item
|
|
||||||
@code{directory-files} does not return a useful value on the
|
|
||||||
@file{/assets} directory itself, and does not return subdirectories
|
|
||||||
inside subdirectories of the @file{/assets} directory.
|
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
Aside from the @file{/assets} directory, Android programs normally
|
Aside from the @file{/assets} directory, Android programs normally
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,7 @@ Appendices
|
||||||
* Haiku:: Using Emacs on Haiku.
|
* Haiku:: Using Emacs on Haiku.
|
||||||
* Android:: Using Emacs on Android.
|
* Android:: Using Emacs on Android.
|
||||||
* Microsoft Windows:: Using Emacs on Microsoft Windows and MS-DOS.
|
* Microsoft Windows:: Using Emacs on Microsoft Windows and MS-DOS.
|
||||||
|
* Other Input Devices:: Using Emacs with other input devices.
|
||||||
* Manifesto:: What's GNU? Gnu's Not Unix!
|
* Manifesto:: What's GNU? Gnu's Not Unix!
|
||||||
|
|
||||||
* Glossary:: Terms used in this manual.
|
* Glossary:: Terms used in this manual.
|
||||||
|
|
@ -1265,6 +1266,10 @@ Emacs and Android
|
||||||
* Android Environment:: Running Emacs under Android.
|
* Android Environment:: Running Emacs under Android.
|
||||||
* Android Fonts:: Font selection under Android.
|
* Android Fonts:: Font selection under Android.
|
||||||
|
|
||||||
|
Emacs and unconventional input devices
|
||||||
|
|
||||||
|
* Touchscreens:: Using Emacs on touchscreens.
|
||||||
|
|
||||||
Emacs and Microsoft Windows/MS-DOS
|
Emacs and Microsoft Windows/MS-DOS
|
||||||
|
|
||||||
* Windows Startup:: How to start Emacs on Windows.
|
* Windows Startup:: How to start Emacs on Windows.
|
||||||
|
|
@ -1636,6 +1641,7 @@ Lisp programming.
|
||||||
@include macos.texi
|
@include macos.texi
|
||||||
@include haiku.texi
|
@include haiku.texi
|
||||||
@include android.texi
|
@include android.texi
|
||||||
|
@include input.texi
|
||||||
@c Includes msdos-xtra.
|
@c Includes msdos-xtra.
|
||||||
@include msdos.texi
|
@include msdos.texi
|
||||||
@include gnu.texi
|
@include gnu.texi
|
||||||
|
|
|
||||||
60
doc/emacs/input.texi
Normal file
60
doc/emacs/input.texi
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
@c This is part of the Emacs manual.
|
||||||
|
@c Copyright (C) 2023 Free Software Foundation, Inc.
|
||||||
|
@c See file emacs.texi for copying conditions.
|
||||||
|
@node Other Input Devices
|
||||||
|
@appendix Emacs and unconventional input devices
|
||||||
|
@cindex other input devices
|
||||||
|
|
||||||
|
Emacs was originally developed with the assumption that users will
|
||||||
|
be sitting in front of a desktop computer, with a keyboard and perhaps
|
||||||
|
a suitable pointing device such as a mouse.
|
||||||
|
|
||||||
|
However, recent developments in the X Window System, and in other
|
||||||
|
operating systems such as Android, mean that this assumption no longer
|
||||||
|
holds true. As a result, Emacs now has support for other kinds of
|
||||||
|
input devices, which is detailed here.
|
||||||
|
|
||||||
|
@menu
|
||||||
|
* Touchscreens:: Using Emacs on touchscreens.
|
||||||
|
@end menu
|
||||||
|
|
||||||
|
@node Touchscreens
|
||||||
|
@section Using Emacs on touchscreens
|
||||||
|
@cindex touchscreens
|
||||||
|
|
||||||
|
Touchscreen input works by having the user press tools onto the
|
||||||
|
screen, which can be his own fingers, or a pointing device such as a
|
||||||
|
stylus, in order to manipulate the contents there in.
|
||||||
|
|
||||||
|
When running under the X Window System or Android, Emacs
|
||||||
|
automatically detects and maps the following touchscreen gestures to
|
||||||
|
common actions:
|
||||||
|
|
||||||
|
@itemize @bullet
|
||||||
|
@item
|
||||||
|
@cindex tapping, touchscreens
|
||||||
|
``Tapping'', meaning to briefly place and lift a tool from the
|
||||||
|
display, will result in Emacs selecting the window that was tapped,
|
||||||
|
and executing any command bound to @code{mouse-1} at that location in
|
||||||
|
the window. If the tap happened on top of a link (@pxref{Mouse
|
||||||
|
References}), then Emacs will follow the link instead.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@cindex scrolling, touchscreens
|
||||||
|
``Scrolling'', meaning to place a tool on the display and move it up
|
||||||
|
or down, will result in Emacs scrolling the window contents in the
|
||||||
|
direction where the tool moves.
|
||||||
|
|
||||||
|
@item
|
||||||
|
@cindex dragging, touchscreens
|
||||||
|
``Dragging'', meaning to place a tool on the display and leave it
|
||||||
|
there for a while before moving the tool around, will make Emacs set
|
||||||
|
the point to where the tool was and begin selecting text under the
|
||||||
|
tool as it moves around, much like what would happen if @code{mouse-1}
|
||||||
|
were to be held down. @xref{Mouse Commands}.
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
@vindex touch-screen-delay
|
||||||
|
By default, Emacs considers a tool as having been left on the
|
||||||
|
display for a while after 0.7 seconds, but this can be changed by
|
||||||
|
customizing the variable @code{touch-screen-delay}.
|
||||||
|
|
@ -1999,24 +1999,24 @@ each point is represented by a cons of an arbitrary number identifying
|
||||||
the point and a mouse position list (@pxref{Click Events}) specifying
|
the point and a mouse position list (@pxref{Click Events}) specifying
|
||||||
the position of the finger when the event occurred.
|
the position of the finger when the event occurred.
|
||||||
|
|
||||||
In addition, @code{touchscreen-begin} events also have imaginary
|
|
||||||
prefixes keys added by @code{read-key-sequence} when they originate on
|
|
||||||
top of a special part of a frame or window. @xref{Key Sequence
|
|
||||||
Input}. The reason the other touch screen events do not undergo this
|
|
||||||
treatment is that they are rarely useful without being used in tandem
|
|
||||||
from their corresponding @code{touchscreen-begin} events.
|
|
||||||
|
|
||||||
@table @code
|
@table @code
|
||||||
@cindex @code{touchscreen-begin} event
|
@cindex @code{touchscreen-begin} event
|
||||||
@item (touchscreen-begin @var{point})
|
@item (touchscreen-begin @var{point})
|
||||||
This event is sent when @var{point} is created by the user pressing a
|
This event is sent when @var{point} is created by the user pressing a
|
||||||
finger against the touchscreen.
|
finger against the touchscreen.
|
||||||
|
|
||||||
|
These events also have imaginary prefixes keys added by
|
||||||
|
@code{read-key-sequence} when they originate on top of a special part
|
||||||
|
of a frame or window. @xref{Key Sequence Input}. The reason the
|
||||||
|
other touch screen events do not undergo this treatment is that they
|
||||||
|
are rarely useful without being used in tandem from their
|
||||||
|
corresponding @code{touchscreen-begin} events.
|
||||||
|
|
||||||
@cindex @code{touchscreen-update} event
|
@cindex @code{touchscreen-update} event
|
||||||
@item (touchscreen-update @var{points})
|
@item (touchscreen-update @var{points})
|
||||||
This event is sent when a point on the touchscreen has changed
|
This event is sent when a point on the touchscreen has changed
|
||||||
position. @var{points} is a list of touch points containing the
|
position. @var{points} is a list of touch points containing the
|
||||||
up-to-date positions of each touch point currently on the touchscreen.
|
up-to-date positions of each touch point currently on the touchscxcompile/reen.
|
||||||
|
|
||||||
@cindex @code{touchscreen-end} event
|
@cindex @code{touchscreen-end} event
|
||||||
@item (touchscreen-end @var{point})
|
@item (touchscreen-end @var{point})
|
||||||
|
|
@ -2030,6 +2030,36 @@ generate any corresponding @code{touchscreen-begin} or
|
||||||
@code{touchscreen-end} events; instead, the menu bar may be displayed
|
@code{touchscreen-end} events; instead, the menu bar may be displayed
|
||||||
when @code{touchscreen-end} should have been delivered.
|
when @code{touchscreen-end} should have been delivered.
|
||||||
|
|
||||||
|
@cindex handling touch screen events
|
||||||
|
@cindex tap and drag, touch screen gestures
|
||||||
|
Emacs provides two functions to handle touch screen events. They are
|
||||||
|
intended to be used by a command bound to @code{touchscreen-begin} to
|
||||||
|
handle common gestures.
|
||||||
|
|
||||||
|
@defun touch-screen-track-tap event &optional update data
|
||||||
|
This function is used to track a single ``tap'' gesture originating
|
||||||
|
from the @code{touchscreen-begin} event @var{event}, often used to
|
||||||
|
set the point or to activate a button. It waits for a
|
||||||
|
@code{touchscreen-end} event with the same touch identifier to arrive,
|
||||||
|
at which point it returns @code{t}, signifying the end of the gesture.
|
||||||
|
|
||||||
|
If a @code{touchscreen-update} event arrives in the mean time and
|
||||||
|
contains at least one touchpoint with the same identifier as in
|
||||||
|
@var{event}, the function @var{update} is called with two arguments,
|
||||||
|
the list of touchpoints in that @code{touchscreen-update} event, and
|
||||||
|
@var{data}.
|
||||||
|
|
||||||
|
If any other event arrives in the mean time, @code{nil} is returned.
|
||||||
|
The caller should not perform any action in that case.
|
||||||
|
@end defun
|
||||||
|
|
||||||
|
@defun touch-screen-track-drag event update &optional data
|
||||||
|
This function is used to track a single ``drag'' gesture originating
|
||||||
|
from the @code{touchscreen-begin} event @code{event}. Currently, it
|
||||||
|
behaves identically to @code{touch-screen-track-tap}, but differences
|
||||||
|
are anticipated in the future.
|
||||||
|
@end defun
|
||||||
|
|
||||||
@node Focus Events
|
@node Focus Events
|
||||||
@subsection Focus Events
|
@subsection Focus Events
|
||||||
@cindex focus event
|
@cindex focus event
|
||||||
|
|
|
||||||
|
|
@ -3725,9 +3725,9 @@ This function displays a pop-up menu and returns an indication of
|
||||||
what selection the user makes.
|
what selection the user makes.
|
||||||
|
|
||||||
The argument @var{position} specifies where on the screen to put the
|
The argument @var{position} specifies where on the screen to put the
|
||||||
top left corner of the menu. It can be either a mouse button event
|
top left corner of the menu. It can be either a mouse button or
|
||||||
(which says to put the menu where the user actuated the button) or a
|
@code{touchscreen-begin} event (which says to put the menu where the
|
||||||
list of this form:
|
user actuated the button) or a list of this form:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
((@var{xoffset} @var{yoffset}) @var{window})
|
((@var{xoffset} @var{yoffset}) @var{window})
|
||||||
|
|
|
||||||
20
etc/NEWS
20
etc/NEWS
|
|
@ -24,6 +24,12 @@ applies, and please also update docstrings as needed.
|
||||||
|
|
||||||
* Installation Changes in Emacs 30.1
|
* Installation Changes in Emacs 30.1
|
||||||
|
|
||||||
|
** Emacs has been ported to the Android operating system.
|
||||||
|
This requires Emacs to be compiled on another computer. The Android
|
||||||
|
NDK, SDK, and a suitable Java compiler must also be installed.
|
||||||
|
|
||||||
|
See the file 'INSTALL.android' for more details.
|
||||||
|
|
||||||
|
|
||||||
* Startup Changes in Emacs 30.1
|
* Startup Changes in Emacs 30.1
|
||||||
|
|
||||||
|
|
@ -53,6 +59,10 @@ trash when deleting. Default is nil.
|
||||||
|
|
||||||
* Editing Changes in Emacs 30.1
|
* Editing Changes in Emacs 30.1
|
||||||
|
|
||||||
|
** Emacs now has better support for touchscreen events.
|
||||||
|
Many touch screen gestures are now implemented, as is support for
|
||||||
|
tapping buttons and opening menus.
|
||||||
|
|
||||||
** New helper variable 'transpose-sexps-function'.
|
** New helper variable 'transpose-sexps-function'.
|
||||||
Emacs now can set this variable to customize the behavior of the
|
Emacs now can set this variable to customize the behavior of the
|
||||||
'transpose-sexps' function.
|
'transpose-sexps' function.
|
||||||
|
|
@ -189,6 +199,16 @@ This user option has been obsoleted in Emacs 27, use
|
||||||
|
|
||||||
* Lisp Changes in Emacs 30.1
|
* Lisp Changes in Emacs 30.1
|
||||||
|
|
||||||
|
+++
|
||||||
|
** 'x-popup-menu' now understands touch screen events.
|
||||||
|
When a 'touchscreen-begin' or 'touchscreen-end' event is passed as the
|
||||||
|
POSITION argument, it will behave as if that event was a mouse event.
|
||||||
|
|
||||||
|
** New functions for handling touch screen events.
|
||||||
|
The new functions 'touch-screen-track-tap' and
|
||||||
|
'touch-screen-track-drag' handle tracking common touch screen gestures
|
||||||
|
from within a command.
|
||||||
|
|
||||||
** New or changed byte-compilation warnings
|
** New or changed byte-compilation warnings
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,10 @@ top_builddir = @top_builddir@
|
||||||
top_srcdir = @top_srcdir@
|
top_srcdir = @top_srcdir@
|
||||||
version = @version@
|
version = @version@
|
||||||
|
|
||||||
|
# This is the host lib-src and lib, not the cross compiler's lib-src.
|
||||||
|
libsrc = ../lib-src
|
||||||
|
EXEEXT = @EXEEXT@
|
||||||
|
|
||||||
-include ${top_builddir}/src/verbose.mk
|
-include ${top_builddir}/src/verbose.mk
|
||||||
|
|
||||||
SHELL = @SHELL@
|
SHELL = @SHELL@
|
||||||
|
|
@ -29,14 +33,25 @@ AAPT = @AAPT@
|
||||||
D8 = @D8@
|
D8 = @D8@
|
||||||
ZIPALIGN = @ZIPALIGN@
|
ZIPALIGN = @ZIPALIGN@
|
||||||
JARSIGNER = @JARSIGNER@
|
JARSIGNER = @JARSIGNER@
|
||||||
|
JARSIGNER_FLAGS =
|
||||||
ANDROID_JAR = @ANDROID_JAR@
|
ANDROID_JAR = @ANDROID_JAR@
|
||||||
ANDROID_ABI = @ANDROID_ABI@
|
ANDROID_ABI = @ANDROID_ABI@
|
||||||
|
ANDROID_SDK_18_OR_EARLIER = @ANDROID_SDK_18_OR_EARLIER@
|
||||||
|
|
||||||
WARN_JAVAFLAGS = -Xlint:deprecation
|
WARN_JAVAFLAGS = -Xlint:deprecation
|
||||||
JAVAFLAGS = -classpath "$(ANDROID_JAR):." -target 1.7 -source 1.7 \
|
JAVAFLAGS = -classpath "$(ANDROID_JAR):." -target 1.7 -source 1.7 \
|
||||||
$(WARN_JAVAFLAGS)
|
$(WARN_JAVAFLAGS)
|
||||||
|
|
||||||
SIGN_EMACS = -keystore emacs.keystore -storepass emacs1
|
# Android 4.3 and earlier require Emacs to be signed with a different
|
||||||
|
# digital signature algorithm.
|
||||||
|
|
||||||
|
ifneq (,$(ANDROID_SDK_18_OR_EARLIER))
|
||||||
|
JARSIGNER_FLAGS = -sigalg MD5withRSA -digestalg SHA1
|
||||||
|
else
|
||||||
|
JARSIGNER_FLAGS =
|
||||||
|
endif
|
||||||
|
|
||||||
|
SIGN_EMACS = -keystore emacs.keystore -storepass emacs1 $(JARSIGNER_FLAGS)
|
||||||
|
|
||||||
JAVA_FILES = $(shell find . -type f -name *.java)
|
JAVA_FILES = $(shell find . -type f -name *.java)
|
||||||
CLASS_FILES = $(foreach file,$(JAVA_FILES),$(basename $(file)).class)
|
CLASS_FILES = $(foreach file,$(JAVA_FILES),$(basename $(file)).class)
|
||||||
|
|
@ -82,7 +97,14 @@ CROSS_LIBS = ../xcompile/src/libemacs.so
|
||||||
../xcompile/lib-src/ctags ../xcompile/lib-src/ebrowse &:
|
../xcompile/lib-src/ctags ../xcompile/lib-src/ebrowse &:
|
||||||
make -C ../xcompile lib-src/$(notdir $@)
|
make -C ../xcompile lib-src/$(notdir $@)
|
||||||
|
|
||||||
emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) AndroidManifest.xml
|
# This is needed to generate the ``.directory-tree'' file used by the
|
||||||
|
# Android emulations of readdir and faccessat.
|
||||||
|
|
||||||
|
$(libsrc)/asset-directory-tool:
|
||||||
|
$(MAKE) -C $(libsrc) $(notdir $@)
|
||||||
|
|
||||||
|
emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) $(libsrc)/asset-directory-tool \
|
||||||
|
AndroidManifest.xml
|
||||||
# Make the working directory for this stuff
|
# Make the working directory for this stuff
|
||||||
rm -rf install_temp
|
rm -rf install_temp
|
||||||
mkdir -p install_temp/lib/$(ANDROID_ABI)
|
mkdir -p install_temp/lib/$(ANDROID_ABI)
|
||||||
|
|
@ -106,6 +128,9 @@ emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) AndroidManifest.xml
|
||||||
rm -rf $${subdir}/[mM]akefile*[.-]in ; \
|
rm -rf $${subdir}/[mM]akefile*[.-]in ; \
|
||||||
rm -rf $${subdir}/Makefile; \
|
rm -rf $${subdir}/Makefile; \
|
||||||
done
|
done
|
||||||
|
# Generate the directory tree for those directories.
|
||||||
|
$(libsrc)/asset-directory-tool install_temp/assets \
|
||||||
|
install_temp/assets/directory-tree
|
||||||
# Install architecture dependents to lib/$(ANDROID_ABI). This
|
# Install architecture dependents to lib/$(ANDROID_ABI). This
|
||||||
# perculiar naming scheme is required to make Android preserve these
|
# perculiar naming scheme is required to make Android preserve these
|
||||||
# binaries upon installation.
|
# binaries upon installation.
|
||||||
|
|
@ -120,10 +145,12 @@ emacs.apk-in: $(CROSS_BINS) $(CROSS_LIBS) AndroidManifest.xml
|
||||||
cp -f $$file install_temp/lib/$(ANDROID_ABI); \
|
cp -f $$file install_temp/lib/$(ANDROID_ABI); \
|
||||||
fi \
|
fi \
|
||||||
done
|
done
|
||||||
# Package everything.
|
# Package everything. Specifying the assets on this command line is
|
||||||
$(AAPT) package -I "$(ANDROID_JAR)" -F $@ -f -M AndroidManifest.xml
|
# necessary for AAssetManager_getNextFileName to work on old versions
|
||||||
|
# of Android.
|
||||||
|
$(AAPT) package -I "$(ANDROID_JAR)" -F $@ -f -M AndroidManifest.xml \
|
||||||
|
-A install_temp/assets
|
||||||
pushd install_temp; $(AAPT) add ../$@ `find lib -type f`; popd
|
pushd install_temp; $(AAPT) add ../$@ `find lib -type f`; popd
|
||||||
pushd install_temp; $(AAPT) add ../$@ `find assets -type f`; popd
|
|
||||||
rm -rf install_temp
|
rm -rf install_temp
|
||||||
|
|
||||||
# Makefile itself.
|
# Makefile itself.
|
||||||
|
|
|
||||||
147
java/debug.sh
147
java/debug.sh
|
|
@ -93,7 +93,7 @@ while [ $# -gt 0 ]; do
|
||||||
shift
|
shift
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ -z $devices ]; then
|
if [ -z "$devices" ]; then
|
||||||
echo "No devices are available."
|
echo "No devices are available."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
@ -117,25 +117,43 @@ if [ -z $app_data_dir ]; then
|
||||||
echo "Is it installed?"
|
echo "Is it installed?"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Found application data directory at $app_data_dir..."
|
echo "Found application data directory at" "$app_data_dir"
|
||||||
|
|
||||||
# Find which PIDs are associated with org.gnu.emacs
|
# Generate an awk script to extract PIDs from Android ps output. It
|
||||||
package_uid=`adb -s $device shell run-as $package id -u`
|
# is enough to run `ps' as the package user on newer versions of
|
||||||
|
# Android, but that doesn't work on Android 2.3.
|
||||||
|
cat << EOF > tmp.awk
|
||||||
|
BEGIN {
|
||||||
|
pid = 0;
|
||||||
|
pid_column = 2;
|
||||||
|
}
|
||||||
|
|
||||||
if [ -z $package_uid ]; then
|
{
|
||||||
echo "Failed to obtain UID of packages named $package"
|
# Remove any trailing carriage return from the input line.
|
||||||
exit 1
|
gsub ("\r", "", \$NF)
|
||||||
fi
|
|
||||||
|
|
||||||
# First, run ps -u $package_uid -o PID,CMD to fetch the list of
|
# If this is line 1, figure out which column contains the PID.
|
||||||
# process IDs.
|
if (NR == 1)
|
||||||
package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD`
|
{
|
||||||
|
for (n = 1; n <= NF; ++n)
|
||||||
|
{
|
||||||
|
if (\$n == "PID")
|
||||||
|
pid_column=n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (\$NF == "$package")
|
||||||
|
print \$pid_column
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
# Next, remove lines matching "ps" itself.
|
# Make sure that file disappears once this script exits.
|
||||||
package_pids=`awk -- '{
|
trap "rm -f $(pwd)/tmp.awk" 0
|
||||||
if (!match ($0, /(PID|ps)/))
|
|
||||||
print $1
|
# First, run ps to fetch the list of process IDs.
|
||||||
}' <<< $package_pids`
|
package_pids=`adb -s $device shell ps`
|
||||||
|
|
||||||
|
# Next, extract the list of PIDs currently running.
|
||||||
|
package_pids=`awk -f tmp.awk <<< $package_pids`
|
||||||
|
|
||||||
if [ "$attach_existing" != "yes" ]; then
|
if [ "$attach_existing" != "yes" ]; then
|
||||||
# Finally, kill each existing process.
|
# Finally, kill each existing process.
|
||||||
|
|
@ -149,19 +167,20 @@ if [ "$attach_existing" != "yes" ]; then
|
||||||
echo "Starting activity $activity and attaching debugger"
|
echo "Starting activity $activity and attaching debugger"
|
||||||
|
|
||||||
# Exit if the activity could not be started.
|
# Exit if the activity could not be started.
|
||||||
adb -s $device shell am start -D "$package/$activity"
|
adb -s $device shell am start -D -n "$package/$activity"
|
||||||
if [ ! $? ]; then
|
if [ ! $? ]; then
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Sleep for a bit. Otherwise, the process may not have started
|
||||||
|
# yet.
|
||||||
|
sleep 1
|
||||||
|
|
||||||
# Now look for processes matching the package again.
|
# Now look for processes matching the package again.
|
||||||
package_pids=`adb -s $device shell run-as $package ps -u $package_uid -o PID,CMD`
|
package_pids=`adb -s $device shell ps`
|
||||||
|
|
||||||
# Next, remove lines matching "ps" itself.
|
# Next, remove lines matching "ps" itself.
|
||||||
package_pids=`awk -- '{
|
package_pids=`awk -f tmp.awk <<< $package_pids`
|
||||||
if (!match ($0, /(PID|ps)/))
|
|
||||||
print $1
|
|
||||||
}' <<< $package_pids`
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pid=$package_pids
|
pid=$package_pids
|
||||||
|
|
@ -170,10 +189,10 @@ num_pids=`wc -w <<< "$package_pids"`
|
||||||
if [ $num_pids -gt 1 ]; then
|
if [ $num_pids -gt 1 ]; then
|
||||||
echo "More than one process was started:"
|
echo "More than one process was started:"
|
||||||
echo ""
|
echo ""
|
||||||
adb -s $device shell run-as $package ps -u $package_uid | awk -- '{
|
adb -s $device shell run-as $package ps | awk -- "{
|
||||||
if (!match ($0, /ps/))
|
if (!match (\$0, /ps/) && match (\$0, /$package/))
|
||||||
print $0
|
print \$0
|
||||||
}'
|
}"
|
||||||
echo ""
|
echo ""
|
||||||
printf "Which one do you want to attach to? "
|
printf "Which one do you want to attach to? "
|
||||||
read pid
|
read pid
|
||||||
|
|
@ -182,10 +201,12 @@ elif [ -z $package_pids ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# This isn't necessary when attaching gdb to an existing process.
|
# If either --jdb was specified or debug.sh is not connecting to an
|
||||||
|
# existing process, then store a suitable JDB invocation in
|
||||||
|
# jdb_command. GDB will then run JDB to unblock the application from
|
||||||
|
# the wait dialog after startup.
|
||||||
|
|
||||||
if [ "$jdb" = "yes" ] || [ "$attach_existing" != yes ]; then
|
if [ "$jdb" = "yes" ] || [ "$attach_existing" != yes ]; then
|
||||||
# Start JDB to make the wait dialog disappear.
|
|
||||||
echo "Attaching JDB to unblock the application."
|
|
||||||
adb -s $device forward --remove-all
|
adb -s $device forward --remove-all
|
||||||
adb -s $device forward "tcp:$jdb_port" "jdwp:$pid"
|
adb -s $device forward "tcp:$jdb_port" "jdwp:$pid"
|
||||||
|
|
||||||
|
|
@ -203,20 +224,42 @@ if [ "$jdb" = "yes" ] || [ "$attach_existing" != yes ]; then
|
||||||
$jdb_command
|
$jdb_command
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
exec 4<> /tmp/file-descriptor-stamp
|
if [ -n "$jdb_command" ]; then
|
||||||
|
echo "Starting JDB to unblock application."
|
||||||
|
|
||||||
# Now run JDB with IO redirected to file descriptor 4 in a subprocess.
|
# Start JDB to unblock the application.
|
||||||
$jdb_command <&4 >&4 &
|
coproc JDB { $jdb_command; }
|
||||||
|
|
||||||
character=
|
# Tell JDB to first suspend all threads.
|
||||||
# Next, wait until the prompt is found.
|
echo "suspend" >&${JDB[1]}
|
||||||
while read -n1 -u 4 character; do
|
|
||||||
if [ "$character" = ">" ]; then
|
# Tell JDB to print a magic string once the program is
|
||||||
echo "JDB attached successfully"
|
# initialized.
|
||||||
break;
|
echo "print \"__verify_jdb_has_started__\"" >&${JDB[1]}
|
||||||
|
|
||||||
|
# Now wait for JDB to give the string back.
|
||||||
|
line=
|
||||||
|
while :; do
|
||||||
|
read -u ${JDB[0]} line
|
||||||
|
if [ ! $? ]; then
|
||||||
|
echo "Failed to read JDB output"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
case "$line" in
|
||||||
|
*__verify_jdb_has_started__*)
|
||||||
|
# Android only polls for a Java debugger every 200ms, so
|
||||||
|
# the debugger must be connected for at least that long.
|
||||||
|
echo "Pausing 1 second for the program to continue."
|
||||||
|
sleep 1
|
||||||
|
break
|
||||||
|
;;
|
||||||
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Note that JDB does not exit until GDB is fully attached!
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# See if gdbserver has to be uploaded
|
# See if gdbserver has to be uploaded
|
||||||
|
|
@ -234,18 +277,19 @@ fi
|
||||||
|
|
||||||
echo "Attaching gdbserver to $pid on $device..."
|
echo "Attaching gdbserver to $pid on $device..."
|
||||||
exec 5<> /tmp/file-descriptor-stamp
|
exec 5<> /tmp/file-descriptor-stamp
|
||||||
|
rm -f /tmp/file-descriptor-stamp
|
||||||
|
|
||||||
if [ -z "$gdbserver" ]; then
|
if [ -z "$gdbserver" ]; then
|
||||||
adb -s $device shell run-as $package $gdbserver_bin --once \
|
adb -s $device shell run-as $package $gdbserver_bin --once \
|
||||||
"+debug.$package_uid.socket" --attach $pid >&5 &
|
"+debug.$package.socket" --attach $pid >&5 &
|
||||||
gdb_socket="localfilesystem:$app_data_dir/debug.$package_uid.socket"
|
gdb_socket="localfilesystem:$app_data_dir/debug.$package.socket"
|
||||||
else
|
else
|
||||||
# Normally the program cannot access $gdbserver_bin when it is
|
# Normally the program cannot access $gdbserver_bin when it is
|
||||||
# placed in /data/local/tmp.
|
# placed in /data/local/tmp.
|
||||||
adb -s $device shell $gdbserver_bin --once \
|
adb -s $device shell $gdbserver_bin --once \
|
||||||
"+/data/local/tmp/debug.$package_uid.socket" \
|
"+/data/local/tmp/debug.$package.socket" \
|
||||||
--attach $pid >&5 &
|
--attach $pid >&5 &
|
||||||
gdb_socket="localfilesystem:/data/local/tmp/debug.$package_uid.socket"
|
gdb_socket="localfilesystem:/data/local/tmp/debug.$package.socket"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Wait until gdbserver successfully runs.
|
# Wait until gdbserver successfully runs.
|
||||||
|
|
@ -256,7 +300,7 @@ while read -u 5 line; do
|
||||||
break;
|
break;
|
||||||
;;
|
;;
|
||||||
*error* | *Error* | failed )
|
*error* | *Error* | failed )
|
||||||
echo $line
|
echo "GDB error:" $line
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
* )
|
* )
|
||||||
|
|
@ -264,19 +308,18 @@ while read -u 5 line; do
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$attach_existing" != "yes" ]; then
|
# Now that GDB is attached, tell the Java debugger to resume execution
|
||||||
# Send EOF to JDB to make it go away. This will also cause
|
# and then exit.
|
||||||
# Android to allow Emacs to continue executing.
|
|
||||||
echo "Making JDB go away..."
|
if [ -n "$jdb_command" ]; then
|
||||||
echo "exit" >&4
|
echo "resume" >&${JDB[1]}
|
||||||
read -u 4 line
|
echo "exit" >&${JDB[1]}
|
||||||
echo "JDB has gone away with $line"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Forward the gdb server port here.
|
# Forward the gdb server port here.
|
||||||
adb -s $device forward "tcp:$gdb_port" $gdb_socket
|
adb -s $device forward "tcp:$gdb_port" $gdb_socket
|
||||||
if [ ! $? ]; then
|
if [ ! $? ]; then
|
||||||
echo "Failed to forward $app_data_dir/debug.$package_uid.socket"
|
echo "Failed to forward $app_data_dir/debug.$package.socket"
|
||||||
echo "to $gdb_port! Perhaps you need to specify a different port"
|
echo "to $gdb_port! Perhaps you need to specify a different port"
|
||||||
echo "with --port?"
|
echo "with --port?"
|
||||||
exit 1;
|
exit 1;
|
||||||
|
|
@ -284,4 +327,4 @@ fi
|
||||||
|
|
||||||
# Finally, start gdb with any extra arguments needed.
|
# Finally, start gdb with any extra arguments needed.
|
||||||
cd "$oldpwd"
|
cd "$oldpwd"
|
||||||
gdb --eval-command "" --eval-command "target remote localhost:$gdb_port" $gdbargs
|
gdb --eval-command "target remote localhost:$gdb_port" $gdbargs
|
||||||
|
|
|
||||||
|
|
@ -168,10 +168,22 @@ public class EmacsContextMenu
|
||||||
{
|
{
|
||||||
if (item.subMenu != null)
|
if (item.subMenu != null)
|
||||||
{
|
{
|
||||||
/* This is a submenu. Create the submenu and add the
|
try
|
||||||
|
{
|
||||||
|
/* This is a submenu. On versions of Android which
|
||||||
|
support doing so, create the submenu and add the
|
||||||
contents of the menu to it. */
|
contents of the menu to it. */
|
||||||
submenu = menu.addSubMenu (item.itemName);
|
submenu = menu.addSubMenu (item.itemName);
|
||||||
item.subMenu.inflateMenuItems (submenu);
|
}
|
||||||
|
catch (UnsupportedOperationException exception)
|
||||||
|
{
|
||||||
|
/* This version of Android has a restriction
|
||||||
|
preventing submenus from being added to submenus.
|
||||||
|
Inflate everything into the parent menu
|
||||||
|
instead. */
|
||||||
|
item.subMenu.inflateMenuItems (menu);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
/* This is still needed to set wasSubmenuSelected. */
|
/* This is still needed to set wasSubmenuSelected. */
|
||||||
menuItem = submenu.getItem ();
|
menuItem = submenu.getItem ();
|
||||||
|
|
|
||||||
|
|
@ -66,19 +66,11 @@ public class EmacsCopyArea
|
||||||
|
|
||||||
paint = gc.gcPaint;
|
paint = gc.gcPaint;
|
||||||
|
|
||||||
canvas = destination.lockCanvas ();
|
canvas = destination.lockCanvas (gc);
|
||||||
|
|
||||||
if (canvas == null)
|
if (canvas == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
canvas.save ();
|
|
||||||
|
|
||||||
if (gc.real_clip_rects != null)
|
|
||||||
{
|
|
||||||
for (i = 0; i < gc.real_clip_rects.length; ++i)
|
|
||||||
canvas.clipRect (gc.real_clip_rects[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* A copy must be created or drawBitmap could end up overwriting
|
/* A copy must be created or drawBitmap could end up overwriting
|
||||||
itself. */
|
itself. */
|
||||||
srcBitmap = source.getBitmap ();
|
srcBitmap = source.getBitmap ();
|
||||||
|
|
@ -189,7 +181,6 @@ public class EmacsCopyArea
|
||||||
maskBitmap.recycle ();
|
maskBitmap.recycle ();
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.restore ();
|
|
||||||
destination.damageRect (rect);
|
destination.damageRect (rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -168,9 +168,6 @@ public class EmacsDialog implements DialogInterface.OnDismissListener
|
||||||
button = buttons.get (1);
|
button = buttons.get (1);
|
||||||
dialog.setButton (DialogInterface.BUTTON_NEUTRAL,
|
dialog.setButton (DialogInterface.BUTTON_NEUTRAL,
|
||||||
button.name, button);
|
button.name, button);
|
||||||
buttonView
|
|
||||||
= dialog.getButton (DialogInterface.BUTTON_NEUTRAL);
|
|
||||||
buttonView.setEnabled (button.enabled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size >= 3)
|
if (size >= 3)
|
||||||
|
|
|
||||||
|
|
@ -49,19 +49,11 @@ public class EmacsDrawLine
|
||||||
Math.min (y, y2 + 1),
|
Math.min (y, y2 + 1),
|
||||||
Math.max (x2 + 1, x),
|
Math.max (x2 + 1, x),
|
||||||
Math.max (y2 + 1, y));
|
Math.max (y2 + 1, y));
|
||||||
canvas = drawable.lockCanvas ();
|
canvas = drawable.lockCanvas (gc);
|
||||||
|
|
||||||
if (canvas == null)
|
if (canvas == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
canvas.save ();
|
|
||||||
|
|
||||||
if (gc.real_clip_rects != null)
|
|
||||||
{
|
|
||||||
for (i = 0; i < gc.real_clip_rects.length; ++i)
|
|
||||||
canvas.clipRect (gc.real_clip_rects[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
paint.setStyle (Paint.Style.STROKE);
|
paint.setStyle (Paint.Style.STROKE);
|
||||||
|
|
||||||
if (gc.clip_mask == null)
|
if (gc.clip_mask == null)
|
||||||
|
|
@ -71,7 +63,6 @@ public class EmacsDrawLine
|
||||||
|
|
||||||
/* DrawLine with clip mask not implemented; it is not used by
|
/* DrawLine with clip mask not implemented; it is not used by
|
||||||
Emacs. */
|
Emacs. */
|
||||||
canvas.restore ();
|
|
||||||
drawable.damageRect (rect);
|
drawable.damageRect (rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import android.graphics.Bitmap;
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.RectF;
|
||||||
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
|
@ -36,51 +37,31 @@ public class EmacsDrawRectangle
|
||||||
Paint maskPaint, paint;
|
Paint maskPaint, paint;
|
||||||
Canvas maskCanvas;
|
Canvas maskCanvas;
|
||||||
Bitmap maskBitmap;
|
Bitmap maskBitmap;
|
||||||
|
Rect rect;
|
||||||
Rect maskRect, dstRect;
|
Rect maskRect, dstRect;
|
||||||
Canvas canvas;
|
Canvas canvas;
|
||||||
Bitmap clipBitmap;
|
Bitmap clipBitmap;
|
||||||
Rect clipRect;
|
|
||||||
|
|
||||||
/* TODO implement stippling. */
|
/* TODO implement stippling. */
|
||||||
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
|
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
canvas = drawable.lockCanvas ();
|
canvas = drawable.lockCanvas (gc);
|
||||||
|
|
||||||
if (canvas == null)
|
if (canvas == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
canvas.save ();
|
|
||||||
|
|
||||||
if (gc.real_clip_rects != null)
|
|
||||||
{
|
|
||||||
for (i = 0; i < gc.real_clip_rects.length; ++i)
|
|
||||||
canvas.clipRect (gc.real_clip_rects[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clip to the clipRect because some versions of Android draw an
|
|
||||||
overly wide line. */
|
|
||||||
clipRect = new Rect (x, y, x + width + 1,
|
|
||||||
y + height + 1);
|
|
||||||
canvas.clipRect (clipRect);
|
|
||||||
|
|
||||||
paint = gc.gcPaint;
|
paint = gc.gcPaint;
|
||||||
|
paint.setStyle (Paint.Style.STROKE);
|
||||||
|
rect = new Rect (x, y, x + width, y + height);
|
||||||
|
|
||||||
if (gc.clip_mask == null)
|
if (gc.clip_mask == null)
|
||||||
{
|
/* Use canvas.drawRect with a RectF. That seems to reliably
|
||||||
/* canvas.drawRect just doesn't work on Android, producing
|
get PostScript behavior. */
|
||||||
different results on various devices. Do a 5 point
|
canvas.drawRect (new RectF (x + 0.5f, y + 0.5f,
|
||||||
PolyLine instead. */
|
x + width + 0.5f,
|
||||||
canvas.drawLine ((float) x, (float) y, (float) x + width,
|
y + height + 0.5f),
|
||||||
(float) y, paint);
|
|
||||||
canvas.drawLine ((float) x + width, (float) y,
|
|
||||||
(float) x + width, (float) y + height,
|
|
||||||
paint);
|
paint);
|
||||||
canvas.drawLine ((float) x + width, (float) y + height,
|
|
||||||
(float) x, (float) y + height, paint);
|
|
||||||
canvas.drawLine ((float) x, (float) y + height,
|
|
||||||
(float) x, (float) y, paint);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Drawing with a clip mask involves calculating the
|
/* Drawing with a clip mask involves calculating the
|
||||||
|
|
@ -137,7 +118,7 @@ public class EmacsDrawRectangle
|
||||||
maskBitmap.recycle ();
|
maskBitmap.recycle ();
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.restore ();
|
drawable.damageRect (new Rect (x, y, x + width + 1,
|
||||||
drawable.damageRect (clipRect);
|
y + height + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import android.graphics.Canvas;
|
||||||
|
|
||||||
public interface EmacsDrawable
|
public interface EmacsDrawable
|
||||||
{
|
{
|
||||||
public Canvas lockCanvas ();
|
public Canvas lockCanvas (EmacsGC gc);
|
||||||
public void damageRect (Rect damageRect);
|
public void damageRect (Rect damageRect);
|
||||||
public Bitmap getBitmap ();
|
public Bitmap getBitmap ();
|
||||||
public boolean isDestroyed ();
|
public boolean isDestroyed ();
|
||||||
|
|
|
||||||
|
|
@ -41,21 +41,13 @@ public class EmacsFillPolygon
|
||||||
RectF rectF;
|
RectF rectF;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
canvas = drawable.lockCanvas ();
|
canvas = drawable.lockCanvas (gc);
|
||||||
|
|
||||||
if (canvas == null)
|
if (canvas == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
paint = gc.gcPaint;
|
paint = gc.gcPaint;
|
||||||
|
|
||||||
canvas.save ();
|
|
||||||
|
|
||||||
if (gc.real_clip_rects != null)
|
|
||||||
{
|
|
||||||
for (i = 0; i < gc.real_clip_rects.length; ++i)
|
|
||||||
canvas.clipRect (gc.real_clip_rects[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Build the path from the given array of points. */
|
/* Build the path from the given array of points. */
|
||||||
path = new Path ();
|
path = new Path ();
|
||||||
|
|
||||||
|
|
@ -83,7 +75,6 @@ public class EmacsFillPolygon
|
||||||
if (gc.clip_mask == null)
|
if (gc.clip_mask == null)
|
||||||
canvas.drawPath (path, paint);
|
canvas.drawPath (path, paint);
|
||||||
|
|
||||||
canvas.restore ();
|
|
||||||
drawable.damageRect (rect);
|
drawable.damageRect (rect);
|
||||||
|
|
||||||
/* FillPolygon with clip mask not implemented; it is not used by
|
/* FillPolygon with clip mask not implemented; it is not used by
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ public class EmacsFillRectangle
|
||||||
perform (EmacsDrawable drawable, EmacsGC gc,
|
perform (EmacsDrawable drawable, EmacsGC gc,
|
||||||
int x, int y, int width, int height)
|
int x, int y, int width, int height)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
Paint maskPaint, paint;
|
Paint maskPaint, paint;
|
||||||
Canvas maskCanvas;
|
Canvas maskCanvas;
|
||||||
Bitmap maskBitmap;
|
Bitmap maskBitmap;
|
||||||
|
|
@ -45,19 +44,11 @@ public class EmacsFillRectangle
|
||||||
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
|
if (gc.fill_style == EmacsGC.GC_FILL_OPAQUE_STIPPLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
canvas = drawable.lockCanvas ();
|
canvas = drawable.lockCanvas (gc);
|
||||||
|
|
||||||
if (canvas == null)
|
if (canvas == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
canvas.save ();
|
|
||||||
|
|
||||||
if (gc.real_clip_rects != null)
|
|
||||||
{
|
|
||||||
for (i = 0; i < gc.real_clip_rects.length; ++i)
|
|
||||||
canvas.clipRect (gc.real_clip_rects[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
paint = gc.gcPaint;
|
paint = gc.gcPaint;
|
||||||
rect = new Rect (x, y, x + width, y + height);
|
rect = new Rect (x, y, x + width, y + height);
|
||||||
|
|
||||||
|
|
@ -120,7 +111,6 @@ public class EmacsFillRectangle
|
||||||
maskBitmap.recycle ();
|
maskBitmap.recycle ();
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.restore ();
|
|
||||||
drawable.damageRect (rect);
|
drawable.damageRect (rect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,14 @@ public class EmacsGC extends EmacsHandleObject
|
||||||
public EmacsPixmap clip_mask, stipple;
|
public EmacsPixmap clip_mask, stipple;
|
||||||
public Paint gcPaint;
|
public Paint gcPaint;
|
||||||
|
|
||||||
|
/* ID incremented every time the clipping rectangles of any GC
|
||||||
|
changes. */
|
||||||
|
private static long clip_serial;
|
||||||
|
|
||||||
|
/* The value of clipRectID after the last time this GCs clip
|
||||||
|
rectangles changed. 0 if there are no clip rectangles. */
|
||||||
|
public long clipRectID;
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
xorAlu = new PorterDuffXfermode (Mode.XOR);
|
xorAlu = new PorterDuffXfermode (Mode.XOR);
|
||||||
|
|
@ -75,10 +83,12 @@ public class EmacsGC extends EmacsHandleObject
|
||||||
recompute real_clip_rects. */
|
recompute real_clip_rects. */
|
||||||
|
|
||||||
public void
|
public void
|
||||||
markDirty ()
|
markDirty (boolean clipRectsChanged)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
if (clipRectsChanged)
|
||||||
|
{
|
||||||
if ((ts_origin_x != 0 || ts_origin_y != 0)
|
if ((ts_origin_x != 0 || ts_origin_y != 0)
|
||||||
&& clip_rects != null)
|
&& clip_rects != null)
|
||||||
{
|
{
|
||||||
|
|
@ -93,6 +103,9 @@ public class EmacsGC extends EmacsHandleObject
|
||||||
else
|
else
|
||||||
real_clip_rects = clip_rects;
|
real_clip_rects = clip_rects;
|
||||||
|
|
||||||
|
clipRectID = ++clip_serial;
|
||||||
|
}
|
||||||
|
|
||||||
gcPaint.setStrokeWidth (1f);
|
gcPaint.setStrokeWidth (1f);
|
||||||
gcPaint.setColor (foreground | 0xff000000);
|
gcPaint.setColor (foreground | 0xff000000);
|
||||||
gcPaint.setXfermode (function == GC_XOR
|
gcPaint.setXfermode (function == GC_XOR
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,14 @@ public class EmacsPixmap extends EmacsHandleObject
|
||||||
/* The canvas used to draw to BITMAP. */
|
/* The canvas used to draw to BITMAP. */
|
||||||
public Canvas canvas;
|
public Canvas canvas;
|
||||||
|
|
||||||
|
/* Whether or not GC should be explicitly triggered upon
|
||||||
|
release. */
|
||||||
|
private boolean needCollect;
|
||||||
|
|
||||||
|
/* ID used to determine whether or not the GC clip rects
|
||||||
|
changed. */
|
||||||
|
private long gcClipRectID;
|
||||||
|
|
||||||
public
|
public
|
||||||
EmacsPixmap (short handle, int colors[], int width,
|
EmacsPixmap (short handle, int colors[], int width,
|
||||||
int height, int depth)
|
int height, int depth)
|
||||||
|
|
@ -83,18 +91,41 @@ public class EmacsPixmap extends EmacsHandleObject
|
||||||
switch (depth)
|
switch (depth)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
bitmap = Bitmap.createBitmap (width, height,
|
bitmap = Bitmap.createBitmap (width, height,
|
||||||
Bitmap.Config.ALPHA_8,
|
Bitmap.Config.ALPHA_8,
|
||||||
false);
|
false);
|
||||||
|
else
|
||||||
|
bitmap = Bitmap.createBitmap (width, height,
|
||||||
|
Bitmap.Config.ALPHA_8);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 24:
|
case 24:
|
||||||
|
|
||||||
|
/* Emacs doesn't just use the first kind of `createBitmap'
|
||||||
|
because the latter allows specifying that the pixmap is
|
||||||
|
always opaque, which really increases efficiency. */
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
|
||||||
|
bitmap = Bitmap.createBitmap (width, height,
|
||||||
|
Bitmap.Config.ARGB_8888);
|
||||||
|
else
|
||||||
bitmap = Bitmap.createBitmap (width, height,
|
bitmap = Bitmap.createBitmap (width, height,
|
||||||
Bitmap.Config.ARGB_8888,
|
Bitmap.Config.ARGB_8888,
|
||||||
false);
|
false);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1)
|
||||||
|
/* On these old versions of Android, Bitmap.recycle frees bitmap
|
||||||
|
contents immediately. */
|
||||||
|
needCollect = false;
|
||||||
|
else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
|
||||||
|
needCollect = (bitmap.getByteCount ()
|
||||||
|
>= 1024 * 512);
|
||||||
|
else
|
||||||
|
needCollect = (bitmap.getAllocationByteCount ()
|
||||||
|
>= 1024 * 512);
|
||||||
|
|
||||||
bitmap.eraseColor (0xff000000);
|
bitmap.eraseColor (0xff000000);
|
||||||
|
|
||||||
this.width = width;
|
this.width = width;
|
||||||
|
|
@ -104,11 +135,32 @@ public class EmacsPixmap extends EmacsHandleObject
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Canvas
|
public Canvas
|
||||||
lockCanvas ()
|
lockCanvas (EmacsGC gc)
|
||||||
{
|
{
|
||||||
if (canvas == null)
|
int i;
|
||||||
canvas = new Canvas (bitmap);
|
|
||||||
|
|
||||||
|
if (canvas == null)
|
||||||
|
{
|
||||||
|
canvas = new Canvas (bitmap);
|
||||||
|
canvas.save ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now see if clipping has to be redone. */
|
||||||
|
if (gc.clipRectID == gcClipRectID)
|
||||||
|
return canvas;
|
||||||
|
|
||||||
|
/* It does have to be redone. Reapply gc.real_clip_rects. */
|
||||||
|
canvas.restore ();
|
||||||
|
canvas.save ();
|
||||||
|
|
||||||
|
if (gc.real_clip_rects != null)
|
||||||
|
{
|
||||||
|
for (i = 0; i < gc.real_clip_rects.length; ++i)
|
||||||
|
canvas.clipRect (gc.real_clip_rects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the clip rect ID again. */
|
||||||
|
gcClipRectID = gc.clipRectID;
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,15 +182,6 @@ public class EmacsPixmap extends EmacsHandleObject
|
||||||
public void
|
public void
|
||||||
destroyHandle ()
|
destroyHandle ()
|
||||||
{
|
{
|
||||||
boolean needCollect;
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
|
|
||||||
needCollect = (bitmap.getByteCount ()
|
|
||||||
>= 1024 * 512);
|
|
||||||
else
|
|
||||||
needCollect = (bitmap.getAllocationByteCount ()
|
|
||||||
>= 1024 * 512);
|
|
||||||
|
|
||||||
bitmap.recycle ();
|
bitmap.recycle ();
|
||||||
bitmap = null;
|
bitmap = null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -510,20 +510,12 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
|
||||||
backgroundRect.right = x + backgroundWidth;
|
backgroundRect.right = x + backgroundWidth;
|
||||||
backgroundRect.bottom = y + sdk7FontObject.descent;
|
backgroundRect.bottom = y + sdk7FontObject.descent;
|
||||||
|
|
||||||
canvas = drawable.lockCanvas ();
|
canvas = drawable.lockCanvas (gc);
|
||||||
|
|
||||||
if (canvas == null)
|
if (canvas == null)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
canvas.save ();
|
|
||||||
paint = gc.gcPaint;
|
paint = gc.gcPaint;
|
||||||
|
|
||||||
if (gc.real_clip_rects != null)
|
|
||||||
{
|
|
||||||
for (i = 0; i < gc.real_clip_rects.length; ++i)
|
|
||||||
canvas.clipRect (gc.real_clip_rects[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
paint.setStyle (Paint.Style.FILL);
|
paint.setStyle (Paint.Style.FILL);
|
||||||
|
|
||||||
if (withBackground)
|
if (withBackground)
|
||||||
|
|
@ -538,7 +530,6 @@ public class EmacsSdk7FontDriver extends EmacsFontDriver
|
||||||
paint.setAntiAlias (true);
|
paint.setAntiAlias (true);
|
||||||
canvas.drawText (charsArray, 0, chars.length, x, y, paint);
|
canvas.drawText (charsArray, 0, chars.length, x, y, paint);
|
||||||
|
|
||||||
canvas.restore ();
|
|
||||||
bounds = new Rect ();
|
bounds = new Rect ();
|
||||||
paint.getTextBounds (charsArray, 0, chars.length, bounds);
|
paint.getTextBounds (charsArray, 0, chars.length, bounds);
|
||||||
bounds.offset (x, y);
|
bounds.offset (x, y);
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,12 @@ public class EmacsService extends Service
|
||||||
{
|
{
|
||||||
view.thing = new EmacsView (window);
|
view.thing = new EmacsView (window);
|
||||||
view.thing.setVisibility (visibility);
|
view.thing.setVisibility (visibility);
|
||||||
|
|
||||||
|
/* The following function is only present on Android 26
|
||||||
|
or later. */
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||||
view.thing.setFocusedByDefault (isFocusedByDefault);
|
view.thing.setFocusedByDefault (isFocusedByDefault);
|
||||||
|
|
||||||
notify ();
|
notify ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,9 @@ public class EmacsView extends ViewGroup
|
||||||
/* The last measured width and height. */
|
/* The last measured width and height. */
|
||||||
private int measuredWidth, measuredHeight;
|
private int measuredWidth, measuredHeight;
|
||||||
|
|
||||||
|
/* The serial of the last clip rectangle change. */
|
||||||
|
private long lastClipSerial;
|
||||||
|
|
||||||
public
|
public
|
||||||
EmacsView (EmacsWindow window)
|
EmacsView (EmacsWindow window)
|
||||||
{
|
{
|
||||||
|
|
@ -105,10 +108,6 @@ public class EmacsView extends ViewGroup
|
||||||
on Android? */
|
on Android? */
|
||||||
setChildrenDrawingOrderEnabled (true);
|
setChildrenDrawingOrderEnabled (true);
|
||||||
|
|
||||||
/* Get rid of the foreground and background tint. */
|
|
||||||
setBackgroundTintList (null);
|
|
||||||
setForegroundTintList (null);
|
|
||||||
|
|
||||||
/* Get rid of the default focus highlight. */
|
/* Get rid of the default focus highlight. */
|
||||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
|
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O)
|
||||||
setDefaultFocusHighlightEnabled (false);
|
setDefaultFocusHighlightEnabled (false);
|
||||||
|
|
@ -145,6 +144,11 @@ public class EmacsView extends ViewGroup
|
||||||
|
|
||||||
/* And canvases. */
|
/* And canvases. */
|
||||||
canvas = new Canvas (bitmap);
|
canvas = new Canvas (bitmap);
|
||||||
|
canvas.save ();
|
||||||
|
|
||||||
|
/* Since the clip rectangles have been cleared, clear the clip
|
||||||
|
rectangle ID. */
|
||||||
|
lastClipSerial = 0;
|
||||||
|
|
||||||
/* Copy over the contents of the old bitmap. */
|
/* Copy over the contents of the old bitmap. */
|
||||||
if (oldBitmap != null)
|
if (oldBitmap != null)
|
||||||
|
|
@ -177,11 +181,31 @@ public class EmacsView extends ViewGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized Canvas
|
public synchronized Canvas
|
||||||
getCanvas ()
|
getCanvas (EmacsGC gc)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
if (bitmapDirty || bitmap == null)
|
if (bitmapDirty || bitmap == null)
|
||||||
handleDirtyBitmap ();
|
handleDirtyBitmap ();
|
||||||
|
|
||||||
|
if (canvas == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
/* Update clip rectangles if necessary. */
|
||||||
|
if (gc.clipRectID != lastClipSerial)
|
||||||
|
{
|
||||||
|
canvas.restore ();
|
||||||
|
canvas.save ();
|
||||||
|
|
||||||
|
if (gc.real_clip_rects != null)
|
||||||
|
{
|
||||||
|
for (i = 0; i < gc.real_clip_rects.length; ++i)
|
||||||
|
canvas.clipRect (gc.real_clip_rects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastClipSerial = gc.clipRectID;
|
||||||
|
}
|
||||||
|
|
||||||
return canvas;
|
return canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -164,7 +164,7 @@ public class EmacsWindow extends EmacsHandleObject
|
||||||
{
|
{
|
||||||
/* scratchGC is used as the argument to a FillRectangles req. */
|
/* scratchGC is used as the argument to a FillRectangles req. */
|
||||||
scratchGC.foreground = pixel;
|
scratchGC.foreground = pixel;
|
||||||
scratchGC.markDirty ();
|
scratchGC.markDirty (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rect
|
public Rect
|
||||||
|
|
@ -466,9 +466,9 @@ public class EmacsWindow extends EmacsHandleObject
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Canvas
|
public Canvas
|
||||||
lockCanvas ()
|
lockCanvas (EmacsGC gc)
|
||||||
{
|
{
|
||||||
return view.getCanvas ();
|
return view.getCanvas (gc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -512,37 +512,75 @@ public class EmacsWindow extends EmacsHandleObject
|
||||||
public void
|
public void
|
||||||
onKeyDown (int keyCode, KeyEvent event)
|
onKeyDown (int keyCode, KeyEvent event)
|
||||||
{
|
{
|
||||||
int state;
|
int state, state_1;
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2)
|
||||||
state = event.getModifiers ();
|
state = event.getModifiers ();
|
||||||
state &= ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK);
|
else
|
||||||
|
{
|
||||||
|
/* Replace this with getMetaState and manual
|
||||||
|
normalization. */
|
||||||
|
state = event.getMetaState ();
|
||||||
|
|
||||||
|
/* Normalize the state by setting the generic modifier bit if
|
||||||
|
either a left or right modifier is pressed. */
|
||||||
|
|
||||||
|
if ((state & KeyEvent.META_ALT_LEFT_ON) != 0
|
||||||
|
|| (state & KeyEvent.META_ALT_RIGHT_ON) != 0)
|
||||||
|
state |= KeyEvent.META_ALT_MASK;
|
||||||
|
|
||||||
|
if ((state & KeyEvent.META_CTRL_LEFT_ON) != 0
|
||||||
|
|| (state & KeyEvent.META_CTRL_RIGHT_ON) != 0)
|
||||||
|
state |= KeyEvent.META_CTRL_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ignore meta-state understood by Emacs for now, or Ctrl+C will
|
||||||
|
not be recognized as an ASCII key press event. */
|
||||||
|
state_1
|
||||||
|
= state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK);
|
||||||
|
|
||||||
EmacsNative.sendKeyPress (this.handle,
|
EmacsNative.sendKeyPress (this.handle,
|
||||||
event.getEventTime (),
|
event.getEventTime (),
|
||||||
event.getModifiers (),
|
state, keyCode,
|
||||||
keyCode,
|
event.getUnicodeChar (state_1));
|
||||||
/* Ignore meta-state understood by Emacs
|
lastModifiers = state;
|
||||||
for now, or Ctrl+C will not be
|
|
||||||
recognized as an ASCII key press
|
|
||||||
event. */
|
|
||||||
event.getUnicodeChar (state));
|
|
||||||
lastModifiers = event.getModifiers ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void
|
public void
|
||||||
onKeyUp (int keyCode, KeyEvent event)
|
onKeyUp (int keyCode, KeyEvent event)
|
||||||
{
|
{
|
||||||
int state;
|
int state, state_1;
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2)
|
||||||
state = event.getModifiers ();
|
state = event.getModifiers ();
|
||||||
state &= ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK);
|
else
|
||||||
|
{
|
||||||
|
/* Replace this with getMetaState and manual
|
||||||
|
normalization. */
|
||||||
|
state = event.getMetaState ();
|
||||||
|
|
||||||
|
/* Normalize the state by setting the generic modifier bit if
|
||||||
|
either a left or right modifier is pressed. */
|
||||||
|
|
||||||
|
if ((state & KeyEvent.META_ALT_LEFT_ON) != 0
|
||||||
|
|| (state & KeyEvent.META_ALT_RIGHT_ON) != 0)
|
||||||
|
state |= KeyEvent.META_ALT_MASK;
|
||||||
|
|
||||||
|
if ((state & KeyEvent.META_CTRL_LEFT_ON) != 0
|
||||||
|
|| (state & KeyEvent.META_CTRL_RIGHT_ON) != 0)
|
||||||
|
state |= KeyEvent.META_CTRL_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ignore meta-state understood by Emacs for now, or Ctrl+C will
|
||||||
|
not be recognized as an ASCII key press event. */
|
||||||
|
state_1
|
||||||
|
= state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK);
|
||||||
|
|
||||||
EmacsNative.sendKeyRelease (this.handle,
|
EmacsNative.sendKeyRelease (this.handle,
|
||||||
event.getEventTime (),
|
event.getEventTime (),
|
||||||
event.getModifiers (),
|
state, keyCode,
|
||||||
keyCode,
|
event.getUnicodeChar (state_1));
|
||||||
event.getUnicodeChar (state));
|
lastModifiers = state;
|
||||||
lastModifiers = event.getModifiers ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void
|
public void
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,9 @@ HAVE_BE_APP=@HAVE_BE_APP@
|
||||||
HAIKU_LIBS=@HAIKU_LIBS@
|
HAIKU_LIBS=@HAIKU_LIBS@
|
||||||
HAIKU_CFLAGS=@HAIKU_CFLAGS@
|
HAIKU_CFLAGS=@HAIKU_CFLAGS@
|
||||||
|
|
||||||
|
## Android build-time support
|
||||||
|
ANDROID=@ANDROID@
|
||||||
|
|
||||||
# emacsclientw.exe for MinGW, empty otherwise
|
# emacsclientw.exe for MinGW, empty otherwise
|
||||||
CLIENTW = @CLIENTW@
|
CLIENTW = @CLIENTW@
|
||||||
|
|
||||||
|
|
@ -164,8 +167,13 @@ UTILITIES = hexl${EXEEXT} \
|
||||||
ifeq ($(HAVE_BE_APP),yes)
|
ifeq ($(HAVE_BE_APP),yes)
|
||||||
DONT_INSTALL= make-docfile${EXEEXT} make-fingerprint${EXEEXT} be-resources
|
DONT_INSTALL= make-docfile${EXEEXT} make-fingerprint${EXEEXT} be-resources
|
||||||
else
|
else
|
||||||
|
ifeq ($(HAVE_ANDROID),yes)
|
||||||
|
DONT_INSTALL = make-docfile${EXEEXT} make-fingerprint${EXEEXT} \
|
||||||
|
asset-directory-tool
|
||||||
|
else
|
||||||
DONT_INSTALL= make-docfile${EXEEXT} make-fingerprint${EXEEXT}
|
DONT_INSTALL= make-docfile${EXEEXT} make-fingerprint${EXEEXT}
|
||||||
endif
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
# Like UTILITIES, but they're not system-dependent, and should not be
|
# Like UTILITIES, but they're not system-dependent, and should not be
|
||||||
# deleted by the distclean target.
|
# deleted by the distclean target.
|
||||||
|
|
@ -414,6 +422,9 @@ etags${EXEEXT}: ${etags_deps}
|
||||||
ctags${EXEEXT}: ${srcdir}/ctags.c ${etags_deps}
|
ctags${EXEEXT}: ${srcdir}/ctags.c ${etags_deps}
|
||||||
$(AM_V_CCLD)$(CC) ${ALL_CFLAGS} -o $@ $< $(etags_libs)
|
$(AM_V_CCLD)$(CC) ${ALL_CFLAGS} -o $@ $< $(etags_libs)
|
||||||
|
|
||||||
|
asset-directory-tool${EXEEXT}: ${srcdir}/asset-directory-tool.c $(config_h)
|
||||||
|
$(AM_V_CCLD)$(CC) ${ALL_CFLAGS} $< $(LOADLIBES) -o $@
|
||||||
|
|
||||||
ebrowse${EXEEXT}: ${srcdir}/ebrowse.c ${srcdir}/../lib/min-max.h $(NTLIB) \
|
ebrowse${EXEEXT}: ${srcdir}/ebrowse.c ${srcdir}/../lib/min-max.h $(NTLIB) \
|
||||||
$(config_h)
|
$(config_h)
|
||||||
$(AM_V_CCLD)$(CC) ${ALL_CFLAGS} -o $@ $< $(NTLIB) $(LOADLIBES)
|
$(AM_V_CCLD)$(CC) ${ALL_CFLAGS} -o $@ $< $(NTLIB) $(LOADLIBES)
|
||||||
|
|
|
||||||
280
lib-src/asset-directory-tool.c
Normal file
280
lib-src/asset-directory-tool.c
Normal file
|
|
@ -0,0 +1,280 @@
|
||||||
|
/* Android asset directory tool.
|
||||||
|
|
||||||
|
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is part of GNU Emacs.
|
||||||
|
|
||||||
|
GNU Emacs is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or (at
|
||||||
|
your option) any later version.
|
||||||
|
|
||||||
|
GNU Emacs is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <endian.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
/* This program takes a directory as input, and generates a
|
||||||
|
``directory-tree'' file suitable for inclusion in an Android
|
||||||
|
application package.
|
||||||
|
|
||||||
|
Such a file records the layout of the `assets' directory in the
|
||||||
|
package. Emacs records this information itself and uses it in the
|
||||||
|
Android emulation of readdir, because the system asset manager APIs
|
||||||
|
are routinely buggy, and are often unable to locate directories or
|
||||||
|
files.
|
||||||
|
|
||||||
|
The file is packed, with no data alignment guarantees made. The
|
||||||
|
file starts with the bytes "EMACS", following which is the name of
|
||||||
|
the first file or directory, a NULL byte and an unsigned int
|
||||||
|
indicating the offset from the start of the file to the start of
|
||||||
|
the next sibling. Following that is a list of subdirectories or
|
||||||
|
files in the same format. The long is stored LSB first. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct directory_tree
|
||||||
|
{
|
||||||
|
/* The offset to the next sibling. */
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
/* The name of this directory or file. */
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
/* Subdirectories and files inside this directory. */
|
||||||
|
struct directory_tree *children, *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Exit with EXIT_FAILURE, after printing a description of a failing
|
||||||
|
function WHAT along with the details of the error. */
|
||||||
|
|
||||||
|
static _Noreturn void
|
||||||
|
croak (const char *what)
|
||||||
|
{
|
||||||
|
perror (what);
|
||||||
|
exit (EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Like malloc, but aborts on failure. */
|
||||||
|
|
||||||
|
static void *
|
||||||
|
xmalloc (size_t size)
|
||||||
|
{
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
ptr = malloc (size);
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
croak ("malloc");
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Recursively build a struct directory_tree structure for each
|
||||||
|
subdirectory or file in DIR, in preparation for writing it out to
|
||||||
|
disk. PARENT should be the directory tree associated with the
|
||||||
|
parent directory, or else PARENT->offset must be initialized to
|
||||||
|
5. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
main_1 (DIR *dir, struct directory_tree *parent)
|
||||||
|
{
|
||||||
|
struct dirent *dirent;
|
||||||
|
int dir_fd, fd;
|
||||||
|
struct stat statb;
|
||||||
|
struct directory_tree *this, **last;
|
||||||
|
size_t length;
|
||||||
|
DIR *otherdir;
|
||||||
|
|
||||||
|
dir_fd = dirfd (dir);
|
||||||
|
last = &parent->children;
|
||||||
|
|
||||||
|
while ((dirent = readdir (dir)))
|
||||||
|
{
|
||||||
|
/* Determine what kind of file DIRENT is. */
|
||||||
|
|
||||||
|
if (fstatat (dir_fd, dirent->d_name, &statb,
|
||||||
|
AT_SYMLINK_NOFOLLOW) == -1)
|
||||||
|
croak ("fstatat");
|
||||||
|
|
||||||
|
/* Ignore . and ... */
|
||||||
|
|
||||||
|
if (!strcmp (dirent->d_name, ".")
|
||||||
|
|| !strcmp (dirent->d_name, ".."))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
length = strlen (dirent->d_name);
|
||||||
|
|
||||||
|
if (statb.st_mode & S_IFDIR)
|
||||||
|
{
|
||||||
|
/* This is a directory. Write its name followed by a
|
||||||
|
trailing slash, then a NULL byte, and the offset to the
|
||||||
|
next sibling. */
|
||||||
|
this = xmalloc (sizeof *this);
|
||||||
|
this->children = NULL;
|
||||||
|
this->next = NULL;
|
||||||
|
*last = this;
|
||||||
|
last = &this->next;
|
||||||
|
this->name = xmalloc (length + 2);
|
||||||
|
strcpy (this->name, dirent->d_name);
|
||||||
|
|
||||||
|
/* Now record the offset to the end of this directory. This
|
||||||
|
is length + 1, for the file name, and 5 more bytes for
|
||||||
|
the trailing NULL and long. */
|
||||||
|
this->offset = parent->offset + length + 6;
|
||||||
|
|
||||||
|
/* Terminate that with a slash and trailing NULL byte. */
|
||||||
|
this->name[length] = '/';
|
||||||
|
this->name[length + 1] = '\0';
|
||||||
|
|
||||||
|
/* Open and build that directory recursively. */
|
||||||
|
|
||||||
|
fd = openat (dir_fd, dirent->d_name, O_DIRECTORY,
|
||||||
|
O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
croak ("openat");
|
||||||
|
otherdir = fdopendir (fd);
|
||||||
|
if (!otherdir)
|
||||||
|
croak ("fdopendir");
|
||||||
|
|
||||||
|
main_1 (otherdir, this);
|
||||||
|
|
||||||
|
/* Close this directory. */
|
||||||
|
closedir (otherdir);
|
||||||
|
|
||||||
|
/* Finally, set parent->offset to this->offset as well. */
|
||||||
|
parent->offset = this->offset;
|
||||||
|
}
|
||||||
|
else if (statb.st_mode & S_IFREG)
|
||||||
|
{
|
||||||
|
/* This is a regular file. */
|
||||||
|
this = xmalloc (sizeof *this);
|
||||||
|
this->children = NULL;
|
||||||
|
this->next = NULL;
|
||||||
|
*last = this;
|
||||||
|
last = &this->next;
|
||||||
|
this->name = xmalloc (length + 1);
|
||||||
|
strcpy (this->name, dirent->d_name);
|
||||||
|
|
||||||
|
/* This is one byte shorter because there is no trailing
|
||||||
|
slash. */
|
||||||
|
this->offset = parent->offset + length + 5;
|
||||||
|
parent->offset = this->offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the struct directory_tree TREE and all of is children to the
|
||||||
|
file descriptor FD. OFFSET is the offset of TREE and may be
|
||||||
|
modified; it is only used for checking purposes. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
main_2 (int fd, struct directory_tree *tree, size_t *offset)
|
||||||
|
{
|
||||||
|
ssize_t size;
|
||||||
|
struct directory_tree *child;
|
||||||
|
unsigned int output;
|
||||||
|
|
||||||
|
/* Write tree->name with the trailing NULL byte. */
|
||||||
|
size = strlen (tree->name) + 1;
|
||||||
|
if (write (fd, tree->name, size) < size)
|
||||||
|
croak ("write");
|
||||||
|
|
||||||
|
/* Write the offset. */
|
||||||
|
output = htole32 (tree->offset);
|
||||||
|
if (write (fd, &output, 4) < 1)
|
||||||
|
croak ("write");
|
||||||
|
size += 4;
|
||||||
|
|
||||||
|
/* Now update offset. */
|
||||||
|
*offset += size;
|
||||||
|
|
||||||
|
/* Write out each child. */
|
||||||
|
for (child = tree->children; child; child = child->next)
|
||||||
|
main_2 (fd, child, offset);
|
||||||
|
|
||||||
|
/* Verify the offset is correct. */
|
||||||
|
if (tree->offset != *offset)
|
||||||
|
{
|
||||||
|
fprintf (stderr,
|
||||||
|
"asset-directory-tool: invalid offset: expected %tu, "
|
||||||
|
"got %tu.\n"
|
||||||
|
"Please report this bug to bug-gnu-emacs@gnu.org, along\n"
|
||||||
|
"with an archive containing the contents of the java/inst"
|
||||||
|
"all_temp directory.\n",
|
||||||
|
tree->offset, *offset);
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
DIR *indir;
|
||||||
|
struct directory_tree tree;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
if (argc != 3)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "usage: %s directory output-file\n",
|
||||||
|
argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open (argv[2], O_CREAT | O_TRUNC | O_RDWR,
|
||||||
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
perror ("open");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
indir = opendir (argv[1]);
|
||||||
|
|
||||||
|
if (!indir)
|
||||||
|
{
|
||||||
|
perror ("opendir");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the first 5 byte header to FD. */
|
||||||
|
|
||||||
|
if (write (fd, "EMACS", 5) < 5)
|
||||||
|
{
|
||||||
|
perror ("write");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now iterate through children of INDIR, building the directory
|
||||||
|
tree. */
|
||||||
|
tree.offset = 5;
|
||||||
|
tree.children = NULL;
|
||||||
|
|
||||||
|
main_1 (indir, &tree);
|
||||||
|
closedir (indir);
|
||||||
|
|
||||||
|
/* Finally, write the directory tree to the output file. */
|
||||||
|
offset = 5;
|
||||||
|
for (; tree.children; tree.children = tree.children->next)
|
||||||
|
main_2 (fd, tree.children, &offset);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -43,11 +43,7 @@ orig_faccessat (int fd, char const *name, int mode, int flag)
|
||||||
/* Write "unistd.h" here, not <unistd.h>, otherwise OSF/1 5.1 DTK cc
|
/* Write "unistd.h" here, not <unistd.h>, otherwise OSF/1 5.1 DTK cc
|
||||||
eliminates this include because of the preliminary #include <unistd.h>
|
eliminates this include because of the preliminary #include <unistd.h>
|
||||||
above. */
|
above. */
|
||||||
#ifdef __ANROID__
|
|
||||||
#include <unistd.h>
|
|
||||||
#else
|
|
||||||
#include "unistd.h"
|
#include "unistd.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HAVE_ACCESS
|
#ifndef HAVE_ACCESS
|
||||||
/* Mingw lacks access, but it also lacks real vs. effective ids, so
|
/* Mingw lacks access, but it also lacks real vs. effective ids, so
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ __fpending (FILE *fp)
|
||||||
return fp->_IO_write_ptr - fp->_IO_write_base;
|
return fp->_IO_write_ptr - fp->_IO_write_base;
|
||||||
#elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
|
#elif defined __sferror || defined __DragonFly__ || defined __ANDROID__
|
||||||
/* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin < 1.7.34, Minix 3, Android */
|
/* FreeBSD, NetBSD, OpenBSD, DragonFly, Mac OS X, Cygwin < 1.7.34, Minix 3, Android */
|
||||||
return fp->_p - fp->_bf._base;
|
return fp_->_p - fp_->_bf._base;
|
||||||
#elif defined __EMX__ /* emx+gcc */
|
#elif defined __EMX__ /* emx+gcc */
|
||||||
return fp->_ptr - fp->_buffer;
|
return fp->_ptr - fp->_buffer;
|
||||||
#elif defined __minix /* Minix */
|
#elif defined __minix /* Minix */
|
||||||
|
|
|
||||||
147
lib/getdelim.c
Normal file
147
lib/getdelim.c
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
/* getdelim.c --- Implementation of replacement getdelim function.
|
||||||
|
Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2023 Free Software
|
||||||
|
Foundation, Inc.
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Ported from glibc by Simon Josefsson. */
|
||||||
|
|
||||||
|
/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
|
||||||
|
optimizes away the lineptr == NULL || n == NULL || fp == NULL tests below. */
|
||||||
|
#define _GL_ARG_NONNULL(params)
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifndef SSIZE_MAX
|
||||||
|
# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_UNLOCKED_IO
|
||||||
|
# include "unlocked-io.h"
|
||||||
|
# define getc_maybe_unlocked(fp) getc(fp)
|
||||||
|
#elif !HAVE_FLOCKFILE || !HAVE_FUNLOCKFILE || !HAVE_DECL_GETC_UNLOCKED
|
||||||
|
# undef flockfile
|
||||||
|
# undef funlockfile
|
||||||
|
# define flockfile(x) ((void) 0)
|
||||||
|
# define funlockfile(x) ((void) 0)
|
||||||
|
# define getc_maybe_unlocked(fp) getc(fp)
|
||||||
|
#else
|
||||||
|
# define getc_maybe_unlocked(fp) getc_unlocked(fp)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
alloc_failed (void)
|
||||||
|
{
|
||||||
|
#if defined _WIN32 && ! defined __CYGWIN__
|
||||||
|
/* Avoid errno problem without using the realloc module; see:
|
||||||
|
https://lists.gnu.org/r/bug-gnulib/2016-08/msg00025.html */
|
||||||
|
errno = ENOMEM;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read up to (and including) a DELIMITER from FP into *LINEPTR (and
|
||||||
|
NUL-terminate it). *LINEPTR is a pointer returned from malloc (or
|
||||||
|
NULL), pointing to *N characters of space. It is realloc'ed as
|
||||||
|
necessary. Returns the number of characters read (not including
|
||||||
|
the null terminator), or -1 on error or EOF. */
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
|
||||||
|
{
|
||||||
|
ssize_t result;
|
||||||
|
size_t cur_len = 0;
|
||||||
|
|
||||||
|
if (lineptr == NULL || n == NULL || fp == NULL)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
flockfile (fp);
|
||||||
|
|
||||||
|
if (*lineptr == NULL || *n == 0)
|
||||||
|
{
|
||||||
|
char *new_lineptr;
|
||||||
|
*n = 120;
|
||||||
|
new_lineptr = (char *) realloc (*lineptr, *n);
|
||||||
|
if (new_lineptr == NULL)
|
||||||
|
{
|
||||||
|
alloc_failed ();
|
||||||
|
result = -1;
|
||||||
|
goto unlock_return;
|
||||||
|
}
|
||||||
|
*lineptr = new_lineptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = getc_maybe_unlocked (fp);
|
||||||
|
if (i == EOF)
|
||||||
|
{
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make enough space for len+1 (for final NUL) bytes. */
|
||||||
|
if (cur_len + 1 >= *n)
|
||||||
|
{
|
||||||
|
size_t needed_max =
|
||||||
|
SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
|
||||||
|
size_t needed = 2 * *n + 1; /* Be generous. */
|
||||||
|
char *new_lineptr;
|
||||||
|
|
||||||
|
if (needed_max < needed)
|
||||||
|
needed = needed_max;
|
||||||
|
if (cur_len + 1 >= needed)
|
||||||
|
{
|
||||||
|
result = -1;
|
||||||
|
errno = EOVERFLOW;
|
||||||
|
goto unlock_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_lineptr = (char *) realloc (*lineptr, needed);
|
||||||
|
if (new_lineptr == NULL)
|
||||||
|
{
|
||||||
|
alloc_failed ();
|
||||||
|
result = -1;
|
||||||
|
goto unlock_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*lineptr = new_lineptr;
|
||||||
|
*n = needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*lineptr)[cur_len] = i;
|
||||||
|
cur_len++;
|
||||||
|
|
||||||
|
if (i == delimiter)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(*lineptr)[cur_len] = '\0';
|
||||||
|
result = cur_len ? cur_len : result;
|
||||||
|
|
||||||
|
unlock_return:
|
||||||
|
funlockfile (fp); /* doesn't set errno */
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
27
lib/getline.c
Normal file
27
lib/getline.c
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* getline.c --- Implementation of replacement getline function.
|
||||||
|
Copyright (C) 2005-2007, 2009-2023 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Written by Simon Josefsson. */
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
getline (char **lineptr, size_t *n, FILE *stream)
|
||||||
|
{
|
||||||
|
return getdelim (lineptr, n, '\n', stream);
|
||||||
|
}
|
||||||
|
|
@ -109,6 +109,7 @@
|
||||||
# fsusage \
|
# fsusage \
|
||||||
# fsync \
|
# fsync \
|
||||||
# futimens \
|
# futimens \
|
||||||
|
# getline \
|
||||||
# getloadavg \
|
# getloadavg \
|
||||||
# getopt-gnu \
|
# getopt-gnu \
|
||||||
# getrandom \
|
# getrandom \
|
||||||
|
|
@ -172,11 +173,19 @@
|
||||||
|
|
||||||
MOSTLYCLEANFILES += core *.stackdump
|
MOSTLYCLEANFILES += core *.stackdump
|
||||||
# Start of GNU Make output.
|
# Start of GNU Make output.
|
||||||
|
AAPT = @AAPT@
|
||||||
ALLOCA = @ALLOCA@
|
ALLOCA = @ALLOCA@
|
||||||
ALLOCA_H = @ALLOCA_H@
|
ALLOCA_H = @ALLOCA_H@
|
||||||
ALSA_CFLAGS = @ALSA_CFLAGS@
|
ALSA_CFLAGS = @ALSA_CFLAGS@
|
||||||
ALSA_LIBS = @ALSA_LIBS@
|
ALSA_LIBS = @ALSA_LIBS@
|
||||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||||
|
ANDROID = @ANDROID@
|
||||||
|
ANDROID_ABI = @ANDROID_ABI@
|
||||||
|
ANDROID_CFLAGS = @ANDROID_CFLAGS@
|
||||||
|
ANDROID_JAR = @ANDROID_JAR@
|
||||||
|
ANDROID_LIBS = @ANDROID_LIBS@
|
||||||
|
ANDROID_MIN_SDK = @ANDROID_MIN_SDK@
|
||||||
|
ANDROID_OBJ = @ANDROID_OBJ@
|
||||||
APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@
|
APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@
|
||||||
AR = @AR@
|
AR = @AR@
|
||||||
ARFLAGS = @ARFLAGS@
|
ARFLAGS = @ARFLAGS@
|
||||||
|
|
@ -216,6 +225,7 @@ CYGWIN_OBJ = @CYGWIN_OBJ@
|
||||||
C_SWITCH_MACHINE = @C_SWITCH_MACHINE@
|
C_SWITCH_MACHINE = @C_SWITCH_MACHINE@
|
||||||
C_SWITCH_SYSTEM = @C_SWITCH_SYSTEM@
|
C_SWITCH_SYSTEM = @C_SWITCH_SYSTEM@
|
||||||
C_SWITCH_X_SITE = @C_SWITCH_X_SITE@
|
C_SWITCH_X_SITE = @C_SWITCH_X_SITE@
|
||||||
|
D8 = @D8@
|
||||||
DBUS_CFLAGS = @DBUS_CFLAGS@
|
DBUS_CFLAGS = @DBUS_CFLAGS@
|
||||||
DBUS_LIBS = @DBUS_LIBS@
|
DBUS_LIBS = @DBUS_LIBS@
|
||||||
DBUS_OBJ = @DBUS_OBJ@
|
DBUS_OBJ = @DBUS_OBJ@
|
||||||
|
|
@ -278,8 +288,10 @@ GL_COND_OBJ_FSTATAT_CONDITION = @GL_COND_OBJ_FSTATAT_CONDITION@
|
||||||
GL_COND_OBJ_FSUSAGE_CONDITION = @GL_COND_OBJ_FSUSAGE_CONDITION@
|
GL_COND_OBJ_FSUSAGE_CONDITION = @GL_COND_OBJ_FSUSAGE_CONDITION@
|
||||||
GL_COND_OBJ_FSYNC_CONDITION = @GL_COND_OBJ_FSYNC_CONDITION@
|
GL_COND_OBJ_FSYNC_CONDITION = @GL_COND_OBJ_FSYNC_CONDITION@
|
||||||
GL_COND_OBJ_FUTIMENS_CONDITION = @GL_COND_OBJ_FUTIMENS_CONDITION@
|
GL_COND_OBJ_FUTIMENS_CONDITION = @GL_COND_OBJ_FUTIMENS_CONDITION@
|
||||||
|
GL_COND_OBJ_GETDELIM_CONDITION = @GL_COND_OBJ_GETDELIM_CONDITION@
|
||||||
GL_COND_OBJ_GETDTABLESIZE_CONDITION = @GL_COND_OBJ_GETDTABLESIZE_CONDITION@
|
GL_COND_OBJ_GETDTABLESIZE_CONDITION = @GL_COND_OBJ_GETDTABLESIZE_CONDITION@
|
||||||
GL_COND_OBJ_GETGROUPS_CONDITION = @GL_COND_OBJ_GETGROUPS_CONDITION@
|
GL_COND_OBJ_GETGROUPS_CONDITION = @GL_COND_OBJ_GETGROUPS_CONDITION@
|
||||||
|
GL_COND_OBJ_GETLINE_CONDITION = @GL_COND_OBJ_GETLINE_CONDITION@
|
||||||
GL_COND_OBJ_GETLOADAVG_CONDITION = @GL_COND_OBJ_GETLOADAVG_CONDITION@
|
GL_COND_OBJ_GETLOADAVG_CONDITION = @GL_COND_OBJ_GETLOADAVG_CONDITION@
|
||||||
GL_COND_OBJ_GETOPT_CONDITION = @GL_COND_OBJ_GETOPT_CONDITION@
|
GL_COND_OBJ_GETOPT_CONDITION = @GL_COND_OBJ_GETOPT_CONDITION@
|
||||||
GL_COND_OBJ_GETRANDOM_CONDITION = @GL_COND_OBJ_GETRANDOM_CONDITION@
|
GL_COND_OBJ_GETRANDOM_CONDITION = @GL_COND_OBJ_GETRANDOM_CONDITION@
|
||||||
|
|
@ -883,6 +895,8 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||||
INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@
|
INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@
|
||||||
INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@
|
INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@
|
||||||
|
JARSIGNER = @JARSIGNER@
|
||||||
|
JAVAC = @JAVAC@
|
||||||
JSON_CFLAGS = @JSON_CFLAGS@
|
JSON_CFLAGS = @JSON_CFLAGS@
|
||||||
JSON_LIBS = @JSON_LIBS@
|
JSON_LIBS = @JSON_LIBS@
|
||||||
JSON_OBJ = @JSON_OBJ@
|
JSON_OBJ = @JSON_OBJ@
|
||||||
|
|
@ -1211,6 +1225,7 @@ REPLACE_WCTOMB = @REPLACE_WCTOMB@
|
||||||
REPLACE_WRITE = @REPLACE_WRITE@
|
REPLACE_WRITE = @REPLACE_WRITE@
|
||||||
RSVG_CFLAGS = @RSVG_CFLAGS@
|
RSVG_CFLAGS = @RSVG_CFLAGS@
|
||||||
RSVG_LIBS = @RSVG_LIBS@
|
RSVG_LIBS = @RSVG_LIBS@
|
||||||
|
SDK_BULD_TOOLS = @SDK_BULD_TOOLS@
|
||||||
SEPCHAR = @SEPCHAR@
|
SEPCHAR = @SEPCHAR@
|
||||||
SETFATTR = @SETFATTR@
|
SETFATTR = @SETFATTR@
|
||||||
SETTINGS_CFLAGS = @SETTINGS_CFLAGS@
|
SETTINGS_CFLAGS = @SETTINGS_CFLAGS@
|
||||||
|
|
@ -1268,6 +1283,7 @@ XARGS_LIMIT = @XARGS_LIMIT@
|
||||||
XCB_LIBS = @XCB_LIBS@
|
XCB_LIBS = @XCB_LIBS@
|
||||||
XCOMPOSITE_CFLAGS = @XCOMPOSITE_CFLAGS@
|
XCOMPOSITE_CFLAGS = @XCOMPOSITE_CFLAGS@
|
||||||
XCOMPOSITE_LIBS = @XCOMPOSITE_LIBS@
|
XCOMPOSITE_LIBS = @XCOMPOSITE_LIBS@
|
||||||
|
XCONFIGURE = @XCONFIGURE@
|
||||||
XCRUN = @XCRUN@
|
XCRUN = @XCRUN@
|
||||||
XDBE_CFLAGS = @XDBE_CFLAGS@
|
XDBE_CFLAGS = @XDBE_CFLAGS@
|
||||||
XDBE_LIBS = @XDBE_LIBS@
|
XDBE_LIBS = @XDBE_LIBS@
|
||||||
|
|
@ -1292,6 +1308,7 @@ XSYNC_CFLAGS = @XSYNC_CFLAGS@
|
||||||
XSYNC_LIBS = @XSYNC_LIBS@
|
XSYNC_LIBS = @XSYNC_LIBS@
|
||||||
XWIDGETS_OBJ = @XWIDGETS_OBJ@
|
XWIDGETS_OBJ = @XWIDGETS_OBJ@
|
||||||
X_TOOLKIT_TYPE = @X_TOOLKIT_TYPE@
|
X_TOOLKIT_TYPE = @X_TOOLKIT_TYPE@
|
||||||
|
ZIPALIGN = @ZIPALIGN@
|
||||||
ac_ct_CC = @ac_ct_CC@
|
ac_ct_CC = @ac_ct_CC@
|
||||||
ac_ct_CXX = @ac_ct_CXX@
|
ac_ct_CXX = @ac_ct_CXX@
|
||||||
ac_ct_OBJC = @ac_ct_OBJC@
|
ac_ct_OBJC = @ac_ct_OBJC@
|
||||||
|
|
@ -1337,6 +1354,7 @@ gl_GNULIB_ENABLED_e80bf6f757095d2e5fc94dafb8f8fc8b_CONDITION = @gl_GNULIB_ENABLE
|
||||||
gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866_CONDITION = @gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866_CONDITION@
|
gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866_CONDITION = @gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866_CONDITION@
|
||||||
gl_GNULIB_ENABLED_euidaccess_CONDITION = @gl_GNULIB_ENABLED_euidaccess_CONDITION@
|
gl_GNULIB_ENABLED_euidaccess_CONDITION = @gl_GNULIB_ENABLED_euidaccess_CONDITION@
|
||||||
gl_GNULIB_ENABLED_fd38c7e463b54744b77b98aeafb4fa7c_CONDITION = @gl_GNULIB_ENABLED_fd38c7e463b54744b77b98aeafb4fa7c_CONDITION@
|
gl_GNULIB_ENABLED_fd38c7e463b54744b77b98aeafb4fa7c_CONDITION = @gl_GNULIB_ENABLED_fd38c7e463b54744b77b98aeafb4fa7c_CONDITION@
|
||||||
|
gl_GNULIB_ENABLED_getdelim_CONDITION = @gl_GNULIB_ENABLED_getdelim_CONDITION@
|
||||||
gl_GNULIB_ENABLED_getdtablesize_CONDITION = @gl_GNULIB_ENABLED_getdtablesize_CONDITION@
|
gl_GNULIB_ENABLED_getdtablesize_CONDITION = @gl_GNULIB_ENABLED_getdtablesize_CONDITION@
|
||||||
gl_GNULIB_ENABLED_getgroups_CONDITION = @gl_GNULIB_ENABLED_getgroups_CONDITION@
|
gl_GNULIB_ENABLED_getgroups_CONDITION = @gl_GNULIB_ENABLED_getgroups_CONDITION@
|
||||||
gl_GNULIB_ENABLED_lchmod_CONDITION = @gl_GNULIB_ENABLED_lchmod_CONDITION@
|
gl_GNULIB_ENABLED_lchmod_CONDITION = @gl_GNULIB_ENABLED_lchmod_CONDITION@
|
||||||
|
|
@ -2093,6 +2111,18 @@ gl_V_at = $(AM_V_GEN)
|
||||||
endif
|
endif
|
||||||
## end gnulib module gen-header
|
## end gnulib module gen-header
|
||||||
|
|
||||||
|
## begin gnulib module getdelim
|
||||||
|
ifeq (,$(OMIT_GNULIB_MODULE_getdelim))
|
||||||
|
|
||||||
|
ifneq (,$(gl_GNULIB_ENABLED_getdelim_CONDITION))
|
||||||
|
ifneq (,$(GL_COND_OBJ_GETDELIM_CONDITION))
|
||||||
|
libgnu_a_SOURCES += getdelim.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
## end gnulib module getdelim
|
||||||
|
|
||||||
## begin gnulib module getdtablesize
|
## begin gnulib module getdtablesize
|
||||||
ifeq (,$(OMIT_GNULIB_MODULE_getdtablesize))
|
ifeq (,$(OMIT_GNULIB_MODULE_getdtablesize))
|
||||||
|
|
||||||
|
|
@ -2117,6 +2147,16 @@ endif
|
||||||
endif
|
endif
|
||||||
## end gnulib module getgroups
|
## end gnulib module getgroups
|
||||||
|
|
||||||
|
## begin gnulib module getline
|
||||||
|
ifeq (,$(OMIT_GNULIB_MODULE_getline))
|
||||||
|
|
||||||
|
ifneq (,$(GL_COND_OBJ_GETLINE_CONDITION))
|
||||||
|
libgnu_a_SOURCES += getline.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
## end gnulib module getline
|
||||||
|
|
||||||
## begin gnulib module getloadavg
|
## begin gnulib module getloadavg
|
||||||
ifeq (,$(OMIT_GNULIB_MODULE_getloadavg))
|
ifeq (,$(OMIT_GNULIB_MODULE_getloadavg))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,117 +17,18 @@
|
||||||
|
|
||||||
/* Written by Paul Eggert and Bruno Haible. */
|
/* Written by Paul Eggert and Bruno Haible. */
|
||||||
|
|
||||||
|
/* Define two obsolescent C11 macros, assuming alignas and alignof are
|
||||||
|
either keywords or alignasof-defined macros. */
|
||||||
|
|
||||||
#ifndef _GL_STDALIGN_H
|
#ifndef _GL_STDALIGN_H
|
||||||
#define _GL_STDALIGN_H
|
#define _GL_STDALIGN_H
|
||||||
|
|
||||||
/* ISO C11 <stdalign.h> for platforms that lack it.
|
|
||||||
|
|
||||||
References:
|
|
||||||
ISO C11 (latest free draft
|
|
||||||
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf>)
|
|
||||||
sections 6.5.3.4, 6.7.5, 7.15.
|
|
||||||
C++11 (latest free draft
|
|
||||||
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf>)
|
|
||||||
section 18.10. */
|
|
||||||
|
|
||||||
/* alignof (TYPE), also known as _Alignof (TYPE), yields the alignment
|
|
||||||
requirement of a structure member (i.e., slot or field) that is of
|
|
||||||
type TYPE, as an integer constant expression.
|
|
||||||
|
|
||||||
This differs from GCC's and clang's __alignof__ operator, which can
|
|
||||||
yield a better-performing alignment for an object of that type. For
|
|
||||||
example, on x86 with GCC and on Linux/x86 with clang,
|
|
||||||
__alignof__ (double) and __alignof__ (long long) are 8, whereas
|
|
||||||
alignof (double) and alignof (long long) are 4 unless the option
|
|
||||||
'-malign-double' is used.
|
|
||||||
|
|
||||||
The result cannot be used as a value for an 'enum' constant, if you
|
|
||||||
want to be portable to HP-UX 10.20 cc and AIX 3.2.5 xlc. */
|
|
||||||
|
|
||||||
/* FreeBSD 9.1 <sys/cdefs.h>, included by <stddef.h> and lots of other
|
|
||||||
standard headers, defines conflicting implementations of _Alignas
|
|
||||||
and _Alignof that are no better than ours; override them. */
|
|
||||||
#undef _Alignas
|
|
||||||
#undef _Alignof
|
|
||||||
|
|
||||||
/* GCC releases before GCC 4.9 had a bug in _Alignof. See GCC bug 52023
|
|
||||||
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023>.
|
|
||||||
clang versions < 8.0.0 have the same bug. */
|
|
||||||
#if (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 \
|
|
||||||
|| (defined __GNUC__ && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \
|
|
||||||
&& !defined __clang__) \
|
|
||||||
|| (defined __clang__ && __clang_major__ < 8))
|
|
||||||
# ifdef __cplusplus
|
|
||||||
# if (201103 <= __cplusplus || defined _MSC_VER)
|
|
||||||
# define _Alignof(type) alignof (type)
|
|
||||||
# else
|
|
||||||
template <class __t> struct __alignof_helper { char __a; __t __b; };
|
|
||||||
# define _Alignof(type) offsetof (__alignof_helper<type>, __b)
|
|
||||||
# define _GL_STDALIGN_NEEDS_STDDEF 1
|
|
||||||
# endif
|
|
||||||
# else
|
|
||||||
# define _Alignof(type) offsetof (struct { char __a; type __b; }, __b)
|
|
||||||
# define _GL_STDALIGN_NEEDS_STDDEF 1
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
#if ! (defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER))
|
|
||||||
# define alignof _Alignof
|
|
||||||
#endif
|
|
||||||
#define __alignof_is_defined 1
|
|
||||||
|
|
||||||
/* alignas (A), also known as _Alignas (A), aligns a variable or type
|
|
||||||
to the alignment A, where A is an integer constant expression. For
|
|
||||||
example:
|
|
||||||
|
|
||||||
int alignas (8) foo;
|
|
||||||
struct s { int a; int alignas (8) bar; };
|
|
||||||
|
|
||||||
aligns the address of FOO and the offset of BAR to be multiples of 8.
|
|
||||||
|
|
||||||
A should be a power of two that is at least the type's alignment
|
|
||||||
and at most the implementation's alignment limit. This limit is
|
|
||||||
2**28 on typical GNUish hosts, and 2**13 on MSVC. To be portable
|
|
||||||
to MSVC through at least version 10.0, A should be an integer
|
|
||||||
constant, as MSVC does not support expressions such as 1 << 3.
|
|
||||||
To be portable to Sun C 5.11, do not align auto variables to
|
|
||||||
anything stricter than their default alignment.
|
|
||||||
|
|
||||||
The following C11 requirements are not supported here:
|
|
||||||
|
|
||||||
- If A is zero, alignas has no effect.
|
|
||||||
- alignas can be used multiple times; the strictest one wins.
|
|
||||||
- alignas (TYPE) is equivalent to alignas (alignof (TYPE)).
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
|
|
||||||
# if defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER)
|
|
||||||
# define _Alignas(a) alignas (a)
|
|
||||||
# elif (!defined __attribute__ \
|
|
||||||
&& ((defined __APPLE__ && defined __MACH__ \
|
|
||||||
? 4 < __GNUC__ + (1 <= __GNUC_MINOR__) \
|
|
||||||
: __GNUC__ && !defined __ibmxl__) \
|
|
||||||
|| (4 <= __clang_major__) \
|
|
||||||
|| (__ia64 && (61200 <= __HP_cc || 61200 <= __HP_aCC)) \
|
|
||||||
|| __ICC || 0x590 <= __SUNPRO_C || 0x0600 <= __xlC__))
|
|
||||||
# define _Alignas(a) __attribute__ ((__aligned__ (a)))
|
|
||||||
# elif 1300 <= _MSC_VER
|
|
||||||
# define _Alignas(a) __declspec (align (a))
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
#if ((defined _Alignas \
|
|
||||||
&& !(defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER))) \
|
|
||||||
|| (defined __STDC_VERSION__ && 201112 <= __STDC_VERSION__))
|
|
||||||
# define alignas _Alignas
|
|
||||||
#endif
|
|
||||||
#if (defined alignas \
|
#if (defined alignas \
|
||||||
|
|| (defined __STDC_VERSION__ && 202311 <= __STDC_VERSION__) \
|
||||||
|| (defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER)))
|
|| (defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER)))
|
||||||
# define __alignas_is_defined 1
|
# define __alignas_is_defined 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Include <stddef.h> if needed for offsetof. */
|
#define __alignof_is_defined 1
|
||||||
#if _GL_STDALIGN_NEEDS_STDDEF
|
|
||||||
# include <stddef.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _GL_STDALIGN_H */
|
#endif /* _GL_STDALIGN_H */
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,12 @@
|
||||||
# define _gl_flags_file_t int
|
# define _gl_flags_file_t int
|
||||||
# else
|
# else
|
||||||
# define _gl_flags_file_t short
|
# define _gl_flags_file_t short
|
||||||
|
# endif
|
||||||
|
# ifdef __LP64__
|
||||||
|
# define _gl_file_offset_t int64_t
|
||||||
|
# else
|
||||||
|
/* see https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md */
|
||||||
|
# define _gl_file_offset_t __kernel_off_t
|
||||||
# endif
|
# endif
|
||||||
/* Up to this commit from 2015-10-12
|
/* Up to this commit from 2015-10-12
|
||||||
<https://android.googlesource.com/platform/bionic.git/+/f0141dfab10a4b332769d52fa76631a64741297a>
|
<https://android.googlesource.com/platform/bionic.git/+/f0141dfab10a4b332769d52fa76631a64741297a>
|
||||||
|
|
@ -96,7 +102,7 @@
|
||||||
unsigned char _nbuf[1]; \
|
unsigned char _nbuf[1]; \
|
||||||
struct { unsigned char *_base; size_t _size; } _lb; \
|
struct { unsigned char *_base; size_t _size; } _lb; \
|
||||||
int _blksize; \
|
int _blksize; \
|
||||||
fpos_t _offset; \
|
_gl_file_offset_t _offset; \
|
||||||
/* More fields, not relevant here. */ \
|
/* More fields, not relevant here. */ \
|
||||||
} *) fp)
|
} *) fp)
|
||||||
# else
|
# else
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,12 @@ Mode-specific keymaps may want to use this as their parent keymap."
|
||||||
;; mode-line or header-line, the `mode-line' or `header-line' prefix
|
;; mode-line or header-line, the `mode-line' or `header-line' prefix
|
||||||
;; shouldn't be necessary!
|
;; shouldn't be necessary!
|
||||||
"<mode-line> <mouse-2>" #'push-button
|
"<mode-line> <mouse-2>" #'push-button
|
||||||
"<header-line> <mouse-2>" #'push-button)
|
"<header-line> <mouse-2>" #'push-button
|
||||||
|
;; `push-button' will automatically dispatch to
|
||||||
|
;; `touch-screen-track-tap'.
|
||||||
|
"<mode-line> <touchscreen-down>" #'push-button
|
||||||
|
"<header-line> <touchscreen-down>" #'push-button
|
||||||
|
"<touchscreen-down>" #'push-button)
|
||||||
|
|
||||||
(define-minor-mode button-mode
|
(define-minor-mode button-mode
|
||||||
"A minor mode for navigating to buttons with the TAB key."
|
"A minor mode for navigating to buttons with the TAB key."
|
||||||
|
|
@ -454,18 +459,22 @@ instead of starting at the next button."
|
||||||
|
|
||||||
(defun push-button (&optional pos use-mouse-action)
|
(defun push-button (&optional pos use-mouse-action)
|
||||||
"Perform the action specified by a button at location POS.
|
"Perform the action specified by a button at location POS.
|
||||||
POS may be either a buffer position or a mouse-event. If
|
POS may be either a buffer position, a mouse-event, or a
|
||||||
USE-MOUSE-ACTION is non-nil, invoke the button's `mouse-action'
|
`touchscreen-down' event. If USE-MOUSE-ACTION is non-nil, invoke
|
||||||
property instead of its `action' property; if the button has no
|
the button's `mouse-action' property instead of its `action'
|
||||||
`mouse-action', the value of `action' is used instead.
|
property; if the button has no `mouse-action', the value of
|
||||||
|
`action' is used instead.
|
||||||
|
|
||||||
|
If POS is a `touchscreen-down' event, wait for the corresponding
|
||||||
|
`touchscreen-up' event before calling `push-button'.
|
||||||
|
|
||||||
The action in both cases may be either a function to call or a
|
The action in both cases may be either a function to call or a
|
||||||
marker to display and is invoked using `button-activate' (which
|
marker to display and is invoked using `button-activate' (which
|
||||||
see).
|
see).
|
||||||
|
|
||||||
POS defaults to point, except when `push-button' is invoked
|
POS defaults to point, except when `push-button' is invoked
|
||||||
interactively as the result of a mouse-event, in which case, the
|
interactively as the result of a mouse-event or touchscreen
|
||||||
mouse event is used.
|
event, in which case, the position in the event event is used.
|
||||||
|
|
||||||
If there's no button at POS, do nothing and return nil, otherwise
|
If there's no button at POS, do nothing and return nil, otherwise
|
||||||
return t.
|
return t.
|
||||||
|
|
@ -483,7 +492,12 @@ pushing a button, use the `button-describe' command."
|
||||||
(if str-button
|
(if str-button
|
||||||
;; mode-line, header-line, or display string event.
|
;; mode-line, header-line, or display string event.
|
||||||
(button-activate str t)
|
(button-activate str t)
|
||||||
(push-button (posn-point posn) t)))))
|
(if (eq (car pos) 'touchscreen-down)
|
||||||
|
;; If touch-screen-track tap returns nil, then the
|
||||||
|
;; tap was cancelled.
|
||||||
|
(when (touch-screen-track-tap pos)
|
||||||
|
(push-button (posn-point posn) t))
|
||||||
|
(push-button (posn-point posn) t))))))
|
||||||
;; POS is just normal position
|
;; POS is just normal position
|
||||||
(let ((button (button-at (or pos (point)))))
|
(let ((button (button-at (or pos (point)))))
|
||||||
(when button
|
(when button
|
||||||
|
|
|
||||||
|
|
@ -2149,8 +2149,12 @@ frame's display)."
|
||||||
"Return non-nil if popup menus are supported on DISPLAY.
|
"Return non-nil if popup menus are supported on DISPLAY.
|
||||||
DISPLAY can be a display name, a frame, or nil (meaning the selected
|
DISPLAY can be a display name, a frame, or nil (meaning the selected
|
||||||
frame's display).
|
frame's display).
|
||||||
Support for popup menus requires that the mouse be available."
|
Support for popup menus requires that a suitable pointing device
|
||||||
(display-mouse-p display))
|
be available."
|
||||||
|
;; Android menus work fine with touch screens as well, and one must
|
||||||
|
;; be present.
|
||||||
|
(or (eq (framep-on-display display) 'android)
|
||||||
|
(display-mouse-p display)))
|
||||||
|
|
||||||
(defun display-graphic-p (&optional display)
|
(defun display-graphic-p (&optional display)
|
||||||
"Return non-nil if DISPLAY is a graphic display.
|
"Return non-nil if DISPLAY is a graphic display.
|
||||||
|
|
|
||||||
14
lisp/subr.el
14
lisp/subr.el
|
|
@ -1636,7 +1636,13 @@ nil or (STRING . POSITION)'.
|
||||||
`posn-timestamp': The time the event occurred, in milliseconds.
|
`posn-timestamp': The time the event occurred, in milliseconds.
|
||||||
|
|
||||||
For more information, see Info node `(elisp)Click Events'."
|
For more information, see Info node `(elisp)Click Events'."
|
||||||
(or (and (consp event) (nth 1 event))
|
(or (and (consp event)
|
||||||
|
;; Ignore touchscreen events. They store the posn in a
|
||||||
|
;; different format, and can have multiple posns.
|
||||||
|
(not (memq (car event) '(touchscreen-begin
|
||||||
|
touchscreen-update
|
||||||
|
touchscreen-end)))
|
||||||
|
(nth 1 event))
|
||||||
(event--posn-at-point)))
|
(event--posn-at-point)))
|
||||||
|
|
||||||
(defun event-end (event)
|
(defun event-end (event)
|
||||||
|
|
@ -1644,7 +1650,11 @@ For more information, see Info node `(elisp)Click Events'."
|
||||||
EVENT should be a click, drag, or key press event.
|
EVENT should be a click, drag, or key press event.
|
||||||
|
|
||||||
See `event-start' for a description of the value returned."
|
See `event-start' for a description of the value returned."
|
||||||
(or (and (consp event) (nth (if (consp (nth 2 event)) 2 1) event))
|
(or (and (consp event)
|
||||||
|
(not (memq (car event) '(touchscreen-begin
|
||||||
|
touchscreen-update
|
||||||
|
touchscreen-end)))
|
||||||
|
(nth (if (consp (nth 2 event)) 2 1) event))
|
||||||
(event--posn-at-point)))
|
(event--posn-at-point)))
|
||||||
|
|
||||||
(defsubst event-click-count (event)
|
(defsubst event-click-count (event)
|
||||||
|
|
|
||||||
|
|
@ -105,10 +105,10 @@ known position of the tool."
|
||||||
(setcar (nthcdr 3 touch-screen-current-tool) 'held)
|
(setcar (nthcdr 3 touch-screen-current-tool) 'held)
|
||||||
;; Go to the initial position of the touchpoint and activate the
|
;; Go to the initial position of the touchpoint and activate the
|
||||||
;; mark.
|
;; mark.
|
||||||
(with-selected-window (cadr touch-screen-current-tool)
|
(select-window (cadr touch-screen-current-tool))
|
||||||
(set-mark (posn-point (nth 4 touch-screen-current-tool)))
|
(set-mark (posn-point (nth 4 touch-screen-current-tool)))
|
||||||
(goto-char (mark))
|
(goto-char (mark))
|
||||||
(activate-mark)))))
|
(activate-mark))))
|
||||||
|
|
||||||
(defun touch-screen-handle-point-update (point)
|
(defun touch-screen-handle-point-update (point)
|
||||||
"Notice that the touch point POINT has changed position.
|
"Notice that the touch point POINT has changed position.
|
||||||
|
|
@ -132,9 +132,7 @@ happens, cancel `touch-screen-current-timer', and set the field
|
||||||
to `drag'. Then, activate the mark and start dragging.
|
to `drag'. Then, activate the mark and start dragging.
|
||||||
|
|
||||||
If the fourth element of `touch-screen-current-tool' is `drag',
|
If the fourth element of `touch-screen-current-tool' is `drag',
|
||||||
then move point to the position of POINT.
|
then move point to the position of POINT."
|
||||||
|
|
||||||
Set `touch-screen-current-tool' to nil should any error occur."
|
|
||||||
(let ((window (nth 1 touch-screen-current-tool))
|
(let ((window (nth 1 touch-screen-current-tool))
|
||||||
(what (nth 3 touch-screen-current-tool)))
|
(what (nth 3 touch-screen-current-tool)))
|
||||||
(cond ((null what)
|
(cond ((null what)
|
||||||
|
|
@ -252,19 +250,42 @@ POINT should be the point currently tracked as
|
||||||
|
|
||||||
If the fourth argument of `touch-screen-current-tool' is nil,
|
If the fourth argument of `touch-screen-current-tool' is nil,
|
||||||
move point to the position of POINT, selecting the window under
|
move point to the position of POINT, selecting the window under
|
||||||
POINT as well; if there is a button at POINT, then activate the
|
POINT as well, and deactivate the mark; if there is a button or
|
||||||
button there. Otherwise, deactivate the mark. Then, display the
|
link at POINT, call the command bound to `mouse-2' there.
|
||||||
on-screen keyboard."
|
Otherwise, call the command bound to `mouse-1'."
|
||||||
(let ((what (nth 3 touch-screen-current-tool)))
|
(let ((what (nth 3 touch-screen-current-tool)))
|
||||||
(cond ((null what)
|
(cond ((null what)
|
||||||
(when (windowp (posn-window (cdr point)))
|
(when (windowp (posn-window (cdr point)))
|
||||||
;; Select the window that was tapped.
|
;; Select the window that was tapped.
|
||||||
(select-window (posn-window (cdr point)))
|
(select-window (posn-window (cdr point)))
|
||||||
(let ((button (button-at (posn-point (cdr point)))))
|
;; Now simulate a mouse click there. If there is a link
|
||||||
(when button
|
;; or a button, use mouse-2 to push it.
|
||||||
(button-activate button t))
|
(let ((event (list (if (or (mouse-on-link-p (cdr point))
|
||||||
|
(button-at (posn-point (cdr point))))
|
||||||
|
'mouse-2
|
||||||
|
'mouse-1)
|
||||||
|
(cdr point)))
|
||||||
|
;; Look for an extra keymap to look in.
|
||||||
|
(keymap (and (posn-object (cdr point))
|
||||||
|
(stringp
|
||||||
|
(posn-object (cdr point)))
|
||||||
|
(get-text-property
|
||||||
|
0 'keymap
|
||||||
|
(posn-object (cdr point)))))
|
||||||
|
command)
|
||||||
|
(save-excursion
|
||||||
|
(when (posn-point (cdr point))
|
||||||
|
(goto-char (posn-point (cdr point))))
|
||||||
|
(if keymap
|
||||||
|
(setq keymap (cons keymap (current-active-maps t)))
|
||||||
|
(setq keymap (current-active-maps t)))
|
||||||
|
(setq command (lookup-key keymap (vector (car event)))))
|
||||||
|
(deactivate-mark)
|
||||||
|
;; This is necessary for following links.
|
||||||
(goto-char (posn-point (cdr point)))
|
(goto-char (posn-point (cdr point)))
|
||||||
(deactivate-mark)))))))
|
(when command
|
||||||
|
(call-interactively command nil
|
||||||
|
(vector event)))))))))
|
||||||
|
|
||||||
(defun touch-screen-handle-touch (event)
|
(defun touch-screen-handle-touch (event)
|
||||||
"Handle a single touch EVENT, and perform associated actions.
|
"Handle a single touch EVENT, and perform associated actions.
|
||||||
|
|
@ -317,6 +338,146 @@ touchscreen-end event."
|
||||||
(define-key global-map [touchscreen-update] #'touch-screen-handle-touch)
|
(define-key global-map [touchscreen-update] #'touch-screen-handle-touch)
|
||||||
(define-key global-map [touchscreen-end] #'touch-screen-handle-touch)
|
(define-key global-map [touchscreen-end] #'touch-screen-handle-touch)
|
||||||
|
|
||||||
|
|
||||||
|
;; Exports. These functions are intended for use externally.
|
||||||
|
|
||||||
|
(defun touch-screen-track-tap (event &optional update data)
|
||||||
|
"Track a single tap starting from EVENT.
|
||||||
|
EVENT should be a `touchscreen-begin' event.
|
||||||
|
|
||||||
|
Read touch screen events until a `touchscreen-end' event is
|
||||||
|
received with the same ID as in EVENT. If UPDATE is non-nil and
|
||||||
|
a `touchscreen-update' event is received in the mean time and
|
||||||
|
contains a touch point with the same ID as in EVENT, call UPDATE
|
||||||
|
with that event and DATA.
|
||||||
|
|
||||||
|
Return nil immediately if any other kind of event is received;
|
||||||
|
otherwise, return t once the `touchscreen-end' event arrives."
|
||||||
|
(catch 'finish
|
||||||
|
(while t
|
||||||
|
(let ((new-event (read-event)))
|
||||||
|
(cond
|
||||||
|
((eq (car-safe new-event) 'touchscreen-update)
|
||||||
|
(when (and update (assq (caadr event) (cadr new-event)))
|
||||||
|
(funcall update new-event data)))
|
||||||
|
((eq (car-safe new-event) 'touchscreen-end)
|
||||||
|
(throw 'finish
|
||||||
|
;; Now determine whether or not the `touchscreen-end'
|
||||||
|
;; event has the same ID as EVENT. If it doesn't,
|
||||||
|
;; then this is another touch, so return nil.
|
||||||
|
(eq (caadr event) (caadr new-event))))
|
||||||
|
(t (throw 'finish nil)))))))
|
||||||
|
|
||||||
|
(defun touch-screen-track-drag (event update &optional data)
|
||||||
|
"Track a single drag starting from EVENT.
|
||||||
|
EVENT should be a `touchscreen-end' event.
|
||||||
|
|
||||||
|
Read touch screen events until a `touchscreen-end' event is
|
||||||
|
received with the same ID as in EVENT. For each
|
||||||
|
`touchscreen-update' event received in the mean time containing a
|
||||||
|
touch point with the same ID as in EVENT, call UPDATE with the
|
||||||
|
touch point in event and DATA.
|
||||||
|
|
||||||
|
Return nil immediately if any other kind of event is received;
|
||||||
|
otherwise, return t once the `touchscreen-end' event arrives."
|
||||||
|
(catch 'finish
|
||||||
|
(while t
|
||||||
|
(let ((new-event (read-event)))
|
||||||
|
(cond
|
||||||
|
((eq (car-safe new-event) 'touchscreen-update)
|
||||||
|
(let ((tool (assq (caadr event) (nth 1 new-event))))
|
||||||
|
(when (and update tool)
|
||||||
|
(funcall update new-event data))))
|
||||||
|
((eq (car-safe new-event) 'touchscreen-end)
|
||||||
|
(throw 'finish
|
||||||
|
;; Now determine whether or not the `touchscreen-end'
|
||||||
|
;; event has the same ID as EVENT. If it doesn't,
|
||||||
|
;; then this is another touch, so return nil.
|
||||||
|
(eq (caadr event) (caadr new-event))))
|
||||||
|
(t (throw 'finish nil)))))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;; Modeline dragging.
|
||||||
|
|
||||||
|
(defun touch-screen-drag-mode-line-1 (event)
|
||||||
|
"Internal helper for `touch-screen-drag-mode-line'.
|
||||||
|
This is called when that function determines it need not execute
|
||||||
|
any keymaps on the mode line at that particular spot."
|
||||||
|
;; Find the window that should be dragged and the starting position.
|
||||||
|
(let* ((window (posn-window (cdadr event)))
|
||||||
|
(relative-xy (touch-screen-relative-xy
|
||||||
|
(cdadr event) window))
|
||||||
|
(last-position (cdr relative-xy)))
|
||||||
|
(when (window-resizable window 0)
|
||||||
|
(touch-screen-track-drag
|
||||||
|
event (lambda (new-event &optional _data)
|
||||||
|
;; Find the position of the touchpoint in NEW-EVENT.
|
||||||
|
(let* ((touchpoint (assq (caadr event) (cadr new-event)))
|
||||||
|
(new-relative-xy
|
||||||
|
(touch-screen-relative-xy (cdr touchpoint)
|
||||||
|
window))
|
||||||
|
(position (cdr new-relative-xy))
|
||||||
|
growth)
|
||||||
|
;; Now set the new height of the window.
|
||||||
|
;; If new-relative-y is above relative-xy, then
|
||||||
|
;; make the window that much shorter. Otherwise,
|
||||||
|
;; make it bigger.
|
||||||
|
(unless (or (zerop (setq growth (- position last-position)))
|
||||||
|
(and (> growth 0)
|
||||||
|
(< position (+ (window-pixel-top window)
|
||||||
|
(window-pixel-height window))))
|
||||||
|
(and (< growth 0)
|
||||||
|
(> position (+ (window-pixel-top window)
|
||||||
|
(window-pixel-height window)))))
|
||||||
|
(adjust-window-trailing-edge window growth nil t))
|
||||||
|
(setq last-position position)))))))
|
||||||
|
|
||||||
|
(defun touch-screen-drag-mode-line (event)
|
||||||
|
"Begin dragging the mode line in response to a touch EVENT.
|
||||||
|
If EVENT lies on top of text with a mouse command bound, run
|
||||||
|
that command instead.
|
||||||
|
|
||||||
|
Change the height of the window based on where the touch point
|
||||||
|
in EVENT moves."
|
||||||
|
(interactive "e")
|
||||||
|
;; If there is an object at EVENT, then look either a keymap bound
|
||||||
|
;; to [down-mouse-1] or a command bound to [mouse-1]. Then, if a
|
||||||
|
;; keymap was found, pop it up as a menu. Otherwise, wait for a tap
|
||||||
|
;; to complete and run the command found.
|
||||||
|
(let* ((object (posn-object (cdadr event)))
|
||||||
|
(object-keymap (and (consp object)
|
||||||
|
(stringp (car object))
|
||||||
|
(or (get-text-property (cdr object)
|
||||||
|
'keymap
|
||||||
|
(car object))
|
||||||
|
(get-text-property (cdr object)
|
||||||
|
'local-map
|
||||||
|
(car object)))))
|
||||||
|
(keymap (lookup-key object-keymap [mode-line down-mouse-1]))
|
||||||
|
(command (or (lookup-key object-keymap [mode-line mouse-1])
|
||||||
|
keymap)))
|
||||||
|
(if (or (keymapp keymap) command)
|
||||||
|
(if (keymapp keymap)
|
||||||
|
(when (touch-screen-track-tap event)
|
||||||
|
(when-let* ((command (x-popup-menu event keymap))
|
||||||
|
(tem (lookup-key keymap
|
||||||
|
(if (consp command)
|
||||||
|
(apply #'vector command)
|
||||||
|
(vector command))
|
||||||
|
t)))
|
||||||
|
(call-interactively tem)))
|
||||||
|
(when (and (commandp command)
|
||||||
|
(touch-screen-track-tap event))
|
||||||
|
(call-interactively command nil
|
||||||
|
(vector (list 'mouse-1 (cdadr event))))))
|
||||||
|
(touch-screen-drag-mode-line-1 event))))
|
||||||
|
|
||||||
|
(global-set-key [mode-line touchscreen-begin]
|
||||||
|
#'touch-screen-drag-mode-line)
|
||||||
|
(global-set-key [bottom-divider touchscreen-begin]
|
||||||
|
#'touch-screen-drag-mode-line)
|
||||||
|
|
||||||
(provide 'touch-screen)
|
(provide 'touch-screen)
|
||||||
|
|
||||||
;;; touch-screen ends here
|
;;; touch-screen ends here
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,11 @@
|
||||||
;;; Compatibility.
|
;;; Compatibility.
|
||||||
|
|
||||||
(defun widget-event-point (event)
|
(defun widget-event-point (event)
|
||||||
"Character position of the end of event if that exists, or nil."
|
"Character position of the end of event if that exists, or nil.
|
||||||
(posn-point (event-end event)))
|
EVENT can either be a mouse event or a touch screen event."
|
||||||
|
(if (eq (car-safe event) 'touchscreen-begin)
|
||||||
|
(posn-point (cdadr event))
|
||||||
|
(posn-point (event-end event))))
|
||||||
|
|
||||||
(defun widget-button-release-event-p (event)
|
(defun widget-button-release-event-p (event)
|
||||||
"Non-nil if EVENT is a mouse-button-release event object."
|
"Non-nil if EVENT is a mouse-button-release event object."
|
||||||
|
|
@ -1017,6 +1020,7 @@ button end points."
|
||||||
(define-key map [backtab] 'widget-backward)
|
(define-key map [backtab] 'widget-backward)
|
||||||
(define-key map [down-mouse-2] 'widget-button-click)
|
(define-key map [down-mouse-2] 'widget-button-click)
|
||||||
(define-key map [down-mouse-1] 'widget-button-click)
|
(define-key map [down-mouse-1] 'widget-button-click)
|
||||||
|
(define-key map [touchscreen-begin] 'widget-button-click)
|
||||||
;; The following definition needs to avoid using escape sequences that
|
;; The following definition needs to avoid using escape sequences that
|
||||||
;; might get converted to ^M when building loaddefs.el
|
;; might get converted to ^M when building loaddefs.el
|
||||||
(define-key map [(control ?m)] 'widget-button-press)
|
(define-key map [(control ?m)] 'widget-button-press)
|
||||||
|
|
@ -1072,8 +1076,18 @@ Note that such modes will need to require wid-edit.")
|
||||||
"If non-nil, `widget-button-click' moves point to a button after invoking it.
|
"If non-nil, `widget-button-click' moves point to a button after invoking it.
|
||||||
If nil, point returns to its original position after invoking a button.")
|
If nil, point returns to its original position after invoking a button.")
|
||||||
|
|
||||||
|
(defun widget-event-start (event)
|
||||||
|
"Return the start of EVENT.
|
||||||
|
If EVENT is not a touchscreen event, simply return its
|
||||||
|
`event-start'. Otherwise, it is a touchscreen event, so return
|
||||||
|
the posn of its touchpoint."
|
||||||
|
(if (eq (car event) 'touchscreen-begin)
|
||||||
|
(cdadr event)
|
||||||
|
(event-start event)))
|
||||||
|
|
||||||
(defun widget-button--check-and-call-button (event button)
|
(defun widget-button--check-and-call-button (event button)
|
||||||
"Call BUTTON if BUTTON is a widget and EVENT is correct for it.
|
"Call BUTTON if BUTTON is a widget and EVENT is correct for it.
|
||||||
|
EVENT can either be a mouse event or a touchscreen-begin event.
|
||||||
If nothing was called, return non-nil."
|
If nothing was called, return non-nil."
|
||||||
(let* ((oevent event)
|
(let* ((oevent event)
|
||||||
(mouse-1 (memq (event-basic-type event) '(mouse-1 down-mouse-1)))
|
(mouse-1 (memq (event-basic-type event) '(mouse-1 down-mouse-1)))
|
||||||
|
|
@ -1084,28 +1098,37 @@ If nothing was called, return non-nil."
|
||||||
;; in a save-excursion so that the click on the button
|
;; in a save-excursion so that the click on the button
|
||||||
;; doesn't change point.
|
;; doesn't change point.
|
||||||
(save-selected-window
|
(save-selected-window
|
||||||
(select-window (posn-window (event-start event)))
|
(select-window (posn-window (widget-event-start event)))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (posn-point (event-start event)))
|
(goto-char (posn-point (widget-event-start event)))
|
||||||
(let* ((overlay (widget-get button :button-overlay))
|
(let* ((overlay (widget-get button :button-overlay))
|
||||||
(pressed-face (or (widget-get button :pressed-face)
|
(pressed-face (or (widget-get button :pressed-face)
|
||||||
widget-button-pressed-face))
|
widget-button-pressed-face))
|
||||||
(face (overlay-get overlay 'face))
|
(face (overlay-get overlay 'face))
|
||||||
(mouse-face (overlay-get overlay 'mouse-face)))
|
(mouse-face (overlay-get overlay 'mouse-face)))
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
;; Read events, including mouse-movement
|
;; Read events, including mouse-movement events,
|
||||||
;; events, waiting for a release event. If we
|
;; waiting for a release event. If we began with a
|
||||||
;; began with a mouse-1 event and receive a
|
;; mouse-1 event and receive a movement event, that
|
||||||
;; movement event, that means the user wants
|
;; means the user wants to perform drag-selection, so
|
||||||
;; to perform drag-selection, so cancel the
|
;; cancel the button press and do the default mouse-1
|
||||||
;; button press and do the default mouse-1
|
;; action. For mouse-2, just highlight/ unhighlight
|
||||||
;; action. For mouse-2, just highlight/
|
;; the button the mouse was initially on when we move
|
||||||
;; unhighlight the button the mouse was
|
;; over it.
|
||||||
;; initially on when we move over it.
|
;;
|
||||||
|
;; If this function was called in response to a
|
||||||
|
;; touchscreen event, then wait for a corresponding
|
||||||
|
;; touchscreen-end event instead.
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(when face ; avoid changing around image
|
(when face ; avoid changing around image
|
||||||
(overlay-put overlay 'face pressed-face)
|
(overlay-put overlay 'face pressed-face)
|
||||||
(overlay-put overlay 'mouse-face pressed-face))
|
(overlay-put overlay 'mouse-face pressed-face))
|
||||||
|
(if (eq (car event) 'touchscreen-begin)
|
||||||
|
;; This a touchscreen event and must be handled
|
||||||
|
;; specially through `touch-screen-track-tap'.
|
||||||
|
(progn
|
||||||
|
(unless (touch-screen-track-tap event)
|
||||||
|
(throw 'button-press-cancelled t)))
|
||||||
(unless (widget-apply button :mouse-down-action event)
|
(unless (widget-apply button :mouse-down-action event)
|
||||||
(let ((track-mouse t))
|
(let ((track-mouse t))
|
||||||
(while (not (widget-button-release-event-p event))
|
(while (not (widget-button-release-event-p event))
|
||||||
|
|
@ -1126,7 +1149,7 @@ If nothing was called, return non-nil."
|
||||||
(overlay-put overlay 'face pressed-face)
|
(overlay-put overlay 'face pressed-face)
|
||||||
(overlay-put overlay 'mouse-face pressed-face))
|
(overlay-put overlay 'mouse-face pressed-face))
|
||||||
(overlay-put overlay 'face face)
|
(overlay-put overlay 'face face)
|
||||||
(overlay-put overlay 'mouse-face mouse-face))))))
|
(overlay-put overlay 'mouse-face mouse-face)))))))
|
||||||
|
|
||||||
;; When mouse is released over the button, run
|
;; When mouse is released over the button, run
|
||||||
;; its action function.
|
;; its action function.
|
||||||
|
|
@ -1148,32 +1171,35 @@ If nothing was called, return non-nil."
|
||||||
(if (widget-event-point event)
|
(if (widget-event-point event)
|
||||||
(let* ((mouse-1 (memq (event-basic-type event) '(mouse-1 down-mouse-1)))
|
(let* ((mouse-1 (memq (event-basic-type event) '(mouse-1 down-mouse-1)))
|
||||||
(pos (widget-event-point event))
|
(pos (widget-event-point event))
|
||||||
(start (event-start event))
|
(start (widget-event-start event))
|
||||||
(button (get-char-property
|
(button (get-char-property
|
||||||
pos 'button (and (windowp (posn-window start))
|
pos 'button (and (windowp (posn-window start))
|
||||||
(window-buffer (posn-window start))))))
|
(window-buffer (posn-window start))))))
|
||||||
|
|
||||||
(when (or (null button)
|
(when (or (null button)
|
||||||
(widget-button--check-and-call-button event button))
|
(widget-button--check-and-call-button event button))
|
||||||
(let ((up t)
|
(let ((up (not (eq (car event) 'touchscreen-begin)))
|
||||||
command)
|
command)
|
||||||
;; Mouse click not on a widget button. Find the global
|
;; Mouse click not on a widget button. Find the global
|
||||||
;; command to run, and check whether it is bound to an
|
;; command to run, and check whether it is bound to an
|
||||||
;; up event.
|
;; up event.
|
||||||
(if mouse-1
|
(cond
|
||||||
(cond ((setq command ;down event
|
((eq (car event) 'touchscreen-begin)
|
||||||
|
(setq command (lookup-key widget-global-map
|
||||||
|
[touchscreen-begin])))
|
||||||
|
(mouse-1 (cond ((setq command ;down event
|
||||||
(lookup-key widget-global-map [down-mouse-1]))
|
(lookup-key widget-global-map [down-mouse-1]))
|
||||||
(setq up nil))
|
(setq up nil))
|
||||||
((setq command ;up event
|
((setq command ;up event
|
||||||
(lookup-key widget-global-map [mouse-1]))))
|
(lookup-key widget-global-map [mouse-1])))))
|
||||||
(cond ((setq command ;down event
|
(t (cond ((setq command ;down event
|
||||||
(lookup-key widget-global-map [down-mouse-2]))
|
(lookup-key widget-global-map [down-mouse-2]))
|
||||||
(setq up nil))
|
(setq up nil))
|
||||||
((setq command ;up event
|
((setq command ;up event
|
||||||
(lookup-key widget-global-map [mouse-2])))))
|
(lookup-key widget-global-map [mouse-2]))))))
|
||||||
(when up
|
(when up
|
||||||
;; Don't execute up events twice.
|
;; Don't execute up events twice.
|
||||||
(while (not (widget-button-release-event-p event))
|
(while (not (and (widget-button-release-event-p event)))
|
||||||
(setq event (read--potential-mouse-event))))
|
(setq event (read--potential-mouse-event))))
|
||||||
(when command
|
(when command
|
||||||
(call-interactively command)))))
|
(call-interactively command)))))
|
||||||
|
|
|
||||||
111
m4/getdelim.m4
Normal file
111
m4/getdelim.m4
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
# getdelim.m4 serial 16
|
||||||
|
|
||||||
|
dnl Copyright (C) 2005-2007, 2009-2023 Free Software Foundation, Inc.
|
||||||
|
dnl
|
||||||
|
dnl This file is free software; the Free Software Foundation
|
||||||
|
dnl gives unlimited permission to copy and/or distribute it,
|
||||||
|
dnl with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
AC_PREREQ([2.59])
|
||||||
|
|
||||||
|
AC_DEFUN([gl_FUNC_GETDELIM],
|
||||||
|
[
|
||||||
|
AC_REQUIRE([gl_STDIO_H_DEFAULTS])
|
||||||
|
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||||
|
|
||||||
|
dnl Persuade glibc <stdio.h> to declare getdelim().
|
||||||
|
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
|
||||||
|
|
||||||
|
AC_CHECK_DECLS_ONCE([getdelim])
|
||||||
|
|
||||||
|
AC_CHECK_FUNCS_ONCE([getdelim])
|
||||||
|
if test $ac_cv_func_getdelim = yes; then
|
||||||
|
HAVE_GETDELIM=1
|
||||||
|
dnl Found it in some library. Verify that it works.
|
||||||
|
AC_CACHE_CHECK([for working getdelim function],
|
||||||
|
[gl_cv_func_working_getdelim],
|
||||||
|
[case "$host_os" in
|
||||||
|
darwin*)
|
||||||
|
dnl On macOS 10.13, valgrind detected an out-of-bounds read during
|
||||||
|
dnl the GNU sed test suite:
|
||||||
|
dnl Invalid read of size 16
|
||||||
|
dnl at 0x100EE6A05: _platform_memchr$VARIANT$Base (in /usr/lib/system/libsystem_platform.dylib)
|
||||||
|
dnl by 0x100B7B0BD: getdelim (in /usr/lib/system/libsystem_c.dylib)
|
||||||
|
dnl by 0x10000B0BE: ck_getdelim (utils.c:254)
|
||||||
|
gl_cv_func_working_getdelim=no ;;
|
||||||
|
*)
|
||||||
|
echo fooNbarN | tr -d '\012' | tr N '\012' > conftest.data
|
||||||
|
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <string.h>
|
||||||
|
int main ()
|
||||||
|
{
|
||||||
|
FILE *in = fopen ("./conftest.data", "r");
|
||||||
|
if (!in)
|
||||||
|
return 1;
|
||||||
|
{
|
||||||
|
/* Test result for a NULL buffer and a zero size.
|
||||||
|
Based on a test program from Karl Heuer. */
|
||||||
|
char *line = NULL;
|
||||||
|
size_t siz = 0;
|
||||||
|
int len = getdelim (&line, &siz, '\n', in);
|
||||||
|
if (!(len == 4 && line && strcmp (line, "foo\n") == 0))
|
||||||
|
{ free (line); fclose (in); return 2; }
|
||||||
|
free (line);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
/* Test result for a NULL buffer and a non-zero size.
|
||||||
|
This crashes on FreeBSD 8.0. */
|
||||||
|
char *line = NULL;
|
||||||
|
size_t siz = (size_t)(~0) / 4;
|
||||||
|
if (getdelim (&line, &siz, '\n', in) == -1)
|
||||||
|
{ fclose (in); return 3; }
|
||||||
|
free (line);
|
||||||
|
}
|
||||||
|
fclose (in);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
]])],
|
||||||
|
[gl_cv_func_working_getdelim=yes],
|
||||||
|
[gl_cv_func_working_getdelim=no],
|
||||||
|
[dnl We're cross compiling.
|
||||||
|
dnl Guess it works on glibc2 systems and musl systems.
|
||||||
|
AC_EGREP_CPP([Lucky GNU user],
|
||||||
|
[
|
||||||
|
#include <features.h>
|
||||||
|
#ifdef __GNU_LIBRARY__
|
||||||
|
#if (__GLIBC__ >= 2) && !defined __UCLIBC__
|
||||||
|
Lucky GNU user
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
],
|
||||||
|
[gl_cv_func_working_getdelim="guessing yes"],
|
||||||
|
[case "$host_os" in
|
||||||
|
*-musl*) gl_cv_func_working_getdelim="guessing yes" ;;
|
||||||
|
*) gl_cv_func_working_getdelim="$gl_cross_guess_normal" ;;
|
||||||
|
esac
|
||||||
|
])
|
||||||
|
])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
])
|
||||||
|
case "$gl_cv_func_working_getdelim" in
|
||||||
|
*yes) ;;
|
||||||
|
*) REPLACE_GETDELIM=1 ;;
|
||||||
|
esac
|
||||||
|
else
|
||||||
|
HAVE_GETDELIM=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $ac_cv_have_decl_getdelim = no; then
|
||||||
|
HAVE_DECL_GETDELIM=0
|
||||||
|
fi
|
||||||
|
])
|
||||||
|
|
||||||
|
# Prerequisites of lib/getdelim.c.
|
||||||
|
AC_DEFUN([gl_PREREQ_GETDELIM],
|
||||||
|
[
|
||||||
|
AC_CHECK_FUNCS([flockfile funlockfile])
|
||||||
|
AC_CHECK_DECLS([getc_unlocked])
|
||||||
|
])
|
||||||
109
m4/getline.m4
Normal file
109
m4/getline.m4
Normal file
|
|
@ -0,0 +1,109 @@
|
||||||
|
# getline.m4 serial 30
|
||||||
|
|
||||||
|
dnl Copyright (C) 1998-2003, 2005-2007, 2009-2023 Free Software Foundation,
|
||||||
|
dnl Inc.
|
||||||
|
dnl
|
||||||
|
dnl This file is free software; the Free Software Foundation
|
||||||
|
dnl gives unlimited permission to copy and/or distribute it,
|
||||||
|
dnl with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
AC_PREREQ([2.59])
|
||||||
|
|
||||||
|
dnl See if there's a working, system-supplied version of the getline function.
|
||||||
|
dnl We can't just do AC_REPLACE_FUNCS([getline]) because some systems
|
||||||
|
dnl have a function by that name in -linet that doesn't have anything
|
||||||
|
dnl to do with the function we need.
|
||||||
|
AC_DEFUN([gl_FUNC_GETLINE],
|
||||||
|
[
|
||||||
|
AC_REQUIRE([gl_STDIO_H_DEFAULTS])
|
||||||
|
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
|
||||||
|
|
||||||
|
dnl Persuade glibc <stdio.h> to declare getline().
|
||||||
|
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
|
||||||
|
|
||||||
|
AC_CHECK_DECLS_ONCE([getline])
|
||||||
|
|
||||||
|
gl_getline_needs_run_time_check=no
|
||||||
|
AC_CHECK_FUNC([getline],
|
||||||
|
[dnl Found it in some library. Verify that it works.
|
||||||
|
gl_getline_needs_run_time_check=yes],
|
||||||
|
[am_cv_func_working_getline=no])
|
||||||
|
if test $gl_getline_needs_run_time_check = yes; then
|
||||||
|
AC_CACHE_CHECK([for working getline function],
|
||||||
|
[am_cv_func_working_getline],
|
||||||
|
[echo fooNbarN | tr -d '\012' | tr N '\012' > conftest.data
|
||||||
|
AC_RUN_IFELSE([AC_LANG_SOURCE([[
|
||||||
|
# include <stdio.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
# include <string.h>
|
||||||
|
int main ()
|
||||||
|
{
|
||||||
|
FILE *in = fopen ("./conftest.data", "r");
|
||||||
|
if (!in)
|
||||||
|
return 1;
|
||||||
|
{
|
||||||
|
/* Test result for a NULL buffer and a zero size.
|
||||||
|
Based on a test program from Karl Heuer. */
|
||||||
|
char *line = NULL;
|
||||||
|
size_t siz = 0;
|
||||||
|
int len = getline (&line, &siz, in);
|
||||||
|
if (!(len == 4 && line && strcmp (line, "foo\n") == 0))
|
||||||
|
{ free (line); fclose (in); return 2; }
|
||||||
|
free (line);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
/* Test result for a NULL buffer and a non-zero size.
|
||||||
|
This crashes on FreeBSD 8.0. */
|
||||||
|
char *line = NULL;
|
||||||
|
size_t siz = (size_t)(~0) / 4;
|
||||||
|
if (getline (&line, &siz, in) == -1)
|
||||||
|
{ fclose (in); return 3; }
|
||||||
|
free (line);
|
||||||
|
}
|
||||||
|
fclose (in);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
]])],
|
||||||
|
[am_cv_func_working_getline=yes],
|
||||||
|
[am_cv_func_working_getline=no],
|
||||||
|
[dnl We're cross compiling.
|
||||||
|
dnl Guess it works on glibc2 systems and musl systems.
|
||||||
|
AC_EGREP_CPP([Lucky GNU user],
|
||||||
|
[
|
||||||
|
#include <features.h>
|
||||||
|
#ifdef __GNU_LIBRARY__
|
||||||
|
#if (__GLIBC__ >= 2) && !defined __UCLIBC__
|
||||||
|
Lucky GNU user
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
],
|
||||||
|
[am_cv_func_working_getline="guessing yes"],
|
||||||
|
[case "$host_os" in
|
||||||
|
*-musl*) am_cv_func_working_getline="guessing yes" ;;
|
||||||
|
*) am_cv_func_working_getline="$gl_cross_guess_normal" ;;
|
||||||
|
esac
|
||||||
|
])
|
||||||
|
])
|
||||||
|
])
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test $ac_cv_have_decl_getline = no; then
|
||||||
|
HAVE_DECL_GETLINE=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$am_cv_func_working_getline" in
|
||||||
|
*yes) ;;
|
||||||
|
*)
|
||||||
|
dnl Set REPLACE_GETLINE always: Even if we have not found the broken
|
||||||
|
dnl getline function among $LIBS, it may exist in libinet and the
|
||||||
|
dnl executable may be linked with -linet.
|
||||||
|
REPLACE_GETLINE=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
])
|
||||||
|
|
||||||
|
# Prerequisites of lib/getline.c.
|
||||||
|
AC_DEFUN([gl_PREREQ_GETLINE],
|
||||||
|
[
|
||||||
|
:
|
||||||
|
])
|
||||||
|
|
@ -44,6 +44,7 @@ AC_DEFUN([gl_EARLY],
|
||||||
|
|
||||||
# Code from module absolute-header:
|
# Code from module absolute-header:
|
||||||
# Code from module acl-permissions:
|
# Code from module acl-permissions:
|
||||||
|
# Code from module alignasof:
|
||||||
# Code from module alloca-opt:
|
# Code from module alloca-opt:
|
||||||
# Code from module allocator:
|
# Code from module allocator:
|
||||||
# Code from module assert-h:
|
# Code from module assert-h:
|
||||||
|
|
@ -103,8 +104,10 @@ AC_DEFUN([gl_EARLY],
|
||||||
# Code from module fsync:
|
# Code from module fsync:
|
||||||
# Code from module futimens:
|
# Code from module futimens:
|
||||||
# Code from module gen-header:
|
# Code from module gen-header:
|
||||||
|
# Code from module getdelim:
|
||||||
# Code from module getdtablesize:
|
# Code from module getdtablesize:
|
||||||
# Code from module getgroups:
|
# Code from module getgroups:
|
||||||
|
# Code from module getline:
|
||||||
# Code from module getloadavg:
|
# Code from module getloadavg:
|
||||||
# Code from module getopt-gnu:
|
# Code from module getopt-gnu:
|
||||||
# Code from module getopt-posix:
|
# Code from module getopt-posix:
|
||||||
|
|
@ -231,6 +234,7 @@ AC_DEFUN([gl_INIT],
|
||||||
gl_source_base='lib'
|
gl_source_base='lib'
|
||||||
gl_source_base_prefix=
|
gl_source_base_prefix=
|
||||||
gl_FUNC_ACL
|
gl_FUNC_ACL
|
||||||
|
gl_ALIGNASOF
|
||||||
gl_FUNC_ALLOCA
|
gl_FUNC_ALLOCA
|
||||||
gl_CONDITIONAL_HEADER([alloca.h])
|
gl_CONDITIONAL_HEADER([alloca.h])
|
||||||
AC_PROG_MKDIR_P
|
AC_PROG_MKDIR_P
|
||||||
|
|
@ -342,6 +346,12 @@ AC_DEFUN([gl_INIT],
|
||||||
gl_CONDITIONAL([GL_COND_OBJ_FUTIMENS],
|
gl_CONDITIONAL([GL_COND_OBJ_FUTIMENS],
|
||||||
[test $HAVE_FUTIMENS = 0 || test $REPLACE_FUTIMENS = 1])
|
[test $HAVE_FUTIMENS = 0 || test $REPLACE_FUTIMENS = 1])
|
||||||
gl_SYS_STAT_MODULE_INDICATOR([futimens])
|
gl_SYS_STAT_MODULE_INDICATOR([futimens])
|
||||||
|
gl_FUNC_GETLINE
|
||||||
|
gl_CONDITIONAL([GL_COND_OBJ_GETLINE], [test $REPLACE_GETLINE = 1])
|
||||||
|
AM_COND_IF([GL_COND_OBJ_GETLINE], [
|
||||||
|
gl_PREREQ_GETLINE
|
||||||
|
])
|
||||||
|
gl_STDIO_MODULE_INDICATOR([getline])
|
||||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||||
gl_GETLOADAVG
|
gl_GETLOADAVG
|
||||||
gl_CONDITIONAL([GL_COND_OBJ_GETLOADAVG], [test $HAVE_GETLOADAVG = 0])
|
gl_CONDITIONAL([GL_COND_OBJ_GETLOADAVG], [test $HAVE_GETLOADAVG = 0])
|
||||||
|
|
@ -637,6 +647,7 @@ AC_DEFUN([gl_INIT],
|
||||||
gl_gnulib_enabled_dirfd=false
|
gl_gnulib_enabled_dirfd=false
|
||||||
gl_gnulib_enabled_925677f0343de64b89a9f0c790b4104c=false
|
gl_gnulib_enabled_925677f0343de64b89a9f0c790b4104c=false
|
||||||
gl_gnulib_enabled_euidaccess=false
|
gl_gnulib_enabled_euidaccess=false
|
||||||
|
gl_gnulib_enabled_getdelim=false
|
||||||
gl_gnulib_enabled_getdtablesize=false
|
gl_gnulib_enabled_getdtablesize=false
|
||||||
gl_gnulib_enabled_getgroups=false
|
gl_gnulib_enabled_getgroups=false
|
||||||
gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false
|
gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36=false
|
||||||
|
|
@ -708,6 +719,19 @@ AC_DEFUN([gl_INIT],
|
||||||
func_gl_gnulib_m4code_6099e9737f757db36c47fa9d9f02e88c
|
func_gl_gnulib_m4code_6099e9737f757db36c47fa9d9f02e88c
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
func_gl_gnulib_m4code_getdelim ()
|
||||||
|
{
|
||||||
|
if ! $gl_gnulib_enabled_getdelim; then
|
||||||
|
gl_FUNC_GETDELIM
|
||||||
|
gl_CONDITIONAL([GL_COND_OBJ_GETDELIM],
|
||||||
|
[test $HAVE_GETDELIM = 0 || test $REPLACE_GETDELIM = 1])
|
||||||
|
AM_COND_IF([GL_COND_OBJ_GETDELIM], [
|
||||||
|
gl_PREREQ_GETDELIM
|
||||||
|
])
|
||||||
|
gl_STDIO_MODULE_INDICATOR([getdelim])
|
||||||
|
gl_gnulib_enabled_getdelim=true
|
||||||
|
fi
|
||||||
|
}
|
||||||
func_gl_gnulib_m4code_getdtablesize ()
|
func_gl_gnulib_m4code_getdtablesize ()
|
||||||
{
|
{
|
||||||
if ! $gl_gnulib_enabled_getdtablesize; then
|
if ! $gl_gnulib_enabled_getdtablesize; then
|
||||||
|
|
@ -973,6 +997,9 @@ AC_DEFUN([gl_INIT],
|
||||||
if test $HAVE_FUTIMENS = 0 || test $REPLACE_FUTIMENS = 1; then
|
if test $HAVE_FUTIMENS = 0 || test $REPLACE_FUTIMENS = 1; then
|
||||||
func_gl_gnulib_m4code_utimens
|
func_gl_gnulib_m4code_utimens
|
||||||
fi
|
fi
|
||||||
|
if test $REPLACE_GETLINE = 1; then
|
||||||
|
func_gl_gnulib_m4code_getdelim
|
||||||
|
fi
|
||||||
if case $host_os in mingw*) false;; *) test $HAVE_GETLOADAVG = 0;; esac; then
|
if case $host_os in mingw*) false;; *) test $HAVE_GETLOADAVG = 0;; esac; then
|
||||||
func_gl_gnulib_m4code_open
|
func_gl_gnulib_m4code_open
|
||||||
fi
|
fi
|
||||||
|
|
@ -1012,6 +1039,7 @@ AC_DEFUN([gl_INIT],
|
||||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_dirfd], [$gl_gnulib_enabled_dirfd])
|
AM_CONDITIONAL([gl_GNULIB_ENABLED_dirfd], [$gl_gnulib_enabled_dirfd])
|
||||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_925677f0343de64b89a9f0c790b4104c], [$gl_gnulib_enabled_925677f0343de64b89a9f0c790b4104c])
|
AM_CONDITIONAL([gl_GNULIB_ENABLED_925677f0343de64b89a9f0c790b4104c], [$gl_gnulib_enabled_925677f0343de64b89a9f0c790b4104c])
|
||||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], [$gl_gnulib_enabled_euidaccess])
|
AM_CONDITIONAL([gl_GNULIB_ENABLED_euidaccess], [$gl_gnulib_enabled_euidaccess])
|
||||||
|
AM_CONDITIONAL([gl_GNULIB_ENABLED_getdelim], [$gl_gnulib_enabled_getdelim])
|
||||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_getdtablesize], [$gl_gnulib_enabled_getdtablesize])
|
AM_CONDITIONAL([gl_GNULIB_ENABLED_getdtablesize], [$gl_gnulib_enabled_getdtablesize])
|
||||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups])
|
AM_CONDITIONAL([gl_GNULIB_ENABLED_getgroups], [$gl_gnulib_enabled_getgroups])
|
||||||
AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36])
|
AM_CONDITIONAL([gl_GNULIB_ENABLED_be453cec5eecf5731a274f2de7f2db36], [$gl_gnulib_enabled_be453cec5eecf5731a274f2de7f2db36])
|
||||||
|
|
@ -1278,8 +1306,10 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||||
lib/ftoastr.h
|
lib/ftoastr.h
|
||||||
lib/futimens.c
|
lib/futimens.c
|
||||||
lib/get-permissions.c
|
lib/get-permissions.c
|
||||||
|
lib/getdelim.c
|
||||||
lib/getdtablesize.c
|
lib/getdtablesize.c
|
||||||
lib/getgroups.c
|
lib/getgroups.c
|
||||||
|
lib/getline.c
|
||||||
lib/getloadavg.c
|
lib/getloadavg.c
|
||||||
lib/getopt-cdefs.in.h
|
lib/getopt-cdefs.in.h
|
||||||
lib/getopt-core.h
|
lib/getopt-core.h
|
||||||
|
|
@ -1456,8 +1486,10 @@ AC_DEFUN([gl_FILE_LIST], [
|
||||||
m4/fsusage.m4
|
m4/fsusage.m4
|
||||||
m4/fsync.m4
|
m4/fsync.m4
|
||||||
m4/futimens.m4
|
m4/futimens.m4
|
||||||
|
m4/getdelim.m4
|
||||||
m4/getdtablesize.m4
|
m4/getdtablesize.m4
|
||||||
m4/getgroups.m4
|
m4/getgroups.m4
|
||||||
|
m4/getline.m4
|
||||||
m4/getloadavg.m4
|
m4/getloadavg.m4
|
||||||
m4/getopt.m4
|
m4/getopt.m4
|
||||||
m4/getrandom.m4
|
m4/getrandom.m4
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,11 @@ dnl This file is free software; the Free Software Foundation
|
||||||
dnl gives unlimited permission to copy and/or distribute it,
|
dnl gives unlimited permission to copy and/or distribute it,
|
||||||
dnl with or without modifications, as long as this notice is preserved.
|
dnl with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
dnl Written by Paul Eggert and Bruno Haible.
|
||||||
|
|
||||||
# Prepare for substituting <stdalign.h> if it is not supported.
|
# Prepare for substituting <stdalign.h> if it is not supported.
|
||||||
|
|
||||||
AC_DEFUN([gl_STDALIGN_H],
|
AC_DEFUN([gl_ALIGNASOF],
|
||||||
[
|
[
|
||||||
AC_CACHE_CHECK([for alignas and alignof],
|
AC_CACHE_CHECK([for alignas and alignof],
|
||||||
[gl_cv_header_working_stdalign_h],
|
[gl_cv_header_working_stdalign_h],
|
||||||
|
|
@ -58,16 +60,11 @@ AC_DEFUN([gl_STDALIGN_H],
|
||||||
test "$gl_cv_header_working_stdalign_h" != no && break
|
test "$gl_cv_header_working_stdalign_h" != no && break
|
||||||
done])
|
done])
|
||||||
|
|
||||||
GL_GENERATE_STDALIGN_H=false
|
|
||||||
AS_CASE([$gl_cv_header_working_stdalign_h],
|
AS_CASE([$gl_cv_header_working_stdalign_h],
|
||||||
[no],
|
|
||||||
[GL_GENERATE_STDALIGN_H=true],
|
|
||||||
[yes*keyword*],
|
[yes*keyword*],
|
||||||
[AC_DEFINE([HAVE_C_ALIGNASOF], [1],
|
[AC_DEFINE([HAVE_C_ALIGNASOF], [1],
|
||||||
[Define to 1 if the alignas and alignof keywords work.])])
|
[Define to 1 if the alignas and alignof keywords work.])])
|
||||||
|
|
||||||
AC_CHECK_HEADERS_ONCE([stdalign.h])
|
|
||||||
|
|
||||||
dnl The "zz" puts this toward config.h's end, to avoid potential
|
dnl The "zz" puts this toward config.h's end, to avoid potential
|
||||||
dnl collisions with other definitions.
|
dnl collisions with other definitions.
|
||||||
AH_VERBATIM([zzalignas],
|
AH_VERBATIM([zzalignas],
|
||||||
|
|
@ -75,11 +72,33 @@ AC_DEFUN([gl_STDALIGN_H],
|
||||||
# if HAVE_STDALIGN_H
|
# if HAVE_STDALIGN_H
|
||||||
# include <stdalign.h>
|
# include <stdalign.h>
|
||||||
# else
|
# else
|
||||||
/* Substitute. Keep consistent with gnulib/lib/stdalign.in.h. */
|
/* ISO C23 alignas and alignof for platforms that lack it.
|
||||||
# ifndef _GL_STDALIGN_H
|
|
||||||
# define _GL_STDALIGN_H
|
References:
|
||||||
# undef _Alignas
|
ISO C23 (latest free draft
|
||||||
# undef _Alignof
|
<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf>)
|
||||||
|
sections 6.5.3.4, 6.7.5, 7.15.
|
||||||
|
C++11 (latest free draft
|
||||||
|
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf>)
|
||||||
|
section 18.10. */
|
||||||
|
|
||||||
|
/* alignof (TYPE), also known as _Alignof (TYPE), yields the alignment
|
||||||
|
requirement of a structure member (i.e., slot or field) that is of
|
||||||
|
type TYPE, as an integer constant expression.
|
||||||
|
|
||||||
|
This differs from GCC's and clang's __alignof__ operator, which can
|
||||||
|
yield a better-performing alignment for an object of that type. For
|
||||||
|
example, on x86 with GCC and on Linux/x86 with clang,
|
||||||
|
__alignof__ (double) and __alignof__ (long long) are 8, whereas
|
||||||
|
alignof (double) and alignof (long long) are 4 unless the option
|
||||||
|
'-malign-double' is used.
|
||||||
|
|
||||||
|
The result cannot be used as a value for an 'enum' constant, if you
|
||||||
|
want to be portable to HP-UX 10.20 cc and AIX 3.2.5 xlc. */
|
||||||
|
|
||||||
|
/* GCC releases before GCC 4.9 had a bug in _Alignof. See GCC bug 52023
|
||||||
|
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52023>.
|
||||||
|
clang versions < 8.0.0 have the same bug. */
|
||||||
# if (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 \
|
# if (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 \
|
||||||
|| (defined __GNUC__ && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \
|
|| (defined __GNUC__ && __GNUC__ < 4 + (__GNUC_MINOR__ < 9) \
|
||||||
&& !defined __clang__) \
|
&& !defined __clang__) \
|
||||||
|
|
@ -100,7 +119,31 @@ AC_DEFUN([gl_STDALIGN_H],
|
||||||
# if ! (defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER))
|
# if ! (defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER))
|
||||||
# define alignof _Alignof
|
# define alignof _Alignof
|
||||||
# endif
|
# endif
|
||||||
# define __alignof_is_defined 1
|
|
||||||
|
/* alignas (A), also known as _Alignas (A), aligns a variable or type
|
||||||
|
to the alignment A, where A is an integer constant expression. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
int alignas (8) foo;
|
||||||
|
struct s { int a; int alignas (8) bar; };
|
||||||
|
|
||||||
|
aligns the address of FOO and the offset of BAR to be multiples of 8.
|
||||||
|
|
||||||
|
A should be a power of two that is at least the type's alignment
|
||||||
|
and at most the implementation's alignment limit. This limit is
|
||||||
|
2**28 on typical GNUish hosts, and 2**13 on MSVC. To be portable
|
||||||
|
to MSVC through at least version 10.0, A should be an integer
|
||||||
|
constant, as MSVC does not support expressions such as 1 << 3.
|
||||||
|
To be portable to Sun C 5.11, do not align auto variables to
|
||||||
|
anything stricter than their default alignment.
|
||||||
|
|
||||||
|
The following C23 requirements are not supported here:
|
||||||
|
|
||||||
|
- If A is zero, alignas has no effect.
|
||||||
|
- alignas can be used multiple times; the strictest one wins.
|
||||||
|
- alignas (TYPE) is equivalent to alignas (alignof (TYPE)).
|
||||||
|
|
||||||
|
*/
|
||||||
# if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
|
# if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
|
||||||
# if defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER)
|
# if defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER)
|
||||||
# define _Alignas(a) alignas (a)
|
# define _Alignas(a) alignas (a)
|
||||||
|
|
@ -117,18 +160,24 @@ AC_DEFUN([gl_STDALIGN_H],
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
# if ((defined _Alignas \
|
# if ((defined _Alignas \
|
||||||
&& !(defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER))) \
|
&& !(defined __cplusplus \
|
||||||
|
&& (201103 <= __cplusplus || defined _MSC_VER))) \
|
||||||
|| (defined __STDC_VERSION__ && 201112 <= __STDC_VERSION__))
|
|| (defined __STDC_VERSION__ && 201112 <= __STDC_VERSION__))
|
||||||
# define alignas _Alignas
|
# define alignas _Alignas
|
||||||
# endif
|
# endif
|
||||||
# if (defined alignas \
|
|
||||||
|| (defined __cplusplus && (201103 <= __cplusplus || defined _MSC_VER)))
|
|
||||||
# define __alignas_is_defined 1
|
|
||||||
# endif
|
|
||||||
# if _GL_STDALIGN_NEEDS_STDDEF
|
# if _GL_STDALIGN_NEEDS_STDDEF
|
||||||
# include <stddef.h>
|
# include <stddef.h>
|
||||||
# endif
|
# endif
|
||||||
# endif /* _GL_STDALIGN_H */
|
|
||||||
# endif
|
# endif
|
||||||
#endif])
|
#endif])
|
||||||
])
|
])
|
||||||
|
|
||||||
|
AC_DEFUN([gl_STDALIGN_H],
|
||||||
|
[
|
||||||
|
AC_REQUIRE([gl_ALIGNASOF])
|
||||||
|
GL_GENERATE_STDALIGN_H=false
|
||||||
|
AS_IF([test "$gl_cv_header_working_stdalign_h" = no],
|
||||||
|
[GL_GENERATE_STDALIGN_H=true])
|
||||||
|
|
||||||
|
AC_CHECK_HEADERS_ONCE([stdalign.h])
|
||||||
|
])
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ AC_DEFUN_ONCE([gl_UNISTD_H],
|
||||||
group_member isatty lchown link linkat lseek pipe pipe2 pread pwrite
|
group_member isatty lchown link linkat lseek pipe pipe2 pread pwrite
|
||||||
readlink readlinkat rmdir sethostname sleep symlink symlinkat
|
readlink readlinkat rmdir sethostname sleep symlink symlinkat
|
||||||
truncate ttyname_r unlink unlinkat usleep])
|
truncate ttyname_r unlink unlinkat usleep])
|
||||||
|
gl_CHECK_FUNCS_ANDROID([ftruncate], [[#include <unistd.h>]])
|
||||||
|
|
||||||
AC_REQUIRE([AC_C_RESTRICT])
|
AC_REQUIRE([AC_C_RESTRICT])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ AC_DEFUN([gl_UTIMENS],
|
||||||
AC_REQUIRE([gl_FUNC_UTIMES])
|
AC_REQUIRE([gl_FUNC_UTIMES])
|
||||||
AC_REQUIRE([gl_CHECK_TYPE_STRUCT_TIMESPEC])
|
AC_REQUIRE([gl_CHECK_TYPE_STRUCT_TIMESPEC])
|
||||||
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
|
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
|
||||||
AC_CHECK_FUNCS_ONCE([futimens utimensat lutimes])
|
AC_CHECK_FUNCS_ONCE([futimens lutimes])
|
||||||
|
gl_CHECK_FUNCS_ANDROID([utimensat], [[#include <sys/stat.h>]])
|
||||||
gl_CHECK_FUNCS_ANDROID([futimes], [[#include <sys/time.h>]])
|
gl_CHECK_FUNCS_ANDROID([futimes], [[#include <sys/time.h>]])
|
||||||
gl_CHECK_FUNCS_ANDROID([futimesat], [[#include <sys/time.h>]])
|
gl_CHECK_FUNCS_ANDROID([futimesat], [[#include <sys/time.h>]])
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,9 @@ AC_DEFUN([gl_FUNC_UTIMENSAT],
|
||||||
AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
|
AC_REQUIRE([gl_SYS_STAT_H_DEFAULTS])
|
||||||
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
||||||
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
|
AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
|
||||||
AC_CHECK_FUNCS_ONCE([utimensat])
|
# This is necessary for cross-compiles, because otherwise utimensat
|
||||||
|
# will appear to work.
|
||||||
|
gl_CHECK_FUNCS_ANDROID([utimensat], [[#include <sys/stat.h>]])
|
||||||
if test $ac_cv_func_utimensat = no; then
|
if test $ac_cv_func_utimensat = no; then
|
||||||
HAVE_UTIMENSAT=0
|
HAVE_UTIMENSAT=0
|
||||||
else
|
else
|
||||||
|
|
|
||||||
42
m4/xattr.m4
42
m4/xattr.m4
|
|
@ -1,5 +1,5 @@
|
||||||
# xattr.m4 - check for Extended Attributes (Linux)
|
# xattr.m4 - check for Extended Attributes (Linux)
|
||||||
# serial 5
|
# serial 6
|
||||||
|
|
||||||
# Copyright (C) 2003-2023 Free Software Foundation, Inc.
|
# Copyright (C) 2003-2023 Free Software Foundation, Inc.
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
|
|
@ -17,23 +17,33 @@ AC_DEFUN([gl_FUNC_XATTR],
|
||||||
AC_SUBST([LIB_XATTR])
|
AC_SUBST([LIB_XATTR])
|
||||||
|
|
||||||
if test "$use_xattr" = yes; then
|
if test "$use_xattr" = yes; then
|
||||||
AC_CHECK_HEADERS([attr/error_context.h attr/libattr.h])
|
AC_CACHE_CHECK([for xattr library with ATTR_ACTION_PERMISSIONS],
|
||||||
use_xattr=no
|
[gl_cv_xattr_lib],
|
||||||
if test "$ac_cv_header_attr_libattr_h" = yes \
|
[gl_cv_xattr_lib=no
|
||||||
&& test "$ac_cv_header_attr_error_context_h" = yes; then
|
AC_LANG_CONFTEST(
|
||||||
xattr_saved_LIBS=$LIBS
|
[AC_LANG_PROGRAM(
|
||||||
AC_SEARCH_LIBS([attr_copy_file], [attr],
|
[[#include <attr/error_context.h>
|
||||||
[test "$ac_cv_search_attr_copy_file" = "none required" ||
|
#include <attr/libattr.h>
|
||||||
LIB_XATTR="$ac_cv_search_attr_copy_file"])
|
static int
|
||||||
AC_CHECK_FUNCS([attr_copy_file])
|
is_attr_permissions (const char *name, struct error_context *ctx)
|
||||||
LIBS=$xattr_saved_LIBS
|
{
|
||||||
if test "$ac_cv_func_attr_copy_file" = yes; then
|
return attr_copy_action (name, ctx) == ATTR_ACTION_PERMISSIONS;
|
||||||
use_xattr=yes
|
}
|
||||||
fi
|
]],
|
||||||
fi
|
[[return attr_copy_fd ("/", 0, "/", 0, is_attr_permissions, 0);
|
||||||
if test $use_xattr = no; then
|
]])])
|
||||||
|
AC_LINK_IFELSE([],
|
||||||
|
[gl_cv_xattr_lib='none required'],
|
||||||
|
[xattr_saved_LIBS=$LIBS
|
||||||
|
LIBS="-lattr $LIBS"
|
||||||
|
AC_LINK_IFELSE([], [gl_cv_xattr_lib=-lattr])
|
||||||
|
LIBS=$xattr_saved_LIBS])])
|
||||||
|
if test "$gl_cv_xattr_lib" = no; then
|
||||||
AC_MSG_WARN([libattr development library was not found or not usable.])
|
AC_MSG_WARN([libattr development library was not found or not usable.])
|
||||||
AC_MSG_WARN([AC_PACKAGE_NAME will be built without xattr support.])
|
AC_MSG_WARN([AC_PACKAGE_NAME will be built without xattr support.])
|
||||||
|
use_xattr=no
|
||||||
|
elif test "$gl_cv_xattr_lib" != 'none required'; then
|
||||||
|
LIB_XATTR=$gl_cv_xattr_lib
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if test "$use_xattr" = yes; then
|
if test "$use_xattr" = yes; then
|
||||||
|
|
|
||||||
34
src/alloc.c
34
src/alloc.c
|
|
@ -6172,16 +6172,44 @@ mark_pinned_objects (void)
|
||||||
mark_object (pobj->object);
|
mark_object (pobj->object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined HAVE_ANDROID && !defined (__clang__)
|
||||||
|
|
||||||
|
/* The Android gcc is broken and needs the following version of
|
||||||
|
make_lisp_symbol. Otherwise a mysterious ICE pops up. */
|
||||||
|
|
||||||
|
#define make_lisp_symbol android_make_lisp_symbol
|
||||||
|
|
||||||
|
static Lisp_Object
|
||||||
|
android_make_lisp_symbol (struct Lisp_Symbol *sym)
|
||||||
|
{
|
||||||
|
intptr_t symoffset;
|
||||||
|
Lisp_Object a;
|
||||||
|
|
||||||
|
symoffset = (intptr_t) sym;
|
||||||
|
INT_SUBTRACT_WRAPV (symoffset, (intptr_t) &lispsym,
|
||||||
|
&symoffset);
|
||||||
|
|
||||||
|
a = TAG_PTR (Lisp_Symbol, symoffset);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mark_pinned_symbols (void)
|
mark_pinned_symbols (void)
|
||||||
{
|
{
|
||||||
struct symbol_block *sblk;
|
struct symbol_block *sblk;
|
||||||
int lim = (symbol_block_pinned == symbol_block
|
int lim;
|
||||||
? symbol_block_index : SYMBOL_BLOCK_SIZE);
|
struct Lisp_Symbol *sym, *end;
|
||||||
|
|
||||||
|
if (symbol_block_pinned == symbol_block)
|
||||||
|
lim = symbol_block_index;
|
||||||
|
else
|
||||||
|
lim = SYMBOL_BLOCK_SIZE;
|
||||||
|
|
||||||
for (sblk = symbol_block_pinned; sblk; sblk = sblk->next)
|
for (sblk = symbol_block_pinned; sblk; sblk = sblk->next)
|
||||||
{
|
{
|
||||||
struct Lisp_Symbol *sym = sblk->symbols, *end = sym + lim;
|
sym = sblk->symbols, end = sym + lim;
|
||||||
for (; sym < end; ++sym)
|
for (; sym < end; ++sym)
|
||||||
if (sym->u.s.pinned)
|
if (sym->u.s.pinned)
|
||||||
mark_object (make_lisp_symbol (sym));
|
mark_object (make_lisp_symbol (sym));
|
||||||
|
|
|
||||||
487
src/android.c
487
src/android.c
|
|
@ -54,6 +54,9 @@ bool android_init_gui;
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
|
||||||
#include <linux/ashmem.h>
|
#include <linux/ashmem.h>
|
||||||
|
#include <linux/unistd.h>
|
||||||
|
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
|
||||||
#define ANDROID_THROW(env, class, msg) \
|
#define ANDROID_THROW(env, class, msg) \
|
||||||
((*(env))->ThrowNew ((env), (*(env))->FindClass ((env), class), msg))
|
((*(env))->ThrowNew ((env), (*(env))->FindClass ((env), class), msg))
|
||||||
|
|
@ -114,6 +117,12 @@ struct android_emacs_drawable
|
||||||
jmethodID damage_rect;
|
jmethodID damage_rect;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct android_emacs_window
|
||||||
|
{
|
||||||
|
jclass class;
|
||||||
|
jmethodID swap_buffers;
|
||||||
|
};
|
||||||
|
|
||||||
/* The asset manager being used. */
|
/* The asset manager being used. */
|
||||||
static AAssetManager *asset_manager;
|
static AAssetManager *asset_manager;
|
||||||
|
|
||||||
|
|
@ -181,6 +190,9 @@ static struct android_graphics_point point_class;
|
||||||
/* Various methods associated with the EmacsDrawable class. */
|
/* Various methods associated with the EmacsDrawable class. */
|
||||||
static struct android_emacs_drawable drawable_class;
|
static struct android_emacs_drawable drawable_class;
|
||||||
|
|
||||||
|
/* Various methods associated with the EmacsWindow class. */
|
||||||
|
static struct android_emacs_window window_class;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Event handling functions. Events are stored on a (circular) queue
|
/* Event handling functions. Events are stored on a (circular) queue
|
||||||
|
|
@ -247,10 +259,21 @@ android_run_select_thread (void *data)
|
||||||
|
|
||||||
sigfillset (&signals);
|
sigfillset (&signals);
|
||||||
|
|
||||||
|
#if __ANDROID_API__ < 16
|
||||||
|
/* sigprocmask must be used instead of pthread_sigmask due to a bug
|
||||||
|
in Android versions earlier than 16. It only affects the calling
|
||||||
|
thread on Android anyhow. */
|
||||||
|
|
||||||
|
if (sigprocmask (SIG_BLOCK, &signals, NULL))
|
||||||
|
__android_log_print (ANDROID_LOG_FATAL, __func__,
|
||||||
|
"sigprocmask: %s",
|
||||||
|
strerror (errno));
|
||||||
|
#else
|
||||||
if (pthread_sigmask (SIG_BLOCK, &signals, NULL))
|
if (pthread_sigmask (SIG_BLOCK, &signals, NULL))
|
||||||
__android_log_print (ANDROID_LOG_FATAL, __func__,
|
__android_log_print (ANDROID_LOG_FATAL, __func__,
|
||||||
"pthread_sigmask: %s",
|
"pthread_sigmask: %s",
|
||||||
strerror (errno));
|
strerror (errno));
|
||||||
|
#endif
|
||||||
|
|
||||||
sigdelset (&signals, SIGUSR1);
|
sigdelset (&signals, SIGUSR1);
|
||||||
sigemptyset (&waitset);
|
sigemptyset (&waitset);
|
||||||
|
|
@ -292,6 +315,8 @@ android_run_select_thread (void *data)
|
||||||
still be locked, so this must come before. */
|
still be locked, so this must come before. */
|
||||||
sem_post (&android_pselect_sem);
|
sem_post (&android_pselect_sem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -538,6 +563,200 @@ android_run_debug_thread (void *data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Asset directory handling functions. ``directory-tree'' is a file in
|
||||||
|
the root of the assets directory describing its contents.
|
||||||
|
|
||||||
|
See lib-src/asset-directory-tool for more details. */
|
||||||
|
|
||||||
|
/* The Android directory tree. */
|
||||||
|
static const char *directory_tree;
|
||||||
|
|
||||||
|
/* The size of the directory tree. */
|
||||||
|
static size_t directory_tree_size;
|
||||||
|
|
||||||
|
/* Read an unaligned (32-bit) long from the address POINTER. */
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
android_extract_long (char *pointer)
|
||||||
|
{
|
||||||
|
unsigned int number;
|
||||||
|
|
||||||
|
memcpy (&number, pointer, sizeof number);
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan to the file FILE in the asset directory tree. Return a
|
||||||
|
pointer to the end of that file (immediately before any children)
|
||||||
|
in the directory tree, or NULL if that file does not exist.
|
||||||
|
|
||||||
|
If returning non-NULL, also return the offset to the end of the
|
||||||
|
last subdirectory or file in *LIMIT_RETURN. LIMIT_RETURN may be
|
||||||
|
NULL.
|
||||||
|
|
||||||
|
FILE must have less than 11 levels of nesting. If it ends with a
|
||||||
|
trailing slash, then NULL will be returned if it is not actually a
|
||||||
|
directory. */
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
android_scan_directory_tree (char *file, size_t *limit_return)
|
||||||
|
{
|
||||||
|
char *token, *saveptr, *copy, *copy1, *start, *max, *limit;
|
||||||
|
size_t token_length, ntokens, i;
|
||||||
|
char *tokens[10];
|
||||||
|
|
||||||
|
USE_SAFE_ALLOCA;
|
||||||
|
|
||||||
|
/* Skip past the 5 byte header. */
|
||||||
|
start = (char *) directory_tree + 5;
|
||||||
|
|
||||||
|
/* Figure out the current limit. */
|
||||||
|
limit = (char *) directory_tree + directory_tree_size;
|
||||||
|
|
||||||
|
/* Now, split `file' into tokens, with the delimiter being the file
|
||||||
|
name separator. Look for the file and seek past it. */
|
||||||
|
|
||||||
|
ntokens = 0;
|
||||||
|
saveptr = NULL;
|
||||||
|
copy = copy1 = xstrdup (file);
|
||||||
|
memset (tokens, 0, sizeof tokens);
|
||||||
|
|
||||||
|
while ((token = strtok_r (copy, "/", &saveptr)))
|
||||||
|
{
|
||||||
|
copy = NULL;
|
||||||
|
|
||||||
|
/* Make sure ntokens is within bounds. */
|
||||||
|
if (ntokens == ARRAYELTS (tokens))
|
||||||
|
{
|
||||||
|
xfree (copy1);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
tokens[ntokens] = SAFE_ALLOCA (strlen (token) + 1);
|
||||||
|
memcpy (tokens[ntokens], token, strlen (token) + 1);
|
||||||
|
ntokens++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free the copy created for strtok_r. */
|
||||||
|
xfree (copy1);
|
||||||
|
|
||||||
|
/* If there are no tokens, just return the start of the directory
|
||||||
|
tree. */
|
||||||
|
if (!ntokens)
|
||||||
|
{
|
||||||
|
SAFE_FREE ();
|
||||||
|
|
||||||
|
/* Subtract the initial header bytes. */
|
||||||
|
if (limit_return)
|
||||||
|
*limit_return = directory_tree_size - 5;
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop through tokens, indexing the directory tree each time. */
|
||||||
|
|
||||||
|
for (i = 0; i < ntokens; ++i)
|
||||||
|
{
|
||||||
|
token = tokens[i];
|
||||||
|
|
||||||
|
/* Figure out how many bytes to compare. */
|
||||||
|
token_length = strlen (token);
|
||||||
|
|
||||||
|
again:
|
||||||
|
|
||||||
|
/* If this would be past the directory, return NULL. */
|
||||||
|
if (start + token_length > limit)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* Now compare the file name. */
|
||||||
|
if (!memcmp (start, token, token_length))
|
||||||
|
{
|
||||||
|
/* They probably match. Find the NULL byte. It must be
|
||||||
|
either one byte past start + token_length, with the last
|
||||||
|
byte a trailing slash (indicating that it is a
|
||||||
|
directory), or just start + token_length. Return 4 bytes
|
||||||
|
past the next NULL byte. */
|
||||||
|
|
||||||
|
max = memchr (start, 0, limit - start);
|
||||||
|
|
||||||
|
if (max != start + token_length
|
||||||
|
&& !(max == start + token_length + 1
|
||||||
|
&& *(max - 1) == '/'))
|
||||||
|
goto false_positive;
|
||||||
|
|
||||||
|
/* Return it if it exists and is in range, and this is the
|
||||||
|
last token. Otherwise, set it as start and the limit as
|
||||||
|
start + the offset and continue the loop. */
|
||||||
|
|
||||||
|
if (max && max + 5 <= limit)
|
||||||
|
{
|
||||||
|
if (i < ntokens - 1)
|
||||||
|
{
|
||||||
|
start = max + 5;
|
||||||
|
limit = ((char *) directory_tree
|
||||||
|
+ android_extract_long (max + 1));
|
||||||
|
|
||||||
|
/* Make sure limit is still in range. */
|
||||||
|
if (limit > directory_tree + directory_tree_size
|
||||||
|
|| start > directory_tree + directory_tree_size)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now see if max is not a directory and file is. If
|
||||||
|
file is a directory, then return NULL. */
|
||||||
|
if (*(max - 1) != '/' && file[strlen (file) - 1] == '/')
|
||||||
|
max = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Figure out the limit. */
|
||||||
|
if (limit_return)
|
||||||
|
*limit_return = android_extract_long (max + 1);
|
||||||
|
|
||||||
|
/* Go to the end of this file. */
|
||||||
|
max += 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_FREE ();
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return NULL otherwise. */
|
||||||
|
__android_log_print (ANDROID_LOG_WARN, __func__,
|
||||||
|
"could not scan to end of directory tree"
|
||||||
|
": %s", file);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
false_positive:
|
||||||
|
|
||||||
|
/* No match was found. Set start to the next sibling and try
|
||||||
|
again. */
|
||||||
|
|
||||||
|
start = memchr (start, 0, limit - start);
|
||||||
|
|
||||||
|
if (!start || start + 5 > limit)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
start = ((char *) directory_tree
|
||||||
|
+ android_extract_long (start + 1));
|
||||||
|
|
||||||
|
/* Make sure start is still in bounds. */
|
||||||
|
|
||||||
|
if (start > limit)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* Continue the loop. */
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
fail:
|
||||||
|
SAFE_FREE ();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Intercept USER_FULL_NAME and return something that makes sense if
|
/* Intercept USER_FULL_NAME and return something that makes sense if
|
||||||
pw->pw_gecos is NULL. */
|
pw->pw_gecos is NULL. */
|
||||||
|
|
||||||
|
|
@ -624,10 +843,6 @@ android_fstatat (int dirfd, const char *restrict pathname,
|
||||||
bool
|
bool
|
||||||
android_file_access_p (const char *name, int amode)
|
android_file_access_p (const char *name, int amode)
|
||||||
{
|
{
|
||||||
AAsset *asset;
|
|
||||||
AAssetDir *directory;
|
|
||||||
int length;
|
|
||||||
|
|
||||||
if (!asset_manager)
|
if (!asset_manager)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -637,50 +852,11 @@ android_file_access_p (const char *name, int amode)
|
||||||
/* /assets always exists. */
|
/* /assets always exists. */
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/* Check if the asset exists by opening it. Suboptimal! */
|
/* Check if the file exists by looking in the ``directory tree''
|
||||||
asset = AAssetManager_open (asset_manager, name,
|
asset generated during the build process. This is used
|
||||||
AASSET_MODE_UNKNOWN);
|
instead of the AAsset functions, because the latter are
|
||||||
|
buggy and treat directories inconsistently. */
|
||||||
if (!asset)
|
return android_scan_directory_tree ((char *) name, NULL) != NULL;
|
||||||
{
|
|
||||||
/* See if it's a directory as well. To open a directory
|
|
||||||
with the asset manager, the trailing slash (if specified)
|
|
||||||
must be removed. */
|
|
||||||
directory = AAssetManager_openDir (asset_manager, name);
|
|
||||||
|
|
||||||
if (directory)
|
|
||||||
{
|
|
||||||
/* Make sure the directory actually has files in it. */
|
|
||||||
|
|
||||||
if (!AAssetDir_getNextFileName (directory))
|
|
||||||
{
|
|
||||||
AAssetDir_close (directory);
|
|
||||||
errno = ENOENT;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AAssetDir_close (directory);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
errno = ENOENT;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AAsset_close (asset);
|
|
||||||
|
|
||||||
/* If NAME is a directory name, but it was a regular file, set
|
|
||||||
errno to ENOTDIR and return false. This is to behave like
|
|
||||||
faccessat. */
|
|
||||||
|
|
||||||
length = strlen (name);
|
|
||||||
if (name[length - 1] == '/')
|
|
||||||
{
|
|
||||||
errno = ENOTDIR;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -908,8 +1084,13 @@ android_get_home_directory (void)
|
||||||
|
|
||||||
/* JNI functions called by Java. */
|
/* JNI functions called by Java. */
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
#else
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
|
||||||
|
#endif
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
|
NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
|
||||||
|
|
@ -923,6 +1104,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
|
||||||
int pipefd[2];
|
int pipefd[2];
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
const char *java_string;
|
const char *java_string;
|
||||||
|
AAsset *asset;
|
||||||
|
|
||||||
/* This may be called from multiple threads. setEmacsParams should
|
/* This may be called from multiple threads. setEmacsParams should
|
||||||
only ever be called once. */
|
only ever be called once. */
|
||||||
|
|
@ -943,6 +1125,33 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
|
||||||
/* Set the asset manager. */
|
/* Set the asset manager. */
|
||||||
asset_manager = AAssetManager_fromJava (env, local_asset_manager);
|
asset_manager = AAssetManager_fromJava (env, local_asset_manager);
|
||||||
|
|
||||||
|
/* Initialize the directory tree. */
|
||||||
|
asset = AAssetManager_open (asset_manager, "directory-tree",
|
||||||
|
AASSET_MODE_BUFFER);
|
||||||
|
|
||||||
|
if (!asset)
|
||||||
|
{
|
||||||
|
__android_log_print (ANDROID_LOG_FATAL, __func__,
|
||||||
|
"Failed to open directory tree");
|
||||||
|
emacs_abort ();
|
||||||
|
}
|
||||||
|
|
||||||
|
directory_tree = AAsset_getBuffer (asset);
|
||||||
|
|
||||||
|
if (!directory_tree)
|
||||||
|
emacs_abort ();
|
||||||
|
|
||||||
|
/* Now figure out how big the directory tree is, and compare the
|
||||||
|
first few bytes. */
|
||||||
|
directory_tree_size = AAsset_getLength (asset);
|
||||||
|
if (directory_tree_size < 5
|
||||||
|
|| memcmp (directory_tree, "EMACS", 5))
|
||||||
|
{
|
||||||
|
__android_log_print (ANDROID_LOG_FATAL, __func__,
|
||||||
|
"Directory tree has bad magic");
|
||||||
|
emacs_abort ();
|
||||||
|
}
|
||||||
|
|
||||||
/* Hold a VM reference to the asset manager to prevent the native
|
/* Hold a VM reference to the asset manager to prevent the native
|
||||||
object from being deleted. */
|
object from being deleted. */
|
||||||
(*env)->NewGlobalRef (env, local_asset_manager);
|
(*env)->NewGlobalRef (env, local_asset_manager);
|
||||||
|
|
@ -1199,6 +1408,36 @@ android_init_emacs_drawable (void)
|
||||||
#undef FIND_METHOD
|
#undef FIND_METHOD
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
android_init_emacs_window (void)
|
||||||
|
{
|
||||||
|
jclass old;
|
||||||
|
|
||||||
|
window_class.class
|
||||||
|
= (*android_java_env)->FindClass (android_java_env,
|
||||||
|
"org/gnu/emacs/EmacsWindow");
|
||||||
|
eassert (window_class.class);
|
||||||
|
|
||||||
|
old = window_class.class;
|
||||||
|
window_class.class
|
||||||
|
= (jclass) (*android_java_env)->NewGlobalRef (android_java_env,
|
||||||
|
(jobject) old);
|
||||||
|
ANDROID_DELETE_LOCAL_REF (old);
|
||||||
|
|
||||||
|
if (!window_class.class)
|
||||||
|
emacs_abort ();
|
||||||
|
|
||||||
|
#define FIND_METHOD(c_name, name, signature) \
|
||||||
|
window_class.c_name \
|
||||||
|
= (*android_java_env)->GetMethodID (android_java_env, \
|
||||||
|
window_class.class, \
|
||||||
|
name, signature); \
|
||||||
|
assert (window_class.c_name);
|
||||||
|
|
||||||
|
FIND_METHOD (swap_buffers, "swapBuffers", "()V");
|
||||||
|
#undef FIND_METHOD
|
||||||
|
}
|
||||||
|
|
||||||
extern JNIEXPORT void JNICALL
|
extern JNIEXPORT void JNICALL
|
||||||
NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv)
|
NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv)
|
||||||
{
|
{
|
||||||
|
|
@ -1232,6 +1471,7 @@ NATIVE_NAME (initEmacs) (JNIEnv *env, jobject object, jarray argv)
|
||||||
android_init_emacs_pixmap ();
|
android_init_emacs_pixmap ();
|
||||||
android_init_graphics_point ();
|
android_init_graphics_point ();
|
||||||
android_init_emacs_drawable ();
|
android_init_emacs_drawable ();
|
||||||
|
android_init_emacs_window ();
|
||||||
|
|
||||||
/* Set HOME to the app data directory. */
|
/* Set HOME to the app data directory. */
|
||||||
setenv ("HOME", android_files_dir, 1);
|
setenv ("HOME", android_files_dir, 1);
|
||||||
|
|
@ -1545,7 +1785,11 @@ NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object,
|
||||||
android_write_event (&event);
|
android_write_event (&event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
|
#else
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1557,8 +1801,6 @@ NATIVE_NAME (sendContextMenu) (JNIEnv *env, jobject object,
|
||||||
This means that every local reference must be explicitly destroyed
|
This means that every local reference must be explicitly destroyed
|
||||||
with DeleteLocalRef. A helper macro is provided to do this. */
|
with DeleteLocalRef. A helper macro is provided to do this. */
|
||||||
|
|
||||||
#define MAX_HANDLE 65535
|
|
||||||
|
|
||||||
struct android_handle_entry
|
struct android_handle_entry
|
||||||
{
|
{
|
||||||
/* The type. */
|
/* The type. */
|
||||||
|
|
@ -1883,7 +2125,7 @@ android_init_emacs_gc_class (void)
|
||||||
emacs_gc_mark_dirty
|
emacs_gc_mark_dirty
|
||||||
= (*android_java_env)->GetMethodID (android_java_env,
|
= (*android_java_env)->GetMethodID (android_java_env,
|
||||||
emacs_gc_class,
|
emacs_gc_class,
|
||||||
"markDirty", "()V");
|
"markDirty", "(Z)V");
|
||||||
assert (emacs_gc_mark_dirty);
|
assert (emacs_gc_mark_dirty);
|
||||||
|
|
||||||
old = emacs_gc_class;
|
old = emacs_gc_class;
|
||||||
|
|
@ -2011,6 +2253,9 @@ android_change_gc (struct android_gc *gc,
|
||||||
struct android_gc_values *values)
|
struct android_gc_values *values)
|
||||||
{
|
{
|
||||||
jobject what, gcontext;
|
jobject what, gcontext;
|
||||||
|
jboolean clip_changed;
|
||||||
|
|
||||||
|
clip_changed = false;
|
||||||
|
|
||||||
android_init_emacs_gc_class ();
|
android_init_emacs_gc_class ();
|
||||||
gcontext = android_resolve_handle (gc->gcontext,
|
gcontext = android_resolve_handle (gc->gcontext,
|
||||||
|
|
@ -2041,16 +2286,22 @@ android_change_gc (struct android_gc *gc,
|
||||||
values->function);
|
values->function);
|
||||||
|
|
||||||
if (mask & ANDROID_GC_CLIP_X_ORIGIN)
|
if (mask & ANDROID_GC_CLIP_X_ORIGIN)
|
||||||
|
{
|
||||||
(*android_java_env)->SetIntField (android_java_env,
|
(*android_java_env)->SetIntField (android_java_env,
|
||||||
gcontext,
|
gcontext,
|
||||||
emacs_gc_clip_x_origin,
|
emacs_gc_clip_x_origin,
|
||||||
values->clip_x_origin);
|
values->clip_x_origin);
|
||||||
|
clip_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (mask & ANDROID_GC_CLIP_Y_ORIGIN)
|
if (mask & ANDROID_GC_CLIP_Y_ORIGIN)
|
||||||
|
{
|
||||||
(*android_java_env)->SetIntField (android_java_env,
|
(*android_java_env)->SetIntField (android_java_env,
|
||||||
gcontext,
|
gcontext,
|
||||||
emacs_gc_clip_y_origin,
|
emacs_gc_clip_y_origin,
|
||||||
values->clip_y_origin);
|
values->clip_y_origin);
|
||||||
|
clip_changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (mask & ANDROID_GC_CLIP_MASK)
|
if (mask & ANDROID_GC_CLIP_MASK)
|
||||||
{
|
{
|
||||||
|
|
@ -2070,6 +2321,7 @@ android_change_gc (struct android_gc *gc,
|
||||||
xfree (gc->clip_rects);
|
xfree (gc->clip_rects);
|
||||||
gc->clip_rects = NULL;
|
gc->clip_rects = NULL;
|
||||||
gc->num_clip_rects = -1;
|
gc->num_clip_rects = -1;
|
||||||
|
clip_changed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mask & ANDROID_GC_STIPPLE)
|
if (mask & ANDROID_GC_STIPPLE)
|
||||||
|
|
@ -2103,7 +2355,8 @@ android_change_gc (struct android_gc *gc,
|
||||||
if (mask)
|
if (mask)
|
||||||
(*android_java_env)->CallVoidMethod (android_java_env,
|
(*android_java_env)->CallVoidMethod (android_java_env,
|
||||||
gcontext,
|
gcontext,
|
||||||
emacs_gc_mark_dirty);
|
emacs_gc_mark_dirty,
|
||||||
|
(jboolean) clip_changed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -2174,7 +2427,8 @@ android_set_clip_rectangles (struct android_gc *gc, int clip_x_origin,
|
||||||
|
|
||||||
(*android_java_env)->CallVoidMethod (android_java_env,
|
(*android_java_env)->CallVoidMethod (android_java_env,
|
||||||
gcontext,
|
gcontext,
|
||||||
emacs_gc_mark_dirty);
|
emacs_gc_mark_dirty,
|
||||||
|
(jboolean) true);
|
||||||
|
|
||||||
/* Cache the clip rectangles on the C side for
|
/* Cache the clip rectangles on the C side for
|
||||||
sfntfont-android.c. */
|
sfntfont-android.c. */
|
||||||
|
|
@ -2327,18 +2581,15 @@ android_swap_buffers (struct android_swap_info *swap_info,
|
||||||
int num_windows)
|
int num_windows)
|
||||||
{
|
{
|
||||||
jobject window;
|
jobject window;
|
||||||
jmethodID swap_buffers;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
swap_buffers = android_lookup_method ("org/gnu/emacs/EmacsWindow",
|
|
||||||
"swapBuffers", "()V");
|
|
||||||
|
|
||||||
for (i = 0; i < num_windows; ++i)
|
for (i = 0; i < num_windows; ++i)
|
||||||
{
|
{
|
||||||
window = android_resolve_handle (swap_info[i].swap_window,
|
window = android_resolve_handle (swap_info[i].swap_window,
|
||||||
ANDROID_HANDLE_WINDOW);
|
ANDROID_HANDLE_WINDOW);
|
||||||
(*android_java_env)->CallVoidMethod (android_java_env,
|
(*android_java_env)->CallVoidMethod (android_java_env,
|
||||||
window, swap_buffers);
|
window,
|
||||||
|
window_class.swap_buffers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3555,11 +3806,17 @@ android_sync (void)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if __ANDROID_API__ >= 17
|
||||||
|
|
||||||
#undef faccessat
|
#undef faccessat
|
||||||
|
|
||||||
/* Replace the system faccessat with one which understands AT_EACCESS.
|
/* Replace the system faccessat with one which understands AT_EACCESS.
|
||||||
Android's faccessat simply fails upon using AT_EACCESS, so repalce
|
Android's faccessat simply fails upon using AT_EACCESS, so repalce
|
||||||
it with zero here. This isn't caught during configuration. */
|
it with zero here. This isn't caught during configuration.
|
||||||
|
|
||||||
|
This replacement is only done when building for Android 17 or
|
||||||
|
later, because earlier versions use the gnulib replacement that
|
||||||
|
lacks these issues. */
|
||||||
|
|
||||||
int
|
int
|
||||||
faccessat (int dirfd, const char *pathname, int mode, int flags)
|
faccessat (int dirfd, const char *pathname, int mode, int flags)
|
||||||
|
|
@ -3572,6 +3829,8 @@ faccessat (int dirfd, const char *pathname, int mode, int flags)
|
||||||
return real_faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS);
|
return real_faccessat (dirfd, pathname, mode, flags & ~AT_EACCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif /* __ANDROID_API__ < 16 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Directory listing emulation. */
|
/* Directory listing emulation. */
|
||||||
|
|
@ -3581,8 +3840,11 @@ struct android_dir
|
||||||
/* The real DIR *, if it exists. */
|
/* The real DIR *, if it exists. */
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
/* Otherwise, the AAssetDir. */
|
/* Otherwise, the pointer to the directory in directory_tree. */
|
||||||
void *asset_dir;
|
char *asset_dir;
|
||||||
|
|
||||||
|
/* And the end of the files in asset_dir. */
|
||||||
|
char *asset_limit;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Like opendir. However, return an asset directory if NAME points to
|
/* Like opendir. However, return an asset directory if NAME points to
|
||||||
|
|
@ -3592,8 +3854,9 @@ struct android_dir *
|
||||||
android_opendir (const char *name)
|
android_opendir (const char *name)
|
||||||
{
|
{
|
||||||
struct android_dir *dir;
|
struct android_dir *dir;
|
||||||
AAssetDir *asset_dir;
|
char *asset_dir;
|
||||||
const char *asset_name;
|
const char *asset_name;
|
||||||
|
size_t limit;
|
||||||
|
|
||||||
asset_name = android_get_asset_name (name);
|
asset_name = android_get_asset_name (name);
|
||||||
|
|
||||||
|
|
@ -3601,8 +3864,9 @@ android_opendir (const char *name)
|
||||||
directory. */
|
directory. */
|
||||||
if (asset_manager && asset_name)
|
if (asset_manager && asset_name)
|
||||||
{
|
{
|
||||||
asset_dir = AAssetManager_openDir (asset_manager,
|
asset_dir
|
||||||
asset_name);
|
= (char *) android_scan_directory_tree ((char *) asset_name,
|
||||||
|
&limit);
|
||||||
|
|
||||||
if (!asset_dir)
|
if (!asset_dir)
|
||||||
{
|
{
|
||||||
|
|
@ -3613,6 +3877,20 @@ android_opendir (const char *name)
|
||||||
dir = xmalloc (sizeof *dir);
|
dir = xmalloc (sizeof *dir);
|
||||||
dir->dir = NULL;
|
dir->dir = NULL;
|
||||||
dir->asset_dir = asset_dir;
|
dir->asset_dir = asset_dir;
|
||||||
|
dir->asset_limit = (char *) directory_tree + limit;
|
||||||
|
|
||||||
|
/* Make sure dir->asset_limit is within bounds. It is a limit,
|
||||||
|
and as such can be exactly one byte past directory_tree. */
|
||||||
|
if (dir->asset_limit > directory_tree + directory_tree_size)
|
||||||
|
{
|
||||||
|
xfree (dir);
|
||||||
|
__android_log_print (ANDROID_LOG_VERBOSE, __func__,
|
||||||
|
"Invalid dir tree, limit %zu, size %zu\n",
|
||||||
|
limit, directory_tree_size);
|
||||||
|
dir = NULL;
|
||||||
|
errno = EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3636,23 +3914,55 @@ struct dirent *
|
||||||
android_readdir (struct android_dir *dir)
|
android_readdir (struct android_dir *dir)
|
||||||
{
|
{
|
||||||
static struct dirent dirent;
|
static struct dirent dirent;
|
||||||
const char *filename;
|
const char *last;
|
||||||
|
|
||||||
if (dir->asset_dir)
|
if (dir->asset_dir)
|
||||||
{
|
{
|
||||||
filename = AAssetDir_getNextFileName (dir->asset_dir);
|
/* There are no more files to read. */
|
||||||
errno = 0;
|
if (dir->asset_dir >= dir->asset_limit)
|
||||||
|
|
||||||
if (!filename)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
/* Otherwise, scan forward looking for the next NULL byte. */
|
||||||
|
last = memchr (dir->asset_dir, 0,
|
||||||
|
dir->asset_limit - dir->asset_dir);
|
||||||
|
|
||||||
|
/* No more NULL bytes remain. */
|
||||||
|
if (!last)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Forward last past the NULL byte. */
|
||||||
|
last++;
|
||||||
|
|
||||||
|
/* Make sure it is still within the directory tree. */
|
||||||
|
if (last >= directory_tree + directory_tree_size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Now, fill in the dirent with the name. */
|
||||||
memset (&dirent, 0, sizeof dirent);
|
memset (&dirent, 0, sizeof dirent);
|
||||||
dirent.d_ino = 0;
|
dirent.d_ino = 0;
|
||||||
dirent.d_off = 0;
|
dirent.d_off = 0;
|
||||||
dirent.d_reclen = sizeof dirent;
|
dirent.d_reclen = sizeof dirent;
|
||||||
dirent.d_type = DT_UNKNOWN;
|
dirent.d_type = DT_UNKNOWN;
|
||||||
strncpy (dirent.d_name, filename,
|
|
||||||
sizeof dirent.d_name - 1);
|
/* Note that dir->asset_dir is actually a NULL terminated
|
||||||
|
string. */
|
||||||
|
memcpy (dirent.d_name, dir->asset_dir,
|
||||||
|
MIN (sizeof dirent.d_name,
|
||||||
|
last - dir->asset_dir));
|
||||||
|
dirent.d_name[sizeof dirent.d_name - 1] = '\0';
|
||||||
|
|
||||||
|
/* Strip off the trailing slash, if any. */
|
||||||
|
if (dirent.d_name[MIN (sizeof dirent.d_name,
|
||||||
|
last - dir->asset_dir)
|
||||||
|
- 2] == '/')
|
||||||
|
dirent.d_name[MIN (sizeof dirent.d_name,
|
||||||
|
last - dir->asset_dir)
|
||||||
|
- 2] = '\0';
|
||||||
|
|
||||||
|
/* Finally, forward dir->asset_dir to the file past last. */
|
||||||
|
dir->asset_dir = ((char *) directory_tree
|
||||||
|
+ android_extract_long ((char *) last));
|
||||||
|
|
||||||
return &dirent;
|
return &dirent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3666,8 +3976,9 @@ android_closedir (struct android_dir *dir)
|
||||||
{
|
{
|
||||||
if (dir->dir)
|
if (dir->dir)
|
||||||
closedir (dir->dir);
|
closedir (dir->dir);
|
||||||
else
|
|
||||||
AAssetDir_close (dir->asset_dir);
|
/* There is no need to close anything else, as the directory tree
|
||||||
|
lies in statically allocated memory. */
|
||||||
|
|
||||||
xfree (dir);
|
xfree (dir);
|
||||||
}
|
}
|
||||||
|
|
@ -4010,6 +4321,36 @@ android_project_image_nearest (struct android_image *image,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* System call wrappers for stuff missing in bionic. */
|
||||||
|
|
||||||
|
#ifndef HAVE_FTRUNCATE
|
||||||
|
|
||||||
|
/* ftruncate wrapper for Android, for systems without ftruncate in the
|
||||||
|
C library.
|
||||||
|
|
||||||
|
Such systems are always 32 bit systems, since Android 21 and later
|
||||||
|
all support ftruncate. In addition, ARM and MIPS require registers
|
||||||
|
used to store long long parameters to be aligned to an even
|
||||||
|
register pair. */
|
||||||
|
|
||||||
|
int
|
||||||
|
android_ftruncate (int fd, off_t length)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
#if defined __arm__ || defined __mips__
|
||||||
|
return syscall (SYS_ftruncate64, fd, 0,
|
||||||
|
(unsigned int) (length & 0xffffffff),
|
||||||
|
(unsigned int) (length >> 32));
|
||||||
|
#else
|
||||||
|
return syscall (SYS_ftruncate64, fd, length);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#else /* ANDROID_STUBIFY */
|
#else /* ANDROID_STUBIFY */
|
||||||
|
|
||||||
/* X emulation functions for Android. */
|
/* X emulation functions for Android. */
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,14 @@ extern struct android_dir *android_opendir (const char *);
|
||||||
extern struct dirent *android_readdir (struct android_dir *);
|
extern struct dirent *android_readdir (struct android_dir *);
|
||||||
extern void android_closedir (struct android_dir *);
|
extern void android_closedir (struct android_dir *);
|
||||||
|
|
||||||
|
#ifndef HAVE_FTRUNCATE
|
||||||
|
extern int android_ftruncate (int, off_t);
|
||||||
|
|
||||||
|
/* Replace calls to ftruncate with android_ftruncate when ftruncate is
|
||||||
|
not defined. */
|
||||||
|
#define ftruncate android_ftruncate
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -683,7 +683,7 @@ handle_one_android_event (struct android_display_info *dpyinfo,
|
||||||
XSETFRAME (inev.ie.frame_or_window, f);
|
XSETFRAME (inev.ie.frame_or_window, f);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* A new frame must be created. */;
|
((void) 0) /* A new frame must be created. */;
|
||||||
}
|
}
|
||||||
|
|
||||||
case ANDROID_ENTER_NOTIFY:
|
case ANDROID_ENTER_NOTIFY:
|
||||||
|
|
@ -988,6 +988,9 @@ handle_one_android_event (struct android_display_info *dpyinfo,
|
||||||
|
|
||||||
if (!NILP (Vmouse_highlight))
|
if (!NILP (Vmouse_highlight))
|
||||||
{
|
{
|
||||||
|
/* Clear the pointer invisible flag to always make
|
||||||
|
note_mouse_highlight do its thing. */
|
||||||
|
any->pointer_invisible = false;
|
||||||
note_mouse_highlight (any, x, y);
|
note_mouse_highlight (any, x, y);
|
||||||
|
|
||||||
/* Always allow future mouse motion to
|
/* Always allow future mouse motion to
|
||||||
|
|
|
||||||
|
|
@ -423,7 +423,15 @@ using_utf8 (void)
|
||||||
the result is known in advance anyway... */
|
the result is known in advance anyway... */
|
||||||
#if defined HAVE_WCHAR_H && !defined WINDOWSNT
|
#if defined HAVE_WCHAR_H && !defined WINDOWSNT
|
||||||
wchar_t wc;
|
wchar_t wc;
|
||||||
|
#ifndef HAVE_ANDROID
|
||||||
mbstate_t mbs = { 0 };
|
mbstate_t mbs = { 0 };
|
||||||
|
#else
|
||||||
|
mbstate_t mbs;
|
||||||
|
|
||||||
|
/* Not sure how mbstate works on Android, but this seems to be
|
||||||
|
required. */
|
||||||
|
memset (&mbs, 0, sizeof mbs);
|
||||||
|
#endif
|
||||||
return mbrtowc (&wc, "\xc4\x80", 2, &mbs) == 2 && wc == 0x100;
|
return mbrtowc (&wc, "\xc4\x80", 2, &mbs) == 2 && wc == 0x100;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
15
src/fileio.c
15
src/fileio.c
|
|
@ -6325,6 +6325,11 @@ effect except for flushing STREAM's data. */)
|
||||||
|
|
||||||
#ifndef DOS_NT
|
#ifndef DOS_NT
|
||||||
|
|
||||||
|
#if defined STAT_STATFS2_BSIZE || defined STAT_STATFS2_FRSIZE \
|
||||||
|
|| defined STAT_STATFS2_FSIZE || defined STAT_STATFS3_OSF1 \
|
||||||
|
|| defined STAT_STATFS4 || defined STAT_STATVFS \
|
||||||
|
|| defined STAT_STATVFS64
|
||||||
|
|
||||||
/* Yield a Lisp number equal to BLOCKSIZE * BLOCKS, with the result
|
/* Yield a Lisp number equal to BLOCKSIZE * BLOCKS, with the result
|
||||||
negated if NEGATE. */
|
negated if NEGATE. */
|
||||||
static Lisp_Object
|
static Lisp_Object
|
||||||
|
|
@ -6339,6 +6344,8 @@ blocks_to_bytes (uintmax_t blocksize, uintmax_t blocks, bool negate)
|
||||||
return CALLN (Ftimes, bs, make_uint (blocks));
|
return CALLN (Ftimes, bs, make_uint (blocks));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
|
DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
|
||||||
doc: /* Return storage information about the file system FILENAME is on.
|
doc: /* Return storage information about the file system FILENAME is on.
|
||||||
Value is a list of numbers (TOTAL FREE AVAIL), where TOTAL is the total
|
Value is a list of numbers (TOTAL FREE AVAIL), where TOTAL is the total
|
||||||
|
|
@ -6360,6 +6367,11 @@ If the underlying system call fails, value is nil. */)
|
||||||
error ("Invalid handler in `file-name-handler-alist'");
|
error ("Invalid handler in `file-name-handler-alist'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Try to detect whether or not fsusage.o is actually built. */
|
||||||
|
#if defined STAT_STATFS2_BSIZE || defined STAT_STATFS2_FRSIZE \
|
||||||
|
|| defined STAT_STATFS2_FSIZE || defined STAT_STATFS3_OSF1 \
|
||||||
|
|| defined STAT_STATFS4 || defined STAT_STATVFS \
|
||||||
|
|| defined STAT_STATVFS64
|
||||||
struct fs_usage u;
|
struct fs_usage u;
|
||||||
if (get_fs_usage (SSDATA (ENCODE_FILE (filename)), NULL, &u) != 0)
|
if (get_fs_usage (SSDATA (ENCODE_FILE (filename)), NULL, &u) != 0)
|
||||||
return errno == ENOSYS ? Qnil : file_attribute_errno (filename, errno);
|
return errno == ENOSYS ? Qnil : file_attribute_errno (filename, errno);
|
||||||
|
|
@ -6367,6 +6379,9 @@ If the underlying system call fails, value is nil. */)
|
||||||
blocks_to_bytes (u.fsu_blocksize, u.fsu_bfree, false),
|
blocks_to_bytes (u.fsu_blocksize, u.fsu_bfree, false),
|
||||||
blocks_to_bytes (u.fsu_blocksize, u.fsu_bavail,
|
blocks_to_bytes (u.fsu_blocksize, u.fsu_bavail,
|
||||||
u.fsu_bavail_top_bit_set));
|
u.fsu_bavail_top_bit_set));
|
||||||
|
#else
|
||||||
|
return Qnil;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !DOS_NT */
|
#endif /* !DOS_NT */
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
#define BOOT_TIME_FILE "/var/run/random-seed"
|
#define BOOT_TIME_FILE "/var/run/random-seed"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Boot time is not available on Android. */
|
||||||
|
|
||||||
|
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
|
||||||
|
#undef BOOT_TIME
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined WTMP_FILE && !defined WINDOWSNT && defined BOOT_TIME
|
#if !defined WTMP_FILE && !defined WINDOWSNT && defined BOOT_TIME
|
||||||
#define WTMP_FILE "/var/log/wtmp"
|
#define WTMP_FILE "/var/log/wtmp"
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -120,12 +126,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
* Non-forced locks on non-MS-Windows systems that support neither
|
* Non-forced locks on non-MS-Windows systems that support neither
|
||||||
hard nor symbolic links. */
|
hard nor symbolic links. */
|
||||||
|
|
||||||
/* Boot time is not available on Android. */
|
|
||||||
|
|
||||||
#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
|
|
||||||
#undef BOOT_TIME
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Return the time of the last system boot. */
|
/* Return the time of the last system boot. */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5666,6 +5666,8 @@ On Nextstep, this just calls `ns-parse-geometry'. */)
|
||||||
int x UNINIT, y UNINIT;
|
int x UNINIT, y UNINIT;
|
||||||
unsigned int width, height;
|
unsigned int width, height;
|
||||||
|
|
||||||
|
width = height = 0;
|
||||||
|
|
||||||
CHECK_STRING (string);
|
CHECK_STRING (string);
|
||||||
|
|
||||||
#ifdef HAVE_NS
|
#ifdef HAVE_NS
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include "syssignal.h"
|
#include "syssignal.h"
|
||||||
|
|
||||||
|
#if defined HAVE_STACK_OVERFLOW_HANDLING && !defined WINDOWSNT
|
||||||
|
#include <setjmp.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
@ -4955,7 +4959,7 @@ const char *const lispy_function_keys[] =
|
||||||
[278] = "copy",
|
[278] = "copy",
|
||||||
[279] = "paste",
|
[279] = "paste",
|
||||||
[28] = "clear",
|
[28] = "clear",
|
||||||
[4] = "back",
|
[4] = "XF86Back",
|
||||||
[61] = "tab",
|
[61] = "tab",
|
||||||
[66] = "return",
|
[66] = "return",
|
||||||
[67] = "backspace",
|
[67] = "backspace",
|
||||||
|
|
|
||||||
|
|
@ -1152,7 +1152,7 @@ x_popup_menu_1 (Lisp_Object position, Lisp_Object menu)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
menuflags |= MENU_FOR_CLICK;
|
menuflags |= MENU_FOR_CLICK;
|
||||||
tem = Fcar (XCDR (position)); /* EVENT_START (position) */
|
tem = EVENT_START (position); /* EVENT_START (position) */
|
||||||
window = Fcar (tem); /* POSN_WINDOW (tem) */
|
window = Fcar (tem); /* POSN_WINDOW (tem) */
|
||||||
tem2 = Fcar (Fcdr (tem)); /* POSN_POSN (tem) */
|
tem2 = Fcar (Fcdr (tem)); /* POSN_POSN (tem) */
|
||||||
/* The MENU_KBD_NAVIGATION field is set when the menu
|
/* The MENU_KBD_NAVIGATION field is set when the menu
|
||||||
|
|
@ -1466,9 +1466,10 @@ cached information about equivalent key sequences.
|
||||||
If the user gets rid of the menu without making a valid choice, for
|
If the user gets rid of the menu without making a valid choice, for
|
||||||
instance by clicking the mouse away from a valid choice or by typing
|
instance by clicking the mouse away from a valid choice or by typing
|
||||||
keyboard input, then this normally results in a quit and
|
keyboard input, then this normally results in a quit and
|
||||||
`x-popup-menu' does not return. But if POSITION is a mouse button
|
`x-popup-menu' does not return. But if POSITION is a mouse button or
|
||||||
event (indicating that the user invoked the menu with the mouse) then
|
touch screen event (indicating that the user invoked the menu with the
|
||||||
no quit occurs and `x-popup-menu' returns nil. */)
|
a pointing device) then no quit occurs and `x-popup-menu' returns
|
||||||
|
nil. */)
|
||||||
(Lisp_Object position, Lisp_Object menu)
|
(Lisp_Object position, Lisp_Object menu)
|
||||||
{
|
{
|
||||||
init_raw_keybuf_count ();
|
init_raw_keybuf_count ();
|
||||||
|
|
|
||||||
|
|
@ -4624,9 +4624,15 @@ main (int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (meta)
|
if (meta)
|
||||||
|
{
|
||||||
fprintf (stderr, "meta table with count: %"PRIu32"\n",
|
fprintf (stderr, "meta table with count: %"PRIu32"\n",
|
||||||
meta->num_data_maps);
|
meta->num_data_maps);
|
||||||
|
|
||||||
|
for (i = 0; i < meta->num_data_maps; ++i)
|
||||||
|
fprintf (stderr, " meta tag: %"PRIx32"\n",
|
||||||
|
meta->data_maps[i].tag);
|
||||||
|
}
|
||||||
|
|
||||||
loca_long = NULL;
|
loca_long = NULL;
|
||||||
loca_short = NULL;
|
loca_short = NULL;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -310,7 +310,7 @@ sfntfont_android_put_glyphs (struct glyph_string *s, int from,
|
||||||
|
|
||||||
/* Allocate enough to hold text_rectangle.height, aligned to 8
|
/* Allocate enough to hold text_rectangle.height, aligned to 8
|
||||||
bytes. Then fill it with the background. */
|
bytes. Then fill it with the background. */
|
||||||
stride = (text_rectangle.width * sizeof *buffer) + 7 & ~7;
|
stride = ((text_rectangle.width * sizeof *buffer) + 7) & ~7;
|
||||||
GET_SCANLINE_BUFFER (buffer, text_rectangle.height, stride);
|
GET_SCANLINE_BUFFER (buffer, text_rectangle.height, stride);
|
||||||
memset (buffer, 0, text_rectangle.height * stride);
|
memset (buffer, 0, text_rectangle.height * stride);
|
||||||
|
|
||||||
|
|
@ -546,6 +546,7 @@ init_sfntfont_android (void)
|
||||||
{
|
{
|
||||||
/* Make sure to pick the right Sans Serif font depending on what
|
/* Make sure to pick the right Sans Serif font depending on what
|
||||||
version of Android the device is running. */
|
version of Android the device is running. */
|
||||||
|
#if HAVE_DECL_ANDROID_GET_DEVICE_API_LEVEL
|
||||||
if (android_get_device_api_level () >= 15)
|
if (android_get_device_api_level () >= 15)
|
||||||
Vsfnt_default_family_alist
|
Vsfnt_default_family_alist
|
||||||
= list3 (Fcons (build_string ("Monospace"),
|
= list3 (Fcons (build_string ("Monospace"),
|
||||||
|
|
@ -557,6 +558,7 @@ init_sfntfont_android (void)
|
||||||
Fcons (build_string ("Sans Serif"),
|
Fcons (build_string ("Sans Serif"),
|
||||||
build_string ("Roboto")));
|
build_string ("Roboto")));
|
||||||
else
|
else
|
||||||
|
#endif
|
||||||
Vsfnt_default_family_alist
|
Vsfnt_default_family_alist
|
||||||
= list3 (Fcons (build_string ("Monospace"),
|
= list3 (Fcons (build_string ("Monospace"),
|
||||||
build_string ("Droid Sans Mono")),
|
build_string ("Droid Sans Mono")),
|
||||||
|
|
|
||||||
111
src/sfntfont.c
111
src/sfntfont.c
|
|
@ -21,6 +21,7 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
#include "lisp.h"
|
#include "lisp.h"
|
||||||
|
|
||||||
|
|
@ -61,6 +62,12 @@ struct sfnt_font_desc
|
||||||
/* Designer (foundry) of the font. */
|
/* Designer (foundry) of the font. */
|
||||||
Lisp_Object designer;
|
Lisp_Object designer;
|
||||||
|
|
||||||
|
/* Style tokens that could not be parsed. */
|
||||||
|
Lisp_Object adstyle;
|
||||||
|
|
||||||
|
/* List of design languages. */
|
||||||
|
Lisp_Object languages;
|
||||||
|
|
||||||
/* Numeric width, weight, slant and spacing. */
|
/* Numeric width, weight, slant and spacing. */
|
||||||
int width, weight, slant, spacing;
|
int width, weight, slant, spacing;
|
||||||
|
|
||||||
|
|
@ -344,7 +351,9 @@ static struct sfnt_style_desc sfnt_width_descriptions[] =
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Figure out DESC->width, DESC->weight, DESC->slant and DESC->spacing
|
/* Figure out DESC->width, DESC->weight, DESC->slant and DESC->spacing
|
||||||
based on the style name passed as STYLE_NAME. */
|
based on the style name passed as STYLE_NAME.
|
||||||
|
|
||||||
|
Also append any unknown tokens to DESC->adstyle. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sfnt_parse_style (Lisp_Object style_name, struct sfnt_font_desc *desc)
|
sfnt_parse_style (Lisp_Object style_name, struct sfnt_font_desc *desc)
|
||||||
|
|
@ -419,16 +428,85 @@ sfnt_parse_style (Lisp_Object style_name, struct sfnt_font_desc *desc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This token is extraneous or was not recognized. Capitalize
|
||||||
|
the first letter and set it as the adstyle. */
|
||||||
|
|
||||||
|
if (strlen (single))
|
||||||
|
{
|
||||||
|
if (islower (single[0]))
|
||||||
|
single[0] = toupper (single[0]);
|
||||||
|
|
||||||
|
if (NILP (desc->adstyle))
|
||||||
|
desc->adstyle = build_string (single);
|
||||||
|
else
|
||||||
|
desc->adstyle = CALLN (Fconcat, desc->adstyle,
|
||||||
|
build_string (" "),
|
||||||
|
build_string (single));
|
||||||
|
}
|
||||||
|
|
||||||
next:
|
next:
|
||||||
|
|
||||||
/* Break early if everything has been found. */
|
|
||||||
if (desc->slant != 100 && desc->width != 100 && desc->weight != 80)
|
|
||||||
break;
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parse the list of design languages in META, a font metadata table,
|
||||||
|
and place the results in DESC->languages. Do nothing if there is
|
||||||
|
no such metadata. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
sfnt_parse_languages (struct sfnt_meta_table *meta,
|
||||||
|
struct sfnt_font_desc *desc)
|
||||||
|
{
|
||||||
|
char *data, *metadata, *tag;
|
||||||
|
struct sfnt_meta_data_map map;
|
||||||
|
char *saveptr;
|
||||||
|
|
||||||
|
/* Look up the ``design languages'' metadata. This is a comma (and
|
||||||
|
possibly space) separated list of scripts that the font was
|
||||||
|
designed for. Here is an example of one such tag:
|
||||||
|
|
||||||
|
zh-Hans,Jpan,Kore
|
||||||
|
|
||||||
|
for a font that covers Simplified Chinese, along with Japanese
|
||||||
|
and Korean text. */
|
||||||
|
|
||||||
|
saveptr = NULL;
|
||||||
|
data = sfnt_find_metadata (meta, SFNT_META_DATA_TAG_DLNG,
|
||||||
|
&map);
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
USE_SAFE_ALLOCA;
|
||||||
|
|
||||||
|
/* Now copy metadata and add a trailing NULL byte. */
|
||||||
|
|
||||||
|
if (map.data_length >= SIZE_MAX)
|
||||||
|
memory_full (SIZE_MAX);
|
||||||
|
|
||||||
|
metadata = SAFE_ALLOCA ((size_t) map.data_length + 1);
|
||||||
|
memcpy (metadata, data, map.data_length);
|
||||||
|
metadata[map.data_length] = '\0';
|
||||||
|
|
||||||
|
/* Loop through each script-language tag. Note that there may be
|
||||||
|
extra leading spaces. */
|
||||||
|
while ((tag = strtok_r (metadata, ",", &saveptr)))
|
||||||
|
{
|
||||||
|
metadata = NULL;
|
||||||
|
|
||||||
|
if (strstr (tag, "Hans") || strstr (tag, "Hant"))
|
||||||
|
desc->languages = Fcons (Qzh, desc->languages);
|
||||||
|
|
||||||
|
if (strstr (tag, "Japn"))
|
||||||
|
desc->languages = Fcons (Qja, desc->languages);
|
||||||
|
|
||||||
|
if (strstr (tag, "Kore"))
|
||||||
|
desc->languages = Fcons (Qko, desc->languages);
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_FREE ();
|
||||||
|
}
|
||||||
|
|
||||||
/* Enumerate the offset subtable SUBTABLES in the file FD, whose file
|
/* Enumerate the offset subtable SUBTABLES in the file FD, whose file
|
||||||
name is FILE. OFFSET should be the offset of the subtable within
|
name is FILE. OFFSET should be the offset of the subtable within
|
||||||
the font file, and is recorded for future use. Value is 1 upon
|
the font file, and is recorded for future use. Value is 1 upon
|
||||||
|
|
@ -481,6 +559,10 @@ sfnt_enum_font_1 (int fd, const char *file,
|
||||||
/* Parse the style. */
|
/* Parse the style. */
|
||||||
sfnt_parse_style (style, desc);
|
sfnt_parse_style (style, desc);
|
||||||
|
|
||||||
|
/* If the meta table exists, parse the list of design languages. */
|
||||||
|
if (meta)
|
||||||
|
sfnt_parse_languages (meta, desc);
|
||||||
|
|
||||||
/* Figure out the spacing. Some fancy test like what Fontconfig
|
/* Figure out the spacing. Some fancy test like what Fontconfig
|
||||||
does is probably in order but not really necessary. */
|
does is probably in order but not really necessary. */
|
||||||
if (!NILP (Fstring_search (Fdowncase (family),
|
if (!NILP (Fstring_search (Fdowncase (family),
|
||||||
|
|
@ -990,11 +1072,10 @@ sfntfont_list_1 (struct sfnt_font_desc *desc, Lisp_Object spec)
|
||||||
desc->family)))
|
desc->family)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Check that no adstyle has been specified. That's a relic from
|
/* Check that the adstyle specified matches. */
|
||||||
the Postscript era. */
|
|
||||||
|
|
||||||
tem = AREF (spec, FONT_ADSTYLE_INDEX);
|
tem = AREF (spec, FONT_ADSTYLE_INDEX);
|
||||||
if (!NILP (tem))
|
if (!NILP (tem) && NILP (Fequal (tem, desc->adstyle)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Check the style. */
|
/* Check the style. */
|
||||||
|
|
@ -1069,6 +1150,11 @@ sfntfont_list_1 (struct sfnt_font_desc *desc, Lisp_Object spec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Now check that the language is supported. */
|
||||||
|
tem = assq_no_quit (QClang, extra);
|
||||||
|
if (!NILP (tem) && NILP (Fmemq (tem, desc->languages)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
/* Set desc->subtable if cmap was specified. */
|
/* Set desc->subtable if cmap was specified. */
|
||||||
if (cmap)
|
if (cmap)
|
||||||
desc->subtable = subtable;
|
desc->subtable = subtable;
|
||||||
|
|
@ -2076,10 +2162,10 @@ sfntfont_text_extents (struct font *font, const unsigned int *code,
|
||||||
|
|
||||||
if (pcm.descent > metrics->descent)
|
if (pcm.descent > metrics->descent)
|
||||||
metrics->descent = pcm.descent;
|
metrics->descent = pcm.descent;
|
||||||
}
|
|
||||||
|
|
||||||
total_width += pcm.width;
|
total_width += pcm.width;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
metrics->width = total_width;
|
metrics->width = total_width;
|
||||||
}
|
}
|
||||||
|
|
@ -2239,6 +2325,9 @@ syms_of_sfntfont (void)
|
||||||
DEFSYM (Qapple_roman, "apple-roman");
|
DEFSYM (Qapple_roman, "apple-roman");
|
||||||
DEFSYM (Qjisx0208_1983_0, "jisx0208.1983-0");
|
DEFSYM (Qjisx0208_1983_0, "jisx0208.1983-0");
|
||||||
DEFSYM (Qksc5601_1987_0, "ksc5601.1987-0");
|
DEFSYM (Qksc5601_1987_0, "ksc5601.1987-0");
|
||||||
|
DEFSYM (Qzh, "zh");
|
||||||
|
DEFSYM (Qja, "ja");
|
||||||
|
DEFSYM (Qko, "ko");
|
||||||
|
|
||||||
/* Char-table purpose. */
|
/* Char-table purpose. */
|
||||||
DEFSYM (Qfont_lookup_cache, "font-lookup-cache");
|
DEFSYM (Qfont_lookup_cache, "font-lookup-cache");
|
||||||
|
|
@ -2269,6 +2358,8 @@ mark_sfntfont (void)
|
||||||
{
|
{
|
||||||
mark_object (desc->family);
|
mark_object (desc->family);
|
||||||
mark_object (desc->style);
|
mark_object (desc->style);
|
||||||
|
mark_object (desc->adstyle);
|
||||||
|
mark_object (desc->languages);
|
||||||
mark_object (desc->char_cache);
|
mark_object (desc->char_cache);
|
||||||
mark_object (desc->designer);
|
mark_object (desc->designer);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,7 @@ orig_faccessat (int fd, char const *name, int mode, int flag)
|
||||||
/* Write "unistd.h" here, not <unistd.h>, otherwise OSF/1 5.1 DTK cc
|
/* Write "unistd.h" here, not <unistd.h>, otherwise OSF/1 5.1 DTK cc
|
||||||
eliminates this include because of the preliminary #include <unistd.h>
|
eliminates this include because of the preliminary #include <unistd.h>
|
||||||
above. */
|
above. */
|
||||||
#ifdef __ANROID__
|
|
||||||
#include <unistd.h>
|
|
||||||
#else
|
|
||||||
#include "unistd.h"
|
#include "unistd.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef HAVE_ACCESS
|
#ifndef HAVE_ACCESS
|
||||||
/* Mingw lacks access, but it also lacks real vs. effective ids, so
|
/* Mingw lacks access, but it also lacks real vs. effective ids, so
|
||||||
|
|
|
||||||
147
xcompile/lib/getdelim.c
Normal file
147
xcompile/lib/getdelim.c
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
/* getdelim.c --- Implementation of replacement getdelim function.
|
||||||
|
Copyright (C) 1994, 1996-1998, 2001, 2003, 2005-2023 Free Software
|
||||||
|
Foundation, Inc.
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Ported from glibc by Simon Josefsson. */
|
||||||
|
|
||||||
|
/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc
|
||||||
|
optimizes away the lineptr == NULL || n == NULL || fp == NULL tests below. */
|
||||||
|
#define _GL_ARG_NONNULL(params)
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#ifndef SSIZE_MAX
|
||||||
|
# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if USE_UNLOCKED_IO
|
||||||
|
# include "unlocked-io.h"
|
||||||
|
# define getc_maybe_unlocked(fp) getc(fp)
|
||||||
|
#elif !HAVE_FLOCKFILE || !HAVE_FUNLOCKFILE || !HAVE_DECL_GETC_UNLOCKED
|
||||||
|
# undef flockfile
|
||||||
|
# undef funlockfile
|
||||||
|
# define flockfile(x) ((void) 0)
|
||||||
|
# define funlockfile(x) ((void) 0)
|
||||||
|
# define getc_maybe_unlocked(fp) getc(fp)
|
||||||
|
#else
|
||||||
|
# define getc_maybe_unlocked(fp) getc_unlocked(fp)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
alloc_failed (void)
|
||||||
|
{
|
||||||
|
#if defined _WIN32 && ! defined __CYGWIN__
|
||||||
|
/* Avoid errno problem without using the realloc module; see:
|
||||||
|
https://lists.gnu.org/r/bug-gnulib/2016-08/msg00025.html */
|
||||||
|
errno = ENOMEM;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read up to (and including) a DELIMITER from FP into *LINEPTR (and
|
||||||
|
NUL-terminate it). *LINEPTR is a pointer returned from malloc (or
|
||||||
|
NULL), pointing to *N characters of space. It is realloc'ed as
|
||||||
|
necessary. Returns the number of characters read (not including
|
||||||
|
the null terminator), or -1 on error or EOF. */
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp)
|
||||||
|
{
|
||||||
|
ssize_t result;
|
||||||
|
size_t cur_len = 0;
|
||||||
|
|
||||||
|
if (lineptr == NULL || n == NULL || fp == NULL)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
flockfile (fp);
|
||||||
|
|
||||||
|
if (*lineptr == NULL || *n == 0)
|
||||||
|
{
|
||||||
|
char *new_lineptr;
|
||||||
|
*n = 120;
|
||||||
|
new_lineptr = (char *) realloc (*lineptr, *n);
|
||||||
|
if (new_lineptr == NULL)
|
||||||
|
{
|
||||||
|
alloc_failed ();
|
||||||
|
result = -1;
|
||||||
|
goto unlock_return;
|
||||||
|
}
|
||||||
|
*lineptr = new_lineptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = getc_maybe_unlocked (fp);
|
||||||
|
if (i == EOF)
|
||||||
|
{
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make enough space for len+1 (for final NUL) bytes. */
|
||||||
|
if (cur_len + 1 >= *n)
|
||||||
|
{
|
||||||
|
size_t needed_max =
|
||||||
|
SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX;
|
||||||
|
size_t needed = 2 * *n + 1; /* Be generous. */
|
||||||
|
char *new_lineptr;
|
||||||
|
|
||||||
|
if (needed_max < needed)
|
||||||
|
needed = needed_max;
|
||||||
|
if (cur_len + 1 >= needed)
|
||||||
|
{
|
||||||
|
result = -1;
|
||||||
|
errno = EOVERFLOW;
|
||||||
|
goto unlock_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_lineptr = (char *) realloc (*lineptr, needed);
|
||||||
|
if (new_lineptr == NULL)
|
||||||
|
{
|
||||||
|
alloc_failed ();
|
||||||
|
result = -1;
|
||||||
|
goto unlock_return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*lineptr = new_lineptr;
|
||||||
|
*n = needed;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*lineptr)[cur_len] = i;
|
||||||
|
cur_len++;
|
||||||
|
|
||||||
|
if (i == delimiter)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(*lineptr)[cur_len] = '\0';
|
||||||
|
result = cur_len ? cur_len : result;
|
||||||
|
|
||||||
|
unlock_return:
|
||||||
|
funlockfile (fp); /* doesn't set errno */
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
27
xcompile/lib/getline.c
Normal file
27
xcompile/lib/getline.c
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* getline.c --- Implementation of replacement getline function.
|
||||||
|
Copyright (C) 2005-2007, 2009-2023 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This file is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Lesser General Public License as
|
||||||
|
published by the Free Software Foundation; either version 2.1 of the
|
||||||
|
License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This file is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Written by Simon Josefsson. */
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
getline (char **lineptr, size_t *n, FILE *stream)
|
||||||
|
{
|
||||||
|
return getdelim (lineptr, n, '\n', stream);
|
||||||
|
}
|
||||||
|
|
@ -109,6 +109,7 @@
|
||||||
# fsusage \
|
# fsusage \
|
||||||
# fsync \
|
# fsync \
|
||||||
# futimens \
|
# futimens \
|
||||||
|
# getline \
|
||||||
# getloadavg \
|
# getloadavg \
|
||||||
# getopt-gnu \
|
# getopt-gnu \
|
||||||
# getrandom \
|
# getrandom \
|
||||||
|
|
@ -172,11 +173,19 @@
|
||||||
|
|
||||||
MOSTLYCLEANFILES += core *.stackdump
|
MOSTLYCLEANFILES += core *.stackdump
|
||||||
# Start of GNU Make output.
|
# Start of GNU Make output.
|
||||||
|
AAPT = @AAPT@
|
||||||
ALLOCA = @ALLOCA@
|
ALLOCA = @ALLOCA@
|
||||||
ALLOCA_H = @ALLOCA_H@
|
ALLOCA_H = @ALLOCA_H@
|
||||||
ALSA_CFLAGS = @ALSA_CFLAGS@
|
ALSA_CFLAGS = @ALSA_CFLAGS@
|
||||||
ALSA_LIBS = @ALSA_LIBS@
|
ALSA_LIBS = @ALSA_LIBS@
|
||||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||||
|
ANDROID = @ANDROID@
|
||||||
|
ANDROID_ABI = @ANDROID_ABI@
|
||||||
|
ANDROID_CFLAGS = @ANDROID_CFLAGS@
|
||||||
|
ANDROID_JAR = @ANDROID_JAR@
|
||||||
|
ANDROID_LIBS = @ANDROID_LIBS@
|
||||||
|
ANDROID_MIN_SDK = @ANDROID_MIN_SDK@
|
||||||
|
ANDROID_OBJ = @ANDROID_OBJ@
|
||||||
APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@
|
APPLE_UNIVERSAL_BUILD = @APPLE_UNIVERSAL_BUILD@
|
||||||
AR = @AR@
|
AR = @AR@
|
||||||
ARFLAGS = @ARFLAGS@
|
ARFLAGS = @ARFLAGS@
|
||||||
|
|
@ -216,6 +225,7 @@ CYGWIN_OBJ = @CYGWIN_OBJ@
|
||||||
C_SWITCH_MACHINE = @C_SWITCH_MACHINE@
|
C_SWITCH_MACHINE = @C_SWITCH_MACHINE@
|
||||||
C_SWITCH_SYSTEM = @C_SWITCH_SYSTEM@
|
C_SWITCH_SYSTEM = @C_SWITCH_SYSTEM@
|
||||||
C_SWITCH_X_SITE = @C_SWITCH_X_SITE@
|
C_SWITCH_X_SITE = @C_SWITCH_X_SITE@
|
||||||
|
D8 = @D8@
|
||||||
DBUS_CFLAGS = @DBUS_CFLAGS@
|
DBUS_CFLAGS = @DBUS_CFLAGS@
|
||||||
DBUS_LIBS = @DBUS_LIBS@
|
DBUS_LIBS = @DBUS_LIBS@
|
||||||
DBUS_OBJ = @DBUS_OBJ@
|
DBUS_OBJ = @DBUS_OBJ@
|
||||||
|
|
@ -278,8 +288,10 @@ GL_COND_OBJ_FSTATAT_CONDITION = @GL_COND_OBJ_FSTATAT_CONDITION@
|
||||||
GL_COND_OBJ_FSUSAGE_CONDITION = @GL_COND_OBJ_FSUSAGE_CONDITION@
|
GL_COND_OBJ_FSUSAGE_CONDITION = @GL_COND_OBJ_FSUSAGE_CONDITION@
|
||||||
GL_COND_OBJ_FSYNC_CONDITION = @GL_COND_OBJ_FSYNC_CONDITION@
|
GL_COND_OBJ_FSYNC_CONDITION = @GL_COND_OBJ_FSYNC_CONDITION@
|
||||||
GL_COND_OBJ_FUTIMENS_CONDITION = @GL_COND_OBJ_FUTIMENS_CONDITION@
|
GL_COND_OBJ_FUTIMENS_CONDITION = @GL_COND_OBJ_FUTIMENS_CONDITION@
|
||||||
|
GL_COND_OBJ_GETDELIM_CONDITION = @GL_COND_OBJ_GETDELIM_CONDITION@
|
||||||
GL_COND_OBJ_GETDTABLESIZE_CONDITION = @GL_COND_OBJ_GETDTABLESIZE_CONDITION@
|
GL_COND_OBJ_GETDTABLESIZE_CONDITION = @GL_COND_OBJ_GETDTABLESIZE_CONDITION@
|
||||||
GL_COND_OBJ_GETGROUPS_CONDITION = @GL_COND_OBJ_GETGROUPS_CONDITION@
|
GL_COND_OBJ_GETGROUPS_CONDITION = @GL_COND_OBJ_GETGROUPS_CONDITION@
|
||||||
|
GL_COND_OBJ_GETLINE_CONDITION = @GL_COND_OBJ_GETLINE_CONDITION@
|
||||||
GL_COND_OBJ_GETLOADAVG_CONDITION = @GL_COND_OBJ_GETLOADAVG_CONDITION@
|
GL_COND_OBJ_GETLOADAVG_CONDITION = @GL_COND_OBJ_GETLOADAVG_CONDITION@
|
||||||
GL_COND_OBJ_GETOPT_CONDITION = @GL_COND_OBJ_GETOPT_CONDITION@
|
GL_COND_OBJ_GETOPT_CONDITION = @GL_COND_OBJ_GETOPT_CONDITION@
|
||||||
GL_COND_OBJ_GETRANDOM_CONDITION = @GL_COND_OBJ_GETRANDOM_CONDITION@
|
GL_COND_OBJ_GETRANDOM_CONDITION = @GL_COND_OBJ_GETRANDOM_CONDITION@
|
||||||
|
|
@ -883,6 +895,8 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||||
INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@
|
INT32_MAX_LT_INTMAX_MAX = @INT32_MAX_LT_INTMAX_MAX@
|
||||||
INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@
|
INT64_MAX_EQ_LONG_MAX = @INT64_MAX_EQ_LONG_MAX@
|
||||||
|
JARSIGNER = @JARSIGNER@
|
||||||
|
JAVAC = @JAVAC@
|
||||||
JSON_CFLAGS = @JSON_CFLAGS@
|
JSON_CFLAGS = @JSON_CFLAGS@
|
||||||
JSON_LIBS = @JSON_LIBS@
|
JSON_LIBS = @JSON_LIBS@
|
||||||
JSON_OBJ = @JSON_OBJ@
|
JSON_OBJ = @JSON_OBJ@
|
||||||
|
|
@ -949,6 +963,7 @@ LIB_PTHREAD = @LIB_PTHREAD@
|
||||||
LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@
|
LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@
|
||||||
LIB_TIMER_TIME = @LIB_TIMER_TIME@
|
LIB_TIMER_TIME = @LIB_TIMER_TIME@
|
||||||
LIB_WSOCK32 = @LIB_WSOCK32@
|
LIB_WSOCK32 = @LIB_WSOCK32@
|
||||||
|
LIB_XATTR = @LIB_XATTR@
|
||||||
LIMITS_H = @LIMITS_H@
|
LIMITS_H = @LIMITS_H@
|
||||||
LN_S_FILEONLY = @LN_S_FILEONLY@
|
LN_S_FILEONLY = @LN_S_FILEONLY@
|
||||||
LTLIBGMP = @LTLIBGMP@
|
LTLIBGMP = @LTLIBGMP@
|
||||||
|
|
@ -1041,6 +1056,7 @@ PROFILING_CFLAGS = @PROFILING_CFLAGS@
|
||||||
PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@
|
PTHREAD_H_DEFINES_STRUCT_TIMESPEC = @PTHREAD_H_DEFINES_STRUCT_TIMESPEC@
|
||||||
PTHREAD_SIGMASK_LIB = @PTHREAD_SIGMASK_LIB@
|
PTHREAD_SIGMASK_LIB = @PTHREAD_SIGMASK_LIB@
|
||||||
PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
|
PTRDIFF_T_SUFFIX = @PTRDIFF_T_SUFFIX@
|
||||||
|
QCOPY_ACL_LIB = @QCOPY_ACL_LIB@
|
||||||
RALLOC_OBJ = @RALLOC_OBJ@
|
RALLOC_OBJ = @RALLOC_OBJ@
|
||||||
RANLIB = @RANLIB@
|
RANLIB = @RANLIB@
|
||||||
REPLACE_ACCESS = @REPLACE_ACCESS@
|
REPLACE_ACCESS = @REPLACE_ACCESS@
|
||||||
|
|
@ -1209,6 +1225,7 @@ REPLACE_WCTOMB = @REPLACE_WCTOMB@
|
||||||
REPLACE_WRITE = @REPLACE_WRITE@
|
REPLACE_WRITE = @REPLACE_WRITE@
|
||||||
RSVG_CFLAGS = @RSVG_CFLAGS@
|
RSVG_CFLAGS = @RSVG_CFLAGS@
|
||||||
RSVG_LIBS = @RSVG_LIBS@
|
RSVG_LIBS = @RSVG_LIBS@
|
||||||
|
SDK_BULD_TOOLS = @SDK_BULD_TOOLS@
|
||||||
SEPCHAR = @SEPCHAR@
|
SEPCHAR = @SEPCHAR@
|
||||||
SETFATTR = @SETFATTR@
|
SETFATTR = @SETFATTR@
|
||||||
SETTINGS_CFLAGS = @SETTINGS_CFLAGS@
|
SETTINGS_CFLAGS = @SETTINGS_CFLAGS@
|
||||||
|
|
@ -1266,6 +1283,7 @@ XARGS_LIMIT = @XARGS_LIMIT@
|
||||||
XCB_LIBS = @XCB_LIBS@
|
XCB_LIBS = @XCB_LIBS@
|
||||||
XCOMPOSITE_CFLAGS = @XCOMPOSITE_CFLAGS@
|
XCOMPOSITE_CFLAGS = @XCOMPOSITE_CFLAGS@
|
||||||
XCOMPOSITE_LIBS = @XCOMPOSITE_LIBS@
|
XCOMPOSITE_LIBS = @XCOMPOSITE_LIBS@
|
||||||
|
XCONFIGURE = @XCONFIGURE@
|
||||||
XCRUN = @XCRUN@
|
XCRUN = @XCRUN@
|
||||||
XDBE_CFLAGS = @XDBE_CFLAGS@
|
XDBE_CFLAGS = @XDBE_CFLAGS@
|
||||||
XDBE_LIBS = @XDBE_LIBS@
|
XDBE_LIBS = @XDBE_LIBS@
|
||||||
|
|
@ -1290,6 +1308,7 @@ XSYNC_CFLAGS = @XSYNC_CFLAGS@
|
||||||
XSYNC_LIBS = @XSYNC_LIBS@
|
XSYNC_LIBS = @XSYNC_LIBS@
|
||||||
XWIDGETS_OBJ = @XWIDGETS_OBJ@
|
XWIDGETS_OBJ = @XWIDGETS_OBJ@
|
||||||
X_TOOLKIT_TYPE = @X_TOOLKIT_TYPE@
|
X_TOOLKIT_TYPE = @X_TOOLKIT_TYPE@
|
||||||
|
ZIPALIGN = @ZIPALIGN@
|
||||||
ac_ct_CC = @ac_ct_CC@
|
ac_ct_CC = @ac_ct_CC@
|
||||||
ac_ct_CXX = @ac_ct_CXX@
|
ac_ct_CXX = @ac_ct_CXX@
|
||||||
ac_ct_OBJC = @ac_ct_OBJC@
|
ac_ct_OBJC = @ac_ct_OBJC@
|
||||||
|
|
@ -1335,6 +1354,7 @@ gl_GNULIB_ENABLED_e80bf6f757095d2e5fc94dafb8f8fc8b_CONDITION = @gl_GNULIB_ENABLE
|
||||||
gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866_CONDITION = @gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866_CONDITION@
|
gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866_CONDITION = @gl_GNULIB_ENABLED_ef455225c00f5049c808c2eda3e76866_CONDITION@
|
||||||
gl_GNULIB_ENABLED_euidaccess_CONDITION = @gl_GNULIB_ENABLED_euidaccess_CONDITION@
|
gl_GNULIB_ENABLED_euidaccess_CONDITION = @gl_GNULIB_ENABLED_euidaccess_CONDITION@
|
||||||
gl_GNULIB_ENABLED_fd38c7e463b54744b77b98aeafb4fa7c_CONDITION = @gl_GNULIB_ENABLED_fd38c7e463b54744b77b98aeafb4fa7c_CONDITION@
|
gl_GNULIB_ENABLED_fd38c7e463b54744b77b98aeafb4fa7c_CONDITION = @gl_GNULIB_ENABLED_fd38c7e463b54744b77b98aeafb4fa7c_CONDITION@
|
||||||
|
gl_GNULIB_ENABLED_getdelim_CONDITION = @gl_GNULIB_ENABLED_getdelim_CONDITION@
|
||||||
gl_GNULIB_ENABLED_getdtablesize_CONDITION = @gl_GNULIB_ENABLED_getdtablesize_CONDITION@
|
gl_GNULIB_ENABLED_getdtablesize_CONDITION = @gl_GNULIB_ENABLED_getdtablesize_CONDITION@
|
||||||
gl_GNULIB_ENABLED_getgroups_CONDITION = @gl_GNULIB_ENABLED_getgroups_CONDITION@
|
gl_GNULIB_ENABLED_getgroups_CONDITION = @gl_GNULIB_ENABLED_getgroups_CONDITION@
|
||||||
gl_GNULIB_ENABLED_lchmod_CONDITION = @gl_GNULIB_ENABLED_lchmod_CONDITION@
|
gl_GNULIB_ENABLED_lchmod_CONDITION = @gl_GNULIB_ENABLED_lchmod_CONDITION@
|
||||||
|
|
@ -2091,6 +2111,18 @@ gl_V_at = $(AM_V_GEN)
|
||||||
endif
|
endif
|
||||||
## end gnulib module gen-header
|
## end gnulib module gen-header
|
||||||
|
|
||||||
|
## begin gnulib module getdelim
|
||||||
|
ifeq (,$(OMIT_GNULIB_MODULE_getdelim))
|
||||||
|
|
||||||
|
ifneq (,$(gl_GNULIB_ENABLED_getdelim_CONDITION))
|
||||||
|
ifneq (,$(GL_COND_OBJ_GETDELIM_CONDITION))
|
||||||
|
libgnu_a_SOURCES += getdelim.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
## end gnulib module getdelim
|
||||||
|
|
||||||
## begin gnulib module getdtablesize
|
## begin gnulib module getdtablesize
|
||||||
ifeq (,$(OMIT_GNULIB_MODULE_getdtablesize))
|
ifeq (,$(OMIT_GNULIB_MODULE_getdtablesize))
|
||||||
|
|
||||||
|
|
@ -2115,6 +2147,16 @@ endif
|
||||||
endif
|
endif
|
||||||
## end gnulib module getgroups
|
## end gnulib module getgroups
|
||||||
|
|
||||||
|
## begin gnulib module getline
|
||||||
|
ifeq (,$(OMIT_GNULIB_MODULE_getline))
|
||||||
|
|
||||||
|
ifneq (,$(GL_COND_OBJ_GETLINE_CONDITION))
|
||||||
|
libgnu_a_SOURCES += getline.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
endif
|
||||||
|
## end gnulib module getline
|
||||||
|
|
||||||
## begin gnulib module getloadavg
|
## begin gnulib module getloadavg
|
||||||
ifeq (,$(OMIT_GNULIB_MODULE_getloadavg))
|
ifeq (,$(OMIT_GNULIB_MODULE_getloadavg))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,20 @@
|
||||||
|
|
||||||
#include "acl-internal.h"
|
#include "acl-internal.h"
|
||||||
|
|
||||||
|
#if USE_XATTR
|
||||||
|
|
||||||
|
# include <attr/libattr.h>
|
||||||
|
|
||||||
|
/* Returns 1 if NAME is the name of an extended attribute that is related
|
||||||
|
to permissions, i.e. ACLs. Returns 0 otherwise. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
is_attr_permissions (const char *name, struct error_context *ctx)
|
||||||
|
{
|
||||||
|
return attr_copy_action (name, ctx) == ATTR_ACTION_PERMISSIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* USE_XATTR */
|
||||||
|
|
||||||
/* Copy access control lists from one file to another. If SOURCE_DESC is
|
/* Copy access control lists from one file to another. If SOURCE_DESC is
|
||||||
a valid file descriptor, use file descriptor operations, else use
|
a valid file descriptor, use file descriptor operations, else use
|
||||||
|
|
@ -39,13 +53,33 @@ int
|
||||||
qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
|
qcopy_acl (const char *src_name, int source_desc, const char *dst_name,
|
||||||
int dest_desc, mode_t mode)
|
int dest_desc, mode_t mode)
|
||||||
{
|
{
|
||||||
struct permission_context ctx;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
#ifdef USE_XATTR
|
||||||
|
/* in case no ACLs present and also to set higher mode bits
|
||||||
|
we chmod before setting ACLs as doing it after could overwrite them
|
||||||
|
(especially true for NFSv4, posix ACL has that ugly "mask" hack that
|
||||||
|
nobody understands) */
|
||||||
|
ret = chmod_or_fchmod (dst_name, dest_desc, mode);
|
||||||
|
/* Rather than fiddling with acls one by one, we just copy the whole ACL xattrs
|
||||||
|
(Posix or NFSv4). Of course, that won't address ACLs conversion
|
||||||
|
(i.e. posix <-> nfs4) but we can't do it anyway, so for now, we don't care
|
||||||
|
Functions attr_copy_* return 0 in case we copied something OR nothing
|
||||||
|
to copy */
|
||||||
|
if (ret == 0)
|
||||||
|
ret = source_desc <= 0 || dest_desc <= 0
|
||||||
|
? attr_copy_file (src_name, dst_name, is_attr_permissions, NULL)
|
||||||
|
: attr_copy_fd (src_name, source_desc, dst_name, dest_desc,
|
||||||
|
is_attr_permissions, NULL);
|
||||||
|
#else
|
||||||
|
/* no XATTR, so we proceed the old dusty way */
|
||||||
|
struct permission_context ctx;
|
||||||
|
|
||||||
ret = get_permissions (src_name, source_desc, mode, &ctx);
|
ret = get_permissions (src_name, source_desc, mode, &ctx);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return -2;
|
return -2;
|
||||||
ret = set_permissions (&ctx, dst_name, dest_desc);
|
ret = set_permissions (&ctx, dst_name, dest_desc);
|
||||||
free_permission_context (&ctx);
|
free_permission_context (&ctx);
|
||||||
|
#endif
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -258,7 +258,9 @@ template <int w>
|
||||||
|
|
||||||
/* @assert.h omit start@ */
|
/* @assert.h omit start@ */
|
||||||
|
|
||||||
#if 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__))
|
#if defined __clang_major__ && __clang_major__ < 5
|
||||||
|
# define _GL_HAS_BUILTIN_TRAP 0
|
||||||
|
#elif 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__))
|
||||||
# define _GL_HAS_BUILTIN_TRAP 1
|
# define _GL_HAS_BUILTIN_TRAP 1
|
||||||
#elif defined __has_builtin
|
#elif defined __has_builtin
|
||||||
# define _GL_HAS_BUILTIN_TRAP __has_builtin (__builtin_trap)
|
# define _GL_HAS_BUILTIN_TRAP __has_builtin (__builtin_trap)
|
||||||
|
|
@ -266,7 +268,9 @@ template <int w>
|
||||||
# define _GL_HAS_BUILTIN_TRAP 0
|
# define _GL_HAS_BUILTIN_TRAP 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
|
#if defined __clang_major__ && __clang_major__ < 5
|
||||||
|
# define _GL_HAS_BUILTIN_UNREACHABLE 0
|
||||||
|
#elif 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
|
||||||
# define _GL_HAS_BUILTIN_UNREACHABLE 1
|
# define _GL_HAS_BUILTIN_UNREACHABLE 1
|
||||||
#elif defined __has_builtin
|
#elif defined __has_builtin
|
||||||
# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
|
# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
|
||||||
|
|
|
||||||
528
xcompile/malloc/dynarray-skeleton.c
Normal file
528
xcompile/malloc/dynarray-skeleton.c
Normal file
|
|
@ -0,0 +1,528 @@
|
||||||
|
/* Type-safe arrays which grow dynamically.
|
||||||
|
Copyright (C) 2017-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* Pre-processor macros which act as parameters:
|
||||||
|
|
||||||
|
DYNARRAY_STRUCT
|
||||||
|
The struct tag of dynamic array to be defined.
|
||||||
|
DYNARRAY_ELEMENT
|
||||||
|
The type name of the element type. Elements are copied
|
||||||
|
as if by memcpy, and can change address as the dynamic
|
||||||
|
array grows.
|
||||||
|
DYNARRAY_PREFIX
|
||||||
|
The prefix of the functions which are defined.
|
||||||
|
|
||||||
|
The following parameters are optional:
|
||||||
|
|
||||||
|
DYNARRAY_ELEMENT_FREE
|
||||||
|
DYNARRAY_ELEMENT_FREE (E) is evaluated to deallocate the
|
||||||
|
contents of elements. E is of type DYNARRAY_ELEMENT *.
|
||||||
|
DYNARRAY_ELEMENT_INIT
|
||||||
|
DYNARRAY_ELEMENT_INIT (E) is evaluated to initialize a new
|
||||||
|
element. E is of type DYNARRAY_ELEMENT *.
|
||||||
|
If DYNARRAY_ELEMENT_FREE but not DYNARRAY_ELEMENT_INIT is
|
||||||
|
defined, new elements are automatically zero-initialized.
|
||||||
|
Otherwise, new elements have undefined contents.
|
||||||
|
DYNARRAY_INITIAL_SIZE
|
||||||
|
The size of the statically allocated array (default:
|
||||||
|
at least 2, more elements if they fit into 128 bytes).
|
||||||
|
Must be a preprocessor constant. If DYNARRAY_INITIAL_SIZE is 0,
|
||||||
|
there is no statically allocated array at, and all non-empty
|
||||||
|
arrays are heap-allocated.
|
||||||
|
DYNARRAY_FINAL_TYPE
|
||||||
|
The name of the type which holds the final array. If not
|
||||||
|
defined, is PREFIX##finalize not provided. DYNARRAY_FINAL_TYPE
|
||||||
|
must be a struct type, with members of type DYNARRAY_ELEMENT and
|
||||||
|
size_t at the start (in this order).
|
||||||
|
|
||||||
|
These macros are undefined after this header file has been
|
||||||
|
included.
|
||||||
|
|
||||||
|
The following types are provided (their members are private to the
|
||||||
|
dynarray implementation):
|
||||||
|
|
||||||
|
struct DYNARRAY_STRUCT
|
||||||
|
|
||||||
|
The following functions are provided:
|
||||||
|
|
||||||
|
void DYNARRAY_PREFIX##init (struct DYNARRAY_STRUCT *);
|
||||||
|
void DYNARRAY_PREFIX##free (struct DYNARRAY_STRUCT *);
|
||||||
|
bool DYNARRAY_PREFIX##has_failed (const struct DYNARRAY_STRUCT *);
|
||||||
|
void DYNARRAY_PREFIX##mark_failed (struct DYNARRAY_STRUCT *);
|
||||||
|
size_t DYNARRAY_PREFIX##size (const struct DYNARRAY_STRUCT *);
|
||||||
|
DYNARRAY_ELEMENT *DYNARRAY_PREFIX##begin (const struct DYNARRAY_STRUCT *);
|
||||||
|
DYNARRAY_ELEMENT *DYNARRAY_PREFIX##end (const struct DYNARRAY_STRUCT *);
|
||||||
|
DYNARRAY_ELEMENT *DYNARRAY_PREFIX##at (struct DYNARRAY_STRUCT *, size_t);
|
||||||
|
void DYNARRAY_PREFIX##add (struct DYNARRAY_STRUCT *, DYNARRAY_ELEMENT);
|
||||||
|
DYNARRAY_ELEMENT *DYNARRAY_PREFIX##emplace (struct DYNARRAY_STRUCT *);
|
||||||
|
bool DYNARRAY_PREFIX##resize (struct DYNARRAY_STRUCT *, size_t);
|
||||||
|
void DYNARRAY_PREFIX##remove_last (struct DYNARRAY_STRUCT *);
|
||||||
|
void DYNARRAY_PREFIX##clear (struct DYNARRAY_STRUCT *);
|
||||||
|
|
||||||
|
The following functions are provided are provided if the
|
||||||
|
prerequisites are met:
|
||||||
|
|
||||||
|
bool DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *,
|
||||||
|
DYNARRAY_FINAL_TYPE *);
|
||||||
|
(if DYNARRAY_FINAL_TYPE is defined)
|
||||||
|
DYNARRAY_ELEMENT *DYNARRAY_PREFIX##finalize (struct DYNARRAY_STRUCT *,
|
||||||
|
size_t *);
|
||||||
|
(if DYNARRAY_FINAL_TYPE is not defined)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <malloc/dynarray.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef DYNARRAY_STRUCT
|
||||||
|
# error "DYNARRAY_STRUCT must be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DYNARRAY_ELEMENT
|
||||||
|
# error "DYNARRAY_ELEMENT must be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef DYNARRAY_PREFIX
|
||||||
|
# error "DYNARRAY_PREFIX must be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DYNARRAY_INITIAL_SIZE
|
||||||
|
# if DYNARRAY_INITIAL_SIZE < 0
|
||||||
|
# error "DYNARRAY_INITIAL_SIZE must be non-negative"
|
||||||
|
# endif
|
||||||
|
# if DYNARRAY_INITIAL_SIZE > 0
|
||||||
|
# define DYNARRAY_HAVE_SCRATCH 1
|
||||||
|
# else
|
||||||
|
# define DYNARRAY_HAVE_SCRATCH 0
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
/* Provide a reasonable default which limits the size of
|
||||||
|
DYNARRAY_STRUCT. */
|
||||||
|
# define DYNARRAY_INITIAL_SIZE \
|
||||||
|
(sizeof (DYNARRAY_ELEMENT) > 64 ? 2 : 128 / sizeof (DYNARRAY_ELEMENT))
|
||||||
|
# define DYNARRAY_HAVE_SCRATCH 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Public type definitions. */
|
||||||
|
|
||||||
|
/* All fields of this struct are private to the implementation. */
|
||||||
|
struct DYNARRAY_STRUCT
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct dynarray_header dynarray_abstract;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/* These fields must match struct dynarray_header. */
|
||||||
|
size_t used;
|
||||||
|
size_t allocated;
|
||||||
|
DYNARRAY_ELEMENT *array;
|
||||||
|
} dynarray_header;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
#if DYNARRAY_HAVE_SCRATCH
|
||||||
|
/* Initial inline allocation. */
|
||||||
|
DYNARRAY_ELEMENT scratch[DYNARRAY_INITIAL_SIZE];
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Internal use only: Helper macros. */
|
||||||
|
|
||||||
|
/* Ensure macro-expansion of DYNARRAY_PREFIX. */
|
||||||
|
#define DYNARRAY_CONCAT0(prefix, name) prefix##name
|
||||||
|
#define DYNARRAY_CONCAT1(prefix, name) DYNARRAY_CONCAT0(prefix, name)
|
||||||
|
#define DYNARRAY_NAME(name) DYNARRAY_CONCAT1(DYNARRAY_PREFIX, name)
|
||||||
|
|
||||||
|
/* Use DYNARRAY_FREE instead of DYNARRAY_NAME (free),
|
||||||
|
so that Gnulib does not change 'free' to 'rpl_free'. */
|
||||||
|
#define DYNARRAY_FREE DYNARRAY_CONCAT1 (DYNARRAY_NAME (f), ree)
|
||||||
|
|
||||||
|
/* Address of the scratch buffer if any. */
|
||||||
|
#if DYNARRAY_HAVE_SCRATCH
|
||||||
|
# define DYNARRAY_SCRATCH(list) (list)->scratch
|
||||||
|
#else
|
||||||
|
# define DYNARRAY_SCRATCH(list) NULL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Internal use only: Helper functions. */
|
||||||
|
|
||||||
|
/* Internal function. Call DYNARRAY_ELEMENT_FREE with the array
|
||||||
|
elements. Name mangling needed due to the DYNARRAY_ELEMENT_FREE
|
||||||
|
macro expansion. */
|
||||||
|
static inline void
|
||||||
|
DYNARRAY_NAME (free__elements__) (DYNARRAY_ELEMENT *__dynarray_array,
|
||||||
|
size_t __dynarray_used)
|
||||||
|
{
|
||||||
|
#ifdef DYNARRAY_ELEMENT_FREE
|
||||||
|
for (size_t __dynarray_i = 0; __dynarray_i < __dynarray_used; ++__dynarray_i)
|
||||||
|
DYNARRAY_ELEMENT_FREE (&__dynarray_array[__dynarray_i]);
|
||||||
|
#endif /* DYNARRAY_ELEMENT_FREE */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal function. Free the non-scratch array allocation. */
|
||||||
|
static inline void
|
||||||
|
DYNARRAY_NAME (free__array__) (struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
#if DYNARRAY_HAVE_SCRATCH
|
||||||
|
if (list->u.dynarray_header.array != list->scratch)
|
||||||
|
free (list->u.dynarray_header.array);
|
||||||
|
#else
|
||||||
|
free (list->u.dynarray_header.array);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Public functions. */
|
||||||
|
|
||||||
|
/* Initialize a dynamic array object. This must be called before any
|
||||||
|
use of the object. */
|
||||||
|
__attribute_nonnull__ ((1))
|
||||||
|
static void
|
||||||
|
DYNARRAY_NAME (init) (struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
list->u.dynarray_header.used = 0;
|
||||||
|
list->u.dynarray_header.allocated = DYNARRAY_INITIAL_SIZE;
|
||||||
|
list->u.dynarray_header.array = DYNARRAY_SCRATCH (list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deallocate the dynamic array and its elements. */
|
||||||
|
__attribute_maybe_unused__ __attribute_nonnull__ ((1))
|
||||||
|
static void
|
||||||
|
DYNARRAY_FREE (struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
DYNARRAY_NAME (free__elements__)
|
||||||
|
(list->u.dynarray_header.array, list->u.dynarray_header.used);
|
||||||
|
DYNARRAY_NAME (free__array__) (list);
|
||||||
|
DYNARRAY_NAME (init) (list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return true if the dynamic array is in an error state. */
|
||||||
|
__attribute_nonnull__ ((1))
|
||||||
|
static inline bool
|
||||||
|
DYNARRAY_NAME (has_failed) (const struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
return list->u.dynarray_header.allocated == __dynarray_error_marker ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark the dynamic array as failed. All elements are deallocated as
|
||||||
|
a side effect. */
|
||||||
|
__attribute_nonnull__ ((1))
|
||||||
|
static void
|
||||||
|
DYNARRAY_NAME (mark_failed) (struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
DYNARRAY_NAME (free__elements__)
|
||||||
|
(list->u.dynarray_header.array, list->u.dynarray_header.used);
|
||||||
|
DYNARRAY_NAME (free__array__) (list);
|
||||||
|
list->u.dynarray_header.array = DYNARRAY_SCRATCH (list);
|
||||||
|
list->u.dynarray_header.used = 0;
|
||||||
|
list->u.dynarray_header.allocated = __dynarray_error_marker ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the number of elements which have been added to the dynamic
|
||||||
|
array. */
|
||||||
|
__attribute_nonnull__ ((1))
|
||||||
|
static inline size_t
|
||||||
|
DYNARRAY_NAME (size) (const struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
return list->u.dynarray_header.used;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a pointer to the array element at INDEX. Terminate the
|
||||||
|
process if INDEX is out of bounds. */
|
||||||
|
__attribute_nonnull__ ((1))
|
||||||
|
static inline DYNARRAY_ELEMENT *
|
||||||
|
DYNARRAY_NAME (at) (struct DYNARRAY_STRUCT *list, size_t index)
|
||||||
|
{
|
||||||
|
if (__glibc_unlikely (index >= DYNARRAY_NAME (size) (list)))
|
||||||
|
__libc_dynarray_at_failure (DYNARRAY_NAME (size) (list), index);
|
||||||
|
return list->u.dynarray_header.array + index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a pointer to the first array element, if any. For a
|
||||||
|
zero-length array, the pointer can be NULL even though the dynamic
|
||||||
|
array has not entered the failure state. */
|
||||||
|
__attribute_nonnull__ ((1))
|
||||||
|
static inline DYNARRAY_ELEMENT *
|
||||||
|
DYNARRAY_NAME (begin) (struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
return list->u.dynarray_header.array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a pointer one element past the last array element. For a
|
||||||
|
zero-length array, the pointer can be NULL even though the dynamic
|
||||||
|
array has not entered the failure state. */
|
||||||
|
__attribute_nonnull__ ((1))
|
||||||
|
static inline DYNARRAY_ELEMENT *
|
||||||
|
DYNARRAY_NAME (end) (struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
return list->u.dynarray_header.array + list->u.dynarray_header.used;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal function. Slow path for the add function below. */
|
||||||
|
static void
|
||||||
|
DYNARRAY_NAME (add__) (struct DYNARRAY_STRUCT *list, DYNARRAY_ELEMENT item)
|
||||||
|
{
|
||||||
|
if (__glibc_unlikely
|
||||||
|
(!__libc_dynarray_emplace_enlarge (&list->u.dynarray_abstract,
|
||||||
|
DYNARRAY_SCRATCH (list),
|
||||||
|
sizeof (DYNARRAY_ELEMENT))))
|
||||||
|
{
|
||||||
|
DYNARRAY_NAME (mark_failed) (list);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the new element and increase the array length. */
|
||||||
|
list->u.dynarray_header.array[list->u.dynarray_header.used++] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add ITEM at the end of the array, enlarging it by one element.
|
||||||
|
Mark *LIST as failed if the dynamic array allocation size cannot be
|
||||||
|
increased. */
|
||||||
|
__attribute_nonnull__ ((1))
|
||||||
|
static inline void
|
||||||
|
DYNARRAY_NAME (add) (struct DYNARRAY_STRUCT *list, DYNARRAY_ELEMENT item)
|
||||||
|
{
|
||||||
|
/* Do nothing in case of previous error. */
|
||||||
|
if (DYNARRAY_NAME (has_failed) (list))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Enlarge the array if necessary. */
|
||||||
|
if (__glibc_unlikely (list->u.dynarray_header.used
|
||||||
|
== list->u.dynarray_header.allocated))
|
||||||
|
{
|
||||||
|
DYNARRAY_NAME (add__) (list, item);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the new element and increase the array length. */
|
||||||
|
list->u.dynarray_header.array[list->u.dynarray_header.used++] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal function. Building block for the emplace functions below.
|
||||||
|
Assumes space for one more element in *LIST. */
|
||||||
|
static inline DYNARRAY_ELEMENT *
|
||||||
|
DYNARRAY_NAME (emplace__tail__) (struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
DYNARRAY_ELEMENT *result
|
||||||
|
= &list->u.dynarray_header.array[list->u.dynarray_header.used];
|
||||||
|
++list->u.dynarray_header.used;
|
||||||
|
#if defined (DYNARRAY_ELEMENT_INIT)
|
||||||
|
DYNARRAY_ELEMENT_INIT (result);
|
||||||
|
#elif defined (DYNARRAY_ELEMENT_FREE)
|
||||||
|
memset (result, 0, sizeof (*result));
|
||||||
|
#endif
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal function. Slow path for the emplace function below. */
|
||||||
|
static DYNARRAY_ELEMENT *
|
||||||
|
DYNARRAY_NAME (emplace__) (struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
if (__glibc_unlikely
|
||||||
|
(!__libc_dynarray_emplace_enlarge (&list->u.dynarray_abstract,
|
||||||
|
DYNARRAY_SCRATCH (list),
|
||||||
|
sizeof (DYNARRAY_ELEMENT))))
|
||||||
|
{
|
||||||
|
DYNARRAY_NAME (mark_failed) (list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return DYNARRAY_NAME (emplace__tail__) (list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate a place for a new element in *LIST and return a pointer to
|
||||||
|
it. The pointer can be NULL if the dynamic array cannot be
|
||||||
|
enlarged due to a memory allocation failure. */
|
||||||
|
__attribute_maybe_unused__ __attribute_warn_unused_result__
|
||||||
|
__attribute_nonnull__ ((1))
|
||||||
|
static
|
||||||
|
/* Avoid inlining with the larger initialization code. */
|
||||||
|
#if !(defined (DYNARRAY_ELEMENT_INIT) || defined (DYNARRAY_ELEMENT_FREE))
|
||||||
|
inline
|
||||||
|
#endif
|
||||||
|
DYNARRAY_ELEMENT *
|
||||||
|
DYNARRAY_NAME (emplace) (struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
/* Do nothing in case of previous error. */
|
||||||
|
if (DYNARRAY_NAME (has_failed) (list))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Enlarge the array if necessary. */
|
||||||
|
if (__glibc_unlikely (list->u.dynarray_header.used
|
||||||
|
== list->u.dynarray_header.allocated))
|
||||||
|
return (DYNARRAY_NAME (emplace__) (list));
|
||||||
|
return DYNARRAY_NAME (emplace__tail__) (list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the size of *LIST to SIZE. If SIZE is larger than the
|
||||||
|
existing size, new elements are added (which can be initialized).
|
||||||
|
Otherwise, the list is truncated, and elements are freed. Return
|
||||||
|
false on memory allocation failure (and mark *LIST as failed). */
|
||||||
|
__attribute_maybe_unused__ __attribute_nonnull__ ((1))
|
||||||
|
static bool
|
||||||
|
DYNARRAY_NAME (resize) (struct DYNARRAY_STRUCT *list, size_t size)
|
||||||
|
{
|
||||||
|
if (size > list->u.dynarray_header.used)
|
||||||
|
{
|
||||||
|
bool ok;
|
||||||
|
#if defined (DYNARRAY_ELEMENT_INIT)
|
||||||
|
/* The new elements have to be initialized. */
|
||||||
|
size_t old_size = list->u.dynarray_header.used;
|
||||||
|
ok = __libc_dynarray_resize (&list->u.dynarray_abstract,
|
||||||
|
size, DYNARRAY_SCRATCH (list),
|
||||||
|
sizeof (DYNARRAY_ELEMENT));
|
||||||
|
if (ok)
|
||||||
|
for (size_t i = old_size; i < size; ++i)
|
||||||
|
{
|
||||||
|
DYNARRAY_ELEMENT_INIT (&list->u.dynarray_header.array[i]);
|
||||||
|
}
|
||||||
|
#elif defined (DYNARRAY_ELEMENT_FREE)
|
||||||
|
/* Zero initialization is needed so that the elements can be
|
||||||
|
safely freed. */
|
||||||
|
ok = __libc_dynarray_resize_clear
|
||||||
|
(&list->u.dynarray_abstract, size,
|
||||||
|
DYNARRAY_SCRATCH (list), sizeof (DYNARRAY_ELEMENT));
|
||||||
|
#else
|
||||||
|
ok = __libc_dynarray_resize (&list->u.dynarray_abstract,
|
||||||
|
size, DYNARRAY_SCRATCH (list),
|
||||||
|
sizeof (DYNARRAY_ELEMENT));
|
||||||
|
#endif
|
||||||
|
if (__glibc_unlikely (!ok))
|
||||||
|
DYNARRAY_NAME (mark_failed) (list);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* The list has shrunk in size. Free the removed elements. */
|
||||||
|
DYNARRAY_NAME (free__elements__)
|
||||||
|
(list->u.dynarray_header.array + size,
|
||||||
|
list->u.dynarray_header.used - size);
|
||||||
|
list->u.dynarray_header.used = size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the last element of LIST if it is present. */
|
||||||
|
__attribute_maybe_unused__ __attribute_nonnull__ ((1))
|
||||||
|
static void
|
||||||
|
DYNARRAY_NAME (remove_last) (struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
/* used > 0 implies that the array is the non-failed state. */
|
||||||
|
if (list->u.dynarray_header.used > 0)
|
||||||
|
{
|
||||||
|
size_t new_length = list->u.dynarray_header.used - 1;
|
||||||
|
#ifdef DYNARRAY_ELEMENT_FREE
|
||||||
|
DYNARRAY_ELEMENT_FREE (&list->u.dynarray_header.array[new_length]);
|
||||||
|
#endif
|
||||||
|
list->u.dynarray_header.used = new_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove all elements from the list. The elements are freed, but the
|
||||||
|
list itself is not. */
|
||||||
|
__attribute_maybe_unused__ __attribute_nonnull__ ((1))
|
||||||
|
static void
|
||||||
|
DYNARRAY_NAME (clear) (struct DYNARRAY_STRUCT *list)
|
||||||
|
{
|
||||||
|
/* free__elements__ does nothing if the list is in the failed
|
||||||
|
state. */
|
||||||
|
DYNARRAY_NAME (free__elements__)
|
||||||
|
(list->u.dynarray_header.array, list->u.dynarray_header.used);
|
||||||
|
list->u.dynarray_header.used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DYNARRAY_FINAL_TYPE
|
||||||
|
/* Transfer the dynamic array to a permanent location at *RESULT.
|
||||||
|
Returns true on success on false on allocation failure. In either
|
||||||
|
case, *LIST is re-initialized and can be reused. A NULL pointer is
|
||||||
|
stored in *RESULT if LIST refers to an empty list. On success, the
|
||||||
|
pointer in *RESULT is heap-allocated and must be deallocated using
|
||||||
|
free. */
|
||||||
|
__attribute_maybe_unused__ __attribute_warn_unused_result__
|
||||||
|
__attribute_nonnull__ ((1, 2))
|
||||||
|
static bool
|
||||||
|
DYNARRAY_NAME (finalize) (struct DYNARRAY_STRUCT *list,
|
||||||
|
DYNARRAY_FINAL_TYPE *result)
|
||||||
|
{
|
||||||
|
struct dynarray_finalize_result res;
|
||||||
|
if (__libc_dynarray_finalize (&list->u.dynarray_abstract,
|
||||||
|
DYNARRAY_SCRATCH (list),
|
||||||
|
sizeof (DYNARRAY_ELEMENT), &res))
|
||||||
|
{
|
||||||
|
/* On success, the result owns all the data. */
|
||||||
|
DYNARRAY_NAME (init) (list);
|
||||||
|
*result = (DYNARRAY_FINAL_TYPE) { res.array, res.length };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* On error, we need to free all data. */
|
||||||
|
DYNARRAY_FREE (list);
|
||||||
|
errno = ENOMEM;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else /* !DYNARRAY_FINAL_TYPE */
|
||||||
|
/* Transfer the dynamic array to a heap-allocated array and return a
|
||||||
|
pointer to it. The pointer is NULL if memory allocation fails, or
|
||||||
|
if the array is empty, so this function should be used only for
|
||||||
|
arrays which are known not be empty (usually because they always
|
||||||
|
have a sentinel at the end). If LENGTHP is not NULL, the array
|
||||||
|
length is written to *LENGTHP. *LIST is re-initialized and can be
|
||||||
|
reused. */
|
||||||
|
__attribute_maybe_unused__ __attribute_warn_unused_result__
|
||||||
|
__attribute_nonnull__ ((1))
|
||||||
|
static DYNARRAY_ELEMENT *
|
||||||
|
DYNARRAY_NAME (finalize) (struct DYNARRAY_STRUCT *list, size_t *lengthp)
|
||||||
|
{
|
||||||
|
struct dynarray_finalize_result res;
|
||||||
|
if (__libc_dynarray_finalize (&list->u.dynarray_abstract,
|
||||||
|
DYNARRAY_SCRATCH (list),
|
||||||
|
sizeof (DYNARRAY_ELEMENT), &res))
|
||||||
|
{
|
||||||
|
/* On success, the result owns all the data. */
|
||||||
|
DYNARRAY_NAME (init) (list);
|
||||||
|
if (lengthp != NULL)
|
||||||
|
*lengthp = res.length;
|
||||||
|
return res.array;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* On error, we need to free all data. */
|
||||||
|
DYNARRAY_FREE (list);
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* !DYNARRAY_FINAL_TYPE */
|
||||||
|
|
||||||
|
/* Undo macro definitions. */
|
||||||
|
|
||||||
|
#undef DYNARRAY_CONCAT0
|
||||||
|
#undef DYNARRAY_CONCAT1
|
||||||
|
#undef DYNARRAY_NAME
|
||||||
|
#undef DYNARRAY_SCRATCH
|
||||||
|
#undef DYNARRAY_HAVE_SCRATCH
|
||||||
|
|
||||||
|
#undef DYNARRAY_STRUCT
|
||||||
|
#undef DYNARRAY_ELEMENT
|
||||||
|
#undef DYNARRAY_PREFIX
|
||||||
|
#undef DYNARRAY_ELEMENT_FREE
|
||||||
|
#undef DYNARRAY_ELEMENT_INIT
|
||||||
|
#undef DYNARRAY_INITIAL_SIZE
|
||||||
|
#undef DYNARRAY_FINAL_TYPE
|
||||||
177
xcompile/malloc/dynarray.h
Normal file
177
xcompile/malloc/dynarray.h
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
/* Type-safe arrays which grow dynamically. Shared definitions.
|
||||||
|
Copyright (C) 2017-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
/* To use the dynarray facility, you need to include
|
||||||
|
<malloc/dynarray-skeleton.c> and define the parameter macros
|
||||||
|
documented in that file.
|
||||||
|
|
||||||
|
A minimal example which provides a growing list of integers can be
|
||||||
|
defined like this:
|
||||||
|
|
||||||
|
struct int_array
|
||||||
|
{
|
||||||
|
// Pointer to result array followed by its length,
|
||||||
|
// as required by DYNARRAY_FINAL_TYPE.
|
||||||
|
int *array;
|
||||||
|
size_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DYNARRAY_STRUCT dynarray_int
|
||||||
|
#define DYNARRAY_ELEMENT int
|
||||||
|
#define DYNARRAY_PREFIX dynarray_int_
|
||||||
|
#define DYNARRAY_FINAL_TYPE struct int_array
|
||||||
|
#include <malloc/dynarray-skeleton.c>
|
||||||
|
|
||||||
|
To create a three-element array with elements 1, 2, 3, use this
|
||||||
|
code:
|
||||||
|
|
||||||
|
struct dynarray_int dyn;
|
||||||
|
dynarray_int_init (&dyn);
|
||||||
|
for (int i = 1; i <= 3; ++i)
|
||||||
|
{
|
||||||
|
int *place = dynarray_int_emplace (&dyn);
|
||||||
|
assert (place != NULL);
|
||||||
|
*place = i;
|
||||||
|
}
|
||||||
|
struct int_array result;
|
||||||
|
bool ok = dynarray_int_finalize (&dyn, &result);
|
||||||
|
assert (ok);
|
||||||
|
assert (result.length == 3);
|
||||||
|
assert (result.array[0] == 1);
|
||||||
|
assert (result.array[1] == 2);
|
||||||
|
assert (result.array[2] == 3);
|
||||||
|
free (result.array);
|
||||||
|
|
||||||
|
If the elements contain resources which must be freed, define
|
||||||
|
DYNARRAY_ELEMENT_FREE appropriately, like this:
|
||||||
|
|
||||||
|
struct str_array
|
||||||
|
{
|
||||||
|
char **array;
|
||||||
|
size_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define DYNARRAY_STRUCT dynarray_str
|
||||||
|
#define DYNARRAY_ELEMENT char *
|
||||||
|
#define DYNARRAY_ELEMENT_FREE(ptr) free (*ptr)
|
||||||
|
#define DYNARRAY_PREFIX dynarray_str_
|
||||||
|
#define DYNARRAY_FINAL_TYPE struct str_array
|
||||||
|
#include <malloc/dynarray-skeleton.c>
|
||||||
|
|
||||||
|
Compared to scratch buffers, dynamic arrays have the following
|
||||||
|
features:
|
||||||
|
|
||||||
|
- They have an element type, and are not just an untyped buffer of
|
||||||
|
bytes.
|
||||||
|
|
||||||
|
- When growing, previously stored elements are preserved. (It is
|
||||||
|
expected that scratch_buffer_grow_preserve and
|
||||||
|
scratch_buffer_set_array_size eventually go away because all
|
||||||
|
current users are moved to dynamic arrays.)
|
||||||
|
|
||||||
|
- Scratch buffers have a more aggressive growth policy because
|
||||||
|
growing them typically means a retry of an operation (across an
|
||||||
|
NSS service module boundary), which is expensive.
|
||||||
|
|
||||||
|
- For the same reason, scratch buffers have a much larger initial
|
||||||
|
stack allocation. */
|
||||||
|
|
||||||
|
#ifndef _DYNARRAY_H
|
||||||
|
#define _DYNARRAY_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct dynarray_header
|
||||||
|
{
|
||||||
|
size_t used;
|
||||||
|
size_t allocated;
|
||||||
|
void *array;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Marker used in the allocated member to indicate that an error was
|
||||||
|
encountered. */
|
||||||
|
static inline size_t
|
||||||
|
__dynarray_error_marker (void)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal function. See the has_failed function in
|
||||||
|
dynarray-skeleton.c. */
|
||||||
|
static inline bool
|
||||||
|
__dynarray_error (struct dynarray_header *list)
|
||||||
|
{
|
||||||
|
return list->allocated == __dynarray_error_marker ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Internal function. Enlarge the dynamically allocated area of the
|
||||||
|
array to make room for one more element. SCRATCH is a pointer to
|
||||||
|
the scratch area (which is not heap-allocated and must not be
|
||||||
|
freed). ELEMENT_SIZE is the size, in bytes, of one element.
|
||||||
|
Return false on failure, true on success. */
|
||||||
|
bool __libc_dynarray_emplace_enlarge (struct dynarray_header *,
|
||||||
|
void *scratch, size_t element_size);
|
||||||
|
|
||||||
|
/* Internal function. Enlarge the dynamically allocated area of the
|
||||||
|
array to make room for at least SIZE elements (which must be larger
|
||||||
|
than the existing used part of the dynamic array). SCRATCH is a
|
||||||
|
pointer to the scratch area (which is not heap-allocated and must
|
||||||
|
not be freed). ELEMENT_SIZE is the size, in bytes, of one element.
|
||||||
|
Return false on failure, true on success. */
|
||||||
|
bool __libc_dynarray_resize (struct dynarray_header *, size_t size,
|
||||||
|
void *scratch, size_t element_size);
|
||||||
|
|
||||||
|
/* Internal function. Like __libc_dynarray_resize, but clear the new
|
||||||
|
part of the dynamic array. */
|
||||||
|
bool __libc_dynarray_resize_clear (struct dynarray_header *, size_t size,
|
||||||
|
void *scratch, size_t element_size);
|
||||||
|
|
||||||
|
/* Internal type. */
|
||||||
|
struct dynarray_finalize_result
|
||||||
|
{
|
||||||
|
void *array;
|
||||||
|
size_t length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Internal function. Copy the dynamically-allocated area to an
|
||||||
|
explicitly-sized heap allocation. SCRATCH is a pointer to the
|
||||||
|
embedded scratch space. ELEMENT_SIZE is the size, in bytes, of the
|
||||||
|
element type. On success, true is returned, and pointer and length
|
||||||
|
are written to *RESULT. On failure, false is returned. The caller
|
||||||
|
has to take care of some of the memory management; this function is
|
||||||
|
expected to be called from dynarray-skeleton.c. */
|
||||||
|
bool __libc_dynarray_finalize (struct dynarray_header *list, void *scratch,
|
||||||
|
size_t element_size,
|
||||||
|
struct dynarray_finalize_result *result);
|
||||||
|
|
||||||
|
|
||||||
|
/* Internal function. Terminate the process after an index error.
|
||||||
|
SIZE is the number of elements of the dynamic array. INDEX is the
|
||||||
|
lookup index which triggered the failure. */
|
||||||
|
_Noreturn void __libc_dynarray_at_failure (size_t size, size_t index);
|
||||||
|
|
||||||
|
#ifndef _ISOMAC
|
||||||
|
libc_hidden_proto (__libc_dynarray_emplace_enlarge)
|
||||||
|
libc_hidden_proto (__libc_dynarray_resize)
|
||||||
|
libc_hidden_proto (__libc_dynarray_resize_clear)
|
||||||
|
libc_hidden_proto (__libc_dynarray_finalize)
|
||||||
|
libc_hidden_proto (__libc_dynarray_at_failure)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _DYNARRAY_H */
|
||||||
40
xcompile/malloc/dynarray_at_failure.c
Normal file
40
xcompile/malloc/dynarray_at_failure.c
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
/* Report an dynamic array index out of bounds condition.
|
||||||
|
Copyright (C) 2017-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _LIBC
|
||||||
|
# include <libc-config.h>
|
||||||
|
# include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <dynarray.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
__libc_dynarray_at_failure (size_t size, size_t index)
|
||||||
|
{
|
||||||
|
#ifdef _LIBC
|
||||||
|
char buf[200];
|
||||||
|
__snprintf (buf, sizeof (buf), "Fatal glibc error: "
|
||||||
|
"array index %zu not less than array length %zu\n",
|
||||||
|
index, size);
|
||||||
|
__libc_fatal (buf);
|
||||||
|
#else
|
||||||
|
abort ();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
libc_hidden_def (__libc_dynarray_at_failure)
|
||||||
77
xcompile/malloc/dynarray_emplace_enlarge.c
Normal file
77
xcompile/malloc/dynarray_emplace_enlarge.c
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/* Increase the size of a dynamic array in preparation of an emplace operation.
|
||||||
|
Copyright (C) 2017-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _LIBC
|
||||||
|
# include <libc-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <dynarray.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <intprops.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
bool
|
||||||
|
__libc_dynarray_emplace_enlarge (struct dynarray_header *list,
|
||||||
|
void *scratch, size_t element_size)
|
||||||
|
{
|
||||||
|
size_t new_allocated;
|
||||||
|
if (list->allocated == 0)
|
||||||
|
{
|
||||||
|
/* No scratch buffer provided. Choose a reasonable default
|
||||||
|
size. */
|
||||||
|
if (element_size < 4)
|
||||||
|
new_allocated = 16;
|
||||||
|
else if (element_size < 8)
|
||||||
|
new_allocated = 8;
|
||||||
|
else
|
||||||
|
new_allocated = 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* Increase the allocated size, using an exponential growth
|
||||||
|
policy. */
|
||||||
|
{
|
||||||
|
new_allocated = list->allocated + list->allocated / 2 + 1;
|
||||||
|
if (new_allocated <= list->allocated)
|
||||||
|
{
|
||||||
|
/* Overflow. */
|
||||||
|
__set_errno (ENOMEM);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t new_size;
|
||||||
|
if (INT_MULTIPLY_WRAPV (new_allocated, element_size, &new_size))
|
||||||
|
return false;
|
||||||
|
void *new_array;
|
||||||
|
if (list->array == scratch)
|
||||||
|
{
|
||||||
|
/* The previous array was not heap-allocated. */
|
||||||
|
new_array = malloc (new_size);
|
||||||
|
if (new_array != NULL && list->array != NULL)
|
||||||
|
memcpy (new_array, list->array, list->used * element_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
new_array = realloc (list->array, new_size);
|
||||||
|
if (new_array == NULL)
|
||||||
|
return false;
|
||||||
|
list->array = new_array;
|
||||||
|
list->allocated = new_allocated;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
libc_hidden_def (__libc_dynarray_emplace_enlarge)
|
||||||
66
xcompile/malloc/dynarray_finalize.c
Normal file
66
xcompile/malloc/dynarray_finalize.c
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* Copy the dynamically-allocated area to an explicitly-sized heap allocation.
|
||||||
|
Copyright (C) 2017-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _LIBC
|
||||||
|
# include <libc-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <dynarray.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
bool
|
||||||
|
__libc_dynarray_finalize (struct dynarray_header *list,
|
||||||
|
void *scratch, size_t element_size,
|
||||||
|
struct dynarray_finalize_result *result)
|
||||||
|
{
|
||||||
|
if (__dynarray_error (list))
|
||||||
|
/* The caller will reported the deferred error. */
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t used = list->used;
|
||||||
|
|
||||||
|
/* Empty list. */
|
||||||
|
if (used == 0)
|
||||||
|
{
|
||||||
|
/* An empty list could still be backed by a heap-allocated
|
||||||
|
array. Free it if necessary. */
|
||||||
|
if (list->array != scratch)
|
||||||
|
free (list->array);
|
||||||
|
*result = (struct dynarray_finalize_result) { NULL, 0 };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t allocation_size = used * element_size;
|
||||||
|
void *heap_array = malloc (allocation_size);
|
||||||
|
if (heap_array != NULL)
|
||||||
|
{
|
||||||
|
/* The new array takes ownership of the strings. */
|
||||||
|
if (list->array != NULL)
|
||||||
|
memcpy (heap_array, list->array, allocation_size);
|
||||||
|
if (list->array != scratch)
|
||||||
|
free (list->array);
|
||||||
|
*result = (struct dynarray_finalize_result)
|
||||||
|
{ .array = heap_array, .length = used };
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* The caller will perform the freeing operation. */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
libc_hidden_def (__libc_dynarray_finalize)
|
||||||
68
xcompile/malloc/dynarray_resize.c
Normal file
68
xcompile/malloc/dynarray_resize.c
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* Increase the size of a dynamic array.
|
||||||
|
Copyright (C) 2017-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _LIBC
|
||||||
|
# include <libc-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <dynarray.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <intprops.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
bool
|
||||||
|
__libc_dynarray_resize (struct dynarray_header *list, size_t size,
|
||||||
|
void *scratch, size_t element_size)
|
||||||
|
{
|
||||||
|
/* The existing allocation provides sufficient room. */
|
||||||
|
if (size <= list->allocated)
|
||||||
|
{
|
||||||
|
list->used = size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, use size as the new allocation size. The caller is
|
||||||
|
expected to provide the final size of the array, so there is no
|
||||||
|
over-allocation here. */
|
||||||
|
|
||||||
|
size_t new_size_bytes;
|
||||||
|
if (INT_MULTIPLY_WRAPV (size, element_size, &new_size_bytes))
|
||||||
|
{
|
||||||
|
/* Overflow. */
|
||||||
|
__set_errno (ENOMEM);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void *new_array;
|
||||||
|
if (list->array == scratch)
|
||||||
|
{
|
||||||
|
/* The previous array was not heap-allocated. */
|
||||||
|
new_array = malloc (new_size_bytes);
|
||||||
|
if (new_array != NULL && list->array != NULL)
|
||||||
|
memcpy (new_array, list->array, list->used * element_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
new_array = realloc (list->array, new_size_bytes);
|
||||||
|
if (new_array == NULL)
|
||||||
|
return false;
|
||||||
|
list->array = new_array;
|
||||||
|
list->allocated = size;
|
||||||
|
list->used = size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
libc_hidden_def (__libc_dynarray_resize)
|
||||||
39
xcompile/malloc/dynarray_resize_clear.c
Normal file
39
xcompile/malloc/dynarray_resize_clear.c
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
/* Increase the size of a dynamic array and clear the new part.
|
||||||
|
Copyright (C) 2017-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _LIBC
|
||||||
|
# include <libc-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <dynarray.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
bool
|
||||||
|
__libc_dynarray_resize_clear (struct dynarray_header *list, size_t size,
|
||||||
|
void *scratch, size_t element_size)
|
||||||
|
{
|
||||||
|
size_t old_size = list->used;
|
||||||
|
if (!__libc_dynarray_resize (list, size, scratch, element_size))
|
||||||
|
return false;
|
||||||
|
/* __libc_dynarray_resize already checked for overflow. */
|
||||||
|
char *array = list->array;
|
||||||
|
memset (array + (old_size * element_size), 0,
|
||||||
|
(size - old_size) * element_size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
libc_hidden_def (__libc_dynarray_resize_clear)
|
||||||
135
xcompile/malloc/scratch_buffer.h
Normal file
135
xcompile/malloc/scratch_buffer.h
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
/* Variable-sized buffer with on-stack default allocation.
|
||||||
|
Copyright (C) 2015-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _SCRATCH_BUFFER_H
|
||||||
|
#define _SCRATCH_BUFFER_H
|
||||||
|
|
||||||
|
/* Scratch buffers with a default stack allocation and fallback to
|
||||||
|
heap allocation. It is expected that this function is used in this
|
||||||
|
way:
|
||||||
|
|
||||||
|
struct scratch_buffer tmpbuf;
|
||||||
|
scratch_buffer_init (&tmpbuf);
|
||||||
|
|
||||||
|
while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length))
|
||||||
|
if (!scratch_buffer_grow (&tmpbuf))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
scratch_buffer_free (&tmpbuf);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
The allocation functions (scratch_buffer_grow,
|
||||||
|
scratch_buffer_grow_preserve, scratch_buffer_set_array_size) make
|
||||||
|
sure that the heap allocation, if any, is freed, so that the code
|
||||||
|
above does not have a memory leak. The buffer still remains in a
|
||||||
|
state that can be deallocated using scratch_buffer_free, so a loop
|
||||||
|
like this is valid as well:
|
||||||
|
|
||||||
|
struct scratch_buffer tmpbuf;
|
||||||
|
scratch_buffer_init (&tmpbuf);
|
||||||
|
|
||||||
|
while (!function_that_uses_buffer (tmpbuf.data, tmpbuf.length))
|
||||||
|
if (!scratch_buffer_grow (&tmpbuf))
|
||||||
|
break;
|
||||||
|
|
||||||
|
scratch_buffer_free (&tmpbuf);
|
||||||
|
|
||||||
|
scratch_buffer_grow and scratch_buffer_grow_preserve are guaranteed
|
||||||
|
to grow the buffer by at least 512 bytes. This means that when
|
||||||
|
using the scratch buffer as a backing store for a non-character
|
||||||
|
array whose element size, in bytes, is 512 or smaller, the scratch
|
||||||
|
buffer only has to grow once to make room for at least one more
|
||||||
|
element.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/* Scratch buffer. Must be initialized with scratch_buffer_init
|
||||||
|
before its use. */
|
||||||
|
struct scratch_buffer {
|
||||||
|
void *data; /* Pointer to the beginning of the scratch area. */
|
||||||
|
size_t length; /* Allocated space at the data pointer, in bytes. */
|
||||||
|
union { max_align_t __align; char __c[1024]; } __space;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Initializes *BUFFER so that BUFFER->data points to BUFFER->__space
|
||||||
|
and BUFFER->length reflects the available space. */
|
||||||
|
static inline void
|
||||||
|
scratch_buffer_init (struct scratch_buffer *buffer)
|
||||||
|
{
|
||||||
|
buffer->data = buffer->__space.__c;
|
||||||
|
buffer->length = sizeof (buffer->__space);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deallocates *BUFFER (if it was heap-allocated). */
|
||||||
|
static inline void
|
||||||
|
scratch_buffer_free (struct scratch_buffer *buffer)
|
||||||
|
{
|
||||||
|
if (buffer->data != buffer->__space.__c)
|
||||||
|
free (buffer->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grow *BUFFER by some arbitrary amount. The buffer contents is NOT
|
||||||
|
preserved. Return true on success, false on allocation failure (in
|
||||||
|
which case the old buffer is freed). On success, the new buffer is
|
||||||
|
larger than the previous size. On failure, *BUFFER is deallocated,
|
||||||
|
but remains in a free-able state, and errno is set. */
|
||||||
|
bool __libc_scratch_buffer_grow (struct scratch_buffer *buffer);
|
||||||
|
libc_hidden_proto (__libc_scratch_buffer_grow)
|
||||||
|
|
||||||
|
/* Alias for __libc_scratch_buffer_grow. */
|
||||||
|
static __always_inline bool
|
||||||
|
scratch_buffer_grow (struct scratch_buffer *buffer)
|
||||||
|
{
|
||||||
|
return __glibc_likely (__libc_scratch_buffer_grow (buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Like __libc_scratch_buffer_grow, but preserve the old buffer
|
||||||
|
contents on success, as a prefix of the new buffer. */
|
||||||
|
bool __libc_scratch_buffer_grow_preserve (struct scratch_buffer *buffer);
|
||||||
|
libc_hidden_proto (__libc_scratch_buffer_grow_preserve)
|
||||||
|
|
||||||
|
/* Alias for __libc_scratch_buffer_grow_preserve. */
|
||||||
|
static __always_inline bool
|
||||||
|
scratch_buffer_grow_preserve (struct scratch_buffer *buffer)
|
||||||
|
{
|
||||||
|
return __glibc_likely (__libc_scratch_buffer_grow_preserve (buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grow *BUFFER so that it can store at least NELEM elements of SIZE
|
||||||
|
bytes. The buffer contents are NOT preserved. Both NELEM and SIZE
|
||||||
|
can be zero. Return true on success, false on allocation failure
|
||||||
|
(in which case the old buffer is freed, but *BUFFER remains in a
|
||||||
|
free-able state, and errno is set). It is unspecified whether this
|
||||||
|
function can reduce the array size. */
|
||||||
|
bool __libc_scratch_buffer_set_array_size (struct scratch_buffer *buffer,
|
||||||
|
size_t nelem, size_t size);
|
||||||
|
libc_hidden_proto (__libc_scratch_buffer_set_array_size)
|
||||||
|
|
||||||
|
/* Alias for __libc_scratch_set_array_size. */
|
||||||
|
static __always_inline bool
|
||||||
|
scratch_buffer_set_array_size (struct scratch_buffer *buffer,
|
||||||
|
size_t nelem, size_t size)
|
||||||
|
{
|
||||||
|
return __glibc_likely (__libc_scratch_buffer_set_array_size
|
||||||
|
(buffer, nelem, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _SCRATCH_BUFFER_H */
|
||||||
41
xcompile/malloc/scratch_buffer_dupfree.c
Normal file
41
xcompile/malloc/scratch_buffer_dupfree.c
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* Variable-sized buffer with on-stack default allocation.
|
||||||
|
Copyright (C) 2020-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _LIBC
|
||||||
|
# include <libc-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <scratch_buffer.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void *
|
||||||
|
__libc_scratch_buffer_dupfree (struct scratch_buffer *buffer, size_t size)
|
||||||
|
{
|
||||||
|
void *data = buffer->data;
|
||||||
|
if (data == buffer->__space.__c)
|
||||||
|
{
|
||||||
|
void *copy = malloc (size);
|
||||||
|
return copy != NULL ? memcpy (copy, data, size) : NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
void *copy = realloc (data, size);
|
||||||
|
return copy != NULL ? copy : data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
libc_hidden_def (__libc_scratch_buffer_dupfree)
|
||||||
56
xcompile/malloc/scratch_buffer_grow.c
Normal file
56
xcompile/malloc/scratch_buffer_grow.c
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* Variable-sized buffer with on-stack default allocation.
|
||||||
|
Copyright (C) 2015-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _LIBC
|
||||||
|
# include <libc-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <scratch_buffer.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
bool
|
||||||
|
__libc_scratch_buffer_grow (struct scratch_buffer *buffer)
|
||||||
|
{
|
||||||
|
void *new_ptr;
|
||||||
|
size_t new_length = buffer->length * 2;
|
||||||
|
|
||||||
|
/* Discard old buffer. */
|
||||||
|
scratch_buffer_free (buffer);
|
||||||
|
|
||||||
|
/* Check for overflow. */
|
||||||
|
if (__glibc_likely (new_length >= buffer->length))
|
||||||
|
new_ptr = malloc (new_length);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__set_errno (ENOMEM);
|
||||||
|
new_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__glibc_unlikely (new_ptr == NULL))
|
||||||
|
{
|
||||||
|
/* Buffer must remain valid to free. */
|
||||||
|
scratch_buffer_init (buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Install new heap-based buffer. */
|
||||||
|
buffer->data = new_ptr;
|
||||||
|
buffer->length = new_length;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
libc_hidden_def (__libc_scratch_buffer_grow)
|
||||||
67
xcompile/malloc/scratch_buffer_grow_preserve.c
Normal file
67
xcompile/malloc/scratch_buffer_grow_preserve.c
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
/* Variable-sized buffer with on-stack default allocation.
|
||||||
|
Copyright (C) 2015-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _LIBC
|
||||||
|
# include <libc-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <scratch_buffer.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
bool
|
||||||
|
__libc_scratch_buffer_grow_preserve (struct scratch_buffer *buffer)
|
||||||
|
{
|
||||||
|
size_t new_length = 2 * buffer->length;
|
||||||
|
void *new_ptr;
|
||||||
|
|
||||||
|
if (buffer->data == buffer->__space.__c)
|
||||||
|
{
|
||||||
|
/* Move buffer to the heap. No overflow is possible because
|
||||||
|
buffer->length describes a small buffer on the stack. */
|
||||||
|
new_ptr = malloc (new_length);
|
||||||
|
if (new_ptr == NULL)
|
||||||
|
return false;
|
||||||
|
memcpy (new_ptr, buffer->__space.__c, buffer->length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Buffer was already on the heap. Check for overflow. */
|
||||||
|
if (__glibc_likely (new_length >= buffer->length))
|
||||||
|
new_ptr = realloc (buffer->data, new_length);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__set_errno (ENOMEM);
|
||||||
|
new_ptr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__glibc_unlikely (new_ptr == NULL))
|
||||||
|
{
|
||||||
|
/* Deallocate, but buffer must remain valid to free. */
|
||||||
|
free (buffer->data);
|
||||||
|
scratch_buffer_init (buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Install new heap-based buffer. */
|
||||||
|
buffer->data = new_ptr;
|
||||||
|
buffer->length = new_length;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
libc_hidden_def (__libc_scratch_buffer_grow_preserve)
|
||||||
64
xcompile/malloc/scratch_buffer_set_array_size.c
Normal file
64
xcompile/malloc/scratch_buffer_set_array_size.c
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
/* Variable-sized buffer with on-stack default allocation.
|
||||||
|
Copyright (C) 2015-2023 Free Software Foundation, Inc.
|
||||||
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The GNU C Library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the GNU C Library; if not, see
|
||||||
|
<https://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef _LIBC
|
||||||
|
# include <libc-config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <scratch_buffer.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
bool
|
||||||
|
__libc_scratch_buffer_set_array_size (struct scratch_buffer *buffer,
|
||||||
|
size_t nelem, size_t size)
|
||||||
|
{
|
||||||
|
size_t new_length = nelem * size;
|
||||||
|
|
||||||
|
/* Avoid overflow check if both values are small. */
|
||||||
|
if ((nelem | size) >> (sizeof (size_t) * CHAR_BIT / 2) != 0
|
||||||
|
&& nelem != 0 && size != new_length / nelem)
|
||||||
|
{
|
||||||
|
/* Overflow. Discard the old buffer, but it must remain valid
|
||||||
|
to free. */
|
||||||
|
scratch_buffer_free (buffer);
|
||||||
|
scratch_buffer_init (buffer);
|
||||||
|
__set_errno (ENOMEM);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_length <= buffer->length)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Discard old buffer. */
|
||||||
|
scratch_buffer_free (buffer);
|
||||||
|
|
||||||
|
char *new_ptr = malloc (new_length);
|
||||||
|
if (new_ptr == NULL)
|
||||||
|
{
|
||||||
|
/* Buffer must remain valid to free. */
|
||||||
|
scratch_buffer_init (buffer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Install new heap-based buffer. */
|
||||||
|
buffer->data = new_ptr;
|
||||||
|
buffer->length = new_length;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
libc_hidden_def (__libc_scratch_buffer_set_array_size)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue