add some missing files, update copyrights

This commit is contained in:
Chet Ramey
2024-04-25 15:50:39 -04:00
parent 622d318652
commit aadb6ffb93
116 changed files with 20558 additions and 1 deletions
+251
View File
@@ -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'}
+236
View File
@@ -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 */
};
+241
View File
@@ -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 */
};
+31
View File
@@ -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
+397
View File
@@ -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 */
+35
View File
@@ -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 */
+138
View File
@@ -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 */
+26
View File
@@ -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
+226
View File
@@ -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 */
+8
View File
@@ -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
+110
View File
@@ -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 */
+57
View File
@@ -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))
+50
View File
@@ -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;
}
+38
View File
@@ -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)
+406
View File
@@ -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;
}
+599
View File
@@ -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 */
+48
View File
@@ -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
+73
View File
@@ -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
View File
@@ -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
View File
@@ -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 */
+90
View File
@@ -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 */
+186
View File
@@ -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;
}
+157
View File
@@ -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 */
+639
View File
@@ -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
+84
View File
@@ -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 */
+458
View File
@@ -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
+150
View File
@@ -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
+1771
View File
File diff suppressed because it is too large Load Diff
+414
View File
@@ -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
}
+82
View File
@@ -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 */
+60
View File
@@ -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 */
+108
View File
@@ -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;
+682
View File
@@ -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 */
+81
View File
@@ -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
+76
View File
@@ -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 */
+44
View File
@@ -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 */
+336
View File
@@ -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
+24
View File
@@ -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;
+84
View File
@@ -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 */
+3
View File
@@ -0,0 +1,3 @@
#include <config.h>
#define XSIZE_INLINE _GL_EXTERN_INLINE
#include "xsize.h"
+108
View File
@@ -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 */
+80
View File
@@ -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 */
+147
View File
@@ -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;
}
+53
View File
@@ -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;
}
+80
View File
@@ -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
+44
View File
@@ -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);
}
+39
View File
@@ -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;
}
+41
View File
@@ -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
View File
@@ -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
])
+27
View File
@@ -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])
])
+44
View File
@@ -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
View File
@@ -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])
])
+31
View File
@@ -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
View File
@@ -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.
+92
View File
@@ -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
+38
View File
@@ -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
+43
View File
@@ -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
+98
View File
@@ -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
+52
View File
@@ -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
+50
View File
@@ -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
+39
View File
@@ -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
+45
View File
@@ -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
+40
View File
@@ -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
+85
View File
@@ -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
+59
View File
@@ -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
+192
View File
@@ -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
+153
View File
@@ -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
+65
View File
@@ -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
+26
View File
@@ -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"
+79
View File
@@ -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; }}
+77
View File
@@ -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
+138
View File
@@ -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 ; }
+36
View File
@@ -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
+64
View File
@@ -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
+28
View File
@@ -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
+19
View File
@@ -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 ]]
+98
View File
@@ -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
+70
View File
@@ -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
+42
View File
@@ -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
+72
View File
@@ -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
+33
View File
@@ -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
+99
View File
@@ -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
+103
View File
@@ -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
+309
View File
@@ -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
+69
View File
@@ -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
+55
View File
@@ -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
+62
View File
@@ -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
{
:
}
)
+44
View File
@@ -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
+74
View File
@@ -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
+16
View File
@@ -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
+35
View File
@@ -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"
+104
View File
@@ -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
+78
View 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
+40
View File
@@ -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
+50
View File
@@ -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
+25
View File
@@ -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
+29
View File
@@ -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
+14
View File
@@ -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'
+42
View File
@@ -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