mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-30 00:49:57 +02:00
add some missing files, update copyrights
This commit is contained in:
@@ -0,0 +1,251 @@
|
||||
# This file is a shell script that caches the results of configure
|
||||
# tests run on this system so they can be shared between configure
|
||||
# scripts and configure runs, see configure's option --config-cache.
|
||||
# It is not useful on other systems. If it contains results you don't
|
||||
# want to keep, you may remove or edit it.
|
||||
#
|
||||
# config.status only pays attention to the cache file if you give it
|
||||
# the --recheck option to rerun configure.
|
||||
#
|
||||
# `ac_cv_env_foo' variables (set or unset) will be overriden when
|
||||
# loading this file, other *unset* `ac_cv_foo' will be assigned the
|
||||
# following values.
|
||||
|
||||
ac_cv_build=${ac_cv_build='i686-pc-msys'}
|
||||
ac_cv_build_alias=${ac_cv_build_alias='i686-pc-msys'}
|
||||
ac_cv_c_bigendian=${ac_cv_c_bigendian='no'}
|
||||
ac_cv_c_char_unsigned=${ac_cv_c_char_unsigned='no'}
|
||||
ac_cv_c_compiler_gnu=${ac_cv_c_compiler_gnu='yes'}
|
||||
ac_cv_c_const=${ac_cv_c_const='yes'}
|
||||
ac_cv_c_inline=${ac_cv_c_inline='inline'}
|
||||
ac_cv_c_long_double=${ac_cv_c_long_double='yes'}
|
||||
ac_cv_c_stringize=${ac_cv_c_stringize='yes'}
|
||||
ac_cv_decl_sys_siglist=${ac_cv_decl_sys_siglist='no'}
|
||||
ac_cv_exeext=${ac_cv_exeext='.exe'}
|
||||
ac_cv_func___setostype=${ac_cv_func___setostype='no'}
|
||||
ac_cv_func__doprnt=${ac_cv_func__doprnt='no'}
|
||||
ac_cv_func_alloca_works=${ac_cv_func_alloca_works='yes'}
|
||||
ac_cv_func_asprintf=${ac_cv_func_asprintf='no'}
|
||||
ac_cv_func_bcopy=${ac_cv_func_bcopy='yes'}
|
||||
ac_cv_func_bindtextdomain=${ac_cv_func_bindtextdomain='no'}
|
||||
ac_cv_func_bzero=${ac_cv_func_bzero='yes'}
|
||||
ac_cv_func_confstr=${ac_cv_func_confstr='no'}
|
||||
ac_cv_func_dlclose=${ac_cv_func_dlclose='yes'}
|
||||
ac_cv_func_dlopen=${ac_cv_func_dlopen='yes'}
|
||||
ac_cv_func_dlsym=${ac_cv_func_dlsym='yes'}
|
||||
ac_cv_func_dup2=${ac_cv_func_dup2='yes'}
|
||||
ac_cv_func_fnmatch=${ac_cv_func_fnmatch='no'}
|
||||
ac_cv_func_getaddrinfo=${ac_cv_func_getaddrinfo='no'}
|
||||
ac_cv_func_getcwd=${ac_cv_func_getcwd='yes'}
|
||||
ac_cv_func_getdtablesize=${ac_cv_func_getdtablesize='yes'}
|
||||
ac_cv_func_getgroups=${ac_cv_func_getgroups='yes'}
|
||||
ac_cv_func_gethostbyname=${ac_cv_func_gethostbyname='yes'}
|
||||
ac_cv_func_gethostname=${ac_cv_func_gethostname='yes'}
|
||||
ac_cv_func_getpagesize=${ac_cv_func_getpagesize='yes'}
|
||||
ac_cv_func_getpeername=${ac_cv_func_getpeername='yes'}
|
||||
ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void='yes'}
|
||||
ac_cv_func_getrlimit=${ac_cv_func_getrlimit='yes'}
|
||||
ac_cv_func_getrusage=${ac_cv_func_getrusage='yes'}
|
||||
ac_cv_func_getservbyname=${ac_cv_func_getservbyname='yes'}
|
||||
ac_cv_func_gettext=${ac_cv_func_gettext='no'}
|
||||
ac_cv_func_gettimeofday=${ac_cv_func_gettimeofday='yes'}
|
||||
ac_cv_func_inet_aton=${ac_cv_func_inet_aton='yes'}
|
||||
ac_cv_func_isascii=${ac_cv_func_isascii='yes'}
|
||||
ac_cv_func_isblank=${ac_cv_func_isblank='no'}
|
||||
ac_cv_func_isgraph=${ac_cv_func_isgraph='yes'}
|
||||
ac_cv_func_isprint=${ac_cv_func_isprint='yes'}
|
||||
ac_cv_func_isspace=${ac_cv_func_isspace='yes'}
|
||||
ac_cv_func_isxdigit=${ac_cv_func_isxdigit='yes'}
|
||||
ac_cv_func_killpg=${ac_cv_func_killpg='yes'}
|
||||
ac_cv_func_lstat=${ac_cv_func_lstat='yes'}
|
||||
ac_cv_func_memmove=${ac_cv_func_memmove='yes'}
|
||||
ac_cv_func_mkfifo=${ac_cv_func_mkfifo='yes'}
|
||||
ac_cv_func_pathconf=${ac_cv_func_pathconf='yes'}
|
||||
ac_cv_func_putenv=${ac_cv_func_putenv='yes'}
|
||||
ac_cv_func_readlink=${ac_cv_func_readlink='yes'}
|
||||
ac_cv_func_rename=${ac_cv_func_rename='yes'}
|
||||
ac_cv_func_sbrk=${ac_cv_func_sbrk='yes'}
|
||||
ac_cv_func_select=${ac_cv_func_select='yes'}
|
||||
ac_cv_func_setdtablesize=${ac_cv_func_setdtablesize='yes'}
|
||||
ac_cv_func_setenv=${ac_cv_func_setenv='yes'}
|
||||
ac_cv_func_setlinebuf=${ac_cv_func_setlinebuf='no'}
|
||||
ac_cv_func_setlocale=${ac_cv_func_setlocale='yes'}
|
||||
ac_cv_func_setvbuf=${ac_cv_func_setvbuf='yes'}
|
||||
ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'}
|
||||
ac_cv_func_siginterrupt=${ac_cv_func_siginterrupt='no'}
|
||||
ac_cv_func_snprintf=${ac_cv_func_snprintf='yes'}
|
||||
ac_cv_func_strcasecmp=${ac_cv_func_strcasecmp='yes'}
|
||||
ac_cv_func_strchr=${ac_cv_func_strchr='yes'}
|
||||
ac_cv_func_strcoll_works=${ac_cv_func_strcoll_works='yes'}
|
||||
ac_cv_func_strerror=${ac_cv_func_strerror='yes'}
|
||||
ac_cv_func_strpbrk=${ac_cv_func_strpbrk='yes'}
|
||||
ac_cv_func_strtod=${ac_cv_func_strtod='yes'}
|
||||
ac_cv_func_strtoimax=${ac_cv_func_strtoimax='no'}
|
||||
ac_cv_func_strtol=${ac_cv_func_strtol='yes'}
|
||||
ac_cv_func_strtoll=${ac_cv_func_strtoll='no'}
|
||||
ac_cv_func_strtoul=${ac_cv_func_strtoul='yes'}
|
||||
ac_cv_func_strtoull=${ac_cv_func_strtoull='no'}
|
||||
ac_cv_func_strtoumax=${ac_cv_func_strtoumax='no'}
|
||||
ac_cv_func_sysconf=${ac_cv_func_sysconf='yes'}
|
||||
ac_cv_func_tcgetattr=${ac_cv_func_tcgetattr='yes'}
|
||||
ac_cv_func_tcgetpgrp=${ac_cv_func_tcgetpgrp='yes'}
|
||||
ac_cv_func_textdomain=${ac_cv_func_textdomain='no'}
|
||||
ac_cv_func_times=${ac_cv_func_times='yes'}
|
||||
ac_cv_func_ttyname=${ac_cv_func_ttyname='yes'}
|
||||
ac_cv_func_tzset=${ac_cv_func_tzset='yes'}
|
||||
ac_cv_func_ulimit=${ac_cv_func_ulimit='no'}
|
||||
ac_cv_func_uname=${ac_cv_func_uname='yes'}
|
||||
ac_cv_func_vasprintf=${ac_cv_func_vasprintf='no'}
|
||||
ac_cv_func_vprintf=${ac_cv_func_vprintf='yes'}
|
||||
ac_cv_func_vsnprintf=${ac_cv_func_vsnprintf='yes'}
|
||||
ac_cv_func_wait3=${ac_cv_func_wait3='yes'}
|
||||
ac_cv_func_waitpid=${ac_cv_func_waitpid='yes'}
|
||||
ac_cv_have_decl_confstr=${ac_cv_have_decl_confstr='no'}
|
||||
ac_cv_have_decl_printf=${ac_cv_have_decl_printf='yes'}
|
||||
ac_cv_have_decl_sbrk=${ac_cv_have_decl_sbrk='yes'}
|
||||
ac_cv_have_decl_strsignal=${ac_cv_have_decl_strsignal='yes'}
|
||||
ac_cv_have_decl_strtold=${ac_cv_have_decl_strtold='no'}
|
||||
ac_cv_header_arpa_inet_h=${ac_cv_header_arpa_inet_h='yes'}
|
||||
ac_cv_header_dirent_dirent_h=${ac_cv_header_dirent_dirent_h='yes'}
|
||||
ac_cv_header_dlfcn_h=${ac_cv_header_dlfcn_h='yes'}
|
||||
ac_cv_header_grp_h=${ac_cv_header_grp_h='yes'}
|
||||
ac_cv_header_inttypes_h=${ac_cv_header_inttypes_h='no'}
|
||||
ac_cv_header_libintl_h=${ac_cv_header_libintl_h='yes'}
|
||||
ac_cv_header_limits_h=${ac_cv_header_limits_h='yes'}
|
||||
ac_cv_header_locale_h=${ac_cv_header_locale_h='yes'}
|
||||
ac_cv_header_memory_h=${ac_cv_header_memory_h='yes'}
|
||||
ac_cv_header_minix_config_h=${ac_cv_header_minix_config_h='no'}
|
||||
ac_cv_header_netdb_h=${ac_cv_header_netdb_h='yes'}
|
||||
ac_cv_header_netinet_in_h=${ac_cv_header_netinet_in_h='yes'}
|
||||
ac_cv_header_stat_broken=${ac_cv_header_stat_broken='no'}
|
||||
ac_cv_header_stdarg_h=${ac_cv_header_stdarg_h='yes'}
|
||||
ac_cv_header_stdc=${ac_cv_header_stdc='yes'}
|
||||
ac_cv_header_stddef_h=${ac_cv_header_stddef_h='yes'}
|
||||
ac_cv_header_stdint_h=${ac_cv_header_stdint_h='no'}
|
||||
ac_cv_header_stdlib_h=${ac_cv_header_stdlib_h='yes'}
|
||||
ac_cv_header_string_h=${ac_cv_header_string_h='yes'}
|
||||
ac_cv_header_strings_h=${ac_cv_header_strings_h='yes'}
|
||||
ac_cv_header_sys_file_h=${ac_cv_header_sys_file_h='yes'}
|
||||
ac_cv_header_sys_param_h=${ac_cv_header_sys_param_h='yes'}
|
||||
ac_cv_header_sys_pte_h=${ac_cv_header_sys_pte_h='no'}
|
||||
ac_cv_header_sys_ptem_h=${ac_cv_header_sys_ptem_h='no'}
|
||||
ac_cv_header_sys_resource_h=${ac_cv_header_sys_resource_h='yes'}
|
||||
ac_cv_header_sys_select_h=${ac_cv_header_sys_select_h='yes'}
|
||||
ac_cv_header_sys_socket_h=${ac_cv_header_sys_socket_h='yes'}
|
||||
ac_cv_header_sys_stat_h=${ac_cv_header_sys_stat_h='yes'}
|
||||
ac_cv_header_sys_stream_h=${ac_cv_header_sys_stream_h='no'}
|
||||
ac_cv_header_sys_time_h=${ac_cv_header_sys_time_h='yes'}
|
||||
ac_cv_header_sys_times_h=${ac_cv_header_sys_times_h='yes'}
|
||||
ac_cv_header_sys_types_h=${ac_cv_header_sys_types_h='yes'}
|
||||
ac_cv_header_sys_wait_h=${ac_cv_header_sys_wait_h='yes'}
|
||||
ac_cv_header_termcap_h=${ac_cv_header_termcap_h='yes'}
|
||||
ac_cv_header_termio_h=${ac_cv_header_termio_h='yes'}
|
||||
ac_cv_header_termios_h=${ac_cv_header_termios_h='yes'}
|
||||
ac_cv_header_time=${ac_cv_header_time='yes'}
|
||||
ac_cv_header_unistd_h=${ac_cv_header_unistd_h='yes'}
|
||||
ac_cv_header_varargs_h=${ac_cv_header_varargs_h='yes'}
|
||||
ac_cv_host=${ac_cv_host='i686-pc-msys'}
|
||||
ac_cv_host_alias=${ac_cv_host_alias='i686-pc-msys'}
|
||||
ac_cv_lib_dir_opendir=${ac_cv_lib_dir_opendir='no'}
|
||||
ac_cv_lib_dl_dlopen=${ac_cv_lib_dl_dlopen='no'}
|
||||
ac_cv_lib_intl_bindtextdomain=${ac_cv_lib_intl_bindtextdomain='yes'}
|
||||
ac_cv_lib_termcap_tgetent=${ac_cv_lib_termcap_tgetent='yes'}
|
||||
ac_cv_member_struct_stat_st_blocks=${ac_cv_member_struct_stat_st_blocks='yes'}
|
||||
ac_cv_member_struct_termio_c_line=${ac_cv_member_struct_termio_c_line='yes'}
|
||||
ac_cv_member_struct_termios_c_line=${ac_cv_member_struct_termios_c_line='yes'}
|
||||
ac_cv_objext=${ac_cv_objext='o'}
|
||||
ac_cv_path_install=${ac_cv_path_install='/usr/bin/install -c'}
|
||||
ac_cv_prog_AR=${ac_cv_prog_AR='ar'}
|
||||
ac_cv_prog_CPP=${ac_cv_prog_CPP='gcc -E'}
|
||||
ac_cv_prog_YACC=${ac_cv_prog_YACC='bison -y'}
|
||||
ac_cv_prog_ac_ct_CC=${ac_cv_prog_ac_ct_CC='gcc'}
|
||||
ac_cv_prog_ac_ct_RANLIB=${ac_cv_prog_ac_ct_RANLIB='ranlib'}
|
||||
ac_cv_prog_cc_g=${ac_cv_prog_cc_g='yes'}
|
||||
ac_cv_prog_cc_stdc=${ac_cv_prog_cc_stdc=''}
|
||||
ac_cv_prog_gcc_traditional=${ac_cv_prog_gcc_traditional='no'}
|
||||
ac_cv_prog_make_make_set=${ac_cv_prog_make_make_set='yes'}
|
||||
ac_cv_sizeof_char=${ac_cv_sizeof_char='1'}
|
||||
ac_cv_sizeof_char_p=${ac_cv_sizeof_char_p='4'}
|
||||
ac_cv_sizeof_double=${ac_cv_sizeof_double='8'}
|
||||
ac_cv_sizeof_int=${ac_cv_sizeof_int='4'}
|
||||
ac_cv_sizeof_long=${ac_cv_sizeof_long='4'}
|
||||
ac_cv_sizeof_long_long=${ac_cv_sizeof_long_long='8'}
|
||||
ac_cv_sizeof_short=${ac_cv_sizeof_short='2'}
|
||||
ac_cv_sys_file_offset_bits=${ac_cv_sys_file_offset_bits='no'}
|
||||
ac_cv_sys_interpreter=${ac_cv_sys_interpreter='yes'}
|
||||
ac_cv_sys_large_files=${ac_cv_sys_large_files='no'}
|
||||
ac_cv_sys_largefile_CC=${ac_cv_sys_largefile_CC='no'}
|
||||
ac_cv_sys_posix_termios=${ac_cv_sys_posix_termios='yes'}
|
||||
ac_cv_sys_tiocgwinsz_in_termios_h=${ac_cv_sys_tiocgwinsz_in_termios_h='yes'}
|
||||
ac_cv_type_bits16_t=${ac_cv_type_bits16_t='no'}
|
||||
ac_cv_type_bits32_t=${ac_cv_type_bits32_t='no'}
|
||||
ac_cv_type_bits64_t=${ac_cv_type_bits64_t='no'}
|
||||
ac_cv_type_char=${ac_cv_type_char='yes'}
|
||||
ac_cv_type_char_p=${ac_cv_type_char_p='yes'}
|
||||
ac_cv_type_double=${ac_cv_type_double='yes'}
|
||||
ac_cv_type_getgroups=${ac_cv_type_getgroups='gid_t'}
|
||||
ac_cv_type_int=${ac_cv_type_int='yes'}
|
||||
ac_cv_type_long=${ac_cv_type_long='yes'}
|
||||
ac_cv_type_long_long=${ac_cv_type_long_long='yes'}
|
||||
ac_cv_type_mode_t=${ac_cv_type_mode_t='yes'}
|
||||
ac_cv_type_off_t=${ac_cv_type_off_t='yes'}
|
||||
ac_cv_type_pid_t=${ac_cv_type_pid_t='yes'}
|
||||
ac_cv_type_ptrdiff_t=${ac_cv_type_ptrdiff_t='yes'}
|
||||
ac_cv_type_short=${ac_cv_type_short='yes'}
|
||||
ac_cv_type_signal=${ac_cv_type_signal='void'}
|
||||
ac_cv_type_size_t=${ac_cv_type_size_t='yes'}
|
||||
ac_cv_type_ssize_t=${ac_cv_type_ssize_t='yes'}
|
||||
ac_cv_type_time_t=${ac_cv_type_time_t='yes'}
|
||||
ac_cv_type_u_bits16_t=${ac_cv_type_u_bits16_t='no'}
|
||||
ac_cv_type_u_bits32_t=${ac_cv_type_u_bits32_t='no'}
|
||||
ac_cv_type_u_int=${ac_cv_type_u_int='yes'}
|
||||
ac_cv_type_u_long=${ac_cv_type_u_long='yes'}
|
||||
ac_cv_type_uid_t=${ac_cv_type_uid_t='yes'}
|
||||
ac_cv_working_alloca_h=${ac_cv_working_alloca_h='no'}
|
||||
|
||||
bash_cv_decl_strtoimax=${bash_cv_decl_strtoimax='no'}
|
||||
bash_cv_decl_strtol=${bash_cv_decl_strtol='yes'}
|
||||
bash_cv_decl_strtoll=${bash_cv_decl_strtoll='no'}
|
||||
bash_cv_decl_strtoul=${bash_cv_decl_strtoul='yes'}
|
||||
bash_cv_decl_strtoull=${bash_cv_decl_strtoull='no'}
|
||||
bash_cv_decl_strtoumax=${bash_cv_decl_strtoumax='no'}
|
||||
bash_cv_decl_under_sys_siglist=${bash_cv_decl_under_sys_siglist='no'}
|
||||
bash_cv_dev_fd=${bash_cv_dev_fd='absent'}
|
||||
bash_cv_dev_stdin=${bash_cv_dev_stdin='absent'}
|
||||
bash_cv_dirent_has_d_fileno=${bash_cv_dirent_has_d_fileno='no'}
|
||||
bash_cv_dirent_has_dino=${bash_cv_dirent_has_dino='yes'}
|
||||
bash_cv_dup2_broken=${bash_cv_dup2_broken='no'}
|
||||
bash_cv_fionread_in_ioctl=${bash_cv_fionread_in_ioctl='no'}
|
||||
bash_cv_func_sigsetjmp=${bash_cv_func_sigsetjmp='present'}
|
||||
bash_cv_func_strcoll_broken=${bash_cv_func_strcoll_broken='no'}
|
||||
bash_cv_getenv_redef=${bash_cv_getenv_redef='yes'}
|
||||
bash_cv_getpw_declared=${bash_cv_getpw_declared='yes'}
|
||||
bash_cv_have_strsignal=${bash_cv_have_strsignal='yes'}
|
||||
bash_cv_job_control_missing=${bash_cv_job_control_missing='present'}
|
||||
bash_cv_mail_dir=${bash_cv_mail_dir='unknown'}
|
||||
bash_cv_must_reinstall_sighandlers=${bash_cv_must_reinstall_sighandlers='no'}
|
||||
bash_cv_opendir_not_robust=${bash_cv_opendir_not_robust='no'}
|
||||
bash_cv_pgrp_pipe=${bash_cv_pgrp_pipe='no'}
|
||||
bash_cv_printf_a_format=${bash_cv_printf_a_format='no'}
|
||||
bash_cv_signal_vintage=${bash_cv_signal_vintage='posix'}
|
||||
bash_cv_speed_t_in_sys_types=${bash_cv_speed_t_in_sys_types='no'}
|
||||
bash_cv_struct_timeval=${bash_cv_struct_timeval='yes'}
|
||||
bash_cv_struct_winsize_header=${bash_cv_struct_winsize_header='termios_h'}
|
||||
bash_cv_sys_errlist=${bash_cv_sys_errlist='no'}
|
||||
bash_cv_sys_named_pipes=${bash_cv_sys_named_pipes='present'}
|
||||
bash_cv_sys_siglist=${bash_cv_sys_siglist='no'}
|
||||
bash_cv_termcap_lib=${bash_cv_termcap_lib='libtermcap'}
|
||||
bash_cv_tiocstat_in_ioctl=${bash_cv_tiocstat_in_ioctl='no'}
|
||||
bash_cv_type_clock_t=${bash_cv_type_clock_t='yes'}
|
||||
bash_cv_type_intmax_t=${bash_cv_type_intmax_t='no'}
|
||||
bash_cv_type_long_long=${bash_cv_type_long_long='long long'}
|
||||
bash_cv_type_quad_t=${bash_cv_type_quad_t='no'}
|
||||
bash_cv_type_rlimit=${bash_cv_type_rlimit='rlim_t'}
|
||||
bash_cv_type_sigset_t=${bash_cv_type_sigset_t='yes'}
|
||||
bash_cv_type_socklen_t=${bash_cv_type_socklen_t='no'}
|
||||
bash_cv_type_uintmax_t=${bash_cv_type_uintmax_t='no'}
|
||||
bash_cv_type_unsigned_long_long=${bash_cv_type_unsigned_long_long='unsigned long long'}
|
||||
bash_cv_ulimit_maxfds=${bash_cv_ulimit_maxfds='no'}
|
||||
bash_cv_under_sys_siglist=${bash_cv_under_sys_siglist='no'}
|
||||
bash_cv_unusable_rtsigs=${bash_cv_unusable_rtsigs='no'}
|
||||
bash_cv_void_sighandler=${bash_cv_void_sighandler='yes'}
|
||||
@@ -0,0 +1,236 @@
|
||||
/* kv - process a series of lines containing key-value pairs and assign them
|
||||
to an associative array. */
|
||||
|
||||
/*
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include "bashansi.h"
|
||||
#include "posixstat.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "loadables.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define KV_ARRAY_DEFAULT "KV"
|
||||
|
||||
/* Split LINE into a key and value, with the delimiter between the key and
|
||||
value being a member of DSTRING. A sequence of one or more delimiters
|
||||
separates the key and value. Assign to associative array KV as if
|
||||
KV[key]=value without expansion. This does not treat single or double
|
||||
quotes specially, nor does it remove whitespace at the beginning or end
|
||||
of LINE. */
|
||||
static int
|
||||
kvsplit (SHELL_VAR *v, char *line, char *dstring)
|
||||
{
|
||||
char *key, *value;
|
||||
size_t ind;
|
||||
|
||||
key = line;
|
||||
value = 0;
|
||||
|
||||
ind = (line && *line) ? strcspn (key, dstring) : 0;
|
||||
|
||||
/* blank line or line starting with delimiter */
|
||||
if (ind == 0 || *key == 0)
|
||||
return 0;
|
||||
|
||||
if (key[ind])
|
||||
{
|
||||
key[ind++] = '\0';
|
||||
value = key + ind;
|
||||
/* skip until non-delim; this allows things like key1 = value1 where delims = " =" */
|
||||
ind = strspn (value, dstring);
|
||||
value += ind;
|
||||
}
|
||||
else
|
||||
value = "";
|
||||
|
||||
return (bind_assoc_variable (v, name_cell (v), savestring (key), value, 0) != 0);
|
||||
}
|
||||
|
||||
int
|
||||
kvfile (SHELL_VAR *v, int fd, char *delims, char *rs)
|
||||
{
|
||||
ssize_t n;
|
||||
char *line;
|
||||
size_t llen;
|
||||
int unbuffered_read, nr;
|
||||
struct stat sb;
|
||||
|
||||
nr = 0;
|
||||
#ifndef __CYGWIN__
|
||||
/* We probably don't need to worry about setting this at all; we're not
|
||||
seeking back and forth yet. */
|
||||
if (*rs == '\n')
|
||||
unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
|
||||
else
|
||||
unbuffered_read = (fstat (fd, &sb) != 0) || (S_ISREG (sb.st_mode) == 0);
|
||||
#else
|
||||
unbuffered_read = 1;
|
||||
#endif
|
||||
|
||||
line = 0;
|
||||
llen = 0;
|
||||
|
||||
zreset ();
|
||||
while ((n = zgetline (fd, &line, &llen, *rs, unbuffered_read)) != -1)
|
||||
{
|
||||
QUIT;
|
||||
if (line[n] == *rs)
|
||||
line[n] = '\0'; /* value doesn't include the record separator */
|
||||
nr += kvsplit (v, line, delims);
|
||||
free (line);
|
||||
line = 0;
|
||||
llen = 0;
|
||||
}
|
||||
|
||||
QUIT;
|
||||
return nr;
|
||||
}
|
||||
|
||||
int
|
||||
kv_builtin (WORD_LIST *list)
|
||||
{
|
||||
int opt, rval, free_delims;
|
||||
char *array_name, *delims, *rs;
|
||||
SHELL_VAR *v;
|
||||
|
||||
array_name = delims = rs = 0;
|
||||
rval = EXECUTION_SUCCESS;
|
||||
free_delims = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "A:s:d:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'A':
|
||||
array_name = list_optarg;
|
||||
break;
|
||||
case 's':
|
||||
delims = list_optarg;
|
||||
break;
|
||||
case 'd':
|
||||
rs = list_optarg;
|
||||
break;
|
||||
CASE_HELPOPT;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list)
|
||||
{
|
||||
builtin_error ("too many arguments");
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (array_name == 0)
|
||||
array_name = KV_ARRAY_DEFAULT;
|
||||
|
||||
if (valid_identifier (array_name) == 0)
|
||||
{
|
||||
sh_invalidid (array_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (delims == 0)
|
||||
{
|
||||
delims = getifs ();
|
||||
free_delims = 1;
|
||||
}
|
||||
if (rs == 0)
|
||||
rs = "\n";
|
||||
|
||||
v = find_or_make_array_variable (array_name, 3);
|
||||
if (v == 0 || readonly_p (v) || noassign_p (v))
|
||||
{
|
||||
if (v && readonly_p (v))
|
||||
err_readonly (array_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (assoc_p (v) == 0)
|
||||
{
|
||||
builtin_error ("%s: not an associative array", array_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (invisible_p (v))
|
||||
VUNSETATTR (v, att_invisible);
|
||||
assoc_flush (assoc_cell (v));
|
||||
|
||||
rval = kvfile (v, 0, delims, rs);
|
||||
|
||||
if (free_delims)
|
||||
free (delims); /* getifs returns allocated memory */
|
||||
return (rval > 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Called when builtin is enabled and loaded from the shared object. If this
|
||||
function returns 0, the load fails. */
|
||||
int
|
||||
kv_builtin_load (char *name)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Called when builtin is disabled. */
|
||||
void
|
||||
kv_builtin_unload (char *name)
|
||||
{
|
||||
}
|
||||
|
||||
char *kv_doc[] = {
|
||||
"Read key-value pairs into an associative array.",
|
||||
"",
|
||||
"Read delimiter-terminated records composed of a single key-value pair",
|
||||
"from the standard input and add the key and corresponding value",
|
||||
"to the associative array ARRAYNAME. The key and value are separated",
|
||||
"by a sequence of one or more characters in SEPARATORS. Records are",
|
||||
"terminated by the first character of RS, similar to the read and",
|
||||
"mapfile builtins.",
|
||||
"",
|
||||
"If SEPARATORS is not supplied, $IFS is used to separate the keys",
|
||||
"and values. If RS is not supplied, newlines terminate records.",
|
||||
"If ARRAYNAME is not supplied, \"KV\" is the default array name.",
|
||||
"",
|
||||
"Returns success if at least one key-value pair is stored in ARRAYNAME.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
struct builtin kv_struct = {
|
||||
"kv", /* builtin name */
|
||||
kv_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
kv_doc, /* array of long documentation strings. */
|
||||
"kv [-A ARRAYNAME] [-s SEPARATORS] [-d RS]", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
||||
@@ -0,0 +1,241 @@
|
||||
/* strptime - take a date-time string and turn it into seconds since the epoch. */
|
||||
|
||||
/* See Makefile for compilation details. */
|
||||
|
||||
/*
|
||||
Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash.
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "posixtime.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "shell.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
struct date_modifier
|
||||
{
|
||||
char *shorthand;
|
||||
int incr;
|
||||
};
|
||||
|
||||
static struct date_modifier date_time_modifiers[] =
|
||||
{
|
||||
{ "now", 0 },
|
||||
{ "today", 0 },
|
||||
{ "tomorrow", 24*60*60 },
|
||||
{ "yesterday", -24*60*60 },
|
||||
{ "day after tomorrow", 48*60*60 },
|
||||
{ "two days ago", -48*60*60 },
|
||||
{ "next week", 7*24*60*60 },
|
||||
{ "last week", -7*24*60*60 },
|
||||
{ "the day after tomorrow", 48*60*60 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static char * const date_time_formats[] =
|
||||
{
|
||||
"%a %b %d %T %Z %Y", /* Unix date */
|
||||
"%a %b %d %T %Y", /* Wkd Mon DD HH:MM:SS YYYY */
|
||||
"%FT%T%z", /* ISO8601 time YYYY-mm-ddTHH:MM:SSzone */
|
||||
"%FT%R%z", /* ISO8601 time YYYY-mm-ddTHH:MMzone */
|
||||
"%G-%m-%dT%T%z", /* ISO8601 time YYYY-mm-ddTHH:MM:SSzone */
|
||||
"%G-%m-%dT%R%z", /* ISO8601 time YYYY-mm-ddTHH:MMzone */
|
||||
"%G-%m-%d", /* ISO8601 time YYYY-mm-dd */
|
||||
/* Can't do 8601 time zone offset with colon or fractions of a second */
|
||||
"%a, %d %b %Y %T %Z", /* RFC822/RFC2822 time */
|
||||
"%a, %d %b %Y %T %z", /* RFC822/RFC2822 time */
|
||||
"%D %T", /* mm/dd/yy HH:MM:SS */
|
||||
"%D %R", /* mm/dd/yy HH:MM */
|
||||
"%D %r", /* mm/dd/yy HH:MM:SS a.m. */
|
||||
"%D %I:%M %p", /* mm/dd/yy HH:MM p.m. */
|
||||
"%m/%d/%Y %T", /* mm/dd/YYYY HH:MM:SS */
|
||||
"%m/%d/%Y %R", /* mm/dd/YYYY HH:MM */
|
||||
"%m/%d/%Y %r", /* mm/dd/YYYY HH:MM:SS a.m */
|
||||
"%m/%d/%Y %I:%M %p", /* mm/dd/YYYY HH:MM p.m. */
|
||||
"%m-%d-%Y %T", /* mm-dd-YYYY HH:MM:SS */
|
||||
"%m-%d-%Y %R", /* mm-dd-YYYY HH:MM */
|
||||
"%m-%d-%Y %r", /* mm-dd-YYYY HH:MM:SS a.m. */
|
||||
"%m-%d-%Y %I:%M %p", /* mm-dd-YYYY HH:MM p.m. */
|
||||
"%Y/%m/%d %T", /* YYYY/mm/dd HH:MM:SS */
|
||||
"%Y/%m/%d %R", /* YYYY/mm/dd HH:MM */
|
||||
"%Y/%m/%d %r", /* YYYY/mm/dd hh:MM:SS a.m. */
|
||||
"%F %T", /* YYYY-mm-dd HH:MM:SS */
|
||||
"%F %r", /* YYYY-mm-dd HH:MM:SS p.m. */
|
||||
"%F %R", /* YYYY-mm-dd HH:MM */
|
||||
"%F %I:%M %p", /* YYYY-mm-dd HH:MM a.m. */
|
||||
"%F", /* YYYY-mm-dd ISO8601 time */
|
||||
"%T", /* HH:MM:SS */
|
||||
"%H.%M.%S", /* HH.MM.SS */
|
||||
/* From coreutils-9.2 date */
|
||||
"%Y-%m-%dT%H:%M:%S%z", /* ISO8601 time */
|
||||
"%Y-%m-%dT%H%z", /* ISO8601 time */
|
||||
"%Y-%m-%dT%H:%M%z", /* ISO8601 time */
|
||||
/* RFC 3339 time */
|
||||
"%Y-%m-%d %H:%M:%S%z", /* RFC 3339 time */
|
||||
"%Y-%m-%dT%H:%M:%S%z", /* RFC 3339 time */
|
||||
/* more oddball formats */
|
||||
"%m.%d.%Y %T", /* mm.dd.YYYY HH:MM:SS */
|
||||
"%m.%d.%Y %R", /* mm.dd.YYYY HH:MM */
|
||||
"%m.%d.%Y %r", /* mm.dd.YYYY HH:MM:SS a.m. */
|
||||
"%m.%d.%Y %I:%M %p", /* mm.dd.YYYY HH:MM p.m. */
|
||||
"%m/%d/%Y", /* mm/dd/YYYY */
|
||||
"%d %B %Y %T", /* dd Month YYYY HH:MM:SS */
|
||||
"%d %B %Y %R", /* dd Month YYYY HH:MM */
|
||||
"%d %B %Y %r", /* dd Month YYYY HH:MM:SS a.m. */
|
||||
"%d %B %Y %I:%M %p", /* dd Month YYYY HH:MM p.m. */
|
||||
"%d %b %Y %T", /* dd Mon YYYY HH:MM:SS */
|
||||
"%d %b %Y %R", /* dd Mon YYYY HH:MM */
|
||||
"%d %b %Y %r", /* dd Mon YYYY HH:MM:SS a.m. */
|
||||
"%d %b %Y %I:%M %p", /* dd Mon YYYY HH:MM p.m. */
|
||||
"%b %d, %Y %T", /* Mon dd, YYYY HH:MM:SS */
|
||||
"%b %d, %Y %R", /* Mon dd, YYYY HH:MM */
|
||||
"%b %d, %Y %r", /* Mon dd, YYYY HH:MM:SS a.m. */
|
||||
"%b %d, %Y %I:%M %p", /* Mon dd, YYYY HH:MM p.m. */
|
||||
"%m-%b-%Y", /* dd-Mon-YYYY */
|
||||
"%m-%b-%Y %T", /* dd-Mon-YYYY HH:MM:SS */
|
||||
"%m-%b-%Y %R", /* dd-Mon-YYYY HH:MM */
|
||||
"%m-%b-%Y %r", /* dd-Mon-YYYY HH:MM:SS a.m. */
|
||||
"%m-%b-%Y %I:%M %p", /* dd-Mon-YYYY HH:MM p.m. */
|
||||
"%d/%b/%Y:%T %z", /* NCSA log format dd/Mon/YYYY:HH:MM:SS zone */
|
||||
"%d/%b/%Y:%T%z", /* NCSA log format dd/Mon/YYYY:HH:MM:SSzone */
|
||||
/* No delimiters */
|
||||
"%Y%m%d %T", /* YYYYMMDD HH:MM:SS */
|
||||
"%Y%m%d %R", /* YYYYMMDD HH:MM */
|
||||
"%Y%m%d %r", /* YYYYMMDD HH:MM:SS a.m. */
|
||||
"%Y%m%d %I:%M %p", /* YYYYMMDD HH:MM p.m. */
|
||||
"%Y%m%d %H:%M:%S%z", /* YYYYMMDD HH:MM:SSzone */
|
||||
"%Y%m%dT%H:%M:%S%z", /* YYYYMMDDTHH:MM:SSzone */
|
||||
"%Y%m%dT%T", /* YYYYMMDDTHH:MM:SS */
|
||||
"%Y%m%dT%R", /* YYYYMMDDTHH:MM */
|
||||
/* Non-US formats */
|
||||
"%d-%m-%Y", /* dd-mm-YYYY */
|
||||
"%d-%m-%Y %T", /* dd-mm-YYYY HH:MM:SS */
|
||||
"%d-%m-%Y %R", /* dd-mm-YYYY HH:MM */
|
||||
"%d-%m-%Y %r", /* dd-mm-YYYY HH:MM:SS a.m. */
|
||||
"%d-%m-%Y %I:%M %p", /* dd-mm-YYYY HH:MM p.m. */
|
||||
"%d/%m/%Y %T", /* dd/mm/YYYY HH:MM:SS */
|
||||
"%d/%m/%Y %R", /* dd/mm/YYYY HH:MM */
|
||||
"%d/%m/%Y %r", /* dd/mm/YYYY HH:MM:SS a.m. */
|
||||
"%d/%m/%Y %I:%M %p", /* dd/mm/YYYY HH:MM p.m. */
|
||||
"%Y-%d-%m %T", /* YYYY-dd-mm HH:MM:SS */
|
||||
"%Y-%d-%m %R", /* YYYY-dd-mm HH:MM */
|
||||
"%d-%m-%Y %T", /* dd-mm-YYYY HH:MM:SS */
|
||||
"%d-%m-%Y %R", /* dd-mm-YYYY HH:MM */
|
||||
"%d-%m-%Y %r", /* dd-mm-YYYY HH:MM:SS a.m. */
|
||||
"%d-%m-%Y %I:%M %p", /* dd-mm-YYYY HH:MM p.m. */
|
||||
"%d.%m.%Y %T", /* dd.mm.YYYY HH:MM:SS */
|
||||
"%d.%m.%Y %R", /* dd.mm.YYYY HH:MM */
|
||||
"%d.%m.%Y %r", /* dd.mm.YYYY HH:MM:SS a.m. */
|
||||
"%d.%m.%Y %I:%M %p", /* dd.mm.YYYY HH:MM p.m. */
|
||||
0
|
||||
};
|
||||
|
||||
static void
|
||||
inittime (time_t *clock, struct tm *timeptr)
|
||||
{
|
||||
timeptr = localtime (clock); /* for now */
|
||||
|
||||
/* but default to midnight */
|
||||
timeptr->tm_hour = timeptr->tm_min = timeptr->tm_sec = 0;
|
||||
/* and let the system figure out the right DST offset */
|
||||
timeptr->tm_isdst = -1;
|
||||
}
|
||||
|
||||
int
|
||||
strptime_builtin (WORD_LIST *list)
|
||||
{
|
||||
char *s;
|
||||
struct tm t, *tm;
|
||||
time_t now, secs;
|
||||
char *datestr;
|
||||
int i;
|
||||
|
||||
if (no_options (list)) /* for now */
|
||||
return (EX_USAGE);
|
||||
|
||||
list = loptend;
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
datestr = string_list (list);
|
||||
if (datestr == 0 || *datestr == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
now = getnow ();
|
||||
secs = -1;
|
||||
for (i = 0; date_time_modifiers[i].shorthand; i++)
|
||||
{
|
||||
if (STREQ (datestr, date_time_modifiers[i].shorthand))
|
||||
{
|
||||
secs = now + date_time_modifiers[i].incr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (secs == -1)
|
||||
{
|
||||
/* init struct tm */
|
||||
inittime (&now, tm);
|
||||
t = *tm;
|
||||
for (i = 0; date_time_formats[i]; i++)
|
||||
{
|
||||
s = strptime (datestr, date_time_formats[i], &t);
|
||||
if (s == 0)
|
||||
continue;
|
||||
/* skip extra characters at the end for now */
|
||||
secs = mktime (&t);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf ("%ld\n", secs);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
char *strptime_doc[] = {
|
||||
"Convert a date-time string to seconds since the epoch.",
|
||||
"",
|
||||
"Take DATE-TIME, a date-time string, parse it against a set of common",
|
||||
"date-time formats. If the string matches one of the formats, convert",
|
||||
"it into seconds since the epoch and display the result.",
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
/* The standard structure describing a builtin command. bash keeps an array
|
||||
of these structures. The flags must include BUILTIN_ENABLED so the
|
||||
builtin can be used. */
|
||||
struct builtin strptime_struct = {
|
||||
"strptime", /* builtin name */
|
||||
strptime_builtin, /* function implementing the builtin */
|
||||
BUILTIN_ENABLED, /* initial flags for builtin */
|
||||
strptime_doc, /* array of long documentation strings. */
|
||||
"strptime date-time", /* usage synopsis; becomes short_doc */
|
||||
0 /* reserved for internal use */
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
# if we are worried somehow about inheriting a function for unset or exec,
|
||||
# set posix mode, then unset it later
|
||||
POSIXLY_CORRECT=1
|
||||
|
||||
# make sure to run with bash -p to prevent inheriting functions. you can
|
||||
# do this (if the script does not need to run setuid) or use the
|
||||
# POSIXLY_CORRECT setting above (as long as you run set +o posix as done below)
|
||||
#case $SHELLOPTS in
|
||||
#*privileged*) ;;
|
||||
#*) \exec /bin/bash -p $0 "$@" ;;
|
||||
#esac
|
||||
|
||||
# unset is a special builtin and will be found before functions; quoting it
|
||||
# will prevent alias expansion
|
||||
# add any other shell builtins you're concerned about
|
||||
\unset -f command builtin unset shopt set unalias hash
|
||||
\unset -f read true exit echo printf
|
||||
|
||||
# remove all aliases and disable alias expansion
|
||||
\unalias -a
|
||||
\shopt -u expand_aliases
|
||||
|
||||
# and make sure we're no longer running in posix mode
|
||||
set +o posix
|
||||
|
||||
# get rid of any hashed commands
|
||||
hash -r
|
||||
|
||||
# if you're concerned about PATH spoofing, make sure to have a path that
|
||||
# will find the standard utilities
|
||||
#PATH=$(command getconf -p getconf PATH):$PATH
|
||||
@@ -0,0 +1,397 @@
|
||||
/* intprops-internal.h -- properties of integer types not visible to users
|
||||
|
||||
Copyright (C) 2001-2024 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
#ifndef _GL_INTPROPS_INTERNAL_H
|
||||
#define _GL_INTPROPS_INTERNAL_H
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* Pacify GCC 13.2 in some calls to _GL_EXPR_SIGNED. */
|
||||
#if defined __GNUC__ && 4 < __GNUC__ + (3 <= __GNUC_MINOR__)
|
||||
# pragma GCC diagnostic ignored "-Wtype-limits"
|
||||
#endif
|
||||
|
||||
/* Return a value with the common real type of E and V and the value of V.
|
||||
Do not evaluate E. */
|
||||
#define _GL_INT_CONVERT(e, v) ((1 ? 0 : (e)) + (v))
|
||||
|
||||
/* Act like _GL_INT_CONVERT (E, -V) but work around a bug in IRIX 6.5 cc; see
|
||||
<https://lists.gnu.org/r/bug-gnulib/2011-05/msg00406.html>. */
|
||||
#define _GL_INT_NEGATE_CONVERT(e, v) ((1 ? 0 : (e)) - (v))
|
||||
|
||||
/* The extra casts in the following macros work around compiler bugs,
|
||||
e.g., in Cray C 5.0.3.0. */
|
||||
|
||||
/* True if the real type T is signed. */
|
||||
#define _GL_TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
|
||||
|
||||
/* Return 1 if the real expression E, after promotion, has a
|
||||
signed or floating type. Do not evaluate E. */
|
||||
#define _GL_EXPR_SIGNED(e) (_GL_INT_NEGATE_CONVERT (e, 1) < 0)
|
||||
|
||||
|
||||
/* Minimum and maximum values for integer types and expressions. */
|
||||
|
||||
/* The width in bits of the integer type or expression T.
|
||||
Do not evaluate T. T must not be a bit-field expression.
|
||||
Padding bits are not supported; this is checked at compile-time below. */
|
||||
#define _GL_TYPE_WIDTH(t) (sizeof (t) * CHAR_BIT)
|
||||
|
||||
/* The maximum and minimum values for the type of the expression E,
|
||||
after integer promotion. E is not evaluated. */
|
||||
#define _GL_INT_MINIMUM(e) \
|
||||
(_GL_EXPR_SIGNED (e) \
|
||||
? ~ _GL_SIGNED_INT_MAXIMUM (e) \
|
||||
: _GL_INT_CONVERT (e, 0))
|
||||
#define _GL_INT_MAXIMUM(e) \
|
||||
(_GL_EXPR_SIGNED (e) \
|
||||
? _GL_SIGNED_INT_MAXIMUM (e) \
|
||||
: _GL_INT_NEGATE_CONVERT (e, 1))
|
||||
#define _GL_SIGNED_INT_MAXIMUM(e) \
|
||||
(((_GL_INT_CONVERT (e, 1) << (_GL_TYPE_WIDTH (+ (e)) - 2)) - 1) * 2 + 1)
|
||||
|
||||
/* Work around OpenVMS incompatibility with C99. */
|
||||
#if !defined LLONG_MAX && defined __INT64_MAX
|
||||
# define LLONG_MAX __INT64_MAX
|
||||
# define LLONG_MIN __INT64_MIN
|
||||
#endif
|
||||
|
||||
/* This include file assumes that signed types are two's complement without
|
||||
padding bits; the above macros have undefined behavior otherwise.
|
||||
If this is a problem for you, please let us know how to fix it for your host.
|
||||
This assumption is tested by the intprops-tests module. */
|
||||
|
||||
/* Does the __typeof__ keyword work? This could be done by
|
||||
'configure', but for now it's easier to do it by hand. */
|
||||
#if (2 <= __GNUC__ \
|
||||
|| (4 <= __clang_major__) \
|
||||
|| (1210 <= __IBMC__ && defined __IBM__TYPEOF__) \
|
||||
|| (0x5110 <= __SUNPRO_C && !__STDC__))
|
||||
# define _GL_HAVE___TYPEOF__ 1
|
||||
#else
|
||||
# define _GL_HAVE___TYPEOF__ 0
|
||||
#endif
|
||||
|
||||
/* Return 1 if the integer type or expression T might be signed. Return 0
|
||||
if it is definitely unsigned. T must not be a bit-field expression.
|
||||
This macro does not evaluate its argument, and expands to an
|
||||
integer constant expression. */
|
||||
#if _GL_HAVE___TYPEOF__
|
||||
# define _GL_SIGNED_TYPE_OR_EXPR(t) _GL_TYPE_SIGNED (__typeof__ (t))
|
||||
#else
|
||||
# define _GL_SIGNED_TYPE_OR_EXPR(t) 1
|
||||
#endif
|
||||
|
||||
/* Return 1 if - A would overflow in [MIN,MAX] arithmetic.
|
||||
A should not have side effects, and A's type should be an
|
||||
integer with minimum value MIN and maximum MAX. */
|
||||
#define _GL_INT_NEGATE_RANGE_OVERFLOW(a, min, max) \
|
||||
((min) < 0 ? (a) < - (max) : 0 < (a))
|
||||
|
||||
/* True if __builtin_add_overflow (A, B, P) and __builtin_sub_overflow
|
||||
(A, B, P) work when P is non-null. */
|
||||
#ifdef __EDG__
|
||||
/* EDG-based compilers like nvc 22.1 cannot add 64-bit signed to unsigned
|
||||
<https://bugs.gnu.org/53256>. */
|
||||
# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
|
||||
#elif defined __has_builtin
|
||||
# define _GL_HAS_BUILTIN_ADD_OVERFLOW __has_builtin (__builtin_add_overflow)
|
||||
/* __builtin_{add,sub}_overflow exists but is not reliable in GCC 5.x and 6.x,
|
||||
see <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98269>. */
|
||||
#elif 7 <= __GNUC__
|
||||
# define _GL_HAS_BUILTIN_ADD_OVERFLOW 1
|
||||
#else
|
||||
# define _GL_HAS_BUILTIN_ADD_OVERFLOW 0
|
||||
#endif
|
||||
|
||||
/* True if __builtin_mul_overflow (A, B, P) works when P is non-null. */
|
||||
#if defined __clang_major__ && __clang_major__ < 14
|
||||
/* Work around Clang bug <https://bugs.llvm.org/show_bug.cgi?id=16404>. */
|
||||
# define _GL_HAS_BUILTIN_MUL_OVERFLOW 0
|
||||
#else
|
||||
# define _GL_HAS_BUILTIN_MUL_OVERFLOW _GL_HAS_BUILTIN_ADD_OVERFLOW
|
||||
#endif
|
||||
|
||||
/* True if __builtin_add_overflow_p (A, B, C) works, and similarly for
|
||||
__builtin_sub_overflow_p and __builtin_mul_overflow_p. */
|
||||
#ifdef __EDG__
|
||||
/* In EDG-based compilers like ICC 2021.3 and earlier,
|
||||
__builtin_add_overflow_p etc. are not treated as integral constant
|
||||
expressions even when all arguments are. */
|
||||
# define _GL_HAS_BUILTIN_OVERFLOW_P 0
|
||||
#elif defined __has_builtin
|
||||
# define _GL_HAS_BUILTIN_OVERFLOW_P __has_builtin (__builtin_mul_overflow_p)
|
||||
#else
|
||||
# define _GL_HAS_BUILTIN_OVERFLOW_P (7 <= __GNUC__)
|
||||
#endif
|
||||
|
||||
#if (!defined _GL_STDCKDINT_H && 202311 <= __STDC_VERSION__ \
|
||||
&& ! (_GL_HAS_BUILTIN_ADD_OVERFLOW && _GL_HAS_BUILTIN_MUL_OVERFLOW))
|
||||
# include <stdckdint.h>
|
||||
#endif
|
||||
|
||||
/* Store the low-order bits of A + B, A - B, A * B, respectively, into *R.
|
||||
Return 1 if the result overflows. Arguments should not have side
|
||||
effects and A, B and *R can be of any integer type other than char,
|
||||
bool, a bit-precise integer type, or an enumeration type. */
|
||||
#if _GL_HAS_BUILTIN_ADD_OVERFLOW
|
||||
# define _GL_INT_ADD_WRAPV(a, b, r) __builtin_add_overflow (a, b, r)
|
||||
# define _GL_INT_SUBTRACT_WRAPV(a, b, r) __builtin_sub_overflow (a, b, r)
|
||||
#elif defined ckd_add && defined ckd_sub && !defined _GL_STDCKDINT_H
|
||||
# define _GL_INT_ADD_WRAPV(a, b, r) ckd_add (r, + (a), + (b))
|
||||
# define _GL_INT_SUBTRACT_WRAPV(a, b, r) ckd_sub (r, + (a), + (b))
|
||||
#else
|
||||
# define _GL_INT_ADD_WRAPV(a, b, r) \
|
||||
_GL_INT_OP_WRAPV (a, b, r, +, _GL_INT_ADD_RANGE_OVERFLOW)
|
||||
# define _GL_INT_SUBTRACT_WRAPV(a, b, r) \
|
||||
_GL_INT_OP_WRAPV (a, b, r, -, _GL_INT_SUBTRACT_RANGE_OVERFLOW)
|
||||
#endif
|
||||
#if _GL_HAS_BUILTIN_MUL_OVERFLOW
|
||||
# if ((9 < __GNUC__ + (3 <= __GNUC_MINOR__) \
|
||||
|| (__GNUC__ == 8 && 4 <= __GNUC_MINOR__)) \
|
||||
&& !defined __EDG__)
|
||||
# define _GL_INT_MULTIPLY_WRAPV(a, b, r) __builtin_mul_overflow (a, b, r)
|
||||
# else
|
||||
/* Work around GCC bug 91450. */
|
||||
# define _GL_INT_MULTIPLY_WRAPV(a, b, r) \
|
||||
((!_GL_SIGNED_TYPE_OR_EXPR (*(r)) && _GL_EXPR_SIGNED (a) && _GL_EXPR_SIGNED (b) \
|
||||
&& _GL_INT_MULTIPLY_RANGE_OVERFLOW (a, b, 0, (__typeof__ (*(r))) -1)) \
|
||||
? ((void) __builtin_mul_overflow (a, b, r), 1) \
|
||||
: __builtin_mul_overflow (a, b, r))
|
||||
# endif
|
||||
#elif defined ckd_mul && !defined _GL_STDCKDINT_H
|
||||
# define _GL_INT_MULTIPLY_WRAPV(a, b, r) ckd_mul (r, + (a), + (b))
|
||||
#else
|
||||
# define _GL_INT_MULTIPLY_WRAPV(a, b, r) \
|
||||
_GL_INT_OP_WRAPV (a, b, r, *, _GL_INT_MULTIPLY_RANGE_OVERFLOW)
|
||||
#endif
|
||||
|
||||
/* Nonzero if this compiler has GCC bug 68193 or Clang bug 25390. See:
|
||||
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68193
|
||||
https://llvm.org/bugs/show_bug.cgi?id=25390
|
||||
For now, assume all versions of GCC-like compilers generate bogus
|
||||
warnings for _Generic. This matters only for compilers that
|
||||
lack relevant builtins. */
|
||||
#if __GNUC__ || defined __clang__
|
||||
# define _GL__GENERIC_BOGUS 1
|
||||
#else
|
||||
# define _GL__GENERIC_BOGUS 0
|
||||
#endif
|
||||
|
||||
/* Store the low-order bits of A <op> B into *R, where OP specifies
|
||||
the operation and OVERFLOW the overflow predicate. Return 1 if the
|
||||
result overflows. Arguments should not have side effects,
|
||||
and A, B and *R can be of any integer type other than char, bool, a
|
||||
bit-precise integer type, or an enumeration type. */
|
||||
#if 201112 <= __STDC_VERSION__ && !_GL__GENERIC_BOGUS
|
||||
# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
|
||||
(_Generic \
|
||||
(*(r), \
|
||||
signed char: \
|
||||
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
|
||||
signed char, SCHAR_MIN, SCHAR_MAX), \
|
||||
unsigned char: \
|
||||
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
|
||||
unsigned char, 0, UCHAR_MAX), \
|
||||
short int: \
|
||||
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
|
||||
short int, SHRT_MIN, SHRT_MAX), \
|
||||
unsigned short int: \
|
||||
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
|
||||
unsigned short int, 0, USHRT_MAX), \
|
||||
int: \
|
||||
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
|
||||
int, INT_MIN, INT_MAX), \
|
||||
unsigned int: \
|
||||
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
|
||||
unsigned int, 0, UINT_MAX), \
|
||||
long int: \
|
||||
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
|
||||
long int, LONG_MIN, LONG_MAX), \
|
||||
unsigned long int: \
|
||||
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
|
||||
unsigned long int, 0, ULONG_MAX), \
|
||||
long long int: \
|
||||
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
|
||||
long long int, LLONG_MIN, LLONG_MAX), \
|
||||
unsigned long long int: \
|
||||
_GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
|
||||
unsigned long long int, 0, ULLONG_MAX)))
|
||||
#else
|
||||
/* Store the low-order bits of A <op> B into *R, where OP specifies
|
||||
the operation and OVERFLOW the overflow predicate. If *R is
|
||||
signed, its type is ST with bounds SMIN..SMAX; otherwise its type
|
||||
is UT with bounds U..UMAX. ST and UT are narrower than int.
|
||||
Return 1 if the result overflows. Arguments should not have side
|
||||
effects, and A, B and *R can be of any integer type other than
|
||||
char, bool, a bit-precise integer type, or an enumeration type. */
|
||||
# if _GL_HAVE___TYPEOF__
|
||||
# define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \
|
||||
(_GL_TYPE_SIGNED (__typeof__ (*(r))) \
|
||||
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, st, smin, smax) \
|
||||
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, ut, 0, umax))
|
||||
# else
|
||||
# define _GL_INT_OP_WRAPV_SMALLISH(a,b,r,op,overflow,st,smin,smax,ut,umax) \
|
||||
(overflow (a, b, smin, smax) \
|
||||
? (overflow (a, b, 0, umax) \
|
||||
? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 1) \
|
||||
: (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) < 0) \
|
||||
: (overflow (a, b, 0, umax) \
|
||||
? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st)) >= 0 \
|
||||
: (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a,b,op,unsigned,st), 0)))
|
||||
# endif
|
||||
|
||||
# define _GL_INT_OP_WRAPV(a, b, r, op, overflow) \
|
||||
(sizeof *(r) == sizeof (signed char) \
|
||||
? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \
|
||||
signed char, SCHAR_MIN, SCHAR_MAX, \
|
||||
unsigned char, UCHAR_MAX) \
|
||||
: sizeof *(r) == sizeof (short int) \
|
||||
? _GL_INT_OP_WRAPV_SMALLISH (a, b, r, op, overflow, \
|
||||
short int, SHRT_MIN, SHRT_MAX, \
|
||||
unsigned short int, USHRT_MAX) \
|
||||
: sizeof *(r) == sizeof (int) \
|
||||
? (_GL_EXPR_SIGNED (*(r)) \
|
||||
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
|
||||
int, INT_MIN, INT_MAX) \
|
||||
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned int, \
|
||||
unsigned int, 0, UINT_MAX)) \
|
||||
: _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow))
|
||||
# ifdef LLONG_MAX
|
||||
# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
|
||||
(sizeof *(r) == sizeof (long int) \
|
||||
? (_GL_EXPR_SIGNED (*(r)) \
|
||||
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
|
||||
long int, LONG_MIN, LONG_MAX) \
|
||||
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
|
||||
unsigned long int, 0, ULONG_MAX)) \
|
||||
: (_GL_EXPR_SIGNED (*(r)) \
|
||||
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
|
||||
long long int, LLONG_MIN, LLONG_MAX) \
|
||||
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long long int, \
|
||||
unsigned long long int, 0, ULLONG_MAX)))
|
||||
# else
|
||||
# define _GL_INT_OP_WRAPV_LONGISH(a, b, r, op, overflow) \
|
||||
(_GL_EXPR_SIGNED (*(r)) \
|
||||
? _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
|
||||
long int, LONG_MIN, LONG_MAX) \
|
||||
: _GL_INT_OP_CALC (a, b, r, op, overflow, unsigned long int, \
|
||||
unsigned long int, 0, ULONG_MAX))
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Store the low-order bits of A <op> B into *R, where the operation
|
||||
is given by OP. Use the unsigned type UT for calculation to avoid
|
||||
overflow problems. *R's type is T, with extrema TMIN and TMAX.
|
||||
T can be any signed integer type other than char, bool, a
|
||||
bit-precise integer type, or an enumeration type.
|
||||
Return 1 if the result overflows. */
|
||||
#define _GL_INT_OP_CALC(a, b, r, op, overflow, ut, t, tmin, tmax) \
|
||||
(overflow (a, b, tmin, tmax) \
|
||||
? (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 1) \
|
||||
: (*(r) = _GL_INT_OP_WRAPV_VIA_UNSIGNED (a, b, op, ut, t), 0))
|
||||
|
||||
/* Return 1 if the integer expressions A - B and -A would overflow,
|
||||
respectively. Arguments should not have side effects,
|
||||
and can be any signed integer type other than char, bool, a
|
||||
bit-precise integer type, or an enumeration type.
|
||||
These macros are tuned for their last input argument being a constant. */
|
||||
|
||||
#if _GL_HAS_BUILTIN_OVERFLOW_P
|
||||
# define _GL_INT_NEGATE_OVERFLOW(a) \
|
||||
__builtin_sub_overflow_p (0, a, (__typeof__ (- (a))) 0)
|
||||
#else
|
||||
# define _GL_INT_NEGATE_OVERFLOW(a) \
|
||||
_GL_INT_NEGATE_RANGE_OVERFLOW (a, _GL_INT_MINIMUM (a), _GL_INT_MAXIMUM (a))
|
||||
#endif
|
||||
|
||||
/* Return the low-order bits of A <op> B, where the operation is given
|
||||
by OP. Use the unsigned type UT for calculation to avoid undefined
|
||||
behavior on signed integer overflow, and convert the result to type T.
|
||||
UT is at least as wide as T and is no narrower than unsigned int,
|
||||
T is two's complement, and there is no padding or trap representations.
|
||||
Assume that converting UT to T yields the low-order bits, as is
|
||||
done in all known two's-complement C compilers. E.g., see:
|
||||
https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html
|
||||
|
||||
According to the C standard, converting UT to T yields an
|
||||
implementation-defined result or signal for values outside T's
|
||||
range. However, code that works around this theoretical problem
|
||||
runs afoul of a compiler bug in Oracle Studio 12.3 x86. See:
|
||||
https://lists.gnu.org/r/bug-gnulib/2017-04/msg00049.html
|
||||
As the compiler bug is real, don't try to work around the
|
||||
theoretical problem. */
|
||||
|
||||
#define _GL_INT_OP_WRAPV_VIA_UNSIGNED(a, b, op, ut, t) \
|
||||
((t) ((ut) (a) op (ut) (b)))
|
||||
|
||||
/* Return true if the numeric values A + B, A - B, A * B fall outside
|
||||
the range TMIN..TMAX. Arguments should not have side effects
|
||||
and can be any integer type other than char, bool,
|
||||
a bit-precise integer type, or an enumeration type.
|
||||
TMIN should be signed and nonpositive.
|
||||
TMAX should be positive, and should be signed unless TMIN is zero. */
|
||||
#define _GL_INT_ADD_RANGE_OVERFLOW(a, b, tmin, tmax) \
|
||||
((b) < 0 \
|
||||
? (((tmin) \
|
||||
? ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (a, (tmin) - (b))) || (b) < (tmin)) \
|
||||
&& (a) < (tmin) - (b)) \
|
||||
: (a) <= -1 - (b)) \
|
||||
|| ((_GL_EXPR_SIGNED (a) ? 0 <= (a) : (tmax) < (a)) && (tmax) < (a) + (b))) \
|
||||
: (a) < 0 \
|
||||
? (((tmin) \
|
||||
? ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (b, (tmin) - (a))) || (a) < (tmin)) \
|
||||
&& (b) < (tmin) - (a)) \
|
||||
: (b) <= -1 - (a)) \
|
||||
|| ((_GL_EXPR_SIGNED (_GL_INT_CONVERT (a, b)) || (tmax) < (b)) \
|
||||
&& (tmax) < (a) + (b))) \
|
||||
: (tmax) < (b) || (tmax) - (b) < (a))
|
||||
#define _GL_INT_SUBTRACT_RANGE_OVERFLOW(a, b, tmin, tmax) \
|
||||
(((a) < 0) == ((b) < 0) \
|
||||
? ((a) < (b) \
|
||||
? !(tmin) || -1 - (tmin) < (b) - (a) - 1 \
|
||||
: (tmax) < (a) - (b)) \
|
||||
: (a) < 0 \
|
||||
? ((!_GL_EXPR_SIGNED (_GL_INT_CONVERT ((a) - (tmin), b)) && (a) - (tmin) < 0) \
|
||||
|| (a) - (tmin) < (b)) \
|
||||
: ((! (_GL_EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
|
||||
&& _GL_EXPR_SIGNED (_GL_INT_CONVERT ((tmax) + (b), a))) \
|
||||
&& (tmax) <= -1 - (b)) \
|
||||
|| (tmax) + (b) < (a)))
|
||||
#define _GL_INT_MULTIPLY_RANGE_OVERFLOW(a, b, tmin, tmax) \
|
||||
((b) < 0 \
|
||||
? ((a) < 0 \
|
||||
? (_GL_EXPR_SIGNED (_GL_INT_CONVERT (tmax, b)) \
|
||||
? (a) < (tmax) / (b) \
|
||||
: ((_GL_INT_NEGATE_OVERFLOW (b) \
|
||||
? _GL_INT_CONVERT (b, tmax) >> (_GL_TYPE_WIDTH (+ (b)) - 1) \
|
||||
: (tmax) / -(b)) \
|
||||
<= -1 - (a))) \
|
||||
: _GL_INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (b, tmin)) && (b) == -1 \
|
||||
? (_GL_EXPR_SIGNED (a) \
|
||||
? 0 < (a) + (tmin) \
|
||||
: 0 < (a) && -1 - (tmin) < (a) - 1) \
|
||||
: (tmin) / (b) < (a)) \
|
||||
: (b) == 0 \
|
||||
? 0 \
|
||||
: ((a) < 0 \
|
||||
? (_GL_INT_NEGATE_OVERFLOW (_GL_INT_CONVERT (a, tmin)) && (a) == -1 \
|
||||
? (_GL_EXPR_SIGNED (b) ? 0 < (b) + (tmin) : -1 - (tmin) < (b) - 1) \
|
||||
: (tmin) / (a) < (b)) \
|
||||
: (tmax) / (b) < (a)))
|
||||
|
||||
#endif /* _GL_INTPROPS_INTERNAL_H */
|
||||
@@ -0,0 +1,35 @@
|
||||
/* stdckdint.h -- checked integer arithmetic
|
||||
|
||||
Copyright 2022-2024 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
#ifndef _GL_STDCKDINT_H
|
||||
#define _GL_STDCKDINT_H
|
||||
|
||||
#include "intprops-internal.h"
|
||||
|
||||
/* Store into *R the low-order bits of A + B, A - B, A * B, respectively.
|
||||
Return 1 if the result overflows, 0 otherwise.
|
||||
A, B, and *R can have any integer type other than char, bool, a
|
||||
bit-precise integer type, or an enumeration type.
|
||||
|
||||
These are like the standard macros introduced in C23, except that
|
||||
arguments should not have side effects. */
|
||||
|
||||
#define ckd_add(r, a, b) ((bool) _GL_INT_ADD_WRAPV (a, b, r))
|
||||
#define ckd_sub(r, a, b) ((bool) _GL_INT_SUBTRACT_WRAPV (a, b, r))
|
||||
#define ckd_mul(r, a, b) ((bool) _GL_INT_MULTIPLY_WRAPV (a, b, r))
|
||||
|
||||
#endif /* _GL_STDCKDINT_H */
|
||||
@@ -0,0 +1,138 @@
|
||||
/* Prefer faster, non-thread-safe stdio functions if available.
|
||||
|
||||
Copyright (C) 2001-2004, 2009-2024 Free Software Foundation, Inc.
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* Written by Jim Meyering. */
|
||||
|
||||
/* Adapted from gnulib:lib/unlocked-io.h */
|
||||
|
||||
#ifndef UNLOCKED_IO_H
|
||||
# define UNLOCKED_IO_H 1
|
||||
|
||||
/* These are wrappers for functions/macros from the GNU C library, and
|
||||
from other C libraries supporting POSIX's optional thread-safe functions.
|
||||
|
||||
The standard I/O functions are thread-safe. These *_unlocked ones are
|
||||
more efficient but not thread-safe. That they're not thread-safe is
|
||||
fine since all of the applications in this package are single threaded.
|
||||
|
||||
Also, some code that is shared with the GNU C library may invoke
|
||||
the *_unlocked functions directly. On hosts that lack those
|
||||
functions, invoke the non-thread-safe versions instead. */
|
||||
|
||||
# include <stdio.h>
|
||||
|
||||
# if HAVE_DECL_CLEARERR_UNLOCKED || defined clearerr_unlocked
|
||||
# undef clearerr
|
||||
# define clearerr(x) clearerr_unlocked (x)
|
||||
# else
|
||||
# define clearerr_unlocked(x) clearerr (x)
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_FEOF_UNLOCKED || defined feof_unlocked
|
||||
# undef feof
|
||||
# define feof(x) feof_unlocked (x)
|
||||
# else
|
||||
# define feof_unlocked(x) feof (x)
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_FERROR_UNLOCKED || defined ferror_unlocked
|
||||
# undef ferror
|
||||
# define ferror(x) ferror_unlocked (x)
|
||||
# else
|
||||
# define ferror_unlocked(x) ferror (x)
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_FFLUSH_UNLOCKED || defined fflush_unlocked
|
||||
# undef fflush
|
||||
# define fflush(x) fflush_unlocked (x)
|
||||
# else
|
||||
# define fflush_unlocked(x) fflush (x)
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_FGETS_UNLOCKED || defined fgets_unlocked
|
||||
# undef fgets
|
||||
# define fgets(x,y,z) fgets_unlocked (x,y,z)
|
||||
# else
|
||||
# define fgets_unlocked(x,y,z) fgets (x,y,z)
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_FPUTC_UNLOCKED || defined fputc_unlocked
|
||||
# undef fputc
|
||||
# define fputc(x,y) fputc_unlocked (x,y)
|
||||
# else
|
||||
# define fputc_unlocked(x,y) fputc (x,y)
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_FPUTS_UNLOCKED || defined fputs_unlocked
|
||||
# undef fputs
|
||||
# define fputs(x,y) fputs_unlocked (x,y)
|
||||
# else
|
||||
# define fputs_unlocked(x,y) fputs (x,y)
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_FREAD_UNLOCKED || defined fread_unlocked
|
||||
# undef fread
|
||||
# define fread(w,x,y,z) fread_unlocked (w,x,y,z)
|
||||
# else
|
||||
# define fread_unlocked(w,x,y,z) fread (w,x,y,z)
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_FWRITE_UNLOCKED || defined fwrite_unlocked
|
||||
# undef fwrite
|
||||
# define fwrite(w,x,y,z) fwrite_unlocked (w,x,y,z)
|
||||
# else
|
||||
# define fwrite_unlocked(w,x,y,z) fwrite (w,x,y,z)
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_GETC_UNLOCKED || defined getc_unlocked
|
||||
# undef getc
|
||||
# define getc(x) getc_unlocked (x)
|
||||
# else
|
||||
# define getc_unlocked(x) getc (x)
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_GETCHAR_UNLOCKED || defined getchar_unlocked
|
||||
# undef getchar
|
||||
# define getchar() getchar_unlocked ()
|
||||
# else
|
||||
# define getchar_unlocked() getchar ()
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_PUTC_UNLOCKED || defined putc_unlocked
|
||||
# undef putc
|
||||
# define putc(x,y) putc_unlocked (x,y)
|
||||
# else
|
||||
# define putc_unlocked(x,y) putc (x,y)
|
||||
# endif
|
||||
|
||||
# if HAVE_DECL_PUTCHAR_UNLOCKED || defined putchar_unlocked
|
||||
# undef putchar
|
||||
# define putchar(x) putchar_unlocked (x)
|
||||
# else
|
||||
# define putchar_unlocked(x) putchar (x)
|
||||
# endif
|
||||
|
||||
# undef flockfile
|
||||
# define flockfile(x) ((void) 0)
|
||||
|
||||
# undef ftrylockfile
|
||||
# define ftrylockfile(x) 0
|
||||
|
||||
# undef funlockfile
|
||||
# define funlockfile(x) ((void) 0)
|
||||
|
||||
#endif /* UNLOCKED_IO_H */
|
||||
@@ -0,0 +1,26 @@
|
||||
/* A C macro for declaring that specific arguments must not be NULL.
|
||||
Copyright (C) 2009-2022 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
/* _GL_ARG_NONNULL((n,...,m)) tells the compiler and static analyzer tools
|
||||
that the values passed as arguments n, ..., m must be non-NULL pointers.
|
||||
n = 1 stands for the first argument, n = 2 for the second argument etc. */
|
||||
#ifndef _GL_ARG_NONNULL
|
||||
# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || defined __clang__
|
||||
# define _GL_ARG_NONNULL(params) __attribute__ ((__nonnull__ params))
|
||||
# else
|
||||
# define _GL_ARG_NONNULL(params)
|
||||
# endif
|
||||
#endif
|
||||
@@ -0,0 +1,226 @@
|
||||
/* ATTRIBUTE_* macros for using attributes in GCC and similar compilers
|
||||
|
||||
Copyright 2020-2022 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Paul Eggert. */
|
||||
|
||||
/* Provide public ATTRIBUTE_* names for the private _GL_ATTRIBUTE_*
|
||||
macros used within Gnulib. */
|
||||
|
||||
/* These attributes can be placed in two ways:
|
||||
- At the start of a declaration (i.e. even before storage-class
|
||||
specifiers!); then they apply to all entities that are declared
|
||||
by the declaration.
|
||||
- Immediately after the name of an entity being declared by the
|
||||
declaration; then they apply to that entity only. */
|
||||
|
||||
#ifndef _GL_ATTRIBUTE_H
|
||||
#define _GL_ATTRIBUTE_H
|
||||
|
||||
|
||||
/* This file defines two types of attributes:
|
||||
* C2x standard attributes. These have macro names that do not begin with
|
||||
'ATTRIBUTE_'.
|
||||
* Selected GCC attributes; see:
|
||||
https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
|
||||
https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html
|
||||
https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html
|
||||
These names begin with 'ATTRIBUTE_' to avoid name clashes. */
|
||||
|
||||
|
||||
/* =============== Attributes for specific kinds of functions =============== */
|
||||
|
||||
/* Attributes for functions that should not be used. */
|
||||
|
||||
/* Warn if the entity is used. */
|
||||
/* Applies to:
|
||||
- function, variable,
|
||||
- struct, union, struct/union member,
|
||||
- enumeration, enumeration item,
|
||||
- typedef,
|
||||
in C++ also: namespace, class, template specialization. */
|
||||
#define DEPRECATED _GL_ATTRIBUTE_DEPRECATED
|
||||
|
||||
/* If a function call is not optimized way, warn with MSG. */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_WARNING(msg) _GL_ATTRIBUTE_WARNING (msg)
|
||||
|
||||
/* If a function call is not optimized way, report an error with MSG. */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_ERROR(msg) _GL_ATTRIBUTE_ERROR (msg)
|
||||
|
||||
|
||||
/* Attributes for memory-allocating functions. */
|
||||
|
||||
/* The function returns a pointer to freshly allocated memory. */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_MALLOC _GL_ATTRIBUTE_MALLOC
|
||||
|
||||
/* ATTRIBUTE_ALLOC_SIZE ((N)) - The Nth argument of the function
|
||||
is the size of the returned memory block.
|
||||
ATTRIBUTE_ALLOC_SIZE ((M, N)) - Multiply the Mth and Nth arguments
|
||||
to determine the size of the returned memory block. */
|
||||
/* Applies to: function, pointer to function, function types. */
|
||||
#define ATTRIBUTE_ALLOC_SIZE(args) _GL_ATTRIBUTE_ALLOC_SIZE (args)
|
||||
|
||||
/* ATTRIBUTE_DEALLOC (F, I) declares that the function returns pointers
|
||||
that can be freed by passing them as the Ith argument to the
|
||||
function F.
|
||||
ATTRIBUTE_DEALLOC_FREE declares that the function returns pointers that
|
||||
can be freed via 'free'; it can be used only after declaring 'free'. */
|
||||
/* Applies to: functions. Cannot be used on inline functions. */
|
||||
#define ATTRIBUTE_DEALLOC(f, i) _GL_ATTRIBUTE_DEALLOC(f, i)
|
||||
#define ATTRIBUTE_DEALLOC_FREE _GL_ATTRIBUTE_DEALLOC_FREE
|
||||
|
||||
/* Attributes for variadic functions. */
|
||||
|
||||
/* The variadic function expects a trailing NULL argument.
|
||||
ATTRIBUTE_SENTINEL () - The last argument is NULL (requires C99).
|
||||
ATTRIBUTE_SENTINEL ((N)) - The (N+1)st argument from the end is NULL. */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_SENTINEL(pos) _GL_ATTRIBUTE_SENTINEL (pos)
|
||||
|
||||
|
||||
/* ================== Attributes for compiler diagnostics ================== */
|
||||
|
||||
/* Attributes that help the compiler diagnose programmer mistakes.
|
||||
Some of them may also help for some compiler optimizations. */
|
||||
|
||||
/* ATTRIBUTE_FORMAT ((ARCHETYPE, STRING-INDEX, FIRST-TO-CHECK)) -
|
||||
The STRING-INDEXth function argument is a format string of style
|
||||
ARCHETYPE, which is one of:
|
||||
printf, gnu_printf
|
||||
scanf, gnu_scanf,
|
||||
strftime, gnu_strftime,
|
||||
strfmon,
|
||||
or the same thing prefixed and suffixed with '__'.
|
||||
If FIRST-TO-CHECK is not 0, arguments starting at FIRST-TO_CHECK
|
||||
are suitable for the format string. */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_FORMAT(spec) _GL_ATTRIBUTE_FORMAT (spec)
|
||||
|
||||
/* ATTRIBUTE_NONNULL ((N1, N2,...)) - Arguments N1, N2,... must not be NULL.
|
||||
ATTRIBUTE_NONNULL () - All pointer arguments must not be null. */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_NONNULL(args) _GL_ATTRIBUTE_NONNULL (args)
|
||||
|
||||
/* The function's return value is a non-NULL pointer. */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_RETURNS_NONNULL _GL_ATTRIBUTE_RETURNS_NONNULL
|
||||
|
||||
/* Warn if the caller does not use the return value,
|
||||
unless the caller uses something like ignore_value. */
|
||||
/* Applies to: function, enumeration, class. */
|
||||
#define NODISCARD _GL_ATTRIBUTE_NODISCARD
|
||||
|
||||
|
||||
/* Attributes that disable false alarms when the compiler diagnoses
|
||||
programmer "mistakes". */
|
||||
|
||||
/* Do not warn if the entity is not used. */
|
||||
/* Applies to:
|
||||
- function, variable,
|
||||
- struct, union, struct/union member,
|
||||
- enumeration, enumeration item,
|
||||
- typedef,
|
||||
in C++ also: class. */
|
||||
#define MAYBE_UNUSED _GL_ATTRIBUTE_MAYBE_UNUSED
|
||||
|
||||
/* The contents of a character array is not meant to be NUL-terminated. */
|
||||
/* Applies to: struct/union members and variables that are arrays of element
|
||||
type '[[un]signed] char'. */
|
||||
#define ATTRIBUTE_NONSTRING _GL_ATTRIBUTE_NONSTRING
|
||||
|
||||
/* Do not warn if control flow falls through to the immediately
|
||||
following 'case' or 'default' label. */
|
||||
/* Applies to: Empty statement (;), inside a 'switch' statement. */
|
||||
#define FALLTHROUGH _GL_ATTRIBUTE_FALLTHROUGH
|
||||
|
||||
|
||||
/* ================== Attributes for debugging information ================== */
|
||||
|
||||
/* Attributes regarding debugging information emitted by the compiler. */
|
||||
|
||||
/* Omit the function from stack traces when debugging. */
|
||||
/* Applies to: function. */
|
||||
#define ATTRIBUTE_ARTIFICIAL _GL_ATTRIBUTE_ARTIFICIAL
|
||||
|
||||
/* Make the entity visible to debuggers etc., even with '-fwhole-program'. */
|
||||
/* Applies to: functions, variables. */
|
||||
#define ATTRIBUTE_EXTERNALLY_VISIBLE _GL_ATTRIBUTE_EXTERNALLY_VISIBLE
|
||||
|
||||
|
||||
/* ========== Attributes that mainly direct compiler optimizations ========== */
|
||||
|
||||
/* The function does not throw exceptions. */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_NOTHROW _GL_ATTRIBUTE_NOTHROW
|
||||
|
||||
/* Do not inline the function. */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_NOINLINE _GL_ATTRIBUTE_NOINLINE
|
||||
|
||||
/* Always inline the function, and report an error if the compiler
|
||||
cannot inline. */
|
||||
/* Applies to: function. */
|
||||
#define ATTRIBUTE_ALWAYS_INLINE _GL_ATTRIBUTE_ALWAYS_INLINE
|
||||
|
||||
/* It is OK for a compiler to omit duplicate calls with the same arguments.
|
||||
This attribute is safe for a function that neither depends on
|
||||
nor affects observable state, and always returns exactly once -
|
||||
e.g., does not loop forever, and does not call longjmp.
|
||||
(This attribute is stricter than ATTRIBUTE_PURE.) */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_CONST _GL_ATTRIBUTE_CONST
|
||||
|
||||
/* It is OK for a compiler to omit duplicate calls with the same
|
||||
arguments if observable state is not changed between calls.
|
||||
This attribute is safe for a function that does not affect
|
||||
observable state, and always returns exactly once.
|
||||
(This attribute is looser than ATTRIBUTE_CONST.) */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_PURE _GL_ATTRIBUTE_PURE
|
||||
|
||||
/* The function is rarely executed. */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_COLD _GL_ATTRIBUTE_COLD
|
||||
|
||||
/* If called from some other compilation unit, the function executes
|
||||
code from that unit only by return or by exception handling,
|
||||
letting the compiler optimize that unit more aggressively. */
|
||||
/* Applies to: functions. */
|
||||
#define ATTRIBUTE_LEAF _GL_ATTRIBUTE_LEAF
|
||||
|
||||
/* For struct members: The member has the smallest possible alignment.
|
||||
For struct, union, class: All members have the smallest possible alignment,
|
||||
minimizing the memory required. */
|
||||
/* Applies to: struct members, struct, union,
|
||||
in C++ also: class. */
|
||||
#define ATTRIBUTE_PACKED _GL_ATTRIBUTE_PACKED
|
||||
|
||||
|
||||
/* ================ Attributes that make invalid code valid ================ */
|
||||
|
||||
/* Attributes that prevent fatal compiler optimizations for code that is not
|
||||
fully ISO C compliant. */
|
||||
|
||||
/* Pointers to the type may point to the same storage as pointers to
|
||||
other types, thus disabling strict aliasing optimization. */
|
||||
/* Applies to: types. */
|
||||
#define ATTRIBUTE_MAY_ALIAS _GL_ATTRIBUTE_MAY_ALIAS
|
||||
|
||||
|
||||
#endif /* _GL_ATTRIBUTE_H */
|
||||
@@ -0,0 +1,8 @@
|
||||
|
||||
#if @HAVE_VISIBILITY@ && BUILDING_LIBINTL
|
||||
#define LIBINTL_DLL_EXPORTED __attribute__((__visibility__("default")))
|
||||
#elif defined _MSC_VER && BUILDING_LIBINTL
|
||||
#define LIBINTL_DLL_EXPORTED __declspec(dllexport)
|
||||
#else
|
||||
#define LIBINTL_DLL_EXPORTED
|
||||
#endif
|
||||
@@ -0,0 +1,110 @@
|
||||
/* Basic filename support macros.
|
||||
Copyright (C) 2001-2004, 2007-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
/* From Paul Eggert and Jim Meyering. */
|
||||
|
||||
#ifndef _FILENAME_H
|
||||
#define _FILENAME_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Filename support.
|
||||
ISSLASH(C) tests whether C is a directory separator
|
||||
character.
|
||||
HAS_DEVICE(Filename) tests whether Filename contains a device
|
||||
specification.
|
||||
FILE_SYSTEM_PREFIX_LEN(Filename) length of the device specification
|
||||
at the beginning of Filename,
|
||||
index of the part consisting of
|
||||
alternating components and slashes.
|
||||
FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
|
||||
1 when a non-empty device specification
|
||||
can be followed by an empty or relative
|
||||
part,
|
||||
0 when a non-empty device specification
|
||||
must be followed by a slash,
|
||||
0 when device specification don't exist.
|
||||
IS_ABSOLUTE_FILE_NAME(Filename)
|
||||
tests whether Filename is independent of
|
||||
any notion of "current directory".
|
||||
IS_RELATIVE_FILE_NAME(Filename)
|
||||
tests whether Filename may be concatenated
|
||||
to a directory filename.
|
||||
Note: On native Windows, OS/2, DOS, "c:" is neither an absolute nor a
|
||||
relative file name!
|
||||
IS_FILE_NAME_WITH_DIR(Filename) tests whether Filename contains a device
|
||||
or directory specification.
|
||||
*/
|
||||
#if defined _WIN32 || defined __CYGWIN__ \
|
||||
|| defined __EMX__ || defined __MSDOS__ || defined __DJGPP__
|
||||
/* Native Windows, Cygwin, OS/2, DOS */
|
||||
# define ISSLASH(C) ((C) == '/' || (C) == '\\')
|
||||
/* Internal macro: Tests whether a character is a drive letter. */
|
||||
# define _IS_DRIVE_LETTER(C) \
|
||||
(((C) >= 'A' && (C) <= 'Z') || ((C) >= 'a' && (C) <= 'z'))
|
||||
/* Help the compiler optimizing it. This assumes ASCII. */
|
||||
# undef _IS_DRIVE_LETTER
|
||||
# define _IS_DRIVE_LETTER(C) \
|
||||
(((unsigned int) (C) | ('a' - 'A')) - 'a' <= 'z' - 'a')
|
||||
# define HAS_DEVICE(Filename) \
|
||||
(_IS_DRIVE_LETTER ((Filename)[0]) && (Filename)[1] == ':')
|
||||
# define FILE_SYSTEM_PREFIX_LEN(Filename) (HAS_DEVICE (Filename) ? 2 : 0)
|
||||
# ifdef __CYGWIN__
|
||||
# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0
|
||||
# else
|
||||
/* On native Windows, OS/2, DOS, the system has the notion of a
|
||||
"current directory" on each drive. */
|
||||
# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 1
|
||||
# endif
|
||||
# if FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE
|
||||
# define IS_ABSOLUTE_FILE_NAME(Filename) \
|
||||
ISSLASH ((Filename)[FILE_SYSTEM_PREFIX_LEN (Filename)])
|
||||
# else
|
||||
# define IS_ABSOLUTE_FILE_NAME(Filename) \
|
||||
(ISSLASH ((Filename)[0]) || HAS_DEVICE (Filename))
|
||||
# endif
|
||||
# define IS_RELATIVE_FILE_NAME(Filename) \
|
||||
(! (ISSLASH ((Filename)[0]) || HAS_DEVICE (Filename)))
|
||||
# define IS_FILE_NAME_WITH_DIR(Filename) \
|
||||
(strchr ((Filename), '/') != NULL || strchr ((Filename), '\\') != NULL \
|
||||
|| HAS_DEVICE (Filename))
|
||||
#else
|
||||
/* Unix */
|
||||
# define ISSLASH(C) ((C) == '/')
|
||||
# define HAS_DEVICE(Filename) ((void) (Filename), 0)
|
||||
# define FILE_SYSTEM_PREFIX_LEN(Filename) ((void) (Filename), 0)
|
||||
# define FILE_SYSTEM_DRIVE_PREFIX_CAN_BE_RELATIVE 0
|
||||
# define IS_ABSOLUTE_FILE_NAME(Filename) ISSLASH ((Filename)[0])
|
||||
# define IS_RELATIVE_FILE_NAME(Filename) (! ISSLASH ((Filename)[0]))
|
||||
# define IS_FILE_NAME_WITH_DIR(Filename) (strchr ((Filename), '/') != NULL)
|
||||
#endif
|
||||
|
||||
/* Deprecated macros. For backward compatibility with old users of the
|
||||
'filename' module. */
|
||||
#define IS_ABSOLUTE_PATH IS_ABSOLUTE_FILE_NAME
|
||||
#define IS_PATH_WITH_DIR IS_FILE_NAME_WITH_DIR
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FILENAME_H */
|
||||
@@ -0,0 +1,57 @@
|
||||
/* Sizes of structs with flexible array members.
|
||||
|
||||
Copyright 2016-2019 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Paul Eggert. */
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/* Nonzero multiple of alignment of TYPE, suitable for FLEXSIZEOF below.
|
||||
On older platforms without _Alignof, use a pessimistic bound that is
|
||||
safe in practice even if FLEXIBLE_ARRAY_MEMBER is 1.
|
||||
On newer platforms, use _Alignof to get a tighter bound. */
|
||||
|
||||
#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112
|
||||
# define FLEXALIGNOF(type) (sizeof (type) & ~ (sizeof (type) - 1))
|
||||
#else
|
||||
# define FLEXALIGNOF(type) _Alignof (type)
|
||||
#endif
|
||||
|
||||
/* Yield a properly aligned upper bound on the size of a struct of
|
||||
type TYPE with a flexible array member named MEMBER that is
|
||||
followed by N bytes of other data. The result is suitable as an
|
||||
argument to malloc. For example:
|
||||
|
||||
struct s { int n; char d[FLEXIBLE_ARRAY_MEMBER]; };
|
||||
struct s *p = malloc (FLEXSIZEOF (struct s, d, n * sizeof (char)));
|
||||
|
||||
FLEXSIZEOF (TYPE, MEMBER, N) is not simply (sizeof (TYPE) + N),
|
||||
since FLEXIBLE_ARRAY_MEMBER may be 1 on pre-C11 platforms. Nor is
|
||||
it simply (offsetof (TYPE, MEMBER) + N), as that might yield a size
|
||||
that causes malloc to yield a pointer that is not properly aligned
|
||||
for TYPE; for example, if sizeof (int) == alignof (int) == 4,
|
||||
malloc (offsetof (struct s, d) + 3 * sizeof (char)) is equivalent
|
||||
to malloc (7) and might yield a pointer that is not a multiple of 4
|
||||
(which means the pointer is not properly aligned for struct s),
|
||||
whereas malloc (FLEXSIZEOF (struct s, d, 3 * sizeof (char))) is
|
||||
equivalent to malloc (8) and must yield a pointer that is a
|
||||
multiple of 4.
|
||||
|
||||
Yield a value less than N if and only if arithmetic overflow occurs. */
|
||||
|
||||
#define FLEXSIZEOF(type, member, n) \
|
||||
((offsetof (type, member) + FLEXALIGNOF (type) - 1 + (n)) \
|
||||
& ~ (FLEXALIGNOF (type) - 1))
|
||||
@@ -0,0 +1,50 @@
|
||||
/* Implements a string hashing function.
|
||||
Copyright (C) 1995-2016 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/>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
/* Specification. */
|
||||
#include "hash-string.h"
|
||||
|
||||
|
||||
/* Defines the so called `hashpjw' function by P.J. Weinberger
|
||||
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
|
||||
1986, 1987 Bell Telephone Laboratories, Inc.] */
|
||||
unsigned long int
|
||||
__hash_string (const char *str_param)
|
||||
{
|
||||
unsigned long int hval, g;
|
||||
const char *str = str_param;
|
||||
|
||||
/* Compute the hash value for the given string. */
|
||||
hval = 0;
|
||||
while (*str != '\0')
|
||||
{
|
||||
hval <<= 4;
|
||||
hval += (unsigned char) *str++;
|
||||
g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4));
|
||||
if (g != 0)
|
||||
{
|
||||
hval ^= g >> (HASHWORDBITS - 8);
|
||||
hval ^= g;
|
||||
}
|
||||
}
|
||||
return hval;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* List of exported symbols of libintl on Cygwin.
|
||||
Copyright (C) 2006, 2012-2020 Free Software Foundation, Inc.
|
||||
Written by Bruno Haible <bruno@clisp.org>, 2006.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
/* IMP(x) is a symbol that contains the address of x. */
|
||||
#if defined _WIN64 || defined _LP64
|
||||
# define IMP(x) __imp_##x
|
||||
#else
|
||||
# define IMP(x) _imp__##x
|
||||
#endif
|
||||
|
||||
/* Ensure that the variable x is exported from the library, and that a
|
||||
pseudo-variable IMP(x) is available. */
|
||||
#define VARIABLE(x) \
|
||||
/* Export x without redefining x. This code was found by compiling a \
|
||||
snippet: \
|
||||
extern __declspec(dllexport) int x; int x = 42; */ \
|
||||
asm (".section .drectve\n"); \
|
||||
asm (".ascii \" -export:" #x ",data\"\n"); \
|
||||
asm (".data\n"); \
|
||||
/* Allocate a pseudo-variable IMP(x). */ \
|
||||
extern int x; \
|
||||
void * IMP(x) = &x;
|
||||
|
||||
VARIABLE(libintl_version)
|
||||
@@ -0,0 +1,406 @@
|
||||
/* Determine the user's language preferences.
|
||||
Copyright (C) 2004-2007, 2018-2019 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Bruno Haible <bruno@clisp.org>.
|
||||
Win32 code originally by Michele Cicciotti <hackbunny@reactos.com>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if HAVE_CFLOCALECOPYPREFERREDLANGUAGES || HAVE_CFPREFERENCESCOPYAPPVALUE
|
||||
# include <string.h>
|
||||
# if HAVE_CFLOCALECOPYPREFERREDLANGUAGES
|
||||
# include <CoreFoundation/CFLocale.h>
|
||||
# elif HAVE_CFPREFERENCESCOPYAPPVALUE
|
||||
# include <CoreFoundation/CFPreferences.h>
|
||||
# endif
|
||||
# include <CoreFoundation/CFPropertyList.h>
|
||||
# include <CoreFoundation/CFArray.h>
|
||||
# include <CoreFoundation/CFString.h>
|
||||
extern void _nl_locale_name_canonicalize (char *name);
|
||||
#endif
|
||||
|
||||
#if defined _WIN32
|
||||
# define WIN32_NATIVE
|
||||
#endif
|
||||
|
||||
#ifdef WIN32_NATIVE
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
|
||||
# ifndef MUI_LANGUAGE_NAME
|
||||
# define MUI_LANGUAGE_NAME 8
|
||||
# endif
|
||||
# ifndef STATUS_BUFFER_OVERFLOW
|
||||
# define STATUS_BUFFER_OVERFLOW 0x80000005
|
||||
# endif
|
||||
|
||||
extern void _nl_locale_name_canonicalize (char *name);
|
||||
extern const char *_nl_locale_name_from_win32_LANGID (LANGID langid);
|
||||
extern const char *_nl_locale_name_from_win32_LCID (LCID lcid);
|
||||
|
||||
/* Get the preferences list through the MUI APIs. This works on Windows Vista
|
||||
and newer. */
|
||||
static const char *
|
||||
_nl_language_preferences_win32_mui (HMODULE kernel32)
|
||||
{
|
||||
/* DWORD GetUserPreferredUILanguages (ULONG dwFlags,
|
||||
PULONG pulNumLanguages,
|
||||
PWSTR pwszLanguagesBuffer,
|
||||
PULONG pcchLanguagesBuffer); */
|
||||
typedef DWORD (WINAPI *GetUserPreferredUILanguages_func) (ULONG, PULONG, PWSTR, PULONG);
|
||||
GetUserPreferredUILanguages_func p_GetUserPreferredUILanguages;
|
||||
|
||||
p_GetUserPreferredUILanguages =
|
||||
(GetUserPreferredUILanguages_func)
|
||||
GetProcAddress (kernel32, "GetUserPreferredUILanguages");
|
||||
if (p_GetUserPreferredUILanguages != NULL)
|
||||
{
|
||||
ULONG num_languages;
|
||||
ULONG bufsize;
|
||||
DWORD ret;
|
||||
|
||||
bufsize = 0;
|
||||
ret = p_GetUserPreferredUILanguages (MUI_LANGUAGE_NAME,
|
||||
&num_languages,
|
||||
NULL, &bufsize);
|
||||
if (ret == 0
|
||||
&& GetLastError () == STATUS_BUFFER_OVERFLOW
|
||||
&& bufsize > 0)
|
||||
{
|
||||
WCHAR *buffer = (WCHAR *) malloc (bufsize * sizeof (WCHAR));
|
||||
if (buffer != NULL)
|
||||
{
|
||||
ret = p_GetUserPreferredUILanguages (MUI_LANGUAGE_NAME,
|
||||
&num_languages,
|
||||
buffer, &bufsize);
|
||||
if (ret)
|
||||
{
|
||||
/* Convert the list from NUL-delimited WCHAR[] Win32 locale
|
||||
names to colon-delimited char[] Unix locale names.
|
||||
We assume that all these locale names are in ASCII,
|
||||
nonempty and contain no colons. */
|
||||
char *languages =
|
||||
(char *) malloc (bufsize + num_languages * 10 + 1);
|
||||
if (languages != NULL)
|
||||
{
|
||||
const WCHAR *p = buffer;
|
||||
char *q = languages;
|
||||
ULONG i;
|
||||
for (i = 0; i < num_languages; i++)
|
||||
{
|
||||
char *q1;
|
||||
char *q2;
|
||||
|
||||
q1 = q;
|
||||
if (i > 0)
|
||||
*q++ = ':';
|
||||
q2 = q;
|
||||
for (; *p != (WCHAR)'\0'; p++)
|
||||
{
|
||||
if ((unsigned char) *p != *p || *p == ':')
|
||||
{
|
||||
/* A non-ASCII character or a colon inside
|
||||
the Win32 locale name! Punt. */
|
||||
q = q1;
|
||||
break;
|
||||
}
|
||||
*q++ = (unsigned char) *p;
|
||||
}
|
||||
if (q == q1)
|
||||
/* An unexpected Win32 locale name occurred. */
|
||||
break;
|
||||
*q = '\0';
|
||||
_nl_locale_name_canonicalize (q2);
|
||||
q = q2 + strlen (q2);
|
||||
p++;
|
||||
}
|
||||
*q = '\0';
|
||||
if (q > languages)
|
||||
{
|
||||
free (buffer);
|
||||
return languages;
|
||||
}
|
||||
free (languages);
|
||||
}
|
||||
}
|
||||
free (buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get a preference. This works on Windows ME and newer. */
|
||||
static const char *
|
||||
_nl_language_preferences_win32_ME (HMODULE kernel32)
|
||||
{
|
||||
/* LANGID GetUserDefaultUILanguage (void); */
|
||||
typedef LANGID (WINAPI *GetUserDefaultUILanguage_func) (void);
|
||||
GetUserDefaultUILanguage_func p_GetUserDefaultUILanguage;
|
||||
|
||||
p_GetUserDefaultUILanguage =
|
||||
(GetUserDefaultUILanguage_func)
|
||||
GetProcAddress (kernel32, "GetUserDefaultUILanguage");
|
||||
if (p_GetUserDefaultUILanguage != NULL)
|
||||
return _nl_locale_name_from_win32_LANGID (p_GetUserDefaultUILanguage ());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get a preference. This works on Windows 95 and newer. */
|
||||
static const char *
|
||||
_nl_language_preferences_win32_95 ()
|
||||
{
|
||||
HKEY desktop_resource_locale_key;
|
||||
|
||||
if (RegOpenKeyExA (HKEY_CURRENT_USER,
|
||||
"Control Panel\\Desktop\\ResourceLocale",
|
||||
0, KEY_QUERY_VALUE, &desktop_resource_locale_key)
|
||||
== NO_ERROR)
|
||||
{
|
||||
DWORD type;
|
||||
BYTE data[8 + 1];
|
||||
DWORD data_size = sizeof (data);
|
||||
DWORD ret;
|
||||
|
||||
ret = RegQueryValueExA (desktop_resource_locale_key, NULL, NULL,
|
||||
&type, data, &data_size);
|
||||
RegCloseKey (desktop_resource_locale_key);
|
||||
|
||||
if (ret == NO_ERROR)
|
||||
{
|
||||
/* We expect a string, at most 8 bytes long, that parses as a
|
||||
hexadecimal number. */
|
||||
if (type == REG_SZ
|
||||
&& data_size <= sizeof (data)
|
||||
&& (data_size < sizeof (data)
|
||||
|| data[sizeof (data) - 1] == '\0'))
|
||||
{
|
||||
LCID lcid;
|
||||
char *endp;
|
||||
/* Ensure it's NUL terminated. */
|
||||
if (data_size < sizeof (data))
|
||||
data[data_size] = '\0';
|
||||
/* Parse it as a hexadecimal number. */
|
||||
lcid = strtoul ((char *) data, &endp, 16);
|
||||
if (endp > (char *) data && *endp == '\0')
|
||||
return _nl_locale_name_from_win32_LCID (lcid);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the system's preference. This can be used as a fallback. */
|
||||
static BOOL CALLBACK
|
||||
ret_first_language (HMODULE h, LPCSTR type, LPCSTR name, WORD lang, LONG_PTR param)
|
||||
{
|
||||
*(const char **)param = _nl_locale_name_from_win32_LANGID (lang);
|
||||
return FALSE;
|
||||
}
|
||||
static const char *
|
||||
_nl_language_preferences_win32_system (HMODULE kernel32)
|
||||
{
|
||||
const char *languages = NULL;
|
||||
/* Ignore the warning on mingw here. mingw has a wrong definition of the last
|
||||
parameter type of ENUMRESLANGPROC. */
|
||||
EnumResourceLanguages (kernel32, RT_VERSION, MAKEINTRESOURCE (1),
|
||||
ret_first_language, (LONG_PTR)&languages);
|
||||
return languages;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Determine the user's language preferences, as a colon separated list of
|
||||
locale names in XPG syntax
|
||||
language[_territory][.codeset][@modifier]
|
||||
The result must not be freed; it is statically allocated.
|
||||
The LANGUAGE environment variable does not need to be considered; it is
|
||||
already taken into account by the caller. */
|
||||
|
||||
const char *
|
||||
_nl_language_preferences_default (void)
|
||||
{
|
||||
#if HAVE_CFLOCALECOPYPREFERREDLANGUAGES || HAVE_CFPREFERENCESCOPYAPPVALUE
|
||||
/* MacOS X 10.4 or newer */
|
||||
{
|
||||
/* Cache the preferences list, since CoreFoundation calls are expensive. */
|
||||
static const char *cached_languages;
|
||||
static int cache_initialized;
|
||||
|
||||
if (!cache_initialized)
|
||||
{
|
||||
# if HAVE_CFLOCALECOPYPREFERREDLANGUAGES /* MacOS X 10.5 or newer */
|
||||
CFArrayRef prefArray = CFLocaleCopyPreferredLanguages ();
|
||||
# elif HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.4 or newer */
|
||||
CFTypeRef preferences =
|
||||
CFPreferencesCopyAppValue (CFSTR ("AppleLanguages"),
|
||||
kCFPreferencesCurrentApplication);
|
||||
if (preferences != NULL
|
||||
&& CFGetTypeID (preferences) == CFArrayGetTypeID ())
|
||||
{
|
||||
CFArrayRef prefArray = (CFArrayRef)preferences;
|
||||
# endif
|
||||
|
||||
int n = CFArrayGetCount (prefArray);
|
||||
char buf[256];
|
||||
char buf2[256];
|
||||
size_t size = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
CFTypeRef element = CFArrayGetValueAtIndex (prefArray, i);
|
||||
if (element != NULL
|
||||
&& CFGetTypeID (element) == CFStringGetTypeID ()
|
||||
&& CFStringGetCString ((CFStringRef)element,
|
||||
buf, sizeof (buf),
|
||||
kCFStringEncodingASCII))
|
||||
{
|
||||
strcpy (buf2, buf);
|
||||
_nl_locale_name_canonicalize (buf);
|
||||
size += strlen (buf) + 1;
|
||||
/* Mac OS X 10.12 or newer returns an array of elements of
|
||||
the form "ll-CC" or "ll-Scrp-CC" where ll is a language
|
||||
code, CC is a country code, and Scrp (optional) is a
|
||||
script code.
|
||||
_nl_locale_name_canonicalize converts this to "ll_CC" or
|
||||
"ll_Scrp_CC".
|
||||
Sometimes ll and CC are unrelated, i.e. there is no
|
||||
translation for "ll_CC" but one for "ll".
|
||||
Similarly, in the case with a script, sometimes there is
|
||||
no translation for "ll_Scrp_CC" but one for "ll_Scrp"
|
||||
(after proper canonicalization).
|
||||
Therefore, in the result, we return "ll_CC" followed
|
||||
by "ll", or similarly for the case with a script. */
|
||||
{
|
||||
char *last_minus = strrchr (buf2, '-');
|
||||
if (last_minus != NULL)
|
||||
{
|
||||
*last_minus = '\0';
|
||||
_nl_locale_name_canonicalize (buf2);
|
||||
size += strlen (buf2) + 1;
|
||||
}
|
||||
}
|
||||
/* Most GNU programs use msgids in English and don't ship
|
||||
an en.mo message catalog. Therefore when we see "en" or
|
||||
"en-CC" in the preferences list, arrange for gettext()
|
||||
to return the msgid, and ignore all further elements of
|
||||
the preferences list. */
|
||||
if (buf[0] == 'e' && buf[1] == 'n'
|
||||
&& (buf[2] == '\0' || buf[2] == '_'))
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (size > 0)
|
||||
{
|
||||
char *languages = (char *) malloc (size);
|
||||
|
||||
if (languages != NULL)
|
||||
{
|
||||
char *p = languages;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
CFTypeRef element =
|
||||
CFArrayGetValueAtIndex (prefArray, i);
|
||||
if (element != NULL
|
||||
&& CFGetTypeID (element) == CFStringGetTypeID ()
|
||||
&& CFStringGetCString ((CFStringRef)element,
|
||||
buf, sizeof (buf),
|
||||
kCFStringEncodingASCII))
|
||||
{
|
||||
strcpy (buf2, buf);
|
||||
_nl_locale_name_canonicalize (buf);
|
||||
strcpy (p, buf);
|
||||
p += strlen (buf);
|
||||
*p++ = ':';
|
||||
{
|
||||
char *last_minus = strrchr (buf2, '-');
|
||||
if (last_minus != NULL)
|
||||
{
|
||||
*last_minus = '\0';
|
||||
_nl_locale_name_canonicalize (buf2);
|
||||
strcpy (p, buf2);
|
||||
p += strlen (buf2);
|
||||
*p++ = ':';
|
||||
}
|
||||
}
|
||||
if (buf[0] == 'e' && buf[1] == 'n'
|
||||
&& (buf[2] == '\0' || buf[2] == '_'))
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
*--p = '\0';
|
||||
|
||||
cached_languages = languages;
|
||||
}
|
||||
}
|
||||
|
||||
# if HAVE_CFLOCALECOPYPREFERREDLANGUAGES /* MacOS X 10.5 or newer */
|
||||
CFRelease (prefArray);
|
||||
# elif HAVE_CFPREFERENCESCOPYAPPVALUE /* MacOS X 10.4 or newer */
|
||||
}
|
||||
# endif
|
||||
cache_initialized = 1;
|
||||
}
|
||||
if (cached_languages != NULL)
|
||||
return cached_languages;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32_NATIVE
|
||||
{
|
||||
/* Cache the preferences list, since computing it is expensive. */
|
||||
static const char *cached_languages;
|
||||
static int cache_initialized;
|
||||
|
||||
/* Activate the new code only when the GETTEXT_MUI environment variable is
|
||||
set, for the time being, since the new code is not well tested. */
|
||||
if (!cache_initialized && getenv ("GETTEXT_MUI") != NULL)
|
||||
{
|
||||
const char *languages = NULL;
|
||||
HMODULE kernel32 = GetModuleHandle ("kernel32");
|
||||
|
||||
if (kernel32 != NULL)
|
||||
languages = _nl_language_preferences_win32_mui (kernel32);
|
||||
|
||||
if (languages == NULL && kernel32 != NULL)
|
||||
languages = _nl_language_preferences_win32_ME (kernel32);
|
||||
|
||||
if (languages == NULL)
|
||||
languages = _nl_language_preferences_win32_95 ();
|
||||
|
||||
if (languages == NULL && kernel32 != NULL)
|
||||
languages = _nl_language_preferences_win32_system (kernel32);
|
||||
|
||||
cached_languages = languages;
|
||||
cache_initialized = 1;
|
||||
}
|
||||
if (cached_languages != NULL)
|
||||
return cached_languages;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,599 @@
|
||||
/* Message catalogs for internationalization.
|
||||
Copyright (C) 1995-1997, 2000-2016, 2018-2022 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
#ifndef _LIBINTL_H
|
||||
#define _LIBINTL_H 1
|
||||
|
||||
#include <locale.h>
|
||||
#if (defined __APPLE__ && defined __MACH__) && @HAVE_NEWLOCALE@
|
||||
# include <xlocale.h>
|
||||
#endif
|
||||
|
||||
/* The LC_MESSAGES locale category is the category used by the functions
|
||||
gettext() and dgettext(). It is specified in POSIX, but not in ANSI C.
|
||||
On systems that don't define it, use an arbitrary value instead.
|
||||
On Solaris, <locale.h> defines __LOCALE_H (or _LOCALE_H in Solaris 2.5)
|
||||
then includes <libintl.h> (i.e. this file!) and then only defines
|
||||
LC_MESSAGES. To avoid a redefinition warning, don't define LC_MESSAGES
|
||||
in this case. */
|
||||
#if !defined LC_MESSAGES && !(defined __LOCALE_H || (defined _LOCALE_H && defined __sun))
|
||||
# define LC_MESSAGES 1729
|
||||
#endif
|
||||
|
||||
/* We define an additional symbol to signal that we use the GNU
|
||||
implementation of gettext. */
|
||||
#define __USE_GNU_GETTEXT 1
|
||||
|
||||
/* Provide information about the supported file formats. Returns the
|
||||
maximum minor revision number supported for a given major revision. */
|
||||
#define __GNU_GETTEXT_SUPPORTED_REVISION(major) \
|
||||
((major) == 0 || (major) == 1 ? 1 : -1)
|
||||
|
||||
/* Resolve a platform specific conflict on DJGPP. GNU gettext takes
|
||||
precedence over _conio_gettext. */
|
||||
#ifdef __DJGPP__
|
||||
# undef gettext
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Version number: (major<<16) + (minor<<8) + subminor */
|
||||
#define LIBINTL_VERSION 0x001501
|
||||
extern int libintl_version;
|
||||
|
||||
|
||||
/* We redirect the functions to those prefixed with "libintl_". This is
|
||||
necessary, because some systems define gettext/textdomain/... in the C
|
||||
library (namely, Solaris 2.4 and newer, and GNU libc 2.0 and newer).
|
||||
If we used the unprefixed names, there would be cases where the
|
||||
definition in the C library would override the one in the libintl.so
|
||||
shared library. Recall that on ELF systems, the symbols are looked
|
||||
up in the following order:
|
||||
1. in the executable,
|
||||
2. in the shared libraries specified on the link command line, in order,
|
||||
3. in the dependencies of the shared libraries specified on the link
|
||||
command line,
|
||||
4. in the dlopen()ed shared libraries, in the order in which they were
|
||||
dlopen()ed.
|
||||
The definition in the C library would override the one in libintl.so if
|
||||
either
|
||||
* -lc is given on the link command line and -lintl isn't, or
|
||||
* -lc is given on the link command line before -lintl, or
|
||||
* libintl.so is a dependency of a dlopen()ed shared library but not
|
||||
linked to the executable at link time.
|
||||
Since Solaris gettext() behaves differently than GNU gettext(), this
|
||||
would be unacceptable.
|
||||
|
||||
The redirection happens by default through macros in C, so that &gettext
|
||||
is independent of the compilation unit, but through inline functions in
|
||||
C++, in order not to interfere with the name mangling of class fields or
|
||||
class methods called 'gettext'. */
|
||||
|
||||
/* The user can define _INTL_REDIRECT_INLINE or _INTL_REDIRECT_MACROS.
|
||||
If he doesn't, we choose the method. A third possible method is
|
||||
_INTL_REDIRECT_ASM, supported only by GCC. */
|
||||
#if !(defined _INTL_REDIRECT_INLINE || defined _INTL_REDIRECT_MACROS)
|
||||
# if defined __GNUC__ && __GNUC__ >= 2 && !(defined __APPLE_CC__ && __APPLE_CC__ > 1) && !defined __MINGW32__ && !(__GNUC__ == 2 && defined _AIX) && (defined __STDC__ || defined __cplusplus)
|
||||
# define _INTL_REDIRECT_ASM
|
||||
# else
|
||||
# ifdef __cplusplus
|
||||
# define _INTL_REDIRECT_INLINE
|
||||
# else
|
||||
# define _INTL_REDIRECT_MACROS
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
/* Auxiliary macros. */
|
||||
#ifdef _INTL_REDIRECT_ASM
|
||||
# define _INTL_ASM(cname) __asm__ (_INTL_ASMNAME (__USER_LABEL_PREFIX__, #cname))
|
||||
# define _INTL_ASMNAME(prefix,cnamestring) _INTL_STRINGIFY (prefix) cnamestring
|
||||
# define _INTL_STRINGIFY(prefix) #prefix
|
||||
#else
|
||||
# define _INTL_ASM(cname)
|
||||
#endif
|
||||
|
||||
/* _INTL_MAY_RETURN_STRING_ARG(n) declares that the given function may return
|
||||
its n-th argument literally. This enables GCC to warn for example about
|
||||
printf (gettext ("foo %y")). */
|
||||
#if defined __GNUC__ && __GNUC__ >= 3 && !(defined __APPLE_CC__ && __APPLE_CC__ > 1 && !(defined __clang__ && __clang__ && __clang_major__ >= 3) && defined __cplusplus)
|
||||
# define _INTL_MAY_RETURN_STRING_ARG(n) __attribute__ ((__format_arg__ (n)))
|
||||
#else
|
||||
# define _INTL_MAY_RETURN_STRING_ARG(n)
|
||||
#endif
|
||||
|
||||
/* Look up MSGID in the current default message catalog for the current
|
||||
LC_MESSAGES locale. If not found, returns MSGID itself (the default
|
||||
text). */
|
||||
#ifdef _INTL_REDIRECT_INLINE
|
||||
extern char *libintl_gettext (const char *__msgid)
|
||||
_INTL_MAY_RETURN_STRING_ARG (1);
|
||||
static inline
|
||||
_INTL_MAY_RETURN_STRING_ARG (1)
|
||||
char *gettext (const char *__msgid)
|
||||
{
|
||||
return libintl_gettext (__msgid);
|
||||
}
|
||||
#else
|
||||
# ifdef _INTL_REDIRECT_MACROS
|
||||
# define gettext libintl_gettext
|
||||
# endif
|
||||
extern char *gettext (const char *__msgid)
|
||||
_INTL_ASM (libintl_gettext)
|
||||
_INTL_MAY_RETURN_STRING_ARG (1);
|
||||
#endif
|
||||
|
||||
/* Look up MSGID in the DOMAINNAME message catalog for the current
|
||||
LC_MESSAGES locale. */
|
||||
#ifdef _INTL_REDIRECT_INLINE
|
||||
extern char *libintl_dgettext (const char *__domainname, const char *__msgid)
|
||||
_INTL_MAY_RETURN_STRING_ARG (2);
|
||||
static inline
|
||||
_INTL_MAY_RETURN_STRING_ARG (2)
|
||||
char *dgettext (const char *__domainname, const char *__msgid)
|
||||
{
|
||||
return libintl_dgettext (__domainname, __msgid);
|
||||
}
|
||||
#else
|
||||
# ifdef _INTL_REDIRECT_MACROS
|
||||
# define dgettext libintl_dgettext
|
||||
# endif
|
||||
extern char *dgettext (const char *__domainname, const char *__msgid)
|
||||
_INTL_ASM (libintl_dgettext)
|
||||
_INTL_MAY_RETURN_STRING_ARG (2);
|
||||
#endif
|
||||
|
||||
/* Look up MSGID in the DOMAINNAME message catalog for the current CATEGORY
|
||||
locale. */
|
||||
#ifdef _INTL_REDIRECT_INLINE
|
||||
extern char *libintl_dcgettext (const char *__domainname, const char *__msgid,
|
||||
int __category)
|
||||
_INTL_MAY_RETURN_STRING_ARG (2);
|
||||
static inline
|
||||
_INTL_MAY_RETURN_STRING_ARG (2)
|
||||
char *dcgettext (const char *__domainname, const char *__msgid, int __category)
|
||||
{
|
||||
return libintl_dcgettext (__domainname, __msgid, __category);
|
||||
}
|
||||
#else
|
||||
# ifdef _INTL_REDIRECT_MACROS
|
||||
# define dcgettext libintl_dcgettext
|
||||
# endif
|
||||
extern char *dcgettext (const char *__domainname, const char *__msgid,
|
||||
int __category)
|
||||
_INTL_ASM (libintl_dcgettext)
|
||||
_INTL_MAY_RETURN_STRING_ARG (2);
|
||||
#endif
|
||||
|
||||
|
||||
/* Similar to 'gettext' but select the plural form corresponding to the
|
||||
number N. */
|
||||
#ifdef _INTL_REDIRECT_INLINE
|
||||
extern char *libintl_ngettext (const char *__msgid1, const char *__msgid2,
|
||||
unsigned long int __n)
|
||||
_INTL_MAY_RETURN_STRING_ARG (1) _INTL_MAY_RETURN_STRING_ARG (2);
|
||||
static inline
|
||||
_INTL_MAY_RETURN_STRING_ARG (1) _INTL_MAY_RETURN_STRING_ARG (2)
|
||||
char *ngettext (const char *__msgid1, const char *__msgid2,
|
||||
unsigned long int __n)
|
||||
{
|
||||
return libintl_ngettext (__msgid1, __msgid2, __n);
|
||||
}
|
||||
#else
|
||||
# ifdef _INTL_REDIRECT_MACROS
|
||||
# define ngettext libintl_ngettext
|
||||
# endif
|
||||
extern char *ngettext (const char *__msgid1, const char *__msgid2,
|
||||
unsigned long int __n)
|
||||
_INTL_ASM (libintl_ngettext)
|
||||
_INTL_MAY_RETURN_STRING_ARG (1) _INTL_MAY_RETURN_STRING_ARG (2);
|
||||
#endif
|
||||
|
||||
/* Similar to 'dgettext' but select the plural form corresponding to the
|
||||
number N. */
|
||||
#ifdef _INTL_REDIRECT_INLINE
|
||||
extern char *libintl_dngettext (const char *__domainname, const char *__msgid1,
|
||||
const char *__msgid2, unsigned long int __n)
|
||||
_INTL_MAY_RETURN_STRING_ARG (2) _INTL_MAY_RETURN_STRING_ARG (3);
|
||||
static inline
|
||||
_INTL_MAY_RETURN_STRING_ARG (2) _INTL_MAY_RETURN_STRING_ARG (3)
|
||||
char *dngettext (const char *__domainname, const char *__msgid1,
|
||||
const char *__msgid2, unsigned long int __n)
|
||||
{
|
||||
return libintl_dngettext (__domainname, __msgid1, __msgid2, __n);
|
||||
}
|
||||
#else
|
||||
# ifdef _INTL_REDIRECT_MACROS
|
||||
# define dngettext libintl_dngettext
|
||||
# endif
|
||||
extern char *dngettext (const char *__domainname,
|
||||
const char *__msgid1, const char *__msgid2,
|
||||
unsigned long int __n)
|
||||
_INTL_ASM (libintl_dngettext)
|
||||
_INTL_MAY_RETURN_STRING_ARG (2) _INTL_MAY_RETURN_STRING_ARG (3);
|
||||
#endif
|
||||
|
||||
/* Similar to 'dcgettext' but select the plural form corresponding to the
|
||||
number N. */
|
||||
#ifdef _INTL_REDIRECT_INLINE
|
||||
extern char *libintl_dcngettext (const char *__domainname,
|
||||
const char *__msgid1, const char *__msgid2,
|
||||
unsigned long int __n, int __category)
|
||||
_INTL_MAY_RETURN_STRING_ARG (2) _INTL_MAY_RETURN_STRING_ARG (3);
|
||||
static inline
|
||||
_INTL_MAY_RETURN_STRING_ARG (2) _INTL_MAY_RETURN_STRING_ARG (3)
|
||||
char *dcngettext (const char *__domainname,
|
||||
const char *__msgid1, const char *__msgid2,
|
||||
unsigned long int __n, int __category)
|
||||
{
|
||||
return libintl_dcngettext (__domainname, __msgid1, __msgid2, __n, __category);
|
||||
}
|
||||
#else
|
||||
# ifdef _INTL_REDIRECT_MACROS
|
||||
# define dcngettext libintl_dcngettext
|
||||
# endif
|
||||
extern char *dcngettext (const char *__domainname,
|
||||
const char *__msgid1, const char *__msgid2,
|
||||
unsigned long int __n, int __category)
|
||||
_INTL_ASM (libintl_dcngettext)
|
||||
_INTL_MAY_RETURN_STRING_ARG (2) _INTL_MAY_RETURN_STRING_ARG (3);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef IN_LIBGLOCALE
|
||||
|
||||
/* Set the current default message catalog to DOMAINNAME.
|
||||
If DOMAINNAME is null, return the current default.
|
||||
If DOMAINNAME is "", reset to the default of "messages". */
|
||||
# ifdef _INTL_REDIRECT_INLINE
|
||||
extern char *libintl_textdomain (const char *__domainname);
|
||||
static inline char *textdomain (const char *__domainname)
|
||||
{
|
||||
return libintl_textdomain (__domainname);
|
||||
}
|
||||
# else
|
||||
# ifdef _INTL_REDIRECT_MACROS
|
||||
# define textdomain libintl_textdomain
|
||||
# endif
|
||||
extern char *textdomain (const char *__domainname)
|
||||
_INTL_ASM (libintl_textdomain);
|
||||
# endif
|
||||
|
||||
/* Specify that the DOMAINNAME message catalog will be found
|
||||
in DIRNAME rather than in the system locale data base. */
|
||||
# ifdef _INTL_REDIRECT_INLINE
|
||||
extern char *libintl_bindtextdomain (const char *__domainname,
|
||||
const char *__dirname);
|
||||
static inline char *bindtextdomain (const char *__domainname,
|
||||
const char *__dirname)
|
||||
{
|
||||
return libintl_bindtextdomain (__domainname, __dirname);
|
||||
}
|
||||
# else
|
||||
# ifdef _INTL_REDIRECT_MACROS
|
||||
# define bindtextdomain libintl_bindtextdomain
|
||||
# endif
|
||||
extern char *bindtextdomain (const char *__domainname, const char *__dirname)
|
||||
_INTL_ASM (libintl_bindtextdomain);
|
||||
# endif
|
||||
|
||||
# if defined _WIN32 && !defined __CYGWIN__
|
||||
/* Specify that the DOMAINNAME message catalog will be found
|
||||
in WDIRNAME rather than in the system locale data base. */
|
||||
# ifdef _INTL_REDIRECT_INLINE
|
||||
extern wchar_t *libintl_wbindtextdomain (const char *__domainname,
|
||||
const wchar_t *__wdirname);
|
||||
static inline wchar_t *wbindtextdomain (const char *__domainname,
|
||||
const wchar_t *__wdirname)
|
||||
{
|
||||
return libintl_wbindtextdomain (__domainname, __wdirname);
|
||||
}
|
||||
# else
|
||||
# ifdef _INTL_REDIRECT_MACROS
|
||||
# define wbindtextdomain libintl_wbindtextdomain
|
||||
# endif
|
||||
extern wchar_t *wbindtextdomain (const char *__domainname,
|
||||
const wchar_t *__wdirname)
|
||||
_INTL_ASM (libintl_wbindtextdomain);
|
||||
# endif
|
||||
# endif
|
||||
|
||||
/* Specify the character encoding in which the messages from the
|
||||
DOMAINNAME message catalog will be returned. */
|
||||
# ifdef _INTL_REDIRECT_INLINE
|
||||
extern char *libintl_bind_textdomain_codeset (const char *__domainname,
|
||||
const char *__codeset);
|
||||
static inline char *bind_textdomain_codeset (const char *__domainname,
|
||||
const char *__codeset)
|
||||
{
|
||||
return libintl_bind_textdomain_codeset (__domainname, __codeset);
|
||||
}
|
||||
# else
|
||||
# ifdef _INTL_REDIRECT_MACROS
|
||||
# define bind_textdomain_codeset libintl_bind_textdomain_codeset
|
||||
# endif
|
||||
extern char *bind_textdomain_codeset (const char *__domainname,
|
||||
const char *__codeset)
|
||||
_INTL_ASM (libintl_bind_textdomain_codeset);
|
||||
# endif
|
||||
|
||||
#endif /* IN_LIBGLOCALE */
|
||||
|
||||
|
||||
/* Support for format strings with positions in *printf(), following the
|
||||
POSIX/XSI specification.
|
||||
Note: These replacements for the *printf() functions are visible only
|
||||
in source files that #include <libintl.h> or #include "gettext.h".
|
||||
Packages that use *printf() in source files that don't refer to _()
|
||||
or gettext() but for which the format string could be the return value
|
||||
of _() or gettext() need to add this #include. Oh well. */
|
||||
|
||||
/* Note: In C++ mode, it is not sufficient to redefine a symbol at the
|
||||
preprocessor macro level, such as
|
||||
#define sprintf libintl_sprintf
|
||||
Some programs may reference std::sprintf after including <libintl.h>.
|
||||
Therefore we must make sure that std::libintl_sprintf is defined and
|
||||
identical to ::libintl_sprintf.
|
||||
The user can define _INTL_CXX_NO_CLOBBER_STD_NAMESPACE to avoid this.
|
||||
In such cases, they will not benefit from the overrides when using
|
||||
the 'std' namespace, and they will need to do the references to the
|
||||
'std' namespace *before* including <libintl.h> or "gettext.h". */
|
||||
|
||||
#if !@HAVE_POSIX_PRINTF@
|
||||
|
||||
# include <stdio.h>
|
||||
# include <stddef.h>
|
||||
|
||||
/* Get va_list. */
|
||||
# if (defined __STDC__ && __STDC__) || defined __cplusplus || defined _MSC_VER
|
||||
# include <stdarg.h>
|
||||
# else
|
||||
# include <varargs.h>
|
||||
# endif
|
||||
|
||||
# if !((defined fprintf && defined _GL_STDIO_H) || defined GNULIB_overrides_fprintf) /* don't override gnulib */
|
||||
# undef fprintf
|
||||
# define fprintf libintl_fprintf
|
||||
extern int fprintf (FILE *, const char *, ...);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_fprintf; }
|
||||
# endif
|
||||
# endif
|
||||
# if !((defined vfprintf && defined _GL_STDIO_H) || defined GNULIB_overrides_vfprintf) /* don't override gnulib */
|
||||
# undef vfprintf
|
||||
# define vfprintf libintl_vfprintf
|
||||
extern int vfprintf (FILE *, const char *, va_list);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_vfprintf; }
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !((defined printf && defined _GL_STDIO_H) || defined GNULIB_overrides_printf) /* don't override gnulib */
|
||||
# undef printf
|
||||
# if defined __NetBSD__ || defined __BEOS__ || defined __CYGWIN__ || defined __MINGW32__
|
||||
/* Don't break __attribute__((format(printf,M,N))).
|
||||
This redefinition is only possible because the libc in NetBSD, Cygwin,
|
||||
mingw does not have a function __printf__.
|
||||
Alternatively, we could have done this redirection only when compiling with
|
||||
__GNUC__, together with a symbol redirection:
|
||||
extern int printf (const char *, ...)
|
||||
__asm__ (#__USER_LABEL_PREFIX__ "libintl_printf");
|
||||
But doing it now would introduce a binary incompatibility with already
|
||||
distributed versions of libintl on these systems. */
|
||||
# define libintl_printf __printf__
|
||||
# endif
|
||||
# define printf libintl_printf
|
||||
extern int printf (const char *, ...);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_printf; }
|
||||
# endif
|
||||
# endif
|
||||
# if !((defined vprintf && defined _GL_STDIO_H) || defined GNULIB_overrides_vprintf) /* don't override gnulib */
|
||||
# undef vprintf
|
||||
# define vprintf libintl_vprintf
|
||||
extern int vprintf (const char *, va_list);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_vprintf; }
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !((defined sprintf && defined _GL_STDIO_H) || defined GNULIB_overrides_sprintf) /* don't override gnulib */
|
||||
# undef sprintf
|
||||
# define sprintf libintl_sprintf
|
||||
extern int sprintf (char *, const char *, ...);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_sprintf; }
|
||||
# endif
|
||||
# endif
|
||||
# if !((defined vsprintf && defined _GL_STDIO_H) || defined GNULIB_overrides_vsprintf) /* don't override gnulib */
|
||||
# undef vsprintf
|
||||
# define vsprintf libintl_vsprintf
|
||||
extern int vsprintf (char *, const char *, va_list);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_vsprintf; }
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if @HAVE_SNPRINTF@
|
||||
|
||||
# if !((defined snprintf && defined _GL_STDIO_H) || defined GNULIB_overrides_snprintf) /* don't override gnulib */
|
||||
# undef snprintf
|
||||
# define snprintf libintl_snprintf
|
||||
extern int snprintf (char *, size_t, const char *, ...);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_snprintf; }
|
||||
# endif
|
||||
# endif
|
||||
# if !((defined vsnprintf && defined _GL_STDIO_H) || defined GNULIB_overrides_vsnprintf) /* don't override gnulib */
|
||||
# undef vsnprintf
|
||||
# define vsnprintf libintl_vsnprintf
|
||||
extern int vsnprintf (char *, size_t, const char *, va_list);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_vsnprintf; }
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
# if @HAVE_ASPRINTF@
|
||||
|
||||
# if !((defined asprintf && defined _GL_STDIO_H) || defined GNULIB_overrides_asprintf) /* don't override gnulib */
|
||||
# undef asprintf
|
||||
# define asprintf libintl_asprintf
|
||||
extern int asprintf (char **, const char *, ...);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_asprintf; }
|
||||
# endif
|
||||
# endif
|
||||
# if !((defined vasprintf && defined _GL_STDIO_H) || defined GNULIB_overrides_vasprintf) /* don't override gnulib */
|
||||
# undef vasprintf
|
||||
# define vasprintf libintl_vasprintf
|
||||
extern int vasprintf (char **, const char *, va_list);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_vasprintf; }
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
# if @HAVE_WPRINTF@
|
||||
|
||||
# undef fwprintf
|
||||
# define fwprintf libintl_fwprintf
|
||||
extern int fwprintf (FILE *, const wchar_t *, ...);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_fwprintf; }
|
||||
# endif
|
||||
# undef vfwprintf
|
||||
# define vfwprintf libintl_vfwprintf
|
||||
extern int vfwprintf (FILE *, const wchar_t *, va_list);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_vfwprintf; }
|
||||
# endif
|
||||
|
||||
# undef wprintf
|
||||
# define wprintf libintl_wprintf
|
||||
extern int wprintf (const wchar_t *, ...);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_wprintf; }
|
||||
# endif
|
||||
# undef vwprintf
|
||||
# define vwprintf libintl_vwprintf
|
||||
extern int vwprintf (const wchar_t *, va_list);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_vwprintf; }
|
||||
# endif
|
||||
|
||||
# undef swprintf
|
||||
# define swprintf libintl_swprintf
|
||||
extern int swprintf (wchar_t *, size_t, const wchar_t *, ...);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_swprintf; }
|
||||
# endif
|
||||
# undef vswprintf
|
||||
# define vswprintf libintl_vswprintf
|
||||
extern int vswprintf (wchar_t *, size_t, const wchar_t *, va_list);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_vswprintf; }
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Support for retrieving the name of a locale_t object. */
|
||||
#if @ENHANCE_LOCALE_FUNCS@
|
||||
|
||||
# ifndef GNULIB_defined_newlocale /* don't override gnulib */
|
||||
# undef newlocale
|
||||
# define newlocale libintl_newlocale
|
||||
extern locale_t newlocale (int, const char *, locale_t);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_newlocale; }
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef GNULIB_defined_duplocale /* don't override gnulib */
|
||||
# undef duplocale
|
||||
# define duplocale libintl_duplocale
|
||||
extern locale_t duplocale (locale_t);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_duplocale; }
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifndef GNULIB_defined_freelocale /* don't override gnulib */
|
||||
# undef freelocale
|
||||
# define freelocale libintl_freelocale
|
||||
extern void freelocale (locale_t);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_freelocale; }
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Support for the locale chosen by the user. */
|
||||
#if (defined __APPLE__ && defined __MACH__) || defined _WIN32 || defined __CYGWIN__
|
||||
|
||||
# ifndef GNULIB_defined_setlocale /* don't override gnulib */
|
||||
# undef setlocale
|
||||
# define setlocale libintl_setlocale
|
||||
extern char *setlocale (int, const char *);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_setlocale; }
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if @HAVE_NEWLOCALE@
|
||||
|
||||
# undef newlocale
|
||||
# define newlocale libintl_newlocale
|
||||
/* Declare newlocale() only if the system headers define the 'locale_t' type. */
|
||||
# if !(defined __CYGWIN__ && !defined LC_ALL_MASK)
|
||||
extern locale_t newlocale (int, const char *, locale_t);
|
||||
# if defined __cplusplus && !defined _INTL_CXX_NO_CLOBBER_STD_NAMESPACE
|
||||
namespace std { using ::libintl_newlocale; }
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* Support for relocatable packages. */
|
||||
|
||||
/* Sets the original and the current installation prefix of the package.
|
||||
Relocation simply replaces a pathname starting with the original prefix
|
||||
by the corresponding pathname with the current prefix instead. Both
|
||||
prefixes should be directory names without trailing slash (i.e. use ""
|
||||
instead of "/"). */
|
||||
#define libintl_set_relocation_prefix libintl_set_relocation_prefix
|
||||
extern void
|
||||
libintl_set_relocation_prefix (const char *orig_prefix,
|
||||
const char *curr_prefix);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* libintl.h */
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Table that maps a locale object to the names of the locale categories.
|
||||
Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Bruno Haible <bruno@clisp.org>, 2018. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if HAVE_WORKING_USELOCALE && HAVE_NAMELESS_LOCALES
|
||||
|
||||
/* Specification. */
|
||||
#include "localename-table.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* A hash function for pointers. */
|
||||
size_t _GL_ATTRIBUTE_CONST
|
||||
locale_hash_function (locale_t x)
|
||||
{
|
||||
uintptr_t p = (uintptr_t) x;
|
||||
size_t h = ((p % 4177) << 12) + ((p % 79) << 6) + (p % 61);
|
||||
return h;
|
||||
}
|
||||
|
||||
struct locale_hash_node * locale_hash_table[LOCALE_HASH_TABLE_SIZE]
|
||||
/* = { NULL, ..., NULL } */;
|
||||
|
||||
gl_rwlock_define_initialized(, locale_lock)
|
||||
|
||||
#else
|
||||
|
||||
/* This declaration is solely to ensure that after preprocessing
|
||||
this file is never empty. */
|
||||
typedef int dummy;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
/* Table that maps a locale object to the names of the locale categories.
|
||||
Copyright (C) 2018 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Bruno Haible <bruno@clisp.org>, 2018. */
|
||||
|
||||
#if HAVE_WORKING_USELOCALE && HAVE_NAMELESS_LOCALES
|
||||
|
||||
# include <stddef.h>
|
||||
# include <locale.h>
|
||||
|
||||
# ifdef IN_LIBINTL
|
||||
# include "lock.h"
|
||||
# else
|
||||
# include "glthread/lock.h"
|
||||
# endif
|
||||
|
||||
struct locale_categories_names
|
||||
{
|
||||
/* Locale category -> name (allocated with indefinite extent). */
|
||||
const char *category_name[6];
|
||||
};
|
||||
|
||||
/* A hash table of fixed size. Multiple threads can access it read-only
|
||||
simultaneously, but only one thread can insert into it or remove from it
|
||||
at the same time.
|
||||
This hash table has global scope, so that when an application uses both
|
||||
GNU libintl and gnulib, the application sees only one hash table. (When
|
||||
linking statically with libintl, the fact that localename-table.c is a
|
||||
separate compilation unit resolves the duplicate symbol conflict. When
|
||||
linking with libintl as a shared library, we rely on ELF and the symbol
|
||||
conflict resolution implemented in the ELF dynamic loader here.)
|
||||
Both the libintl overrides and the gnulib overrides of the functions
|
||||
newlocale, duplocale, freelocale see the same hash table (and the same lock).
|
||||
For this reason, the internal layout of the hash table and the hash function
|
||||
MUST NEVER CHANGE. If you need to change the internal layout or the hash
|
||||
function, introduce versioning by appending a version suffix to the symbols
|
||||
at the linker level. */
|
||||
# define locale_hash_function libintl_locale_hash_function
|
||||
# define locale_hash_table libintl_locale_hash_table
|
||||
# define locale_lock libintl_locale_lock
|
||||
|
||||
extern size_t _GL_ATTRIBUTE_CONST locale_hash_function (locale_t x);
|
||||
|
||||
/* A node in a hash bucket collision list. */
|
||||
struct locale_hash_node
|
||||
{
|
||||
struct locale_hash_node *next;
|
||||
locale_t locale;
|
||||
struct locale_categories_names names;
|
||||
};
|
||||
|
||||
# define LOCALE_HASH_TABLE_SIZE 101
|
||||
extern struct locale_hash_node * locale_hash_table[LOCALE_HASH_TABLE_SIZE];
|
||||
|
||||
/* This lock protects the locale_hash_table against multiple simultaneous
|
||||
accesses (except that multiple simultaneous read accesses are allowed). */
|
||||
|
||||
gl_rwlock_define(extern, locale_lock)
|
||||
|
||||
#endif
|
||||
+749
@@ -0,0 +1,749 @@
|
||||
/* Locking in multithreaded situations.
|
||||
Copyright (C) 2005-2008, 2012, 2017, 2019-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Bruno Haible <bruno@clisp.org>, 2005.
|
||||
Based on GCC's gthr-posix.h, gthr-posix95.h. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "lock.h"
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
|
||||
|
||||
/* -------------------------- gl_lock_t datatype -------------------------- */
|
||||
|
||||
int
|
||||
glthread_lock_init (gl_lock_t *lock)
|
||||
{
|
||||
if (mtx_init (&lock->mutex, mtx_plain) != thrd_success)
|
||||
return ENOMEM;
|
||||
lock->init_needed = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_lock_lock (gl_lock_t *lock)
|
||||
{
|
||||
if (lock->init_needed)
|
||||
call_once (&lock->init_once, lock->init_func);
|
||||
if (mtx_lock (&lock->mutex) != thrd_success)
|
||||
return EAGAIN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_lock_unlock (gl_lock_t *lock)
|
||||
{
|
||||
if (lock->init_needed)
|
||||
call_once (&lock->init_once, lock->init_func);
|
||||
if (mtx_unlock (&lock->mutex) != thrd_success)
|
||||
return EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_lock_destroy (gl_lock_t *lock)
|
||||
{
|
||||
if (lock->init_needed)
|
||||
call_once (&lock->init_once, lock->init_func);
|
||||
mtx_destroy (&lock->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
|
||||
|
||||
int
|
||||
glthread_rwlock_init (gl_rwlock_t *lock)
|
||||
{
|
||||
if (mtx_init (&lock->lock, mtx_plain) != thrd_success
|
||||
|| cnd_init (&lock->waiting_readers) != thrd_success
|
||||
|| cnd_init (&lock->waiting_writers) != thrd_success)
|
||||
return ENOMEM;
|
||||
lock->waiting_writers_count = 0;
|
||||
lock->runcount = 0;
|
||||
lock->init_needed = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_rdlock (gl_rwlock_t *lock)
|
||||
{
|
||||
if (lock->init_needed)
|
||||
call_once (&lock->init_once, lock->init_func);
|
||||
if (mtx_lock (&lock->lock) != thrd_success)
|
||||
return EAGAIN;
|
||||
/* Test whether only readers are currently running, and whether the runcount
|
||||
field will not overflow, and whether no writer is waiting. The latter
|
||||
condition is because POSIX recommends that "write locks shall take
|
||||
precedence over read locks", to avoid "writer starvation". */
|
||||
while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
|
||||
{
|
||||
/* This thread has to wait for a while. Enqueue it among the
|
||||
waiting_readers. */
|
||||
if (cnd_wait (&lock->waiting_readers, &lock->lock) != thrd_success)
|
||||
{
|
||||
mtx_unlock (&lock->lock);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
lock->runcount++;
|
||||
if (mtx_unlock (&lock->lock) != thrd_success)
|
||||
return EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_wrlock (gl_rwlock_t *lock)
|
||||
{
|
||||
if (lock->init_needed)
|
||||
call_once (&lock->init_once, lock->init_func);
|
||||
if (mtx_lock (&lock->lock) != thrd_success)
|
||||
return EAGAIN;
|
||||
/* Test whether no readers or writers are currently running. */
|
||||
while (!(lock->runcount == 0))
|
||||
{
|
||||
/* This thread has to wait for a while. Enqueue it among the
|
||||
waiting_writers. */
|
||||
lock->waiting_writers_count++;
|
||||
if (cnd_wait (&lock->waiting_writers, &lock->lock) != thrd_success)
|
||||
{
|
||||
lock->waiting_writers_count--;
|
||||
mtx_unlock (&lock->lock);
|
||||
return EINVAL;
|
||||
}
|
||||
lock->waiting_writers_count--;
|
||||
}
|
||||
lock->runcount--; /* runcount becomes -1 */
|
||||
if (mtx_unlock (&lock->lock) != thrd_success)
|
||||
return EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_unlock (gl_rwlock_t *lock)
|
||||
{
|
||||
if (lock->init_needed)
|
||||
call_once (&lock->init_once, lock->init_func);
|
||||
if (mtx_lock (&lock->lock) != thrd_success)
|
||||
return EAGAIN;
|
||||
if (lock->runcount < 0)
|
||||
{
|
||||
/* Drop a writer lock. */
|
||||
if (!(lock->runcount == -1))
|
||||
{
|
||||
mtx_unlock (&lock->lock);
|
||||
return EINVAL;
|
||||
}
|
||||
lock->runcount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Drop a reader lock. */
|
||||
if (!(lock->runcount > 0))
|
||||
{
|
||||
mtx_unlock (&lock->lock);
|
||||
return EINVAL;
|
||||
}
|
||||
lock->runcount--;
|
||||
}
|
||||
if (lock->runcount == 0)
|
||||
{
|
||||
/* POSIX recommends that "write locks shall take precedence over read
|
||||
locks", to avoid "writer starvation". */
|
||||
if (lock->waiting_writers_count > 0)
|
||||
{
|
||||
/* Wake up one of the waiting writers. */
|
||||
if (cnd_signal (&lock->waiting_writers) != thrd_success)
|
||||
{
|
||||
mtx_unlock (&lock->lock);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wake up all waiting readers. */
|
||||
if (cnd_broadcast (&lock->waiting_readers) != thrd_success)
|
||||
{
|
||||
mtx_unlock (&lock->lock);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mtx_unlock (&lock->lock) != thrd_success)
|
||||
return EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_destroy (gl_rwlock_t *lock)
|
||||
{
|
||||
if (lock->init_needed)
|
||||
call_once (&lock->init_once, lock->init_func);
|
||||
mtx_destroy (&lock->lock);
|
||||
cnd_destroy (&lock->waiting_readers);
|
||||
cnd_destroy (&lock->waiting_writers);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
|
||||
|
||||
int
|
||||
glthread_recursive_lock_init (gl_recursive_lock_t *lock)
|
||||
{
|
||||
if (mtx_init (&lock->mutex, mtx_plain | mtx_recursive) != thrd_success)
|
||||
return ENOMEM;
|
||||
lock->init_needed = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_recursive_lock_lock (gl_recursive_lock_t *lock)
|
||||
{
|
||||
if (lock->init_needed)
|
||||
call_once (&lock->init_once, lock->init_func);
|
||||
if (mtx_lock (&lock->mutex) != thrd_success)
|
||||
return EAGAIN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_recursive_lock_unlock (gl_recursive_lock_t *lock)
|
||||
{
|
||||
if (lock->init_needed)
|
||||
call_once (&lock->init_once, lock->init_func);
|
||||
if (mtx_unlock (&lock->mutex) != thrd_success)
|
||||
return EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_recursive_lock_destroy (gl_recursive_lock_t *lock)
|
||||
{
|
||||
if (lock->init_needed)
|
||||
call_once (&lock->init_once, lock->init_func);
|
||||
mtx_destroy (&lock->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -------------------------- gl_once_t datatype -------------------------- */
|
||||
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
#if USE_POSIX_THREADS
|
||||
|
||||
/* -------------------------- gl_lock_t datatype -------------------------- */
|
||||
|
||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
|
||||
|
||||
# if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
|
||||
|
||||
# if defined PTHREAD_RWLOCK_INITIALIZER || defined PTHREAD_RWLOCK_INITIALIZER_NP
|
||||
|
||||
# if !HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
|
||||
/* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
|
||||
|
||||
int
|
||||
glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock)
|
||||
{
|
||||
pthread_rwlockattr_t attributes;
|
||||
int err;
|
||||
|
||||
err = pthread_rwlockattr_init (&attributes);
|
||||
if (err != 0)
|
||||
return err;
|
||||
/* Note: PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP is the only value that
|
||||
causes the writer to be preferred. PTHREAD_RWLOCK_PREFER_WRITER_NP does not
|
||||
do this; see
|
||||
http://man7.org/linux/man-pages/man3/pthread_rwlockattr_setkind_np.3.html */
|
||||
err = pthread_rwlockattr_setkind_np (&attributes,
|
||||
PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);
|
||||
if (err == 0)
|
||||
err = pthread_rwlock_init(lock, &attributes);
|
||||
/* pthread_rwlockattr_destroy always returns 0. It cannot influence the
|
||||
return value. */
|
||||
pthread_rwlockattr_destroy (&attributes);
|
||||
return err;
|
||||
}
|
||||
|
||||
# endif
|
||||
# else
|
||||
|
||||
int
|
||||
glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_rwlock_init (&lock->rwlock, NULL);
|
||||
if (err != 0)
|
||||
return err;
|
||||
lock->initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
|
||||
{
|
||||
if (!lock->initialized)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_lock (&lock->guard);
|
||||
if (err != 0)
|
||||
return err;
|
||||
if (!lock->initialized)
|
||||
{
|
||||
err = glthread_rwlock_init_multithreaded (lock);
|
||||
if (err != 0)
|
||||
{
|
||||
pthread_mutex_unlock (&lock->guard);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
err = pthread_mutex_unlock (&lock->guard);
|
||||
if (err != 0)
|
||||
return err;
|
||||
}
|
||||
return pthread_rwlock_rdlock (&lock->rwlock);
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
|
||||
{
|
||||
if (!lock->initialized)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_lock (&lock->guard);
|
||||
if (err != 0)
|
||||
return err;
|
||||
if (!lock->initialized)
|
||||
{
|
||||
err = glthread_rwlock_init_multithreaded (lock);
|
||||
if (err != 0)
|
||||
{
|
||||
pthread_mutex_unlock (&lock->guard);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
err = pthread_mutex_unlock (&lock->guard);
|
||||
if (err != 0)
|
||||
return err;
|
||||
}
|
||||
return pthread_rwlock_wrlock (&lock->rwlock);
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
|
||||
{
|
||||
if (!lock->initialized)
|
||||
return EINVAL;
|
||||
return pthread_rwlock_unlock (&lock->rwlock);
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!lock->initialized)
|
||||
return EINVAL;
|
||||
err = pthread_rwlock_destroy (&lock->rwlock);
|
||||
if (err != 0)
|
||||
return err;
|
||||
lock->initialized = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
# else
|
||||
|
||||
int
|
||||
glthread_rwlock_init_multithreaded (gl_rwlock_t *lock)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_init (&lock->lock, NULL);
|
||||
if (err != 0)
|
||||
return err;
|
||||
err = pthread_cond_init (&lock->waiting_readers, NULL);
|
||||
if (err != 0)
|
||||
return err;
|
||||
err = pthread_cond_init (&lock->waiting_writers, NULL);
|
||||
if (err != 0)
|
||||
return err;
|
||||
lock->waiting_writers_count = 0;
|
||||
lock->runcount = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_lock (&lock->lock);
|
||||
if (err != 0)
|
||||
return err;
|
||||
/* Test whether only readers are currently running, and whether the runcount
|
||||
field will not overflow, and whether no writer is waiting. The latter
|
||||
condition is because POSIX recommends that "write locks shall take
|
||||
precedence over read locks", to avoid "writer starvation". */
|
||||
while (!(lock->runcount + 1 > 0 && lock->waiting_writers_count == 0))
|
||||
{
|
||||
/* This thread has to wait for a while. Enqueue it among the
|
||||
waiting_readers. */
|
||||
err = pthread_cond_wait (&lock->waiting_readers, &lock->lock);
|
||||
if (err != 0)
|
||||
{
|
||||
pthread_mutex_unlock (&lock->lock);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
lock->runcount++;
|
||||
return pthread_mutex_unlock (&lock->lock);
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_lock (&lock->lock);
|
||||
if (err != 0)
|
||||
return err;
|
||||
/* Test whether no readers or writers are currently running. */
|
||||
while (!(lock->runcount == 0))
|
||||
{
|
||||
/* This thread has to wait for a while. Enqueue it among the
|
||||
waiting_writers. */
|
||||
lock->waiting_writers_count++;
|
||||
err = pthread_cond_wait (&lock->waiting_writers, &lock->lock);
|
||||
if (err != 0)
|
||||
{
|
||||
lock->waiting_writers_count--;
|
||||
pthread_mutex_unlock (&lock->lock);
|
||||
return err;
|
||||
}
|
||||
lock->waiting_writers_count--;
|
||||
}
|
||||
lock->runcount--; /* runcount becomes -1 */
|
||||
return pthread_mutex_unlock (&lock->lock);
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_lock (&lock->lock);
|
||||
if (err != 0)
|
||||
return err;
|
||||
if (lock->runcount < 0)
|
||||
{
|
||||
/* Drop a writer lock. */
|
||||
if (!(lock->runcount == -1))
|
||||
{
|
||||
pthread_mutex_unlock (&lock->lock);
|
||||
return EINVAL;
|
||||
}
|
||||
lock->runcount = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Drop a reader lock. */
|
||||
if (!(lock->runcount > 0))
|
||||
{
|
||||
pthread_mutex_unlock (&lock->lock);
|
||||
return EINVAL;
|
||||
}
|
||||
lock->runcount--;
|
||||
}
|
||||
if (lock->runcount == 0)
|
||||
{
|
||||
/* POSIX recommends that "write locks shall take precedence over read
|
||||
locks", to avoid "writer starvation". */
|
||||
if (lock->waiting_writers_count > 0)
|
||||
{
|
||||
/* Wake up one of the waiting writers. */
|
||||
err = pthread_cond_signal (&lock->waiting_writers);
|
||||
if (err != 0)
|
||||
{
|
||||
pthread_mutex_unlock (&lock->lock);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wake up all waiting readers. */
|
||||
err = pthread_cond_broadcast (&lock->waiting_readers);
|
||||
if (err != 0)
|
||||
{
|
||||
pthread_mutex_unlock (&lock->lock);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pthread_mutex_unlock (&lock->lock);
|
||||
}
|
||||
|
||||
int
|
||||
glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_destroy (&lock->lock);
|
||||
if (err != 0)
|
||||
return err;
|
||||
err = pthread_cond_destroy (&lock->waiting_readers);
|
||||
if (err != 0)
|
||||
return err;
|
||||
err = pthread_cond_destroy (&lock->waiting_writers);
|
||||
if (err != 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
|
||||
|
||||
# if HAVE_PTHREAD_MUTEX_RECURSIVE
|
||||
|
||||
# if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
|
||||
|
||||
int
|
||||
glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
|
||||
{
|
||||
pthread_mutexattr_t attributes;
|
||||
int err;
|
||||
|
||||
err = pthread_mutexattr_init (&attributes);
|
||||
if (err != 0)
|
||||
return err;
|
||||
err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
|
||||
if (err != 0)
|
||||
{
|
||||
pthread_mutexattr_destroy (&attributes);
|
||||
return err;
|
||||
}
|
||||
err = pthread_mutex_init (lock, &attributes);
|
||||
if (err != 0)
|
||||
{
|
||||
pthread_mutexattr_destroy (&attributes);
|
||||
return err;
|
||||
}
|
||||
err = pthread_mutexattr_destroy (&attributes);
|
||||
if (err != 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
int
|
||||
glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
|
||||
{
|
||||
pthread_mutexattr_t attributes;
|
||||
int err;
|
||||
|
||||
err = pthread_mutexattr_init (&attributes);
|
||||
if (err != 0)
|
||||
return err;
|
||||
err = pthread_mutexattr_settype (&attributes, PTHREAD_MUTEX_RECURSIVE);
|
||||
if (err != 0)
|
||||
{
|
||||
pthread_mutexattr_destroy (&attributes);
|
||||
return err;
|
||||
}
|
||||
err = pthread_mutex_init (&lock->recmutex, &attributes);
|
||||
if (err != 0)
|
||||
{
|
||||
pthread_mutexattr_destroy (&attributes);
|
||||
return err;
|
||||
}
|
||||
err = pthread_mutexattr_destroy (&attributes);
|
||||
if (err != 0)
|
||||
return err;
|
||||
lock->initialized = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
|
||||
{
|
||||
if (!lock->initialized)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_lock (&lock->guard);
|
||||
if (err != 0)
|
||||
return err;
|
||||
if (!lock->initialized)
|
||||
{
|
||||
err = glthread_recursive_lock_init_multithreaded (lock);
|
||||
if (err != 0)
|
||||
{
|
||||
pthread_mutex_unlock (&lock->guard);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
err = pthread_mutex_unlock (&lock->guard);
|
||||
if (err != 0)
|
||||
return err;
|
||||
}
|
||||
return pthread_mutex_lock (&lock->recmutex);
|
||||
}
|
||||
|
||||
int
|
||||
glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
|
||||
{
|
||||
if (!lock->initialized)
|
||||
return EINVAL;
|
||||
return pthread_mutex_unlock (&lock->recmutex);
|
||||
}
|
||||
|
||||
int
|
||||
glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!lock->initialized)
|
||||
return EINVAL;
|
||||
err = pthread_mutex_destroy (&lock->recmutex);
|
||||
if (err != 0)
|
||||
return err;
|
||||
lock->initialized = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
# else
|
||||
|
||||
int
|
||||
glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_init (&lock->mutex, NULL);
|
||||
if (err != 0)
|
||||
return err;
|
||||
lock->owner = (pthread_t) 0;
|
||||
lock->depth = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock)
|
||||
{
|
||||
pthread_t self = pthread_self ();
|
||||
if (lock->owner != self)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_lock (&lock->mutex);
|
||||
if (err != 0)
|
||||
return err;
|
||||
lock->owner = self;
|
||||
}
|
||||
if (++(lock->depth) == 0) /* wraparound? */
|
||||
{
|
||||
lock->depth--;
|
||||
return EAGAIN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock)
|
||||
{
|
||||
if (lock->owner != pthread_self ())
|
||||
return EPERM;
|
||||
if (lock->depth == 0)
|
||||
return EINVAL;
|
||||
if (--(lock->depth) == 0)
|
||||
{
|
||||
lock->owner = (pthread_t) 0;
|
||||
return pthread_mutex_unlock (&lock->mutex);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock)
|
||||
{
|
||||
if (lock->owner != (pthread_t) 0)
|
||||
return EBUSY;
|
||||
return pthread_mutex_destroy (&lock->mutex);
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
/* -------------------------- gl_once_t datatype -------------------------- */
|
||||
|
||||
static const pthread_once_t fresh_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
int
|
||||
glthread_once_singlethreaded (pthread_once_t *once_control)
|
||||
{
|
||||
/* We don't know whether pthread_once_t is an integer type, a floating-point
|
||||
type, a pointer type, or a structure type. */
|
||||
char *firstbyte = (char *)once_control;
|
||||
if (*firstbyte == *(const char *)&fresh_once)
|
||||
{
|
||||
/* First time use of once_control. Invert the first byte. */
|
||||
*firstbyte = ~ *(const char *)&fresh_once;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
# if !(PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK)
|
||||
|
||||
int
|
||||
glthread_once_multithreaded (pthread_once_t *once_control,
|
||||
void (*init_function) (void))
|
||||
{
|
||||
int err = pthread_once (once_control, init_function);
|
||||
if (err == ENOSYS)
|
||||
{
|
||||
/* This happens on FreeBSD 11: The pthread_once function in libc returns
|
||||
ENOSYS. */
|
||||
if (glthread_once_singlethreaded (once_control))
|
||||
init_function ();
|
||||
return 0;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
#if USE_WINDOWS_THREADS
|
||||
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
+791
@@ -0,0 +1,791 @@
|
||||
/* Locking in multithreaded situations.
|
||||
Copyright (C) 2005-2008, 2017-2022 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Bruno Haible <bruno@clisp.org>, 2005.
|
||||
Based on GCC's gthr-posix.h, gthr-posix95.h, gthr-win32.h. */
|
||||
|
||||
/* This file contains locking primitives for use with a given thread library.
|
||||
It does not contain primitives for creating threads or for other
|
||||
synchronization primitives.
|
||||
|
||||
Normal (non-recursive) locks:
|
||||
Type: gl_lock_t
|
||||
Declaration: gl_lock_define(extern, name)
|
||||
Initializer: gl_lock_define_initialized(, name)
|
||||
Initialization: gl_lock_init (name);
|
||||
Taking the lock: gl_lock_lock (name);
|
||||
Releasing the lock: gl_lock_unlock (name);
|
||||
De-initialization: gl_lock_destroy (name);
|
||||
Equivalent functions with control of error handling:
|
||||
Initialization: err = glthread_lock_init (&name);
|
||||
Taking the lock: err = glthread_lock_lock (&name);
|
||||
Releasing the lock: err = glthread_lock_unlock (&name);
|
||||
De-initialization: err = glthread_lock_destroy (&name);
|
||||
|
||||
Read-Write (non-recursive) locks:
|
||||
Type: gl_rwlock_t
|
||||
Declaration: gl_rwlock_define(extern, name)
|
||||
Initializer: gl_rwlock_define_initialized(, name)
|
||||
Initialization: gl_rwlock_init (name);
|
||||
Taking the lock: gl_rwlock_rdlock (name);
|
||||
gl_rwlock_wrlock (name);
|
||||
Releasing the lock: gl_rwlock_unlock (name);
|
||||
De-initialization: gl_rwlock_destroy (name);
|
||||
Equivalent functions with control of error handling:
|
||||
Initialization: err = glthread_rwlock_init (&name);
|
||||
Taking the lock: err = glthread_rwlock_rdlock (&name);
|
||||
err = glthread_rwlock_wrlock (&name);
|
||||
Releasing the lock: err = glthread_rwlock_unlock (&name);
|
||||
De-initialization: err = glthread_rwlock_destroy (&name);
|
||||
|
||||
Recursive locks:
|
||||
Type: gl_recursive_lock_t
|
||||
Declaration: gl_recursive_lock_define(extern, name)
|
||||
Initializer: gl_recursive_lock_define_initialized(, name)
|
||||
Initialization: gl_recursive_lock_init (name);
|
||||
Taking the lock: gl_recursive_lock_lock (name);
|
||||
Releasing the lock: gl_recursive_lock_unlock (name);
|
||||
De-initialization: gl_recursive_lock_destroy (name);
|
||||
Equivalent functions with control of error handling:
|
||||
Initialization: err = glthread_recursive_lock_init (&name);
|
||||
Taking the lock: err = glthread_recursive_lock_lock (&name);
|
||||
Releasing the lock: err = glthread_recursive_lock_unlock (&name);
|
||||
De-initialization: err = glthread_recursive_lock_destroy (&name);
|
||||
|
||||
Once-only execution:
|
||||
Type: gl_once_t
|
||||
Initializer: gl_once_define(extern, name)
|
||||
Execution: gl_once (name, initfunction);
|
||||
Equivalent functions with control of error handling:
|
||||
Execution: err = glthread_once (&name, initfunction);
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _LOCK_H
|
||||
#define _LOCK_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if !defined c11_threads_in_use
|
||||
# if HAVE_THREADS_H && USE_POSIX_THREADS_FROM_LIBC
|
||||
# define c11_threads_in_use() 1
|
||||
# elif HAVE_THREADS_H && USE_POSIX_THREADS_WEAK
|
||||
# include <threads.h>
|
||||
# pragma weak thrd_exit
|
||||
# define c11_threads_in_use() (thrd_exit != NULL)
|
||||
# else
|
||||
# define c11_threads_in_use() 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
#if USE_ISOC_THREADS || USE_ISOC_AND_POSIX_THREADS
|
||||
|
||||
/* Use the ISO C threads library. */
|
||||
|
||||
# include <threads.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
/* -------------------------- gl_lock_t datatype -------------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int volatile init_needed;
|
||||
once_flag init_once;
|
||||
void (*init_func) (void);
|
||||
mtx_t mutex;
|
||||
}
|
||||
gl_lock_t;
|
||||
# define gl_lock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_lock_t NAME;
|
||||
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
|
||||
static void _atomic_init_##NAME (void); \
|
||||
STORAGECLASS gl_lock_t NAME = \
|
||||
{ 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \
|
||||
static void _atomic_init_##NAME (void) \
|
||||
{ \
|
||||
if (glthread_lock_init (&(NAME))) \
|
||||
abort (); \
|
||||
}
|
||||
extern int glthread_lock_init (gl_lock_t *lock);
|
||||
extern int glthread_lock_lock (gl_lock_t *lock);
|
||||
extern int glthread_lock_unlock (gl_lock_t *lock);
|
||||
extern int glthread_lock_destroy (gl_lock_t *lock);
|
||||
|
||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int volatile init_needed;
|
||||
once_flag init_once;
|
||||
void (*init_func) (void);
|
||||
mtx_t lock; /* protects the remaining fields */
|
||||
cnd_t waiting_readers; /* waiting readers */
|
||||
cnd_t waiting_writers; /* waiting writers */
|
||||
unsigned int waiting_writers_count; /* number of waiting writers */
|
||||
int runcount; /* number of readers running, or -1 when a writer runs */
|
||||
}
|
||||
gl_rwlock_t;
|
||||
# define gl_rwlock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_rwlock_t NAME;
|
||||
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
|
||||
static void _atomic_init_##NAME (void); \
|
||||
STORAGECLASS gl_rwlock_t NAME = \
|
||||
{ 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \
|
||||
static void _atomic_init_##NAME (void) \
|
||||
{ \
|
||||
if (glthread_rwlock_init (&(NAME))) \
|
||||
abort (); \
|
||||
}
|
||||
extern int glthread_rwlock_init (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_rdlock (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_wrlock (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_unlock (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_destroy (gl_rwlock_t *lock);
|
||||
|
||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int volatile init_needed;
|
||||
once_flag init_once;
|
||||
void (*init_func) (void);
|
||||
mtx_t mutex;
|
||||
}
|
||||
gl_recursive_lock_t;
|
||||
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_recursive_lock_t NAME;
|
||||
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
|
||||
static void _atomic_init_##NAME (void); \
|
||||
STORAGECLASS gl_recursive_lock_t NAME = \
|
||||
{ 1, ONCE_FLAG_INIT, _atomic_init_##NAME }; \
|
||||
static void _atomic_init_##NAME (void) \
|
||||
{ \
|
||||
if (glthread_recursive_lock_init (&(NAME))) \
|
||||
abort (); \
|
||||
}
|
||||
extern int glthread_recursive_lock_init (gl_recursive_lock_t *lock);
|
||||
extern int glthread_recursive_lock_lock (gl_recursive_lock_t *lock);
|
||||
extern int glthread_recursive_lock_unlock (gl_recursive_lock_t *lock);
|
||||
extern int glthread_recursive_lock_destroy (gl_recursive_lock_t *lock);
|
||||
|
||||
/* -------------------------- gl_once_t datatype -------------------------- */
|
||||
|
||||
typedef once_flag gl_once_t;
|
||||
# define gl_once_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS once_flag NAME = ONCE_FLAG_INIT;
|
||||
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
|
||||
(call_once (ONCE_CONTROL, INITFUNCTION), 0)
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
#if USE_POSIX_THREADS
|
||||
|
||||
/* Use the POSIX threads library. */
|
||||
|
||||
# include <pthread.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
# if PTHREAD_IN_USE_DETECTION_HARD
|
||||
|
||||
/* The pthread_in_use() detection needs to be done at runtime. */
|
||||
# define pthread_in_use() \
|
||||
glthread_in_use ()
|
||||
extern int glthread_in_use (void);
|
||||
|
||||
# endif
|
||||
|
||||
# if USE_POSIX_THREADS_WEAK
|
||||
|
||||
/* Use weak references to the POSIX threads library. */
|
||||
|
||||
/* Weak references avoid dragging in external libraries if the other parts
|
||||
of the program don't use them. Here we use them, because we don't want
|
||||
every program that uses libintl to depend on libpthread. This assumes
|
||||
that libpthread would not be loaded after libintl; i.e. if libintl is
|
||||
loaded first, by an executable that does not depend on libpthread, and
|
||||
then a module is dynamically loaded that depends on libpthread, libintl
|
||||
will not be multithread-safe. */
|
||||
|
||||
/* The way to test at runtime whether libpthread is present is to test
|
||||
whether a function pointer's value, such as &pthread_mutex_init, is
|
||||
non-NULL. However, some versions of GCC have a bug through which, in
|
||||
PIC mode, &foo != NULL always evaluates to true if there is a direct
|
||||
call to foo(...) in the same function. To avoid this, we test the
|
||||
address of a function in libpthread that we don't use. */
|
||||
|
||||
# pragma weak pthread_mutex_init
|
||||
# pragma weak pthread_mutex_lock
|
||||
# pragma weak pthread_mutex_unlock
|
||||
# pragma weak pthread_mutex_destroy
|
||||
# pragma weak pthread_rwlock_init
|
||||
# pragma weak pthread_rwlock_rdlock
|
||||
# pragma weak pthread_rwlock_wrlock
|
||||
# pragma weak pthread_rwlock_unlock
|
||||
# pragma weak pthread_rwlock_destroy
|
||||
# pragma weak pthread_once
|
||||
# pragma weak pthread_cond_init
|
||||
# pragma weak pthread_cond_wait
|
||||
# pragma weak pthread_cond_signal
|
||||
# pragma weak pthread_cond_broadcast
|
||||
# pragma weak pthread_cond_destroy
|
||||
# pragma weak pthread_mutexattr_init
|
||||
# pragma weak pthread_mutexattr_settype
|
||||
# pragma weak pthread_mutexattr_destroy
|
||||
# pragma weak pthread_rwlockattr_init
|
||||
# if __GNU_LIBRARY__ > 1
|
||||
# pragma weak pthread_rwlockattr_setkind_np
|
||||
# endif
|
||||
# pragma weak pthread_rwlockattr_destroy
|
||||
# ifndef pthread_self
|
||||
# pragma weak pthread_self
|
||||
# endif
|
||||
|
||||
# if !PTHREAD_IN_USE_DETECTION_HARD
|
||||
/* Considering all platforms with USE_POSIX_THREADS_WEAK, only few symbols
|
||||
can be used to determine whether libpthread is in use. These are:
|
||||
pthread_mutexattr_gettype
|
||||
pthread_rwlockattr_destroy
|
||||
pthread_rwlockattr_init
|
||||
*/
|
||||
# pragma weak pthread_mutexattr_gettype
|
||||
# define pthread_in_use() \
|
||||
(pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
|
||||
# endif
|
||||
|
||||
# else
|
||||
|
||||
# if !PTHREAD_IN_USE_DETECTION_HARD
|
||||
# define pthread_in_use() 1
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
/* -------------------------- gl_lock_t datatype -------------------------- */
|
||||
|
||||
typedef pthread_mutex_t gl_lock_t;
|
||||
# define gl_lock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS pthread_mutex_t NAME;
|
||||
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
|
||||
STORAGECLASS pthread_mutex_t NAME = gl_lock_initializer;
|
||||
# define gl_lock_initializer \
|
||||
PTHREAD_MUTEX_INITIALIZER
|
||||
# define glthread_lock_init(LOCK) \
|
||||
(pthread_in_use () ? pthread_mutex_init (LOCK, NULL) : 0)
|
||||
# define glthread_lock_lock(LOCK) \
|
||||
(pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
|
||||
# define glthread_lock_unlock(LOCK) \
|
||||
(pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
|
||||
# define glthread_lock_destroy(LOCK) \
|
||||
(pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
|
||||
|
||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
|
||||
|
||||
# if HAVE_PTHREAD_RWLOCK && (HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER || (defined PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP && (__GNU_LIBRARY__ > 1)))
|
||||
|
||||
# if defined PTHREAD_RWLOCK_INITIALIZER || defined PTHREAD_RWLOCK_INITIALIZER_NP
|
||||
|
||||
typedef pthread_rwlock_t gl_rwlock_t;
|
||||
# define gl_rwlock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS pthread_rwlock_t NAME;
|
||||
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
|
||||
STORAGECLASS pthread_rwlock_t NAME = gl_rwlock_initializer;
|
||||
# if HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER
|
||||
# if defined PTHREAD_RWLOCK_INITIALIZER
|
||||
# define gl_rwlock_initializer \
|
||||
PTHREAD_RWLOCK_INITIALIZER
|
||||
# else
|
||||
# define gl_rwlock_initializer \
|
||||
PTHREAD_RWLOCK_INITIALIZER_NP
|
||||
# endif
|
||||
# define glthread_rwlock_init(LOCK) \
|
||||
(pthread_in_use () ? pthread_rwlock_init (LOCK, NULL) : 0)
|
||||
# else /* glibc with bug https://sourceware.org/bugzilla/show_bug.cgi?id=13701 */
|
||||
# define gl_rwlock_initializer \
|
||||
PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
|
||||
# define glthread_rwlock_init(LOCK) \
|
||||
(pthread_in_use () ? glthread_rwlock_init_for_glibc (LOCK) : 0)
|
||||
extern int glthread_rwlock_init_for_glibc (pthread_rwlock_t *lock);
|
||||
# endif
|
||||
# define glthread_rwlock_rdlock(LOCK) \
|
||||
(pthread_in_use () ? pthread_rwlock_rdlock (LOCK) : 0)
|
||||
# define glthread_rwlock_wrlock(LOCK) \
|
||||
(pthread_in_use () ? pthread_rwlock_wrlock (LOCK) : 0)
|
||||
# define glthread_rwlock_unlock(LOCK) \
|
||||
(pthread_in_use () ? pthread_rwlock_unlock (LOCK) : 0)
|
||||
# define glthread_rwlock_destroy(LOCK) \
|
||||
(pthread_in_use () ? pthread_rwlock_destroy (LOCK) : 0)
|
||||
|
||||
# else
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int initialized;
|
||||
pthread_mutex_t guard; /* protects the initialization */
|
||||
pthread_rwlock_t rwlock; /* read-write lock */
|
||||
}
|
||||
gl_rwlock_t;
|
||||
# define gl_rwlock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_rwlock_t NAME;
|
||||
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
|
||||
# define gl_rwlock_initializer \
|
||||
{ 0, PTHREAD_MUTEX_INITIALIZER }
|
||||
# define glthread_rwlock_init(LOCK) \
|
||||
(pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
|
||||
# define glthread_rwlock_rdlock(LOCK) \
|
||||
(pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
|
||||
# define glthread_rwlock_wrlock(LOCK) \
|
||||
(pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
|
||||
# define glthread_rwlock_unlock(LOCK) \
|
||||
(pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
|
||||
# define glthread_rwlock_destroy(LOCK) \
|
||||
(pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
|
||||
extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
|
||||
|
||||
# endif
|
||||
|
||||
# else
|
||||
|
||||
typedef struct
|
||||
{
|
||||
pthread_mutex_t lock; /* protects the remaining fields */
|
||||
pthread_cond_t waiting_readers; /* waiting readers */
|
||||
pthread_cond_t waiting_writers; /* waiting writers */
|
||||
unsigned int waiting_writers_count; /* number of waiting writers */
|
||||
int runcount; /* number of readers running, or -1 when a writer runs */
|
||||
}
|
||||
gl_rwlock_t;
|
||||
# define gl_rwlock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_rwlock_t NAME;
|
||||
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
|
||||
# define gl_rwlock_initializer \
|
||||
{ PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER, 0, 0 }
|
||||
# define glthread_rwlock_init(LOCK) \
|
||||
(pthread_in_use () ? glthread_rwlock_init_multithreaded (LOCK) : 0)
|
||||
# define glthread_rwlock_rdlock(LOCK) \
|
||||
(pthread_in_use () ? glthread_rwlock_rdlock_multithreaded (LOCK) : 0)
|
||||
# define glthread_rwlock_wrlock(LOCK) \
|
||||
(pthread_in_use () ? glthread_rwlock_wrlock_multithreaded (LOCK) : 0)
|
||||
# define glthread_rwlock_unlock(LOCK) \
|
||||
(pthread_in_use () ? glthread_rwlock_unlock_multithreaded (LOCK) : 0)
|
||||
# define glthread_rwlock_destroy(LOCK) \
|
||||
(pthread_in_use () ? glthread_rwlock_destroy_multithreaded (LOCK) : 0)
|
||||
extern int glthread_rwlock_init_multithreaded (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_rdlock_multithreaded (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_wrlock_multithreaded (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_unlock_multithreaded (gl_rwlock_t *lock);
|
||||
extern int glthread_rwlock_destroy_multithreaded (gl_rwlock_t *lock);
|
||||
|
||||
# endif
|
||||
|
||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
|
||||
|
||||
# if HAVE_PTHREAD_MUTEX_RECURSIVE
|
||||
|
||||
# if defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER || defined PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
|
||||
|
||||
typedef pthread_mutex_t gl_recursive_lock_t;
|
||||
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS pthread_mutex_t NAME;
|
||||
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
|
||||
STORAGECLASS pthread_mutex_t NAME = gl_recursive_lock_initializer;
|
||||
# ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER
|
||||
# define gl_recursive_lock_initializer \
|
||||
PTHREAD_RECURSIVE_MUTEX_INITIALIZER
|
||||
# else
|
||||
# define gl_recursive_lock_initializer \
|
||||
PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
|
||||
# endif
|
||||
# define glthread_recursive_lock_init(LOCK) \
|
||||
(pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
|
||||
# define glthread_recursive_lock_lock(LOCK) \
|
||||
(pthread_in_use () ? pthread_mutex_lock (LOCK) : 0)
|
||||
# define glthread_recursive_lock_unlock(LOCK) \
|
||||
(pthread_in_use () ? pthread_mutex_unlock (LOCK) : 0)
|
||||
# define glthread_recursive_lock_destroy(LOCK) \
|
||||
(pthread_in_use () ? pthread_mutex_destroy (LOCK) : 0)
|
||||
extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
|
||||
|
||||
# else
|
||||
|
||||
typedef struct
|
||||
{
|
||||
pthread_mutex_t recmutex; /* recursive mutex */
|
||||
pthread_mutex_t guard; /* protects the initialization */
|
||||
int initialized;
|
||||
}
|
||||
gl_recursive_lock_t;
|
||||
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_recursive_lock_t NAME;
|
||||
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
|
||||
# define gl_recursive_lock_initializer \
|
||||
{ PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, 0 }
|
||||
# define glthread_recursive_lock_init(LOCK) \
|
||||
(pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
|
||||
# define glthread_recursive_lock_lock(LOCK) \
|
||||
(pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
|
||||
# define glthread_recursive_lock_unlock(LOCK) \
|
||||
(pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
|
||||
# define glthread_recursive_lock_destroy(LOCK) \
|
||||
(pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
|
||||
extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
|
||||
extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
|
||||
extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
|
||||
extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
|
||||
|
||||
# endif
|
||||
|
||||
# else
|
||||
|
||||
/* Old versions of POSIX threads on Solaris did not have recursive locks.
|
||||
We have to implement them ourselves. */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
pthread_t owner;
|
||||
unsigned long depth;
|
||||
}
|
||||
gl_recursive_lock_t;
|
||||
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_recursive_lock_t NAME;
|
||||
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
|
||||
# define gl_recursive_lock_initializer \
|
||||
{ PTHREAD_MUTEX_INITIALIZER, (pthread_t) 0, 0 }
|
||||
# define glthread_recursive_lock_init(LOCK) \
|
||||
(pthread_in_use () ? glthread_recursive_lock_init_multithreaded (LOCK) : 0)
|
||||
# define glthread_recursive_lock_lock(LOCK) \
|
||||
(pthread_in_use () ? glthread_recursive_lock_lock_multithreaded (LOCK) : 0)
|
||||
# define glthread_recursive_lock_unlock(LOCK) \
|
||||
(pthread_in_use () ? glthread_recursive_lock_unlock_multithreaded (LOCK) : 0)
|
||||
# define glthread_recursive_lock_destroy(LOCK) \
|
||||
(pthread_in_use () ? glthread_recursive_lock_destroy_multithreaded (LOCK) : 0)
|
||||
extern int glthread_recursive_lock_init_multithreaded (gl_recursive_lock_t *lock);
|
||||
extern int glthread_recursive_lock_lock_multithreaded (gl_recursive_lock_t *lock);
|
||||
extern int glthread_recursive_lock_unlock_multithreaded (gl_recursive_lock_t *lock);
|
||||
extern int glthread_recursive_lock_destroy_multithreaded (gl_recursive_lock_t *lock);
|
||||
|
||||
# endif
|
||||
|
||||
/* -------------------------- gl_once_t datatype -------------------------- */
|
||||
|
||||
typedef pthread_once_t gl_once_t;
|
||||
# define gl_once_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS pthread_once_t NAME = PTHREAD_ONCE_INIT;
|
||||
# if PTHREAD_IN_USE_DETECTION_HARD || USE_POSIX_THREADS_WEAK
|
||||
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
|
||||
(pthread_in_use () \
|
||||
? pthread_once (ONCE_CONTROL, INITFUNCTION) \
|
||||
: (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
|
||||
# else
|
||||
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
|
||||
(pthread_in_use () \
|
||||
? glthread_once_multithreaded (ONCE_CONTROL, INITFUNCTION) \
|
||||
: (glthread_once_singlethreaded (ONCE_CONTROL) ? (INITFUNCTION (), 0) : 0))
|
||||
extern int glthread_once_multithreaded (pthread_once_t *once_control,
|
||||
void (*init_function) (void));
|
||||
# endif
|
||||
extern int glthread_once_singlethreaded (pthread_once_t *once_control);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
#if USE_WINDOWS_THREADS
|
||||
|
||||
# define WIN32_LEAN_AND_MEAN /* avoid including junk */
|
||||
# include <windows.h>
|
||||
|
||||
# include "windows-mutex.h"
|
||||
# include "windows-rwlock.h"
|
||||
# include "windows-recmutex.h"
|
||||
# include "windows-once.h"
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
|
||||
/* We can use CRITICAL_SECTION directly, rather than the native Windows Event,
|
||||
Mutex, Semaphore types, because
|
||||
- we need only to synchronize inside a single process (address space),
|
||||
not inter-process locking,
|
||||
- we don't need to support trylock operations. (TryEnterCriticalSection
|
||||
does not work on Windows 95/98/ME. Packages that need trylock usually
|
||||
define their own mutex type.) */
|
||||
|
||||
/* There is no way to statically initialize a CRITICAL_SECTION. It needs
|
||||
to be done lazily, once only. For this we need spinlocks. */
|
||||
|
||||
/* -------------------------- gl_lock_t datatype -------------------------- */
|
||||
|
||||
typedef glwthread_mutex_t gl_lock_t;
|
||||
# define gl_lock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_lock_t NAME;
|
||||
# define gl_lock_define_initialized(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_lock_t NAME = gl_lock_initializer;
|
||||
# define gl_lock_initializer \
|
||||
GLWTHREAD_MUTEX_INIT
|
||||
# define glthread_lock_init(LOCK) \
|
||||
(glwthread_mutex_init (LOCK), 0)
|
||||
# define glthread_lock_lock(LOCK) \
|
||||
glwthread_mutex_lock (LOCK)
|
||||
# define glthread_lock_unlock(LOCK) \
|
||||
glwthread_mutex_unlock (LOCK)
|
||||
# define glthread_lock_destroy(LOCK) \
|
||||
glwthread_mutex_destroy (LOCK)
|
||||
|
||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
|
||||
|
||||
typedef glwthread_rwlock_t gl_rwlock_t;
|
||||
# define gl_rwlock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_rwlock_t NAME;
|
||||
# define gl_rwlock_define_initialized(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_rwlock_t NAME = gl_rwlock_initializer;
|
||||
# define gl_rwlock_initializer \
|
||||
GLWTHREAD_RWLOCK_INIT
|
||||
# define glthread_rwlock_init(LOCK) \
|
||||
(glwthread_rwlock_init (LOCK), 0)
|
||||
# define glthread_rwlock_rdlock(LOCK) \
|
||||
glwthread_rwlock_rdlock (LOCK)
|
||||
# define glthread_rwlock_wrlock(LOCK) \
|
||||
glwthread_rwlock_wrlock (LOCK)
|
||||
# define glthread_rwlock_unlock(LOCK) \
|
||||
glwthread_rwlock_unlock (LOCK)
|
||||
# define glthread_rwlock_destroy(LOCK) \
|
||||
glwthread_rwlock_destroy (LOCK)
|
||||
|
||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
|
||||
|
||||
typedef glwthread_recmutex_t gl_recursive_lock_t;
|
||||
# define gl_recursive_lock_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_recursive_lock_t NAME;
|
||||
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_recursive_lock_t NAME = gl_recursive_lock_initializer;
|
||||
# define gl_recursive_lock_initializer \
|
||||
GLWTHREAD_RECMUTEX_INIT
|
||||
# define glthread_recursive_lock_init(LOCK) \
|
||||
(glwthread_recmutex_init (LOCK), 0)
|
||||
# define glthread_recursive_lock_lock(LOCK) \
|
||||
glwthread_recmutex_lock (LOCK)
|
||||
# define glthread_recursive_lock_unlock(LOCK) \
|
||||
glwthread_recmutex_unlock (LOCK)
|
||||
# define glthread_recursive_lock_destroy(LOCK) \
|
||||
glwthread_recmutex_destroy (LOCK)
|
||||
|
||||
/* -------------------------- gl_once_t datatype -------------------------- */
|
||||
|
||||
typedef glwthread_once_t gl_once_t;
|
||||
# define gl_once_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_once_t NAME = GLWTHREAD_ONCE_INIT;
|
||||
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
|
||||
(glwthread_once (ONCE_CONTROL, INITFUNCTION), 0)
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
#if !(USE_ISOC_THREADS || USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS || USE_WINDOWS_THREADS)
|
||||
|
||||
/* Provide dummy implementation if threads are not supported. */
|
||||
|
||||
/* -------------------------- gl_lock_t datatype -------------------------- */
|
||||
|
||||
typedef int gl_lock_t;
|
||||
# define gl_lock_define(STORAGECLASS, NAME)
|
||||
# define gl_lock_define_initialized(STORAGECLASS, NAME)
|
||||
# define glthread_lock_init(NAME) 0
|
||||
# define glthread_lock_lock(NAME) 0
|
||||
# define glthread_lock_unlock(NAME) 0
|
||||
# define glthread_lock_destroy(NAME) 0
|
||||
|
||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
|
||||
|
||||
typedef int gl_rwlock_t;
|
||||
# define gl_rwlock_define(STORAGECLASS, NAME)
|
||||
# define gl_rwlock_define_initialized(STORAGECLASS, NAME)
|
||||
# define glthread_rwlock_init(NAME) 0
|
||||
# define glthread_rwlock_rdlock(NAME) 0
|
||||
# define glthread_rwlock_wrlock(NAME) 0
|
||||
# define glthread_rwlock_unlock(NAME) 0
|
||||
# define glthread_rwlock_destroy(NAME) 0
|
||||
|
||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
|
||||
|
||||
typedef int gl_recursive_lock_t;
|
||||
# define gl_recursive_lock_define(STORAGECLASS, NAME)
|
||||
# define gl_recursive_lock_define_initialized(STORAGECLASS, NAME)
|
||||
# define glthread_recursive_lock_init(NAME) 0
|
||||
# define glthread_recursive_lock_lock(NAME) 0
|
||||
# define glthread_recursive_lock_unlock(NAME) 0
|
||||
# define glthread_recursive_lock_destroy(NAME) 0
|
||||
|
||||
/* -------------------------- gl_once_t datatype -------------------------- */
|
||||
|
||||
typedef int gl_once_t;
|
||||
# define gl_once_define(STORAGECLASS, NAME) \
|
||||
STORAGECLASS gl_once_t NAME = 0;
|
||||
# define glthread_once(ONCE_CONTROL, INITFUNCTION) \
|
||||
(*(ONCE_CONTROL) == 0 ? (*(ONCE_CONTROL) = ~ 0, INITFUNCTION (), 0) : 0)
|
||||
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
/* Macros with built-in error handling. */
|
||||
|
||||
/* -------------------------- gl_lock_t datatype -------------------------- */
|
||||
|
||||
#define gl_lock_init(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_lock_init (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
#define gl_lock_lock(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_lock_lock (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
#define gl_lock_unlock(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_lock_unlock (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
#define gl_lock_destroy(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_lock_destroy (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* ------------------------- gl_rwlock_t datatype ------------------------- */
|
||||
|
||||
#define gl_rwlock_init(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_rwlock_init (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
#define gl_rwlock_rdlock(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_rwlock_rdlock (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
#define gl_rwlock_wrlock(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_rwlock_wrlock (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
#define gl_rwlock_unlock(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_rwlock_unlock (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
#define gl_rwlock_destroy(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_rwlock_destroy (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* --------------------- gl_recursive_lock_t datatype --------------------- */
|
||||
|
||||
#define gl_recursive_lock_init(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_recursive_lock_init (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
#define gl_recursive_lock_lock(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_recursive_lock_lock (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
#define gl_recursive_lock_unlock(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_recursive_lock_unlock (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
#define gl_recursive_lock_destroy(NAME) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_recursive_lock_destroy (&NAME)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* -------------------------- gl_once_t datatype -------------------------- */
|
||||
|
||||
#define gl_once(NAME, INITFUNCTION) \
|
||||
do \
|
||||
{ \
|
||||
if (glthread_once (&NAME, INITFUNCTION)) \
|
||||
abort (); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
#endif /* _LOCK_H */
|
||||
@@ -0,0 +1,90 @@
|
||||
/* A Bison parser, made by GNU Bison 3.8.2. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program 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.
|
||||
|
||||
This program 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 this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
|
||||
especially those whose name start with YY_ or yy_. They are
|
||||
private implementation details that can be changed or removed. */
|
||||
|
||||
#ifndef YY__GETTEXT_PLURAL_TAB_H_INCLUDED
|
||||
# define YY__GETTEXT_PLURAL_TAB_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef YYDEBUG
|
||||
# define YYDEBUG 0
|
||||
#endif
|
||||
#if YYDEBUG
|
||||
extern int __gettextdebug;
|
||||
#endif
|
||||
|
||||
/* Token kinds. */
|
||||
#ifndef YYTOKENTYPE
|
||||
# define YYTOKENTYPE
|
||||
enum yytokentype
|
||||
{
|
||||
YYEMPTY = -2,
|
||||
YYEOF = 0, /* "end of file" */
|
||||
YYerror = 256, /* error */
|
||||
YYUNDEF = 257, /* "invalid token" */
|
||||
EQUOP2 = 258, /* EQUOP2 */
|
||||
CMPOP2 = 259, /* CMPOP2 */
|
||||
ADDOP2 = 260, /* ADDOP2 */
|
||||
MULOP2 = 261, /* MULOP2 */
|
||||
NUMBER = 262 /* NUMBER */
|
||||
};
|
||||
typedef enum yytokentype yytoken_kind_t;
|
||||
#endif
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
|
||||
union YYSTYPE
|
||||
{
|
||||
#line 42 "plural.y"
|
||||
|
||||
unsigned long int num;
|
||||
enum expression_operator op;
|
||||
struct expression *exp;
|
||||
|
||||
#line 77 "plural.h"
|
||||
|
||||
};
|
||||
typedef union YYSTYPE YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define YYSTYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
int __gettextparse (struct parse_args *arg);
|
||||
|
||||
|
||||
#endif /* !YY__GETTEXT_PLURAL_TAB_H_INCLUDED */
|
||||
@@ -0,0 +1,186 @@
|
||||
/* Decomposed printf argument list.
|
||||
Copyright (C) 1999, 2002-2003, 2005-2007 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
/* This file can be parametrized with the following macros:
|
||||
ENABLE_UNISTDIO Set to 1 to enable the unistdio extensions.
|
||||
PRINTF_FETCHARGS Name of the function to be defined.
|
||||
STATIC Set to 'static' to declare the function static. */
|
||||
|
||||
#ifndef PRINTF_FETCHARGS
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
/* Specification. */
|
||||
#ifndef PRINTF_FETCHARGS
|
||||
# include "printf-args.h"
|
||||
#endif
|
||||
|
||||
#ifdef STATIC
|
||||
STATIC
|
||||
#endif
|
||||
int
|
||||
PRINTF_FETCHARGS (va_list args, arguments *a)
|
||||
{
|
||||
size_t i;
|
||||
argument *ap;
|
||||
|
||||
for (i = 0, ap = &a->arg[0]; i < a->count; i++, ap++)
|
||||
switch (ap->type)
|
||||
{
|
||||
case TYPE_SCHAR:
|
||||
ap->a.a_schar = va_arg (args, /*signed char*/ int);
|
||||
break;
|
||||
case TYPE_UCHAR:
|
||||
ap->a.a_uchar = va_arg (args, /*unsigned char*/ int);
|
||||
break;
|
||||
case TYPE_SHORT:
|
||||
ap->a.a_short = va_arg (args, /*short*/ int);
|
||||
break;
|
||||
case TYPE_USHORT:
|
||||
ap->a.a_ushort = va_arg (args, /*unsigned short*/ int);
|
||||
break;
|
||||
case TYPE_INT:
|
||||
ap->a.a_int = va_arg (args, int);
|
||||
break;
|
||||
case TYPE_UINT:
|
||||
ap->a.a_uint = va_arg (args, unsigned int);
|
||||
break;
|
||||
case TYPE_LONGINT:
|
||||
ap->a.a_longint = va_arg (args, long int);
|
||||
break;
|
||||
case TYPE_ULONGINT:
|
||||
ap->a.a_ulongint = va_arg (args, unsigned long int);
|
||||
break;
|
||||
#if HAVE_LONG_LONG_INT
|
||||
case TYPE_LONGLONGINT:
|
||||
ap->a.a_longlongint = va_arg (args, long long int);
|
||||
break;
|
||||
case TYPE_ULONGLONGINT:
|
||||
ap->a.a_ulonglongint = va_arg (args, unsigned long long int);
|
||||
break;
|
||||
#endif
|
||||
case TYPE_DOUBLE:
|
||||
ap->a.a_double = va_arg (args, double);
|
||||
break;
|
||||
case TYPE_LONGDOUBLE:
|
||||
ap->a.a_longdouble = va_arg (args, long double);
|
||||
break;
|
||||
case TYPE_CHAR:
|
||||
ap->a.a_char = va_arg (args, int);
|
||||
break;
|
||||
#if HAVE_WINT_T
|
||||
case TYPE_WIDE_CHAR:
|
||||
/* Although ISO C 99 7.24.1.(2) says that wint_t is "unchanged by
|
||||
default argument promotions", this is not the case in mingw32,
|
||||
where wint_t is 'unsigned short'. */
|
||||
ap->a.a_wide_char =
|
||||
(sizeof (wint_t) < sizeof (int)
|
||||
? va_arg (args, int)
|
||||
: va_arg (args, wint_t));
|
||||
break;
|
||||
#endif
|
||||
case TYPE_STRING:
|
||||
ap->a.a_string = va_arg (args, const char *);
|
||||
/* A null pointer is an invalid argument for "%s", but in practice
|
||||
it occurs quite frequently in printf statements that produce
|
||||
debug output. Use a fallback in this case. */
|
||||
if (ap->a.a_string == NULL)
|
||||
ap->a.a_string = "(NULL)";
|
||||
break;
|
||||
#if HAVE_WCHAR_T
|
||||
case TYPE_WIDE_STRING:
|
||||
ap->a.a_wide_string = va_arg (args, const wchar_t *);
|
||||
/* A null pointer is an invalid argument for "%ls", but in practice
|
||||
it occurs quite frequently in printf statements that produce
|
||||
debug output. Use a fallback in this case. */
|
||||
if (ap->a.a_wide_string == NULL)
|
||||
{
|
||||
static const wchar_t wide_null_string[] =
|
||||
{
|
||||
(wchar_t)'(',
|
||||
(wchar_t)'N', (wchar_t)'U', (wchar_t)'L', (wchar_t)'L',
|
||||
(wchar_t)')',
|
||||
(wchar_t)0
|
||||
};
|
||||
ap->a.a_wide_string = wide_null_string;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case TYPE_POINTER:
|
||||
ap->a.a_pointer = va_arg (args, void *);
|
||||
break;
|
||||
case TYPE_COUNT_SCHAR_POINTER:
|
||||
ap->a.a_count_schar_pointer = va_arg (args, signed char *);
|
||||
break;
|
||||
case TYPE_COUNT_SHORT_POINTER:
|
||||
ap->a.a_count_short_pointer = va_arg (args, short *);
|
||||
break;
|
||||
case TYPE_COUNT_INT_POINTER:
|
||||
ap->a.a_count_int_pointer = va_arg (args, int *);
|
||||
break;
|
||||
case TYPE_COUNT_LONGINT_POINTER:
|
||||
ap->a.a_count_longint_pointer = va_arg (args, long int *);
|
||||
break;
|
||||
#if HAVE_LONG_LONG_INT
|
||||
case TYPE_COUNT_LONGLONGINT_POINTER:
|
||||
ap->a.a_count_longlongint_pointer = va_arg (args, long long int *);
|
||||
break;
|
||||
#endif
|
||||
#if ENABLE_UNISTDIO
|
||||
/* The unistdio extensions. */
|
||||
case TYPE_U8_STRING:
|
||||
ap->a.a_u8_string = va_arg (args, const uint8_t *);
|
||||
/* A null pointer is an invalid argument for "%U", but in practice
|
||||
it occurs quite frequently in printf statements that produce
|
||||
debug output. Use a fallback in this case. */
|
||||
if (ap->a.a_u8_string == NULL)
|
||||
{
|
||||
static const uint8_t u8_null_string[] =
|
||||
{ '(', 'N', 'U', 'L', 'L', ')', 0 };
|
||||
ap->a.a_u8_string = u8_null_string;
|
||||
}
|
||||
break;
|
||||
case TYPE_U16_STRING:
|
||||
ap->a.a_u16_string = va_arg (args, const uint16_t *);
|
||||
/* A null pointer is an invalid argument for "%lU", but in practice
|
||||
it occurs quite frequently in printf statements that produce
|
||||
debug output. Use a fallback in this case. */
|
||||
if (ap->a.a_u16_string == NULL)
|
||||
{
|
||||
static const uint16_t u16_null_string[] =
|
||||
{ '(', 'N', 'U', 'L', 'L', ')', 0 };
|
||||
ap->a.a_u16_string = u16_null_string;
|
||||
}
|
||||
break;
|
||||
case TYPE_U32_STRING:
|
||||
ap->a.a_u32_string = va_arg (args, const uint32_t *);
|
||||
/* A null pointer is an invalid argument for "%llU", but in practice
|
||||
it occurs quite frequently in printf statements that produce
|
||||
debug output. Use a fallback in this case. */
|
||||
if (ap->a.a_u32_string == NULL)
|
||||
{
|
||||
static const uint32_t u32_null_string[] =
|
||||
{ '(', 'N', 'U', 'L', 'L', ')', 0 };
|
||||
ap->a.a_u32_string = u32_null_string;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* Unknown type. */
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
/* Decomposed printf argument list.
|
||||
Copyright (C) 1999, 2002-2003, 2006-2007, 2011 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
#ifndef _PRINTF_ARGS_H
|
||||
#define _PRINTF_ARGS_H
|
||||
|
||||
/* This file can be parametrized with the following macros:
|
||||
ENABLE_UNISTDIO Set to 1 to enable the unistdio extensions.
|
||||
PRINTF_FETCHARGS Name of the function to be declared.
|
||||
STATIC Set to 'static' to declare the function static. */
|
||||
|
||||
/* Default parameters. */
|
||||
#ifndef PRINTF_FETCHARGS
|
||||
# define PRINTF_FETCHARGS printf_fetchargs
|
||||
#endif
|
||||
|
||||
/* Get size_t. */
|
||||
#include <stddef.h>
|
||||
|
||||
/* Get wchar_t. */
|
||||
#if HAVE_WCHAR_T
|
||||
# include <stddef.h>
|
||||
#endif
|
||||
|
||||
/* Get wint_t. */
|
||||
#if HAVE_WINT_T
|
||||
# include <wchar.h>
|
||||
#endif
|
||||
|
||||
/* Get va_list. */
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
/* Argument types */
|
||||
typedef enum
|
||||
{
|
||||
TYPE_NONE,
|
||||
TYPE_SCHAR,
|
||||
TYPE_UCHAR,
|
||||
TYPE_SHORT,
|
||||
TYPE_USHORT,
|
||||
TYPE_INT,
|
||||
TYPE_UINT,
|
||||
TYPE_LONGINT,
|
||||
TYPE_ULONGINT,
|
||||
#if HAVE_LONG_LONG_INT
|
||||
TYPE_LONGLONGINT,
|
||||
TYPE_ULONGLONGINT,
|
||||
#endif
|
||||
TYPE_DOUBLE,
|
||||
TYPE_LONGDOUBLE,
|
||||
TYPE_CHAR,
|
||||
#if HAVE_WINT_T
|
||||
TYPE_WIDE_CHAR,
|
||||
#endif
|
||||
TYPE_STRING,
|
||||
#if HAVE_WCHAR_T
|
||||
TYPE_WIDE_STRING,
|
||||
#endif
|
||||
TYPE_POINTER,
|
||||
TYPE_COUNT_SCHAR_POINTER,
|
||||
TYPE_COUNT_SHORT_POINTER,
|
||||
TYPE_COUNT_INT_POINTER,
|
||||
TYPE_COUNT_LONGINT_POINTER
|
||||
#if HAVE_LONG_LONG_INT
|
||||
, TYPE_COUNT_LONGLONGINT_POINTER
|
||||
#endif
|
||||
#if ENABLE_UNISTDIO
|
||||
/* The unistdio extensions. */
|
||||
, TYPE_U8_STRING
|
||||
, TYPE_U16_STRING
|
||||
, TYPE_U32_STRING
|
||||
#endif
|
||||
} arg_type;
|
||||
|
||||
/* Polymorphic argument */
|
||||
typedef struct
|
||||
{
|
||||
arg_type type;
|
||||
union
|
||||
{
|
||||
signed char a_schar;
|
||||
unsigned char a_uchar;
|
||||
short a_short;
|
||||
unsigned short a_ushort;
|
||||
int a_int;
|
||||
unsigned int a_uint;
|
||||
long int a_longint;
|
||||
unsigned long int a_ulongint;
|
||||
#if HAVE_LONG_LONG_INT
|
||||
long long int a_longlongint;
|
||||
unsigned long long int a_ulonglongint;
|
||||
#endif
|
||||
float a_float;
|
||||
double a_double;
|
||||
long double a_longdouble;
|
||||
int a_char;
|
||||
#if HAVE_WINT_T
|
||||
wint_t a_wide_char;
|
||||
#endif
|
||||
const char* a_string;
|
||||
#if HAVE_WCHAR_T
|
||||
const wchar_t* a_wide_string;
|
||||
#endif
|
||||
void* a_pointer;
|
||||
signed char * a_count_schar_pointer;
|
||||
short * a_count_short_pointer;
|
||||
int * a_count_int_pointer;
|
||||
long int * a_count_longint_pointer;
|
||||
#if HAVE_LONG_LONG_INT
|
||||
long long int * a_count_longlongint_pointer;
|
||||
#endif
|
||||
#if ENABLE_UNISTDIO
|
||||
/* The unistdio extensions. */
|
||||
const uint8_t * a_u8_string;
|
||||
const uint16_t * a_u16_string;
|
||||
const uint32_t * a_u32_string;
|
||||
#endif
|
||||
}
|
||||
a;
|
||||
}
|
||||
argument;
|
||||
|
||||
/* Number of directly allocated arguments (no malloc() needed). */
|
||||
#define N_DIRECT_ALLOC_ARGUMENTS 7
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t count;
|
||||
argument *arg;
|
||||
argument direct_alloc_arg[N_DIRECT_ALLOC_ARGUMENTS];
|
||||
}
|
||||
arguments;
|
||||
|
||||
|
||||
/* Fetch the arguments, putting them into a. */
|
||||
#ifdef STATIC
|
||||
STATIC
|
||||
#else
|
||||
extern
|
||||
#endif
|
||||
int PRINTF_FETCHARGS (va_list args, arguments *a);
|
||||
|
||||
#endif /* _PRINTF_ARGS_H */
|
||||
@@ -0,0 +1,639 @@
|
||||
/* Formatted output to strings.
|
||||
Copyright (C) 1999-2000, 2002-2003, 2006-2008, 2010-2011, 2018 Free Software
|
||||
Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
/* This file can be parametrized with the following macros:
|
||||
CHAR_T The element type of the format string.
|
||||
CHAR_T_ONLY_ASCII Set to 1 to enable verification that all characters
|
||||
in the format string are ASCII.
|
||||
DIRECTIVE Structure denoting a format directive.
|
||||
Depends on CHAR_T.
|
||||
DIRECTIVES Structure denoting the set of format directives of a
|
||||
format string. Depends on CHAR_T.
|
||||
PRINTF_PARSE Function that parses a format string.
|
||||
Depends on CHAR_T.
|
||||
STATIC Set to 'static' to declare the function static.
|
||||
ENABLE_UNISTDIO Set to 1 to enable the unistdio extensions. */
|
||||
|
||||
#ifndef PRINTF_PARSE
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
/* Specification. */
|
||||
#ifndef PRINTF_PARSE
|
||||
# include "printf-parse.h"
|
||||
#endif
|
||||
|
||||
/* Default parameters. */
|
||||
#ifndef PRINTF_PARSE
|
||||
# define PRINTF_PARSE printf_parse
|
||||
# define CHAR_T char
|
||||
# define DIRECTIVE char_directive
|
||||
# define DIRECTIVES char_directives
|
||||
#endif
|
||||
|
||||
/* Get size_t, NULL. */
|
||||
#include <stddef.h>
|
||||
|
||||
/* Get intmax_t. */
|
||||
#if defined IN_LIBINTL || defined IN_LIBASPRINTF
|
||||
# if HAVE_STDINT_H_WITH_UINTMAX
|
||||
# include <stdint.h>
|
||||
# endif
|
||||
# if HAVE_INTTYPES_H_WITH_UINTMAX
|
||||
# include <inttypes.h>
|
||||
# endif
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
/* malloc(), realloc(), free(). */
|
||||
#include <stdlib.h>
|
||||
|
||||
/* memcpy(). */
|
||||
#include <string.h>
|
||||
|
||||
/* errno. */
|
||||
#include <errno.h>
|
||||
|
||||
/* Checked size_t computations. */
|
||||
#include "xsize.h"
|
||||
|
||||
#if CHAR_T_ONLY_ASCII
|
||||
/* c_isascii(). */
|
||||
# include "c-ctype.h"
|
||||
#endif
|
||||
|
||||
#ifdef STATIC
|
||||
STATIC
|
||||
#endif
|
||||
int
|
||||
PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
|
||||
{
|
||||
const CHAR_T *cp = format; /* pointer into format */
|
||||
size_t arg_posn = 0; /* number of regular arguments consumed */
|
||||
size_t d_allocated; /* allocated elements of d->dir */
|
||||
size_t a_allocated; /* allocated elements of a->arg */
|
||||
size_t max_width_length = 0;
|
||||
size_t max_precision_length = 0;
|
||||
|
||||
d->count = 0;
|
||||
d_allocated = N_DIRECT_ALLOC_DIRECTIVES;
|
||||
d->dir = d->direct_alloc_dir;
|
||||
|
||||
a->count = 0;
|
||||
a_allocated = N_DIRECT_ALLOC_ARGUMENTS;
|
||||
a->arg = a->direct_alloc_arg;
|
||||
|
||||
#define REGISTER_ARG(_index_,_type_) \
|
||||
{ \
|
||||
size_t n = (_index_); \
|
||||
if (n >= a_allocated) \
|
||||
{ \
|
||||
size_t memory_size; \
|
||||
argument *memory; \
|
||||
\
|
||||
a_allocated = xtimes (a_allocated, 2); \
|
||||
if (a_allocated <= n) \
|
||||
a_allocated = xsum (n, 1); \
|
||||
memory_size = xtimes (a_allocated, sizeof (argument)); \
|
||||
if (size_overflow_p (memory_size)) \
|
||||
/* Overflow, would lead to out of memory. */ \
|
||||
goto out_of_memory; \
|
||||
memory = (argument *) (a->arg != a->direct_alloc_arg \
|
||||
? realloc (a->arg, memory_size) \
|
||||
: malloc (memory_size)); \
|
||||
if (memory == NULL) \
|
||||
/* Out of memory. */ \
|
||||
goto out_of_memory; \
|
||||
if (a->arg == a->direct_alloc_arg) \
|
||||
memcpy (memory, a->arg, a->count * sizeof (argument)); \
|
||||
a->arg = memory; \
|
||||
} \
|
||||
while (a->count <= n) \
|
||||
a->arg[a->count++].type = TYPE_NONE; \
|
||||
if (a->arg[n].type == TYPE_NONE) \
|
||||
a->arg[n].type = (_type_); \
|
||||
else if (a->arg[n].type != (_type_)) \
|
||||
/* Ambiguous type for positional argument. */ \
|
||||
goto error; \
|
||||
}
|
||||
|
||||
while (*cp != '\0')
|
||||
{
|
||||
CHAR_T c = *cp++;
|
||||
if (c == '%')
|
||||
{
|
||||
size_t arg_index = ARG_NONE;
|
||||
DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
|
||||
|
||||
/* Initialize the next directive. */
|
||||
dp->dir_start = cp - 1;
|
||||
dp->flags = 0;
|
||||
dp->width_start = NULL;
|
||||
dp->width_end = NULL;
|
||||
dp->width_arg_index = ARG_NONE;
|
||||
dp->precision_start = NULL;
|
||||
dp->precision_end = NULL;
|
||||
dp->precision_arg_index = ARG_NONE;
|
||||
dp->arg_index = ARG_NONE;
|
||||
|
||||
/* Test for positional argument. */
|
||||
if (*cp >= '0' && *cp <= '9')
|
||||
{
|
||||
const CHAR_T *np;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
;
|
||||
if (*np == '$')
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
n = xsum (xtimes (n, 10), *np - '0');
|
||||
if (n == 0)
|
||||
/* Positional argument 0. */
|
||||
goto error;
|
||||
if (size_overflow_p (n))
|
||||
/* n too large, would lead to out of memory later. */
|
||||
goto error;
|
||||
arg_index = n - 1;
|
||||
cp = np + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the flags. */
|
||||
for (;;)
|
||||
{
|
||||
if (*cp == '\'')
|
||||
{
|
||||
dp->flags |= FLAG_GROUP;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == '-')
|
||||
{
|
||||
dp->flags |= FLAG_LEFT;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == '+')
|
||||
{
|
||||
dp->flags |= FLAG_SHOWSIGN;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == ' ')
|
||||
{
|
||||
dp->flags |= FLAG_SPACE;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == '#')
|
||||
{
|
||||
dp->flags |= FLAG_ALT;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == '0')
|
||||
{
|
||||
dp->flags |= FLAG_ZERO;
|
||||
cp++;
|
||||
}
|
||||
#if __GLIBC__ >= 2 && !defined __UCLIBC__
|
||||
else if (*cp == 'I')
|
||||
{
|
||||
dp->flags |= FLAG_LOCALIZED;
|
||||
cp++;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Parse the field width. */
|
||||
if (*cp == '*')
|
||||
{
|
||||
dp->width_start = cp;
|
||||
cp++;
|
||||
dp->width_end = cp;
|
||||
if (max_width_length < 1)
|
||||
max_width_length = 1;
|
||||
|
||||
/* Test for positional argument. */
|
||||
if (*cp >= '0' && *cp <= '9')
|
||||
{
|
||||
const CHAR_T *np;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
;
|
||||
if (*np == '$')
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
n = xsum (xtimes (n, 10), *np - '0');
|
||||
if (n == 0)
|
||||
/* Positional argument 0. */
|
||||
goto error;
|
||||
if (size_overflow_p (n))
|
||||
/* n too large, would lead to out of memory later. */
|
||||
goto error;
|
||||
dp->width_arg_index = n - 1;
|
||||
cp = np + 1;
|
||||
}
|
||||
}
|
||||
if (dp->width_arg_index == ARG_NONE)
|
||||
{
|
||||
dp->width_arg_index = arg_posn++;
|
||||
if (dp->width_arg_index == ARG_NONE)
|
||||
/* arg_posn wrapped around. */
|
||||
goto error;
|
||||
}
|
||||
REGISTER_ARG (dp->width_arg_index, TYPE_INT);
|
||||
}
|
||||
else if (*cp >= '0' && *cp <= '9')
|
||||
{
|
||||
size_t width_length;
|
||||
|
||||
dp->width_start = cp;
|
||||
for (; *cp >= '0' && *cp <= '9'; cp++)
|
||||
;
|
||||
dp->width_end = cp;
|
||||
width_length = dp->width_end - dp->width_start;
|
||||
if (max_width_length < width_length)
|
||||
max_width_length = width_length;
|
||||
}
|
||||
|
||||
/* Parse the precision. */
|
||||
if (*cp == '.')
|
||||
{
|
||||
cp++;
|
||||
if (*cp == '*')
|
||||
{
|
||||
dp->precision_start = cp - 1;
|
||||
cp++;
|
||||
dp->precision_end = cp;
|
||||
if (max_precision_length < 2)
|
||||
max_precision_length = 2;
|
||||
|
||||
/* Test for positional argument. */
|
||||
if (*cp >= '0' && *cp <= '9')
|
||||
{
|
||||
const CHAR_T *np;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
;
|
||||
if (*np == '$')
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
for (np = cp; *np >= '0' && *np <= '9'; np++)
|
||||
n = xsum (xtimes (n, 10), *np - '0');
|
||||
if (n == 0)
|
||||
/* Positional argument 0. */
|
||||
goto error;
|
||||
if (size_overflow_p (n))
|
||||
/* n too large, would lead to out of memory
|
||||
later. */
|
||||
goto error;
|
||||
dp->precision_arg_index = n - 1;
|
||||
cp = np + 1;
|
||||
}
|
||||
}
|
||||
if (dp->precision_arg_index == ARG_NONE)
|
||||
{
|
||||
dp->precision_arg_index = arg_posn++;
|
||||
if (dp->precision_arg_index == ARG_NONE)
|
||||
/* arg_posn wrapped around. */
|
||||
goto error;
|
||||
}
|
||||
REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t precision_length;
|
||||
|
||||
dp->precision_start = cp - 1;
|
||||
for (; *cp >= '0' && *cp <= '9'; cp++)
|
||||
;
|
||||
dp->precision_end = cp;
|
||||
precision_length = dp->precision_end - dp->precision_start;
|
||||
if (max_precision_length < precision_length)
|
||||
max_precision_length = precision_length;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
arg_type type;
|
||||
|
||||
/* Parse argument type/size specifiers. */
|
||||
{
|
||||
int flags = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (*cp == 'h')
|
||||
{
|
||||
flags |= (1 << (flags & 1));
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == 'L')
|
||||
{
|
||||
flags |= 4;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == 'l')
|
||||
{
|
||||
flags += 8;
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == 'j')
|
||||
{
|
||||
if (sizeof (intmax_t) > sizeof (long))
|
||||
{
|
||||
/* intmax_t = long long */
|
||||
flags += 16;
|
||||
}
|
||||
else if (sizeof (intmax_t) > sizeof (int))
|
||||
{
|
||||
/* intmax_t = long */
|
||||
flags += 8;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == 'z' || *cp == 'Z')
|
||||
{
|
||||
/* 'z' is standardized in ISO C 99, but glibc uses 'Z'
|
||||
because the warning facility in gcc-2.95.2 understands
|
||||
only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
|
||||
if (sizeof (size_t) > sizeof (long))
|
||||
{
|
||||
/* size_t = long long */
|
||||
flags += 16;
|
||||
}
|
||||
else if (sizeof (size_t) > sizeof (int))
|
||||
{
|
||||
/* size_t = long */
|
||||
flags += 8;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == 't')
|
||||
{
|
||||
if (sizeof (ptrdiff_t) > sizeof (long))
|
||||
{
|
||||
/* ptrdiff_t = long long */
|
||||
flags += 16;
|
||||
}
|
||||
else if (sizeof (ptrdiff_t) > sizeof (int))
|
||||
{
|
||||
/* ptrdiff_t = long */
|
||||
flags += 8;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
#if defined __APPLE__ && defined __MACH__
|
||||
/* On Mac OS X 10.3, PRIdMAX is defined as "qd".
|
||||
We cannot change it to "lld" because PRIdMAX must also
|
||||
be understood by the system's printf routines. */
|
||||
else if (*cp == 'q')
|
||||
{
|
||||
if (64 / 8 > sizeof (long))
|
||||
{
|
||||
/* int64_t = long long */
|
||||
flags += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* int64_t = long */
|
||||
flags += 8;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
#endif
|
||||
#if defined _WIN32 && ! defined __CYGWIN__
|
||||
/* On native Windows, PRIdMAX is defined as "I64d".
|
||||
We cannot change it to "lld" because PRIdMAX must also
|
||||
be understood by the system's printf routines. */
|
||||
else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
|
||||
{
|
||||
if (64 / 8 > sizeof (long))
|
||||
{
|
||||
/* __int64 = long long */
|
||||
flags += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* __int64 = long */
|
||||
flags += 8;
|
||||
}
|
||||
cp += 3;
|
||||
}
|
||||
#endif
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read the conversion character. */
|
||||
c = *cp++;
|
||||
switch (c)
|
||||
{
|
||||
case 'd': case 'i':
|
||||
#if HAVE_LONG_LONG_INT
|
||||
/* If 'long long' exists and is larger than 'long': */
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_LONGLONGINT;
|
||||
else
|
||||
#endif
|
||||
/* If 'long long' exists and is the same as 'long', we parse
|
||||
"lld" into TYPE_LONGINT. */
|
||||
if (flags >= 8)
|
||||
type = TYPE_LONGINT;
|
||||
else if (flags & 2)
|
||||
type = TYPE_SCHAR;
|
||||
else if (flags & 1)
|
||||
type = TYPE_SHORT;
|
||||
else
|
||||
type = TYPE_INT;
|
||||
break;
|
||||
case 'o': case 'u': case 'x': case 'X':
|
||||
#if HAVE_LONG_LONG_INT
|
||||
/* If 'long long' exists and is larger than 'long': */
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_ULONGLONGINT;
|
||||
else
|
||||
#endif
|
||||
/* If 'unsigned long long' exists and is the same as
|
||||
'unsigned long', we parse "llu" into TYPE_ULONGINT. */
|
||||
if (flags >= 8)
|
||||
type = TYPE_ULONGINT;
|
||||
else if (flags & 2)
|
||||
type = TYPE_UCHAR;
|
||||
else if (flags & 1)
|
||||
type = TYPE_USHORT;
|
||||
else
|
||||
type = TYPE_UINT;
|
||||
break;
|
||||
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
|
||||
case 'a': case 'A':
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_LONGDOUBLE;
|
||||
else
|
||||
type = TYPE_DOUBLE;
|
||||
break;
|
||||
case 'c':
|
||||
if (flags >= 8)
|
||||
#if HAVE_WINT_T
|
||||
type = TYPE_WIDE_CHAR;
|
||||
#else
|
||||
goto error;
|
||||
#endif
|
||||
else
|
||||
type = TYPE_CHAR;
|
||||
break;
|
||||
#if HAVE_WINT_T
|
||||
case 'C':
|
||||
type = TYPE_WIDE_CHAR;
|
||||
c = 'c';
|
||||
break;
|
||||
#endif
|
||||
case 's':
|
||||
if (flags >= 8)
|
||||
#if HAVE_WCHAR_T
|
||||
type = TYPE_WIDE_STRING;
|
||||
#else
|
||||
goto error;
|
||||
#endif
|
||||
else
|
||||
type = TYPE_STRING;
|
||||
break;
|
||||
#if HAVE_WCHAR_T
|
||||
case 'S':
|
||||
type = TYPE_WIDE_STRING;
|
||||
c = 's';
|
||||
break;
|
||||
#endif
|
||||
case 'p':
|
||||
type = TYPE_POINTER;
|
||||
break;
|
||||
case 'n':
|
||||
#if HAVE_LONG_LONG_INT
|
||||
/* If 'long long' exists and is larger than 'long': */
|
||||
if (flags >= 16 || (flags & 4))
|
||||
type = TYPE_COUNT_LONGLONGINT_POINTER;
|
||||
else
|
||||
#endif
|
||||
/* If 'long long' exists and is the same as 'long', we parse
|
||||
"lln" into TYPE_COUNT_LONGINT_POINTER. */
|
||||
if (flags >= 8)
|
||||
type = TYPE_COUNT_LONGINT_POINTER;
|
||||
else if (flags & 2)
|
||||
type = TYPE_COUNT_SCHAR_POINTER;
|
||||
else if (flags & 1)
|
||||
type = TYPE_COUNT_SHORT_POINTER;
|
||||
else
|
||||
type = TYPE_COUNT_INT_POINTER;
|
||||
break;
|
||||
#if ENABLE_UNISTDIO
|
||||
/* The unistdio extensions. */
|
||||
case 'U':
|
||||
if (flags >= 16)
|
||||
type = TYPE_U32_STRING;
|
||||
else if (flags >= 8)
|
||||
type = TYPE_U16_STRING;
|
||||
else
|
||||
type = TYPE_U8_STRING;
|
||||
break;
|
||||
#endif
|
||||
case '%':
|
||||
type = TYPE_NONE;
|
||||
break;
|
||||
default:
|
||||
/* Unknown conversion character. */
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (type != TYPE_NONE)
|
||||
{
|
||||
dp->arg_index = arg_index;
|
||||
if (dp->arg_index == ARG_NONE)
|
||||
{
|
||||
dp->arg_index = arg_posn++;
|
||||
if (dp->arg_index == ARG_NONE)
|
||||
/* arg_posn wrapped around. */
|
||||
goto error;
|
||||
}
|
||||
REGISTER_ARG (dp->arg_index, type);
|
||||
}
|
||||
dp->conversion = c;
|
||||
dp->dir_end = cp;
|
||||
}
|
||||
|
||||
d->count++;
|
||||
if (d->count >= d_allocated)
|
||||
{
|
||||
size_t memory_size;
|
||||
DIRECTIVE *memory;
|
||||
|
||||
d_allocated = xtimes (d_allocated, 2);
|
||||
memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
|
||||
if (size_overflow_p (memory_size))
|
||||
/* Overflow, would lead to out of memory. */
|
||||
goto out_of_memory;
|
||||
memory = (DIRECTIVE *) (d->dir != d->direct_alloc_dir
|
||||
? realloc (d->dir, memory_size)
|
||||
: malloc (memory_size));
|
||||
if (memory == NULL)
|
||||
/* Out of memory. */
|
||||
goto out_of_memory;
|
||||
if (d->dir == d->direct_alloc_dir)
|
||||
memcpy (memory, d->dir, d->count * sizeof (DIRECTIVE));
|
||||
d->dir = memory;
|
||||
}
|
||||
}
|
||||
#if CHAR_T_ONLY_ASCII
|
||||
else if (!c_isascii (c))
|
||||
{
|
||||
/* Non-ASCII character. Not supported. */
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
d->dir[d->count].dir_start = cp;
|
||||
|
||||
d->max_width_length = max_width_length;
|
||||
d->max_precision_length = max_precision_length;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (a->arg != a->direct_alloc_arg)
|
||||
free (a->arg);
|
||||
if (d->dir != d->direct_alloc_dir)
|
||||
free (d->dir);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
|
||||
out_of_memory:
|
||||
if (a->arg != a->direct_alloc_arg)
|
||||
free (a->arg);
|
||||
if (d->dir != d->direct_alloc_dir)
|
||||
free (d->dir);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#undef PRINTF_PARSE
|
||||
#undef DIRECTIVES
|
||||
#undef DIRECTIVE
|
||||
#undef CHAR_T_ONLY_ASCII
|
||||
#undef CHAR_T
|
||||
@@ -0,0 +1,84 @@
|
||||
/* Parse printf format string.
|
||||
Copyright (C) 1999, 2002-2003, 2005, 2007, 2010-2011 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
#ifndef _PRINTF_PARSE_H
|
||||
#define _PRINTF_PARSE_H
|
||||
|
||||
#if HAVE_FEATURES_H
|
||||
# include <features.h> /* for __GLIBC__, __UCLIBC__ */
|
||||
#endif
|
||||
|
||||
#include "printf-args.h"
|
||||
|
||||
|
||||
/* Flags */
|
||||
#define FLAG_GROUP 1 /* ' flag */
|
||||
#define FLAG_LEFT 2 /* - flag */
|
||||
#define FLAG_SHOWSIGN 4 /* + flag */
|
||||
#define FLAG_SPACE 8 /* space flag */
|
||||
#define FLAG_ALT 16 /* # flag */
|
||||
#define FLAG_ZERO 32
|
||||
#if __GLIBC__ >= 2 && !defined __UCLIBC__
|
||||
# define FLAG_LOCALIZED 64 /* I flag, uses localized digits */
|
||||
#endif
|
||||
|
||||
/* arg_index value indicating that no argument is consumed. */
|
||||
#define ARG_NONE (~(size_t)0)
|
||||
|
||||
/* Number of directly allocated directives (no malloc() needed). */
|
||||
#define N_DIRECT_ALLOC_DIRECTIVES 7
|
||||
|
||||
/* A parsed directive. */
|
||||
typedef struct
|
||||
{
|
||||
const char* dir_start;
|
||||
const char* dir_end;
|
||||
int flags;
|
||||
const char* width_start;
|
||||
const char* width_end;
|
||||
size_t width_arg_index;
|
||||
const char* precision_start;
|
||||
const char* precision_end;
|
||||
size_t precision_arg_index;
|
||||
char conversion; /* d i o u x X f e E g G c s p n U % but not C S */
|
||||
size_t arg_index;
|
||||
}
|
||||
char_directive;
|
||||
|
||||
/* A parsed format string. */
|
||||
typedef struct
|
||||
{
|
||||
size_t count;
|
||||
char_directive *dir;
|
||||
size_t max_width_length;
|
||||
size_t max_precision_length;
|
||||
char_directive direct_alloc_dir[N_DIRECT_ALLOC_DIRECTIVES];
|
||||
}
|
||||
char_directives;
|
||||
|
||||
|
||||
/* Parses the format string. Fills in the number N of directives, and fills
|
||||
in directives[0], ..., directives[N-1], and sets directives[N].dir_start
|
||||
to the end of the format string. Also fills in the arg_type fields of the
|
||||
arguments and the needed count of arguments. */
|
||||
#ifdef STATIC
|
||||
STATIC
|
||||
#else
|
||||
extern
|
||||
#endif
|
||||
int printf_parse (const char *format, char_directives *d, arguments *a);
|
||||
|
||||
#endif /* _PRINTF_PARSE_H */
|
||||
@@ -0,0 +1,458 @@
|
||||
/* Formatted output to strings, using POSIX/XSI format strings with positions.
|
||||
Copyright (C) 2003, 2006-2007, 2009-2011, 2018, 2020-2022 Free Software Foundation, Inc.
|
||||
Written by Bruno Haible <bruno@clisp.org>, 2003.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define alloca __builtin_alloca
|
||||
# define HAVE_ALLOCA 1
|
||||
#else
|
||||
# ifdef _MSC_VER
|
||||
# include <malloc.h>
|
||||
# define alloca _alloca
|
||||
# else
|
||||
# if defined HAVE_ALLOCA_H || defined _LIBC
|
||||
# include <alloca.h>
|
||||
# else
|
||||
# ifdef _AIX
|
||||
#pragma alloca
|
||||
# else
|
||||
# ifndef alloca
|
||||
char *alloca ();
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if !HAVE_POSIX_PRINTF
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
|
||||
#ifndef EOVERFLOW
|
||||
# define EOVERFLOW E2BIG
|
||||
#endif
|
||||
|
||||
/* When building a DLL, we must export some functions. Note that because
|
||||
the functions are only defined for binary backward compatibility, we
|
||||
don't need to use __declspec(dllimport) in any case. */
|
||||
#if HAVE_VISIBILITY && BUILDING_DLL
|
||||
# define DLL_EXPORTED __attribute__((__visibility__("default")))
|
||||
#elif defined _MSC_VER && BUILDING_DLL
|
||||
# define DLL_EXPORTED __declspec(dllexport)
|
||||
#else
|
||||
# define DLL_EXPORTED
|
||||
#endif
|
||||
|
||||
#define STATIC static
|
||||
|
||||
/* You can enable this for debugging on Windows. But not in a release! */
|
||||
#if 0
|
||||
# define ENABLE_WCHAR_FALLBACK 1
|
||||
#endif
|
||||
|
||||
/* This needs to be consistent with libgnuintl.in.h. */
|
||||
#if defined __NetBSD__ || defined __BEOS__ || defined __CYGWIN__ || defined __MINGW32__
|
||||
/* Don't break __attribute__((format(printf,M,N))).
|
||||
This redefinition is only possible because the libc in NetBSD, Cygwin,
|
||||
mingw does not have a function __printf__. */
|
||||
# define libintl_printf __printf__
|
||||
#endif
|
||||
|
||||
/* Define auxiliary functions declared in "printf-args.h". */
|
||||
#include "printf-args.c"
|
||||
|
||||
/* Define auxiliary functions declared in "printf-parse.h". */
|
||||
#include "printf-parse.c"
|
||||
|
||||
/* Define functions declared in "vasnprintf.h". */
|
||||
#define vasnprintf libintl_vasnprintf
|
||||
#include "vasnprintf.c"
|
||||
#if 0 /* not needed */
|
||||
#define asnprintf libintl_asnprintf
|
||||
#include "asnprintf.c"
|
||||
#endif
|
||||
|
||||
/* Users don't expect libintl_fprintf to be less POSIX compliant
|
||||
than the fprintf implementation provided by gnulib or - on mingw -
|
||||
the one provided by mingw libs when __USE_MINGW_ANSI_STDIO is in
|
||||
effect. */
|
||||
#define USE_REPLACEMENT_CODE_ALWAYS 1
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_vfprintf (FILE *stream, const char *format, va_list args)
|
||||
{
|
||||
#if !USE_REPLACEMENT_CODE_ALWAYS
|
||||
if (strchr (format, '$') == NULL)
|
||||
return vfprintf (stream, format, args);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
size_t length;
|
||||
char *result = libintl_vasnprintf (NULL, &length, format, args);
|
||||
int retval = -1;
|
||||
if (result != NULL)
|
||||
{
|
||||
size_t written = fwrite (result, 1, length, stream);
|
||||
free (result);
|
||||
if (written == length)
|
||||
{
|
||||
if (length > INT_MAX)
|
||||
errno = EOVERFLOW;
|
||||
else
|
||||
retval = length;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_fprintf (FILE *stream, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int retval;
|
||||
|
||||
va_start (args, format);
|
||||
retval = libintl_vfprintf (stream, format, args);
|
||||
va_end (args);
|
||||
return retval;
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_vprintf (const char *format, va_list args)
|
||||
{
|
||||
return libintl_vfprintf (stdout, format, args);
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_printf (const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int retval;
|
||||
|
||||
va_start (args, format);
|
||||
retval = libintl_vprintf (format, args);
|
||||
va_end (args);
|
||||
return retval;
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_vsprintf (char *resultbuf, const char *format, va_list args)
|
||||
{
|
||||
#if !USE_REPLACEMENT_CODE_ALWAYS
|
||||
if (strchr (format, '$') == NULL)
|
||||
return vsprintf (resultbuf, format, args);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
size_t length = (size_t) ~0 / (4 * sizeof (char));
|
||||
char *result = libintl_vasnprintf (resultbuf, &length, format, args);
|
||||
if (result != resultbuf)
|
||||
{
|
||||
free (result);
|
||||
return -1;
|
||||
}
|
||||
if (length > INT_MAX)
|
||||
{
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_sprintf (char *resultbuf, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int retval;
|
||||
|
||||
va_start (args, format);
|
||||
retval = libintl_vsprintf (resultbuf, format, args);
|
||||
va_end (args);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if HAVE_SNPRINTF
|
||||
|
||||
# if HAVE_DECL__SNPRINTF
|
||||
/* Windows. The mingw function vsnprintf() has fewer bugs than the MSVCRT
|
||||
function _vsnprintf(), so prefer that. */
|
||||
# if defined __MINGW32__
|
||||
# define system_vsnprintf vsnprintf
|
||||
# else
|
||||
# define system_vsnprintf _vsnprintf
|
||||
# endif
|
||||
# else
|
||||
/* Unix. */
|
||||
# define system_vsnprintf vsnprintf
|
||||
# endif
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_vsnprintf (char *resultbuf, size_t length, const char *format, va_list args)
|
||||
{
|
||||
# if !USE_REPLACEMENT_CODE_ALWAYS
|
||||
if (strchr (format, '$') == NULL)
|
||||
return system_vsnprintf (resultbuf, length, format, args);
|
||||
else
|
||||
# endif
|
||||
{
|
||||
size_t maxlength = length;
|
||||
char *result = libintl_vasnprintf (resultbuf, &length, format, args);
|
||||
if (result == NULL)
|
||||
return -1;
|
||||
if (result != resultbuf)
|
||||
{
|
||||
if (maxlength > 0)
|
||||
{
|
||||
size_t pruned_length =
|
||||
(length < maxlength ? length : maxlength - 1);
|
||||
memcpy (resultbuf, result, pruned_length);
|
||||
resultbuf[pruned_length] = '\0';
|
||||
}
|
||||
free (result);
|
||||
}
|
||||
if (length > INT_MAX)
|
||||
{
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_snprintf (char *resultbuf, size_t length, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int retval;
|
||||
|
||||
va_start (args, format);
|
||||
retval = libintl_vsnprintf (resultbuf, length, format, args);
|
||||
va_end (args);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if HAVE_ASPRINTF
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_vasprintf (char **resultp, const char *format, va_list args)
|
||||
{
|
||||
size_t length;
|
||||
char *result = libintl_vasnprintf (NULL, &length, format, args);
|
||||
if (result == NULL)
|
||||
return -1;
|
||||
if (length > INT_MAX)
|
||||
{
|
||||
free (result);
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
*resultp = result;
|
||||
return length;
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_asprintf (char **resultp, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int retval;
|
||||
|
||||
va_start (args, format);
|
||||
retval = libintl_vasprintf (resultp, format, args);
|
||||
va_end (args);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if HAVE_WPRINTF
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#define WIDE_CHAR_VERSION 1
|
||||
|
||||
#include "wprintf-parse.h"
|
||||
/* Define auxiliary functions declared in "wprintf-parse.h". */
|
||||
#define CHAR_T wchar_t
|
||||
#define DIRECTIVE wchar_t_directive
|
||||
#define DIRECTIVES wchar_t_directives
|
||||
#define PRINTF_PARSE wprintf_parse
|
||||
#include "printf-parse.c"
|
||||
|
||||
/* Define functions declared in "vasnprintf.h". */
|
||||
#define vasnwprintf libintl_vasnwprintf
|
||||
#include "vasnprintf.c"
|
||||
#if 0 /* not needed */
|
||||
#define asnwprintf libintl_asnwprintf
|
||||
#include "asnprintf.c"
|
||||
#endif
|
||||
|
||||
# if HAVE_DECL__SNWPRINTF
|
||||
/* Windows. The function vswprintf() has a different signature than
|
||||
on Unix; we use the function _vsnwprintf() instead. */
|
||||
# define system_vswprintf _vsnwprintf
|
||||
# else
|
||||
/* Unix. */
|
||||
# define system_vswprintf vswprintf
|
||||
# endif
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_vfwprintf (FILE *stream, const wchar_t *format, va_list args)
|
||||
{
|
||||
# if !USE_REPLACEMENT_CODE_ALWAYS
|
||||
if (wcschr (format, '$') == NULL)
|
||||
return vfwprintf (stream, format, args);
|
||||
else
|
||||
# endif
|
||||
{
|
||||
size_t length;
|
||||
wchar_t *result = libintl_vasnwprintf (NULL, &length, format, args);
|
||||
int retval = -1;
|
||||
if (result != NULL)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < length; i++)
|
||||
if (fputwc (result[i], stream) == WEOF)
|
||||
break;
|
||||
free (result);
|
||||
if (i == length)
|
||||
{
|
||||
if (length > INT_MAX)
|
||||
errno = EOVERFLOW;
|
||||
else
|
||||
retval = length;
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_fwprintf (FILE *stream, const wchar_t *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int retval;
|
||||
|
||||
va_start (args, format);
|
||||
retval = libintl_vfwprintf (stream, format, args);
|
||||
va_end (args);
|
||||
return retval;
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_vwprintf (const wchar_t *format, va_list args)
|
||||
{
|
||||
return libintl_vfwprintf (stdout, format, args);
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_wprintf (const wchar_t *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int retval;
|
||||
|
||||
va_start (args, format);
|
||||
retval = libintl_vwprintf (format, args);
|
||||
va_end (args);
|
||||
return retval;
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_vswprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, va_list args)
|
||||
{
|
||||
# if !USE_REPLACEMENT_CODE_ALWAYS
|
||||
if (wcschr (format, '$') == NULL)
|
||||
return system_vswprintf (resultbuf, length, format, args);
|
||||
else
|
||||
# endif
|
||||
{
|
||||
size_t maxlength = length;
|
||||
wchar_t *result = libintl_vasnwprintf (resultbuf, &length, format, args);
|
||||
if (result == NULL)
|
||||
return -1;
|
||||
if (result != resultbuf)
|
||||
{
|
||||
if (maxlength > 0)
|
||||
{
|
||||
size_t pruned_length =
|
||||
(length < maxlength ? length : maxlength - 1);
|
||||
memcpy (resultbuf, result, pruned_length * sizeof (wchar_t));
|
||||
resultbuf[pruned_length] = 0;
|
||||
}
|
||||
free (result);
|
||||
/* Unlike vsnprintf, which has to return the number of character that
|
||||
would have been produced if the resultbuf had been sufficiently
|
||||
large, the vswprintf function has to return a negative value if
|
||||
the resultbuf was not sufficiently large. */
|
||||
if (length >= maxlength)
|
||||
return -1;
|
||||
}
|
||||
if (length > INT_MAX)
|
||||
{
|
||||
errno = EOVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return length;
|
||||
}
|
||||
}
|
||||
|
||||
DLL_EXPORTED
|
||||
int
|
||||
libintl_swprintf (wchar_t *resultbuf, size_t length, const wchar_t *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int retval;
|
||||
|
||||
va_start (args, format);
|
||||
retval = libintl_vswprintf (resultbuf, length, format, args);
|
||||
va_end (args);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,150 @@
|
||||
/* Return the internal lock used by setlocale_null_r.
|
||||
Copyright (C) 2019-2020 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Bruno Haible <bruno@clisp.org>, 2019. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* When it is known that the gl_get_setlocale_null_lock function is defined
|
||||
by a dependency library, it should not be defined here. */
|
||||
#if OMIT_SETLOCALE_LOCK
|
||||
|
||||
/* This declaration is solely to ensure that after preprocessing
|
||||
this file is never empty. */
|
||||
typedef int dummy;
|
||||
|
||||
#else
|
||||
|
||||
/* This file defines the internal lock used by setlocale_null_r.
|
||||
It is a separate compilation unit, so that only one copy of it is
|
||||
present when linking statically. */
|
||||
|
||||
/* Prohibit renaming this symbol. */
|
||||
# undef gl_get_setlocale_null_lock
|
||||
|
||||
/* Macro for exporting a symbol (function, not variable) defined in this file,
|
||||
when compiled into a shared library. */
|
||||
# ifndef DLL_EXPORTED
|
||||
# if HAVE_VISIBILITY
|
||||
/* Override the effect of the compiler option '-fvisibility=hidden'. */
|
||||
# define DLL_EXPORTED __attribute__((__visibility__("default")))
|
||||
# elif defined _WIN32 || defined __CYGWIN__
|
||||
# define DLL_EXPORTED __declspec(dllexport)
|
||||
# else
|
||||
# define DLL_EXPORTED
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined _WIN32 && !defined __CYGWIN__
|
||||
|
||||
# define WIN32_LEAN_AND_MEAN /* avoid including junk */
|
||||
# include <windows.h>
|
||||
|
||||
# include "windows-initguard.h"
|
||||
|
||||
/* The return type is a 'CRITICAL_SECTION *', not a 'glwthread_mutex_t *',
|
||||
because the latter is not guaranteed to be a stable ABI in the future. */
|
||||
|
||||
/* Make sure the function gets exported from DLLs. */
|
||||
DLL_EXPORTED CRITICAL_SECTION *gl_get_setlocale_null_lock (void);
|
||||
|
||||
static glwthread_initguard_t guard = GLWTHREAD_INITGUARD_INIT;
|
||||
static CRITICAL_SECTION lock;
|
||||
|
||||
/* Returns the internal lock used by setlocale_null_r. */
|
||||
CRITICAL_SECTION *
|
||||
gl_get_setlocale_null_lock (void)
|
||||
{
|
||||
if (!guard.done)
|
||||
{
|
||||
if (InterlockedIncrement (&guard.started) == 0)
|
||||
{
|
||||
/* This thread is the first one to need the lock. Initialize it. */
|
||||
InitializeCriticalSection (&lock);
|
||||
guard.done = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Don't let guard.started grow and wrap around. */
|
||||
InterlockedDecrement (&guard.started);
|
||||
/* Yield the CPU while waiting for another thread to finish
|
||||
initializing this mutex. */
|
||||
while (!guard.done)
|
||||
Sleep (0);
|
||||
}
|
||||
}
|
||||
return &lock;
|
||||
}
|
||||
|
||||
# elif HAVE_PTHREAD_API
|
||||
|
||||
# include <pthread.h>
|
||||
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/* Make sure the function gets exported from shared libraries. */
|
||||
DLL_EXPORTED pthread_mutex_t *gl_get_setlocale_null_lock (void);
|
||||
|
||||
/* Returns the internal lock used by setlocale_null_r. */
|
||||
pthread_mutex_t *
|
||||
gl_get_setlocale_null_lock (void)
|
||||
{
|
||||
return &mutex;
|
||||
}
|
||||
|
||||
# elif HAVE_THREADS_H
|
||||
|
||||
# include <threads.h>
|
||||
# include <stdlib.h>
|
||||
|
||||
static int volatile init_needed = 1;
|
||||
static once_flag init_once = ONCE_FLAG_INIT;
|
||||
static mtx_t mutex;
|
||||
|
||||
static void
|
||||
atomic_init (void)
|
||||
{
|
||||
if (mtx_init (&mutex, mtx_plain) != thrd_success)
|
||||
abort ();
|
||||
init_needed = 0;
|
||||
}
|
||||
|
||||
/* Make sure the function gets exported from shared libraries. */
|
||||
DLL_EXPORTED mtx_t *gl_get_setlocale_null_lock (void);
|
||||
|
||||
/* Returns the internal lock used by setlocale_null_r. */
|
||||
mtx_t *
|
||||
gl_get_setlocale_null_lock (void)
|
||||
{
|
||||
if (init_needed)
|
||||
call_once (&init_once, atomic_init);
|
||||
return &mutex;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
# if (defined _WIN32 || defined __CYGWIN__) && !defined _MSC_VER
|
||||
/* Make sure the '__declspec(dllimport)' in setlocale_null.c does not cause
|
||||
a link failure when no DLLs are involved. */
|
||||
# if defined _WIN64 || defined _LP64
|
||||
# define IMP(x) __imp_##x
|
||||
# else
|
||||
# define IMP(x) _imp__##x
|
||||
# endif
|
||||
void * IMP(gl_get_setlocale_null_lock) = &gl_get_setlocale_null_lock;
|
||||
# endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,414 @@
|
||||
/* Query the name of the current global locale.
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Bruno Haible <bruno@clisp.org>, 2019. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#define SETLOCALE_NULL_ALL_MTSAFE 1
|
||||
#define SETLOCALE_NULL_ONE_MTSAFE 1
|
||||
|
||||
/* Specification. */
|
||||
#include "setlocale_null.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if defined _WIN32 && !defined __CYGWIN__
|
||||
# include <wchar.h>
|
||||
#endif
|
||||
|
||||
#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE)
|
||||
# if defined _WIN32 && !defined __CYGWIN__
|
||||
|
||||
# define WIN32_LEAN_AND_MEAN /* avoid including junk */
|
||||
# include <windows.h>
|
||||
|
||||
# elif HAVE_PTHREAD_API
|
||||
|
||||
# include <pthread.h>
|
||||
# if HAVE_THREADS_H && HAVE_WEAK_SYMBOLS
|
||||
# include <threads.h>
|
||||
# pragma weak thrd_exit
|
||||
# define c11_threads_in_use() (thrd_exit != NULL)
|
||||
# else
|
||||
# define c11_threads_in_use() 0
|
||||
# endif
|
||||
|
||||
# elif HAVE_THREADS_H
|
||||
|
||||
# include <threads.h>
|
||||
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Use the system's setlocale() function, not the gnulib override, here. */
|
||||
#undef setlocale
|
||||
|
||||
static const char *
|
||||
setlocale_null_androidfix (int category)
|
||||
{
|
||||
const char *result = setlocale (category, NULL);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (result == NULL)
|
||||
switch (category)
|
||||
{
|
||||
case LC_CTYPE:
|
||||
case LC_NUMERIC:
|
||||
case LC_TIME:
|
||||
case LC_COLLATE:
|
||||
case LC_MONETARY:
|
||||
case LC_MESSAGES:
|
||||
case LC_ALL:
|
||||
case LC_PAPER:
|
||||
case LC_NAME:
|
||||
case LC_ADDRESS:
|
||||
case LC_TELEPHONE:
|
||||
case LC_MEASUREMENT:
|
||||
result = "C";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int
|
||||
setlocale_null_unlocked (int category, char *buf, size_t bufsize)
|
||||
{
|
||||
#if defined _WIN32 && !defined __CYGWIN__ && defined _MSC_VER
|
||||
/* On native Windows, nowadays, the setlocale() implementation is based
|
||||
on _wsetlocale() and uses malloc() for the result. We are better off
|
||||
using _wsetlocale() directly. */
|
||||
const wchar_t *result = _wsetlocale (category, NULL);
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
/* CATEGORY is invalid. */
|
||||
if (bufsize > 0)
|
||||
/* Return an empty string in BUF.
|
||||
This is a convenience for callers that don't want to write explicit
|
||||
code for handling EINVAL. */
|
||||
buf[0] = '\0';
|
||||
return EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t length = wcslen (result);
|
||||
if (length < bufsize)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
/* Convert wchar_t[] -> char[], assuming plain ASCII. */
|
||||
for (i = 0; i <= length; i++)
|
||||
buf[i] = result[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bufsize > 0)
|
||||
{
|
||||
/* Return a truncated result in BUF.
|
||||
This is a convenience for callers that don't want to write
|
||||
explicit code for handling ERANGE. */
|
||||
size_t i;
|
||||
|
||||
/* Convert wchar_t[] -> char[], assuming plain ASCII. */
|
||||
for (i = 0; i < bufsize; i++)
|
||||
buf[i] = result[i];
|
||||
buf[bufsize - 1] = '\0';
|
||||
}
|
||||
return ERANGE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
const char *result = setlocale_null_androidfix (category);
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
/* CATEGORY is invalid. */
|
||||
if (bufsize > 0)
|
||||
/* Return an empty string in BUF.
|
||||
This is a convenience for callers that don't want to write explicit
|
||||
code for handling EINVAL. */
|
||||
buf[0] = '\0';
|
||||
return EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t length = strlen (result);
|
||||
if (length < bufsize)
|
||||
{
|
||||
memcpy (buf, result, length + 1);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bufsize > 0)
|
||||
{
|
||||
/* Return a truncated result in BUF.
|
||||
This is a convenience for callers that don't want to write
|
||||
explicit code for handling ERANGE. */
|
||||
memcpy (buf, result, bufsize - 1);
|
||||
buf[bufsize - 1] = '\0';
|
||||
}
|
||||
return ERANGE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !(SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE) /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin */
|
||||
|
||||
/* Use a lock, so that no two threads can invoke setlocale_null_unlocked
|
||||
at the same time. */
|
||||
|
||||
/* Prohibit renaming this symbol. */
|
||||
# undef gl_get_setlocale_null_lock
|
||||
|
||||
# if defined _WIN32 && !defined __CYGWIN__
|
||||
|
||||
extern __declspec(dllimport) CRITICAL_SECTION *gl_get_setlocale_null_lock (void);
|
||||
|
||||
static int
|
||||
setlocale_null_with_lock (int category, char *buf, size_t bufsize)
|
||||
{
|
||||
CRITICAL_SECTION *lock = gl_get_setlocale_null_lock ();
|
||||
int ret;
|
||||
|
||||
EnterCriticalSection (lock);
|
||||
ret = setlocale_null_unlocked (category, buf, bufsize);
|
||||
LeaveCriticalSection (lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
# elif HAVE_PTHREAD_API /* musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin */
|
||||
|
||||
extern
|
||||
# if defined _WIN32 || defined __CYGWIN__
|
||||
__declspec(dllimport)
|
||||
# endif
|
||||
pthread_mutex_t *gl_get_setlocale_null_lock (void);
|
||||
|
||||
# if HAVE_WEAK_SYMBOLS /* musl libc, FreeBSD, NetBSD, OpenBSD, Haiku */
|
||||
|
||||
/* Avoid the need to link with '-lpthread'. */
|
||||
# pragma weak pthread_mutex_lock
|
||||
# pragma weak pthread_mutex_unlock
|
||||
|
||||
/* Determine whether libpthread is in use. */
|
||||
# pragma weak pthread_mutexattr_gettype
|
||||
/* See the comments in lock.h. */
|
||||
# define pthread_in_use() \
|
||||
(pthread_mutexattr_gettype != NULL || c11_threads_in_use ())
|
||||
|
||||
# else
|
||||
# define pthread_in_use() 1
|
||||
# endif
|
||||
|
||||
static int
|
||||
setlocale_null_with_lock (int category, char *buf, size_t bufsize)
|
||||
{
|
||||
if (pthread_in_use())
|
||||
{
|
||||
pthread_mutex_t *lock = gl_get_setlocale_null_lock ();
|
||||
int ret;
|
||||
|
||||
if (pthread_mutex_lock (lock))
|
||||
abort ();
|
||||
ret = setlocale_null_unlocked (category, buf, bufsize);
|
||||
if (pthread_mutex_unlock (lock))
|
||||
abort ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
return setlocale_null_unlocked (category, buf, bufsize);
|
||||
}
|
||||
|
||||
# elif HAVE_THREADS_H
|
||||
|
||||
extern mtx_t *gl_get_setlocale_null_lock (void);
|
||||
|
||||
static int
|
||||
setlocale_null_with_lock (int category, char *buf, size_t bufsize)
|
||||
{
|
||||
mtx_t *lock = gl_get_setlocale_null_lock ();
|
||||
int ret;
|
||||
|
||||
if (mtx_lock (lock) != thrd_success)
|
||||
abort ();
|
||||
ret = setlocale_null_unlocked (category, buf, bufsize);
|
||||
if (mtx_unlock (lock) != thrd_success)
|
||||
abort ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
setlocale_null_r (int category, char *buf, size_t bufsize)
|
||||
{
|
||||
#if SETLOCALE_NULL_ALL_MTSAFE
|
||||
# if SETLOCALE_NULL_ONE_MTSAFE
|
||||
|
||||
return setlocale_null_unlocked (category, buf, bufsize);
|
||||
|
||||
# else
|
||||
|
||||
if (category == LC_ALL)
|
||||
return setlocale_null_unlocked (category, buf, bufsize);
|
||||
else
|
||||
return setlocale_null_with_lock (category, buf, bufsize);
|
||||
|
||||
# endif
|
||||
#else
|
||||
# if SETLOCALE_NULL_ONE_MTSAFE
|
||||
|
||||
if (category == LC_ALL)
|
||||
return setlocale_null_with_lock (category, buf, bufsize);
|
||||
else
|
||||
return setlocale_null_unlocked (category, buf, bufsize);
|
||||
|
||||
# else
|
||||
|
||||
return setlocale_null_with_lock (category, buf, bufsize);
|
||||
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
const char *
|
||||
setlocale_null (int category)
|
||||
{
|
||||
#if SETLOCALE_NULL_ALL_MTSAFE && SETLOCALE_NULL_ONE_MTSAFE
|
||||
return setlocale_null_androidfix (category);
|
||||
#else
|
||||
|
||||
/* This call must be multithread-safe. To achieve this without using
|
||||
thread-local storage:
|
||||
1. We use a specific static buffer for each possible CATEGORY
|
||||
argument. So that different threads can call setlocale_mtsafe
|
||||
with different CATEGORY arguments, without interfering.
|
||||
2. We use a simple strcpy or memcpy to fill this static buffer.
|
||||
Filling it through, for example, strcpy + strcat would not be
|
||||
guaranteed to leave the buffer's contents intact if another thread
|
||||
is currently accessing it. If necessary, the contents is first
|
||||
assembled in a stack-allocated buffer. */
|
||||
if (category == LC_ALL)
|
||||
{
|
||||
# if SETLOCALE_NULL_ALL_MTSAFE
|
||||
return setlocale_null_androidfix (LC_ALL);
|
||||
# else
|
||||
char buf[SETLOCALE_NULL_ALL_MAX];
|
||||
static char resultbuf[SETLOCALE_NULL_ALL_MAX];
|
||||
|
||||
if (setlocale_null_r (LC_ALL, buf, sizeof (buf)))
|
||||
return "C";
|
||||
strcpy (resultbuf, buf);
|
||||
return resultbuf;
|
||||
# endif
|
||||
}
|
||||
else
|
||||
{
|
||||
# if SETLOCALE_NULL_ONE_MTSAFE
|
||||
return setlocale_null_androidfix (category);
|
||||
# else
|
||||
enum
|
||||
{
|
||||
LC_CTYPE_INDEX,
|
||||
LC_NUMERIC_INDEX,
|
||||
LC_TIME_INDEX,
|
||||
LC_COLLATE_INDEX,
|
||||
LC_MONETARY_INDEX,
|
||||
LC_MESSAGES_INDEX,
|
||||
# ifdef LC_PAPER
|
||||
LC_PAPER_INDEX,
|
||||
# endif
|
||||
# ifdef LC_NAME
|
||||
LC_NAME_INDEX,
|
||||
# endif
|
||||
# ifdef LC_ADDRESS
|
||||
LC_ADDRESS_INDEX,
|
||||
# endif
|
||||
# ifdef LC_TELEPHONE
|
||||
LC_TELEPHONE_INDEX,
|
||||
# endif
|
||||
# ifdef LC_MEASUREMENT
|
||||
LC_MEASUREMENT_INDEX,
|
||||
# endif
|
||||
# ifdef LC_IDENTIFICATION
|
||||
LC_IDENTIFICATION_INDEX,
|
||||
# endif
|
||||
LC_INDICES_COUNT
|
||||
}
|
||||
i;
|
||||
char buf[SETLOCALE_NULL_MAX];
|
||||
static char resultbuf[LC_INDICES_COUNT][SETLOCALE_NULL_MAX];
|
||||
int err;
|
||||
|
||||
err = setlocale_null_r (category, buf, sizeof (buf));
|
||||
if (err == EINVAL)
|
||||
return NULL;
|
||||
if (err)
|
||||
return "C";
|
||||
|
||||
switch (category)
|
||||
{
|
||||
case LC_CTYPE: i = LC_CTYPE_INDEX; break;
|
||||
case LC_NUMERIC: i = LC_NUMERIC_INDEX; break;
|
||||
case LC_TIME: i = LC_TIME_INDEX; break;
|
||||
case LC_COLLATE: i = LC_COLLATE_INDEX; break;
|
||||
case LC_MONETARY: i = LC_MONETARY_INDEX; break;
|
||||
case LC_MESSAGES: i = LC_MESSAGES_INDEX; break;
|
||||
# ifdef LC_PAPER
|
||||
case LC_PAPER: i = LC_PAPER_INDEX; break;
|
||||
# endif
|
||||
# ifdef LC_NAME
|
||||
case LC_NAME: i = LC_NAME_INDEX; break;
|
||||
# endif
|
||||
# ifdef LC_ADDRESS
|
||||
case LC_ADDRESS: i = LC_ADDRESS_INDEX; break;
|
||||
# endif
|
||||
# ifdef LC_TELEPHONE
|
||||
case LC_TELEPHONE: i = LC_TELEPHONE_INDEX; break;
|
||||
# endif
|
||||
# ifdef LC_MEASUREMENT
|
||||
case LC_MEASUREMENT: i = LC_MEASUREMENT_INDEX; break;
|
||||
# endif
|
||||
# ifdef LC_IDENTIFICATION
|
||||
case LC_IDENTIFICATION: i = LC_IDENTIFICATION_INDEX; break;
|
||||
# endif
|
||||
default:
|
||||
/* If you get here, a #ifdef LC_xxx is missing. */
|
||||
abort ();
|
||||
}
|
||||
|
||||
strcpy (resultbuf[i], buf);
|
||||
return resultbuf[i];
|
||||
# endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/* Query the name of the current global locale.
|
||||
Copyright (C) 2019 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Bruno Haible <bruno@clisp.org>, 2019. */
|
||||
|
||||
#ifndef _SETLOCALE_NULL_H
|
||||
#define _SETLOCALE_NULL_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "arg-nonnull.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/* Recommended size of a buffer for a locale name for a single category.
|
||||
On glibc systems, you can have locale names that are relative file names;
|
||||
assume a maximum length 256.
|
||||
In native Windows, in 2018 the longest locale name was of length 58
|
||||
("FYRO Macedonian_Former Yugoslav Republic of Macedonia.1251"). */
|
||||
#define SETLOCALE_NULL_MAX (256+1)
|
||||
|
||||
/* Recommended size of a buffer for a locale name with all categories.
|
||||
On glibc systems, you can have locale names that are relative file names;
|
||||
assume maximum length 256 for each. There are 12 categories; so, the
|
||||
maximum total length is 148+12*256.
|
||||
In native Windows, there are 5 categories, and the maximum total length is
|
||||
55+5*58. */
|
||||
#define SETLOCALE_NULL_ALL_MAX (148+12*256+1)
|
||||
|
||||
/* setlocale_null_r (CATEGORY, BUF, BUFSIZE) is like setlocale (CATEGORY, NULL),
|
||||
except that
|
||||
- it is guaranteed to be multithread-safe,
|
||||
- it returns the resulting locale category name or locale name in the
|
||||
user-supplied buffer BUF, which must be BUFSIZE bytes long.
|
||||
The recommended minimum buffer size is
|
||||
- SETLOCALE_NULL_MAX for CATEGORY != LC_ALL, and
|
||||
- SETLOCALE_NULL_ALL_MAX for CATEGORY == LC_ALL.
|
||||
The return value is an error code: 0 if the call is successful, EINVAL if
|
||||
CATEGORY is invalid, or ERANGE if BUFSIZE is smaller than the length needed
|
||||
size (including the trailing NUL byte). In the latter case, a truncated
|
||||
result is returned in BUF, but still NUL-terminated if BUFSIZE > 0.
|
||||
For this call to be multithread-safe, *all* calls to
|
||||
setlocale (CATEGORY, NULL) in all other threads must have been converted
|
||||
to use setlocale_null_r or setlocale_null as well, and the other threads
|
||||
must not make other setlocale invocations (since changing the global locale
|
||||
has side effects on all threads). */
|
||||
extern int setlocale_null_r (int category, char *buf, size_t bufsize)
|
||||
_GL_ARG_NONNULL ((2));
|
||||
|
||||
/* setlocale_null (CATEGORY) is like setlocale (CATEGORY, NULL), except that
|
||||
it is guaranteed to be multithread-safe.
|
||||
The return value is NULL if CATEGORY is invalid.
|
||||
For this call to be multithread-safe, *all* calls to
|
||||
setlocale (CATEGORY, NULL) in all other threads must have been converted
|
||||
to use setlocale_null_r or setlocale_null as well, and the other threads
|
||||
must not make other setlocale invocations (since changing the global locale
|
||||
has side effects on all threads). */
|
||||
extern const char *setlocale_null (int category);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SETLOCALE_NULL_H */
|
||||
@@ -0,0 +1,60 @@
|
||||
/* Optimization of multithreaded code.
|
||||
|
||||
Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Bruno Haible <bruno@clisp.org>, 2020. */
|
||||
|
||||
#ifndef _THREAD_OPTIM_H
|
||||
#define _THREAD_OPTIM_H
|
||||
|
||||
/* This file defines a way to optimize multithreaded code for the single-thread
|
||||
case, based on the variable '__libc_single_threaded', defined in
|
||||
glibc >= 2.32. */
|
||||
|
||||
/* Typical use: In a block or function, use
|
||||
|
||||
bool mt = gl_multithreaded ();
|
||||
...
|
||||
if (mt)
|
||||
if (pthread_mutex_lock (&lock)) abort ();
|
||||
...
|
||||
if (mt)
|
||||
if (pthread_mutex_unlock (&lock)) abort ();
|
||||
|
||||
The gl_multithreaded () invocation determines whether the program currently
|
||||
is multithreaded.
|
||||
|
||||
if (mt) STATEMENT executes STATEMENT in the multithreaded case, and skips
|
||||
it in the single-threaded case.
|
||||
|
||||
The code between the gl_multithreaded () invocation and any use of the
|
||||
variable 'mt' must not create threads or invoke functions that may
|
||||
indirectly create threads (e.g. 'dlopen' may, indirectly through C++
|
||||
initializers of global variables in the shared library being opened,
|
||||
create threads).
|
||||
|
||||
The lock here is meant to synchronize threads in the same process. The
|
||||
same optimization cannot be applied to locks that synchronize different
|
||||
processes (e.g. through shared memory mappings). */
|
||||
|
||||
#if HAVE_SYS_SINGLE_THREADED_H /* glibc >= 2.32 */
|
||||
# include <sys/single_threaded.h>
|
||||
# define gl_multithreaded() !__libc_single_threaded
|
||||
#else
|
||||
# define gl_multithreaded() 1
|
||||
#endif
|
||||
|
||||
#endif /* _THREAD_OPTIM_H */
|
||||
@@ -0,0 +1,108 @@
|
||||
/* Multithreading primitives.
|
||||
Copyright (C) 2005-2022 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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 Bruno Haible <bruno@clisp.org>, 2005. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
#if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS
|
||||
|
||||
/* Use the POSIX threads library. */
|
||||
|
||||
# include <errno.h>
|
||||
# include <pthread.h>
|
||||
# include <stdlib.h>
|
||||
|
||||
# if PTHREAD_IN_USE_DETECTION_HARD
|
||||
|
||||
# if defined __FreeBSD__ || defined __DragonFly__ /* FreeBSD */
|
||||
|
||||
/* Test using pthread_key_create. */
|
||||
|
||||
int
|
||||
glthread_in_use (void)
|
||||
{
|
||||
static int tested;
|
||||
static int result; /* 1: linked with -lpthread, 0: only with libc */
|
||||
|
||||
if (!tested)
|
||||
{
|
||||
pthread_key_t key;
|
||||
int err = pthread_key_create (&key, NULL);
|
||||
|
||||
if (err == ENOSYS)
|
||||
result = 0;
|
||||
else
|
||||
{
|
||||
result = 1;
|
||||
if (err == 0)
|
||||
pthread_key_delete (key);
|
||||
}
|
||||
tested = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
# else /* Solaris, HP-UX */
|
||||
|
||||
/* Test using pthread_create. */
|
||||
|
||||
/* The function to be executed by a dummy thread. */
|
||||
static void *
|
||||
dummy_thread_func (void *arg)
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
|
||||
int
|
||||
glthread_in_use (void)
|
||||
{
|
||||
static int tested;
|
||||
static int result; /* 1: linked with -lpthread, 0: only with libc */
|
||||
|
||||
if (!tested)
|
||||
{
|
||||
pthread_t thread;
|
||||
|
||||
if (pthread_create (&thread, NULL, dummy_thread_func, NULL) != 0)
|
||||
/* Thread creation failed. */
|
||||
result = 0;
|
||||
else
|
||||
{
|
||||
/* Thread creation works. */
|
||||
void *retval;
|
||||
if (pthread_join (thread, &retval) != 0)
|
||||
abort ();
|
||||
result = 1;
|
||||
}
|
||||
tested = 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/* ========================================================================= */
|
||||
|
||||
/* This declaration is solely to ensure that after preprocessing
|
||||
this file is never empty. */
|
||||
typedef int dummy;
|
||||
@@ -0,0 +1,682 @@
|
||||
/* Copyright (C) 1995-1997, 2000, 2006 Free Software Foundation, Inc.
|
||||
Contributed by Bernd Schmidt <crux@Pool.Informatik.RWTH-Aachen.DE>, 1997.
|
||||
|
||||
NOTE: The canonical source of this file is maintained with the GNU C
|
||||
Library. Bugs can be reported to bug-glibc@gnu.org.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
/* Tree search for red/black trees.
|
||||
The algorithm for adding nodes is taken from one of the many "Algorithms"
|
||||
books by Robert Sedgewick, although the implementation differs.
|
||||
The algorithm for deleting nodes can probably be found in a book named
|
||||
"Introduction to Algorithms" by Cormen/Leiserson/Rivest. At least that's
|
||||
the book that my professor took most algorithms from during the "Data
|
||||
Structures" course...
|
||||
|
||||
Totally public domain. */
|
||||
|
||||
/* Red/black trees are binary trees in which the edges are colored either red
|
||||
or black. They have the following properties:
|
||||
1. The number of black edges on every path from the root to a leaf is
|
||||
constant.
|
||||
2. No two red edges are adjacent.
|
||||
Therefore there is an upper bound on the length of every path, it's
|
||||
O(log n) where n is the number of nodes in the tree. No path can be longer
|
||||
than 1+2*P where P is the length of the shortest path in the tree.
|
||||
Useful for the implementation:
|
||||
3. If one of the children of a node is NULL, then the other one is red
|
||||
(if it exists).
|
||||
|
||||
In the implementation, not the edges are colored, but the nodes. The color
|
||||
interpreted as the color of the edge leading to this node. The color is
|
||||
meaningless for the root node, but we color the root node black for
|
||||
convenience. All added nodes are red initially.
|
||||
|
||||
Adding to a red/black tree is rather easy. The right place is searched
|
||||
with a usual binary tree search. Additionally, whenever a node N is
|
||||
reached that has two red successors, the successors are colored black and
|
||||
the node itself colored red. This moves red edges up the tree where they
|
||||
pose less of a problem once we get to really insert the new node. Changing
|
||||
N's color to red may violate rule 2, however, so rotations may become
|
||||
necessary to restore the invariants. Adding a new red leaf may violate
|
||||
the same rule, so afterwards an additional check is run and the tree
|
||||
possibly rotated.
|
||||
|
||||
Deleting is hairy. There are mainly two nodes involved: the node to be
|
||||
deleted (n1), and another node that is to be unchained from the tree (n2).
|
||||
If n1 has a successor (the node with a smallest key that is larger than
|
||||
n1), then the successor becomes n2 and its contents are copied into n1,
|
||||
otherwise n1 becomes n2.
|
||||
Unchaining a node may violate rule 1: if n2 is black, one subtree is
|
||||
missing one black edge afterwards. The algorithm must try to move this
|
||||
error upwards towards the root, so that the subtree that does not have
|
||||
enough black edges becomes the whole tree. Once that happens, the error
|
||||
has disappeared. It may not be necessary to go all the way up, since it
|
||||
is possible that rotations and recoloring can fix the error before that.
|
||||
|
||||
Although the deletion algorithm must walk upwards through the tree, we
|
||||
do not store parent pointers in the nodes. Instead, delete allocates a
|
||||
small array of parent pointers and fills it while descending the tree.
|
||||
Since we know that the length of a path is O(log n), where n is the number
|
||||
of nodes, this is likely to use less memory. */
|
||||
|
||||
/* Tree rotations look like this:
|
||||
A C
|
||||
/ \ / \
|
||||
B C A G
|
||||
/ \ / \ --> / \
|
||||
D E F G B F
|
||||
/ \
|
||||
D E
|
||||
|
||||
In this case, A has been rotated left. This preserves the ordering of the
|
||||
binary tree. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Specification. */
|
||||
#ifdef IN_LIBINTL
|
||||
# include "tsearch.h"
|
||||
#else
|
||||
# include <search.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef int (*__compar_fn_t) (const void *, const void *);
|
||||
typedef void (*__action_fn_t) (const void *, VISIT, int);
|
||||
|
||||
#ifndef weak_alias
|
||||
# define __tsearch tsearch
|
||||
# define __tfind tfind
|
||||
# define __tdelete tdelete
|
||||
# define __twalk twalk
|
||||
#endif
|
||||
|
||||
#ifndef internal_function
|
||||
/* Inside GNU libc we mark some function in a special way. In other
|
||||
environments simply ignore the marking. */
|
||||
# define internal_function
|
||||
#endif
|
||||
|
||||
typedef struct node_t
|
||||
{
|
||||
/* Callers expect this to be the first element in the structure - do not
|
||||
move! */
|
||||
const void *key;
|
||||
struct node_t *left;
|
||||
struct node_t *right;
|
||||
unsigned int red:1;
|
||||
} *node;
|
||||
typedef const struct node_t *const_node;
|
||||
|
||||
#undef DEBUGGING
|
||||
|
||||
#ifdef DEBUGGING
|
||||
|
||||
/* Routines to check tree invariants. */
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define CHECK_TREE(a) check_tree(a)
|
||||
|
||||
static void
|
||||
check_tree_recurse (node p, int d_sofar, int d_total)
|
||||
{
|
||||
if (p == NULL)
|
||||
{
|
||||
assert (d_sofar == d_total);
|
||||
return;
|
||||
}
|
||||
|
||||
check_tree_recurse (p->left, d_sofar + (p->left && !p->left->red), d_total);
|
||||
check_tree_recurse (p->right, d_sofar + (p->right && !p->right->red), d_total);
|
||||
if (p->left)
|
||||
assert (!(p->left->red && p->red));
|
||||
if (p->right)
|
||||
assert (!(p->right->red && p->red));
|
||||
}
|
||||
|
||||
static void
|
||||
check_tree (node root)
|
||||
{
|
||||
int cnt = 0;
|
||||
node p;
|
||||
if (root == NULL)
|
||||
return;
|
||||
root->red = 0;
|
||||
for(p = root->left; p; p = p->left)
|
||||
cnt += !p->red;
|
||||
check_tree_recurse (root, 0, cnt);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define CHECK_TREE(a)
|
||||
|
||||
#endif
|
||||
|
||||
/* Possibly "split" a node with two red successors, and/or fix up two red
|
||||
edges in a row. ROOTP is a pointer to the lowest node we visited, PARENTP
|
||||
and GPARENTP pointers to its parent/grandparent. P_R and GP_R contain the
|
||||
comparison values that determined which way was taken in the tree to reach
|
||||
ROOTP. MODE is 1 if we need not do the split, but must check for two red
|
||||
edges between GPARENTP and ROOTP. */
|
||||
static void
|
||||
maybe_split_for_insert (node *rootp, node *parentp, node *gparentp,
|
||||
int p_r, int gp_r, int mode)
|
||||
{
|
||||
node root = *rootp;
|
||||
node *rp, *lp;
|
||||
rp = &(*rootp)->right;
|
||||
lp = &(*rootp)->left;
|
||||
|
||||
/* See if we have to split this node (both successors red). */
|
||||
if (mode == 1
|
||||
|| ((*rp) != NULL && (*lp) != NULL && (*rp)->red && (*lp)->red))
|
||||
{
|
||||
/* This node becomes red, its successors black. */
|
||||
root->red = 1;
|
||||
if (*rp)
|
||||
(*rp)->red = 0;
|
||||
if (*lp)
|
||||
(*lp)->red = 0;
|
||||
|
||||
/* If the parent of this node is also red, we have to do
|
||||
rotations. */
|
||||
if (parentp != NULL && (*parentp)->red)
|
||||
{
|
||||
node gp = *gparentp;
|
||||
node p = *parentp;
|
||||
/* There are two main cases:
|
||||
1. The edge types (left or right) of the two red edges differ.
|
||||
2. Both red edges are of the same type.
|
||||
There exist two symmetries of each case, so there is a total of
|
||||
4 cases. */
|
||||
if ((p_r > 0) != (gp_r > 0))
|
||||
{
|
||||
/* Put the child at the top of the tree, with its parent
|
||||
and grandparent as successors. */
|
||||
p->red = 1;
|
||||
gp->red = 1;
|
||||
root->red = 0;
|
||||
if (p_r < 0)
|
||||
{
|
||||
/* Child is left of parent. */
|
||||
p->left = *rp;
|
||||
*rp = p;
|
||||
gp->right = *lp;
|
||||
*lp = gp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Child is right of parent. */
|
||||
p->right = *lp;
|
||||
*lp = p;
|
||||
gp->left = *rp;
|
||||
*rp = gp;
|
||||
}
|
||||
*gparentp = root;
|
||||
}
|
||||
else
|
||||
{
|
||||
*gparentp = *parentp;
|
||||
/* Parent becomes the top of the tree, grandparent and
|
||||
child are its successors. */
|
||||
p->red = 0;
|
||||
gp->red = 1;
|
||||
if (p_r < 0)
|
||||
{
|
||||
/* Left edges. */
|
||||
gp->left = p->right;
|
||||
p->right = gp;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Right edges. */
|
||||
gp->right = p->left;
|
||||
p->left = gp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Find or insert datum into search tree.
|
||||
KEY is the key to be located, ROOTP is the address of tree root,
|
||||
COMPAR the ordering function. */
|
||||
void *
|
||||
__tsearch (const void *key, void **vrootp, __compar_fn_t compar)
|
||||
{
|
||||
node q;
|
||||
node *parentp = NULL, *gparentp = NULL;
|
||||
node *rootp = (node *) vrootp;
|
||||
node *nextp;
|
||||
int r = 0, p_r = 0, gp_r = 0; /* No they might not, Mr Compiler. */
|
||||
|
||||
if (rootp == NULL)
|
||||
return NULL;
|
||||
|
||||
/* This saves some additional tests below. */
|
||||
if (*rootp != NULL)
|
||||
(*rootp)->red = 0;
|
||||
|
||||
CHECK_TREE (*rootp);
|
||||
|
||||
nextp = rootp;
|
||||
while (*nextp != NULL)
|
||||
{
|
||||
node root = *rootp;
|
||||
r = (*compar) (key, root->key);
|
||||
if (r == 0)
|
||||
return root;
|
||||
|
||||
maybe_split_for_insert (rootp, parentp, gparentp, p_r, gp_r, 0);
|
||||
/* If that did any rotations, parentp and gparentp are now garbage.
|
||||
That doesn't matter, because the values they contain are never
|
||||
used again in that case. */
|
||||
|
||||
nextp = r < 0 ? &root->left : &root->right;
|
||||
if (*nextp == NULL)
|
||||
break;
|
||||
|
||||
gparentp = parentp;
|
||||
parentp = rootp;
|
||||
rootp = nextp;
|
||||
|
||||
gp_r = p_r;
|
||||
p_r = r;
|
||||
}
|
||||
|
||||
q = (struct node_t *) malloc (sizeof (struct node_t));
|
||||
if (q != NULL)
|
||||
{
|
||||
*nextp = q; /* link new node to old */
|
||||
q->key = key; /* initialize new node */
|
||||
q->red = 1;
|
||||
q->left = q->right = NULL;
|
||||
|
||||
if (nextp != rootp)
|
||||
/* There may be two red edges in a row now, which we must avoid by
|
||||
rotating the tree. */
|
||||
maybe_split_for_insert (nextp, rootp, parentp, r, p_r, 1);
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
#ifdef weak_alias
|
||||
weak_alias (__tsearch, tsearch)
|
||||
#endif
|
||||
|
||||
|
||||
/* Find datum in search tree.
|
||||
KEY is the key to be located, ROOTP is the address of tree root,
|
||||
COMPAR the ordering function. */
|
||||
void *
|
||||
__tfind (key, vrootp, compar)
|
||||
const void *key;
|
||||
void *const *vrootp;
|
||||
__compar_fn_t compar;
|
||||
{
|
||||
node *rootp = (node *) vrootp;
|
||||
|
||||
if (rootp == NULL)
|
||||
return NULL;
|
||||
|
||||
CHECK_TREE (*rootp);
|
||||
|
||||
while (*rootp != NULL)
|
||||
{
|
||||
node root = *rootp;
|
||||
int r;
|
||||
|
||||
r = (*compar) (key, root->key);
|
||||
if (r == 0)
|
||||
return root;
|
||||
|
||||
rootp = r < 0 ? &root->left : &root->right;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#ifdef weak_alias
|
||||
weak_alias (__tfind, tfind)
|
||||
#endif
|
||||
|
||||
|
||||
/* Delete node with given key.
|
||||
KEY is the key to be deleted, ROOTP is the address of the root of tree,
|
||||
COMPAR the comparison function. */
|
||||
void *
|
||||
__tdelete (const void *key, void **vrootp, __compar_fn_t compar)
|
||||
{
|
||||
node p, q, r, retval;
|
||||
int cmp;
|
||||
node *rootp = (node *) vrootp;
|
||||
node root, unchained;
|
||||
/* Stack of nodes so we remember the parents without recursion. It's
|
||||
_very_ unlikely that there are paths longer than 40 nodes. The tree
|
||||
would need to have around 250.000 nodes. */
|
||||
int stacksize = 100;
|
||||
int sp = 0;
|
||||
node *nodestack[100];
|
||||
|
||||
if (rootp == NULL)
|
||||
return NULL;
|
||||
p = *rootp;
|
||||
if (p == NULL)
|
||||
return NULL;
|
||||
|
||||
CHECK_TREE (p);
|
||||
|
||||
while ((cmp = (*compar) (key, (*rootp)->key)) != 0)
|
||||
{
|
||||
if (sp == stacksize)
|
||||
abort ();
|
||||
|
||||
nodestack[sp++] = rootp;
|
||||
p = *rootp;
|
||||
rootp = ((cmp < 0)
|
||||
? &(*rootp)->left
|
||||
: &(*rootp)->right);
|
||||
if (*rootp == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This is bogus if the node to be deleted is the root... this routine
|
||||
really should return an integer with 0 for success, -1 for failure
|
||||
and errno = ESRCH or something. */
|
||||
retval = p;
|
||||
|
||||
/* We don't unchain the node we want to delete. Instead, we overwrite
|
||||
it with its successor and unchain the successor. If there is no
|
||||
successor, we really unchain the node to be deleted. */
|
||||
|
||||
root = *rootp;
|
||||
|
||||
r = root->right;
|
||||
q = root->left;
|
||||
|
||||
if (q == NULL || r == NULL)
|
||||
unchained = root;
|
||||
else
|
||||
{
|
||||
node *parent = rootp, *up = &root->right;
|
||||
for (;;)
|
||||
{
|
||||
if (sp == stacksize)
|
||||
abort ();
|
||||
nodestack[sp++] = parent;
|
||||
parent = up;
|
||||
if ((*up)->left == NULL)
|
||||
break;
|
||||
up = &(*up)->left;
|
||||
}
|
||||
unchained = *up;
|
||||
}
|
||||
|
||||
/* We know that either the left or right successor of UNCHAINED is NULL.
|
||||
R becomes the other one, it is chained into the parent of UNCHAINED. */
|
||||
r = unchained->left;
|
||||
if (r == NULL)
|
||||
r = unchained->right;
|
||||
if (sp == 0)
|
||||
*rootp = r;
|
||||
else
|
||||
{
|
||||
q = *nodestack[sp-1];
|
||||
if (unchained == q->right)
|
||||
q->right = r;
|
||||
else
|
||||
q->left = r;
|
||||
}
|
||||
|
||||
if (unchained != root)
|
||||
root->key = unchained->key;
|
||||
if (!unchained->red)
|
||||
{
|
||||
/* Now we lost a black edge, which means that the number of black
|
||||
edges on every path is no longer constant. We must balance the
|
||||
tree. */
|
||||
/* NODESTACK now contains all parents of R. R is likely to be NULL
|
||||
in the first iteration. */
|
||||
/* NULL nodes are considered black throughout - this is necessary for
|
||||
correctness. */
|
||||
while (sp > 0 && (r == NULL || !r->red))
|
||||
{
|
||||
node *pp = nodestack[sp - 1];
|
||||
p = *pp;
|
||||
/* Two symmetric cases. */
|
||||
if (r == p->left)
|
||||
{
|
||||
/* Q is R's brother, P is R's parent. The subtree with root
|
||||
R has one black edge less than the subtree with root Q. */
|
||||
q = p->right;
|
||||
if (q->red)
|
||||
{
|
||||
/* If Q is red, we know that P is black. We rotate P left
|
||||
so that Q becomes the top node in the tree, with P below
|
||||
it. P is colored red, Q is colored black.
|
||||
This action does not change the black edge count for any
|
||||
leaf in the tree, but we will be able to recognize one
|
||||
of the following situations, which all require that Q
|
||||
is black. */
|
||||
q->red = 0;
|
||||
p->red = 1;
|
||||
/* Left rotate p. */
|
||||
p->right = q->left;
|
||||
q->left = p;
|
||||
*pp = q;
|
||||
/* Make sure pp is right if the case below tries to use
|
||||
it. */
|
||||
nodestack[sp++] = pp = &q->left;
|
||||
q = p->right;
|
||||
}
|
||||
/* We know that Q can't be NULL here. We also know that Q is
|
||||
black. */
|
||||
if ((q->left == NULL || !q->left->red)
|
||||
&& (q->right == NULL || !q->right->red))
|
||||
{
|
||||
/* Q has two black successors. We can simply color Q red.
|
||||
The whole subtree with root P is now missing one black
|
||||
edge. Note that this action can temporarily make the
|
||||
tree invalid (if P is red). But we will exit the loop
|
||||
in that case and set P black, which both makes the tree
|
||||
valid and also makes the black edge count come out
|
||||
right. If P is black, we are at least one step closer
|
||||
to the root and we'll try again the next iteration. */
|
||||
q->red = 1;
|
||||
r = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Q is black, one of Q's successors is red. We can
|
||||
repair the tree with one operation and will exit the
|
||||
loop afterwards. */
|
||||
if (q->right == NULL || !q->right->red)
|
||||
{
|
||||
/* The left one is red. We perform the same action as
|
||||
in maybe_split_for_insert where two red edges are
|
||||
adjacent but point in different directions:
|
||||
Q's left successor (let's call it Q2) becomes the
|
||||
top of the subtree we are looking at, its parent (Q)
|
||||
and grandparent (P) become its successors. The former
|
||||
successors of Q2 are placed below P and Q.
|
||||
P becomes black, and Q2 gets the color that P had.
|
||||
This changes the black edge count only for node R and
|
||||
its successors. */
|
||||
node q2 = q->left;
|
||||
q2->red = p->red;
|
||||
p->right = q2->left;
|
||||
q->left = q2->right;
|
||||
q2->right = q;
|
||||
q2->left = p;
|
||||
*pp = q2;
|
||||
p->red = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* It's the right one. Rotate P left. P becomes black,
|
||||
and Q gets the color that P had. Q's right successor
|
||||
also becomes black. This changes the black edge
|
||||
count only for node R and its successors. */
|
||||
q->red = p->red;
|
||||
p->red = 0;
|
||||
|
||||
q->right->red = 0;
|
||||
|
||||
/* left rotate p */
|
||||
p->right = q->left;
|
||||
q->left = p;
|
||||
*pp = q;
|
||||
}
|
||||
|
||||
/* We're done. */
|
||||
sp = 1;
|
||||
r = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Comments: see above. */
|
||||
q = p->left;
|
||||
if (q->red)
|
||||
{
|
||||
q->red = 0;
|
||||
p->red = 1;
|
||||
p->left = q->right;
|
||||
q->right = p;
|
||||
*pp = q;
|
||||
nodestack[sp++] = pp = &q->right;
|
||||
q = p->left;
|
||||
}
|
||||
if ((q->right == NULL || !q->right->red)
|
||||
&& (q->left == NULL || !q->left->red))
|
||||
{
|
||||
q->red = 1;
|
||||
r = p;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (q->left == NULL || !q->left->red)
|
||||
{
|
||||
node q2 = q->right;
|
||||
q2->red = p->red;
|
||||
p->left = q2->right;
|
||||
q->right = q2->left;
|
||||
q2->left = q;
|
||||
q2->right = p;
|
||||
*pp = q2;
|
||||
p->red = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
q->red = p->red;
|
||||
p->red = 0;
|
||||
q->left->red = 0;
|
||||
p->left = q->right;
|
||||
q->right = p;
|
||||
*pp = q;
|
||||
}
|
||||
sp = 1;
|
||||
r = NULL;
|
||||
}
|
||||
}
|
||||
--sp;
|
||||
}
|
||||
if (r != NULL)
|
||||
r->red = 0;
|
||||
}
|
||||
|
||||
free (unchained);
|
||||
return retval;
|
||||
}
|
||||
#ifdef weak_alias
|
||||
weak_alias (__tdelete, tdelete)
|
||||
#endif
|
||||
|
||||
|
||||
/* Walk the nodes of a tree.
|
||||
ROOT is the root of the tree to be walked, ACTION the function to be
|
||||
called at each node. LEVEL is the level of ROOT in the whole tree. */
|
||||
static void
|
||||
internal_function
|
||||
trecurse (const void *vroot, __action_fn_t action, int level)
|
||||
{
|
||||
const_node root = (const_node) vroot;
|
||||
|
||||
if (root->left == NULL && root->right == NULL)
|
||||
(*action) (root, leaf, level);
|
||||
else
|
||||
{
|
||||
(*action) (root, preorder, level);
|
||||
if (root->left != NULL)
|
||||
trecurse (root->left, action, level + 1);
|
||||
(*action) (root, postorder, level);
|
||||
if (root->right != NULL)
|
||||
trecurse (root->right, action, level + 1);
|
||||
(*action) (root, endorder, level);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Walk the nodes of a tree.
|
||||
ROOT is the root of the tree to be walked, ACTION the function to be
|
||||
called at each node. */
|
||||
void
|
||||
__twalk (const void *vroot, __action_fn_t action)
|
||||
{
|
||||
const_node root = (const_node) vroot;
|
||||
|
||||
CHECK_TREE (root);
|
||||
|
||||
if (root != NULL && action != NULL)
|
||||
trecurse (root, action, 0);
|
||||
}
|
||||
#ifdef weak_alias
|
||||
weak_alias (__twalk, twalk)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _LIBC
|
||||
|
||||
/* The standardized functions miss an important functionality: the
|
||||
tree cannot be removed easily. We provide a function to do this. */
|
||||
static void
|
||||
internal_function
|
||||
tdestroy_recurse (node root, __free_fn_t freefct)
|
||||
{
|
||||
if (root->left != NULL)
|
||||
tdestroy_recurse (root->left, freefct);
|
||||
if (root->right != NULL)
|
||||
tdestroy_recurse (root->right, freefct);
|
||||
(*freefct) ((void *) root->key);
|
||||
/* Free the node itself. */
|
||||
free (root);
|
||||
}
|
||||
|
||||
void
|
||||
__tdestroy (void *vroot, __free_fn_t freefct)
|
||||
{
|
||||
node root = (node) vroot;
|
||||
|
||||
CHECK_TREE (root);
|
||||
|
||||
if (root != NULL)
|
||||
tdestroy_recurse (root, freefct);
|
||||
}
|
||||
weak_alias (__tdestroy, tdestroy)
|
||||
|
||||
#endif /* _LIBC */
|
||||
@@ -0,0 +1,81 @@
|
||||
/* Binary tree data structure.
|
||||
Copyright (C) 2006 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
#ifndef _TSEARCH_H
|
||||
#define _TSEARCH_H
|
||||
|
||||
#if HAVE_TSEARCH
|
||||
|
||||
/* Get tseach(), tfind(), tdelete(), twalk() declarations. */
|
||||
#include <search.h>
|
||||
|
||||
#else
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* See <http://www.opengroup.org/susv3xbd/search.h.html>,
|
||||
<http://www.opengroup.org/susv3xsh/tsearch.html>
|
||||
for details. */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
preorder,
|
||||
postorder,
|
||||
endorder,
|
||||
leaf
|
||||
}
|
||||
VISIT;
|
||||
|
||||
/* Searches an element in the tree *VROOTP that compares equal to KEY.
|
||||
If one is found, it is returned. Otherwise, a new element equal to KEY
|
||||
is inserted in the tree and is returned. */
|
||||
extern void * tsearch (const void *key, void **vrootp,
|
||||
int (*compar) (const void *, const void *));
|
||||
|
||||
/* Searches an element in the tree *VROOTP that compares equal to KEY.
|
||||
If one is found, it is returned. Otherwise, NULL is returned. */
|
||||
extern void * tfind (const void *key, void *const *vrootp,
|
||||
int (*compar) (const void *, const void *));
|
||||
|
||||
/* Searches an element in the tree *VROOTP that compares equal to KEY.
|
||||
If one is found, it is removed from the tree, and its parent node is
|
||||
returned. Otherwise, NULL is returned. */
|
||||
extern void * tdelete (const void *key, void **vrootp,
|
||||
int (*compar) (const void *, const void *));
|
||||
|
||||
/* Perform a depth-first, left-to-right traversal of the tree VROOT.
|
||||
The ACTION function is called:
|
||||
- for non-leaf nodes: 3 times, before the left subtree traversal,
|
||||
after the left subtree traversal but before the right subtree traversal,
|
||||
and after the right subtree traversal,
|
||||
- for leaf nodes: once.
|
||||
The arguments passed to ACTION are:
|
||||
1. the node; it can be casted to a 'const void * const *', i.e. into a
|
||||
pointer to the key,
|
||||
2. an indicator which visit of the node this is,
|
||||
3. the level of the node in the tree (0 for the root). */
|
||||
extern void twalk (const void *vroot,
|
||||
void (*action) (const void *, VISIT, int));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _TSEARCH_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
||||
/* vsprintf with automatic memory allocation.
|
||||
Copyright (C) 2002-2004, 2012 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
#ifndef _VASNPRINTF_H
|
||||
#define _VASNPRINTF_H
|
||||
|
||||
/* Get va_list. */
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Get size_t. */
|
||||
#include <stddef.h>
|
||||
|
||||
#ifndef __attribute__
|
||||
/* This feature is available in gcc versions 2.5 and later. */
|
||||
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
|
||||
# define __attribute__(Spec) /* empty */
|
||||
# endif
|
||||
/* The __-protected variants of 'format' and 'printf' attributes
|
||||
are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
|
||||
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
|
||||
# define __format__ format
|
||||
# define __printf__ printf
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Write formatted output to a string dynamically allocated with malloc().
|
||||
You can pass a preallocated buffer for the result in RESULTBUF and its
|
||||
size in *LENGTHP; otherwise you pass RESULTBUF = NULL.
|
||||
If successful, return the address of the string (this may be = RESULTBUF
|
||||
if no dynamic memory allocation was necessary) and set *LENGTHP to the
|
||||
number of resulting bytes, excluding the trailing NUL. Upon error, set
|
||||
errno and return NULL.
|
||||
|
||||
When dynamic memory allocation occurs, the preallocated buffer is left
|
||||
alone (with possibly modified contents). This makes it possible to use
|
||||
a statically allocated or stack-allocated buffer, like this:
|
||||
|
||||
char buf[100];
|
||||
size_t len = sizeof (buf);
|
||||
char *output = vasnprintf (buf, &len, format, args);
|
||||
if (output == NULL)
|
||||
... error handling ...;
|
||||
else
|
||||
{
|
||||
... use the output string ...;
|
||||
if (output != buf)
|
||||
free (output);
|
||||
}
|
||||
*/
|
||||
extern char * asnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
|
||||
__attribute__ ((__format__ (__printf__, 3, 4)));
|
||||
extern char * vasnprintf (char *resultbuf, size_t *lengthp, const char *format, va_list args)
|
||||
__attribute__ ((__format__ (__printf__, 3, 0)));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _VASNPRINTF_H */
|
||||
@@ -0,0 +1,44 @@
|
||||
/* vswprintf with automatic memory allocation.
|
||||
Copyright (C) 2002-2003 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
#ifndef _VASNWPRINTF_H
|
||||
#define _VASNWPRINTF_H
|
||||
|
||||
/* Get va_list. */
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Get wchar_t, size_t. */
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Write formatted output to a string dynamically allocated with malloc().
|
||||
You can pass a preallocated buffer for the result in RESULTBUF and its
|
||||
size in *LENGTHP; otherwise you pass RESULTBUF = NULL.
|
||||
If successful, return the address of the string (this may be = RESULTBUF
|
||||
if no dynamic memory allocation was necessary) and set *LENGTHP to the
|
||||
number of resulting bytes, excluding the trailing NUL. Upon error, set
|
||||
errno and return NULL. */
|
||||
extern wchar_t * asnwprintf (wchar_t *resultbuf, size_t *lengthp, const wchar_t *format, ...);
|
||||
extern wchar_t * vasnwprintf (wchar_t *resultbuf, size_t *lengthp, const wchar_t *format, va_list args);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _VASNWPRINTF_H */
|
||||
@@ -0,0 +1,336 @@
|
||||
/* Compile-time assert-like macros.
|
||||
|
||||
Copyright (C) 2005-2006, 2009-2022 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 Paul Eggert, Bruno Haible, and Jim Meyering. */
|
||||
|
||||
#ifndef _GL_VERIFY_H
|
||||
#define _GL_VERIFY_H
|
||||
|
||||
|
||||
/* Define _GL_HAVE__STATIC_ASSERT to 1 if _Static_assert (R, DIAGNOSTIC)
|
||||
works as per C11. This is supported by GCC 4.6.0+ and by clang 4+.
|
||||
|
||||
Define _GL_HAVE__STATIC_ASSERT1 to 1 if _Static_assert (R) works as
|
||||
per C2x. This is supported by GCC 9.1+.
|
||||
|
||||
Support compilers claiming conformance to the relevant standard,
|
||||
and also support GCC when not pedantic. If we were willing to slow
|
||||
'configure' down we could also use it with other compilers, but
|
||||
since this affects only the quality of diagnostics, why bother? */
|
||||
#ifndef __cplusplus
|
||||
# if (201112L <= __STDC_VERSION__ \
|
||||
|| (!defined __STRICT_ANSI__ \
|
||||
&& (4 < __GNUC__ + (6 <= __GNUC_MINOR__) || 5 <= __clang_major__)))
|
||||
# define _GL_HAVE__STATIC_ASSERT 1
|
||||
# endif
|
||||
# if (202000L <= __STDC_VERSION__ \
|
||||
|| (!defined __STRICT_ANSI__ && 9 <= __GNUC__))
|
||||
# define _GL_HAVE__STATIC_ASSERT1 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* FreeBSD 9.1 <sys/cdefs.h>, included by <stddef.h> and lots of other
|
||||
system headers, defines a conflicting _Static_assert that is no
|
||||
better than ours; override it. */
|
||||
#ifndef _GL_HAVE__STATIC_ASSERT
|
||||
# include <stddef.h>
|
||||
# undef _Static_assert
|
||||
#endif
|
||||
|
||||
/* Each of these macros verifies that its argument R is nonzero. To
|
||||
be portable, R should be an integer constant expression. Unlike
|
||||
assert (R), there is no run-time overhead.
|
||||
|
||||
If _Static_assert works, verify (R) uses it directly. Similarly,
|
||||
_GL_VERIFY_TRUE works by packaging a _Static_assert inside a struct
|
||||
that is an operand of sizeof.
|
||||
|
||||
The code below uses several ideas for C++ compilers, and for C
|
||||
compilers that do not support _Static_assert:
|
||||
|
||||
* The first step is ((R) ? 1 : -1). Given an expression R, of
|
||||
integral or boolean or floating-point type, this yields an
|
||||
expression of integral type, whose value is later verified to be
|
||||
constant and nonnegative.
|
||||
|
||||
* Next this expression W is wrapped in a type
|
||||
struct _gl_verify_type {
|
||||
unsigned int _gl_verify_error_if_negative: W;
|
||||
}.
|
||||
If W is negative, this yields a compile-time error. No compiler can
|
||||
deal with a bit-field of negative size.
|
||||
|
||||
One might think that an array size check would have the same
|
||||
effect, that is, that the type struct { unsigned int dummy[W]; }
|
||||
would work as well. However, inside a function, some compilers
|
||||
(such as C++ compilers and GNU C) allow local parameters and
|
||||
variables inside array size expressions. With these compilers,
|
||||
an array size check would not properly diagnose this misuse of
|
||||
the verify macro:
|
||||
|
||||
void function (int n) { verify (n < 0); }
|
||||
|
||||
* For the verify macro, the struct _gl_verify_type will need to
|
||||
somehow be embedded into a declaration. To be portable, this
|
||||
declaration must declare an object, a constant, a function, or a
|
||||
typedef name. If the declared entity uses the type directly,
|
||||
such as in
|
||||
|
||||
struct dummy {...};
|
||||
typedef struct {...} dummy;
|
||||
extern struct {...} *dummy;
|
||||
extern void dummy (struct {...} *);
|
||||
extern struct {...} *dummy (void);
|
||||
|
||||
two uses of the verify macro would yield colliding declarations
|
||||
if the entity names are not disambiguated. A workaround is to
|
||||
attach the current line number to the entity name:
|
||||
|
||||
#define _GL_CONCAT0(x, y) x##y
|
||||
#define _GL_CONCAT(x, y) _GL_CONCAT0 (x, y)
|
||||
extern struct {...} * _GL_CONCAT (dummy, __LINE__);
|
||||
|
||||
But this has the problem that two invocations of verify from
|
||||
within the same macro would collide, since the __LINE__ value
|
||||
would be the same for both invocations. (The GCC __COUNTER__
|
||||
macro solves this problem, but is not portable.)
|
||||
|
||||
A solution is to use the sizeof operator. It yields a number,
|
||||
getting rid of the identity of the type. Declarations like
|
||||
|
||||
extern int dummy [sizeof (struct {...})];
|
||||
extern void dummy (int [sizeof (struct {...})]);
|
||||
extern int (*dummy (void)) [sizeof (struct {...})];
|
||||
|
||||
can be repeated.
|
||||
|
||||
* Should the implementation use a named struct or an unnamed struct?
|
||||
Which of the following alternatives can be used?
|
||||
|
||||
extern int dummy [sizeof (struct {...})];
|
||||
extern int dummy [sizeof (struct _gl_verify_type {...})];
|
||||
extern void dummy (int [sizeof (struct {...})]);
|
||||
extern void dummy (int [sizeof (struct _gl_verify_type {...})]);
|
||||
extern int (*dummy (void)) [sizeof (struct {...})];
|
||||
extern int (*dummy (void)) [sizeof (struct _gl_verify_type {...})];
|
||||
|
||||
In the second and sixth case, the struct type is exported to the
|
||||
outer scope; two such declarations therefore collide. GCC warns
|
||||
about the first, third, and fourth cases. So the only remaining
|
||||
possibility is the fifth case:
|
||||
|
||||
extern int (*dummy (void)) [sizeof (struct {...})];
|
||||
|
||||
* GCC warns about duplicate declarations of the dummy function if
|
||||
-Wredundant-decls is used. GCC 4.3 and later have a builtin
|
||||
__COUNTER__ macro that can let us generate unique identifiers for
|
||||
each dummy function, to suppress this warning.
|
||||
|
||||
* This implementation exploits the fact that older versions of GCC,
|
||||
which do not support _Static_assert, also do not warn about the
|
||||
last declaration mentioned above.
|
||||
|
||||
* GCC warns if -Wnested-externs is enabled and 'verify' is used
|
||||
within a function body; but inside a function, you can always
|
||||
arrange to use verify_expr instead.
|
||||
|
||||
* In C++, any struct definition inside sizeof is invalid.
|
||||
Use a template type to work around the problem. */
|
||||
|
||||
/* Concatenate two preprocessor tokens. */
|
||||
#define _GL_CONCAT(x, y) _GL_CONCAT0 (x, y)
|
||||
#define _GL_CONCAT0(x, y) x##y
|
||||
|
||||
/* _GL_COUNTER is an integer, preferably one that changes each time we
|
||||
use it. Use __COUNTER__ if it works, falling back on __LINE__
|
||||
otherwise. __LINE__ isn't perfect, but it's better than a
|
||||
constant. */
|
||||
#if defined __COUNTER__ && __COUNTER__ != __COUNTER__
|
||||
# define _GL_COUNTER __COUNTER__
|
||||
#else
|
||||
# define _GL_COUNTER __LINE__
|
||||
#endif
|
||||
|
||||
/* Generate a symbol with the given prefix, making it unique if
|
||||
possible. */
|
||||
#define _GL_GENSYM(prefix) _GL_CONCAT (prefix, _GL_COUNTER)
|
||||
|
||||
/* Verify requirement R at compile-time, as an integer constant expression
|
||||
that returns 1. If R is false, fail at compile-time, preferably
|
||||
with a diagnostic that includes the string-literal DIAGNOSTIC. */
|
||||
|
||||
#define _GL_VERIFY_TRUE(R, DIAGNOSTIC) \
|
||||
(!!sizeof (_GL_VERIFY_TYPE (R, DIAGNOSTIC)))
|
||||
|
||||
#ifdef __cplusplus
|
||||
# if !GNULIB_defined_struct__gl_verify_type
|
||||
template <int w>
|
||||
struct _gl_verify_type {
|
||||
unsigned int _gl_verify_error_if_negative: w;
|
||||
};
|
||||
# define GNULIB_defined_struct__gl_verify_type 1
|
||||
# endif
|
||||
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
||||
_gl_verify_type<(R) ? 1 : -1>
|
||||
#elif defined _GL_HAVE__STATIC_ASSERT
|
||||
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
||||
struct { \
|
||||
_Static_assert (R, DIAGNOSTIC); \
|
||||
int _gl_dummy; \
|
||||
}
|
||||
#else
|
||||
# define _GL_VERIFY_TYPE(R, DIAGNOSTIC) \
|
||||
struct { unsigned int _gl_verify_error_if_negative: (R) ? 1 : -1; }
|
||||
#endif
|
||||
|
||||
/* Verify requirement R at compile-time, as a declaration without a
|
||||
trailing ';'. If R is false, fail at compile-time.
|
||||
|
||||
This macro requires three or more arguments but uses at most the first
|
||||
two, so that the _Static_assert macro optionally defined below supports
|
||||
both the C11 two-argument syntax and the C2x one-argument syntax.
|
||||
|
||||
Unfortunately, unlike C11, this implementation must appear as an
|
||||
ordinary declaration, and cannot appear inside struct { ... }. */
|
||||
|
||||
#if 200410 <= __cpp_static_assert
|
||||
# define _GL_VERIFY(R, DIAGNOSTIC, ...) static_assert (R, DIAGNOSTIC)
|
||||
#elif defined _GL_HAVE__STATIC_ASSERT
|
||||
# define _GL_VERIFY(R, DIAGNOSTIC, ...) _Static_assert (R, DIAGNOSTIC)
|
||||
#else
|
||||
# define _GL_VERIFY(R, DIAGNOSTIC, ...) \
|
||||
extern int (*_GL_GENSYM (_gl_verify_function) (void)) \
|
||||
[_GL_VERIFY_TRUE (R, DIAGNOSTIC)]
|
||||
#endif
|
||||
|
||||
/* _GL_STATIC_ASSERT_H is defined if this code is copied into assert.h. */
|
||||
#ifdef _GL_STATIC_ASSERT_H
|
||||
# if !defined _GL_HAVE__STATIC_ASSERT1 && !defined _Static_assert
|
||||
# define _Static_assert(R, ...) \
|
||||
_GL_VERIFY ((R), "static assertion failed", -)
|
||||
# endif
|
||||
# if (!defined static_assert \
|
||||
&& (!defined __cplusplus \
|
||||
|| (__cpp_static_assert < 201411 \
|
||||
&& __GNUG__ < 6 && __clang_major__ < 6)))
|
||||
# if defined __cplusplus && _MSC_VER >= 1900 && !defined __clang__
|
||||
/* MSVC 14 in C++ mode supports the two-arguments static_assert but not
|
||||
the one-argument static_assert, and it does not support _Static_assert.
|
||||
We have to play preprocessor tricks to distinguish the two cases.
|
||||
Since the MSVC preprocessor is not ISO C compliant (cf.
|
||||
<https://stackoverflow.com/questions/5134523/>), the solution is specific
|
||||
to MSVC. */
|
||||
# define _GL_EXPAND(x) x
|
||||
# define _GL_SA1(a1) static_assert ((a1), "static assertion failed")
|
||||
# define _GL_SA2 static_assert
|
||||
# define _GL_SA3 static_assert
|
||||
# define _GL_SA_PICK(x1,x2,x3,x4,...) x4
|
||||
# define static_assert(...) _GL_EXPAND(_GL_SA_PICK(__VA_ARGS__,_GL_SA3,_GL_SA2,_GL_SA1)) (__VA_ARGS__)
|
||||
# else
|
||||
# define static_assert _Static_assert /* C11 requires this #define. */
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* @assert.h omit start@ */
|
||||
|
||||
#if 3 < __GNUC__ + (3 < __GNUC_MINOR__ + (4 <= __GNUC_PATCHLEVEL__))
|
||||
# define _GL_HAS_BUILTIN_TRAP 1
|
||||
#elif defined __has_builtin
|
||||
# define _GL_HAS_BUILTIN_TRAP __has_builtin (__builtin_trap)
|
||||
#else
|
||||
# define _GL_HAS_BUILTIN_TRAP 0
|
||||
#endif
|
||||
|
||||
#if 4 < __GNUC__ + (5 <= __GNUC_MINOR__)
|
||||
# define _GL_HAS_BUILTIN_UNREACHABLE 1
|
||||
#elif defined __has_builtin
|
||||
# define _GL_HAS_BUILTIN_UNREACHABLE __has_builtin (__builtin_unreachable)
|
||||
#else
|
||||
# define _GL_HAS_BUILTIN_UNREACHABLE 0
|
||||
#endif
|
||||
|
||||
/* Each of these macros verifies that its argument R is nonzero. To
|
||||
be portable, R should be an integer constant expression. Unlike
|
||||
assert (R), there is no run-time overhead.
|
||||
|
||||
There are two macros, since no single macro can be used in all
|
||||
contexts in C. verify_expr (R, E) is for scalar contexts, including
|
||||
integer constant expression contexts. verify (R) is for declaration
|
||||
contexts, e.g., the top level. */
|
||||
|
||||
/* Verify requirement R at compile-time. Return the value of the
|
||||
expression E. */
|
||||
|
||||
#define verify_expr(R, E) \
|
||||
(_GL_VERIFY_TRUE (R, "verify_expr (" #R ", " #E ")") ? (E) : (E))
|
||||
|
||||
/* Verify requirement R at compile-time, as a declaration without a
|
||||
trailing ';'. verify (R) acts like static_assert (R) except that
|
||||
it is portable to C11/C++14 and earlier, it can issue better
|
||||
diagnostics, and its name is shorter and may be more convenient. */
|
||||
|
||||
#ifdef __PGI
|
||||
/* PGI barfs if R is long. */
|
||||
# define verify(R) _GL_VERIFY (R, "verify (...)", -)
|
||||
#else
|
||||
# define verify(R) _GL_VERIFY (R, "verify (" #R ")", -)
|
||||
#endif
|
||||
|
||||
/* Assume that R always holds. Behavior is undefined if R is false,
|
||||
fails to evaluate, or has side effects.
|
||||
|
||||
'assume (R)' is a directive from the programmer telling the
|
||||
compiler that R is true so the compiler needn't generate code to
|
||||
test R. This is why 'assume' is in verify.h: it's related to
|
||||
static checking (in this case, static checking done by the
|
||||
programmer), not dynamic checking.
|
||||
|
||||
'assume (R)' can affect compilation of all the code, not just code
|
||||
that happens to be executed after the assume (R) is "executed".
|
||||
For example, if the code mistakenly does 'assert (R); assume (R);'
|
||||
the compiler is entitled to optimize away the 'assert (R)'.
|
||||
|
||||
Although assuming R can help a compiler generate better code or
|
||||
diagnostics, performance can suffer if R uses hard-to-optimize
|
||||
features such as function calls not inlined by the compiler.
|
||||
|
||||
Avoid Clang's __builtin_assume, as it breaks GNU Emacs master
|
||||
as of 2020-08-23T21:09:49Z!eggert@cs.ucla.edu; see
|
||||
<https://bugs.gnu.org/43152#71>. It's not known whether this breakage
|
||||
is a Clang bug or an Emacs bug; play it safe for now. */
|
||||
|
||||
#if _GL_HAS_BUILTIN_UNREACHABLE
|
||||
# define assume(R) ((R) ? (void) 0 : __builtin_unreachable ())
|
||||
#elif 1200 <= _MSC_VER
|
||||
# define assume(R) __assume (R)
|
||||
#elif 202311L <= __STDC_VERSION__
|
||||
# include <stddef.h>
|
||||
# define assume(R) ((R) ? (void) 0 : unreachable ())
|
||||
#elif (defined GCC_LINT || defined lint) && _GL_HAS_BUILTIN_TRAP
|
||||
/* Doing it this way helps various packages when configured with
|
||||
--enable-gcc-warnings, which compiles with -Dlint. It's nicer
|
||||
if 'assume' silences warnings with GCC 3.4 through GCC 4.4.7 (2012). */
|
||||
# define assume(R) ((R) ? (void) 0 : __builtin_trap ())
|
||||
#else
|
||||
/* Some older tools grok NOTREACHED, e.g., Oracle Studio 12.6 (2017). */
|
||||
# define assume(R) ((R) ? (void) 0 : /*NOTREACHED*/ (void) 0)
|
||||
#endif
|
||||
|
||||
/* @assert.h omit end@ */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
/* libintl library version.
|
||||
Copyright (C) 2005 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "libgnuintl.h"
|
||||
|
||||
/* Version number: (major<<16) + (minor<<8) + subminor */
|
||||
int libintl_version = LIBINTL_VERSION;
|
||||
@@ -0,0 +1,84 @@
|
||||
/* Parse printf format string.
|
||||
Copyright (C) 1999, 2002-2003, 2005, 2007, 2010-2011 Free Software Foundation, Inc.
|
||||
|
||||
This program 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 program 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/>. */
|
||||
|
||||
#ifndef _WPRINTF_PARSE_H
|
||||
#define _WPRINTF_PARSE_H
|
||||
|
||||
#if HAVE_FEATURES_H
|
||||
# include <features.h> /* for __GLIBC__, __UCLIBC__ */
|
||||
#endif
|
||||
|
||||
#include "printf-args.h"
|
||||
|
||||
|
||||
/* Flags */
|
||||
#define FLAG_GROUP 1 /* ' flag */
|
||||
#define FLAG_LEFT 2 /* - flag */
|
||||
#define FLAG_SHOWSIGN 4 /* + flag */
|
||||
#define FLAG_SPACE 8 /* space flag */
|
||||
#define FLAG_ALT 16 /* # flag */
|
||||
#define FLAG_ZERO 32
|
||||
#if __GLIBC__ >= 2 && !defined __UCLIBC__
|
||||
# define FLAG_LOCALIZED 64 /* I flag, uses localized digits */
|
||||
#endif
|
||||
|
||||
/* arg_index value indicating that no argument is consumed. */
|
||||
#define ARG_NONE (~(size_t)0)
|
||||
|
||||
/* Number of directly allocated directives (no malloc() needed). */
|
||||
#define N_DIRECT_ALLOC_DIRECTIVES 7
|
||||
|
||||
/* A parsed directive. */
|
||||
typedef struct
|
||||
{
|
||||
const wchar_t* dir_start;
|
||||
const wchar_t* dir_end;
|
||||
int flags;
|
||||
const wchar_t* width_start;
|
||||
const wchar_t* width_end;
|
||||
size_t width_arg_index;
|
||||
const wchar_t* precision_start;
|
||||
const wchar_t* precision_end;
|
||||
size_t precision_arg_index;
|
||||
wchar_t conversion; /* d i o u x X f F e E g G a A c s p n U % but not C S */
|
||||
size_t arg_index;
|
||||
}
|
||||
wchar_t_directive;
|
||||
|
||||
/* A parsed format string. */
|
||||
typedef struct
|
||||
{
|
||||
size_t count;
|
||||
wchar_t_directive *dir;
|
||||
size_t max_width_length;
|
||||
size_t max_precision_length;
|
||||
wchar_t_directive direct_alloc_dir[N_DIRECT_ALLOC_DIRECTIVES];
|
||||
}
|
||||
wchar_t_directives;
|
||||
|
||||
|
||||
/* Parses the format string. Fills in the number N of directives, and fills
|
||||
in directives[0], ..., directives[N-1], and sets directives[N].dir_start
|
||||
to the end of the format string. Also fills in the arg_type fields of the
|
||||
arguments and the needed count of arguments. */
|
||||
#ifdef STATIC
|
||||
STATIC
|
||||
#else
|
||||
extern
|
||||
#endif
|
||||
int wprintf_parse (const wchar_t *format, wchar_t_directives *d, arguments *a);
|
||||
|
||||
#endif /* _WPRINTF_PARSE_H */
|
||||
@@ -0,0 +1,3 @@
|
||||
#include <config.h>
|
||||
#define XSIZE_INLINE _GL_EXTERN_INLINE
|
||||
#include "xsize.h"
|
||||
@@ -0,0 +1,108 @@
|
||||
/* xsize.h -- Checked size_t computations.
|
||||
|
||||
Copyright (C) 2003, 2008-2022 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/>. */
|
||||
|
||||
#ifndef _XSIZE_H
|
||||
#define _XSIZE_H
|
||||
|
||||
/* Get size_t. */
|
||||
#include <stddef.h>
|
||||
|
||||
/* Get SIZE_MAX. */
|
||||
#include <limits.h>
|
||||
#if HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
|
||||
/* Get ATTRIBUTE_PURE. */
|
||||
#include "attribute.h"
|
||||
|
||||
#ifndef _GL_INLINE_HEADER_BEGIN
|
||||
#error "Please include config.h first."
|
||||
#endif
|
||||
_GL_INLINE_HEADER_BEGIN
|
||||
#ifndef XSIZE_INLINE
|
||||
# define XSIZE_INLINE _GL_INLINE
|
||||
#endif
|
||||
|
||||
/* The size of memory objects is often computed through expressions of
|
||||
type size_t. Example:
|
||||
void* p = malloc (header_size + n * element_size).
|
||||
These computations can lead to overflow. When this happens, malloc()
|
||||
returns a piece of memory that is way too small, and the program then
|
||||
crashes while attempting to fill the memory.
|
||||
To avoid this, the functions and macros in this file check for overflow.
|
||||
The convention is that SIZE_MAX represents overflow.
|
||||
malloc (SIZE_MAX) is not guaranteed to fail -- think of a malloc
|
||||
implementation that uses mmap --, it's recommended to use size_overflow_p()
|
||||
or size_in_bounds_p() before invoking malloc().
|
||||
The example thus becomes:
|
||||
size_t size = xsum (header_size, xtimes (n, element_size));
|
||||
void *p = (size_in_bounds_p (size) ? malloc (size) : NULL);
|
||||
*/
|
||||
|
||||
/* Convert an arbitrary value >= 0 to type size_t. */
|
||||
#define xcast_size_t(N) \
|
||||
((N) <= SIZE_MAX ? (size_t) (N) : SIZE_MAX)
|
||||
|
||||
/* Sum of two sizes, with overflow check. */
|
||||
XSIZE_INLINE size_t ATTRIBUTE_PURE
|
||||
xsum (size_t size1, size_t size2)
|
||||
{
|
||||
size_t sum = size1 + size2;
|
||||
return (sum >= size1 ? sum : SIZE_MAX);
|
||||
}
|
||||
|
||||
/* Sum of three sizes, with overflow check. */
|
||||
XSIZE_INLINE size_t ATTRIBUTE_PURE
|
||||
xsum3 (size_t size1, size_t size2, size_t size3)
|
||||
{
|
||||
return xsum (xsum (size1, size2), size3);
|
||||
}
|
||||
|
||||
/* Sum of four sizes, with overflow check. */
|
||||
XSIZE_INLINE size_t ATTRIBUTE_PURE
|
||||
xsum4 (size_t size1, size_t size2, size_t size3, size_t size4)
|
||||
{
|
||||
return xsum (xsum (xsum (size1, size2), size3), size4);
|
||||
}
|
||||
|
||||
/* Maximum of two sizes, with overflow check. */
|
||||
XSIZE_INLINE size_t ATTRIBUTE_PURE
|
||||
xmax (size_t size1, size_t size2)
|
||||
{
|
||||
/* No explicit check is needed here, because for any n:
|
||||
max (SIZE_MAX, n) == SIZE_MAX and max (n, SIZE_MAX) == SIZE_MAX. */
|
||||
return (size1 >= size2 ? size1 : size2);
|
||||
}
|
||||
|
||||
/* Multiplication of a count with an element size, with overflow check.
|
||||
The count must be >= 0 and the element size must be > 0.
|
||||
This is a macro, not a function, so that it works correctly even
|
||||
when N is of a wider type and N > SIZE_MAX. */
|
||||
#define xtimes(N, ELSIZE) \
|
||||
((N) <= SIZE_MAX / (ELSIZE) ? (size_t) (N) * (ELSIZE) : SIZE_MAX)
|
||||
|
||||
/* Check for overflow. */
|
||||
#define size_overflow_p(SIZE) \
|
||||
((SIZE) == SIZE_MAX)
|
||||
/* Check against overflow. */
|
||||
#define size_in_bounds_p(SIZE) \
|
||||
((SIZE) != SIZE_MAX)
|
||||
|
||||
_GL_INLINE_HEADER_END
|
||||
|
||||
#endif /* _XSIZE_H */
|
||||
@@ -0,0 +1,80 @@
|
||||
/* Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined (HAVE_BRK) && !defined (HAVE_SBRK)
|
||||
|
||||
static void *initialbrk;
|
||||
static void *curbrk;
|
||||
|
||||
static int
|
||||
initbrk (void)
|
||||
{
|
||||
if (initialbrk == 0)
|
||||
{
|
||||
void *b;
|
||||
|
||||
b = brk (NULL);
|
||||
if (b == (void *)-1)
|
||||
return -1;
|
||||
initialbrk = curbrk = b;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* sbrk(3) implementation in terms of brk(2). Good enough for malloc to use. */
|
||||
void *
|
||||
sbrk (intptr_t incr)
|
||||
{
|
||||
void *newbrk, *oldbrk;
|
||||
|
||||
if (initialbrk == 0 && initbrk () == -1)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
if (incr == 0)
|
||||
return curbrk;
|
||||
|
||||
/* bounds checking, overflow */
|
||||
if ((incr > 0 && (uintptr_t) curbrk + incr < (uintptr_t) curbrk) ||
|
||||
(incr < 0 && (uintptr_t) curbrk + incr > (uintptr_t) curbrk))
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
newbrk = curbrk + incr;
|
||||
if (newbrk < initialbrk)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
if (brk (newbrk) == (void *)-1)
|
||||
return (void *)-1; /* preserve errno */
|
||||
|
||||
oldbrk = curbrk;
|
||||
curbrk = newbrk;
|
||||
|
||||
return (oldbrk);
|
||||
}
|
||||
#endif /* HAVE_BRK && !HAVE_SBRK */
|
||||
@@ -0,0 +1,147 @@
|
||||
/* anonfile.c - open and close temporary files (anonymous and memory-backed if possible). */
|
||||
|
||||
/* Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <bashtypes.h>
|
||||
|
||||
#if defined (HAVE_MEMFD_CREATE) || defined (HAVE_SHM_OPEN) || defined (HAVE_SHM_MKSTEMP)
|
||||
# include <sys/mman.h>
|
||||
#endif
|
||||
#include <filecntl.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <shell.h>
|
||||
#include <bashansi.h>
|
||||
|
||||
static int anonunlink (const char *);
|
||||
|
||||
#if defined (HAVE_SHM_OPEN)
|
||||
#ifndef O_NOFOLLOW
|
||||
# define O_NOFOLLOW 0
|
||||
#endif
|
||||
|
||||
static int
|
||||
anonshmunlink (const char *fn)
|
||||
{
|
||||
return (shm_unlink (fn));
|
||||
}
|
||||
|
||||
static int
|
||||
anonshmopen (const char *name, int flags, char **fn)
|
||||
{
|
||||
int fd;
|
||||
char *fname;
|
||||
|
||||
fd = -1;
|
||||
if (fn)
|
||||
*fn = 0;
|
||||
|
||||
#if defined (HAVE_SHM_MKSTEMP)
|
||||
fname = savestring ("/shm-XXXXXXXXXX");
|
||||
fd = shm_mkstemp (fname);
|
||||
if (fd < 0)
|
||||
free (fname);
|
||||
#endif
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
fname = sh_mktmpname (name, flags);
|
||||
fd = shm_open (fname, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600);
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
free (fname);
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (shm_unlink (fname) < 0)
|
||||
{
|
||||
int o;
|
||||
o = errno;
|
||||
free (fname);
|
||||
close (fd);
|
||||
errno = o;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fn)
|
||||
*fn = fname;
|
||||
else
|
||||
free (fname);
|
||||
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
anonopen (const char *name, int flags, char **fn)
|
||||
{
|
||||
int fd, flag;
|
||||
char *fname;
|
||||
|
||||
#if defined (HAVE_MEMFD_CREATE)
|
||||
/* "Names do not affect the behavior of the file descriptor." */
|
||||
fd = memfd_create ("anonopen", 0);
|
||||
if (fd >= 0)
|
||||
{
|
||||
if (fn)
|
||||
*fn = 0;
|
||||
return fd;
|
||||
}
|
||||
/* If memfd_create fails, we fall through to the unlinked-shm-or-regular-file
|
||||
implementation. */
|
||||
#endif
|
||||
|
||||
/* Heuristic */
|
||||
flag = (name && *name == '/') ? MT_TEMPLATE : MT_USETMPDIR;
|
||||
|
||||
#if defined (HAVE_SHM_OPEN)
|
||||
fd = anonshmopen (name, flag, fn);
|
||||
if (fd >= 0)
|
||||
return fd; /* anonshmopen sets *FN appropriately */
|
||||
#endif
|
||||
|
||||
fd = sh_mktmpfd (name, flag|MT_USERANDOM|MT_READWRITE|MT_UNLINK, fn);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
anonclose (int fd, const char *name)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = close (fd);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
anonunlink (const char *fn)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = unlink (fn);
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/* compat.c - functions for backwards compatibility with previous versions */
|
||||
|
||||
/* Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <bashtypes.h>
|
||||
#include <shell.h>
|
||||
|
||||
/* For backwards compatibility with existing loadable builtins. */
|
||||
int
|
||||
legal_number (const char *string, intmax_t *result)
|
||||
{
|
||||
return (valid_number (string, result));
|
||||
}
|
||||
|
||||
int
|
||||
legal_identifier (const char *string)
|
||||
{
|
||||
return (valid_identifier (string));
|
||||
}
|
||||
|
||||
int
|
||||
legal_alias_name (const char *string, int flags)
|
||||
{
|
||||
return (valid_alias_name (string, flags));
|
||||
}
|
||||
|
||||
int
|
||||
compat_init (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/* mbsncmp - multibyte string comparison. */
|
||||
|
||||
/* Copyright (C) 1995-2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if !defined (HAVE_MBSNCMP) && defined (HANDLE_MULTIBYTE)
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
extern int locale_utf8locale;
|
||||
|
||||
/* Compare MBS1 and MBS2 up to N multibyte characters. */
|
||||
int
|
||||
mbsncmp (const char *mbs1, const char *mbs2, size_t n)
|
||||
{
|
||||
int len1, len2, mb_cur_max;
|
||||
wchar_t c1, c2;
|
||||
mbstate_t state1 = { 0 }, state2 = { 0 };
|
||||
|
||||
len1 = len2 = 0;
|
||||
mb_cur_max = MB_CUR_MAX;
|
||||
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
do
|
||||
{
|
||||
len1 = mbrtowc (&c1, mbs1, mb_cur_max, &state1);
|
||||
len2 = mbrtowc (&c2, mbs2, mb_cur_max, &state2);
|
||||
|
||||
if (len1 == 0)
|
||||
return len2 == 0 ? 0 : -1;
|
||||
else if (len2 == 0)
|
||||
return 1;
|
||||
else if (len1 > 0 && len2 < 0)
|
||||
return -1;
|
||||
else if (len1 < 0 && len2 > 0)
|
||||
return 1;
|
||||
else if (len1 < 0 && len2 < 0)
|
||||
{
|
||||
len1 = strlen (mbs1);
|
||||
len2 = strlen (mbs2);
|
||||
return (len1 == len2 ? memcmp (mbs1, mbs2, len1)
|
||||
: ((len1 < len2) ? (memcmp (mbs1, mbs2, len1) > 0 ? 1 : -1)
|
||||
: (memcmp (mbs1, mbs2, len2) >= 0 ? 1 : -1)));
|
||||
}
|
||||
|
||||
mbs1 += len1;
|
||||
mbs2 += len2;
|
||||
n--;
|
||||
if (c1 != c2)
|
||||
break;
|
||||
}
|
||||
while (n > 0);
|
||||
|
||||
return c1 - c2;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
/* reallocarray.c - reallocate memory for an array given type size and
|
||||
number of elements */
|
||||
|
||||
/* Copyright (C) 2024 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include <stdckdint.h>
|
||||
|
||||
#include <errno.h>
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
void *
|
||||
reallocarray (void *ptr, size_t nmemb, size_t size)
|
||||
{
|
||||
size_t nbytes;
|
||||
|
||||
if (ckd_mul (&nbytes, nmemb, size))
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return realloc (ptr, nbytes);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/* strlcpy - null-terminated string copy with length checking. */
|
||||
|
||||
/* Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <bashansi.h>
|
||||
|
||||
size_t
|
||||
strlcpy(char *dest, const char *src, size_t size)
|
||||
{
|
||||
size_t ret;
|
||||
|
||||
ret = strlen(src);
|
||||
if (size)
|
||||
{
|
||||
size_t len;
|
||||
len = (ret >= size) ? size - 1 : ret;
|
||||
memcpy (dest, src, len);
|
||||
dest[len] = '\0';
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/* strscpy - null-terminated string copy with length checking. */
|
||||
|
||||
/* Copyright (C) 2023 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash 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.
|
||||
|
||||
Bash 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 Bash. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <bashansi.h>
|
||||
|
||||
ssize_t
|
||||
strscpy (char *d, const char *s, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if ((d[i] = s[i]) == 0)
|
||||
return ((ssize_t)i);
|
||||
|
||||
if (i != 0)
|
||||
d[--i] = '\0';
|
||||
|
||||
return (-1); /* strlen (s) > len */
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
# serial 10
|
||||
|
||||
# Copyright (C) 2002-2006, 2008-2022 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# There are two types of parser skeletons:
|
||||
#
|
||||
# * Those that can be used with any Yacc implementation, including bison.
|
||||
# For these, in the configure.ac, up to Autoconf 2.69, you could use
|
||||
# AC_PROG_YACC
|
||||
# In newer Autoconf versions, however, this macro is broken. See
|
||||
# https://lists.gnu.org/archive/html/autoconf-patches/2013-03/msg00000.html
|
||||
# https://lists.gnu.org/archive/html/bug-autoconf/2018-12/msg00001.html
|
||||
# In the Makefile.am you could use
|
||||
# $(SHELL) $(YLWRAP) $(srcdir)/foo.y \
|
||||
# y.tab.c foo.c \
|
||||
# y.tab.h foo.h \
|
||||
# y.output foo.output \
|
||||
# -- $(YACC) $(YFLAGS) $(AM_YFLAGS)
|
||||
# or similar.
|
||||
#
|
||||
# * Those that make use of Bison extensions. For example,
|
||||
# - %define api.pure requires bison 2.7 or newer,
|
||||
# - %precedence requires bison 3.0 or newer.
|
||||
# For these, in the configure.ac you will need an invocation of
|
||||
# gl_PROG_BISON([VARIABLE], [MIN_BISON_VERSION])
|
||||
# Example:
|
||||
# gl_PROG_BISON([PARSE_DATETIME_BISON], [2.4])
|
||||
# With this preparation, in the Makefile.am there are two ways to formulate
|
||||
# the invocation. Both are direct, without use of 'ylwrap'.
|
||||
# (a) You can invoke
|
||||
# $(VARIABLE) -d $(SOME_BISON_OPTIONS) --output foo.c $(srcdir)/foo.y
|
||||
# or similar.
|
||||
# (b) If you want the invocation to honor an YFLAGS=... parameter passed to
|
||||
# 'configure' or an YFLAGS environment variable present at 'configure'
|
||||
# time, add an invocation of gl_BISON to the configure.ac, and write
|
||||
# $(VARIABLE) -d $(YFLAGS) $(AM_YFLAGS) $(srcdir)/foo.y
|
||||
# or similar.
|
||||
|
||||
# This macro defines the autoconf variable VARIABLE to 'bison' if the specified
|
||||
# minimum version of bison is found in $PATH, or to ':' otherwise.
|
||||
AC_DEFUN([gl_PROG_BISON],
|
||||
[
|
||||
AC_CHECK_PROGS([$1], [bison])
|
||||
if test -z "$[$1]"; then
|
||||
ac_verc_fail=yes
|
||||
else
|
||||
cat >conftest.y <<_ACEOF
|
||||
%require "$2"
|
||||
%%
|
||||
exp:
|
||||
_ACEOF
|
||||
AC_MSG_CHECKING([for bison $2 or newer])
|
||||
ac_prog_version=`$$1 --version 2>&1 | sed -n 's/^.*GNU Bison.* \([[0-9]]*\.[[0-9.]]*\).*$/\1/p'`
|
||||
: ${ac_prog_version:='v. ?.??'}
|
||||
if $$1 conftest.y -o conftest.c 2>/dev/null; then
|
||||
ac_prog_version="$ac_prog_version, ok"
|
||||
ac_verc_fail=no
|
||||
else
|
||||
ac_prog_version="$ac_prog_version, bad"
|
||||
ac_verc_fail=yes
|
||||
fi
|
||||
rm -f conftest.y conftest.c
|
||||
AC_MSG_RESULT([$ac_prog_version])
|
||||
fi
|
||||
if test $ac_verc_fail = yes; then
|
||||
[$1]=:
|
||||
fi
|
||||
AC_SUBST([$1])
|
||||
])
|
||||
|
||||
# This macro sets the autoconf variables YACC (for old-style yacc Makefile
|
||||
# rules) and YFLAGS (to allow options to be passed as 'configure' time).
|
||||
AC_DEFUN([gl_BISON],
|
||||
[
|
||||
: ${YACC='bison -o y.tab.c'}
|
||||
dnl
|
||||
dnl Declaring YACC & YFLAGS precious will not be necessary after GNULIB
|
||||
dnl requires an Autoconf greater than 2.59c, but it will probably still be
|
||||
dnl useful to override the description of YACC in the --help output, re
|
||||
dnl parse-datetime.y assuming 'bison -o y.tab.c'.
|
||||
AC_ARG_VAR([YACC],
|
||||
[The "Yet Another C Compiler" implementation to use. Defaults to
|
||||
'bison -o y.tab.c'. Values other than 'bison -o y.tab.c' will most likely
|
||||
break on most systems.])dnl
|
||||
AC_ARG_VAR([YFLAGS],
|
||||
[YFLAGS contains the list arguments that will be passed by default to Bison.
|
||||
This script will default YFLAGS to the empty string to avoid a default value of
|
||||
'-d' given by some make applications.])dnl
|
||||
])
|
||||
@@ -0,0 +1,27 @@
|
||||
# Check for bool that conforms to C2023.
|
||||
|
||||
dnl Copyright 2022-2024 Free Software Foundation, Inc.
|
||||
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_DEFUN([gl_C_BOOL],
|
||||
[
|
||||
AC_CACHE_CHECK([for bool, true, false], [gl_cv_c_bool],
|
||||
[AC_COMPILE_IFELSE(
|
||||
[AC_LANG_SOURCE([[
|
||||
#if true == false
|
||||
#error "true == false"
|
||||
#endif
|
||||
extern bool b;
|
||||
bool b = true == false;]])],
|
||||
[gl_cv_c_bool=yes],
|
||||
[gl_cv_c_bool=no])])
|
||||
if test "$gl_cv_c_bool" = yes; then
|
||||
AC_DEFINE([HAVE_C_BOOL], [1],
|
||||
[Define to 1 if bool, true and false work as per C2023.])
|
||||
fi
|
||||
|
||||
AC_CHECK_HEADERS_ONCE([stdbool.h])
|
||||
|
||||
])
|
||||
@@ -0,0 +1,44 @@
|
||||
# serial 5
|
||||
# Check for flexible array member support.
|
||||
|
||||
# Copyright (C) 2006, 2009-2022 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# Written by Paul Eggert.
|
||||
|
||||
AC_DEFUN([AC_C_FLEXIBLE_ARRAY_MEMBER],
|
||||
[
|
||||
AC_CACHE_CHECK([for flexible array member],
|
||||
ac_cv_c_flexmember,
|
||||
[AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
struct m { struct m *next, **list; char name[]; };
|
||||
struct s { struct s *p; struct m *m; int n; double d[]; };]],
|
||||
[[int m = getchar ();
|
||||
size_t nbytes = offsetof (struct s, d) + m * sizeof (double);
|
||||
nbytes += sizeof (struct s) - 1;
|
||||
nbytes -= nbytes % sizeof (struct s);
|
||||
struct s *p = malloc (nbytes);
|
||||
p->p = p;
|
||||
p->m = NULL;
|
||||
p->d[0] = 0.0;
|
||||
return p->d != (double *) NULL;]])],
|
||||
[ac_cv_c_flexmember=yes],
|
||||
[ac_cv_c_flexmember=no])])
|
||||
if test $ac_cv_c_flexmember = yes; then
|
||||
AC_DEFINE([FLEXIBLE_ARRAY_MEMBER], [],
|
||||
[Define to nothing if C supports flexible array members, and to
|
||||
1 if it does not. That way, with a declaration like 'struct s
|
||||
{ int n; short d@<:@FLEXIBLE_ARRAY_MEMBER@:>@; };', the struct hack
|
||||
can be used with pre-C99 compilers.
|
||||
Use 'FLEXSIZEOF (struct s, d, N * sizeof (short))' to calculate
|
||||
the size in bytes of such a struct containing an N-element array.])
|
||||
else
|
||||
AC_DEFINE([FLEXIBLE_ARRAY_MEMBER], [1])
|
||||
fi
|
||||
])
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
# locale_h.m4 serial 28
|
||||
dnl Copyright (C) 2007, 2009-2022 Free Software Foundation, Inc.
|
||||
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_DEFUN_ONCE([gl_LOCALE_H],
|
||||
[
|
||||
dnl Ensure to expand the default settings once only, before all statements
|
||||
dnl that occur in other macros.
|
||||
AC_REQUIRE([gl_LOCALE_H_DEFAULTS])
|
||||
|
||||
dnl Persuade glibc <locale.h> to define locale_t and the int_p_*, int_n_*
|
||||
dnl members of 'struct lconv'.
|
||||
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
||||
|
||||
dnl If <stddef.h> is replaced, then <locale.h> must also be replaced.
|
||||
AC_REQUIRE([gl_STDDEF_H])
|
||||
|
||||
AC_REQUIRE([gl_LOCALE_T])
|
||||
|
||||
dnl Solaris 11.0 defines the int_p_*, int_n_* members of 'struct lconv'
|
||||
dnl only if _LCONV_C99 is defined.
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
case "$host_os" in
|
||||
solaris*)
|
||||
AC_DEFINE([_LCONV_C99], [1], [Define to 1 on Solaris.])
|
||||
;;
|
||||
esac
|
||||
|
||||
AC_CACHE_CHECK([whether locale.h conforms to POSIX:2001],
|
||||
[gl_cv_header_locale_h_posix2001],
|
||||
[AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#include <locale.h>
|
||||
int x = LC_MESSAGES;
|
||||
int y = sizeof (((struct lconv *) 0)->decimal_point);]],
|
||||
[[]])],
|
||||
[gl_cv_header_locale_h_posix2001=yes],
|
||||
[gl_cv_header_locale_h_posix2001=no])])
|
||||
|
||||
dnl Check whether 'struct lconv' is complete.
|
||||
dnl Bionic libc's 'struct lconv' is just a dummy.
|
||||
dnl On OpenBSD 4.9, HP-UX 11, IRIX 6.5, OSF/1 5.1, Solaris 9, Cygwin 1.5.x,
|
||||
dnl mingw, MSVC 9, it lacks the int_p_* and int_n_* members.
|
||||
AC_CACHE_CHECK([whether struct lconv is properly defined],
|
||||
[gl_cv_sys_struct_lconv_ok],
|
||||
[AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#include <locale.h>
|
||||
struct lconv l;
|
||||
int x = sizeof (l.decimal_point);
|
||||
int y = sizeof (l.int_p_cs_precedes);]],
|
||||
[[]])],
|
||||
[gl_cv_sys_struct_lconv_ok=yes],
|
||||
[gl_cv_sys_struct_lconv_ok=no])
|
||||
])
|
||||
if test $gl_cv_sys_struct_lconv_ok = no; then
|
||||
dnl On native Windows with MSVC, merely define these member names as macros.
|
||||
dnl This avoids trouble in C++ mode.
|
||||
case "$host_os" in
|
||||
mingw*)
|
||||
AC_EGREP_CPP([Special], [
|
||||
#ifdef _MSC_VER
|
||||
Special
|
||||
#endif
|
||||
],
|
||||
[],
|
||||
[REPLACE_STRUCT_LCONV=1])
|
||||
;;
|
||||
*) REPLACE_STRUCT_LCONV=1 ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
dnl <locale.h> is always overridden, because of GNULIB_POSIXCHECK.
|
||||
gl_NEXT_HEADERS([locale.h])
|
||||
|
||||
dnl Check for declarations of anything we want to poison if the
|
||||
dnl corresponding gnulib module is not in use.
|
||||
gl_WARN_ON_USE_PREPARE([[#include <locale.h>
|
||||
/* Some systems provide declarations in a non-standard header. */
|
||||
#if HAVE_XLOCALE_H
|
||||
# include <xlocale.h>
|
||||
#endif
|
||||
]],
|
||||
[setlocale newlocale duplocale freelocale])
|
||||
])
|
||||
|
||||
dnl Checks to determine whether the system has the locale_t type,
|
||||
dnl and how to obtain it.
|
||||
AC_DEFUN([gl_LOCALE_T],
|
||||
[
|
||||
dnl Persuade glibc and Solaris <locale.h> to define locale_t.
|
||||
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
|
||||
|
||||
dnl Check whether use of locale_t requires inclusion of <xlocale.h>,
|
||||
dnl e.g. on Mac OS X 10.5. If <locale.h> does not define locale_t by
|
||||
dnl itself, we assume that <xlocale.h> will do so.
|
||||
AC_CACHE_CHECK([whether locale.h defines locale_t],
|
||||
[gl_cv_header_locale_has_locale_t],
|
||||
[AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[[#include <locale.h>
|
||||
locale_t x;]],
|
||||
[[]])],
|
||||
[gl_cv_header_locale_has_locale_t=yes],
|
||||
[gl_cv_header_locale_has_locale_t=no])
|
||||
])
|
||||
|
||||
dnl Check for <xlocale.h>.
|
||||
AC_CHECK_HEADERS_ONCE([xlocale.h])
|
||||
if test $ac_cv_header_xlocale_h = yes; then
|
||||
HAVE_XLOCALE_H=1
|
||||
if test $gl_cv_header_locale_has_locale_t = yes; then
|
||||
gl_cv_header_locale_h_needs_xlocale_h=no
|
||||
else
|
||||
gl_cv_header_locale_h_needs_xlocale_h=yes
|
||||
fi
|
||||
HAVE_LOCALE_T=1
|
||||
else
|
||||
HAVE_XLOCALE_H=0
|
||||
gl_cv_header_locale_h_needs_xlocale_h=no
|
||||
if test $gl_cv_header_locale_has_locale_t = yes; then
|
||||
HAVE_LOCALE_T=1
|
||||
else
|
||||
HAVE_LOCALE_T=0
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([HAVE_XLOCALE_H])
|
||||
])
|
||||
|
||||
# gl_LOCALE_MODULE_INDICATOR([modulename])
|
||||
# sets the shell variable that indicates the presence of the given module
|
||||
# to a C preprocessor expression that will evaluate to 1.
|
||||
# This macro invocation must not occur in macros that are AC_REQUIREd.
|
||||
AC_DEFUN([gl_LOCALE_MODULE_INDICATOR],
|
||||
[
|
||||
dnl Ensure to expand the default settings once only.
|
||||
gl_LOCALE_H_REQUIRE_DEFAULTS
|
||||
gl_MODULE_INDICATOR_SET_VARIABLE([$1])
|
||||
dnl Define it also as a C macro, for the benefit of the unit tests.
|
||||
gl_MODULE_INDICATOR_FOR_TESTS([$1])
|
||||
])
|
||||
|
||||
# Initializes the default values for AC_SUBSTed shell variables.
|
||||
# This macro must not be AC_REQUIREd. It must only be invoked, and only
|
||||
# outside of macros or in macros that are not AC_REQUIREd.
|
||||
AC_DEFUN([gl_LOCALE_H_REQUIRE_DEFAULTS],
|
||||
[
|
||||
m4_defun(GL_MODULE_INDICATOR_PREFIX[_LOCALE_H_MODULE_INDICATOR_DEFAULTS], [
|
||||
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALECONV])
|
||||
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETLOCALE])
|
||||
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_SETLOCALE_NULL])
|
||||
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_DUPLOCALE])
|
||||
gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_LOCALENAME])
|
||||
])
|
||||
m4_require(GL_MODULE_INDICATOR_PREFIX[_LOCALE_H_MODULE_INDICATOR_DEFAULTS])
|
||||
AC_REQUIRE([gl_LOCALE_H_DEFAULTS])
|
||||
])
|
||||
|
||||
AC_DEFUN([gl_LOCALE_H_DEFAULTS],
|
||||
[
|
||||
dnl Assume proper GNU behavior unless another module says otherwise.
|
||||
HAVE_NEWLOCALE=1; AC_SUBST([HAVE_NEWLOCALE])
|
||||
HAVE_DUPLOCALE=1; AC_SUBST([HAVE_DUPLOCALE])
|
||||
HAVE_FREELOCALE=1; AC_SUBST([HAVE_FREELOCALE])
|
||||
REPLACE_LOCALECONV=0; AC_SUBST([REPLACE_LOCALECONV])
|
||||
REPLACE_SETLOCALE=0; AC_SUBST([REPLACE_SETLOCALE])
|
||||
REPLACE_NEWLOCALE=0; AC_SUBST([REPLACE_NEWLOCALE])
|
||||
REPLACE_DUPLOCALE=0; AC_SUBST([REPLACE_DUPLOCALE])
|
||||
REPLACE_FREELOCALE=0; AC_SUBST([REPLACE_FREELOCALE])
|
||||
REPLACE_STRUCT_LCONV=0; AC_SUBST([REPLACE_STRUCT_LCONV])
|
||||
LOCALENAME_ENHANCE_LOCALE_FUNCS=0; AC_SUBST([LOCALENAME_ENHANCE_LOCALE_FUNCS])
|
||||
])
|
||||
@@ -0,0 +1,31 @@
|
||||
# unlocked-io.m4 serial 16
|
||||
|
||||
# Copyright (C) 1998-2006, 2009-2024 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
dnl From Jim Meyering.
|
||||
dnl
|
||||
dnl Adapted from gnulib:m4/unlocked-io.m4
|
||||
AC_DEFUN([BASH_FUNC_UNLOCKED_IO],
|
||||
[
|
||||
dnl Persuade glibc and Solaris <stdio.h> to declare
|
||||
dnl fgets_unlocked(), fputs_unlocked() etc.
|
||||
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
|
||||
|
||||
AC_CHECK_DECLS_ONCE([clearerr_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([feof_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([ferror_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([fflush_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([fgets_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([fputc_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([fputs_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([fread_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([fwrite_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([getc_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([getchar_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([putc_unlocked])
|
||||
AC_CHECK_DECLS_ONCE([putchar_unlocked])
|
||||
])
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/* patchlevel.h -- current bash patch level */
|
||||
|
||||
/* Copyright (C) 2001-2022 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2001-2024 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# Change bash to expand the next word following aliases ending with a space
|
||||
# that are more than one level deep. Change how bash handles the expand-next-word
|
||||
# flag when recognizing a reserved word.
|
||||
#
|
||||
# Bash never did this before post-bash-5.2
|
||||
|
||||
: ${THIS_SH:=./bash}
|
||||
|
||||
shopt -s expand_aliases 2>/dev/null
|
||||
|
||||
alias a1='echo '
|
||||
alias a2=a1
|
||||
|
||||
alias foo=bar
|
||||
alias x=xtra
|
||||
|
||||
a2 foo
|
||||
unalias foo
|
||||
|
||||
alias e='echo '
|
||||
alias f='foo '
|
||||
alias b=bar
|
||||
|
||||
e f b x
|
||||
|
||||
alias e=echo
|
||||
|
||||
a2 foo;e x
|
||||
|
||||
unalias e f b
|
||||
|
||||
alias e=echo
|
||||
alias foo='bar '
|
||||
alias c=';'
|
||||
|
||||
a2 foo c e x
|
||||
|
||||
unalias foo e c
|
||||
|
||||
alias file='/dev/null ;'
|
||||
alias e=echo
|
||||
alias foo='bar '
|
||||
alias c='< '
|
||||
alias x=xtra
|
||||
a2 foo c file e x
|
||||
|
||||
unalias a1 a2 e foo c x file
|
||||
|
||||
alias foo=bar
|
||||
|
||||
alias al=' '
|
||||
alias foo=bar
|
||||
|
||||
al for foo in v
|
||||
do echo foo=$foo bar=$bar
|
||||
done
|
||||
|
||||
al case foo in foo) echo foo;; bar) echo bar;; esac
|
||||
|
||||
# one difference between bash in default and posix modes is that default mode
|
||||
# bash allows reserved words to be aliased, which posix says is a no-no
|
||||
|
||||
${THIS_SH} -c '
|
||||
shopt -s expand_aliases 2>/dev/null
|
||||
alias al=" "
|
||||
alias foo=bar
|
||||
alias for=echo
|
||||
al for foo in v
|
||||
do echo foo=$foo bar=$bar
|
||||
done' bash
|
||||
|
||||
${THIS_SH} -o posix -c '
|
||||
alias al=" "
|
||||
alias foo=bar
|
||||
alias for=echo
|
||||
al for foo in v
|
||||
do echo foo=$foo bar=$bar
|
||||
done' bash
|
||||
@@ -0,0 +1,38 @@
|
||||
# test expression evaluation with unset variables
|
||||
set -u
|
||||
|
||||
( echo $(( a > 4 )) ; echo after 1 ) # error
|
||||
( echo $(( a[0] > 4 )); echo after 2) # error
|
||||
|
||||
set +u
|
||||
( echo $(( a > 4 )) ; echo after 3 $? )
|
||||
( echo $(( a[0] > 4 )); echo after 4 $?)
|
||||
|
||||
# this is a recursion stack error
|
||||
a=b
|
||||
b=a
|
||||
echo $(( a + 7 ))
|
||||
|
||||
# make sure command printing works for arithmetic expansions and commands
|
||||
set -x
|
||||
var=42
|
||||
|
||||
echo $(( $var ))
|
||||
echo $?
|
||||
|
||||
echo $(( $null ))
|
||||
echo $?
|
||||
|
||||
(( $var ))
|
||||
echo $?
|
||||
|
||||
(( $null ))
|
||||
echo $?
|
||||
|
||||
set +x
|
||||
|
||||
# invalid expressions in different cases
|
||||
x=4+
|
||||
declare -i x
|
||||
x+=7 y=4
|
||||
echo x = $x y = $y
|
||||
@@ -0,0 +1,43 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# Tilde expansion in indexed array assignments; prep for future work
|
||||
HOME=/homes/cj
|
||||
|
||||
declare -a aa
|
||||
aa=([0]=~/Desktop)
|
||||
declare -p aa
|
||||
unset aa
|
||||
|
||||
declare -a aa=([0]=~/Desktop)
|
||||
declare -p aa
|
||||
unset aa
|
||||
|
||||
declare -a aa=([0]=~/Desktop:~/Library:~/Documents)
|
||||
declare -p aa
|
||||
unset aa
|
||||
|
||||
declare -a aa
|
||||
aa=([0]=~/Desktop:~/Library:~/Documents)
|
||||
declare -p aa
|
||||
unset aa
|
||||
|
||||
declare -a aa=([0]=~/Desktop:~/Library:~/Documents [1]=~/Applications)
|
||||
declare -p aa
|
||||
unset aa
|
||||
|
||||
declare -a aa
|
||||
aa=([0]=~/Desktop:~/Library:~/Documents [1]=~/Applications)
|
||||
declare -p aa
|
||||
unset aa
|
||||
@@ -0,0 +1,98 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# change behavior of shell builtins to extend assoc_expand_once to indexed
|
||||
# arrays
|
||||
|
||||
export subscript='$(echo INJECTION! >&2 ; echo 0)'
|
||||
shopt -s array_expand_once
|
||||
|
||||
printf -v a["$subscript"] %s hi
|
||||
declare -p a
|
||||
unset a
|
||||
|
||||
printf -v "a[$subscript]" %s hi
|
||||
declare -p a
|
||||
|
||||
a[0]=hi
|
||||
|
||||
unset a["$subscript"]
|
||||
declare -p a
|
||||
|
||||
unset a
|
||||
|
||||
unset a["$subscript"]
|
||||
declare -p a
|
||||
|
||||
unset -v a
|
||||
read a["$subscript"] <<<hi
|
||||
declare -p a
|
||||
|
||||
declare -a a
|
||||
read a["$subscript"] <<<hi
|
||||
declare -p a
|
||||
|
||||
unset -v a
|
||||
|
||||
declare -a a
|
||||
|
||||
{ sleep 1; exit 12; } & bgpid=$!
|
||||
wait -n -p a["$subscript"] $bgpid
|
||||
|
||||
declare -p a
|
||||
|
||||
unset -v a
|
||||
declare -a a
|
||||
|
||||
declare -i a["$subscript"]=42
|
||||
declare -p a
|
||||
|
||||
# this still won't work because the quotes prevent it from being recognized as
|
||||
# an assignment statement
|
||||
#declare -i "a[$subscript]"=42
|
||||
#declare -p a
|
||||
|
||||
test -v a["$subscript"] && echo set
|
||||
[ -v a["$subscript"] ] && echo set
|
||||
|
||||
let a["$subscript"]+=1
|
||||
unset -v a
|
||||
|
||||
# these are all already arithmetic expression errors
|
||||
|
||||
declare -a a
|
||||
|
||||
(( a[$subscript]++ ))
|
||||
declare -p a
|
||||
: $(( a[$subscript]++ ))
|
||||
declare -p a
|
||||
|
||||
a[$subscript]=hi
|
||||
declare -p a
|
||||
|
||||
# length shortcuts for unset variables, so give it a value
|
||||
a[0]=zero
|
||||
echo ${#a[$subscript]}
|
||||
|
||||
unset -v a
|
||||
|
||||
# compound assignments should not perform double expansion
|
||||
|
||||
a=( [$subscript]=hi )
|
||||
declare -p a
|
||||
|
||||
declare -a a
|
||||
a=( [$subscript]=hi )
|
||||
declare -p a
|
||||
|
||||
unset -v a
|
||||
@@ -0,0 +1,52 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# implicit and explicit variable type conversions
|
||||
|
||||
declare -A A=(x x)
|
||||
declare -p A
|
||||
|
||||
f() { declare -g A=([1]=1); }
|
||||
f
|
||||
|
||||
declare -p A
|
||||
|
||||
unset -f f
|
||||
# error to convert associative to indexed
|
||||
f() { declare -ga A=([1]=1); }
|
||||
f
|
||||
|
||||
# error to convert associative to indexed
|
||||
declare -a A=([1]=1)
|
||||
declare -p A
|
||||
|
||||
unset -v A
|
||||
|
||||
declare -a A=(x x)
|
||||
declare -p A
|
||||
|
||||
# error to convert indexed to associative
|
||||
f() { declare -gA A=([1]=1); }
|
||||
f
|
||||
|
||||
declare -p A
|
||||
|
||||
# error to convert indexed to associative
|
||||
declare -A A=([1]=1)
|
||||
declare -p A
|
||||
|
||||
# can't read into an associative array
|
||||
unset -v A
|
||||
declare -A A
|
||||
read -a A </dev/null
|
||||
@@ -0,0 +1,50 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Problems with tilde expansion of keys and values in bash-5.2
|
||||
|
||||
HOME=/homes/cj
|
||||
|
||||
declare -A aa=([key]=~/Desktop)
|
||||
declare -p aa
|
||||
unset aa
|
||||
|
||||
declare -A aa
|
||||
aa=([key]=~/Desktop)
|
||||
declare -p aa
|
||||
unset aa
|
||||
|
||||
declare -A aa=([key]=~/Desktop [k2]=~/Library )
|
||||
declare -p aa
|
||||
unset aa
|
||||
|
||||
declare -A aa=([~/key]=~/Desktop)
|
||||
declare -p aa
|
||||
unset aa
|
||||
|
||||
declare -A aa
|
||||
aa=([~/key]=~/Desktop)
|
||||
aa[~/Documents]=~/Library
|
||||
declare -p aa
|
||||
unset aa
|
||||
|
||||
declare -A aa
|
||||
aa=([~/key]=~/Desktop:~/Documents:~/Applications)
|
||||
aa[~/Documents]=~/Library
|
||||
declare -p aa
|
||||
unset aa
|
||||
|
||||
declare -A aa=([~/key]=~/Desktop:~/Documents:~/Applications [~/Documents]=~/Library)
|
||||
declare -p aa
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# have to run through sed or grep to filter out version information
|
||||
|
||||
# let's exercise print-help
|
||||
help -x
|
||||
|
||||
help -- | sed 1d
|
||||
|
||||
command help -s help
|
||||
builtin help -d shift
|
||||
shift --help
|
||||
help -s builtin shift
|
||||
|
||||
# this hasn't ever been very useful
|
||||
help -s 'read*'
|
||||
# but prefix matching is
|
||||
help -s rea
|
||||
|
||||
help :
|
||||
|
||||
help -m : | grep -v version
|
||||
|
||||
LC_ALL=en_US.UTF-8
|
||||
help -- | sed 1d
|
||||
|
||||
# maybe sometime in the future this will do something
|
||||
help -- bash
|
||||
@@ -0,0 +1,45 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# ulimit tests
|
||||
|
||||
ulimit unlimited # default to -f
|
||||
ulimit -f # better be unlimited
|
||||
ulimit -Sf hard
|
||||
|
||||
corelim=${ ulimit -c; }
|
||||
|
||||
# pick -c because everyone's going to have it
|
||||
ulimit -Sc unlimited
|
||||
ulimit -c soft
|
||||
ulimit -c # unlimited
|
||||
# maybe someday the leading `+' will be accepted, but not today
|
||||
ulimit -c -S -- +1999
|
||||
ulimit -c -S -- 1999
|
||||
ulimit -c 0
|
||||
ulimit -Hc # hard and soft 0
|
||||
ulimit -Sc hard # should be 0
|
||||
ulimit -c
|
||||
|
||||
ulimit -a >/dev/null # just make sure we have no errors
|
||||
|
||||
# these are errors
|
||||
ulimit -g
|
||||
# have to see about this one
|
||||
ulimit -u $(( 2**31 - 1 ))
|
||||
|
||||
lim=$(ulimit -Sn)
|
||||
ulimit -n $lim
|
||||
lim2=$(ulimit -n)
|
||||
|
||||
[[ $lim -eq $lim2 ]] || echo 'ulimit: setting to soft limit fails' >&2
|
||||
@@ -0,0 +1,40 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# pushd/popd/dirs tests
|
||||
|
||||
cd /bin
|
||||
pushd /tmp
|
||||
dirs --
|
||||
|
||||
pushd --
|
||||
pushd -x
|
||||
|
||||
popd --
|
||||
popd -x
|
||||
|
||||
pushd /
|
||||
popd dir # error
|
||||
|
||||
dirs -p
|
||||
pushd --
|
||||
|
||||
pushd /bin
|
||||
|
||||
# out of range errors
|
||||
popd -8
|
||||
popd +8
|
||||
|
||||
# this needs a fix to work right
|
||||
popd -- +8
|
||||
popd -- -8
|
||||
@@ -0,0 +1,85 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
umask 022
|
||||
umask u=r+w
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask u=r-w
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask g+u,o+rwx-u
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask u=r+w,g=wx,o+xr
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask u+w=r+x
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask o=u
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask g=u
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask u=rwx,u-w
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask u=xwr
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask +xwr
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask a+xwr
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask +xr
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask a+xr
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask g+X
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask o+X
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask +X
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask g+x,o+x
|
||||
umask -S
|
||||
|
||||
umask 022
|
||||
umask u+g,g+o,o-rw
|
||||
umask -S
|
||||
@@ -0,0 +1,59 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# hash printing, deleting tests
|
||||
hash -r # start with empty hash table
|
||||
hash # should be error/warning
|
||||
|
||||
hash -d notthere
|
||||
echo $?
|
||||
|
||||
hash -p /nosuchdir/nosuchfile cat
|
||||
|
||||
hash -t cat
|
||||
hash -lt cat
|
||||
hash -l
|
||||
|
||||
hash -d cat
|
||||
|
||||
hash -d notthere
|
||||
|
||||
hash -lt notthere
|
||||
hash -t notthere
|
||||
|
||||
hash -t cat 2>/dev/null
|
||||
echo $?
|
||||
|
||||
# this should fail
|
||||
hash -p /nosuchdir/nosuchfile cat
|
||||
cat </dev/null
|
||||
echo $?
|
||||
hash -t cat
|
||||
echo $?
|
||||
|
||||
# but with checkhash set, it should not
|
||||
shopt -s checkhash
|
||||
cat </dev/null
|
||||
echo $?
|
||||
{ hash -t cat | grep cat >/dev/null; } && echo found
|
||||
|
||||
hash -r
|
||||
hash -p / root
|
||||
|
||||
hash -r
|
||||
|
||||
# assignment to BASH_CMDS[x] should be like hash -p
|
||||
BASH_CMDS[cat]=/nosuchfile
|
||||
hash -lt cat
|
||||
hash -d cat
|
||||
@@ -0,0 +1,192 @@
|
||||
aa bb cc dd
|
||||
AAaa bb cc ddBB
|
||||
aa bb cc dd
|
||||
aa bb cc dd
|
||||
DDDDDaa bb cc ddEEEEE
|
||||
aa bb cc dd
|
||||
outside: 42
|
||||
aa bb cc dd
|
||||
outside:
|
||||
assignment: 12
|
||||
func ()
|
||||
{
|
||||
echo func-inside
|
||||
}
|
||||
abcde
|
||||
67890
|
||||
12345
|
||||
argv[1] = <>
|
||||
argv[1] = <>
|
||||
aa,bb
|
||||
JOBaa bb cc ddCONTROL
|
||||
./comsub2.tests: line 68: p: command not found
|
||||
NOTFOUND
|
||||
./comsub2.tests: line 75: p: command not found
|
||||
./comsub2.tests: line 75: p: command not found
|
||||
expand_aliases off
|
||||
expand_aliases off
|
||||
outside:
|
||||
./comsub2.tests: line 79: alias: p: not found
|
||||
alias e='echo inside redefine'
|
||||
expand_aliases off
|
||||
1
|
||||
expand_aliases on
|
||||
2
|
||||
expand_aliases on
|
||||
outside:
|
||||
./comsub2.tests: line 89: alias: p: not found
|
||||
expand_aliases on
|
||||
1
|
||||
xx
|
||||
expand_aliases on
|
||||
2
|
||||
xx
|
||||
expand_aliases on
|
||||
outside:
|
||||
expand_aliases on
|
||||
inside: 12 22 42
|
||||
outside: 42 2
|
||||
newlines
|
||||
|
||||
|
||||
outside: 42
|
||||
before: 1 2
|
||||
after: 2
|
||||
before: 1 2
|
||||
after: 2
|
||||
before: 1 2
|
||||
after: 1 2
|
||||
XnestedY
|
||||
a nested b
|
||||
one two
|
||||
42
|
||||
42
|
||||
42
|
||||
123
|
||||
123
|
||||
0
|
||||
123
|
||||
123
|
||||
0
|
||||
Mon Aug 29 20:03:02 EDT 2022
|
||||
Mon Aug 29 20:03:02 EDT 2022
|
||||
Mon Aug 29 20:03:02 EDT 2022
|
||||
Mon Aug 29 20:03:02 EDT 2022
|
||||
123
|
||||
before 123
|
||||
in for 123
|
||||
outside before: value
|
||||
inside before: value
|
||||
inside after: funsub
|
||||
inside: after false xxx
|
||||
outside after: funsub
|
||||
=====posix mode=====
|
||||
outside before: value
|
||||
.
|
||||
declare -a a=([0]="1" [1]="2" [2]="3" [3]="4")
|
||||
declare -- int="2"
|
||||
after here-doc: 1
|
||||
[1]- Running sleep 1 &
|
||||
[2]+ Running sleep 1 &
|
||||
[1]- Running sleep 1 &
|
||||
[2]+ Running sleep 1 &
|
||||
17772 26794
|
||||
17772 26794
|
||||
we should try rhs
|
||||
comsub
|
||||
and
|
||||
funsub
|
||||
in here-documents
|
||||
after all they work here
|
||||
and work here
|
||||
a b c == 1 2 3
|
||||
== 1 2 3
|
||||
before return
|
||||
after func
|
||||
1 2 3a b c
|
||||
2 2
|
||||
foobara b c
|
||||
declare -- IFS=" "
|
||||
*???
|
||||
*???
|
||||
yyy zzzz
|
||||
argv[1] = <AA^ABB>
|
||||
argv[1] = <AA^OBB>
|
||||
argv[1] = <AA^?BB>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <AA^ABB>
|
||||
argv[1] = <AA^ABB>
|
||||
argv[1] = <AA^OBB>
|
||||
argv[1] = <AA^OBB>
|
||||
argv[1] = <AA^?BB>
|
||||
argv[1] = <AA^?BB>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^A>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <^?>
|
||||
argv[1] = <AA^ABB>
|
||||
argv[1] = <AA>
|
||||
argv[2] = <BB>
|
||||
argv[1] = <AA^ABB>
|
||||
argv[1] = <AA>
|
||||
argv[2] = <BB>
|
||||
argv[1] = <AA^?BB>
|
||||
argv[1] = <AA>
|
||||
argv[2] = <BB>
|
||||
argv[1] = <AA^?BB>
|
||||
argv[1] = <AA>
|
||||
argv[2] = <BB>
|
||||
argv[1] = <AA BB>
|
||||
argv[1] = <AA>
|
||||
argv[2] = <BB>
|
||||
argv[1] = <AA BB>
|
||||
argv[1] = <AA BB>
|
||||
argv[1] = <AA BB>
|
||||
argv[1] = <AA>
|
||||
argv[2] = <BB>
|
||||
argv[1] = <AA BB>
|
||||
argv[1] = <AA BB>
|
||||
inside1-inside2-outside
|
||||
BEFOREAA
|
||||
BB
|
||||
CC
|
||||
AFTER
|
||||
BEFOREAA
|
||||
BB
|
||||
CC
|
||||
AFTER
|
||||
unbalanced braces}}
|
||||
combined comsubs
|
||||
combined comsubs
|
||||
inside
|
||||
after: var = inside
|
||||
after: 42 var = inside
|
||||
var=inside 42
|
||||
after: 0 var = inside
|
||||
@@ -0,0 +1,153 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# initial set of tests for ${Ccommand; } nofork command substitution
|
||||
|
||||
# basic functionality
|
||||
|
||||
echo ${ printf '%s\n' aa bb cc dd; }
|
||||
echo AA${ printf '%s\n' aa bb cc dd; }BB
|
||||
|
||||
echo ${ printf '%s\n' aa bb cc dd; return; echo ee ff; }
|
||||
echo ${ printf '%s\n' aa bb cc dd
|
||||
}
|
||||
echo DDDDD${
|
||||
printf '%s\n' aa bb cc dd
|
||||
}EEEEE
|
||||
unset x
|
||||
echo ${ printf '%s\n' aa bb cc dd; x=42 ; return 12; echo ee ff; }
|
||||
echo outside: $x
|
||||
unset x
|
||||
echo ${ local x; printf '%s\n' aa bb cc dd; x=42 ; return 12; echo ee ff; }
|
||||
echo outside: $x
|
||||
xx=${ local x; printf '%s\n' aa bb cc dd; x=42 ; return 12; echo ee ff; }
|
||||
echo assignment: $?
|
||||
unset xx
|
||||
|
||||
declare -i x
|
||||
y=${ :;}
|
||||
declare -i z
|
||||
unset -v x y z
|
||||
|
||||
# variables can be local, but all function declarations are global
|
||||
func() { echo func-outside; }
|
||||
xx=${ func() { echo func-inside; }; }
|
||||
declare -f func
|
||||
xx=${ unset -f func; }
|
||||
declare -f func
|
||||
|
||||
echo ${ ( echo abcde );}
|
||||
|
||||
echo ${| echo 67890; REPLY=12345; } # works in mksh
|
||||
x=${| REPLY= ;}
|
||||
recho "$x"
|
||||
unset x
|
||||
x=${| :;}
|
||||
recho "$x"
|
||||
unset x
|
||||
|
||||
echo ${ echo aa; },${ echo bb; }
|
||||
|
||||
# basic job control
|
||||
set -m
|
||||
echo this should disappear | echo JOB${ printf '%s\n' aa bb cc dd; }CONTROL | cat
|
||||
set +m
|
||||
|
||||
# command not found should still echo error messages to stderr
|
||||
echo NOT${ p; }FOUND
|
||||
|
||||
# alias handling in command substitutions, default and posix mode
|
||||
alias p=printf
|
||||
alias e='echo aliasval'
|
||||
echo "${ typeset x;
|
||||
for f in 1 2; do p '%s\n' $f ; shopt expand_aliases; done
|
||||
unalias p
|
||||
alias e='echo inside redefine'
|
||||
x=42 ; return; echo this should not be seen; }"
|
||||
echo outside: $x
|
||||
alias p e
|
||||
shopt expand_aliases
|
||||
|
||||
alias p=printf
|
||||
set -o posix
|
||||
echo "${ typeset x;
|
||||
for f in 1 2; do p '%s\n' $f ; shopt expand_aliases; done
|
||||
unalias p;
|
||||
x=42 ; return; echo this should not be seen; }"
|
||||
echo outside: $x
|
||||
alias p
|
||||
shopt expand_aliases
|
||||
|
||||
set +o posix
|
||||
|
||||
shopt -s expand_aliases
|
||||
|
||||
alias p=printf
|
||||
echo "${ typeset x;
|
||||
for f in 1 2; do p '%s\n' $f ; /bin/echo xx ; shopt expand_aliases; done
|
||||
x=42 ; return; echo ee ff; }"
|
||||
echo outside: $x
|
||||
shopt expand_aliases
|
||||
|
||||
# more tests for value substitutions and local variables
|
||||
a=1 b=2
|
||||
a=${| local b ; a=12 ; b=22 ; REPLY=42 ; echo inside: $a $b $REPLY; }
|
||||
echo outside: $a $b
|
||||
unset a b
|
||||
|
||||
# this form doesn't remove the trailing newlines
|
||||
REPLY=42
|
||||
a=${| REPLY=$'newlines\n\n'; }
|
||||
echo "$a"
|
||||
echo outside: $REPLY
|
||||
|
||||
# how do we handle shift with these weird ksh93 function-like semantics?
|
||||
# ksh93 doesn't reset the positional parameters here
|
||||
set -- 1 2
|
||||
echo before: "$@"
|
||||
: "${ shift;}"
|
||||
echo after: "$@"
|
||||
|
||||
set -- 1 2
|
||||
echo before: "$@"
|
||||
: "${| shift;}"
|
||||
echo after: "$@"
|
||||
|
||||
set -- 1 2
|
||||
echo before: "$@"
|
||||
: "${ ( shift) }" # parse_comsub adds the closing semicolon anyway
|
||||
echo after: "$@"
|
||||
|
||||
# nested funsubs
|
||||
echo ${ echo X${ echo nested; }Y; }
|
||||
echo ${ echo a ; echo ${ echo nested; }; echo b; }
|
||||
|
||||
# nested funsubs/comsubs
|
||||
x=${
|
||||
echo ${ echo one;} $(echo two)
|
||||
}
|
||||
echo $x
|
||||
|
||||
# mixing funsubs and arithmetic expansion
|
||||
echo $(( ${ echo 24 + 18; }))
|
||||
echo $(( ${ echo 14 + 18; }+ 10))
|
||||
echo ${ echo $(( 24+18 )); }
|
||||
|
||||
# alias expansion and nested funsubs in other constructs
|
||||
${THIS_SH} ./comsub21.sub
|
||||
${THIS_SH} ./comsub22.sub
|
||||
${THIS_SH} ./comsub23.sub
|
||||
${THIS_SH} ./comsub24.sub
|
||||
${THIS_SH} ./comsub25.sub
|
||||
${THIS_SH} ./comsub26.sub
|
||||
@@ -0,0 +1,65 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# posix-mode alias expansion in nofork command substitutions within
|
||||
# other constructs
|
||||
|
||||
DATE='Mon Aug 29 20:03:02 EDT 2022'
|
||||
shopt -s expand_aliases
|
||||
|
||||
alias number="echo 123"
|
||||
|
||||
echo ${ number; }
|
||||
echo $(( ${ number; } ))
|
||||
(( ${ number; } )) ; echo $?
|
||||
|
||||
set -o posix
|
||||
echo ${ number; }
|
||||
echo $(( ${ number; } ))
|
||||
(( ${ number; } )) ; echo $?
|
||||
set +o posix
|
||||
|
||||
# have to turn it back on after leaving posix mode
|
||||
shopt -s expand_aliases
|
||||
|
||||
alias my_alias='echo $DATE'
|
||||
|
||||
echo ${ eval my_alias; }
|
||||
echo ${ my_alias; }
|
||||
|
||||
set -o posix
|
||||
echo ${ eval my_alias; }
|
||||
echo ${ my_alias; }
|
||||
set +o posix ; shopt -s expand_aliases
|
||||
|
||||
alias e=echo
|
||||
alias v='e 123'
|
||||
|
||||
set -o posix
|
||||
echo ${ v; }
|
||||
echo ${ echo before ; v; }
|
||||
echo ${ for f in 0; do
|
||||
echo in for
|
||||
done; v; }
|
||||
set +o posix ; shopt -s expand_aliases
|
||||
|
||||
alias let='let --'
|
||||
|
||||
let '1 == 1'
|
||||
: ${ let '1 == 1'; }
|
||||
|
||||
set -o posix
|
||||
let '1 == 1'
|
||||
: ${ let '1 == 1'; }
|
||||
set +o posix ; shopt -s expand_aliases
|
||||
@@ -0,0 +1,26 @@
|
||||
# tests for inheriting set -e into command substitutions
|
||||
|
||||
set -e
|
||||
var=value
|
||||
echo "outside before: $var"
|
||||
echo "${
|
||||
echo "inside before: $var"
|
||||
var=funsub
|
||||
echo "inside after: $var"
|
||||
false;
|
||||
echo inside: after false
|
||||
}" xxx
|
||||
echo "outside after: $var"
|
||||
|
||||
set -o posix
|
||||
echo =====posix mode=====
|
||||
var=value
|
||||
echo "outside before: $var"
|
||||
echo "${
|
||||
echo "inside before: $var"
|
||||
var=funsub
|
||||
echo "inside after: $var"
|
||||
false;
|
||||
echo inside: after false
|
||||
}" xxx
|
||||
echo "outside after: $var"
|
||||
@@ -0,0 +1,79 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# more odds and ends for nofork command substitution
|
||||
|
||||
# make sure parsing is right within conditional commands
|
||||
[[ ${ echo -n "[${ echo -n foo; }]" ; } == '[foo]' ]] || echo bad 1
|
||||
[[ "${ echo -n "[${ echo -n foo; }]" ; }" == '[foo]' ]] || echo bad 1
|
||||
|
||||
# mix multiple calls to parse_and_execute
|
||||
got=$(eval 'x=${ for i in test; do case $i in test) echo .;; esac; done; }' ; echo $x)
|
||||
echo $got
|
||||
|
||||
# mix compound assignment and nofork command substitution
|
||||
: ${ a=(1 2 3 ${ echo 4;} ); }
|
||||
declare -p a
|
||||
unset a
|
||||
|
||||
# function execution with side effects
|
||||
int=0
|
||||
incr()
|
||||
{
|
||||
echo incr: $int
|
||||
(( int++ ))
|
||||
}
|
||||
: ${ incr; }
|
||||
: ${ incr; }
|
||||
declare -p int
|
||||
|
||||
# expansion inside here-document body
|
||||
int=0
|
||||
: <<EOF
|
||||
${ incr; }
|
||||
EOF
|
||||
echo after here-doc: $int
|
||||
|
||||
# jobs list in nofork command substitution
|
||||
sleep 1 &
|
||||
sleep 1 &
|
||||
|
||||
jl1=${ jobs; }
|
||||
printf '%s\n' "$jl1"
|
||||
|
||||
jl2=${ jobs; }
|
||||
printf '%s\n' "$jl2"
|
||||
|
||||
# nofork command substitution doesn't affect the shell's random number sequence
|
||||
RANDOM=42
|
||||
echo $RANDOM ${ echo $RANDOM; }
|
||||
|
||||
RANDOM=42
|
||||
echo $RANDOM $RANDOM
|
||||
|
||||
# here-documents and other word expansions with comsub/funsub on the rhs
|
||||
|
||||
exec 4<<EOF
|
||||
we should try rhs
|
||||
${word-$(echo comsub)}
|
||||
and
|
||||
${word-${ echo funsub; }}
|
||||
in here-documents
|
||||
EOF
|
||||
|
||||
cat <&4
|
||||
exec 4<&-
|
||||
|
||||
echo after all they ${word-$(echo work here)}
|
||||
echo and ${word-${ echo work here; }}
|
||||
@@ -0,0 +1,77 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# test function calling in nofork comsubs
|
||||
set -- 1 2 3
|
||||
|
||||
func()
|
||||
{
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
x=${ func a b c; }
|
||||
echo "$x" == "$@"
|
||||
|
||||
x=${ func; }
|
||||
echo "$x" == "$@"
|
||||
|
||||
unset -f func
|
||||
func()
|
||||
{
|
||||
echo before return
|
||||
return 12
|
||||
echo after return
|
||||
}
|
||||
|
||||
x=${ func; echo after func; }
|
||||
echo "$x"
|
||||
|
||||
unset -f func
|
||||
unset x
|
||||
set --
|
||||
|
||||
# more shift and order-of-expansion tests
|
||||
set -- 1 2 3
|
||||
echo "$*${ set -- a b c;}$*"
|
||||
|
||||
set -- 1 2
|
||||
x=${ shift; echo "$@"; }
|
||||
echo $x "$@"
|
||||
|
||||
# order of expansion
|
||||
|
||||
echo "${ IFS= ; echo foo; }${ unset IFS; echo bar;}${ IFS=' '; echo a b c;}"
|
||||
declare -p IFS
|
||||
|
||||
IFS=$' \t\n'
|
||||
|
||||
: ${TMPDIR:=/tmp}
|
||||
TDIR=$TMPDIR/comsub24-$$
|
||||
[ -d "${TDIR}" ] || mkdir "${TDIR}"
|
||||
cd "${TDIR}" || {
|
||||
echo "comsub24: cannot cd to ${TDIR}"
|
||||
exit 2
|
||||
}
|
||||
touch xx yy zz
|
||||
|
||||
echo "${ set -f; echo '*';}${ set +f; echo '???'; }"
|
||||
echo ${ set -f; echo '*';}${ set +f; echo '???'; }
|
||||
|
||||
rm xx yy zz
|
||||
touch xx yyy zzzz
|
||||
|
||||
echo ${ set -f; echo '*';}${ set +f; echo '???'; }
|
||||
|
||||
cd $OLDPWD
|
||||
rm -rf $TDIR
|
||||
@@ -0,0 +1,138 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# tests of internal quoting characters in read_comsub and comsub_quote_string
|
||||
|
||||
CTLESC=$'\001'
|
||||
CTLNUL=$'\177'
|
||||
|
||||
x=${| REPLY=$'AA\001BB' ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
|
||||
x=${| REPLY=$'AA\017BB' ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
|
||||
x=${| REPLY=$'AA\177BB' ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
|
||||
x=${| REPLY=$'\001' ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
x=${| REPLY="" ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
x=${| REPLY= ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
x=${| REPLY=$CTLESC ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
x=${| REPLY="$CTLESC" ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
x="${| REPLY="$CTLESC" ; }"
|
||||
recho "$x"
|
||||
unset x
|
||||
|
||||
x=${| REPLY=$'\177' ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
x=${| REPLY="" ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
x=${| REPLY= ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
x=${| REPLY=$CTLNUL ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
x=${| REPLY="$CTLNUL" ; }
|
||||
recho "$x"
|
||||
unset x
|
||||
x="${| REPLY="$CTLNUL" ; }"
|
||||
recho "$x"
|
||||
unset x
|
||||
|
||||
recho "${ echo $'AA\001BB' ; }"
|
||||
recho ${ echo $'AA\001BB' ; }
|
||||
|
||||
recho "${ echo $'AA\017BB' ; }"
|
||||
recho ${ echo $'AA\017BB' ; }
|
||||
|
||||
recho "${ echo $'AA\177BB' ; }"
|
||||
recho ${ echo $'AA\177BB' ; }
|
||||
|
||||
recho "${ echo $'\001' ; }"
|
||||
recho ${ echo $'\001' ; }
|
||||
|
||||
recho "${ echo "" ; }"
|
||||
recho ${ echo "" ; }
|
||||
recho "${ echo ; }"
|
||||
recho ${ echo ; }
|
||||
|
||||
recho "${ echo $CTLESC ; }"
|
||||
recho ${ echo $CTLESC ; }
|
||||
recho ${ echo "$CTLESC" ; }
|
||||
recho "${ echo "$CTLESC" ; }"
|
||||
|
||||
recho "${ echo $'\177' ; }"
|
||||
recho ${ echo $'\177' ; }
|
||||
|
||||
recho "${ echo "" ; }"
|
||||
recho ${ echo "" ; }
|
||||
recho "${ echo ; }"
|
||||
recho ${ echo ; }
|
||||
recho "${ echo $CTLNUL ; }"
|
||||
recho ${ echo $CTLNUL ; }
|
||||
recho "${ echo "$CTLNUL" ; }"
|
||||
recho ${ echo "$CTLNUL" ; }
|
||||
|
||||
IFS=$CTLESC
|
||||
x=${| REPLY=$'AA\001BB' ; }
|
||||
recho "$x"
|
||||
recho $x
|
||||
unset x
|
||||
|
||||
recho "${ echo $'AA\001BB' ; }"
|
||||
recho ${ echo $'AA\001BB' ; }
|
||||
|
||||
IFS=$CTLNUL
|
||||
x=${| REPLY=$'AA\177BB' ; }
|
||||
recho "$x"
|
||||
recho $x
|
||||
unset x
|
||||
|
||||
recho "${ echo $'AA\177BB' ; }"
|
||||
recho ${ echo $'AA\177BB' ; }
|
||||
|
||||
unset IFS
|
||||
x=${| REPLY=AA" "BB ; }
|
||||
recho "$x"
|
||||
recho $x
|
||||
|
||||
IFS=
|
||||
recho "$x"
|
||||
recho $x
|
||||
unset x
|
||||
|
||||
unset IFS
|
||||
recho "${ echo AA" "BB ; }"
|
||||
recho ${ echo AA" "BB ; }
|
||||
|
||||
IFS=
|
||||
recho "${ echo AA" "BB ; }"
|
||||
recho ${ echo AA" "BB ; }
|
||||
@@ -0,0 +1,36 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# more tests for nofork comsub functionality
|
||||
|
||||
REPLY=outside
|
||||
|
||||
echo ${| REPLY=inside1; }-${| REPLY=inside2; }-$REPLY
|
||||
|
||||
echo "BEFORE${| printf -v REPLY '%s\n' AA BB CC; }AFTER"
|
||||
echo "BEFORE${| printf -v REPLY $'%s\n' AA BB CC; }AFTER"
|
||||
|
||||
echo ${ echo unbalanced braces; }}}
|
||||
|
||||
echo $(echo combined ${| REPLY=comsubs; })
|
||||
echo ${ echo $(echo combined ${| REPLY=comsubs; }); }
|
||||
|
||||
var=outside
|
||||
echo ${ var=inside; echo $var; }
|
||||
echo after: var = $var
|
||||
|
||||
( echo ${ echo var=inside; exit 42 ; echo var=inside2; } )
|
||||
echo after: $? var = $var
|
||||
|
||||
( echo ${ echo var=inside; return 42 ; echo var=inside2; } $? )
|
||||
echo after: $? var = $var
|
||||
@@ -0,0 +1,64 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# posix-mode alias expansion in command substitutions within other constructs
|
||||
|
||||
DATE='Mon Aug 29 20:03:02 EDT 2022'
|
||||
shopt -s expand_aliases
|
||||
|
||||
alias number="echo 123"
|
||||
|
||||
echo $(number)
|
||||
echo $(( $(number) ))
|
||||
(( $(number) )) ; echo $?
|
||||
|
||||
set -o posix
|
||||
echo $(number)
|
||||
echo $(( $(number) ))
|
||||
(( $(number) )) ; echo $?
|
||||
set +o posix
|
||||
|
||||
# have to turn it back on after leaving posix mode
|
||||
shopt -s expand_aliases
|
||||
|
||||
alias my_alias='echo $DATE'
|
||||
|
||||
echo $(eval my_alias)
|
||||
echo $(my_alias)
|
||||
|
||||
set -o posix
|
||||
echo $(eval my_alias)
|
||||
echo $(my_alias)
|
||||
set +o posix ; shopt -s expand_aliases
|
||||
|
||||
alias e=echo
|
||||
alias v='e 123'
|
||||
|
||||
set -o posix
|
||||
echo $(v)
|
||||
echo $(echo before ; v)
|
||||
echo $(for f in 0; do
|
||||
echo in for
|
||||
done; v)
|
||||
set +o posix ; shopt -s expand_aliases
|
||||
|
||||
alias let='let --'
|
||||
|
||||
let '1 == 1'
|
||||
: $(let '1 == 1')
|
||||
|
||||
set -o posix
|
||||
let '1 == 1'
|
||||
: $(let '1 == 1')
|
||||
set +o posix ; shopt -s expand_aliases
|
||||
@@ -0,0 +1,28 @@
|
||||
: ${THIS_SH:=./bash}
|
||||
|
||||
# all parse errors
|
||||
${THIS_SH} -c '[[ ( -n xx' bash
|
||||
${THIS_SH} -c '[[ ( -n xx )' bash
|
||||
|
||||
${THIS_SH} -c '[[ ( -t X ) ]' bash
|
||||
|
||||
${THIS_SH} -c '[[ -n &' bash
|
||||
${THIS_SH} -c '[[ -n XX &' bash
|
||||
${THIS_SH} -c '[[ -n XX & ]' bash
|
||||
|
||||
${THIS_SH} -c '[[ 4 & ]]' bash
|
||||
${THIS_SH} -c '[[ 4 > & ]]' bash
|
||||
|
||||
${THIS_SH} -c '[[ & ]]' bash
|
||||
${THIS_SH} -c '[[ -Q 7 ]]' bash
|
||||
${THIS_SH} -c '[[ -n < ]]' bash
|
||||
|
||||
# let's see what failed cond commands do with ERR trap
|
||||
trap 'echo ERR: $LINENO: -$BASH_COMMAND- failed' ERR
|
||||
[[ -n $unset ]]
|
||||
|
||||
func()
|
||||
{
|
||||
[[ -z nonempty ]]
|
||||
}
|
||||
func
|
||||
@@ -0,0 +1,19 @@
|
||||
# printing conditional commands for xtrace
|
||||
|
||||
set -x
|
||||
|
||||
# error
|
||||
[[ -t X ]]
|
||||
# null operand
|
||||
[[ $b > 7 ]]
|
||||
|
||||
# successful unary operator
|
||||
[[ -n X ]]
|
||||
|
||||
# successful binary operator
|
||||
ivar=42
|
||||
[[ $ivar -eq 42 ]]
|
||||
|
||||
# compound operator, displayed as two unary expressions
|
||||
|
||||
[[ -n a && -n b ]]
|
||||
@@ -0,0 +1,98 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
set aa bb cc -- dd ; f=$'\1' IFS=$f
|
||||
|
||||
recho "$f$*$f"
|
||||
recho "$f--$f"
|
||||
|
||||
[[ $f$*$f == *$f--$f* ]] && echo ok 1
|
||||
[[ $f$*$f == "$f--$f" ]] || echo ok 2
|
||||
|
||||
[[ ${f}${*}${f} == *$f--$f* ]] && echo ok 3
|
||||
|
||||
[[ $f$*$f == $f$*$f ]] && echo ok 4
|
||||
[[ ${f}${*}${f} == $f$*$f ]] && echo ok 5
|
||||
[[ $f$*$f == *--* ]] && echo ok 6
|
||||
|
||||
[[ $* == $* ]] && echo ok 7
|
||||
[[ $* == ${*} ]] && echo ok 8
|
||||
[[ $f == $f ]] && echo ok 9
|
||||
[[ $f == ${f} ]] && echo ok 10
|
||||
|
||||
# now with f an array and $f -> ${f[0]}
|
||||
|
||||
set aa bb cc -- dd ; f=( $'\1' )
|
||||
|
||||
[[ $f$*$f == *$f--$f* ]] && echo ok 11
|
||||
[[ ${f}${*}${f} == *$f--$f* ]] && echo ok 12
|
||||
[[ $f$*$f == $f$*$f ]] && echo ok 13
|
||||
[[ ${f}${*}${f} == $f$*$f ]] && echo ok 14
|
||||
[[ $f$*$f == *--* ]] && echo ok 15
|
||||
|
||||
[[ $* == $* ]] && echo ok 16
|
||||
[[ $* == ${*} ]] && echo ok 17
|
||||
[[ $f == $f ]] && echo ok 18
|
||||
[[ $f == ${f} ]] && echo ok 19
|
||||
|
||||
# now use an array instead of $*
|
||||
A=( aa bb cc -- dd ); f=$'\1' IFS=$f
|
||||
|
||||
[[ $f${A[*]}$f == $f${A[*]}$f ]] && echo ok 20
|
||||
[[ $f${A[*]}$f == *--* ]] && echo ok 21
|
||||
[[ ${f}${A[*]}${f} == *$f--$f* ]] && echo ok 22
|
||||
|
||||
[[ ${f}${A[*]}${f} == $f${A[*]}$f ]] && echo ok 23
|
||||
[[ ${A[*]} == ${A[*]} ]] && echo ok 24
|
||||
|
||||
# now test $N/${N}/${A[N]}
|
||||
set aa bb $'\1' cc -- dd ; f=$'\1' IFS=$f
|
||||
|
||||
[[ $3$*$3 == $3$*$3 ]] && echo ok 25
|
||||
[[ $3$*$3 == ${3}${*}${3} ]] && echo ok 26
|
||||
[[ $3$*$3 == $3${*}${3} ]] && echo ok 27
|
||||
[[ $* == *$3* ]]&& echo ok 28
|
||||
[[ $* == *${3}* ]]&& echo ok 29
|
||||
|
||||
# now use an array instead of $*
|
||||
A=( aa bb $'\1' cc -- dd )
|
||||
|
||||
[[ ${A[2]}${A[*]}${A[2]} == ${A[2]}${A[*]}${A[2]} ]] && echo ok 30
|
||||
[[ ${A[2]}$*${A[2]} == ${A[2]}${*}${A[2]} ]] && echo ok 31
|
||||
[[ ${A[2]}$*${A[2]} == ${A[2]}${*}${A[2]} ]] && echo ok 32
|
||||
[[ $* == *${A[2]}* ]]&& echo ok 33
|
||||
[[ $* == *${A[2]}* ]]&& echo ok 34
|
||||
|
||||
unset -v A
|
||||
|
||||
set -- aa bb cc -- dd
|
||||
case $* in
|
||||
"$*") echo ok 35;;
|
||||
*) echo bad 35;;
|
||||
esac
|
||||
|
||||
case $f in
|
||||
$f) echo ok 36;;
|
||||
*) echo bad 36;;
|
||||
esac
|
||||
|
||||
case $f$*$f in
|
||||
$f"$*"$f) echo ok 37;;
|
||||
*) echo bad 37;;
|
||||
esac
|
||||
|
||||
case $f$*$f in
|
||||
*$f--$f*) echo ok 38;;
|
||||
*) echo bad 38;;
|
||||
esac
|
||||
@@ -0,0 +1,70 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
: ${THIS_SH:=$PWD/bash} ${TMPDIR:=/tmp}
|
||||
POSIX_SH="${THIS_SH} -o posix"
|
||||
|
||||
# these are the posix special builtins that take a numeric argument
|
||||
|
||||
echo invalid numeric argument
|
||||
# default mode
|
||||
for b in exit break continue shift; do
|
||||
BUILTIN=$b ${THIS_SH} -c 'set -- a b c; (exit 45); for f in _; do $BUILTIN abcde; done; echo after $BUILTIN: $?' bash
|
||||
done
|
||||
${THIS_SH} -c 'func() { return abcde; echo in func: $?; }; func; echo after return: $?' bash
|
||||
|
||||
# posix mode
|
||||
for b in exit break continue shift; do
|
||||
BUILTIN=$b ${POSIX_SH} -c 'set -- a b c; (exit 45); for f in _; do $BUILTIN abcde; done; echo after $BUILTIN: $?' bash
|
||||
done
|
||||
${POSIX_SH} -c 'func() { return abcde; echo in func: $?; }; func; echo after return: $?' bash
|
||||
|
||||
# non-special builtins, no difference
|
||||
set -o history
|
||||
HISTFILE=/dev/null
|
||||
echo a >/dev/null
|
||||
echo b >/dev/null
|
||||
echo c >/dev/null
|
||||
history abcde
|
||||
echo after history: $?
|
||||
history 10 42
|
||||
echo after history: $?
|
||||
set +o history
|
||||
|
||||
# too many arguments
|
||||
|
||||
echo too many arguments
|
||||
|
||||
TDIR=$TMPDIR/errors-$$
|
||||
TFILE=errors
|
||||
mkdir $TDIR || exit 1
|
||||
cd $TDIR
|
||||
|
||||
cat <<\EOF >$TFILE
|
||||
set -- a b c
|
||||
(exit 45)
|
||||
for f in _; do $BUILTIN 42 abcde; done
|
||||
echo after $BUILTIN: $?
|
||||
EOF
|
||||
|
||||
# default mode
|
||||
for b in exit return shift break continue; do
|
||||
BUILTIN=$b ${THIS_SH} $TFILE # TFILE for consistent error messages
|
||||
done
|
||||
# posix mode
|
||||
for b in exit return shift break continue; do
|
||||
BUILTIN=$b ${POSIX_SH} $TFILE # TFILE for consistent error messages
|
||||
done
|
||||
|
||||
cd $OLDPWD
|
||||
rm -rf $TDIR
|
||||
@@ -0,0 +1,42 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
: ${THIS_SH:=./bash}
|
||||
|
||||
${THIS_SH} -c 'readonly non-identifier ; echo after: $?' bash
|
||||
${THIS_SH} -c 'export non-identifier ; echo after: $?' bash
|
||||
|
||||
${THIS_SH} -c 'readonly non-identifier invalid+ident ; echo after: $?' bash
|
||||
${THIS_SH} -c 'export non-identifier invalid+ident ; echo after: $?' bash
|
||||
|
||||
${THIS_SH} -o posix -c 'readonly non-identifier ; echo after: $?' sh
|
||||
${THIS_SH} -o posix -c 'export non-identifier ; echo after: $?' sh
|
||||
|
||||
${THIS_SH} -o posix -c 'readonly non-identifier invalid+ident ; echo after: $?' sh
|
||||
${THIS_SH} -o posix -c 'export non-identifier invalid+ident ; echo after: $?' sh
|
||||
|
||||
${THIS_SH} -c 'command readonly non-identifier ; echo command: $?' bash
|
||||
${THIS_SH} -c 'command export non-identifier ; echo command: $?' bash
|
||||
|
||||
${THIS_SH} -o posix -c 'command readonly non-identifier ; echo command: $?' sh
|
||||
${THIS_SH} -o posix -c 'command export non-identifier ; echo command: $?' sh
|
||||
|
||||
# invalid array references
|
||||
|
||||
${THIS_SH} -c 'export AA[4] ; echo array: $?' bash
|
||||
${THIS_SH} -c 'readonly AA[4] ; echo array: $?' bash
|
||||
|
||||
${THIS_SH} -o posix -c 'export AA[4] ; echo array: $?' sh
|
||||
${THIS_SH} -o posix -c 'readonly AA[4] ; echo array: $?' sh
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# problems with fork optimization in subshells in bash-5.2
|
||||
|
||||
: ${TMPDIR:=/tmp}
|
||||
TDIR=$TMPDIR/delta-$$
|
||||
mkdir "$TDIR" || exit 2
|
||||
|
||||
CMD='env true && env ls -1 "$TDIR"'
|
||||
|
||||
trap 'rm -rf "$TDIR"' EXIT
|
||||
|
||||
cd "$TDIR" &&
|
||||
{
|
||||
touch archive install test;
|
||||
echo "$CMD" > s
|
||||
echo '( echo "1 start" ; . "$TDIR/sub2" ; echo "1 done" ; exit 42 )' >sub1
|
||||
echo 'echo "2 start" && env echo sub3' >sub2
|
||||
} &&
|
||||
cd "$OLDPWD"
|
||||
|
||||
[ -f "$TDIR"/s ] || exit 2
|
||||
|
||||
d2()
|
||||
{
|
||||
eval "$1" ; return 78
|
||||
}
|
||||
|
||||
d1()
|
||||
{
|
||||
cmd="$1"
|
||||
|
||||
( env true && env ls -1 "$TDIR";
|
||||
exit 68 )
|
||||
echo $?
|
||||
( . $TDIR/s ; exit 44 )
|
||||
echo $?
|
||||
( eval "$cmd" ; exit 86 )
|
||||
echo $?
|
||||
return 43
|
||||
}
|
||||
|
||||
dfunc()
|
||||
{
|
||||
local x="$CMD"
|
||||
|
||||
d1 "$x" || return 2
|
||||
echo oops: after
|
||||
}
|
||||
|
||||
${THIS_SH} -c '(. <(echo ": && env echo Darwin"); echo x)'
|
||||
|
||||
( dfunc xxx )
|
||||
echo $?
|
||||
v=$(d2 "$CMD")
|
||||
echo $?
|
||||
|
||||
. $TDIR/sub1
|
||||
echo $?
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,33 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# extglob option interaction with other parts of the shell that force
|
||||
# extended_glob on; only an issue in compatibility mode
|
||||
|
||||
shopt -u extglob
|
||||
|
||||
BASH_COMPAT=50
|
||||
shopt extglob
|
||||
|
||||
echo $(echo $(echo $(echo $(echo $(echo x) ) ) ) )
|
||||
shopt extglob
|
||||
|
||||
shopt -u extglob
|
||||
|
||||
[[ '' = $(shopt extglob >&2) ]]
|
||||
shopt extglob
|
||||
|
||||
shopt -u extglob
|
||||
|
||||
[[ foo = $(: $(shopt extglob >&2)) ]]
|
||||
shopt extglob
|
||||
@@ -0,0 +1,99 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# these are ok
|
||||
|
||||
function a=2
|
||||
{
|
||||
printf "FUNCNAME: %s\n" $FUNCNAME
|
||||
}
|
||||
|
||||
function 11111
|
||||
{
|
||||
printf "FUNCNAME: %s\n" $FUNCNAME
|
||||
}
|
||||
|
||||
# but this is still not
|
||||
function sys$read
|
||||
{
|
||||
printf "FUNCNAME: %s\n" $FUNCNAME
|
||||
}
|
||||
|
||||
declare -f
|
||||
set -o posix
|
||||
declare -f
|
||||
set +o posix
|
||||
|
||||
a\=2
|
||||
|
||||
<(:) ()
|
||||
{
|
||||
echo $FUNCNAME
|
||||
}
|
||||
\<\(:\)
|
||||
type '<(:)'
|
||||
|
||||
break()
|
||||
{
|
||||
echo inside function $FUNCNAME
|
||||
}
|
||||
|
||||
testfunc()
|
||||
{
|
||||
echo type
|
||||
type break
|
||||
type -t break
|
||||
echo command -v
|
||||
command -v break
|
||||
echo command -V
|
||||
command -V break
|
||||
|
||||
echo type -a
|
||||
type -a break
|
||||
echo declare
|
||||
declare -f break
|
||||
echo execution
|
||||
break
|
||||
}
|
||||
|
||||
set -o posix
|
||||
echo posix mode:
|
||||
testfunc
|
||||
|
||||
set +o posix
|
||||
echo default mode:
|
||||
testfunc
|
||||
unset -f testfunc break
|
||||
|
||||
# but in posix mode, declaring such a function is a fatal error
|
||||
( set -o posix
|
||||
break()
|
||||
{
|
||||
echo FUNCNAME: $FUNCNAME
|
||||
}
|
||||
echo after
|
||||
)
|
||||
|
||||
# in posix mode, functions whose names are invalid identifiers are fatal errors
|
||||
( set -o posix
|
||||
!! () { fc -s "$@" ; }
|
||||
type \!\!
|
||||
)
|
||||
|
||||
# but you can create such functions and print them in posix mode
|
||||
!! () { fc -s "$@" ; }
|
||||
type '!!'
|
||||
set -o posix
|
||||
type '!!'
|
||||
set +o posix
|
||||
@@ -0,0 +1,103 @@
|
||||
--- $GLOBIGNORE vs fnmatch(3) ---
|
||||
#1: pat=ab/cd/efg yes/yes
|
||||
#2: pat=ab[/]cd/efg no/no
|
||||
#3: pat=ab[/a]cd/efg no/no
|
||||
#4: pat=ab[a/]cd/efg no/no
|
||||
#5: pat=ab[!a]cd/efg no/no
|
||||
#6: pat=ab[.-0]cd/efg no/no
|
||||
#7: pat=*/*/efg yes/yes
|
||||
#8: pat=*[/]*/efg no/no
|
||||
#9: pat=*[/a]*/efg no/no
|
||||
#10: pat=*[a/]*/efg no/no
|
||||
#11: pat=*[!a]*/efg no/no
|
||||
#12: pat=*[.-0]*/efg no/no
|
||||
#13: pat=*/*/efg yes/yes
|
||||
#14: pat=*[b]/*/efg yes/yes
|
||||
#15: pat=*[ab]/*/efg yes/yes
|
||||
#16: pat=*[ba]/*/efg yes/yes
|
||||
#17: pat=*[!a]/*/efg yes/yes
|
||||
#18: pat=*[a-c]/*/efg yes/yes
|
||||
#19: pat=ab@(/)cd/efg yes/yes
|
||||
#20: pat=*@(/)cd/efg no/no
|
||||
#21: pat=*/cd/efg yes/yes
|
||||
|
||||
---Tests for a slash in bracket expressions---
|
||||
#22: pat=ab[/]ef str=ab[/]ef yes/yes
|
||||
#23: pat=ab[/]ef str=ab/ef no/no
|
||||
#24: pat=ab[c/d]ef str=ab[c/d]ef yes/yes
|
||||
#25: pat=ab[c/d]ef str=abcef no/no
|
||||
#26: pat=ab[.-/]ef str=ab[.-/]ef yes/yes
|
||||
#27: pat=ab[.-/]ef str=ab.ef no/no
|
||||
#28: pat=ab[[=/=]]ef str=ab[[=/=]]ef yes/yes
|
||||
#29: pat=ab[[=/=]]ef str=ab/ef no/no
|
||||
#30: pat=ab[[=c=]/]ef str=ab[=/]ef yes/yes
|
||||
#31: pat=ab[[=c=]/]ef str=abcef no/no
|
||||
#32: pat=ab[[:alpha:]/]ef str=ab[:/]ef yes/yes
|
||||
#33: pat=ab[[:alpha:]/]ef str=abxef no/no
|
||||
#34: pat=ab[/[abc]]ef str=ab[/c]ef yes/yes
|
||||
#35: pat=ab[/[abc]]ef str=abc]ef no/no
|
||||
#36: pat=ab[c[=/=]]ef str=ab[c[=/=]]ef yes/yes
|
||||
#37: pat=ab[c[=/=]]ef str=abc[=/=]ef no/no
|
||||
#38: pat=ab[c[=/=]]ef str=abcef no/no
|
||||
#39: pat=a[b\/c] str=a[b/c] yes/yes
|
||||
#40: pat=a[b\/c] str=ab no/no
|
||||
#41: pat=a[b\/c] str=ac no/no
|
||||
|
||||
---Tests for incomplete bracket expressions---
|
||||
#42: pat=ab[c str=ab[c yes/yes
|
||||
#43: pat=ab[c str=abc no/no
|
||||
#44: pat=ab[c[=d= str=ab[c[=d= yes/yes
|
||||
#45: pat=ab[c[=d= str=abc no/no
|
||||
#46: pat=ab[c[.d str=ab[c[.d yes/yes
|
||||
#47: pat=ab[c[.d str=abc no/no
|
||||
#48: pat=ab[c[:alpha: str=ab[c[:alpha: yes/yes
|
||||
#49: pat=ab[c[:alpha: str=abc no/no
|
||||
#50: pat=ab[c- str=ab[c- yes/yes
|
||||
#51: pat=ab[c- str=abc no/no
|
||||
#52: pat=ab[c\ str=ab[c\ yes/yes
|
||||
#53: pat=ab[c\ str=abc no/no
|
||||
#54: pat=ab[[\ str=ab[[\ yes/yes
|
||||
#55: pat=ab[[\ str=ab[ no/no
|
||||
|
||||
--- PATSCAN vs BRACKMATCH ---
|
||||
#56: pat=@([[.].])A]) str=] yes/yes
|
||||
#57: pat=@([[.].])A]) str===]A]) no/no
|
||||
#58: pat=@([[.].])A]) str=AA]) no/no
|
||||
#59: pat=@([[=]=])A]) str=] no/no
|
||||
#60: pat=@([[=]=])A]) str===]A]) yes/yes
|
||||
#61: pat=@([[=]=])A]) str=AA]) no/no
|
||||
|
||||
--- BRACKMATCH: after match vs before match ---
|
||||
#62: pat=[[=]=]ab] str=a no/no
|
||||
#63: pat=[[.[=.]ab] str=a yes/yes
|
||||
#64: pat=[[.[==].]ab] str=a yes/yes
|
||||
|
||||
#65: pat=[a[=]=]b] str=a no/no
|
||||
#66: pat=[a[.[=.]b] str=a yes/yes
|
||||
#67: pat=[a[.[==].]b] str=a yes/yes
|
||||
|
||||
#68: pat=[a[=]=]b] str=b no/no
|
||||
#69: pat=[a[=]=]b] str=a=]b] yes/yes
|
||||
#70: pat=[a[.[=.]b] str=b yes/yes
|
||||
#71: pat=[a[.[=.]b] str=ab] no/no
|
||||
#72: pat=[a[.[==].]b] str=b yes/yes
|
||||
#73: pat=[a[.[==].]b] str=ab] no/no
|
||||
|
||||
--- incomplete POSIX brackets ---
|
||||
#74: pat=x[a[:y] str=x[ yes/yes
|
||||
#75: pat=x[a[:y] str=x: yes/yes
|
||||
#76: pat=x[a[:y] str=xy yes/yes
|
||||
#77: pat=x[a[:y] str=x[ay no/no
|
||||
|
||||
#78: pat=x[a[.y] str=x[ yes/yes
|
||||
#79: pat=x[a[.y] str=x. yes/yes
|
||||
#80: pat=x[a[.y] str=xy yes/yes
|
||||
#81: pat=x[a[.y] str=x[ay no/no
|
||||
|
||||
#82: pat=x[a[=y] str=x[ yes/yes
|
||||
#83: pat=x[a[=y] str=x= yes/yes
|
||||
#84: pat=x[a[=y] str=xy yes/yes
|
||||
#85: pat=x[a[=y] str=x[ay no/no
|
||||
|
||||
--- MISC tests ---
|
||||
#86: pat=a\ str=a\ yes/yes
|
||||
@@ -0,0 +1,309 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# tests of various aspects of pathname expansion, mostly dealing with bracket
|
||||
# expressions
|
||||
#
|
||||
# Derived from tests contributed by Koichi Murase <myoga.murase@gmail.com>
|
||||
|
||||
LC_COLLATE=C
|
||||
|
||||
ORIG_DIR=$PWD
|
||||
|
||||
: ${TMPDIR:=/tmp} ${BUILD_DIR:=$ORIG_DIR}
|
||||
|
||||
trap 'rm -rf $TESTDIR $WORK_DIR' EXIT
|
||||
|
||||
WORK_DIR=${TMPDIR}/globtest-$$
|
||||
|
||||
mkdir $WORK_DIR || {
|
||||
echo "glob-bracket: cannot create directory $WORK_DIR" >&2
|
||||
exit 1
|
||||
}
|
||||
cd $WORK_DIR || {
|
||||
echo "glob-bracket: cannot cd to directory $WORK_DIR" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
eval $(grep -E '^(CC |SHOBJ_).*=' $BUILD_DIR/examples/loadables/Makefile | sed -e 's/[ ]*=[ ]*/="/' -e 's/\$@/strmatch/' -e 's/$/"/' )
|
||||
|
||||
if [ "$SHOBJ_STATUS" != "supported" ]; then
|
||||
echo "glob-bracket: shared objects not supported, cannot continue" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
# we assume gcc as a default here
|
||||
: ${CC:=gcc}
|
||||
|
||||
cat > fnmatch.c <<-EOF
|
||||
#include <fnmatch.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (2 >= argc) {
|
||||
fprintf(stderr, "usage: fnmatch string pattern\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
#ifdef FNM_EXTMATCH
|
||||
int flags = FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH;
|
||||
#else
|
||||
int flags = FNM_PATHNAME | FNM_PERIOD;
|
||||
#endif
|
||||
if (fnmatch(argv[2], argv[1], flags) == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
EOF
|
||||
$CC -O2 -o fnmatch fnmatch.c
|
||||
rm -f fnmatch.c
|
||||
|
||||
if [ ! -f fnmatch ] ; then
|
||||
echo "glob-bracket: cannot create fnmatch executable" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
cat > strmatch.c <<-EOF
|
||||
#define BUILTIN_ENABLED 0x01
|
||||
struct word_desc { char* word; int flags; };
|
||||
struct word_list { struct word_list* next; struct word_desc* word; };
|
||||
struct builtin {
|
||||
const char* name;
|
||||
int (*function)(struct word_list*);
|
||||
int flags;
|
||||
const char** long_doc;
|
||||
const char* short_doc;
|
||||
char* handle;
|
||||
};
|
||||
|
||||
/*#include <glob/strmatch.h>*/
|
||||
int strmatch(char *pattern, char *string, int flags);
|
||||
#define FNM_PATHNAME (1 << 0)
|
||||
#define FNM_NOESCAPE (1 << 1)
|
||||
#define FNM_PERIOD (1 << 2)
|
||||
#define FNM_LEADING_DIR (1 << 3)
|
||||
#define FNM_CASEFOLD (1 << 4)
|
||||
#define FNM_EXTMATCH (1 << 5)
|
||||
#define FNM_FIRSTCHAR (1 << 6)
|
||||
#define FNM_DOTDOT (1 << 7)
|
||||
|
||||
static int strmatch_builtin(struct word_list* list) {
|
||||
char *str, *pat;
|
||||
if (!list || !list->word) return 2;
|
||||
str = list->word->word;
|
||||
if (!list->next || !list->next->word) return 2;
|
||||
pat = list->next->word->word;
|
||||
|
||||
if (strmatch (pat, str, FNM_PATHNAME | FNM_PERIOD | FNM_EXTMATCH) == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
static const char* strmatch_doc[] = { "This is a builtin to test the behavior of strmatch", 0 };
|
||||
struct builtin strmatch_struct = { "strmatch", strmatch_builtin, BUILTIN_ENABLED, strmatch_doc, "strmatch string pattern", 0, };
|
||||
EOF
|
||||
|
||||
${SHOBJ_CC} ${SHOBJ_CFLAGS} -c -o strmatch.o strmatch.c
|
||||
rm -f strmatch.c
|
||||
|
||||
${SHOBJ_LD} ${SHOBJ_LDFLAGS} ${SHOBJ_XLDFLAGS} -o strmatch.so strmatch.o ${SHOBJ_LIBS}
|
||||
rm -f strmatch.o
|
||||
|
||||
if [ ! -f strmatch.so ] ; then
|
||||
echo "glob-bracket: cannot create strmatch loadable builtin" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
enable -f ./strmatch.so strmatch || {
|
||||
echo "glob-bracket: cannot load strmatch builtin" >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
check_count=1
|
||||
|
||||
if [ -z "$BASH_TSTOUT" ]; then
|
||||
yes=$'\033[32myes\033[m' no=$'\033[31mno\033[m'
|
||||
else
|
||||
yes=yes no=no
|
||||
fi
|
||||
|
||||
function check {
|
||||
# bash impl
|
||||
if strmatch "$2" "$1"; then
|
||||
local strmatch=$yes
|
||||
else
|
||||
local strmatch=$no
|
||||
fi
|
||||
|
||||
# fnmatch
|
||||
local expect=${3-}
|
||||
if [[ ! $expect ]]; then
|
||||
if $WORK_DIR/fnmatch "$2" "$1"; then
|
||||
expect=$yes
|
||||
else
|
||||
expect=$no
|
||||
fi
|
||||
fi
|
||||
printf '#%d: pat=%-20s str=%-16s %s/%s\n' "$((check_count++))" "$1" "$2" "$strmatch" "$expect"
|
||||
}
|
||||
|
||||
function pcheck {
|
||||
local GLOBIGNORE=$1
|
||||
|
||||
# bash impl
|
||||
local -a f=(*/*/efg*)
|
||||
if [[ $f == '*/*/efg*' ]]; then
|
||||
local strmatch=$yes
|
||||
else
|
||||
local strmatch=$no
|
||||
fi
|
||||
|
||||
# Linux fnmatch
|
||||
local fnmatch=${2-}
|
||||
if [[ ! $fnmatch ]]; then
|
||||
if $WORK_DIR/fnmatch ab/cd/efg "$1"; then
|
||||
fnmatch=$yes
|
||||
else
|
||||
fnmatch=$no
|
||||
fi
|
||||
fi
|
||||
|
||||
printf '#%d: pat=%-16s %s/%s\n' "$((check_count++))" "$1" "$strmatch" "$fnmatch"
|
||||
}
|
||||
|
||||
TESTDIR=${TMPDIR}/pathtest-$$
|
||||
TESTPATH=${TESTDIR}/ab/cd/efg
|
||||
mkdir -p $TESTPATH
|
||||
|
||||
if [ -d "$TESTPATH" ] && cd "$TESTDIR"; then
|
||||
echo '--- $GLOBIGNORE vs fnmatch(3) ---'
|
||||
pcheck 'ab/cd/efg'
|
||||
pcheck 'ab[/]cd/efg'
|
||||
pcheck 'ab[/a]cd/efg'
|
||||
pcheck 'ab[a/]cd/efg'
|
||||
pcheck 'ab[!a]cd/efg'
|
||||
pcheck 'ab[.-0]cd/efg'
|
||||
pcheck '*/*/efg'
|
||||
pcheck '*[/]*/efg'
|
||||
pcheck '*[/a]*/efg'
|
||||
pcheck '*[a/]*/efg'
|
||||
pcheck '*[!a]*/efg'
|
||||
pcheck '*[.-0]*/efg'
|
||||
|
||||
pcheck '*/*/efg'
|
||||
pcheck '*[b]/*/efg'
|
||||
pcheck '*[ab]/*/efg'
|
||||
pcheck '*[ba]/*/efg'
|
||||
pcheck '*[!a]/*/efg'
|
||||
pcheck '*[a-c]/*/efg'
|
||||
|
||||
shopt -s extglob
|
||||
pcheck 'ab@(/)cd/efg' "$yes"
|
||||
pcheck '*@(/)cd/efg' "$no"
|
||||
pcheck '*/cd/efg'
|
||||
shopt -u extglob
|
||||
|
||||
cd "$WORK_DIR"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo '---Tests for a slash in bracket expressions---'
|
||||
check 'ab[/]ef' 'ab[/]ef' "$yes"
|
||||
check 'ab[/]ef' 'ab/ef' "$no"
|
||||
check 'ab[c/d]ef' 'ab[c/d]ef' "$yes"
|
||||
check 'ab[c/d]ef' 'abcef' "$no"
|
||||
check 'ab[.-/]ef' 'ab[.-/]ef' "$yes"
|
||||
check 'ab[.-/]ef' 'ab.ef' "$no"
|
||||
check 'ab[[=/=]]ef' 'ab[[=/=]]ef' "$yes"
|
||||
check 'ab[[=/=]]ef' 'ab/ef' "$no"
|
||||
check 'ab[[=c=]/]ef' 'ab[=/]ef' "$yes"
|
||||
check 'ab[[=c=]/]ef' 'abcef' "$no"
|
||||
check 'ab[[:alpha:]/]ef' 'ab[:/]ef' "$yes"
|
||||
check 'ab[[:alpha:]/]ef' 'abxef' "$no"
|
||||
check 'ab[/[abc]]ef' 'ab[/c]ef' "$yes"
|
||||
check 'ab[/[abc]]ef' 'abc]ef' "$no"
|
||||
check 'ab[c[=/=]]ef' 'ab[c[=/=]]ef' "$yes"
|
||||
check 'ab[c[=/=]]ef' 'abc[=/=]ef' "$no"
|
||||
check 'ab[c[=/=]]ef' 'abcef' "$no"
|
||||
check 'a[b\/c]' 'a[b/c]' "$yes"
|
||||
check 'a[b\/c]' 'ab' "$no"
|
||||
check 'a[b\/c]' 'ac' "$no"
|
||||
|
||||
echo
|
||||
echo '---Tests for incomplete bracket expressions---'
|
||||
check 'ab[c' 'ab[c' "$yes"
|
||||
check 'ab[c' 'abc' "$no"
|
||||
check 'ab[c[=d=' 'ab[c[=d=' "$yes"
|
||||
check 'ab[c[=d=' 'abc' "$no"
|
||||
check 'ab[c[.d' 'ab[c[.d' "$yes"
|
||||
check 'ab[c[.d' 'abc' "$no"
|
||||
check 'ab[c[:alpha:' 'ab[c[:alpha:' "$yes"
|
||||
check 'ab[c[:alpha:' 'abc' "$no"
|
||||
check 'ab[c-' 'ab[c-' "$yes"
|
||||
check 'ab[c-' 'abc' "$no"
|
||||
check 'ab[c\' 'ab[c\' "$yes"
|
||||
check 'ab[c\' 'abc' "$no"
|
||||
check 'ab[[\' 'ab[[\' "$yes"
|
||||
check 'ab[[\' 'ab[' "$no"
|
||||
|
||||
echo
|
||||
echo '--- PATSCAN vs BRACKMATCH ---'
|
||||
check '@([[.].])A])' ']' "$yes"
|
||||
check '@([[.].])A])' '==]A])' "$no"
|
||||
check '@([[.].])A])' 'AA])' "$no"
|
||||
check '@([[=]=])A])' ']' "$no"
|
||||
check '@([[=]=])A])' '==]A])' "$yes"
|
||||
check '@([[=]=])A])' 'AA])' "$no"
|
||||
|
||||
echo
|
||||
echo '--- BRACKMATCH: after match vs before match ---'
|
||||
check '[[=]=]ab]' 'a' "$no"
|
||||
check '[[.[=.]ab]' 'a' "$yes"
|
||||
check '[[.[==].]ab]' 'a' "$yes"
|
||||
echo
|
||||
check '[a[=]=]b]' 'a' "$no"
|
||||
check '[a[.[=.]b]' 'a' "$yes"
|
||||
check '[a[.[==].]b]' 'a' "$yes"
|
||||
echo
|
||||
check '[a[=]=]b]' 'b' "$no"
|
||||
check '[a[=]=]b]' 'a=]b]' "$yes"
|
||||
check '[a[.[=.]b]' 'b' "$yes"
|
||||
check '[a[.[=.]b]' 'ab]' "$no"
|
||||
check '[a[.[==].]b]' 'b' "$yes"
|
||||
check '[a[.[==].]b]' 'ab]' "$no"
|
||||
|
||||
echo
|
||||
echo '--- incomplete POSIX brackets ---'
|
||||
check 'x[a[:y]' 'x[' "$yes"
|
||||
check 'x[a[:y]' 'x:' "$yes"
|
||||
check 'x[a[:y]' 'xy' "$yes"
|
||||
check 'x[a[:y]' 'x[ay' "$no"
|
||||
echo
|
||||
check 'x[a[.y]' 'x[' "$yes"
|
||||
check 'x[a[.y]' 'x.' "$yes"
|
||||
check 'x[a[.y]' 'xy' "$yes"
|
||||
check 'x[a[.y]' 'x[ay' "$no"
|
||||
echo
|
||||
check 'x[a[=y]' 'x[' "$yes"
|
||||
check 'x[a[=y]' 'x=' "$yes"
|
||||
check 'x[a[=y]' 'xy' "$yes"
|
||||
check 'x[a[=y]' 'x[ay' "$no"
|
||||
|
||||
echo
|
||||
echo '--- MISC tests ---'
|
||||
check 'a\' 'a\' "$yes"
|
||||
|
||||
cd $ORIG_DIR
|
||||
|
||||
enable -d strmatch # just testing
|
||||
exit 0
|
||||
@@ -0,0 +1,69 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# testing GLOBSORT
|
||||
LC_COLLATE=C
|
||||
LC_CTYPE=C
|
||||
LANG=C
|
||||
|
||||
: ${TMPDIR:=/tmp}
|
||||
|
||||
TDIR=$TMPDIR/glob-$$
|
||||
{ mkdir $TDIR && cd $TDIR; } || exit 1
|
||||
|
||||
# try to impose some kind of testable ordering
|
||||
echo 123 > mksyntax ; sleep 0.1
|
||||
echo 123456 > mksignames ; sleep 0.1
|
||||
echo 1234567879 > make_cmd.o ; sleep 0.1
|
||||
echo 123456789012 > mailcheck.o ; sleep 0.1
|
||||
echo 123456789012345 > mksignames.o ; sleep 0.1
|
||||
echo 123456789012345678 > mksyntax.dSYM ; sleep 0.1
|
||||
|
||||
echo m*
|
||||
GLOBSORT=nosort
|
||||
#echo m* # might have to take this one out
|
||||
unset GLOBSORT
|
||||
echo
|
||||
|
||||
GLOBSORT=
|
||||
echo m*
|
||||
GLOBSORT='-name'
|
||||
echo m*
|
||||
echo
|
||||
|
||||
GLOBSORT='+nonsense'
|
||||
echo m*
|
||||
GLOBSORT='-nonsense'
|
||||
echo m*
|
||||
echo
|
||||
|
||||
GLOBSORT='+atime'
|
||||
echo m*
|
||||
GLOBSORT='-atime'
|
||||
echo m*
|
||||
echo
|
||||
|
||||
GLOBSORT='+mtime'
|
||||
echo m*
|
||||
GLOBSORT='-mtime'
|
||||
echo m*
|
||||
echo
|
||||
|
||||
GLOBSORT=size
|
||||
echo m*
|
||||
GLOBSORT=-size
|
||||
echo m*
|
||||
|
||||
cd $OLDPWD
|
||||
rm -rf $TDIR
|
||||
@@ -0,0 +1,55 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# test various forms of reading here-documents from an alias
|
||||
shopt -s expand_aliases
|
||||
|
||||
# single alias definition contains entire here-document
|
||||
alias 'heredoc=cat <<EOF
|
||||
hello
|
||||
world
|
||||
EOF'
|
||||
heredoc
|
||||
|
||||
# here-document body continues after alias definition
|
||||
alias 'headplus=cat <<EOF
|
||||
hello'
|
||||
headplus
|
||||
world
|
||||
EOF
|
||||
|
||||
unalias heredoc headplus
|
||||
|
||||
alias head='cat <<END'
|
||||
|
||||
head
|
||||
here-doc line 1
|
||||
here-doc line 2
|
||||
END
|
||||
|
||||
# here-document delimiter in one alias, body in another
|
||||
alias head='cat <<\END' body='head
|
||||
here-document
|
||||
END'
|
||||
body
|
||||
|
||||
# make sure delimiter is recognized whether the alias ends with a newline or not
|
||||
shopt -s expand_aliases
|
||||
alias head='cat <<\END' body='head
|
||||
here-document
|
||||
END
|
||||
'
|
||||
body
|
||||
|
||||
unalias head body
|
||||
@@ -0,0 +1,62 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# problems with comsub printing and re-parsing with here-documents and compound
|
||||
# commands in bash-5.2
|
||||
|
||||
z=$(
|
||||
f1() {
|
||||
c <<-!
|
||||
!
|
||||
}
|
||||
f2() {
|
||||
:
|
||||
}
|
||||
)
|
||||
|
||||
z=$(
|
||||
f1() {
|
||||
c
|
||||
}
|
||||
f2() {
|
||||
:
|
||||
}
|
||||
)
|
||||
|
||||
z=$(
|
||||
f1() {
|
||||
c <<-!
|
||||
!
|
||||
}
|
||||
:
|
||||
)
|
||||
|
||||
z=$(
|
||||
{
|
||||
: <<-!
|
||||
!
|
||||
}
|
||||
{
|
||||
:
|
||||
}
|
||||
)
|
||||
|
||||
z=$(
|
||||
for f in 0; do
|
||||
: <<-!
|
||||
!
|
||||
done
|
||||
{
|
||||
:
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,44 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# various issues with printing here-documents as part of function bodies
|
||||
|
||||
foo()
|
||||
{
|
||||
echo begin
|
||||
if cat << HERE
|
||||
contents
|
||||
HERE
|
||||
then
|
||||
echo 1 2
|
||||
echo 3 4
|
||||
fi
|
||||
}
|
||||
|
||||
declare -pf foo
|
||||
|
||||
foo()
|
||||
{
|
||||
echo begin
|
||||
while read var << HERE
|
||||
contents
|
||||
HERE
|
||||
do
|
||||
echo 1 2
|
||||
echo 3 4
|
||||
done
|
||||
}
|
||||
|
||||
declare -pf foo
|
||||
unset -f foo
|
||||
@@ -0,0 +1,74 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# test history file truncation for various values of $HISTFILESIZE
|
||||
. ./test-glue-functions
|
||||
|
||||
: ${THIS_SH:=./bash}
|
||||
: ${TMPDIR:=/var/tmp}
|
||||
|
||||
export HISTTIMEFORMAT=
|
||||
export HISTFILESIZE=3
|
||||
export HISTFILE=$TMPDIR/hist-$$
|
||||
export PS1='$ '
|
||||
|
||||
rm -f $HISTFILE
|
||||
|
||||
# exactly the number of lines
|
||||
${THIS_SH} --norc -in <<<$'1\n2\n3'
|
||||
wc -l < $HISTFILE | _cut_leading_spaces
|
||||
|
||||
rm -f $HISTFILE
|
||||
|
||||
# truncating to fewer lines
|
||||
${THIS_SH} --norc -in <<<$'1\n2\n3\n4\n5'
|
||||
wc -l < $HISTFILE | _cut_leading_spaces
|
||||
|
||||
rm -f $HISTFILE
|
||||
|
||||
# the history file contains fewer lines than $HISTFILESIZE
|
||||
${THIS_SH} --norc -in <<<$'1\n2'
|
||||
wc -l < $HISTFILE | _cut_leading_spaces
|
||||
|
||||
rm -f $HISTFILE
|
||||
|
||||
# now we try it without timestamps
|
||||
unset HISTTIMEFORMAT
|
||||
|
||||
# exactly the number of lines
|
||||
${THIS_SH} --norc -in <<<$'e 1\ne 2\ne 3'
|
||||
wc -l < $HISTFILE | _cut_leading_spaces
|
||||
cat $HISTFILE
|
||||
|
||||
rm -f $HISTFILE
|
||||
|
||||
# truncating to fewer lines
|
||||
${THIS_SH} --norc -in <<<$'x 1\nx 2\nx 3\nx 4\nx 5'
|
||||
wc -l < $HISTFILE | _cut_leading_spaces
|
||||
cat $HISTFILE
|
||||
|
||||
rm -f $HISTFILE
|
||||
|
||||
# the history file contains fewer lines than $HISTFILESIZE
|
||||
${THIS_SH} --norc -in <<<$'y 1\ny 2'
|
||||
wc -l < $HISTFILE | _cut_leading_spaces
|
||||
cat $HISTFILE
|
||||
|
||||
rm -f $HISTFILE
|
||||
|
||||
# we want to truncate the history file to zero length
|
||||
HISTFILESIZE=0
|
||||
${THIS_SH} --norc -in <<<$'1\n2'
|
||||
wc -l < $HISTFILE | _cut_leading_spaces
|
||||
|
||||
rm -f $HISTFILE
|
||||
@@ -0,0 +1,16 @@
|
||||
trap 'rm -f "$OUT"' 0 1 2 3 6 15
|
||||
|
||||
HISTFILE=$TMPDIR/fchist-$$ ; OUT=$HISTFILE
|
||||
unset HISTIGNORE HISTCONTROL
|
||||
set -o history
|
||||
|
||||
echo a
|
||||
echo b
|
||||
echo c
|
||||
echo d
|
||||
|
||||
history -d 2
|
||||
history
|
||||
|
||||
history -d 72
|
||||
history -d -72
|
||||
@@ -0,0 +1,35 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# printf "%ls" and "%lc" format specifiers for multibyte characters with
|
||||
# field width and precision in characters instead of bytes
|
||||
LC_ALL=en_US.UTF-8
|
||||
|
||||
V=ಇಳಿಕೆಗಳು
|
||||
V2=${V:0:2}
|
||||
V3=${V:0:1}
|
||||
|
||||
printf "%ls\n" "$V"
|
||||
printf "%ls\n" "$V2"
|
||||
printf "%lc\n" "$V"
|
||||
printf "%.2ls\n" "$V"
|
||||
|
||||
printf "%4.2ls\n" "$V"
|
||||
printf "%-4.2ls---\n" "$V"
|
||||
|
||||
printf "%ls\n" "$V3"
|
||||
printf "%lc\n" "$V3"
|
||||
|
||||
printf "%4.2lc\n" "$V3"
|
||||
printf "%-4.2lc---\n" "$V3"
|
||||
@@ -0,0 +1,104 @@
|
||||
.: .: Is a directory
|
||||
bash: -c: option requires an argument
|
||||
bash: --badopt: invalid option
|
||||
bash [GNU long option] [option] ...
|
||||
bash [GNU long option] [option] script-file ...
|
||||
GNU long options:
|
||||
--debug
|
||||
--debugger
|
||||
--dump-po-strings
|
||||
--dump-strings
|
||||
--help
|
||||
--init-file
|
||||
--login
|
||||
--noediting
|
||||
--noprofile
|
||||
--norc
|
||||
--posix
|
||||
--pretty-print
|
||||
--rcfile
|
||||
--restricted
|
||||
--verbose
|
||||
--version
|
||||
Shell options:
|
||||
-ilrsD or -c command or -O shopt_option (invocation only)
|
||||
-abefhkmnptuvxBCEHPT or -o option
|
||||
bash: --initfile: invalid option
|
||||
bash [GNU long option] [option] ...
|
||||
bash [GNU long option] [option] script-file ...
|
||||
GNU long options:
|
||||
--debug
|
||||
--debugger
|
||||
--dump-po-strings
|
||||
--dump-strings
|
||||
--help
|
||||
--init-file
|
||||
--login
|
||||
--noediting
|
||||
--noprofile
|
||||
--norc
|
||||
--posix
|
||||
--pretty-print
|
||||
--rcfile
|
||||
--restricted
|
||||
--verbose
|
||||
--version
|
||||
Shell options:
|
||||
-ilrsD or -c command or -O shopt_option (invocation only)
|
||||
-abefhkmnptuvxBCEHPT or -o option
|
||||
bash: -q: invalid option
|
||||
bash [GNU long option] [option] ...
|
||||
bash [GNU long option] [option] script-file ...
|
||||
GNU long options:
|
||||
--debug
|
||||
--debugger
|
||||
--dump-po-strings
|
||||
--dump-strings
|
||||
--help
|
||||
--init-file
|
||||
--login
|
||||
--noediting
|
||||
--noprofile
|
||||
--norc
|
||||
--posix
|
||||
--pretty-print
|
||||
--rcfile
|
||||
--restricted
|
||||
--verbose
|
||||
--version
|
||||
Shell options:
|
||||
-ilrsD or -c command or -O shopt_option (invocation only)
|
||||
-abefhkmnptuvxBCEHPT or -o option
|
||||
this-bash this-bash
|
||||
$- for -c includes c
|
||||
bash: line 0: badopt: invalid shell option name
|
||||
checkwinsize:cmdhist:complete_fullquote:extquote:force_fignore:globasciiranges:globskipdots:hostcomplete:interactive_comments:patsub_replacement:progcomp:promptvars:sourcepath
|
||||
checkhash:checkwinsize:cmdhist:complete_fullquote:extquote:force_fignore:globasciiranges:globskipdots:hostcomplete:interactive_comments:patsub_replacement:progcomp:promptvars:sourcepath
|
||||
cmdhist:complete_fullquote:extquote:force_fignore:globasciiranges:globskipdots:hostcomplete:interactive_comments:patsub_replacement:progcomp:promptvars:sourcepath
|
||||
./invocation1.sub: line 40: BASHOPTS: readonly variable
|
||||
braceexpand:hashall:interactive-comments
|
||||
braceexpand:hashall:interactive-comments
|
||||
hashall:interactive-comments
|
||||
hashall:interactive-comments
|
||||
braceexpand:hashall:interactive-comments:noglob
|
||||
braceexpand:hashall:interactive-comments:noglob
|
||||
./invocation2.sub: line 50: SHELLOPTS: readonly variable
|
||||
for i in 1 2 3;
|
||||
do
|
||||
select var in a b c;
|
||||
do
|
||||
echo $REPLY;
|
||||
done <<< a; echo answer was $REPLY;
|
||||
done
|
||||
|
||||
for ((i=1; i <= 3; i++ ))
|
||||
do
|
||||
echo $(( 2**$i ));
|
||||
done
|
||||
|
||||
this is bash_logout
|
||||
a
|
||||
a
|
||||
bad-interp
|
||||
./invocation.tests: ./x23: nosuchfile: bad interpreter: No such file or directory
|
||||
cannot execute binary file
|
||||
@@ -0,0 +1,78 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
: ${THIS_SH:=./bash}
|
||||
|
||||
# invocation modes and errors
|
||||
|
||||
${THIS_SH} .
|
||||
|
||||
#${THIS_SH} --version -c 'exit 0' bash
|
||||
#${THIS_SH} --help -c 'exit 0' bash
|
||||
|
||||
${THIS_SH} -c |& sed 's|^.*/bash|bash|'
|
||||
|
||||
${THIS_SH} --badopt |& sed 's|^.*/bash|bash|'
|
||||
${THIS_SH} --initfile |& sed 's|^.*/bash|bash|'
|
||||
${THIS_SH} -q |& sed 's|^.*/bash|bash|'
|
||||
|
||||
export BASH_ARGV0=this-bash
|
||||
${THIS_SH} -c 'echo $0 $BASH_ARGV0'
|
||||
unset BASH_ARGV0
|
||||
|
||||
{ ${THIS_SH} -c 'echo $-' bash | grep c >/dev/null; } && echo '$- for -c includes c'
|
||||
|
||||
# BASHOPTS
|
||||
${THIS_SH} ./invocation1.sub
|
||||
# SHELLOPTS
|
||||
${THIS_SH} ./invocation2.sub
|
||||
|
||||
# rudimentary pretty-print tests
|
||||
${THIS_SH} ./invocation3.sub
|
||||
|
||||
: ${TMPDIR:=/tmp}
|
||||
TDIR=$TMPDIR/invocation-$$
|
||||
mkdir $TDIR || exit 1
|
||||
SAVEPWD=$PWD
|
||||
|
||||
echo 'echo this is bash_logout' > $TDIR/.bash_logout
|
||||
HOME=$TDIR ${THIS_SH} --login -c 'logout'
|
||||
rm -f $TDIR/.bash_logout
|
||||
|
||||
# script that ends with a comment and no newline
|
||||
printf 'echo a # comment' > $TDIR/x23.in
|
||||
${THIS_SH} $TDIR/x23.in
|
||||
printf 'echo a' > $TDIR/x23.in
|
||||
${THIS_SH} $TDIR/x23.in
|
||||
rm -f $TDIR/x23.in
|
||||
|
||||
# script with invalid interpreter
|
||||
cat > $TDIR/x23 <<EOF
|
||||
#! nosuchfile
|
||||
echo bad-interp
|
||||
EOF
|
||||
chmod +x $TDIR/x23
|
||||
|
||||
# this is fine
|
||||
${THIS_SH} $TDIR/x23
|
||||
command cd -L $TDIR
|
||||
# but this results in a bad-interpreter error
|
||||
./x23
|
||||
|
||||
# this should result in a cannot execute binary file error since ls is in $PATH
|
||||
PATH=/bin:/usr/bin
|
||||
${THIS_SH} ls |& sed 's|^.*: ||'
|
||||
|
||||
cd $SAVEPWD
|
||||
rm -rf $TDIR
|
||||
@@ -0,0 +1,40 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
set +o posix
|
||||
shopt -u xpg_echo
|
||||
|
||||
# check $BASHOPTS inheritance
|
||||
# the first should be an error
|
||||
${THIS_SH} -O checkhash -O badopt -c 'echo $BASHOPTS' bash 2>&1 | sed 's|^.*/bash|bash|'
|
||||
# this should reflect the default set of options
|
||||
${THIS_SH} -c 'echo $BASHOPTS'
|
||||
# now let's turn one of them on (checkhash is not enabled by default)
|
||||
${THIS_SH} -O checkhash -c 'echo $BASHOPTS' bash
|
||||
# let's turn one of them off
|
||||
${THIS_SH} +O checkwinsize -c 'echo $BASHOPTS' bash
|
||||
|
||||
# turn on a non-default option
|
||||
shopt -s checkhash
|
||||
export BASHOPTS
|
||||
# and make sure the child shell sees it enabled
|
||||
if ${THIS_SH} -c 'echo $BASHOPTS' | grep checkhash >/dev/null 2>&1; then
|
||||
:
|
||||
else
|
||||
echo 'BASHOPTS: checkhash not inherited correctly'
|
||||
fi
|
||||
shopt -u checkhash
|
||||
export -n BASHOPTS
|
||||
|
||||
# but assigning to BASHOPTS is an error
|
||||
BASHOPTS=$BASHOPTS
|
||||
@@ -0,0 +1,50 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
set +o posix
|
||||
shopt -u xpg_echo
|
||||
|
||||
echo $SHELLOPTS
|
||||
set +B # on by default
|
||||
# shouldn't appear
|
||||
echo $SHELLOPTS | grep braceexpand
|
||||
export SHELLOPTS
|
||||
# but it will appear here because it's enabled by default
|
||||
${THIS_SH} -c 'echo $SHELLOPTS'
|
||||
|
||||
# turn off an option that's on by default
|
||||
${THIS_SH} +B -c 'echo $SHELLOPTS'
|
||||
${THIS_SH} +o braceexpand -c 'echo $SHELLOPTS'
|
||||
|
||||
# turn on an option that's off by default
|
||||
if ${THIS_SH} -f -c 'echo $SHELLOPTS' | grep noglob 2>&1; then
|
||||
:
|
||||
else
|
||||
echo 'SHELLOPTS: noglob not inherited correctly'
|
||||
fi
|
||||
|
||||
# in a different way
|
||||
set -o noglob
|
||||
if ${THIS_SH} -c 'echo $SHELLOPTS' | grep noglob 2>&1; then
|
||||
:
|
||||
else
|
||||
echo 'SHELLOPTS: noglob not inherited correctly'
|
||||
fi
|
||||
|
||||
# restore default state
|
||||
set -o braceexpand
|
||||
set +o noglob
|
||||
|
||||
# but assigning to SHELLOPTS is an error; have to use set -o/+o
|
||||
SHELLOPTS=$SHELLOPTS
|
||||
@@ -0,0 +1,25 @@
|
||||
: ${THIS_SH:=./bash} ${TMPDIR:=/tmp}
|
||||
|
||||
# start at tests for pretty-print mode
|
||||
# so far these are cases that aren't handled by the printing code anywhere
|
||||
# else in the test suite
|
||||
|
||||
SCRIPT=$TMPDIR/pretty-print-$$
|
||||
|
||||
cat >$SCRIPT <<\EOF
|
||||
for i in 1 2 3
|
||||
{
|
||||
select var in a b c; { echo $REPLY; } <<<a
|
||||
echo answer was $REPLY
|
||||
}
|
||||
|
||||
for (( i=1; i <= 3; i++ ))
|
||||
{
|
||||
echo $(( 2**$i ))
|
||||
}
|
||||
EOF
|
||||
|
||||
${THIS_SH} --pretty-print $SCRIPT
|
||||
|
||||
rm -f $SCRIPT
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
# tests of disown -h
|
||||
|
||||
set -m
|
||||
|
||||
sleep 1&
|
||||
sleep 1&
|
||||
sleep 1&
|
||||
|
||||
disown -ah
|
||||
|
||||
sleep 1&
|
||||
sleep 1&
|
||||
sleep 1&
|
||||
|
||||
disown -rh
|
||||
@@ -0,0 +1,14 @@
|
||||
# When the shell is waiting, by means of the wait utility, for asynchronous
|
||||
# commands to complete, the reception of a signal for which a trap has been
|
||||
# set shall cause the wait utility to return immediately with an exit status
|
||||
# >128, immediately after which the trap associated with that signal shall be
|
||||
# taken.
|
||||
|
||||
trap 'echo got $(kill -l $BASH_TRAPSIG)' USR1
|
||||
|
||||
sleep 10 &
|
||||
( sleep 2 ; kill -USR1 $$ ) &
|
||||
|
||||
# should be interrupted by the signal
|
||||
wait
|
||||
[[ $? -gt 128 ]] || echo 'wait status not greater than 128'
|
||||
@@ -0,0 +1,42 @@
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# issues with taking the length of nameref variables
|
||||
#
|
||||
# just the basics
|
||||
|
||||
scalar=foo
|
||||
declare -a array=(foo)
|
||||
|
||||
declare -n name=array
|
||||
declare -n name1=array[0]
|
||||
declare -n name2=unset
|
||||
declare -n name3=
|
||||
declare -n name4='a&b'
|
||||
|
||||
echo ${#name} # length of nameref resolving to set variable
|
||||
echo ${#name1} # length of nameref resolving to valid non-identifier
|
||||
echo ${#name2} # length of nameref resolving to unset variable
|
||||
echo ${#name3} # length of nameref resolving to empty string
|
||||
echo ${#name4} # length of nameref resolving to invalid non-identifier
|
||||
|
||||
unset -n name name1
|
||||
|
||||
declare -n name=scalar
|
||||
declare -n name1=scalar[0]
|
||||
name4='aa&bb'
|
||||
declare -n name4
|
||||
|
||||
echo ${#name} # length of nameref resolving to set variable
|
||||
echo ${#name1} # length of nameref resolving to valid non-identifier
|
||||
echo ${#name4} # length of nameref resolving to invalid non-identifier
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user