diff --git a/local/patches/base/P0-bootstrap-workspace-fix.patch b/local/patches/base/P0-bootstrap-workspace-fix.patch index 383617473d..1519b3a849 100644 --- a/local/patches/base/P0-bootstrap-workspace-fix.patch +++ b/local/patches/base/P0-bootstrap-workspace-fix.patch @@ -1,9 +1,6 @@ diff --git a/bootstrap/Cargo.toml b/bootstrap/Cargo.toml +index 82120c21..50faead5 100644 --- a/bootstrap/Cargo.toml +++ b/bootstrap/Cargo.toml -@@ -7,5 +7,3 @@ edition = "2024" - license = "MIT" - --[workspace] +@@ -8 +7,0 @@ license = "MIT" - - [dependencies] diff --git a/local/patches/base/P9-base-local-relibc-patch.patch b/local/patches/base/P9-base-local-relibc-patch.patch new file mode 100644 index 0000000000..dd91b9a656 --- /dev/null +++ b/local/patches/base/P9-base-local-relibc-patch.patch @@ -0,0 +1,8 @@ +diff --git a/Cargo.toml b/Cargo.toml +index 9e776232..fdaeae69 100644 +--- a/Cargo.toml ++++ b/Cargo.toml +@@ -117 +117,2 @@ precedence = "deny" +-#redox-ioctl = { path = "../../relibc/source/redox-ioctl" } ++redox-ioctl = { path = "../../relibc/source/redox-ioctl" } ++redox-rt = { path = "../../relibc/source/redox-rt" } diff --git a/local/patches/relibc/P4-pselect-implementation.patch b/local/patches/relibc/P4-pselect-implementation.patch new file mode 100644 index 0000000000..975d566903 --- /dev/null +++ b/local/patches/relibc/P4-pselect-implementation.patch @@ -0,0 +1,127 @@ +diff --git a/src/header/sys_select/cbindgen.toml b/src/header/sys_select/cbindgen.toml +index 36bfa1fc..bb88cf19 100644 +--- a/src/header/sys_select/cbindgen.toml ++++ b/src/header/sys_select/cbindgen.toml +@@ -2,0 +3,2 @@ after_includes = """ ++#include // for timespec (needed by pselect) ++ +@@ -33,0 +36,3 @@ exclude = ["FD_SETSIZE", "fd_set"] ++ ++[export.rename] ++"timespec" = "struct timespec" +diff --git a/src/header/sys_select/mod.rs b/src/header/sys_select/mod.rs +index 45e7a238..d4c34fb1 100644 +--- a/src/header/sys_select/mod.rs ++++ b/src/header/sys_select/mod.rs +@@ -5 +5 @@ +-use core::mem; ++use core::{mem, ptr}; +@@ -11,0 +12,2 @@ use crate::{ ++ bits_sigset_t::sigset_t, ++ bits_timespec::timespec, +@@ -15 +17 @@ use crate::{ +- epoll_data, epoll_event, epoll_wait, ++ epoll_data, epoll_event, epoll_pwait, +@@ -48,0 +51,5 @@ pub struct fd_set { ++/// Inner implementation shared by `select` and `pselect`. ++/// ++/// Uses epoll internally, mirroring the `poll_epoll` pattern from `poll/mod.rs`. ++/// The `timeout_ms` parameter is in milliseconds (-1 = block forever, 0 = non-blocking). ++/// The `sigmask` parameter is passed through to `epoll_pwait` for atomic signal mask changes. +@@ -55 +62,2 @@ pub fn select_epoll( +- timeout: Option<&mut timeval>, ++ timeout_ms: c_int, ++ sigmask: *const sigset_t, +@@ -136,11 +144 @@ pub fn select_epoll( +- match timeout { +- Some(timeout) => { +- let sec_ms = (timeout.tv_sec as c_int).checked_mul(1000); +- let usec_ms = (timeout.tv_usec as c_int) / 1000; +- match sec_ms.and_then(|s| s.checked_add(usec_ms)) { +- Some(s) => s as c_int, +- None => c_int::MAX, +- } +- } +- None => -1, +- } ++ timeout_ms +@@ -149 +147 @@ pub fn select_epoll( +- epoll_wait( ++ epoll_pwait( +@@ -153,0 +152 @@ pub fn select_epoll( ++ sigmask, +@@ -188 +187 @@ pub fn select_epoll( +-/// See . ++/// See . +@@ -196,0 +196,11 @@ pub unsafe extern "C" fn select( ++ let timeout_ms = if timeout.is_null() { ++ -1 ++ } else { ++ let tv = unsafe { &*timeout }; ++ let sec_ms = (tv.tv_sec as c_int).checked_mul(1000); ++ let usec_ms = (tv.tv_usec as c_int) / 1000; ++ match sec_ms.and_then(|s| s.checked_add(usec_ms)) { ++ Some(s) => s as c_int, ++ None => c_int::MAX, ++ } ++ }; +@@ -215,5 +225,2 @@ pub unsafe extern "C" fn select( +- if timeout.is_null() { +- None +- } else { +- Some(unsafe { &mut *timeout }) +- } ++ timeout_ms, ++ ptr::null() +@@ -228,0 +236,51 @@ pub unsafe extern "C" fn select( ++ ++/// See . ++#[unsafe(no_mangle)] ++pub unsafe extern "C" fn pselect( ++ nfds: c_int, ++ readfds: *mut fd_set, ++ writefds: *mut fd_set, ++ exceptfds: *mut fd_set, ++ timeout: *const timespec, ++ sigmask: *const sigset_t, ++) -> c_int { ++ let timeout_ms = if timeout.is_null() { ++ -1 ++ } else { ++ let ts = unsafe { &*timeout }; ++ if ts.tv_sec > (c_int::MAX / 1000) as _ { ++ c_int::MAX ++ } else { ++ ((ts.tv_sec as c_int) * 1000) + ((ts.tv_nsec as c_int) / 1000000) ++ } ++ }; ++ trace_expr!( ++ select_epoll( ++ nfds, ++ if readfds.is_null() { ++ None ++ } else { ++ Some(unsafe { &mut *readfds }) ++ }, ++ if writefds.is_null() { ++ None ++ } else { ++ Some(unsafe { &mut *writefds }) ++ }, ++ if exceptfds.is_null() { ++ None ++ } else { ++ Some(unsafe { &mut *exceptfds }) ++ }, ++ timeout_ms, ++ sigmask ++ ), ++ "pselect({}, {:p}, {:p}, {:p}, {:p}, {:p})", ++ nfds, ++ readfds, ++ writefds, ++ exceptfds, ++ timeout, ++ sigmask ++ ) ++} diff --git a/local/recipes/dev/bison/recipe.toml b/local/recipes/dev/bison/recipe.toml index ec50419fed..94d48f24fc 100644 --- a/local/recipes/dev/bison/recipe.toml +++ b/local/recipes/dev/bison/recipe.toml @@ -7,13 +7,102 @@ template = "custom" script = """ DYNAMIC_INIT export ac_cv_func___fseterr=yes -export ac_cv_type_sigset_t=yes + +# Gnulib cross-compilation: relibc has standard POSIX headers and types +# but gnulib's configure can't run test programs during cross-compilation. +# Without these, gnulib generates broken #define fallbacks and replacement headers. + +# Standard headers (gnulib can't detect these when cross-compiling) +export ac_cv_header_stdio_h=yes +export ac_cv_header_stdlib_h=yes +export ac_cv_header_string_h=yes +export ac_cv_header_strings_h=yes +export ac_cv_header_inttypes_h=yes +export ac_cv_header_stdint_h=yes +export ac_cv_header_unistd_h=yes +export ac_cv_header_sys_types_h=yes +export ac_cv_header_sys_stat_h=yes +export ac_cv_header_time_h=yes +export ac_cv_header_sys_time_h=yes +export ac_cv_header_sys_select_h=yes +export ac_cv_header_wchar_h=yes +export ac_cv_header_wctype_h=yes +export ac_cv_header_signal_h=yes +export ac_cv_header_dirent_h=yes +export ac_cv_header_fcntl_h=yes +export ac_cv_header_locale_h=yes +export ac_cv_header_errno_h=yes +export ac_cv_header_ctype_h=yes +export ac_cv_header_limits_h=yes +export ac_cv_header_stdarg_h=yes +export ac_cv_header_stddef_h=yes +export ac_cv_header_math_h=yes +export ac_cv_header_spawn_h=yes +export gl_cv_header_inttypes_h=yes +export gl_cv_header_stdint_h=yes +export gl_cv_header_inttypes_h_with_uintmax=yes +export ac_cv_have_inttypes_h_with_uintmax=yes + +# Standard types (gnulib generates broken fallbacks without these) +export ac_cv_type_intmax_t=yes +export ac_cv_type_uintmax_t=yes +export ac_cv_type_gid_t=yes +export ac_cv_type_uid_t=yes +export ac_cv_type_pid_t=yes +export ac_cv_type_mode_t=yes +export ac_cv_type_off_t=yes +export ac_cv_type_size_t=yes +export ac_cv_type_ssize_t=yes +export ac_cv_type_ptrdiff_t=yes +export ac_cv_type_nlink_t=yes +export ac_cv_type_mbstate_t=yes +export gl_cv_type_intmax_t=yes +export gl_cv_type_ptrdiff_t_signed=yes +export gl_cv_header_inttypes_h_with_uintmax=yes +export ac_cv_have_inttypes_h_with_uintmax=yes + +# Spawn functions (relibc provides these via the P3-spawn patch) +export gl_cv_func_spawn_posix_spawn=yes +export gl_cv_func_spawn_posix_spawnp=yes +export ac_cv_func_posix_spawn=yes +export ac_cv_func_posix_spawnp=yes +export ac_cv_func_posix_spawn_file_actions_init=yes +export ac_cv_func_posix_spawn_file_actions_destroy=yes +export ac_cv_func_posix_spawn_file_actions_addopen=yes +export ac_cv_func_posix_spawn_file_actions_addclose=yes +export ac_cv_func_posix_spawn_file_actions_adddup2=yes +export ac_cv_func_posix_spawnattr_init=yes +export ac_cv_func_posix_spawnattr_destroy=yes +export ac_cv_func_posix_spawnattr_setflags=yes +export ac_cv_func_posix_spawnattr_getflags=yes +export ac_cv_func_posix_spawnattr_setsigmask=yes +export ac_cv_func_posix_spawnattr_getsigmask=yes + +# Other functions +export ac_cv_func_getpagesize=yes +export ac_cv_func_memcmp_working=yes +export ac_cv_func_mmap_fixed_mapped=yes + +# Spawn types export ac_cv_type_posix_spawnattr_t=yes export ac_cv_type_posix_spawn_file_actions_t=yes COOKBOOK_CONFIGURE_FLAGS+=( --disable-nls ) -cookbook_configure + +# Cross-compilation fix: run configure manually, then patch the +# generated Makefile to use host bison instead of the cross-compiled +# wrapper. The generated Makefile hardcodes +# BISON = $(top_builddir)/tests/bison +# which wraps the x86_64-unknown-redox binary — unrunnable on the host. +"${COOKBOOK_CONFIGURE}" "${COOKBOOK_CONFIGURE_FLAGS[@]}" +sed -i 's|^BISON = .*|BISON = /usr/bin/bison|' "${COOKBOOK_BUILD}/Makefile" + +# Fix gnulib cross-compilation misdetections in config.h +"${COOKBOOK_ROOT}/local/scripts/gnulib-cross-fix.sh" "${COOKBOOK_BUILD}/lib/config.h" + +"${COOKBOOK_MAKE}" -j "${COOKBOOK_MAKE_JOBS}" +"${COOKBOOK_MAKE}" install DESTDIR="${COOKBOOK_STAGE}" """ [package] diff --git a/local/recipes/dev/bison/source/configure b/local/recipes/dev/bison/source/configure index c8c4cfebdf..67b26a3e32 100755 --- a/local/recipes/dev/bison/source/configure +++ b/local/recipes/dev/bison/source/configure @@ -1,11 +1,11 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.71 for GNU Bison 3.8.2. +# Generated by GNU Autoconf 2.73 for GNU Bison 3.8.2. # # Report bugs to . # # -# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Copyright (C) 1992-1996, 1998-2017, 2020-2026 Free Software Foundation, # Inc. # # @@ -17,21 +17,21 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. + # contradicts POSIX and common usage. Disable this. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( +else case e in #( + e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi @@ -103,13 +103,13 @@ IFS=$as_save_IFS ;; esac -# We did not find ourselves, most probably we were run as `sh COMMAND' +# We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi @@ -131,30 +131,33 @@ case $- in # (((( *x* ) as_opts=-x ;; * ) as_opts= ;; esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +case $# in # (( + 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; + *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; +esac # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +# out after a failed 'exec'. +printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="as_nop=: -if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 + as_bourne_compatible="if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. + # contradicts POSIX and common usage. Disable this. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST -else \$as_nop - case \`(set -o) 2>/dev/null\` in #( +else case e in #( + e) case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi " @@ -172,8 +175,9 @@ as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : -else \$as_nop - exitcode=1; echo positional parameters were not saved. +else case e in #( + e) exitcode=1; echo positional parameters were not saved. ;; +esac fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) @@ -187,14 +191,15 @@ test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes -else $as_nop - as_have_required=no +else case e in #( + e) as_have_required=no ;; +esac fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do @@ -227,12 +232,13 @@ IFS=$as_save_IFS if $as_found then : -else $as_nop - if { test -f "$SHELL" || test -f "$SHELL.exe"; } && +else case e in #( + e) if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes -fi +fi ;; +esac fi @@ -252,29 +258,33 @@ case $- in # (((( *x* ) as_opts=-x ;; * ) as_opts= ;; esac -exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +case $# in # (( + 0) exec $CONFIG_SHELL $as_opts "$as_myself" ;; + *) exec $CONFIG_SHELL $as_opts "$as_myself" "$@" ;; +esac # Admittedly, this is quite paranoid, since all the known shells bail -# out after a failed `exec'. -printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +# out after a failed 'exec'. +printf '%s\n' "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : - printf "%s\n" "$0: This script requires a shell more modern than all" - printf "%s\n" "$0: the shells that I found on your system." + printf '%s\n' "$0: This script requires a shell more modern than all" + printf '%s\n' "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then - printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" - printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." + printf '%s\n' "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf '%s\n' "$0: be upgraded to zsh 4.3.4 or later." else - printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and bug-bison@gnu.org + printf '%s\n' "$0: Please tell bug-autoconf@gnu.org and bug-bison@gnu.org $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 -fi +fi ;; +esac fi fi SHELL=${CONFIG_SHELL-/bin/sh} @@ -313,14 +323,6 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -335,7 +337,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -344,7 +346,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_dir" | +printf '%s\n' X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -389,11 +391,12 @@ then : { eval $1+=\$2 }' -else $as_nop - as_fn_append () +else case e in #( + e) as_fn_append () { eval $1=\$$1\$2 - } + } ;; +esac fi # as_fn_append # as_fn_arith ARG... @@ -407,21 +410,14 @@ then : { as_val=$(( $* )) }' -else $as_nop - as_fn_arith () +else case e in #( + e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } + } ;; +esac fi # as_fn_arith -# as_fn_nop -# --------- -# Do nothing but, unlike ":", preserve the value of $?. -as_fn_nop () -{ - return $? -} -as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -433,9 +429,9 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - printf "%s\n" "$as_me: error: $2" >&2 + printf '%s\n' "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -462,7 +458,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X/"$0" | +printf '%s\n' X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -495,6 +491,8 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits /[$]LINENO/= ' <$as_myself | sed ' + t clear + :clear s/[$]LINENO.*/&-/ t lineno b @@ -506,7 +504,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || - { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + { printf '%s\n' "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall @@ -520,30 +518,6 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits exit } - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -# For backward compatibility with old third-party macros, we provide -# the shell variables $as_echo and $as_echo_n. New code should use -# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. -as_echo='printf %s\n' -as_echo_n='printf %s' - - rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -555,9 +529,9 @@ if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. + # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -582,10 +556,12 @@ as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated test -n "$DJDIR" || exec 7<&0 /dev/null | sed 1q` # Initializations. # ac_default_prefix=/usr/local +ac_clean_CONFIG_STATUS= ac_clean_files= ac_config_libobj_dir=. LIBOBJS= @@ -1026,6 +1003,7 @@ HAVE_RAISE HAVE_PTHREAD_SIGMASK HAVE_POSIX_SIGNALBLOCKING ASM_SYMBOL_PREFIX +EGREP GL_GNULIB_POSIX_SPAWNATTR_DESTROY GL_GNULIB_POSIX_SPAWNATTR_SETSIGMASK GL_GNULIB_POSIX_SPAWNATTR_GETSIGMASK @@ -1165,6 +1143,7 @@ HAVE_MBSINIT HAVE_BTOWC NEXT_AS_FIRST_DIRECTIVE_MATH_H NEXT_MATH_H +GREP SED LTLIBMULTITHREAD LIBMULTITHREAD @@ -2184,8 +2163,6 @@ HAVE_LIBTEXTSTYLE RANLIB ARFLAGS AR -EGREP -GREP CPP host_os host_vendor @@ -2248,13 +2225,13 @@ INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM PACKAGE_COPYRIGHT_YEAR +ECHO_T +ECHO_N +ECHO_C target_alias host_alias build_alias LIBS -ECHO_T -ECHO_N -ECHO_C DEFS mandir localedir @@ -2432,9 +2409,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" + as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -2458,9 +2435,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: \`$ac_useropt'" + as_fn_error $? "invalid feature name: '$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -2671,9 +2648,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" + as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -2687,9 +2664,9 @@ do ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: \`$ac_useropt'" + as_fn_error $? "invalid package name: '$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf '%s\n' "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -2717,8 +2694,8 @@ do | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" + -*) as_fn_error $? "unrecognized option: '$ac_option' +Try '$0 --help' for more information" ;; *=*) @@ -2726,16 +2703,16 @@ Try \`$0 --help' for more information" # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + as_fn_error $? "invalid variable name: '$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. - printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 + printf '%s\n' "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 + printf '%s\n' "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -2743,7 +2720,7 @@ Try \`$0 --help' for more information" done if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` + ac_option=--`printf '%s\n' $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi @@ -2751,7 +2728,7 @@ if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; - *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + *) printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -2776,7 +2753,7 @@ do as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done -# There might be people who depend on the old broken behavior: `$host' +# There might be people who depend on the old broken behavior: '$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias @@ -2815,7 +2792,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_myself" | +printf '%s\n' X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -2844,7 +2821,7 @@ if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_msg="sources are in $srcdir, but 'cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` @@ -2872,7 +2849,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures GNU Bison 3.8.2 to adapt to many kinds of systems. +'configure' configures GNU Bison 3.8.2 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -2886,11 +2863,11 @@ Configuration: --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages + -q, --quiet, --silent do not print 'checking ...' messages --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' + -C, --config-cache alias for '--cache-file=config.cache' -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] + --srcdir=DIR find the sources in DIR [configure dir or '..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX @@ -2898,10 +2875,10 @@ Installation directories: --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. +By default, 'make install' will install all the files in +'$ac_default_prefix/bin', '$ac_default_prefix/lib' etc. You can specify +an installation prefix other than '$ac_default_prefix' using '--prefix', +for instance '--prefix=\$HOME'. For better control, use the options below. @@ -2998,16 +2975,16 @@ Some influential environment variables: CXX C++ compiler command CXXFLAGS C++ compiler flags CPP C preprocessor - YACC The `Yet Another Compiler Compiler' implementation to use. - Defaults to the first program found out of: `bison -y', `byacc', - `yacc'. + YACC The 'Yet Another Compiler Compiler' implementation to use. + Defaults to the first program found out of: 'bison -y', 'byacc', + 'yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a - default value of `-d' given by some make applications. + default value of '-d' given by some make applications. M4 Location of GNU M4 1.4.6 or later. Defaults to the first program of 'm4', 'gm4', or 'gnum4' on PATH that meets Autoconf needs. -Use these variables to override the choices made by `configure' or to help +Use these variables to override the choices made by 'configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . @@ -3028,9 +3005,9 @@ if test "$ac_init_help" = "recursive"; then case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -3067,7 +3044,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + printf '%s\n' "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -3077,9 +3054,9 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF GNU Bison configure 3.8.2 -generated by GNU Autoconf 2.71 +generated by GNU Autoconf 2.73 -Copyright (C) 2021 Free Software Foundation, Inc. +Copyright (C) 2026 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -3103,7 +3080,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -3111,18 +3088,19 @@ printf "%s\n" "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf '%s\n' "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval @@ -3142,7 +3120,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -3150,18 +3128,19 @@ printf "%s\n" "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf '%s\n' "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval @@ -3175,13 +3154,13 @@ fi ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> @@ -3189,14 +3168,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile @@ -3213,7 +3194,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -3221,18 +3202,19 @@ printf "%s\n" "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err } then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf '%s\n' "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval @@ -3252,7 +3234,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -3260,7 +3242,7 @@ printf "%s\n" "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err @@ -3270,11 +3252,12 @@ printf "%s\n" "$ac_try_echo"; } >&5 } then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf '%s\n' "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would @@ -3292,20 +3275,20 @@ fi ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. */ + which can conflict with char $2 (void); below. */ #include #undef $2 @@ -3316,7 +3299,7 @@ else $as_nop #ifdef __cplusplus extern "C" #endif -char $2 (); +char $2 (void); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ @@ -3335,15 +3318,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext + conftest$ac_exeext conftest.$ac_ext ;; +esac fi eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func @@ -3361,7 +3346,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -3369,7 +3354,7 @@ printf "%s\n" "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err @@ -3379,11 +3364,12 @@ printf "%s\n" "$ac_try_echo"; } >&5 } then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf '%s\n' "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=1 + ac_retval=1 ;; +esac fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would @@ -3402,13 +3388,13 @@ fi ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 @@ -3438,16 +3424,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - eval "$3=yes" +else case e in #( + e) eval "$3=yes" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type @@ -3465,29 +3453,30 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : ac_retval=0 -else $as_nop - printf "%s\n" "$as_me: program exited with status $ac_status" >&5 - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf '%s\n' "$as_me: program exited with status $ac_status" >&5 + printf '%s\n' "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ac_retval=$ac_status + ac_retval=$ac_status ;; +esac fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno @@ -3540,18 +3529,19 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=$ac_mid; break -else $as_nop - as_fn_arith $ac_mid + 1 && ac_lo=$as_val +else case e in #( + e) as_fn_arith $ac_mid + 1 && ac_lo=$as_val if test $ac_lo -le $ac_mid; then ac_lo= ac_hi= break fi - as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val + as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int @@ -3586,20 +3576,23 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_lo=$ac_mid; break -else $as_nop - as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val +else case e in #( + e) as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val if test $ac_mid -le $ac_hi; then ac_lo= ac_hi= break fi - as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val + as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done -else $as_nop - ac_lo= ac_hi= +else case e in #( + e) ac_lo= ac_hi= ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext # Binary search between lo and hi bounds. @@ -3622,8 +3615,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_hi=$ac_mid -else $as_nop - as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val +else case e in #( + e) as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done @@ -3671,8 +3665,9 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : echo >>conftest.val; read $3 &5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 printf %s "checking whether $as_decl_name is declared... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 -else $as_nop - as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` +else case e in #( + e) as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` eval ac_save_FLAGS=\$$6 as_fn_append $6 " $5" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -3726,16 +3721,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" -else $as_nop - eval "$3=no" +else case e in #( + e) eval "$3=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval $6=\$ac_save_FLAGS - + ;; +esac fi eval ac_res=\$$3 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno ac_compile="$ac_save_ac_compile" @@ -3748,13 +3745,13 @@ printf "%s\n" "$ac_res" >&6; } ac_fn_c_check_member () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 printf %s "checking for $2.$3... " >&6; } if eval test \${$4+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int @@ -3770,8 +3767,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $5 int @@ -3787,16 +3784,19 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$4=yes" -else $as_nop - eval "$4=no" +else case e in #( + e) eval "$4=no" ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi eval ac_res=\$$4 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_member @@ -3805,7 +3805,7 @@ for ac_arg do case $ac_arg in *\'*) - ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done @@ -3817,7 +3817,7 @@ case $ac_configure_args_raw in ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" - ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; + ac_configure_args_raw=` printf '%s\n' "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF @@ -3825,7 +3825,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by GNU Bison $as_me 3.8.2, which was -generated by GNU Autoconf 2.71. Invocation command line was +generated by GNU Autoconf 2.73. Invocation command line was $ $0$ac_configure_args_raw @@ -3865,7 +3865,7 @@ do */) ;; *) as_dir=$as_dir/ ;; esac - printf "%s\n" "PATH: $as_dir" + printf '%s\n' "PATH: $as_dir" done IFS=$as_save_IFS @@ -3900,7 +3900,7 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf '%s\n' "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; @@ -3929,31 +3929,22 @@ done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Sanitize IFS. - IFS=" "" $as_nl" - # Save into config.log some information that might help in debugging. - { - echo - - printf "%s\n" "## ---------------- ## -## Cache variables. ## -## ---------------- ##" - echo - # The following way of writing the cache mishandles newlines in values, +# Dump the cache to stdout. It can be in a pipe (this is a requirement). +ac_cache_dump () +{ + # The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. ( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( - *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + *_cv_*) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf '%s\n' "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -3962,67 +3953,95 @@ printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} esac ;; esac done + (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) + # 'set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) + # 'set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) - echo +} - printf "%s\n" "## ----------------- ## +# Print debugging info to stdout. +ac_dump_debugging_info () +{ + echo + + printf '%s\n' "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + ac_cache_dump + echo + + printf '%s\n' "## ----------------- ## ## Output variables. ## ## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; + esac + printf '%s\n' "$ac_var='$ac_val'" + done | sort + echo + + if test -n "$ac_subst_files"; then + printf '%s\n' "## ------------------- ## +## File substitutions. ## +## ------------------- ##" echo - for ac_var in $ac_subst_vars + for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'*) ac_val=`printf '%s\n' "$ac_val" | sed "s/'/'\\\\\\\\''/g"`;; esac - printf "%s\n" "$ac_var='\''$ac_val'\''" + printf '%s\n' "$ac_var='$ac_val'" done | sort echo + fi - if test -n "$ac_subst_files"; then - printf "%s\n" "## ------------------- ## -## File substitutions. ## -## ------------------- ##" - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - printf "%s\n" "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - printf "%s\n" "## ----------- ## + if test -s confdefs.h; then + printf '%s\n' "## ----------- ## ## confdefs.h. ## ## ----------- ##" - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - printf "%s\n" "$as_me: caught signal $ac_signal" - printf "%s\n" "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + printf '%s\n' "$as_me: caught signal $ac_signal" + printf '%s\n' "$as_me: exit $exit_status" +} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. +ac_exit_trap () +{ + exit_status= + # Sanitize IFS. + IFS=" "" $as_nl" + # Save into config.log some information that might help in debugging. + ac_dump_debugging_info >&5 + eval "rm -f $ac_clean_CONFIG_STATUS core *.core core.conftest.*" && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status -' 0 +} + +trap 'ac_exit_trap $?' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done @@ -4031,21 +4050,21 @@ ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h -printf "%s\n" "/* confdefs.h */" > confdefs.h +printf '%s\n' "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. -printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h +printf '%s\n' "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h -printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h +printf '%s\n' "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h -printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h +printf '%s\n' "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h -printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h +printf '%s\n' "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h -printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h +printf '%s\n' "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h -printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h +printf '%s\n' "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. @@ -4067,14 +4086,14 @@ do ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf '%s\n' "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } fi done @@ -4082,27 +4101,120 @@ if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -printf "%s\n" "$as_me: loading cache $cache_file" >&6;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf '%s\n' "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -printf "%s\n" "$as_me: creating cache $cache_file" >&6;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf '%s\n' "$as_me: creating cache $cache_file" >&6;} >$cache_file fi +# Test code for whether the C compiler supports C23 (global declarations) +ac_c_conftest_c23_globals=' +/* Does the compiler advertise conformance to C17 or earlier? + Although GCC 14 does not do that, even with -std=gnu23, + it is close enough, and defines __STDC_VERSION == 202000L. */ +#if !defined __STDC_VERSION__ || __STDC_VERSION__ <= 201710L +# error "Compiler advertises conformance to C17 or earlier" +#endif + +// Check alignas. +char alignas (double) c23_aligned_as_double; +char alignas (0) c23_no_special_alignment; +extern char c23_aligned_as_int; +char alignas (0) alignas (int) c23_aligned_as_int; + +// Check alignof. +enum +{ + c23_int_alignment = alignof (int), + c23_int_array_alignment = alignof (int[100]), + c23_char_alignment = alignof (char) +}; +static_assert (0 < -alignof (int), "alignof is signed"); + +int function_with_unnamed_parameter (int) { return 0; } + +void c23_noreturn (); + +/* Test parsing of string and char UTF-8 literals (including hex escapes). + The parens pacify GCC 15. */ +bool use_u8 = (!sizeof u8"\xFF") == (!u8'\''x'\''); + +bool check_that_bool_works = true | false | !nullptr; +#if !true +# error "true does not work in #if" +#endif +#if false +#elifdef __STDC_VERSION__ +#else +# error "#elifdef does not work" +#endif + +#ifndef __has_c_attribute +# error "__has_c_attribute not defined" +#endif + +#ifndef __has_include +# error "__has_include not defined" +#endif + +#define LPAREN() ( +#define FORTY_TWO(x) 42 +#define VA_OPT_TEST(r, x, ...) __VA_OPT__ (FORTY_TWO r x)) +static_assert (VA_OPT_TEST (LPAREN (), 0, <:-) == 42); + +static_assert (0b101010 == 42); +static_assert (0B101010 == 42); +static_assert (0xDEAD'\''BEEF == 3'\''735'\''928'\''559); +static_assert (0.500'\''000'\''000 == 0.5); + +enum unsignedish : unsigned int { uione = 1 }; +static_assert (0 < -uione); + +#include +constexpr nullptr_t null_pointer = nullptr; + +static typeof (1 + 1L) two () { return 2; } +static long int three () { return 3; } +' + +# Test code for whether the C compiler supports C23 (body of main). +ac_c_conftest_c23_main=' + { + label_before_declaration: + int arr[10] = {}; + if (arr[0]) + goto label_before_declaration; + if (!arr[0]) + goto label_at_end_of_block; + label_at_end_of_block: + } + ok |= !null_pointer; + ok |= two != three; +' + +# Test code for whether the C compiler supports C23 (complete). +ac_c_conftest_c23_program="${ac_c_conftest_c23_globals} + +int +main (int, char **) +{ + int ok = 0; + ${ac_c_conftest_c23_main} + return ok; +} +" + # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' -/* Does the compiler advertise C89 conformance? - Do not test the value of __STDC__, because some compilers set it to 0 - while being otherwise adequately conformant. */ -#if !defined __STDC__ -# error "Compiler does not advertise C89 conformance" -#endif +/* Do not test the value of __STDC__, because some compilers define it to 0 + or do not define it, while otherwise adequately conforming. */ #include #include @@ -4110,9 +4222,7 @@ struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; +static char *e (char **p, int i) { return p[i]; } @@ -4126,6 +4236,21 @@ static char *f (char * (*g) (char **, int), char **p, ...) return s; } +/* C89 style stringification. */ +#define noexpand_stringify(a) #a +const char *stringified = noexpand_stringify(arbitrary+token=sequence); + +/* C89 style token pasting. Exercises some of the corner cases that + e.g. old MSVC gets wrong, but not very hard. */ +#define noexpand_concat(a,b) a##b +#define expand_concat(a,b) noexpand_concat(a,b) +extern int vA; +extern int vbee; +#define aye A +#define bee B +int *pvA = &expand_concat(v,aye); +int *pvbee = &noexpand_concat(v,bee); + /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated @@ -4153,20 +4278,24 @@ ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' -// Does the compiler advertise C99 conformance? +/* Does the compiler advertise C99 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif +// See if C++-style comments work. + #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); +extern void free (void *); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare -// FILE and stderr. +// FILE and stderr, and "aND" is used instead of "and" to work around +// GCC bug 40564 which is irrelevant here. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) @@ -4177,7 +4306,7 @@ test_varargs_macros (void) int y = 5678; debug ("Flag"); debug ("X = %d\n", x); - showlist (The first, second, and third items.); + showlist (The first, second, aND third items.); report (x>y, "x is %d but y is %d", x, y); } @@ -4212,7 +4341,6 @@ typedef const char *ccp; static inline int test_restrict (ccp restrict text) { - // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) @@ -4266,18 +4394,20 @@ ac_c_conftest_c99_main=' // Check restrict. if (test_restrict ("String literal") == 0) success = true; - char *restrict newvar = "Another string"; + const char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. - struct incomplete_array *ia = - malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + static struct incomplete_array *volatile incomplete_array_pointer; + struct incomplete_array *ia = incomplete_array_pointer; ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; + // Work around memory leak warnings. + free (ia); // Check named initializers. struct named_init ni = { @@ -4288,18 +4418,17 @@ ac_c_conftest_c99_main=' ni.number = 58; - int dynamic_array[ni.number]; - dynamic_array[0] = argv[0][0]; - dynamic_array[ni.number - 1] = 543; + // Do not test for VLAs, as some otherwise-conforming compilers lack them. + // C code should instead use __STDC_NO_VLA__; see Autoconf manual. // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' - || dynamic_array[ni.number - 1] != 543); + || ni.number != 58); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' -// Does the compiler advertise C11 conformance? +/* Does the compiler advertise C11 conformance? */ #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif @@ -4403,222 +4532,6 @@ main (int argc, char **argv) } " -# Test code for whether the C++ compiler supports C++98 (global declarations) -ac_cxx_conftest_cxx98_globals=' -// Does the compiler advertise C++98 conformance? -#if !defined __cplusplus || __cplusplus < 199711L -# error "Compiler does not advertise C++98 conformance" -#endif - -// These inclusions are to reject old compilers that -// lack the unsuffixed header files. -#include -#include - -// and are *not* freestanding headers in C++98. -extern void assert (int); -namespace std { - extern int strcmp (const char *, const char *); -} - -// Namespaces, exceptions, and templates were all added after "C++ 2.0". -using std::exception; -using std::strcmp; - -namespace { - -void test_exception_syntax() -{ - try { - throw "test"; - } catch (const char *s) { - // Extra parentheses suppress a warning when building autoconf itself, - // due to lint rules shared with more typical C programs. - assert (!(strcmp) (s, "test")); - } -} - -template struct test_template -{ - T const val; - explicit test_template(T t) : val(t) {} - template T add(U u) { return static_cast(u) + val; } -}; - -} // anonymous namespace -' - -# Test code for whether the C++ compiler supports C++98 (body of main) -ac_cxx_conftest_cxx98_main=' - assert (argc); - assert (! argv[0]); -{ - test_exception_syntax (); - test_template tt (2.0); - assert (tt.add (4) == 6.0); - assert (true && !false); -} -' - -# Test code for whether the C++ compiler supports C++11 (global declarations) -ac_cxx_conftest_cxx11_globals=' -// Does the compiler advertise C++ 2011 conformance? -#if !defined __cplusplus || __cplusplus < 201103L -# error "Compiler does not advertise C++11 conformance" -#endif - -namespace cxx11test -{ - constexpr int get_val() { return 20; } - - struct testinit - { - int i; - double d; - }; - - class delegate - { - public: - delegate(int n) : n(n) {} - delegate(): delegate(2354) {} - - virtual int getval() { return this->n; }; - protected: - int n; - }; - - class overridden : public delegate - { - public: - overridden(int n): delegate(n) {} - virtual int getval() override final { return this->n * 2; } - }; - - class nocopy - { - public: - nocopy(int i): i(i) {} - nocopy() = default; - nocopy(const nocopy&) = delete; - nocopy & operator=(const nocopy&) = delete; - private: - int i; - }; - - // for testing lambda expressions - template Ret eval(Fn f, Ret v) - { - return f(v); - } - - // for testing variadic templates and trailing return types - template auto sum(V first) -> V - { - return first; - } - template auto sum(V first, Args... rest) -> V - { - return first + sum(rest...); - } -} -' - -# Test code for whether the C++ compiler supports C++11 (body of main) -ac_cxx_conftest_cxx11_main=' -{ - // Test auto and decltype - auto a1 = 6538; - auto a2 = 48573953.4; - auto a3 = "String literal"; - - int total = 0; - for (auto i = a3; *i; ++i) { total += *i; } - - decltype(a2) a4 = 34895.034; -} -{ - // Test constexpr - short sa[cxx11test::get_val()] = { 0 }; -} -{ - // Test initializer lists - cxx11test::testinit il = { 4323, 435234.23544 }; -} -{ - // Test range-based for - int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, - 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; - for (auto &x : array) { x += 23; } -} -{ - // Test lambda expressions - using cxx11test::eval; - assert (eval ([](int x) { return x*2; }, 21) == 42); - double d = 2.0; - assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); - assert (d == 5.0); - assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); - assert (d == 5.0); -} -{ - // Test use of variadic templates - using cxx11test::sum; - auto a = sum(1); - auto b = sum(1, 2); - auto c = sum(1.0, 2.0, 3.0); -} -{ - // Test constructor delegation - cxx11test::delegate d1; - cxx11test::delegate d2(); - cxx11test::delegate d3(45); -} -{ - // Test override and final - cxx11test::overridden o1(55464); -} -{ - // Test nullptr - char *c = nullptr; -} -{ - // Test template brackets - test_template<::test_template> v(test_template(12)); -} -{ - // Unicode literals - char const *utf8 = u8"UTF-8 string \u2500"; - char16_t const *utf16 = u"UTF-8 string \u2500"; - char32_t const *utf32 = U"UTF-32 string \u2500"; -} -' - -# Test code for whether the C compiler supports C++11 (complete). -ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} -${ac_cxx_conftest_cxx11_globals} - -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_cxx_conftest_cxx98_main} - ${ac_cxx_conftest_cxx11_main} - return ok; -} -" - -# Test code for whether the C compiler supports C++98 (complete). -ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} -int -main (int argc, char **argv) -{ - int ok = 0; - ${ac_cxx_conftest_cxx98_main} - return ok; -} -" - as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" @@ -4722,7 +4635,7 @@ ac_aux_dir_candidates="${srcdir}/build-aux" # $ac_aux_dir_candidates and give up. ac_missing_aux_files="" ac_first_candidate=: -printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +printf '%s\n' "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in $ac_aux_dir_candidates @@ -4735,7 +4648,7 @@ do esac as_found=: - printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 ac_aux_dir_found=yes ac_install_sh= for ac_aux in $ac_aux_files @@ -4746,13 +4659,13 @@ do if test x"$ac_aux" = x"install-sh" then if test -f "${as_dir}install-sh"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 ac_install_sh="${as_dir}install-sh -c" elif test -f "${as_dir}install.sh"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 ac_install_sh="${as_dir}install.sh -c" elif test -f "${as_dir}shtool"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 ac_install_sh="${as_dir}shtool install -c" else ac_aux_dir_found=no @@ -4764,7 +4677,7 @@ do fi else if test -f "${as_dir}${ac_aux}"; then - printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 else ac_aux_dir_found=no if $ac_first_candidate; then @@ -4787,8 +4700,9 @@ IFS=$as_save_IFS if $as_found then : -else $as_nop - as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 +else case e in #( + e) as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5 ;; +esac fi @@ -4816,38 +4730,44 @@ for ac_var in $ac_precious_vars; do eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&5 +printf '%s\n' "$as_me: error: '$ac_var' was set to '$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' was not set in the previous run" >&5 +printf '%s\n' "$as_me: error: '$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` + ac_old_val_w= + for ac_val in x $ac_old_val; do + ac_old_val_w="$ac_old_val_w $ac_val" + done + ac_new_val_w= + for ac_val in x $ac_new_val; do + ac_new_val_w="$ac_new_val_w $ac_val" + done if test "$ac_old_val_w" != "$ac_new_val_w"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: '$ac_var' has changed since the previous run:" >&5 +printf '%s\n' "$as_me: error: '$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&5 +printf '%s\n' "$as_me: warning: ignoring whitespace changes in '$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: former value: '$ac_old_val'" >&5 +printf '%s\n' "$as_me: former value: '$ac_old_val'" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: current value: '$ac_new_val'" >&5 +printf '%s\n' "$as_me: current value: '$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in - *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_arg=$ac_var=`printf '%s\n' "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in @@ -4857,17 +4777,34 @@ printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi done if $ac_cache_corrupted; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf '%s\n' "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run '${MAKE-make} distclean' and/or 'rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -4878,7 +4815,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu PACKAGE_COPYRIGHT_YEAR=2021 -printf "%s\n" "#define PACKAGE_COPYRIGHT_YEAR $PACKAGE_COPYRIGHT_YEAR" >>confdefs.h +printf '%s\n' "#define PACKAGE_COPYRIGHT_YEAR $PACKAGE_COPYRIGHT_YEAR" >>confdefs.h @@ -4911,14 +4848,14 @@ am__api_version='1.16' # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test ${ac_cv_path_install+y} then : printf %s "(cached) " >&6 -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS @@ -4934,8 +4871,8 @@ case $as_dir in #(( ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root + # OSF/1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF/1 since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do @@ -4972,7 +4909,8 @@ esac IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir - + ;; +esac fi if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install @@ -4984,8 +4922,8 @@ fi INSTALL=$ac_install_sh fi fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -printf "%s\n" "$INSTALL" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +printf '%s\n' "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. @@ -4995,7 +4933,7 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 printf %s "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. @@ -5050,8 +4988,8 @@ else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf '%s\n' "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= @@ -5068,9 +5006,9 @@ test "$program_prefix" != NONE && test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. -# By default was `s,x,x', remove it if useless. +# By default was 's,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`printf "%s\n" "$program_transform_name" | sed "$ac_script"` +program_transform_name=`printf '%s\n' "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. @@ -5085,8 +5023,8 @@ if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 -printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +printf '%s\n' "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then @@ -5106,13 +5044,13 @@ if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_STRIP+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$STRIP"; then +else case e in #( + e) if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5127,22 +5065,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -printf "%s\n" "$STRIP" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +printf '%s\n' "$STRIP" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -5151,13 +5090,13 @@ if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_STRIP+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_STRIP"; then +else case e in #( + e) if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5172,22 +5111,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -printf "%s\n" "$ac_ct_STRIP" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +printf '%s\n' "$ac_ct_STRIP" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then @@ -5195,8 +5135,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP @@ -5209,14 +5149,14 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if test ${ac_cv_path_mkdir+y} then : printf %s "(cached) " >&6 -else $as_nop - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +else case e in #( + e) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS @@ -5230,7 +5170,7 @@ do as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir ('*'coreutils) '* | \ - 'BusyBox '* | \ + *'BusyBox '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; @@ -5239,34 +5179,33 @@ do done done IFS=$as_save_IFS - + ;; +esac fi test -d ./--version && rmdir ./--version if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else - # As a last resort, use the slow shell script. Don't cache a - # value for MKDIR_P within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - MKDIR_P="$ac_install_sh -d" + # As a last resort, use plain mkdir -p, + # in the hope it doesn't have the bugs of ancient mkdir. + MKDIR_P='mkdir -p' fi fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -printf "%s\n" "$MKDIR_P" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +printf '%s\n' "$MKDIR_P" >&6; } -for ac_prog in gawk mawk nawk awk +for ac_prog in gawk mawk nawk awk 'busybox awk' do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AWK+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$AWK"; then +else case e in #( + e) if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5281,40 +5220,41 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -printf "%s\n" "$AWK" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +printf '%s\n' "$AWK" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi test -n "$AWK" && break done -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 printf %s "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} -ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +ac_make=`printf '%s\n' "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval test \${ac_cv_prog_make_${ac_make}_set+y} then : printf %s "(cached) " >&6 -else $as_nop - cat >conftest.make <<\_ACEOF +else case e in #( + e) cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: - @echo '@@@%%%=$(MAKE)=@@@%%%' + @printf '%s\n' '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in @@ -5323,15 +5263,16 @@ case `${MAKE-make} -f conftest.make 2>/dev/null` in *) eval ac_cv_prog_make_${ac_make}_set=no;; esac -rm -f conftest.make +rm -f conftest.make ;; +esac fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf '%s\n' "yes" >&6; } SET_MAKE= else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi @@ -5356,13 +5297,13 @@ case $enable_silent_rules in # ((( *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 -else $as_nop - if printf "%s\n" 'TRUE=$(BAR$(V)) +else case e in #( + e) if printf '%s\n' 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 @@ -5372,10 +5313,11 @@ am__doit: am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no +fi ;; +esac fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +printf '%s\n' "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' @@ -5410,10 +5352,10 @@ fi VERSION='3.8.2' -printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h +printf '%s\n' "#define PACKAGE \"$PACKAGE\"" >>confdefs.h -printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h +printf '%s\n' "#define VERSION \"$VERSION\"" >>confdefs.h # Some tools Automake needs. @@ -5522,13 +5464,13 @@ case $enable_silent_rules in # ((( *) AM_DEFAULT_VERBOSITY=0;; esac am_make=${MAKE-make} -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 printf %s "checking whether $am_make supports nested variables... " >&6; } if test ${am_cv_make_support_nested_variables+y} then : printf %s "(cached) " >&6 -else $as_nop - if printf "%s\n" 'TRUE=$(BAR$(V)) +else case e in #( + e) if printf '%s\n' 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 @@ -5538,10 +5480,11 @@ am__doit: am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no +fi ;; +esac fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +printf '%s\n' "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' @@ -5564,6 +5507,9 @@ ac_config_headers="$ac_config_headers lib/config.h:lib/config.in.h" + + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -5572,13 +5518,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5593,22 +5539,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf '%s\n' "$CC" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -5617,13 +5564,13 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5638,22 +5585,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf '%s\n' "$ac_ct_CC" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -5661,8 +5609,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -5675,13 +5623,13 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5696,22 +5644,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf '%s\n' "$CC" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -5720,13 +5669,13 @@ fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no @@ -5746,7 +5695,7 @@ do continue fi ac_cv_prog_CC="cc" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -5765,15 +5714,16 @@ if test $ac_prog_rejected = yes; then ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf '%s\n' "$CC" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -5784,13 +5734,13 @@ if test -z "$CC"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5805,22 +5755,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf '%s\n' "$CC" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -5833,13 +5784,13 @@ if test -z "$CC"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5854,22 +5805,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf '%s\n' "$ac_ct_CC" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -5881,8 +5833,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -5894,13 +5846,13 @@ if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CC"; then +else case e in #( + e) if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5915,22 +5867,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi CC=$ac_cv_prog_CC if test -n "$CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -printf "%s\n" "$CC" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf '%s\n' "$CC" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -5939,13 +5892,13 @@ if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CC"; then +else case e in #( + e) if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -5960,22 +5913,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -printf "%s\n" "$ac_ct_CC" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf '%s\n' "$ac_ct_CC" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -5983,8 +5937,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -5996,13 +5950,13 @@ fi fi -test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +test -z "$CC" && { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. -printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do @@ -6012,7 +5966,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -6022,7 +5976,7 @@ printf "%s\n" "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done @@ -6042,9 +5996,9 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } -ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +ac_link_default=`printf '%s\n' "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" @@ -6065,14 +6019,14 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' + # Autoconf-2.13 could set the ac_cv_exeext variable to 'no'. +# So ignore a value of 'no', otherwise this would lead to 'EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. @@ -6092,7 +6046,7 @@ do ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' + # safe: cross compilers may not add the suffix if given an '-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. @@ -6103,33 +6057,35 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else $as_nop - ac_file='' +else case e in #( + e) ac_file='' ;; +esac fi if test -z "$ac_file" then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } -printf "%s\n" "$as_me: failed program was:" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } +printf '%s\n' "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf '%s\n' "yes" >&6; } ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -printf "%s\n" "$ac_file" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf '%s\n' "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in @@ -6137,16 +6093,16 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. + # If both 'conftest.exe' and 'conftest' are 'present' (well, observable) +# catch 'conftest.exe'. For instance with Cygwin, 'ls conftest' will +# work properly (i.e., refer to 'conftest.exe'), while it won't with +# 'rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in @@ -6156,15 +6112,16 @@ for ac_file in conftest.exe conftest conftest.*; do * ) break;; esac done -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +else case e in #( + e) { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi rm -f conftest conftest$ac_cv_exeext -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -printf "%s\n" "$ac_cv_exeext" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf '%s\n' "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext @@ -6176,6 +6133,8 @@ int main (void) { FILE *f = fopen ("conftest.out", "w"); + if (!f) + return 1; return ferror (f) || fclose (f) != 0; ; @@ -6185,7 +6144,7 @@ _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" @@ -6194,10 +6153,10 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in @@ -6205,36 +6164,37 @@ printf "%s\n" "$ac_try_echo"; } >&5 *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5; } +If you meant to cross compile, use '--host'. +See 'config.log' for more details" "$LINENO" 5; } fi fi fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -printf "%s\n" "$cross_compiling" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf '%s\n' "$cross_compiling" >&6; } -rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +rm -f conftest.$ac_ext conftest$ac_cv_exeext \ + conftest.o conftest.obj conftest.out ac_clean_files=$ac_clean_files_save -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -6252,10 +6212,10 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do @@ -6266,28 +6226,30 @@ then : break;; esac done -else $as_nop - printf "%s\n" "$as_me: failed program was:" >&5 +else case e in #( + e) printf '%s\n' "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 -{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +{ { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext +rm -f conftest.$ac_cv_objext conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -printf "%s\n" "$ac_cv_objext" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf '%s\n' "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -6304,15 +6266,17 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no +else case e in #( + e) ac_compiler_gnu=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf '%s\n' "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then @@ -6322,13 +6286,13 @@ else fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_c_werror_flag=$ac_c_werror_flag +else case e in #( + e) ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" @@ -6346,8 +6310,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes -else $as_nop - CFLAGS="" +else case e in #( + e) CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6362,8 +6326,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - ac_c_werror_flag=$ac_save_c_werror_flag +else case e in #( + e) ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6380,15 +6344,18 @@ if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf '%s\n' "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then @@ -6407,19 +6374,68 @@ fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C23 features" >&5 +printf %s "checking for $CC option to enable C23 features... " >&6; } +if test ${ac_cv_prog_cc_c23+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_cv_prog_cc_c23=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c23_program +_ACEOF +for ac_arg in '' -std=gnu23 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c23=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c23" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC ;; +esac +fi + +if test "x$ac_cv_prog_cc_c23" = xno +then : + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf '%s\n' "unsupported" >&6; } +else case e in #( + e) if test "x$ac_cv_prog_cc_c23" = x +then : + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf '%s\n' "none needed" >&6; } +else case e in #( + e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c23" >&5 +printf '%s\n' "$ac_cv_prog_cc_c23" >&6; } + CC="$CC $ac_cv_prog_cc_c23" ;; +esac +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c23 + ac_prog_cc_stdc=c23 ;; +esac +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c11=no +else case e in #( + e) ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF -for ac_arg in '' -std=gnu11 +for ac_arg in '' -std=gnu11 -std:c11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" @@ -6430,36 +6446,39 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c11" = xno then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c11" = x + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf '%s\n' "unsupported" >&6; } +else case e in #( + e) if test "x$ac_cv_prog_cc_c11" = x then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 -printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } - CC="$CC $ac_cv_prog_cc_c11" + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf '%s\n' "none needed" >&6; } +else case e in #( + e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf '%s\n' "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 - ac_prog_cc_stdc=c11 + ac_prog_cc_stdc=c11 ;; +esac fi fi if test x$ac_prog_cc_stdc = xno then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c99=no +else case e in #( + e) ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6476,36 +6495,39 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c99" = xno then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c99" = x + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf '%s\n' "unsupported" >&6; } +else case e in #( + e) if test "x$ac_cv_prog_cc_c99" = x then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 -printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } - CC="$CC $ac_cv_prog_cc_c99" + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf '%s\n' "none needed" >&6; } +else case e in #( + e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf '%s\n' "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 - ac_prog_cc_stdc=c99 + ac_prog_cc_stdc=c99 ;; +esac fi fi if test x$ac_prog_cc_stdc = xno then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cc_c89=no +else case e in #( + e) ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -6522,25 +6544,28 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext -CC=$ac_save_CC +CC=$ac_save_CC ;; +esac fi if test "x$ac_cv_prog_cc_c89" = xno then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cc_c89" = x + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf '%s\n' "unsupported" >&6; } +else case e in #( + e) if test "x$ac_cv_prog_cc_c89" = x then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } - CC="$CC $ac_cv_prog_cc_c89" + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf '%s\n' "none needed" >&6; } +else case e in #( + e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf '%s\n' "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" ;; +esac fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 - ac_prog_cc_stdc=c89 + ac_prog_cc_stdc=c89 ;; +esac fi fi @@ -6556,13 +6581,13 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 printf %s "checking whether $CC understands -c and -o together... " >&6; } if test ${am_cv_prog_cc_c_o+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -6592,10 +6617,11 @@ _ACEOF fi done rm -f core conftest* - unset am_i + unset am_i ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +printf '%s\n' "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. @@ -6612,13 +6638,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler is clang" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the compiler is clang" >&5 printf %s "checking whether the compiler is clang... " >&6; } if test ${gl_cv_compiler_clang+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __clang__ @@ -6637,23 +6663,25 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_compiler_clang=no -else $as_nop - gl_cv_compiler_clang=yes +else case e in #( + e) gl_cv_compiler_clang=yes ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_compiler_clang" >&5 -printf "%s\n" "$gl_cv_compiler_clang" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_compiler_clang" >&5 +printf '%s\n' "$gl_cv_compiler_clang" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for compiler option needed when checking for declarations" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for compiler option needed when checking for declarations" >&5 printf %s "checking for compiler option needed when checking for declarations... " >&6; } if test ${gl_cv_compiler_check_decl_option+y} then : printf %s "(cached) " >&6 -else $as_nop - if test $gl_cv_compiler_clang = yes; then +else case e in #( + e) if test $gl_cv_compiler_clang = yes; then save_ac_compile="$ac_compile" ac_compile="$ac_compile -Werror=implicit-function-declaration" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6670,18 +6698,20 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_compiler_check_decl_option='-Werror=implicit-function-declaration' -else $as_nop - gl_cv_compiler_check_decl_option=none +else case e in #( + e) gl_cv_compiler_check_decl_option=none ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_compile="$save_ac_compile" else gl_cv_compiler_check_decl_option=none fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_compiler_check_decl_option" >&5 -printf "%s\n" "$gl_cv_compiler_check_decl_option" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_compiler_check_decl_option" >&5 +printf '%s\n' "$gl_cv_compiler_check_decl_option" >&6; } if test "x$gl_cv_compiler_check_decl_option" != xnone; then ac_compile_for_check_decl="$ac_compile $gl_cv_compiler_check_decl_option" else @@ -6692,7 +6722,7 @@ DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @@ -6729,8 +6759,8 @@ esac fi done rm -f confinc.* confmf.* -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 -printf "%s\n" "${_am_result}" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 +printf '%s\n' "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test ${enable_dependency_tracking+y} @@ -6755,13 +6785,13 @@ fi depcc="$CC" am_compiler_list= -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CC_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then +else case e in #( + e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up @@ -6865,10 +6895,11 @@ else $as_nop else am_cv_CC_dependencies_compiler_type=none fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 -printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +printf '%s\n' "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if @@ -6882,12 +6913,6 @@ else fi - - - - - - ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -6902,13 +6927,13 @@ if test -z "$CXX"; then do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$CXX"; then +else case e in #( + e) if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -6923,22 +6948,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 -printf "%s\n" "$CXX" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +printf '%s\n' "$CXX" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -6951,13 +6977,13 @@ if test -z "$CXX"; then do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CXX+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_CXX"; then +else case e in #( + e) if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -6972,22 +6998,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CXX="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 -printf "%s\n" "$ac_ct_CXX" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +printf '%s\n' "$ac_ct_CXX" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -6999,8 +7026,8 @@ done else case $cross_compiling:$ac_tool_warned in yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX @@ -7010,7 +7037,7 @@ fi fi fi # Provide some information about the compiler. -printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do @@ -7020,7 +7047,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -7030,17 +7057,17 @@ printf "%s\n" "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 printf %s "checking whether the compiler supports GNU C++... " >&6; } if test ${ac_cv_cxx_compiler_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -7057,15 +7084,17 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_compiler_gnu=yes -else $as_nop - ac_compiler_gnu=no +else case e in #( + e) ac_compiler_gnu=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 -printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +printf '%s\n' "$ac_cv_cxx_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test $ac_compiler_gnu = yes; then @@ -7075,13 +7104,13 @@ else fi ac_test_CXXFLAGS=${CXXFLAGS+y} ac_save_CXXFLAGS=$CXXFLAGS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 printf %s "checking whether $CXX accepts -g... " >&6; } if test ${ac_cv_prog_cxx_g+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_cxx_werror_flag=$ac_cxx_werror_flag +else case e in #( + e) ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" @@ -7099,8 +7128,8 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes -else $as_nop - CXXFLAGS="" +else case e in #( + e) CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -7115,8 +7144,8 @@ _ACEOF if ac_fn_cxx_try_compile "$LINENO" then : -else $as_nop - ac_cxx_werror_flag=$ac_save_cxx_werror_flag +else case e in #( + e) ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -7133,15 +7162,18 @@ if ac_fn_cxx_try_compile "$LINENO" then : ac_cv_prog_cxx_g=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - ac_cxx_werror_flag=$ac_save_cxx_werror_flag -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 -printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +printf '%s\n' "$ac_cv_prog_cxx_g" >&6; } if test $ac_test_CXXFLAGS; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then @@ -7157,100 +7189,6 @@ else CXXFLAGS= fi fi -ac_prog_cxx_stdcxx=no -if test x$ac_prog_cxx_stdcxx = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 -printf %s "checking for $CXX option to enable C++11 features... " >&6; } -if test ${ac_cv_prog_cxx_11+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_11=no -ac_save_CXX=$CXX -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_cxx_conftest_cxx11_program -_ACEOF -for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA -do - CXX="$ac_save_CXX $ac_arg" - if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_cxx11=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cxx_cxx11" != "xno" && break -done -rm -f conftest.$ac_ext -CXX=$ac_save_CXX -fi - -if test "x$ac_cv_prog_cxx_cxx11" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx11" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 -printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx11" -fi - ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 - ac_prog_cxx_stdcxx=cxx11 -fi -fi -if test x$ac_prog_cxx_stdcxx = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 -printf %s "checking for $CXX option to enable C++98 features... " >&6; } -if test ${ac_cv_prog_cxx_98+y} -then : - printf %s "(cached) " >&6 -else $as_nop - ac_cv_prog_cxx_98=no -ac_save_CXX=$CXX -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$ac_cxx_conftest_cxx98_program -_ACEOF -for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA -do - CXX="$ac_save_CXX $ac_arg" - if ac_fn_cxx_try_compile "$LINENO" -then : - ac_cv_prog_cxx_cxx98=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext conftest.beam - test "x$ac_cv_prog_cxx_cxx98" != "xno" && break -done -rm -f conftest.$ac_ext -CXX=$ac_save_CXX -fi - -if test "x$ac_cv_prog_cxx_cxx98" = xno -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -printf "%s\n" "unsupported" >&6; } -else $as_nop - if test "x$ac_cv_prog_cxx_cxx98" = x -then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -printf "%s\n" "none needed" >&6; } -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 -printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } - CXX="$CXX $ac_cv_prog_cxx_cxx98" -fi - ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 - ac_prog_cxx_stdcxx=cxx98 -fi -fi - ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -7259,13 +7197,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu depcc="$CXX" am_compiler_list= -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 printf %s "checking dependency style of $depcc... " >&6; } if test ${am_cv_CXX_dependencies_compiler_type+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then +else case e in #( + e) if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up @@ -7369,10 +7307,11 @@ else $as_nop else am_cv_CXX_dependencies_compiler_type=none fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 -printf "%s\n" "$am_cv_CXX_dependencies_compiler_type" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +printf '%s\n' "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if @@ -7395,7 +7334,7 @@ do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then - printf "%s\n" "#define $ac_item 1" >> confdefs.h + printf '%s\n' "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then @@ -7415,7 +7354,7 @@ done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : -printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h +printf '%s\n' "#define STDC_HEADERS 1" >>confdefs.h fi @@ -7424,13 +7363,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 printf %s "checking whether it is safe to define __EXTENSIONS__... " >&6; } if test ${ac_cv_safe_to_define___extensions__+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # define __EXTENSIONS__ 1 @@ -7446,21 +7385,23 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_safe_to_define___extensions__=yes -else $as_nop - ac_cv_safe_to_define___extensions__=no +else case e in #( + e) ac_cv_safe_to_define___extensions__=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 -printf "%s\n" "$ac_cv_safe_to_define___extensions__" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 +printf '%s\n' "$ac_cv_safe_to_define___extensions__" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether _XOPEN_SOURCE should be defined" >&5 printf %s "checking whether _XOPEN_SOURCE should be defined... " >&6; } if test ${ac_cv_should_define__xopen_source+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_should_define__xopen_source=no +else case e in #( + e) ac_cv_should_define__xopen_source=no if test $ac_cv_header_wchar_h = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -7479,8 +7420,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _XOPEN_SOURCE 500 @@ -7498,64 +7439,71 @@ if ac_fn_c_try_compile "$LINENO" then : ac_cv_should_define__xopen_source=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +fi ;; +esac fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 -printf "%s\n" "$ac_cv_should_define__xopen_source" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_should_define__xopen_source" >&5 +printf '%s\n' "$ac_cv_should_define__xopen_source" >&6; } - printf "%s\n" "#define _ALL_SOURCE 1" >>confdefs.h + printf '%s\n' "#define _ALL_SOURCE 1" >>confdefs.h - printf "%s\n" "#define _DARWIN_C_SOURCE 1" >>confdefs.h + printf '%s\n' "#define _COSMO_SOURCE 1" >>confdefs.h - printf "%s\n" "#define _GNU_SOURCE 1" >>confdefs.h + printf '%s\n' "#define _DARWIN_C_SOURCE 1" >>confdefs.h - printf "%s\n" "#define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h + printf '%s\n' "#define _GNU_SOURCE 1" >>confdefs.h - printf "%s\n" "#define _NETBSD_SOURCE 1" >>confdefs.h + printf '%s\n' "#define _HPUX_ALT_XOPEN_SOCKET_API 1" >>confdefs.h - printf "%s\n" "#define _OPENBSD_SOURCE 1" >>confdefs.h + printf '%s\n' "#define _NETBSD_SOURCE 1" >>confdefs.h - printf "%s\n" "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + printf '%s\n' "#define _OPENBSD_SOURCE 1" >>confdefs.h - printf "%s\n" "#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h + printf '%s\n' "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - printf "%s\n" "#define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h + printf '%s\n' "#define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1" >>confdefs.h - printf "%s\n" "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h + printf '%s\n' "#define __STDC_WANT_IEC_60559_BFP_EXT__ 1" >>confdefs.h - printf "%s\n" "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h + printf '%s\n' "#define __STDC_WANT_IEC_60559_DFP_EXT__ 1" >>confdefs.h - printf "%s\n" "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h + printf '%s\n' "#define __STDC_WANT_IEC_60559_EXT__ 1" >>confdefs.h - printf "%s\n" "#define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h + printf '%s\n' "#define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1" >>confdefs.h - printf "%s\n" "#define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h + printf '%s\n' "#define __STDC_WANT_IEC_60559_TYPES_EXT__ 1" >>confdefs.h - printf "%s\n" "#define _TANDEM_SOURCE 1" >>confdefs.h + printf '%s\n' "#define __STDC_WANT_LIB_EXT2__ 1" >>confdefs.h + + printf '%s\n' "#define __STDC_WANT_MATH_SPEC_FUNCS__ 1" >>confdefs.h + + printf '%s\n' "#define _TANDEM_SOURCE 1" >>confdefs.h if test $ac_cv_header_minix_config_h = yes then : MINIX=yes - printf "%s\n" "#define _MINIX 1" >>confdefs.h + printf '%s\n' "#define _MINIX 1" >>confdefs.h - printf "%s\n" "#define _POSIX_SOURCE 1" >>confdefs.h + printf '%s\n' "#define _POSIX_SOURCE 1" >>confdefs.h - printf "%s\n" "#define _POSIX_1_SOURCE 2" >>confdefs.h + printf '%s\n' "#define _POSIX_1_SOURCE 2" >>confdefs.h -else $as_nop - MINIX= +else case e in #( + e) MINIX= ;; +esac fi if test $ac_cv_safe_to_define___extensions__ = yes then : - printf "%s\n" "#define __EXTENSIONS__ 1" >>confdefs.h + printf '%s\n' "#define __EXTENSIONS__ 1" >>confdefs.h fi if test $ac_cv_should_define__xopen_source = yes then : - printf "%s\n" "#define _XOPEN_SOURCE 500" >>confdefs.h + printf '%s\n' "#define _XOPEN_SOURCE 500" >>confdefs.h fi @@ -7565,23 +7513,24 @@ fi $SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 printf %s "checking build system type... " >&6; } if test ${ac_cv_build+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_build_alias=$build_alias +else case e in #( + e) ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5 - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -printf "%s\n" "$ac_cv_build" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf '%s\n' "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; @@ -7597,25 +7546,26 @@ shift; shift # except with old shells: build_os=$* IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac +case $build_os in *\ *) build_os=`printf '%s\n' "$build_os" | sed 's/ /-/g'`;; esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 printf %s "checking host system type... " >&6; } if test ${ac_cv_host+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "x$host_alias" = x; then +else case e in #( + e) if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` || as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5 fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -printf "%s\n" "$ac_cv_host" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf '%s\n' "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; @@ -7631,7 +7581,7 @@ shift; shift # except with old shells: host_os=$* IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac +case $host_os in *\ *) host_os=`printf '%s\n' "$host_os" | sed 's/ /-/g'`;; esac @@ -7641,7 +7591,7 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac case "$host_os" in openbsd*) -printf "%s\n" "#define _ISOC11_SOURCE 1" >>confdefs.h +printf '%s\n' "#define _ISOC11_SOURCE 1" >>confdefs.h ;; esac @@ -7651,7 +7601,7 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then @@ -7661,8 +7611,8 @@ if test -z "$CPP"; then if test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 -else $as_nop - # Double quotes because $CC needs to be expanded +else case e in #( + e) # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false @@ -7680,9 +7630,10 @@ _ACEOF if ac_fn_c_try_cpp "$LINENO" then : -else $as_nop - # Broken: fails on valid input. -continue +else case e in #( + e) # Broken: fails on valid input. +continue ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext @@ -7696,15 +7647,16 @@ if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue -else $as_nop - # Passes both tests. +else case e in #( + e) # Passes both tests. ac_preproc_ok=: -break +break ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : @@ -7713,14 +7665,15 @@ fi done ac_cv_prog_CPP=$CPP - + ;; +esac fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -printf "%s\n" "$CPP" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +printf '%s\n' "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do @@ -7736,9 +7689,10 @@ _ACEOF if ac_fn_c_try_cpp "$LINENO" then : -else $as_nop - # Broken: fails on valid input. -continue +else case e in #( + e) # Broken: fails on valid input. +continue ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext @@ -7752,24 +7706,26 @@ if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue -else $as_nop - # Passes both tests. +else case e in #( + e) # Passes both tests. ac_preproc_ok=: -break +break ;; +esac fi rm -f conftest.err conftest.i conftest.$ac_ext done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +# Because of 'break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +else case e in #( + e) { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi ac_ext=c @@ -7779,14 +7735,14 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -printf %s "checking for grep that handles long lines and -e... " >&6; } -if test ${ac_cv_path_GREP+y} +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for egrep -e" >&5 +printf %s "checking for egrep -e... " >&6; } +if test ${ac_cv_path_EGREP_TRADITIONAL+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -z "$GREP"; then - ac_path_GREP_found=false +else case e in #( + e) if test -z "$EGREP_TRADITIONAL"; then + ac_path_EGREP_TRADITIONAL_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin @@ -7800,13 +7756,14 @@ do for ac_prog in grep ggrep do for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_GREP" || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in + ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue +# Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found. + # Check for GNU $ac_path_EGREP_TRADITIONAL +case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #( *GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; + ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;; +#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -7815,14 +7772,14 @@ case `"$ac_path_GREP" --version 2>&1` in cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" - printf "%s\n" 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + printf '%s\n' 'EGREP_TRADITIONAL' >> "conftest.nl" + "$ac_path_EGREP_TRADITIONAL" -E 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then + if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count + ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" + ac_path_EGREP_TRADITIONAL_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break @@ -7830,35 +7787,24 @@ case `"$ac_path_GREP" --version 2>&1` in rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac - $ac_path_GREP_found && break 3 + $ac_path_EGREP_TRADITIONAL_found && break 3 done done done IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then + : fi else - ac_cv_path_GREP=$GREP + ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -printf "%s\n" "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -printf %s "checking for egrep... " >&6; } -if test ${ac_cv_path_EGREP+y} + if test "$ac_cv_path_EGREP_TRADITIONAL" then : - printf %s "(cached) " >&6 -else $as_nop - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false + ac_cv_path_EGREP_TRADITIONAL="$ac_cv_path_EGREP_TRADITIONAL -E" +else case e in #( + e) if test -z "$EGREP_TRADITIONAL"; then + ac_path_EGREP_TRADITIONAL_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin @@ -7872,13 +7818,14 @@ do for ac_prog in egrep do for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" - as_fn_executable_p "$ac_path_EGREP" || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in + ac_path_EGREP_TRADITIONAL="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP_TRADITIONAL" || continue +# Check for GNU ac_path_EGREP_TRADITIONAL and select it if it is found. + # Check for GNU $ac_path_EGREP_TRADITIONAL +case `"$ac_path_EGREP_TRADITIONAL" --version 2>&1` in #( *GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; + ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" ac_path_EGREP_TRADITIONAL_found=:;; +#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -7887,14 +7834,14 @@ case `"$ac_path_EGREP" --version 2>&1` in cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" - printf "%s\n" 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + printf '%s\n' 'EGREP_TRADITIONAL' >> "conftest.nl" + "$ac_path_EGREP_TRADITIONAL" 'EGR(EP|AC)_TRADITIONAL$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then + if test $ac_count -gt ${ac_path_EGREP_TRADITIONAL_max-0}; then # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count + ac_cv_path_EGREP_TRADITIONAL="$ac_path_EGREP_TRADITIONAL" + ac_path_EGREP_TRADITIONAL_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break @@ -7902,35 +7849,36 @@ case `"$ac_path_EGREP" --version 2>&1` in rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac - $ac_path_EGREP_found && break 3 + $ac_path_EGREP_TRADITIONAL_found && break 3 done done done IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then + if test -z "$ac_cv_path_EGREP_TRADITIONAL"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else - ac_cv_path_EGREP=$EGREP + ac_cv_path_EGREP_TRADITIONAL=$EGREP_TRADITIONAL fi - - fi + ;; +esac +fi ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -printf "%s\n" "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP_TRADITIONAL" >&5 +printf '%s\n' "$ac_cv_path_EGREP_TRADITIONAL" >&6; } + EGREP_TRADITIONAL=$ac_cv_path_EGREP_TRADITIONAL - - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Minix Amsterdam compiler" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for Minix Amsterdam compiler" >&5 printf %s "checking for Minix Amsterdam compiler... " >&6; } if test ${gl_cv_c_amsterdam_compiler+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -7940,18 +7888,20 @@ Amsterdam _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Amsterdam" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Amsterdam" >/dev/null 2>&1 then : gl_cv_c_amsterdam_compiler=yes -else $as_nop - gl_cv_c_amsterdam_compiler=no +else case e in #( + e) gl_cv_c_amsterdam_compiler=no ;; +esac fi rm -rf conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_c_amsterdam_compiler" >&5 -printf "%s\n" "$gl_cv_c_amsterdam_compiler" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_c_amsterdam_compiler" >&5 +printf '%s\n' "$gl_cv_c_amsterdam_compiler" >&6; } if test $gl_cv_c_amsterdam_compiler = yes; then if test -z "$AR"; then @@ -7967,13 +7917,13 @@ printf "%s\n" "$gl_cv_c_amsterdam_compiler" >&6; } if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_AR+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$AR"; then +else case e in #( + e) if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -7988,22 +7938,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_AR="${ac_tool_prefix}ar" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi AR=$ac_cv_prog_AR if test -n "$AR"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -printf "%s\n" "$AR" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +printf '%s\n' "$AR" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -8012,13 +7963,13 @@ if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_AR+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_AR"; then +else case e in #( + e) if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -8033,22 +7984,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="ar" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -printf "%s\n" "$ac_ct_AR" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +printf '%s\n' "$ac_ct_AR" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi if test "x$ac_ct_AR" = x; then @@ -8056,8 +8008,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR @@ -8079,13 +8031,13 @@ fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$RANLIB"; then +else case e in #( + e) if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -8100,22 +8052,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -printf "%s\n" "$RANLIB" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +printf '%s\n' "$RANLIB" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -8124,13 +8077,13 @@ if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_RANLIB"; then +else case e in #( + e) if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -8145,22 +8098,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -printf "%s\n" "$ac_ct_RANLIB" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +printf '%s\n' "$ac_ct_RANLIB" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then @@ -8168,8 +8122,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB @@ -8220,13 +8174,13 @@ fi if test "$enable_largefile" != no then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 printf %s "checking for special C compiler options needed for large files... " >&6; } if test ${ac_cv_sys_largefile_CC+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_sys_largefile_CC=no +else case e in #( + e) ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do @@ -8235,13 +8189,16 @@ else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, +#ifndef FTYPE +# define FTYPE off_t +#endif + /* Check that FTYPE can represent 2**63 - 1 correctly. + We can't simply define LARGE_FTYPE to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) +#define LARGE_FTYPE (((FTYPE) 1 << 31 << 31) - 1 + ((FTYPE) 1 << 31 << 31)) + int FTYPE_is_large[(LARGE_FTYPE % 2147483629 == 721 + && LARGE_FTYPE % 2147483647 == 1) ? 1 : -1]; int main (void) @@ -8266,31 +8223,35 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam done CC=$ac_save_CC rm -f conftest.$ac_ext - fi + fi ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 -printf "%s\n" "$ac_cv_sys_largefile_CC" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 +printf '%s\n' "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 printf %s "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if test ${ac_cv_sys_file_offset_bits+y} then : printf %s "(cached) " >&6 -else $as_nop - while :; do +else case e in #( + e) while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, +#ifndef FTYPE +# define FTYPE off_t +#endif + /* Check that FTYPE can represent 2**63 - 1 correctly. + We can't simply define LARGE_FTYPE to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) +#define LARGE_FTYPE (((FTYPE) 1 << 31 << 31) - 1 + ((FTYPE) 1 << 31 << 31)) + int FTYPE_is_large[(LARGE_FTYPE % 2147483629 == 721 + && LARGE_FTYPE % 2147483647 == 1) ? 1 : -1]; int main (void) @@ -8310,13 +8271,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext #undef _FILE_OFFSET_BITS #define _FILE_OFFSET_BITS 64 #include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, +#ifndef FTYPE +# define FTYPE off_t +#endif + /* Check that FTYPE can represent 2**63 - 1 correctly. + We can't simply define LARGE_FTYPE to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) +#define LARGE_FTYPE (((FTYPE) 1 << 31 << 31) - 1 + ((FTYPE) 1 << 31 << 31)) + int FTYPE_is_large[(LARGE_FTYPE % 2147483629 == 721 + && LARGE_FTYPE % 2147483647 == 1) ? 1 : -1]; int main (void) @@ -8333,36 +8297,40 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break -done +done ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 -printf "%s\n" "$ac_cv_sys_file_offset_bits" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 +printf '%s\n' "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) -printf "%s\n" "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h +printf '%s\n' "#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits" >>confdefs.h ;; esac rm -rf conftest* case $ac_cv_sys_file_offset_bits in #( unknown) : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 printf %s "checking for _LARGE_FILES value needed for large files... " >&6; } if test ${ac_cv_sys_large_files+y} then : printf %s "(cached) " >&6 -else $as_nop - while :; do +else case e in #( + e) while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, +#ifndef FTYPE +# define FTYPE off_t +#endif + /* Check that FTYPE can represent 2**63 - 1 correctly. + We can't simply define LARGE_FTYPE to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) +#define LARGE_FTYPE (((FTYPE) 1 << 31 << 31) - 1 + ((FTYPE) 1 << 31 << 31)) + int FTYPE_is_large[(LARGE_FTYPE % 2147483629 == 721 + && LARGE_FTYPE % 2147483647 == 1) ? 1 : -1]; int main (void) @@ -8382,13 +8350,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext #undef _LARGE_FILES #define _LARGE_FILES 1 #include - /* Check that off_t can represent 2**63 - 1 correctly. - We can't simply define LARGE_OFF_T to be 9223372036854775807, +#ifndef FTYPE +# define FTYPE off_t +#endif + /* Check that FTYPE can represent 2**63 - 1 correctly. + We can't simply define LARGE_FTYPE to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 31 << 31) - 1 + ((off_t) 1 << 31 << 31)) - int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 - && LARGE_OFF_T % 2147483647 == 1) +#define LARGE_FTYPE (((FTYPE) 1 << 31 << 31) - 1 + ((FTYPE) 1 << 31 << 31)) + int FTYPE_is_large[(LARGE_FTYPE % 2147483629 == 721 + && LARGE_FTYPE % 2147483647 == 1) ? 1 : -1]; int main (void) @@ -8405,14 +8376,15 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_sys_large_files=unknown break -done +done ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 -printf "%s\n" "$ac_cv_sys_large_files" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 +printf '%s\n' "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) -printf "%s\n" "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h +printf '%s\n' "#define _LARGE_FILES $ac_cv_sys_large_files" >>confdefs.h ;; esac rm -rf conftest* ;; #( @@ -8427,13 +8399,13 @@ fi if test "$enable_year2038" != no then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for time_t past the year 2038" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for time_t past the year 2038" >&5 printf %s "checking for time_t past the year 2038... " >&6; } if test ${gl_cv_type_time_t_y2038+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -8448,22 +8420,24 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_type_time_t_y2038=yes -else $as_nop - gl_cv_type_time_t_y2038=no +else case e in #( + e) gl_cv_type_time_t_y2038=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_time_t_y2038" >&5 -printf "%s\n" "$gl_cv_type_time_t_y2038" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_time_t_y2038" >&5 +printf '%s\n' "$gl_cv_type_time_t_y2038" >&6; } if test "$gl_cv_type_time_t_y2038" = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit time_t with _TIME_BITS=64" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for 64-bit time_t with _TIME_BITS=64" >&5 printf %s "checking for 64-bit time_t with _TIME_BITS=64... " >&6; } if test ${gl_cv_type_time_t_bits_macro+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _TIME_BITS 64 #define _FILE_OFFSET_BITS 64 @@ -8480,20 +8454,22 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_type_time_t_bits_macro=yes -else $as_nop - gl_cv_type_time_t_bits_macro=no +else case e in #( + e) gl_cv_type_time_t_bits_macro=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_time_t_bits_macro" >&5 -printf "%s\n" "$gl_cv_type_time_t_bits_macro" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_time_t_bits_macro" >&5 +printf '%s\n' "$gl_cv_type_time_t_bits_macro" >&6; } if test "$gl_cv_type_time_t_bits_macro" = yes; then -printf "%s\n" "#define _TIME_BITS 64" >>confdefs.h +printf '%s\n' "#define _TIME_BITS 64" >>confdefs.h -printf "%s\n" "#define _FILE_OFFSET_BITS 64" >>confdefs.h +printf '%s\n' "#define _FILE_OFFSET_BITS 64" >>confdefs.h gl_cv_type_time_t_y2038=yes fi @@ -8510,29 +8486,30 @@ printf "%s\n" "#define _FILE_OFFSET_BITS 64" >>confdefs.h _ACEOF if ac_fn_c_try_compile "$LINENO" then : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "The 'time_t' type stops working after January 2038. Remove _USE_32BIT_TIME_T from the compiler flags. -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - # If not cross-compiling and says we should check, +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) # If not cross-compiling and says we should check, # and 'touch' works with a large timestamp, then evidently wider time_t # is desired and supported, so fail and ask the builder to fix the # problem. Otherwise, just warn the builder. if test "$gl_warned_about_y2038" != yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: The 'time_t' type stops working after January 2038, + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: The 'time_t' type stops working after January 2038, and this package needs a wider 'time_t' type if there is any way to access timestamps after that. Configure with 'CC=\"${CC} -m64\"' perhaps?" >&5 -printf "%s\n" "$as_me: WARNING: The 'time_t' type stops working after January 2038, +printf '%s\n' "$as_me: WARNING: The 'time_t' type stops working after January 2038, and this package needs a wider 'time_t' type if there is any way to access timestamps after that. Configure with 'CC=\"${CC} -m64\"' perhaps?" >&2;} gl_warned_about_y2038=yes fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi @@ -8548,7 +8525,7 @@ fi case "$host_os" in mingw*) -printf "%s\n" "#define __MINGW_USE_VC2005_COMPAT 1" >>confdefs.h +printf '%s\n' "#define __MINGW_USE_VC2005_COMPAT 1" >>confdefs.h ;; esac @@ -8563,8 +8540,8 @@ printf "%s\n" "#define __MINGW_USE_VC2005_COMPAT 1" >>confdefs.h if test ${enable_threads+y} then : enableval=$enable_threads; gl_use_threads=$enableval -else $as_nop - if test -n "$gl_use_threads_default"; then +else case e in #( + e) if test -n "$gl_use_threads_default"; then gl_use_threads="$gl_use_threads_default" else case "$host_os" in @@ -8585,7 +8562,8 @@ else $as_nop *) gl_use_threads=yes ;; esac fi - + ;; +esac fi if test "$gl_use_threads" = yes \ @@ -8991,8 +8969,9 @@ fi if test ${with_gnu_ld+y} then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes -else $as_nop - with_gnu_ld=no +else case e in #( + e) with_gnu_ld=no ;; +esac fi # Prepare PATH_SEPARATOR. @@ -9009,16 +8988,16 @@ if test "${PATH_SEPARATOR+set}" != set; then fi if test -n "$LD"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ld" >&5 printf %s "checking for ld... " >&6; } elif test "$GCC" = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 printf %s "checking for ld used by $CC... " >&6; } elif test "$with_gnu_ld" = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 printf %s "checking for GNU ld... " >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 printf %s "checking for non-GNU ld... " >&6; } fi if test -n "$LD"; then @@ -9028,8 +9007,8 @@ else if test ${acl_cv_path_LD+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) acl_cv_path_LD= # Final result of this test ac_prog=ld # Program to search in $PATH if test "$GCC" = yes; then @@ -9122,38 +9101,40 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - # The compiler produces 32-bit code. Add option '-m elf32_sparc' +else case e in #( + e) # The compiler produces 32-bit code. Add option '-m elf32_sparc' # so that the linker groks 32-bit object files. case "$acl_cv_path_LD " in *" -m elf32_sparc "*) ;; *) acl_cv_path_LD="$acl_cv_path_LD -m elf32_sparc" ;; esac - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac - + ;; +esac fi LD="$acl_cv_path_LD" fi if test -n "$LD"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 -printf "%s\n" "$LD" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +printf '%s\n' "$LD" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 printf %s "checking if the linker ($LD) is GNU ld... " >&6; } if test ${acl_cv_prog_gnu_ld+y} then : printf %s "(cached) " >&6 -else $as_nop - # I'd rather use --version here, but apparently some GNU lds only accept -v. +else case e in #( + e) # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &1 &5 -printf "%s\n" "$acl_cv_prog_gnu_ld" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $acl_cv_prog_gnu_ld" >&5 +printf '%s\n' "$acl_cv_prog_gnu_ld" >&6; } with_gnu_ld=$acl_cv_prog_gnu_ld - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for shared library run path origin" >&5 printf %s "checking for shared library run path origin... " >&6; } if test ${acl_cv_rpath+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_rpath=done - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 -printf "%s\n" "$acl_cv_rpath" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $acl_cv_rpath" >&5 +printf '%s\n' "$acl_cv_rpath" >&6; } wl="$acl_cv_wl" acl_libext="$acl_cv_libext" acl_shlibext="$acl_cv_shlibext" @@ -9200,20 +9183,21 @@ printf "%s\n" "$acl_cv_rpath" >&6; } if test ${enable_rpath+y} then : enableval=$enable_rpath; : -else $as_nop - enable_rpath=yes +else case e in #( + e) enable_rpath=yes ;; +esac fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking 32-bit host C ABI" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking 32-bit host C ABI" >&5 printf %s "checking 32-bit host C ABI... " >&6; } if test ${gl_cv_host_cpu_c_abi_32bit+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$gl_cv_host_cpu_c_abi"; then +else case e in #( + e) if test -n "$gl_cv_host_cpu_c_abi"; then case "$gl_cv_host_cpu_c_abi" in i386 | x86_64-x32 | arm | armhf | arm64-ilp32 | hppa | ia64-ilp32 | mips | mipsn32 | powerpc | riscv*-ilp32* | s390 | sparc) gl_cv_host_cpu_c_abi_32bit=yes ;; @@ -9277,8 +9261,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_host_cpu_c_abi_32bit=no -else $as_nop - gl_cv_host_cpu_c_abi_32bit=yes +else case e in #( + e) gl_cv_host_cpu_c_abi_32bit=yes ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -9302,8 +9287,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_host_cpu_c_abi_32bit=no -else $as_nop - gl_cv_host_cpu_c_abi_32bit=yes +else case e in #( + e) gl_cv_host_cpu_c_abi_32bit=yes ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -9323,8 +9309,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_host_cpu_c_abi_32bit=no -else $as_nop - gl_cv_host_cpu_c_abi_32bit=yes +else case e in #( + e) gl_cv_host_cpu_c_abi_32bit=yes ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -9344,8 +9331,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_host_cpu_c_abi_32bit=yes -else $as_nop - gl_cv_host_cpu_c_abi_32bit=no +else case e in #( + e) gl_cv_host_cpu_c_abi_32bit=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -9365,8 +9353,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_host_cpu_c_abi_32bit=no -else $as_nop - gl_cv_host_cpu_c_abi_32bit=yes +else case e in #( + e) gl_cv_host_cpu_c_abi_32bit=yes ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -9390,8 +9379,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_host_cpu_c_abi_32bit=no -else $as_nop - gl_cv_host_cpu_c_abi_32bit=yes +else case e in #( + e) gl_cv_host_cpu_c_abi_32bit=yes ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -9415,8 +9405,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_host_cpu_c_abi_32bit=no -else $as_nop - gl_cv_host_cpu_c_abi_32bit=yes +else case e in #( + e) gl_cv_host_cpu_c_abi_32bit=yes ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -9436,8 +9427,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_host_cpu_c_abi_32bit=no -else $as_nop - gl_cv_host_cpu_c_abi_32bit=yes +else case e in #( + e) gl_cv_host_cpu_c_abi_32bit=yes ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -9457,8 +9449,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_host_cpu_c_abi_32bit=no -else $as_nop - gl_cv_host_cpu_c_abi_32bit=yes +else case e in #( + e) gl_cv_host_cpu_c_abi_32bit=yes ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -9468,10 +9461,11 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_host_cpu_c_abi_32bit" >&5 -printf "%s\n" "$gl_cv_host_cpu_c_abi_32bit" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_host_cpu_c_abi_32bit" >&5 +printf '%s\n' "$gl_cv_host_cpu_c_abi_32bit" >&6; } HOST_CPU_C_ABI_32BIT="$gl_cv_host_cpu_c_abi_32bit" @@ -9479,13 +9473,13 @@ printf "%s\n" "$gl_cv_host_cpu_c_abi_32bit" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ELF binary format" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ELF binary format" >&5 printf %s "checking for ELF binary format... " >&6; } if test ${gl_cv_elf+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __ELF__ Extensible Linking Format @@ -9493,18 +9487,20 @@ else $as_nop _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Extensible Linking Format" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Extensible Linking Format" >/dev/null 2>&1 then : gl_cv_elf=yes -else $as_nop - gl_cv_elf=no +else case e in #( + e) gl_cv_elf=no ;; +esac fi rm -rf conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_elf" >&5 -printf "%s\n" "$gl_cv_elf" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_elf" >&5 +printf '%s\n' "$gl_cv_elf" >&6; } if test $gl_cv_elf = yes; then # Extract the ELF class of a file (5th byte) in decimal. # Cf. https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header @@ -9555,13 +9551,13 @@ printf "%s\n" "$gl_cv_elf" >&6; } } fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for the common suffixes of directories in the library search path" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for the common suffixes of directories in the library search path" >&5 printf %s "checking for the common suffixes of directories in the library search path... " >&6; } if test ${acl_cv_libdirstems+y} then : printf %s "(cached) " >&6 -else $as_nop - acl_libdirstem=lib +else case e in #( + e) acl_libdirstem=lib acl_libdirstem2= acl_libdirstem3= case "$host_os" in @@ -9622,10 +9618,11 @@ else $as_nop test -n "$acl_libdirstem2" || acl_libdirstem2="$acl_libdirstem" test -n "$acl_libdirstem3" || acl_libdirstem3="$acl_libdirstem" acl_cv_libdirstems="$acl_libdirstem,$acl_libdirstem2,$acl_libdirstem3" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $acl_cv_libdirstems" >&5 -printf "%s\n" "$acl_cv_libdirstems" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $acl_cv_libdirstems" >&5 +printf '%s\n' "$acl_cv_libdirstems" >&6; } acl_libdirstem=`echo "$acl_cv_libdirstems" | sed -e 's/,.*//'` acl_libdirstem2=`echo "$acl_cv_libdirstems" | sed -e 's/^[^,]*,//' -e 's/,.*//'` acl_libdirstem3=`echo "$acl_cv_libdirstems" | sed -e 's/^[^,]*,[^,]*,//' -e 's/,.*//'` @@ -10163,13 +10160,13 @@ fi done - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for libtextstyle" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for libtextstyle" >&5 printf %s "checking for libtextstyle... " >&6; } if test ${ac_cv_libtextstyle+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ac_save_LIBS="$LIBS" case " $LIBTEXTSTYLE" in *" -l"*) LIBS="$LIBS $LIBTEXTSTYLE" ;; @@ -10189,25 +10186,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_libtextstyle=yes -else $as_nop - ac_cv_libtextstyle='no' +else case e in #( + e) ac_cv_libtextstyle='no' ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libtextstyle" >&5 -printf "%s\n" "$ac_cv_libtextstyle" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libtextstyle" >&5 +printf '%s\n' "$ac_cv_libtextstyle" >&6; } if test "$ac_cv_libtextstyle" = yes; then HAVE_LIBTEXTSTYLE=yes -printf "%s\n" "#define HAVE_LIBTEXTSTYLE 1" >>confdefs.h +printf '%s\n' "#define HAVE_LIBTEXTSTYLE 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to link with libtextstyle" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to link with libtextstyle" >&5 printf %s "checking how to link with libtextstyle... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIBTEXTSTYLE" >&5 -printf "%s\n" "$LIBTEXTSTYLE" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LIBTEXTSTYLE" >&5 +printf '%s\n' "$LIBTEXTSTYLE" >&6; } else HAVE_LIBTEXTSTYLE=no CPPFLAGS="$ac_save_CPPFLAGS" @@ -10223,13 +10222,13 @@ printf "%s\n" "$LIBTEXTSTYLE" >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 printf %s "checking for inline... " >&6; } if test ${ac_cv_c_inline+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_c_inline=no +else case e in #( + e) ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -10247,10 +10246,11 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test "$ac_cv_c_inline" != no && break done - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 -printf "%s\n" "$ac_cv_c_inline" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +printf '%s\n' "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; @@ -10309,13 +10309,13 @@ fi # Gnulib uses '#pragma GCC diagnostic push' to silence some # warnings, but older gcc doesn't support this. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pragma GCC diagnostic push works" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether pragma GCC diagnostic push works" >&5 printf %s "checking whether pragma GCC diagnostic push works... " >&6; } if test ${lv_cv_gcc_pragma_push_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) save_CFLAGS=$CFLAGS CFLAGS='-Wunknown-pragmas -Werror' cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10335,14 +10335,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : lv_cv_gcc_pragma_push_works=yes -else $as_nop - lv_cv_gcc_pragma_push_works=no +else case e in #( + e) lv_cv_gcc_pragma_push_works=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - CFLAGS=$save_CFLAGS + CFLAGS=$save_CFLAGS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $lv_cv_gcc_pragma_push_works" >&5 -printf "%s\n" "$lv_cv_gcc_pragma_push_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $lv_cv_gcc_pragma_push_works" >&5 +printf '%s\n' "$lv_cv_gcc_pragma_push_works" >&6; } ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' @@ -10359,13 +10361,13 @@ ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ex ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Werror -Wunknown-warning-option" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Werror -Wunknown-warning-option" >&5 printf %s "checking whether C++ compiler handles -Werror -Wunknown-warning-option... " >&6; } if test ${gl_cv_warn_cxx__Werror__Wunknown_warning_option+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Werror -Wunknown-warning-option" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10382,21 +10384,24 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__Werror__Wunknown_warning_option=yes -else $as_nop - gl_cv_warn_cxx__Werror__Wunknown_warning_option=no +else case e in #( + e) gl_cv_warn_cxx__Werror__Wunknown_warning_option=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&5 -printf "%s\n" "$gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&5 +printf '%s\n' "$gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&6; } if test "x$gl_cv_warn_cxx__Werror__Wunknown_warning_option" = xyes then : gl_unknown_warnings_are_errors='-Wunknown-warning-option -Werror' -else $as_nop - gl_unknown_warnings_are_errors= +else case e in #( + e) gl_unknown_warnings_are_errors= ;; +esac fi ac_ext=cpp @@ -10408,13 +10413,13 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fno-exceptions" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fno-exceptions" >&5 printf %s "checking whether C++ compiler handles -fno-exceptions... " >&6; } if test ${gl_cv_warn_cxx__fno_exceptions+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fno-exceptions" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10431,16 +10436,18 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__fno_exceptions=yes -else $as_nop - gl_cv_warn_cxx__fno_exceptions=no +else case e in #( + e) gl_cv_warn_cxx__fno_exceptions=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fno_exceptions" >&5 -printf "%s\n" "$gl_cv_warn_cxx__fno_exceptions" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fno_exceptions" >&5 +printf '%s\n' "$gl_cv_warn_cxx__fno_exceptions" >&6; } if test "x$gl_cv_warn_cxx__fno_exceptions" = xyes then : as_fn_append NO_EXCEPTIONS_CXXFLAGS " -fno-exceptions" @@ -10456,14 +10463,14 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu for f in '-std=c++98' '-std=c++98 -stdlib=libc++' do - as_CACHEVAR=`printf "%s\n" "ax_cv_check_cxxflags__$f" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 + as_CACHEVAR=`printf '%s\n' "ax_cv_check_cxxflags__$f" | sed "$as_sed_sh"` +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 printf %s "checking whether C++ compiler accepts $f... " >&6; } if eval test \${$as_CACHEVAR+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ax_check_save_flags=$CXXFLAGS CXXFLAGS="$CXXFLAGS $f" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10482,17 +10489,19 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_CACHEVAR=yes" -else $as_nop - eval "$as_CACHEVAR=no" +else case e in #( + e) eval "$as_CACHEVAR=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - CXXFLAGS=$ax_check_save_flags + CXXFLAGS=$ax_check_save_flags ;; +esac fi eval ac_res=\$$as_CACHEVAR - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\n" "$as_val"'`" = xyes + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } +if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\\n" "$as_val"'`" = xyes then : CXX98_CXXFLAGS=$f break @@ -10515,14 +10524,14 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu for f in '-std=c++03' '-std=c++03 -stdlib=libc++' do - as_CACHEVAR=`printf "%s\n" "ax_cv_check_cxxflags__$f" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 + as_CACHEVAR=`printf '%s\n' "ax_cv_check_cxxflags__$f" | sed "$as_sed_sh"` +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 printf %s "checking whether C++ compiler accepts $f... " >&6; } if eval test \${$as_CACHEVAR+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ax_check_save_flags=$CXXFLAGS CXXFLAGS="$CXXFLAGS $f" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10542,17 +10551,19 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_CACHEVAR=yes" -else $as_nop - eval "$as_CACHEVAR=no" +else case e in #( + e) eval "$as_CACHEVAR=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - CXXFLAGS=$ax_check_save_flags + CXXFLAGS=$ax_check_save_flags ;; +esac fi eval ac_res=\$$as_CACHEVAR - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\n" "$as_val"'`" = xyes + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } +if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\\n" "$as_val"'`" = xyes then : CXX03_CXXFLAGS=$f break @@ -10575,14 +10586,14 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu for f in '-std=c++11' '-std=c++11 -stdlib=libc++' do - as_CACHEVAR=`printf "%s\n" "ax_cv_check_cxxflags__$f" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 + as_CACHEVAR=`printf '%s\n' "ax_cv_check_cxxflags__$f" | sed "$as_sed_sh"` +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 printf %s "checking whether C++ compiler accepts $f... " >&6; } if eval test \${$as_CACHEVAR+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ax_check_save_flags=$CXXFLAGS CXXFLAGS="$CXXFLAGS $f" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10672,17 +10683,19 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_CACHEVAR=yes" -else $as_nop - eval "$as_CACHEVAR=no" +else case e in #( + e) eval "$as_CACHEVAR=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - CXXFLAGS=$ax_check_save_flags + CXXFLAGS=$ax_check_save_flags ;; +esac fi eval ac_res=\$$as_CACHEVAR - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\n" "$as_val"'`" = xyes + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } +if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\\n" "$as_val"'`" = xyes then : CXX11_CXXFLAGS=$f break @@ -10705,14 +10718,14 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu for f in '-std=c++14' '-std=c++14 -stdlib=libc++' do - as_CACHEVAR=`printf "%s\n" "ax_cv_check_cxxflags__$f" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 + as_CACHEVAR=`printf '%s\n' "ax_cv_check_cxxflags__$f" | sed "$as_sed_sh"` +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 printf %s "checking whether C++ compiler accepts $f... " >&6; } if eval test \${$as_CACHEVAR+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ax_check_save_flags=$CXXFLAGS CXXFLAGS="$CXXFLAGS $f" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10812,17 +10825,19 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_CACHEVAR=yes" -else $as_nop - eval "$as_CACHEVAR=no" +else case e in #( + e) eval "$as_CACHEVAR=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - CXXFLAGS=$ax_check_save_flags + CXXFLAGS=$ax_check_save_flags ;; +esac fi eval ac_res=\$$as_CACHEVAR - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\n" "$as_val"'`" = xyes + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } +if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\\n" "$as_val"'`" = xyes then : CXX14_CXXFLAGS=$f break @@ -10845,14 +10860,14 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu for f in '-std=c++17' '-std=c++17 -stdlib=libc++' do - as_CACHEVAR=`printf "%s\n" "ax_cv_check_cxxflags__$f" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 + as_CACHEVAR=`printf '%s\n' "ax_cv_check_cxxflags__$f" | sed "$as_sed_sh"` +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 printf %s "checking whether C++ compiler accepts $f... " >&6; } if eval test \${$as_CACHEVAR+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ax_check_save_flags=$CXXFLAGS CXXFLAGS="$CXXFLAGS $f" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -10959,17 +10974,19 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_CACHEVAR=yes" -else $as_nop - eval "$as_CACHEVAR=no" +else case e in #( + e) eval "$as_CACHEVAR=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - CXXFLAGS=$ax_check_save_flags + CXXFLAGS=$ax_check_save_flags ;; +esac fi eval ac_res=\$$as_CACHEVAR - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\n" "$as_val"'`" = xyes + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } +if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\\n" "$as_val"'`" = xyes then : CXX17_CXXFLAGS=$f break @@ -10992,14 +11009,14 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu for f in '-std=c++20' '-std=c++20 -stdlib=libc++' do - as_CACHEVAR=`printf "%s\n" "ax_cv_check_cxxflags__$f" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 + as_CACHEVAR=`printf '%s\n' "ax_cv_check_cxxflags__$f" | sed "$as_sed_sh"` +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 printf %s "checking whether C++ compiler accepts $f... " >&6; } if eval test \${$as_CACHEVAR+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ax_check_save_flags=$CXXFLAGS CXXFLAGS="$CXXFLAGS $f" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11108,17 +11125,19 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_CACHEVAR=yes" -else $as_nop - eval "$as_CACHEVAR=no" +else case e in #( + e) eval "$as_CACHEVAR=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - CXXFLAGS=$ax_check_save_flags + CXXFLAGS=$ax_check_save_flags ;; +esac fi eval ac_res=\$$as_CACHEVAR - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\n" "$as_val"'`" = xyes + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } +if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\\n" "$as_val"'`" = xyes then : CXX20_CXXFLAGS=$f break @@ -11141,14 +11160,14 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu for f in '-std=c++2b' '-std=c++2b -stdlib=libc++' do - as_CACHEVAR=`printf "%s\n" "ax_cv_check_cxxflags__$f" | $as_tr_sh` -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 + as_CACHEVAR=`printf '%s\n' "ax_cv_check_cxxflags__$f" | sed "$as_sed_sh"` +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler accepts $f" >&5 printf %s "checking whether C++ compiler accepts $f... " >&6; } if eval test \${$as_CACHEVAR+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ax_check_save_flags=$CXXFLAGS CXXFLAGS="$CXXFLAGS $f" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11259,17 +11278,19 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_CACHEVAR=yes" -else $as_nop - eval "$as_CACHEVAR=no" +else case e in #( + e) eval "$as_CACHEVAR=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - CXXFLAGS=$ax_check_save_flags + CXXFLAGS=$ax_check_save_flags ;; +esac fi eval ac_res=\$$as_CACHEVAR - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } -if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\n" "$as_val"'`" = xyes + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } +if test x"`eval 'as_val=${'$as_CACHEVAR'};printf "%s\\n" "$as_val"'`" = xyes then : CXX2B_CXXFLAGS=$f break @@ -11313,8 +11334,9 @@ then : yes|no) ;; *) as_fn_error $? "invalid value for --gcc-warnings: $enable_gcc_warnings" "$LINENO" 5;; esac -else $as_nop - enable_gcc_warnings=no +else case e in #( + e) enable_gcc_warnings=no ;; +esac fi if test "$enable_gcc_warnings" = yes; then @@ -11410,13 +11432,13 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -Werror -Wunknown-warning-option" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -Werror -Wunknown-warning-option" >&5 printf %s "checking whether C compiler handles -Werror -Wunknown-warning-option... " >&6; } if test ${gl_cv_warn_c__Werror__Wunknown_warning_option+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CFLAGS" as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -Werror -Wunknown-warning-option" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11433,21 +11455,24 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_warn_c__Werror__Wunknown_warning_option=yes -else $as_nop - gl_cv_warn_c__Werror__Wunknown_warning_option=no +else case e in #( + e) gl_cv_warn_c__Werror__Wunknown_warning_option=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__Werror__Wunknown_warning_option" >&5 -printf "%s\n" "$gl_cv_warn_c__Werror__Wunknown_warning_option" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__Werror__Wunknown_warning_option" >&5 +printf '%s\n' "$gl_cv_warn_c__Werror__Wunknown_warning_option" >&6; } if test "x$gl_cv_warn_c__Werror__Wunknown_warning_option" = xyes then : gl_unknown_warnings_are_errors='-Wunknown-warning-option -Werror' -else $as_nop - gl_unknown_warnings_are_errors= +else case e in #( + e) gl_unknown_warnings_are_errors= ;; +esac fi ac_ext=c @@ -11459,13 +11484,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -Werror=unknown-warning-option" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -Werror=unknown-warning-option" >&5 printf %s "checking whether C compiler handles -Werror=unknown-warning-option... " >&6; } if test ${gl_cv_warn_c__Werror_unknown_warning_option+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CFLAGS" as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -Werror=unknown-warning-option" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11482,16 +11507,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_warn_c__Werror_unknown_warning_option=yes -else $as_nop - gl_cv_warn_c__Werror_unknown_warning_option=no +else case e in #( + e) gl_cv_warn_c__Werror_unknown_warning_option=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__Werror_unknown_warning_option" >&5 -printf "%s\n" "$gl_cv_warn_c__Werror_unknown_warning_option" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__Werror_unknown_warning_option" >&5 +printf '%s\n' "$gl_cv_warn_c__Werror_unknown_warning_option" >&6; } if test "x$gl_cv_warn_c__Werror_unknown_warning_option" = xyes then : as_fn_append CFLAGS " -Werror=unknown-warning-option" @@ -11502,13 +11529,13 @@ fi # and 3.4). -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -Wunreachable-code" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -Wunreachable-code" >&5 printf %s "checking whether C compiler handles -Wunreachable-code... " >&6; } if test ${gl_cv_warn_c__Wunreachable_code+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CFLAGS" as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -Wunreachable-code" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11525,16 +11552,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_warn_c__Wunreachable_code=yes -else $as_nop - gl_cv_warn_c__Wunreachable_code=no +else case e in #( + e) gl_cv_warn_c__Wunreachable_code=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__Wunreachable_code" >&5 -printf "%s\n" "$gl_cv_warn_c__Wunreachable_code" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__Wunreachable_code" >&5 +printf '%s\n' "$gl_cv_warn_c__Wunreachable_code" >&6; } if test "x$gl_cv_warn_c__Wunreachable_code" = xyes then : as_fn_append WARN_CFLAGS " -Wunreachable-code" @@ -11545,18 +11574,18 @@ fi do -as_gl_Warn=`printf "%s\n" "gl_cv_warn_c_$i" | $as_tr_sh` +as_gl_Warn=`printf '%s\n' "gl_cv_warn_c_$i" | sed "$as_sed_sh"` gl_positive="$i" case $gl_positive in -Wno-*) gl_positive=-W`expr "X$gl_positive" : 'X-Wno-\(.*\)'` ;; esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles $i" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles $i" >&5 printf %s "checking whether C compiler handles $i... " >&6; } if eval test \${$as_gl_Warn+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CFLAGS" as_fn_append CFLAGS " $gl_unknown_warnings_are_errors $gl_positive" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11573,17 +11602,19 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$as_gl_Warn=yes" -else $as_nop - eval "$as_gl_Warn=no" +else case e in #( + e) eval "$as_gl_Warn=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi eval ac_res=\$$as_gl_Warn - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } if eval test \"x\$"$as_gl_Warn"\" = x"yes" then : as_fn_append WARN_CFLAGS " $i" @@ -11593,13 +11624,13 @@ fi done -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -Werror" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles -Werror" >&5 printf %s "checking whether C compiler handles -Werror... " >&6; } if test ${gl_cv_warn_c__Werror+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CFLAGS" as_fn_append CFLAGS " $gl_unknown_warnings_are_errors -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11616,16 +11647,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_warn_c__Werror=yes -else $as_nop - gl_cv_warn_c__Werror=no +else case e in #( + e) gl_cv_warn_c__Werror=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__Werror" >&5 -printf "%s\n" "$gl_cv_warn_c__Werror" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_c__Werror" >&5 +printf '%s\n' "$gl_cv_warn_c__Werror" >&6; } if test "x$gl_cv_warn_c__Werror" = xyes then : as_fn_append WERROR_CFLAGS " -Werror" @@ -11643,18 +11676,18 @@ fi do -as_gl_Warn=`printf "%s\n" "gl_cv_warn_c_$i" | $as_tr_sh` +as_gl_Warn=`printf '%s\n' "gl_cv_warn_c_$i" | sed "$as_sed_sh"` gl_positive="$i" case $gl_positive in -Wno-*) gl_positive=-W`expr "X$gl_positive" : 'X-Wno-\(.*\)'` ;; esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles $i" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C compiler handles $i" >&5 printf %s "checking whether C compiler handles $i... " >&6; } if eval test \${$as_gl_Warn+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CFLAGS" as_fn_append CFLAGS " $gl_unknown_warnings_are_errors $gl_positive" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11671,17 +11704,19 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$as_gl_Warn=yes" -else $as_nop - eval "$as_gl_Warn=no" +else case e in #( + e) eval "$as_gl_Warn=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi eval ac_res=\$$as_gl_Warn - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } if eval test \"x\$"$as_gl_Warn"\" = x"yes" then : as_fn_append WARN_CFLAGS_TEST " $i" @@ -11707,13 +11742,13 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu save_CXXFLAGS=$CXXFLAGS -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Werror=unknown-warning-option" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Werror=unknown-warning-option" >&5 printf %s "checking whether C++ compiler handles -Werror=unknown-warning-option... " >&6; } if test ${gl_cv_warn_cxx__Werror_unknown_warning_option+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Werror=unknown-warning-option" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11730,16 +11765,18 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__Werror_unknown_warning_option=yes -else $as_nop - gl_cv_warn_cxx__Werror_unknown_warning_option=no +else case e in #( + e) gl_cv_warn_cxx__Werror_unknown_warning_option=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Werror_unknown_warning_option" >&5 -printf "%s\n" "$gl_cv_warn_cxx__Werror_unknown_warning_option" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Werror_unknown_warning_option" >&5 +printf '%s\n' "$gl_cv_warn_cxx__Werror_unknown_warning_option" >&6; } if test "x$gl_cv_warn_cxx__Werror_unknown_warning_option" = xyes then : as_fn_append CXXFLAGS " -Werror=unknown-warning-option" @@ -11750,18 +11787,18 @@ fi do -as_gl_Warn=`printf "%s\n" "gl_cv_warn_cxx_$i" | $as_tr_sh` +as_gl_Warn=`printf '%s\n' "gl_cv_warn_cxx_$i" | sed "$as_sed_sh"` gl_positive="$i" case $gl_positive in -Wno-*) gl_positive=-W`expr "X$gl_positive" : 'X-Wno-\(.*\)'` ;; esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles $i" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles $i" >&5 printf %s "checking whether C++ compiler handles $i... " >&6; } if eval test \${$as_gl_Warn+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors $gl_positive" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11778,17 +11815,19 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_gl_Warn=yes" -else $as_nop - eval "$as_gl_Warn=no" +else case e in #( + e) eval "$as_gl_Warn=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi eval ac_res=\$$as_gl_Warn - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } if eval test \"x\$"$as_gl_Warn"\" = x"yes" then : as_fn_append WARN_CXXFLAGS " $i" @@ -11800,13 +11839,13 @@ fi # and 3.4). -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wunreachable-code" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wunreachable-code" >&5 printf %s "checking whether C++ compiler handles -Wunreachable-code... " >&6; } if test ${gl_cv_warn_cxx__Wunreachable_code+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Wunreachable-code" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11823,16 +11862,18 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__Wunreachable_code=yes -else $as_nop - gl_cv_warn_cxx__Wunreachable_code=no +else case e in #( + e) gl_cv_warn_cxx__Wunreachable_code=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wunreachable_code" >&5 -printf "%s\n" "$gl_cv_warn_cxx__Wunreachable_code" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wunreachable_code" >&5 +printf '%s\n' "$gl_cv_warn_cxx__Wunreachable_code" >&6; } if test "x$gl_cv_warn_cxx__Wunreachable_code" = xyes then : as_fn_append WARN_CXXFLAGS " -Wunreachable-code" @@ -11841,13 +11882,13 @@ fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wzero-as-null-pointer-constant" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wzero-as-null-pointer-constant" >&5 printf %s "checking whether C++ compiler handles -Wzero-as-null-pointer-constant... " >&6; } if test ${gl_cv_warn_cxx__Wzero_as_null_pointer_constant+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Wzero-as-null-pointer-constant" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11864,16 +11905,18 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__Wzero_as_null_pointer_constant=yes -else $as_nop - gl_cv_warn_cxx__Wzero_as_null_pointer_constant=no +else case e in #( + e) gl_cv_warn_cxx__Wzero_as_null_pointer_constant=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wzero_as_null_pointer_constant" >&5 -printf "%s\n" "$gl_cv_warn_cxx__Wzero_as_null_pointer_constant" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wzero_as_null_pointer_constant" >&5 +printf '%s\n' "$gl_cv_warn_cxx__Wzero_as_null_pointer_constant" >&6; } if test "x$gl_cv_warn_cxx__Wzero_as_null_pointer_constant" = xyes then : as_fn_append WARN_CXXFLAGS " -Wzero-as-null-pointer-constant" @@ -11884,13 +11927,13 @@ fi # this warning. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wuseless-cast" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wuseless-cast" >&5 printf %s "checking whether C++ compiler handles -Wuseless-cast... " >&6; } if test ${gl_cv_warn_cxx__Wuseless_cast+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Wuseless-cast" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11911,16 +11954,18 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__Wuseless_cast=yes -else $as_nop - gl_cv_warn_cxx__Wuseless_cast=no +else case e in #( + e) gl_cv_warn_cxx__Wuseless_cast=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wuseless_cast" >&5 -printf "%s\n" "$gl_cv_warn_cxx__Wuseless_cast" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wuseless_cast" >&5 +printf '%s\n' "$gl_cv_warn_cxx__Wuseless_cast" >&6; } if test "x$gl_cv_warn_cxx__Wuseless_cast" = xyes then : as_fn_append WARN_CXXFLAGS " -Wuseless-cast" @@ -11929,13 +11974,13 @@ fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Werror" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Werror" >&5 printf %s "checking whether C++ compiler handles -Werror... " >&6; } if test ${gl_cv_warn_cxx__Werror+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -11952,16 +11997,18 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__Werror=yes -else $as_nop - gl_cv_warn_cxx__Werror=no +else case e in #( + e) gl_cv_warn_cxx__Werror=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Werror" >&5 -printf "%s\n" "$gl_cv_warn_cxx__Werror" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Werror" >&5 +printf '%s\n' "$gl_cv_warn_cxx__Werror" >&6; } if test "x$gl_cv_warn_cxx__Werror" = xyes then : as_fn_append WERROR_CXXFLAGS " -Werror" @@ -11973,18 +12020,18 @@ fi do -as_gl_Warn=`printf "%s\n" "gl_cv_warn_cxx_$i" | $as_tr_sh` +as_gl_Warn=`printf '%s\n' "gl_cv_warn_cxx_$i" | sed "$as_sed_sh"` gl_positive="$i" case $gl_positive in -Wno-*) gl_positive=-W`expr "X$gl_positive" : 'X-Wno-\(.*\)'` ;; esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles $i" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles $i" >&5 printf %s "checking whether C++ compiler handles $i... " >&6; } if eval test \${$as_gl_Warn+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors $gl_positive" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12001,17 +12048,19 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : eval "$as_gl_Warn=yes" -else $as_nop - eval "$as_gl_Warn=no" +else case e in #( + e) eval "$as_gl_Warn=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi eval ac_res=\$$as_gl_Warn - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } if eval test \"x\$"$as_gl_Warn"\" = x"yes" then : as_fn_append WARN_CXXFLAGS_TEST " $i" @@ -12022,13 +12071,13 @@ fi # Too many compilers complain about Flex generated code. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wno-error" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wno-error" >&5 printf %s "checking whether C++ compiler handles -Wno-error... " >&6; } if test ${gl_cv_warn_cxx__Wno_error+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12045,16 +12094,18 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__Wno_error=yes -else $as_nop - gl_cv_warn_cxx__Wno_error=no +else case e in #( + e) gl_cv_warn_cxx__Wno_error=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wno_error" >&5 -printf "%s\n" "$gl_cv_warn_cxx__Wno_error" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wno_error" >&5 +printf '%s\n' "$gl_cv_warn_cxx__Wno_error" >&6; } if test "x$gl_cv_warn_cxx__Wno_error" = xyes then : as_fn_append FLEX_SCANNER_CXXFLAGS " -Wno-error" @@ -12064,13 +12115,13 @@ fi # Clang++ deprecates compiling C. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wno-deprecated" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wno-deprecated" >&5 printf %s "checking whether C++ compiler handles -Wno-deprecated... " >&6; } if test ${gl_cv_warn_cxx__Wno_deprecated+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_save_compiler_FLAGS="$CXXFLAGS" as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Wdeprecated" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12087,16 +12138,18 @@ _ACEOF if ac_fn_cxx_try_link "$LINENO" then : gl_cv_warn_cxx__Wno_deprecated=yes -else $as_nop - gl_cv_warn_cxx__Wno_deprecated=no +else case e in #( + e) gl_cv_warn_cxx__Wno_deprecated=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CXXFLAGS="$gl_save_compiler_FLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wno_deprecated" >&5 -printf "%s\n" "$gl_cv_warn_cxx__Wno_deprecated" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wno_deprecated" >&5 +printf '%s\n' "$gl_cv_warn_cxx__Wno_deprecated" >&6; } if test "x$gl_cv_warn_cxx__Wno_deprecated" = xyes then : as_fn_append WNO_DEPRECATED_CXXFLAGS " -Wno-deprecated" @@ -12129,11 +12182,12 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +else case e in #( + e) { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot compile a simple C program -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext BISON_C_WORKS=: @@ -12145,13 +12199,13 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC supports POSIXLY_CORRECT=1" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CC supports POSIXLY_CORRECT=1" >&5 printf %s "checking whether $CC supports POSIXLY_CORRECT=1... " >&6; } if test ${bison_cv_c_supports_posixly_correct+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_awk_probe='BEGIN { if ("POSIXLY_CORRECT" in ENVIRON) print "x" }' +else case e in #( + e) gl_awk_probe='BEGIN { if ("POSIXLY_CORRECT" in ENVIRON) print "x" }' case ${POSIXLY_CORRECT+x}`$AWK "$gl_awk_probe" &5 -printf "%s\n" "$bison_cv_c_supports_posixly_correct" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $bison_cv_c_supports_posixly_correct" >&5 +printf '%s\n' "$bison_cv_c_supports_posixly_correct" >&6; } case $bison_cv_c_supports_posixly_correct in yes) C_COMPILER_POSIXLY_CORRECT=true ;; @@ -12202,13 +12258,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX builds executables that work" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CXX builds executables that work" >&5 printf %s "checking whether $CXX builds executables that work... " >&6; } if test ${bison_cv_cxx_works+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_ext=cpp +else case e in #( + e) ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' @@ -12245,22 +12301,23 @@ then : { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 (eval $ac_try) 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : if test "$cross_compiling" = yes then : bison_cv_cxx_works=cross -else $as_nop - if { ac_try='./conftest$ac_exeext' +else case e in #( + e) if { ac_try='./conftest$ac_exeext' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 (eval $ac_try) 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } then : bison_cv_cxx_works=yes -fi +fi ;; +esac fi fi rm -f conftest$ac_exeext @@ -12271,10 +12328,11 @@ ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bison_cv_cxx_works" >&5 -printf "%s\n" "$bison_cv_cxx_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $bison_cv_cxx_works" >&5 +printf '%s\n' "$bison_cv_cxx_works" >&6; } case $bison_cv_cxx_works in yes) BISON_CXX_WORKS=':';; @@ -12297,13 +12355,13 @@ ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports POSIXLY_CORRECT=1" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports POSIXLY_CORRECT=1" >&5 printf %s "checking whether $CXX supports POSIXLY_CORRECT=1... " >&6; } if test ${bison_cv_cxx_supports_posixly_correct+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_awk_probe='BEGIN { if ("POSIXLY_CORRECT" in ENVIRON) print "x" }' +else case e in #( + e) gl_awk_probe='BEGIN { if ("POSIXLY_CORRECT" in ENVIRON) print "x" }' case ${POSIXLY_CORRECT+x}`$AWK "$gl_awk_probe" &5 -printf "%s\n" "$bison_cv_cxx_supports_posixly_correct" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $bison_cv_cxx_supports_posixly_correct" >&5 +printf '%s\n' "$bison_cv_cxx_supports_posixly_correct" >&6; } case $bison_cv_cxx_supports_posixly_correct in yes) CXX_COMPILER_POSIXLY_CORRECT=true ;; @@ -12359,13 +12419,13 @@ for ac_prog in dmd do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$DC"; then +else case e in #( + e) if test -n "$DC"; then ac_cv_prog_DC="$DC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -12380,22 +12440,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi DC=$ac_cv_prog_DC if test -n "$DC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DC" >&5 -printf "%s\n" "$DC" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DC" >&5 +printf '%s\n' "$DC" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -12406,13 +12467,13 @@ for ac_prog in -g do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_DCFLAGS+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$DCFLAGS"; then +else case e in #( + e) if test -n "$DCFLAGS"; then ac_cv_prog_DCFLAGS="$DCFLAGS" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -12427,22 +12488,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_DCFLAGS="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi DCFLAGS=$ac_cv_prog_DCFLAGS if test -n "$DCFLAGS"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $DCFLAGS" >&5 -printf "%s\n" "$DCFLAGS" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $DCFLAGS" >&5 +printf '%s\n' "$DCFLAGS" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -12470,11 +12532,12 @@ fi _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : CLASSPATH_SEPARATOR=';' -else $as_nop - CLASSPATH_SEPARATOR=':' +else case e in #( + e) CLASSPATH_SEPARATOR=':' ;; +esac fi rm -rf conftest* @@ -12531,7 +12594,7 @@ rm -rf conftest* echo } fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Java compiler" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for Java compiler" >&5 printf %s "checking for Java compiler... " >&6; } CONF_JAVAC= HAVE_JAVAC_ENVVAR= @@ -12551,23 +12614,23 @@ EOF if $JAVAC --version 2>/dev/null | sed -e 1q | grep gcj > /dev/null; then if $JAVAC --version 2>/dev/null | sed -e 's,^[^0-9]*,,' -e 1q | sed -e '/^4\.[012]/d' | grep '^[4-9]' >/dev/null; then rm -f conftest.class - if { echo "$as_me:12554: $JAVAC -d . conftest.java" >&5 + if { echo "$as_me:12617: $JAVAC -d . conftest.java" >&5 $JAVAC -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5; then rm -f conftest.class rm -f conftestfail.class - if { echo "$as_me:12561: $JAVAC -fsource=$source_version -d . conftest.java" >&5 + if { echo "$as_me:12624: $JAVAC -fsource=$source_version -d . conftest.java" >&5 $JAVAC -fsource="$source_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5 \ - && { echo "$as_me:12566: $JAVAC -d . conftestfail.java" >&5 + && { echo "$as_me:12629: $JAVAC -d . conftestfail.java" >&5 $JAVAC -d . conftestfail.java >&5 2>&1 } \ && test -f conftestfail.class \ - && ! { echo "$as_me:12570: $JAVAC -fsource=$source_version -d . conftestfail.java" >&5 + && ! { echo "$as_me:12633: $JAVAC -fsource=$source_version -d . conftestfail.java" >&5 $JAVAC -fsource="$source_version" -d . conftestfail.java >&5 2>&1 }; then CONF_JAVAC="$JAVAC -fsource=$source_version" @@ -12581,7 +12644,7 @@ EOF else rm -f conftest.class rm -f conftestfail.class - if { echo "$as_me:12584: $JAVAC -fsource=$source_version -ftarget=$target_version -d . conftest.java" >&5 + if { echo "$as_me:12647: $JAVAC -fsource=$source_version -ftarget=$target_version -d . conftest.java" >&5 $JAVAC -fsource="$source_version" -ftarget="$target_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ @@ -12594,7 +12657,7 @@ EOF else if test "$target_version" = 1.4 && test "$source_version" = 1.4; then rm -f conftest.class - if { echo "$as_me:12597: $JAVAC -d . conftest.java" >&5 + if { echo "$as_me:12660: $JAVAC -d . conftest.java" >&5 $JAVAC -d . conftest.java >&5 2>&1 } \ && test -f conftest.class; then @@ -12606,7 +12669,7 @@ EOF if test "$target_version" = 1.4 && test "$source_version" = 1.3; then javac_works= rm -f conftest.class - if { echo "$as_me:12609: $JAVAC -d . conftest.java" >&5 + if { echo "$as_me:12672: $JAVAC -d . conftest.java" >&5 $JAVAC -d . conftest.java >&5 2>&1 } \ && test -f conftest.class; then @@ -12614,7 +12677,7 @@ EOF fi javac_noassert_works= rm -f conftest.class - if { echo "$as_me:12617: $JAVAC -fno-assert -d . conftest.java" >&5 + if { echo "$as_me:12680: $JAVAC -fno-assert -d . conftest.java" >&5 $JAVAC -fno-assert -d . conftest.java >&5 2>&1 } \ && test -f conftest.class; then @@ -12622,11 +12685,11 @@ EOF fi if test -n "$javac_works" && test -n "$javac_noassert_works"; then rm -f conftestfail.class - if { echo "$as_me:12625: $JAVAC -d . conftestfail.java" >&5 + if { echo "$as_me:12688: $JAVAC -d . conftestfail.java" >&5 $JAVAC -d . conftestfail.java >&5 2>&1 } \ && test -f conftestfail.class \ - && ! { echo "$as_me:12629: $JAVAC -fno-assert -d . conftestfail.java" >&5 + && ! { echo "$as_me:12692: $JAVAC -fno-assert -d . conftestfail.java" >&5 $JAVAC -fno-assert -d . conftestfail.java >&5 2>&1 }; then javac_works= @@ -12654,23 +12717,23 @@ EOF esac fi rm -f conftest.class - if { echo "$as_me:12657: $JAVAC -d . conftest.java" >&5 + if { echo "$as_me:12720: $JAVAC -d . conftest.java" >&5 $JAVAC -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5; then rm -f conftest.class rm -f conftestfail.class - if { echo "$as_me:12664: $JAVAC -source $source_version -d . conftest.java" >&5 + if { echo "$as_me:12727: $JAVAC -source $source_version -d . conftest.java" >&5 $JAVAC -source "$source_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5 \ - && { echo "$as_me:12669: $JAVAC -d . conftestfail.java" >&5 + && { echo "$as_me:12732: $JAVAC -d . conftestfail.java" >&5 $JAVAC -d . conftestfail.java >&5 2>&1 } \ && test -f conftestfail.class \ - && ! { echo "$as_me:12673: $JAVAC -source $source_version -d . conftestfail.java" >&5 + && ! { echo "$as_me:12736: $JAVAC -source $source_version -d . conftestfail.java" >&5 $JAVAC -source "$source_version" -d . conftestfail.java >&5 2>&1 }; then CONF_JAVAC="$JAVAC -source $source_version" @@ -12683,23 +12746,23 @@ EOF fi else rm -f conftest.class - if { echo "$as_me:12686: $JAVAC -target $target_version -d . conftest.java" >&5 + if { echo "$as_me:12749: $JAVAC -target $target_version -d . conftest.java" >&5 $JAVAC -target "$target_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5; then rm -f conftest.class rm -f conftestfail.class - if { echo "$as_me:12693: $JAVAC -target $target_version -source $source_version -d . conftest.java" >&5 + if { echo "$as_me:12756: $JAVAC -target $target_version -source $source_version -d . conftest.java" >&5 $JAVAC -target "$target_version" -source "$source_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5 \ - && { echo "$as_me:12698: $JAVAC -target $target_version -d . conftestfail.java" >&5 + && { echo "$as_me:12761: $JAVAC -target $target_version -d . conftestfail.java" >&5 $JAVAC -target "$target_version" -d . conftestfail.java >&5 2>&1 } \ && test -f conftestfail.class \ - && ! { echo "$as_me:12702: $JAVAC -target $target_version -source $source_version -d . conftestfail.java" >&5 + && ! { echo "$as_me:12765: $JAVAC -target $target_version -source $source_version -d . conftestfail.java" >&5 $JAVAC -target "$target_version" -source "$source_version" -d . conftestfail.java >&5 2>&1 }; then CONF_JAVAC="$JAVAC -target $target_version -source $source_version" @@ -12712,7 +12775,7 @@ EOF fi else rm -f conftest.class - if { echo "$as_me:12715: $JAVAC -target $target_version -source $source_version -d . conftest.java" >&5 + if { echo "$as_me:12778: $JAVAC -target $target_version -source $source_version -d . conftest.java" >&5 $JAVAC -target "$target_version" -source "$source_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ @@ -12732,8 +12795,8 @@ set dummy gcj; ac_word=$2 if test ${ac_cv_prog_HAVE_GCJ_IN_PATH+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$HAVE_GCJ_IN_PATH"; then +else case e in #( + e) if test -n "$HAVE_GCJ_IN_PATH"; then ac_cv_prog_HAVE_GCJ_IN_PATH="$HAVE_GCJ_IN_PATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -12748,14 +12811,15 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_GCJ_IN_PATH="yes" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi HAVE_GCJ_IN_PATH=$ac_cv_prog_HAVE_GCJ_IN_PATH if test -n "$HAVE_GCJ_IN_PATH"; then @@ -12771,8 +12835,8 @@ set dummy javac; ac_word=$2 if test ${ac_cv_prog_HAVE_JAVAC_IN_PATH+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$HAVE_JAVAC_IN_PATH"; then +else case e in #( + e) if test -n "$HAVE_JAVAC_IN_PATH"; then ac_cv_prog_HAVE_JAVAC_IN_PATH="$HAVE_JAVAC_IN_PATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -12787,14 +12851,15 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_JAVAC_IN_PATH="yes" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi HAVE_JAVAC_IN_PATH=$ac_cv_prog_HAVE_JAVAC_IN_PATH if test -n "$HAVE_JAVAC_IN_PATH"; then @@ -12810,8 +12875,8 @@ set dummy jikes; ac_word=$2 if test ${ac_cv_prog_HAVE_JIKES_IN_PATH+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$HAVE_JIKES_IN_PATH"; then +else case e in #( + e) if test -n "$HAVE_JIKES_IN_PATH"; then ac_cv_prog_HAVE_JIKES_IN_PATH="$HAVE_JIKES_IN_PATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -12826,14 +12891,15 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_JIKES_IN_PATH="yes" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi HAVE_JIKES_IN_PATH=$ac_cv_prog_HAVE_JIKES_IN_PATH if test -n "$HAVE_JIKES_IN_PATH"; then @@ -12845,28 +12911,28 @@ fi if test -z "$HAVE_JAVACOMP" && test -n "$HAVE_GCJ_IN_PATH"; then if gcj --version 2>/dev/null | sed -e 's,^[^0-9]*,,' -e 1q | sed -e '/^3\.[01]/d' | grep '^[3-9]' >/dev/null; then - if { echo "$as_me:12848: gcj -C -d . conftestlib.java" >&5 + if { echo "$as_me:12914: gcj -C -d . conftestlib.java" >&5 gcj -C -d . conftestlib.java >&5 2>&1 }; then if gcj --version 2>/dev/null | sed -e 's,^[^0-9]*,,' -e 1q | sed -e '/^4\.[012]/d' | grep '^[4-9]' >/dev/null; then rm -f conftest.class - if { echo "$as_me:12853: gcj -C -d . conftest.java" >&5 + if { echo "$as_me:12919: gcj -C -d . conftest.java" >&5 gcj -C -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5; then rm -f conftest.class rm -f conftestfail.class - if { echo "$as_me:12860: gcj -C -fsource=$source_version -d . conftest.java" >&5 + if { echo "$as_me:12926: gcj -C -fsource=$source_version -d . conftest.java" >&5 gcj -C -fsource="$source_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5 \ - && { echo "$as_me:12865: gcj -C -d . conftestfail.java" >&5 + && { echo "$as_me:12931: gcj -C -d . conftestfail.java" >&5 gcj -C -d . conftestfail.java >&5 2>&1 } \ && test -f conftestfail.class \ - && ! { echo "$as_me:12869: gcj -C -fsource=$source_version -d . conftestfail.java" >&5 + && ! { echo "$as_me:12935: gcj -C -fsource=$source_version -d . conftestfail.java" >&5 gcj -C -fsource="$source_version" -d . conftestfail.java >&5 2>&1 }; then CONF_JAVAC="gcj -C -fsource=$source_version" @@ -12880,7 +12946,7 @@ fi else rm -f conftest.class rm -f conftestfail.class - if { echo "$as_me:12883: gcj -C -fsource=$source_version -ftarget=$target_version -d . conftest.java" >&5 + if { echo "$as_me:12949: gcj -C -fsource=$source_version -ftarget=$target_version -d . conftest.java" >&5 gcj -C -fsource="$source_version" -ftarget="$target_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ @@ -12893,7 +12959,7 @@ fi else if test "$target_version" = 1.4 && test "$source_version" = 1.4; then rm -f conftest.class - if { echo "$as_me:12896: gcj -C -d . conftest.java" >&5 + if { echo "$as_me:12962: gcj -C -d . conftest.java" >&5 gcj -C -d . conftest.java >&5 2>&1 } \ && test -f conftest.class; then @@ -12904,7 +12970,7 @@ fi else if test "$target_version" = 1.4 && test "$source_version" = 1.3; then rm -f conftest.class - if { echo "$as_me:12907: gcj -C -fno-assert -d . conftest.java" >&5 + if { echo "$as_me:12973: gcj -C -fno-assert -d . conftest.java" >&5 gcj -C -fno-assert -d . conftest.java >&5 2>&1 } \ && test -f conftest.class; then @@ -12913,7 +12979,7 @@ fi HAVE_JAVACOMP=1 else rm -f conftest.class - if { echo "$as_me:12916: gcj -C -d . conftest.java" >&5 + if { echo "$as_me:12982: gcj -C -d . conftest.java" >&5 gcj -C -d . conftest.java >&5 2>&1 } \ && test -f conftest.class; then @@ -12938,23 +13004,23 @@ fi esac fi rm -f conftest.class - if { echo "$as_me:12941: javac -d . conftest.java" >&5 + if { echo "$as_me:13007: javac -d . conftest.java" >&5 javac -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5; then rm -f conftest.class rm -f conftestfail.class - if { echo "$as_me:12948: javac -source $source_version -d . conftest.java" >&5 + if { echo "$as_me:13014: javac -source $source_version -d . conftest.java" >&5 javac -source "$source_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5 \ - && { echo "$as_me:12953: javac -d . conftestfail.java" >&5 + && { echo "$as_me:13019: javac -d . conftestfail.java" >&5 javac -d . conftestfail.java >&5 2>&1 } \ && test -f conftestfail.class \ - && ! { echo "$as_me:12957: javac -source $source_version -d . conftestfail.java" >&5 + && ! { echo "$as_me:13023: javac -source $source_version -d . conftestfail.java" >&5 javac -source "$source_version" -d . conftestfail.java >&5 2>&1 }; then CONF_JAVAC="javac -source $source_version" @@ -12967,23 +13033,23 @@ fi fi else rm -f conftest.class - if { echo "$as_me:12970: javac -target $target_version -d . conftest.java" >&5 + if { echo "$as_me:13036: javac -target $target_version -d . conftest.java" >&5 javac -target "$target_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5; then rm -f conftest.class rm -f conftestfail.class - if { echo "$as_me:12977: javac -target $target_version -source $source_version -d . conftest.java" >&5 + if { echo "$as_me:13043: javac -target $target_version -source $source_version -d . conftest.java" >&5 javac -target "$target_version" -source "$source_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ && expr `func_classfile_version conftest.class` '<=' $cfversion >/dev/null 2>&5 \ - && { echo "$as_me:12982: javac -target $target_version -d . conftestfail.java" >&5 + && { echo "$as_me:13048: javac -target $target_version -d . conftestfail.java" >&5 javac -target "$target_version" -d . conftestfail.java >&5 2>&1 } \ && test -f conftestfail.class \ - && ! { echo "$as_me:12986: javac -target $target_version -source $source_version -d . conftestfail.java" >&5 + && ! { echo "$as_me:13052: javac -target $target_version -source $source_version -d . conftestfail.java" >&5 javac -target "$target_version" -source "$source_version" -d . conftestfail.java >&5 2>&1 }; then CONF_JAVAC="javac -target $target_version -source $source_version" @@ -12996,7 +13062,7 @@ fi fi else rm -f conftest.class - if { echo "$as_me:12999: javac -target $target_version -source $source_version -d . conftest.java" >&5 + if { echo "$as_me:13065: javac -target $target_version -source $source_version -d . conftest.java" >&5 javac -target "$target_version" -source "$source_version" -d . conftest.java >&5 2>&1 } \ && test -f conftest.class \ @@ -13033,8 +13099,8 @@ fi else ac_result="no" fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_result" >&5 -printf "%s\n" "$ac_result" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_result" >&5 +printf '%s\n' "$ac_result" >&6; } @@ -13044,7 +13110,7 @@ printf "%s\n" "$ac_result" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Java virtual machine" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for Java virtual machine" >&5 printf %s "checking for Java virtual machine... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -13055,11 +13121,12 @@ printf %s "checking for Java virtual machine... " >&6; } _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : CLASSPATH_SEPARATOR=';' -else $as_nop - CLASSPATH_SEPARATOR=':' +else case e in #( + e) CLASSPATH_SEPARATOR=':' ;; +esac fi rm -rf conftest* @@ -13080,8 +13147,8 @@ set dummy gij; ac_word=$2 if test ${ac_cv_prog_HAVE_GIJ_IN_PATH+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$HAVE_GIJ_IN_PATH"; then +else case e in #( + e) if test -n "$HAVE_GIJ_IN_PATH"; then ac_cv_prog_HAVE_GIJ_IN_PATH="$HAVE_GIJ_IN_PATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -13096,14 +13163,15 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_GIJ_IN_PATH="yes" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi HAVE_GIJ_IN_PATH=$ac_cv_prog_HAVE_GIJ_IN_PATH if test -n "$HAVE_GIJ_IN_PATH"; then @@ -13119,8 +13187,8 @@ set dummy java; ac_word=$2 if test ${ac_cv_prog_HAVE_JAVA_IN_PATH+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$HAVE_JAVA_IN_PATH"; then +else case e in #( + e) if test -n "$HAVE_JAVA_IN_PATH"; then ac_cv_prog_HAVE_JAVA_IN_PATH="$HAVE_JAVA_IN_PATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -13135,14 +13203,15 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_JAVA_IN_PATH="yes" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi HAVE_JAVA_IN_PATH=$ac_cv_prog_HAVE_JAVA_IN_PATH if test -n "$HAVE_JAVA_IN_PATH"; then @@ -13158,8 +13227,8 @@ set dummy jre; ac_word=$2 if test ${ac_cv_prog_HAVE_JRE_IN_PATH+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$HAVE_JRE_IN_PATH"; then +else case e in #( + e) if test -n "$HAVE_JRE_IN_PATH"; then ac_cv_prog_HAVE_JRE_IN_PATH="$HAVE_JRE_IN_PATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -13174,14 +13243,15 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_JRE_IN_PATH="yes" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi HAVE_JRE_IN_PATH=$ac_cv_prog_HAVE_JRE_IN_PATH if test -n "$HAVE_JRE_IN_PATH"; then @@ -13197,8 +13267,8 @@ set dummy jview; ac_word=$2 if test ${ac_cv_prog_HAVE_JVIEW_IN_PATH+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$HAVE_JVIEW_IN_PATH"; then +else case e in #( + e) if test -n "$HAVE_JVIEW_IN_PATH"; then ac_cv_prog_HAVE_JVIEW_IN_PATH="$HAVE_JVIEW_IN_PATH" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -13213,14 +13283,15 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_JVIEW_IN_PATH="yes" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi HAVE_JVIEW_IN_PATH=$ac_cv_prog_HAVE_JVIEW_IN_PATH if test -n "$HAVE_JVIEW_IN_PATH"; then @@ -13268,8 +13339,8 @@ fi else ac_result="no" fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_result" >&5 -printf "%s\n" "$ac_result" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_result" >&5 +printf '%s\n' "$ac_result" >&6; } @@ -13293,8 +13364,9 @@ fi if test ${enable_yacc+y} then : enableval=$enable_yacc; -else $as_nop - enable_yacc=yes +else case e in #( + e) enable_yacc=yes ;; +esac fi if test "$enable_yacc" = yes; then @@ -13316,13 +13388,13 @@ for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_LEX+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$LEX"; then +else case e in #( + e) if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -13337,22 +13409,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_LEX="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 -printf "%s\n" "$LEX" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 +printf '%s\n' "$LEX" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -13361,13 +13434,13 @@ done test -n "$LEX" || LEX=":" if test "x$LEX" != "x:"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether lex is flex" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether lex is flex" >&5 printf %s "checking whether lex is flex... " >&6; } if test ${ac_cv_prog_lex_is_flex+y} then : printf %s "(cached) " >&6 -else $as_nop - cat >conftest.l <<_ACEOF +else case e in #( + e) cat >conftest.l <<_ACEOF %option debug nodefault noinput nounput noyywrap never-interactive %x SC_CONF_TEST %% @@ -13379,46 +13452,48 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$LEX conftest.l") 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then ac_cv_prog_lex_is_flex=yes else ac_cv_prog_lex_is_flex=no fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_is_flex" >&5 -printf "%s\n" "$ac_cv_prog_lex_is_flex" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_is_flex" >&5 +printf '%s\n' "$ac_cv_prog_lex_is_flex" >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether flex supports --header=FILE" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether flex supports --header=FILE" >&5 printf %s "checking whether flex supports --header=FILE... " >&6; } if test ${ac_cv_prog_lex_supports_header_opt+y} then : printf %s "(cached) " >&6 -else $as_nop - if { { ac_try="$LEX --header=conftest.h conftest.l" +else case e in #( + e) if { { ac_try="$LEX --header=conftest.h conftest.l" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$LEX --header=conftest.h conftest.l") 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then ac_cv_prog_lex_supports_header_opt=yes else ac_cv_prog_lex_supports_header_opt=no fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_supports_header_opt" >&5 -printf "%s\n" "$ac_cv_prog_lex_supports_header_opt" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_supports_header_opt" >&5 +printf '%s\n' "$ac_cv_prog_lex_supports_header_opt" >&6; } if test "$ac_cv_prog_lex_supports_header_opt" = yes; then FLEX_SUPPORTS_HEADER_OPT=true else @@ -13452,38 +13527,39 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -printf "%s\n" "$ac_try_echo"; } >&5 +printf '%s\n' "$ac_try_echo"; } >&5 (eval "$LEX conftest.l") 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 printf %s "checking lex output file root... " >&6; } if test ${ac_cv_prog_lex_root+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy else as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 +fi ;; +esac fi -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 -printf "%s\n" "$ac_cv_prog_lex_root" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 +printf '%s\n' "$ac_cv_prog_lex_root" >&6; } LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root if test -z "${LEXLIB+set}"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 printf %s "checking lex library... " >&6; } if test ${ac_cv_lib_lex+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ac_save_LIBS=$LIBS ac_cv_lib_lex='none needed' for ac_lib in '' -lfl -ll; do @@ -13501,21 +13577,22 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ test "$ac_cv_lib_lex" != 'none needed' && break done LIBS=$ac_save_LIBS - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 -printf "%s\n" "$ac_cv_lib_lex" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 +printf '%s\n' "$ac_cv_lib_lex" >&6; } test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 printf %s "checking whether yytext is a pointer... " >&6; } if test ${ac_cv_prog_lex_yytext_pointer+y} then : printf %s "(cached) " >&6 -else $as_nop - # POSIX says lex can declare yytext either as a pointer or an array; the +else case e in #( + e) # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no @@ -13534,13 +13611,14 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_save_LIBS - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 -printf "%s\n" "$ac_cv_prog_lex_yytext_pointer" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 +printf '%s\n' "$ac_cv_prog_lex_yytext_pointer" >&6; } if test $ac_cv_prog_lex_yytext_pointer = yes; then -printf "%s\n" "#define YYTEXT_POINTER 1" >>confdefs.h +printf '%s\n' "#define YYTEXT_POINTER 1" >>confdefs.h fi rm -f conftest.l $LEX_OUTPUT_ROOT.c @@ -13549,8 +13627,8 @@ fi LEX_IS_FLEX=`test "$ac_cv_prog_lex_is_flex" = yes && echo true || echo false` if ! "$LEX_IS_FLEX" || test "X$LEX" = X:; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: bypassing lex because flex is required" >&5 -printf "%s\n" "$as_me: WARNING: bypassing lex because flex is required" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: bypassing lex because flex is required" >&5 +printf '%s\n' "$as_me: WARNING: bypassing lex because flex is required" >&2;} LEX=: fi if $LEX_IS_FLEX && $FLEX_SUPPORTS_HEADER_OPT; then @@ -13573,13 +13651,13 @@ for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_YACC+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$YACC"; then +else case e in #( + e) if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -13594,22 +13672,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 -printf "%s\n" "$YACC" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 +printf '%s\n' "$YACC" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -13620,13 +13699,13 @@ test -n "$YACC" || YACC="yacc" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_RANLIB+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$RANLIB"; then +else case e in #( + e) if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -13641,22 +13720,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -printf "%s\n" "$RANLIB" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +printf '%s\n' "$RANLIB" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -13665,13 +13745,13 @@ if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_RANLIB+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$ac_ct_RANLIB"; then +else case e in #( + e) if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -13686,22 +13766,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -printf "%s\n" "$ac_ct_RANLIB" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +printf '%s\n' "$ac_ct_RANLIB" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then @@ -13709,8 +13790,8 @@ fi else case $cross_compiling:$ac_tool_warned in yes:) -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf '%s\n' "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB @@ -13720,13 +13801,13 @@ else fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU M4 that supports accurate traces" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for GNU M4 that supports accurate traces" >&5 printf %s "checking for GNU M4 that supports accurate traces... " >&6; } if test ${ac_cv_path_M4+y} then : printf %s "(cached) " >&6 -else $as_nop - rm -f conftest.m4f +else case e in #( + e) rm -f conftest.m4f ac_had_posixly_correct=${POSIXLY_CORRECT:+yes} { POSIXLY_CORRECT=; unset POSIXLY_CORRECT;} if test -z "$M4"; then @@ -13755,7 +13836,7 @@ do ac_snippet=${ac_snippet}${as_nl}if'else(in''dex(..wi.d.,.d.),-1,bug)' ac_snippet=${ac_snippet}${as_nl}if'else(in''dex(;:11-:12-:12-:12-:12-:12-:12-:12-:12.:12.:12.:12.:12.:12.:12.:12.:12-,:12-:12-:12-:12-:12-:12-:12-:12-),-1,,strstr-bug2)' test -z "`$ac_path_M4 -F conftest.m4f &1`" \ - && test -z "`printf "%s\n" $ac_snippet | $ac_path_M4 --trace=mac 2>&1`" \ + && test -z "`printf '%s\n' $ac_snippet | $ac_path_M4 --trace=mac 2>&1`" \ && test -f conftest.m4f \ && ac_cv_path_M4=$ac_path_M4 ac_path_M4_found=: rm -f conftest.m4f @@ -13773,24 +13854,26 @@ Glibc 2.9 - 2.12 and GNU M4 1.4.11 - 1.4.15 have another strstr bug." "$LINENO" else ac_cv_path_M4=$M4 fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_M4" >&5 -printf "%s\n" "$ac_cv_path_M4" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_M4" >&5 +printf '%s\n' "$ac_cv_path_M4" >&6; } M4=$ac_cv_path_M4 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $ac_cv_path_M4 accepts --gnu" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $ac_cv_path_M4 accepts --gnu" >&5 printf %s "checking whether $ac_cv_path_M4 accepts --gnu... " >&6; } if test ${ac_cv_prog_gnu_m4_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - case `$M4 --help < /dev/null 2>&1` in +else case e in #( + e) case `$M4 --help < /dev/null 2>&1` in *--gnu*) ac_cv_prog_gnu_m4_gnu=yes ;; *) ac_cv_prog_gnu_m4_gnu=no ;; - esac + esac ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gnu_m4_gnu" >&5 -printf "%s\n" "$ac_cv_prog_gnu_m4_gnu" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gnu_m4_gnu" >&5 +printf '%s\n' "$ac_cv_prog_gnu_m4_gnu" >&6; } if test "$ac_cv_prog_gnu_m4_gnu" = yes; then M4_GNU=--gnu else @@ -13800,43 +13883,44 @@ printf "%s\n" "$ac_cv_prog_gnu_m4_gnu" >&6; } if test x$ac_had_posixly_correct = xyes; then POSIXLY_CORRECT=: if test $ac_cv_prog_gnu_m4_gnu = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: the version of M4 that was found does not support -g" >&5 -printf "%s\n" "$as_me: WARNING: the version of M4 that was found does not support -g" >&2;} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using it with POSIXLY_CORRECT set may cause problems" >&5 -printf "%s\n" "$as_me: WARNING: using it with POSIXLY_CORRECT set may cause problems" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: the version of M4 that was found does not support -g" >&5 +printf '%s\n' "$as_me: WARNING: the version of M4 that was found does not support -g" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: using it with POSIXLY_CORRECT set may cause problems" >&5 +printf '%s\n' "$as_me: WARNING: using it with POSIXLY_CORRECT set may cause problems" >&2;} fi fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how m4 supports trace files" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how m4 supports trace files" >&5 printf %s "checking how m4 supports trace files... " >&6; } if test ${ac_cv_prog_gnu_m4_debugfile+y} then : printf %s "(cached) " >&6 -else $as_nop - case `$M4 --help < /dev/null 2>&1` in +else case e in #( + e) case `$M4 --help < /dev/null 2>&1` in *debugfile*) ac_cv_prog_gnu_m4_debugfile=--debugfile ;; *) ac_cv_prog_gnu_m4_debugfile=--error-output ;; - esac + esac ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gnu_m4_debugfile" >&5 -printf "%s\n" "$ac_cv_prog_gnu_m4_debugfile" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_gnu_m4_debugfile" >&5 +printf '%s\n' "$ac_cv_prog_gnu_m4_debugfile" >&6; } M4_DEBUGFILE=$ac_cv_prog_gnu_m4_debugfile -printf "%s\n" "#define M4 \"$M4\"" >>confdefs.h +printf '%s\n' "#define M4 \"$M4\"" >>confdefs.h -printf "%s\n" "#define M4_GNU_OPTION \"$M4_GNU\"" >>confdefs.h +printf '%s\n' "#define M4_GNU_OPTION \"$M4_GNU\"" >>confdefs.h # Extract the first word of "perl", so it can be a program name with args. set dummy perl; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_PERL+y} then : printf %s "(cached) " >&6 -else $as_nop - case $PERL in +else case e in #( + e) case $PERL in [\\/]* | ?:[\\/]*) ac_cv_path_PERL="$PERL" # Let the user override the test with a path. ;; @@ -13853,7 +13937,7 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_PERL="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -13861,15 +13945,16 @@ done IFS=$as_save_IFS ;; +esac ;; esac fi PERL=$ac_cv_path_PERL if test -n "$PERL"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 -printf "%s\n" "$PERL" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $PERL" >&5 +printf '%s\n' "$PERL" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -13878,13 +13963,13 @@ HELP2MAN=${HELP2MAN-"${am_missing_run}help2man"} # Extract the first word of "xsltproc", so it can be a program name with args. set dummy xsltproc; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_XSLTPROC+y} then : printf %s "(cached) " >&6 -else $as_nop - case $XSLTPROC in +else case e in #( + e) case $XSLTPROC in [\\/]* | ?:[\\/]*) ac_cv_path_XSLTPROC="$XSLTPROC" # Let the user override the test with a path. ;; @@ -13901,7 +13986,7 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_XSLTPROC="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -13909,15 +13994,16 @@ done IFS=$as_save_IFS ;; +esac ;; esac fi XSLTPROC=$ac_cv_path_XSLTPROC if test -n "$XSLTPROC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 -printf "%s\n" "$XSLTPROC" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XSLTPROC" >&5 +printf '%s\n' "$XSLTPROC" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -13928,13 +14014,13 @@ fi # Checks for compiler characteristics. -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 printf %s "checking for inline... " >&6; } if test ${ac_cv_c_inline+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_c_inline=no +else case e in #( + e) ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -13952,10 +14038,11 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test "$ac_cv_c_inline" != no && break done - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 -printf "%s\n" "$ac_cv_c_inline" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +printf '%s\n' "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; @@ -13987,13 +14074,14 @@ esac if test ${enable_cross_guesses+y} then : enableval=$enable_cross_guesses; if test "x$enableval" != xconservative && test "x$enableval" != xrisky; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: invalid argument supplied to --enable-cross-guesses" >&5 -printf "%s\n" "$as_me: WARNING: invalid argument supplied to --enable-cross-guesses" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: invalid argument supplied to --enable-cross-guesses" >&5 +printf '%s\n' "$as_me: WARNING: invalid argument supplied to --enable-cross-guesses" >&2;} enableval=conservative fi gl_cross_guesses="$enableval" -else $as_nop - gl_cross_guesses=conservative +else case e in #( + e) gl_cross_guesses=conservative ;; +esac fi if test $gl_cross_guesses = risky; then @@ -14441,21 +14529,22 @@ ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes then : -else $as_nop - -printf "%s\n" "#define size_t unsigned int" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define size_t unsigned int" >>confdefs.h + ;; +esac fi # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works # for constant arguments. Useless! -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 printf %s "checking for working alloca.h... " >&6; } if test ${ac_cv_working_alloca_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -14470,29 +14559,31 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_working_alloca_h=yes -else $as_nop - ac_cv_working_alloca_h=no +else case e in #( + e) ac_cv_working_alloca_h=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext + conftest$ac_exeext conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 -printf "%s\n" "$ac_cv_working_alloca_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 +printf '%s\n' "$ac_cv_working_alloca_h" >&6; } if test $ac_cv_working_alloca_h = yes; then -printf "%s\n" "#define HAVE_ALLOCA_H 1" >>confdefs.h +printf '%s\n' "#define HAVE_ALLOCA_H 1" >>confdefs.h fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 printf %s "checking for alloca... " >&6; } if test ${ac_cv_func_alloca_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test $ac_cv_working_alloca_h = yes; then - ac_cv_func_alloca_works=yes -else +else case e in #( + e) ac_cv_func_alloca_works=$ac_cv_working_alloca_h +if test "$ac_cv_func_alloca_works" != yes +then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -14523,19 +14614,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_func_alloca_works=yes -else $as_nop - ac_cv_func_alloca_works=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext +fi ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 -printf "%s\n" "$ac_cv_func_alloca_works" >&6; } -fi +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 +printf '%s\n' "$ac_cv_func_alloca_works" >&6; } if test $ac_cv_func_alloca_works = yes; then -printf "%s\n" "#define HAVE_ALLOCA 1" >>confdefs.h +printf '%s\n' "#define HAVE_ALLOCA 1" >>confdefs.h else # The SVR3 libPW and SVR4 libucb both contain incompatible functions @@ -14549,20 +14639,20 @@ else ALLOCA=\${LIBOBJDIR}alloca.$ac_objext -printf "%s\n" "#define C_ALLOCA 1" >>confdefs.h +printf '%s\n' "#define C_ALLOCA 1" >>confdefs.h -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 printf %s "checking stack direction for C alloca... " >&6; } if test ${ac_cv_c_stack_direction+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : ac_cv_c_stack_direction=0 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int @@ -14585,17 +14675,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_c_stack_direction=1 -else $as_nop - ac_cv_c_stack_direction=-1 +else case e in #( + e) ac_cv_c_stack_direction=-1 ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 -printf "%s\n" "$ac_cv_c_stack_direction" >&6; } -printf "%s\n" "#define STACK_DIRECTION $ac_cv_c_stack_direction" >>confdefs.h +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 +printf '%s\n' "$ac_cv_c_stack_direction" >&6; } +printf '%s\n' "#define STACK_DIRECTION $ac_cv_c_stack_direction" >>confdefs.h fi @@ -14675,13 +14768,13 @@ fi REPLACE_WCTOMB=0; - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether malloc is ptrdiff_t safe" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether malloc is ptrdiff_t safe" >&5 printf %s "checking whether malloc is ptrdiff_t safe... " >&6; } if test ${gl_cv_malloc_ptrdiff+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -14715,14 +14808,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_malloc_ptrdiff=yes -else $as_nop - gl_cv_malloc_ptrdiff=no +else case e in #( + e) gl_cv_malloc_ptrdiff=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_malloc_ptrdiff" >&5 -printf "%s\n" "$gl_cv_malloc_ptrdiff" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_malloc_ptrdiff" >&5 +printf '%s\n' "$gl_cv_malloc_ptrdiff" >&6; } @@ -14731,13 +14826,13 @@ printf "%s\n" "$gl_cv_malloc_ptrdiff" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether malloc, realloc, calloc set errno on failure" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether malloc, realloc, calloc set errno on failure" >&5 printf %s "checking whether malloc, realloc, calloc set errno on failure... " >&6; } if test ${gl_cv_func_malloc_posix+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in mingw*) gl_cv_func_malloc_posix=no ;; @@ -14747,10 +14842,11 @@ else $as_nop *) gl_cv_func_malloc_posix=yes ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_malloc_posix" >&5 -printf "%s\n" "$gl_cv_func_malloc_posix" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_malloc_posix" >&5 +printf '%s\n' "$gl_cv_func_malloc_posix" >&6; } @@ -14758,7 +14854,7 @@ printf "%s\n" "$gl_cv_func_malloc_posix" >&6; } if test "$gl_cv_func_malloc_posix" = yes; then -printf "%s\n" "#define HAVE_MALLOC_POSIX 1" >>confdefs.h +printf '%s\n' "#define HAVE_MALLOC_POSIX 1" >>confdefs.h else REPLACE_MALLOC=1 @@ -14954,13 +15050,13 @@ printf "%s\n" "#define HAVE_MALLOC_POSIX 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether lstat correctly handles trailing slash" >&5 printf %s "checking whether lstat correctly handles trailing slash... " >&6; } if test ${gl_cv_func_lstat_dereferences_slashed_symlink+y} then : printf %s "(cached) " >&6 -else $as_nop - rm -f conftest.sym conftest.file +else case e in #( + e) rm -f conftest.sym conftest.file echo >conftest.file if test "$cross_compiling" = yes then : @@ -14979,8 +15075,8 @@ then : gl_cv_func_lstat_dereferences_slashed_symlink="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int @@ -15001,22 +15097,25 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_lstat_dereferences_slashed_symlink=yes -else $as_nop - gl_cv_func_lstat_dereferences_slashed_symlink=no +else case e in #( + e) gl_cv_func_lstat_dereferences_slashed_symlink=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.sym conftest.file - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_lstat_dereferences_slashed_symlink" >&5 -printf "%s\n" "$gl_cv_func_lstat_dereferences_slashed_symlink" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_lstat_dereferences_slashed_symlink" >&5 +printf '%s\n' "$gl_cv_func_lstat_dereferences_slashed_symlink" >&6; } case "$gl_cv_func_lstat_dereferences_slashed_symlink" in *yes) -printf "%s\n" "#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1" >>confdefs.h +printf '%s\n' "#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1" >>confdefs.h ;; esac @@ -15025,13 +15124,13 @@ printf "%s\n" "#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether // is distinct from /" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether // is distinct from /" >&5 printf %s "checking whether // is distinct from /... " >&6; } if test ${gl_cv_double_slash_root+y} then : printf %s "(cached) " >&6 -else $as_nop - if test x"$cross_compiling" = xyes ; then +else case e in #( + e) if test x"$cross_compiling" = xyes ; then # When cross-compiling, there is no way to tell whether // is special # short of a list of hosts. However, the only known hosts to date # that have a distinct // are Apollo DomainOS (too old to port to), @@ -15053,13 +15152,14 @@ else $as_nop else gl_cv_double_slash_root=yes fi - fi + fi ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_double_slash_root" >&5 -printf "%s\n" "$gl_cv_double_slash_root" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_double_slash_root" >&5 +printf '%s\n' "$gl_cv_double_slash_root" >&6; } if test "$gl_cv_double_slash_root" = yes; then -printf "%s\n" "#define DOUBLE_SLASH_IS_DISTINCT_ROOT 1" >>confdefs.h +printf '%s\n' "#define DOUBLE_SLASH_IS_DISTINCT_ROOT 1" >>confdefs.h fi @@ -15067,13 +15167,13 @@ printf "%s\n" "#define DOUBLE_SLASH_IS_DISTINCT_ROOT 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether realpath works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether realpath works" >&5 printf %s "checking whether realpath works... " >&6; } if test ${gl_cv_func_realpath_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) rm -rf conftest.a conftest.d touch conftest.a # Assume that if we have lstat, we can also check symlinks. @@ -15096,8 +15196,8 @@ then : *) gl_cv_func_realpath_works="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -15284,31 +15384,34 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_realpath_works=yes -else $as_nop - case $? in +else case e in #( + e) case $? in 32) gl_cv_func_realpath_works=nearly ;; *) gl_cv_func_realpath_works=no ;; esac - + ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -rf conftest.a conftest.l conftest.d - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_realpath_works" >&5 -printf "%s\n" "$gl_cv_func_realpath_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_realpath_works" >&5 +printf '%s\n' "$gl_cv_func_realpath_works" >&6; } case "$gl_cv_func_realpath_works" in *yes) -printf "%s\n" "#define FUNC_REALPATH_WORKS 1" >>confdefs.h +printf '%s\n' "#define FUNC_REALPATH_WORKS 1" >>confdefs.h ;; *nearly) -printf "%s\n" "#define FUNC_REALPATH_NEARLY_WORKS 1" >>confdefs.h +printf '%s\n' "#define FUNC_REALPATH_NEARLY_WORKS 1" >>confdefs.h ;; esac @@ -15325,7 +15428,7 @@ printf "%s\n" "#define FUNC_REALPATH_NEARLY_WORKS 1" >>confdefs.h *) ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" if test "x$ac_cv_func_getcwd" = xyes then : - printf "%s\n" "#define HAVE_GETCWD 1" >>confdefs.h + printf '%s\n' "#define HAVE_GETCWD 1" >>confdefs.h fi ;; @@ -15335,13 +15438,13 @@ fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5 printf %s "checking for C/C++ restrict keyword... " >&6; } if test ${ac_cv_c_restrict+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_c_restrict=no +else case e in #( + e) ac_cv_c_restrict=no # Put '__restrict__' first, to avoid problems with glibc and non-GCC; see: # https://lists.gnu.org/archive/html/bug-autoconf/2016-02/msg00006.html # Put 'restrict' last, because C++ lacks it. @@ -15372,16 +15475,17 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext test "$ac_cv_c_restrict" != no && break done - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 -printf "%s\n" "$ac_cv_c_restrict" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5 +printf '%s\n' "$ac_cv_c_restrict" >&6; } case $ac_cv_c_restrict in restrict) ;; - no) printf "%s\n" "#define restrict /**/" >>confdefs.h + no) printf '%s\n' "#define restrict /**/" >>confdefs.h ;; - *) printf "%s\n" "#define restrict $ac_cv_c_restrict" >>confdefs.h + *) printf '%s\n' "#define restrict $ac_cv_c_restrict" >>confdefs.h ;; esac @@ -15392,7 +15496,7 @@ printf "%s\n" "$ac_cv_c_restrict" >&6; } if test $ac_cv_func__set_invalid_parameter_handler = yes; then HAVE_MSVC_INVALID_PARAMETER_HANDLER=1 -printf "%s\n" "#define HAVE_MSVC_INVALID_PARAMETER_HANDLER 1" >>confdefs.h +printf '%s\n' "#define HAVE_MSVC_INVALID_PARAMETER_HANDLER 1" >>confdefs.h else HAVE_MSVC_INVALID_PARAMETER_HANDLER=0 @@ -15469,13 +15573,13 @@ gl_mda_defines=' - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if environ is properly declared" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking if environ is properly declared" >&5 printf %s "checking if environ is properly declared... " >&6; } if test ${gt_cv_var_environ_declaration+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_UNISTD_H #include @@ -15496,16 +15600,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gt_cv_var_environ_declaration=no -else $as_nop - gt_cv_var_environ_declaration=yes +else case e in #( + e) gt_cv_var_environ_declaration=yes ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_var_environ_declaration" >&5 -printf "%s\n" "$gt_cv_var_environ_declaration" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_var_environ_declaration" >&5 +printf '%s\n' "$gt_cv_var_environ_declaration" >&6; } if test $gt_cv_var_environ_declaration = yes; then -printf "%s\n" "#define HAVE_ENVIRON_DECL 1" >>confdefs.h +printf '%s\n' "#define HAVE_ENVIRON_DECL 1" >>confdefs.h fi @@ -15516,13 +15622,13 @@ printf "%s\n" "#define HAVE_ENVIRON_DECL 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the preprocessor supports include_next" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the preprocessor supports include_next" >&5 printf %s "checking whether the preprocessor supports include_next... " >&6; } if test ${gl_cv_have_include_next+y} then : printf %s "(cached) " >&6 -else $as_nop - rm -rf conftestd1a conftestd1b conftestd2 +else case e in #( + e) rm -rf conftestd1a conftestd1b conftestd2 mkdir conftestd1a conftestd1b conftestd2 cat < conftestd1a/conftest.h #define DEFINED_IN_CONFTESTD1 @@ -15558,8 +15664,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_have_include_next=yes -else $as_nop - CPPFLAGS="$gl_save_CPPFLAGS -Iconftestd1a -Iconftestd2" +else case e in #( + e) CPPFLAGS="$gl_save_CPPFLAGS -Iconftestd1a -Iconftestd2" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -15567,19 +15673,22 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_have_include_next=buggy -else $as_nop - gl_cv_have_include_next=no +else case e in #( + e) gl_cv_have_include_next=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CPPFLAGS="$gl_save_CPPFLAGS" rm -rf conftestd1a conftestd1b conftestd2 - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_include_next" >&5 -printf "%s\n" "$gl_cv_have_include_next" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_include_next" >&5 +printf '%s\n' "$gl_cv_have_include_next" >&6; } PRAGMA_SYSTEM_HEADER= if test $gl_cv_have_include_next = yes; then INCLUDE_NEXT=include_next @@ -15600,13 +15709,13 @@ printf "%s\n" "$gl_cv_have_include_next" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether source code line length is unlimited" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether source code line length is unlimited" >&5 printf %s "checking whether source code line length is unlimited... " >&6; } if test ${gl_cv_source_line_length_unlimited+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __TANDEM @@ -15615,18 +15724,20 @@ choke me _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "choke me" >/dev/null 2>&1 + $EGREP_TRADITIONAL "choke me" >/dev/null 2>&1 then : gl_cv_source_line_length_unlimited=no -else $as_nop - gl_cv_source_line_length_unlimited=yes +else case e in #( + e) gl_cv_source_line_length_unlimited=yes ;; +esac fi rm -rf conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_source_line_length_unlimited" >&5 -printf "%s\n" "$gl_cv_source_line_length_unlimited" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_source_line_length_unlimited" >&5 +printf '%s\n' "$gl_cv_source_line_length_unlimited" >&6; } if test $gl_cv_source_line_length_unlimited = no; then PRAGMA_COLUMNS="#pragma COLUMNS 10000" else @@ -15636,13 +15747,13 @@ printf "%s\n" "$gl_cv_source_line_length_unlimited" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for complete errno.h" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for complete errno.h" >&5 printf %s "checking for complete errno.h... " >&6; } if test ${gl_cv_header_errno_h_complete+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -15701,18 +15812,20 @@ booboo _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "booboo" >/dev/null 2>&1 + $EGREP_TRADITIONAL "booboo" >/dev/null 2>&1 then : gl_cv_header_errno_h_complete=no -else $as_nop - gl_cv_header_errno_h_complete=yes +else case e in #( + e) gl_cv_header_errno_h_complete=yes ;; +esac fi rm -rf conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_complete" >&5 -printf "%s\n" "$gl_cv_header_errno_h_complete" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_complete" >&5 +printf '%s\n' "$gl_cv_header_errno_h_complete" >&6; } if test $gl_cv_header_errno_h_complete = yes; then ERRNO_H='' else @@ -15727,13 +15840,13 @@ printf "%s\n" "$gl_cv_header_errno_h_complete" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_errno_h='<'errno.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_errno_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -15769,10 +15882,11 @@ _ACEOF gl_header=$gl_cv_absolute_errno_h gl_cv_next_errno_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_errno_h" >&5 -printf "%s\n" "$gl_cv_next_errno_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_errno_h" >&5 +printf '%s\n' "$gl_cv_next_errno_h" >&6; } fi NEXT_ERRNO_H=$gl_cv_next_errno_h @@ -15801,13 +15915,13 @@ fi if test -n "$ERRNO_H"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for EMULTIHOP value" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for EMULTIHOP value" >&5 printf %s "checking for EMULTIHOP value... " >&6; } if test ${gl_cv_header_errno_h_EMULTIHOP+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -15818,11 +15932,12 @@ yes _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : gl_cv_header_errno_h_EMULTIHOP=yes -else $as_nop - gl_cv_header_errno_h_EMULTIHOP=no +else case e in #( + e) gl_cv_header_errno_h_EMULTIHOP=no ;; +esac fi rm -rf conftest* @@ -15838,7 +15953,7 @@ yes _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : gl_cv_header_errno_h_EMULTIHOP=hidden fi @@ -15858,10 +15973,11 @@ fi fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_EMULTIHOP" >&5 -printf "%s\n" "$gl_cv_header_errno_h_EMULTIHOP" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_EMULTIHOP" >&5 +printf '%s\n' "$gl_cv_header_errno_h_EMULTIHOP" >&6; } case $gl_cv_header_errno_h_EMULTIHOP in yes | no) EMULTIHOP_HIDDEN=0; EMULTIHOP_VALUE= @@ -15876,13 +15992,13 @@ printf "%s\n" "$gl_cv_header_errno_h_EMULTIHOP" >&6; } if test -n "$ERRNO_H"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ENOLINK value" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ENOLINK value" >&5 printf %s "checking for ENOLINK value... " >&6; } if test ${gl_cv_header_errno_h_ENOLINK+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -15893,11 +16009,12 @@ yes _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : gl_cv_header_errno_h_ENOLINK=yes -else $as_nop - gl_cv_header_errno_h_ENOLINK=no +else case e in #( + e) gl_cv_header_errno_h_ENOLINK=no ;; +esac fi rm -rf conftest* @@ -15913,7 +16030,7 @@ yes _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : gl_cv_header_errno_h_ENOLINK=hidden fi @@ -15933,10 +16050,11 @@ fi fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_ENOLINK" >&5 -printf "%s\n" "$gl_cv_header_errno_h_ENOLINK" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_ENOLINK" >&5 +printf '%s\n' "$gl_cv_header_errno_h_ENOLINK" >&6; } case $gl_cv_header_errno_h_ENOLINK in yes | no) ENOLINK_HIDDEN=0; ENOLINK_VALUE= @@ -15951,13 +16069,13 @@ printf "%s\n" "$gl_cv_header_errno_h_ENOLINK" >&6; } if test -n "$ERRNO_H"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for EOVERFLOW value" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for EOVERFLOW value" >&5 printf %s "checking for EOVERFLOW value... " >&6; } if test ${gl_cv_header_errno_h_EOVERFLOW+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -15968,11 +16086,12 @@ yes _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : gl_cv_header_errno_h_EOVERFLOW=yes -else $as_nop - gl_cv_header_errno_h_EOVERFLOW=no +else case e in #( + e) gl_cv_header_errno_h_EOVERFLOW=no ;; +esac fi rm -rf conftest* @@ -15988,7 +16107,7 @@ yes _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : gl_cv_header_errno_h_EOVERFLOW=hidden fi @@ -16008,10 +16127,11 @@ fi fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_EOVERFLOW" >&5 -printf "%s\n" "$gl_cv_header_errno_h_EOVERFLOW" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_errno_h_EOVERFLOW" >&5 +printf '%s\n' "$gl_cv_header_errno_h_EOVERFLOW" >&6; } case $gl_cv_header_errno_h_EOVERFLOW in yes | no) EOVERFLOW_HIDDEN=0; EOVERFLOW_VALUE= @@ -16025,13 +16145,13 @@ printf "%s\n" "$gl_cv_header_errno_h_EOVERFLOW" >&6; } fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC options needed to detect all undeclared functions" >&5 -printf %s "checking for $CC options needed to detect all undeclared functions... " >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to detect undeclared functions" >&5 +printf %s "checking for $CC options to detect undeclared functions... " >&6; } if test ${ac_cv_c_undeclared_builtin_options+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_save_CFLAGS=$CFLAGS +else case e in #( + e) ac_save_CFLAGS=$CFLAGS ac_cv_c_undeclared_builtin_options='cannot detect' for ac_arg in '' -fno-builtin; do CFLAGS="$ac_save_CFLAGS $ac_arg" @@ -16050,8 +16170,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - # This test program should compile successfully. +else case e in #( + e) # This test program should compile successfully. # No library function is consistently available on # freestanding implementations, so test against a dummy # declaration. Include always-available headers on the @@ -16079,40 +16199,87 @@ then : if test x"$ac_arg" = x then : ac_cv_c_undeclared_builtin_options='none needed' -else $as_nop - ac_cv_c_undeclared_builtin_options=$ac_arg +else case e in #( + e) ac_cv_c_undeclared_builtin_options=$ac_arg ;; +esac fi break fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext done CFLAGS=$ac_save_CFLAGS - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 -printf "%s\n" "$ac_cv_c_undeclared_builtin_options" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_undeclared_builtin_options" >&5 +printf '%s\n' "$ac_cv_c_undeclared_builtin_options" >&6; } case $ac_cv_c_undeclared_builtin_options in #( 'cannot detect') : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot make $CC report undeclared builtins -See \`config.log' for more details" "$LINENO" 5; } ;; #( +See 'config.log' for more details" "$LINENO" 5; } ;; #( 'none needed') : ac_c_undeclared_builtin_options='' ;; #( *) : ac_c_undeclared_builtin_options=$ac_cv_c_undeclared_builtin_options ;; esac -ac_fn_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $CC options to ignore future-version functions" >&5 +printf %s "checking for $CC options to ignore future-version functions... " >&6; } +if test ${ac_cv_c_future_darwin_options+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) ac_compile_saved="$ac_compile" + ac_compile="$ac_compile -Werror=unguarded-availability-new" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if ! (defined __APPLE__ && defined __MACH__) + #error "-Werror=unguarded-availability-new not needed here" + #endif + +int +main (void) +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_c_future_darwin_options='-Werror=unguarded-availability-new' +else case e in #( + e) ac_cv_c_future_darwin_options='none needed' ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext + ac_compile="$ac_compile_saved" + ;; +esac +fi +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_future_darwin_options" >&5 +printf '%s\n' "$ac_cv_c_future_darwin_options" >&6; } + case $ac_cv_c_future_darwin_options in #( + 'none needed') : + ac_c_future_darwin_options='' ;; #( + *) : + ac_c_future_darwin_options=$ac_cv_c_future_darwin_options ;; +esac + +ac_fn_check_decl "$LINENO" "strerror_r" "ac_cv_have_decl_strerror_r" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_strerror_r" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_STRERROR_R $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_STRERROR_R $ac_have_decl" >>confdefs.h if test $ac_cv_have_decl_strerror_r = yes; then @@ -16120,17 +16287,17 @@ if test $ac_cv_have_decl_strerror_r = yes; then # (We used to run AC_CHECK_FUNCS_ONCE for strerror_r, as well # as AC_CHECK_DECLS_ONCE.) -printf "%s\n" "#define HAVE_STRERROR_R 1" >>confdefs.h +printf '%s\n' "#define HAVE_STRERROR_R 1" >>confdefs.h fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether strerror_r returns char *" >&5 printf %s "checking whether strerror_r returns char *... " >&6; } if test ${ac_cv_func_strerror_r_char_p+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) ac_cv_func_strerror_r_char_p=no if test $ac_cv_have_decl_strerror_r = yes; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -16156,13 +16323,14 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5 -printf "%s\n" "$ac_cv_func_strerror_r_char_p" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strerror_r_char_p" >&5 +printf '%s\n' "$ac_cv_func_strerror_r_char_p" >&6; } if test $ac_cv_func_strerror_r_char_p = yes; then -printf "%s\n" "#define STRERROR_R_CHAR_P 1" >>confdefs.h +printf '%s\n' "#define STRERROR_R_CHAR_P 1" >>confdefs.h fi @@ -16173,10 +16341,11 @@ ac_fn_c_check_type "$LINENO" "mode_t" "ac_cv_type_mode_t" "$ac_includes_default" if test "x$ac_cv_type_mode_t" = xyes then : -else $as_nop - -printf "%s\n" "#define mode_t int" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define mode_t int" >>confdefs.h + ;; +esac fi @@ -16188,13 +16357,14 @@ fi if test "x$ac_cv_type_sig_atomic_t" = xyes then : -printf "%s\n" "#define HAVE_SIG_ATOMIC_T 1" >>confdefs.h +printf '%s\n' "#define HAVE_SIG_ATOMIC_T 1" >>confdefs.h -else $as_nop - -printf "%s\n" "#define sig_atomic_t int" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define sig_atomic_t int" >>confdefs.h + ;; +esac fi @@ -16243,13 +16413,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working fcntl.h" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working fcntl.h" >&5 printf %s "checking for working fcntl.h... " >&6; } if test ${gl_cv_header_working_fcntl_h+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess 'no' on native Windows. @@ -16257,8 +16427,8 @@ then : *) gl_cv_header_working_fcntl_h=cross-compiling ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -16360,29 +16530,32 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_header_working_fcntl_h=yes -else $as_nop - case $? in #( +else case e in #( + e) case $? in #( 4) gl_cv_header_working_fcntl_h='no (bad O_NOFOLLOW)';; #( 64) gl_cv_header_working_fcntl_h='no (bad O_NOATIME)';; #( 68) gl_cv_header_working_fcntl_h='no (bad O_NOATIME, O_NOFOLLOW)';; #( *) gl_cv_header_working_fcntl_h='no';; - esac + esac ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_working_fcntl_h" >&5 -printf "%s\n" "$gl_cv_header_working_fcntl_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_working_fcntl_h" >&5 +printf '%s\n' "$gl_cv_header_working_fcntl_h" >&6; } case $gl_cv_header_working_fcntl_h in #( *O_NOATIME* | no | cross-compiling) ac_val=0;; #( *) ac_val=1;; esac -printf "%s\n" "#define HAVE_WORKING_O_NOATIME $ac_val" >>confdefs.h +printf '%s\n' "#define HAVE_WORKING_O_NOATIME $ac_val" >>confdefs.h case $gl_cv_header_working_fcntl_h in #( @@ -16390,7 +16563,7 @@ printf "%s\n" "#define HAVE_WORKING_O_NOATIME $ac_val" >>confdefs.h *) ac_val=1;; esac -printf "%s\n" "#define HAVE_WORKING_O_NOFOLLOW $ac_val" >>confdefs.h +printf '%s\n' "#define HAVE_WORKING_O_NOFOLLOW $ac_val" >>confdefs.h @@ -16399,8 +16572,8 @@ printf "%s\n" "#define HAVE_WORKING_O_NOFOLLOW $ac_val" >>confdefs.h if test "x$ac_cv_type_pid_t" = xyes then : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined _WIN64 && !defined __CYGWIN__ @@ -16419,14 +16592,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_pid_type='int' -else $as_nop - ac_pid_type='__int64' +else case e in #( + e) ac_pid_type='__int64' ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -printf "%s\n" "#define pid_t $ac_pid_type" >>confdefs.h - +printf '%s\n' "#define pid_t $ac_pid_type" >>confdefs.h + ;; +esac fi @@ -16444,13 +16619,13 @@ fi if test $gl_cv_have_include_next = yes; then gl_cv_next_fcntl_h='<'fcntl.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_fcntl_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -16486,10 +16661,11 @@ _ACEOF gl_header=$gl_cv_absolute_fcntl_h gl_cv_next_fcntl_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_fcntl_h" >&5 -printf "%s\n" "$gl_cv_next_fcntl_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_fcntl_h" >&5 +printf '%s\n' "$gl_cv_next_fcntl_h" >&6; } fi NEXT_FCNTL_H=$gl_cv_next_fcntl_h @@ -16737,10 +16913,11 @@ printf "%s\n" "$gl_cv_next_fcntl_h" >&6; } if test "x$ac_cv_func_eaccess" = xyes then : -else $as_nop - -printf "%s\n" "#define eaccess access" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define eaccess access" >>confdefs.h + ;; +esac fi @@ -17035,13 +17212,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdint.h" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for stdint.h" >&5 printf %s "checking for stdint.h... " >&6; } if test ${gl_cv_header_stdint_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -17056,27 +17233,29 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_header_stdint_h=yes -else $as_nop - gl_cv_header_stdint_h=no +else case e in #( + e) gl_cv_header_stdint_h=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_stdint_h" >&5 -printf "%s\n" "$gl_cv_header_stdint_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_stdint_h" >&5 +printf '%s\n' "$gl_cv_header_stdint_h" >&6; } if test $gl_cv_header_stdint_h = yes; then -printf "%s\n" "#define HAVE_STDINT_H_WITH_UINTMAX 1" >>confdefs.h +printf '%s\n' "#define HAVE_STDINT_H_WITH_UINTMAX 1" >>confdefs.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for inttypes.h" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for inttypes.h" >&5 printf %s "checking for inttypes.h... " >&6; } if test ${gl_cv_header_inttypes_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -17093,16 +17272,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_header_inttypes_h=yes -else $as_nop - gl_cv_header_inttypes_h=no +else case e in #( + e) gl_cv_header_inttypes_h=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_inttypes_h" >&5 -printf "%s\n" "$gl_cv_header_inttypes_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_inttypes_h" >&5 +printf '%s\n' "$gl_cv_header_inttypes_h" >&6; } if test $gl_cv_header_inttypes_h = yes; then -printf "%s\n" "#define HAVE_INTTYPES_H_WITH_UINTMAX 1" >>confdefs.h +printf '%s\n' "#define HAVE_INTTYPES_H_WITH_UINTMAX 1" >>confdefs.h fi @@ -17110,13 +17291,13 @@ printf "%s\n" "#define HAVE_INTTYPES_H_WITH_UINTMAX 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports size specifiers as in C99" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports size specifiers as in C99" >&5 printf %s "checking whether printf supports size specifiers as in C99... " >&6; } if test ${gl_cv_func_printf_sizes_c99+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -17155,11 +17336,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_printf_sizes_c99="guessing yes" -else $as_nop - gl_cv_func_printf_sizes_c99="guessing no" +else case e in #( + e) gl_cv_func_printf_sizes_c99="guessing no" ;; +esac fi rm -rf conftest* @@ -17168,8 +17350,8 @@ rm -rf conftest* *) gl_cv_func_printf_sizes_c99="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -17212,27 +17394,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_sizes_c99=yes -else $as_nop - gl_cv_func_printf_sizes_c99=no +else case e in #( + e) gl_cv_func_printf_sizes_c99=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_sizes_c99" >&5 -printf "%s\n" "$gl_cv_func_printf_sizes_c99" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_sizes_c99" >&5 +printf '%s\n' "$gl_cv_func_printf_sizes_c99" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports 'long double' arguments" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports 'long double' arguments" >&5 printf %s "checking whether printf supports 'long double' arguments... " >&6; } if test ${gl_cv_func_printf_long_double+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -17250,11 +17435,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_printf_long_double="guessing yes" -else $as_nop - gl_cv_func_printf_long_double="guessing no" +else case e in #( + e) gl_cv_func_printf_long_double="guessing no" ;; +esac fi rm -rf conftest* @@ -17262,8 +17448,8 @@ rm -rf conftest* *) gl_cv_func_printf_long_double="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -17290,27 +17476,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_long_double=yes -else $as_nop - gl_cv_func_printf_long_double=no +else case e in #( + e) gl_cv_func_printf_long_double=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_long_double" >&5 -printf "%s\n" "$gl_cv_func_printf_long_double" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_long_double" >&5 +printf '%s\n' "$gl_cv_func_printf_long_double" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports infinite 'double' arguments" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports infinite 'double' arguments" >&5 printf %s "checking whether printf supports infinite 'double' arguments... " >&6; } if test ${gl_cv_func_printf_infinite+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -17350,11 +17539,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_printf_infinite="guessing yes" -else $as_nop - gl_cv_func_printf_infinite="guessing no" +else case e in #( + e) gl_cv_func_printf_infinite="guessing no" ;; +esac fi rm -rf conftest* @@ -17363,8 +17553,8 @@ rm -rf conftest* *) gl_cv_func_printf_infinite="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -17437,26 +17627,29 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_infinite=yes -else $as_nop - gl_cv_func_printf_infinite=no +else case e in #( + e) gl_cv_func_printf_infinite=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_infinite" >&5 -printf "%s\n" "$gl_cv_func_printf_infinite" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_infinite" >&5 +printf '%s\n' "$gl_cv_func_printf_infinite" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 printf %s "checking whether byte ordering is bigendian... " >&6; } if test ${ac_cv_c_bigendian+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_c_bigendian=unknown +else case e in #( + e) ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -17502,8 +17695,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext int main (void) { -#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ - && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \\ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \\ && LITTLE_ENDIAN) bogus endian macros #endif @@ -17534,8 +17727,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes -else $as_nop - ac_cv_c_bigendian=no +else case e in #( + e) ac_cv_c_bigendian=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi @@ -17579,8 +17773,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes -else $as_nop - ac_cv_c_bigendian=no +else case e in #( + e) ac_cv_c_bigendian=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi @@ -17607,22 +17802,23 @@ unsigned short int ascii_mm[] = int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } - extern int foo; - -int -main (void) -{ -return use_ascii (foo) == use_ebcdic (foo); - ; - return 0; -} + int + main (int argc, char **argv) + { + /* Intimidate the compiler so that it does not + optimize the arrays away. */ + char *p = argv[0]; + ascii_mm[1] = *p++; ebcdic_mm[1] = *p++; + ascii_ii[1] = *p++; ebcdic_ii[1] = *p++; + return use_ascii (argc) == use_ebcdic (*p); + } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : - if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + if grep BIGenDianSyS conftest$ac_exeext >/dev/null; then ac_cv_c_bigendian=yes fi - if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if grep LiTTleEnDian conftest$ac_exeext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else @@ -17631,9 +17827,10 @@ then : fi fi fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int @@ -17656,26 +17853,29 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_c_bigendian=no -else $as_nop - ac_cv_c_bigendian=yes +else case e in #( + e) ac_cv_c_bigendian=yes ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - fi + fi ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 -printf "%s\n" "$ac_cv_c_bigendian" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +printf '%s\n' "$ac_cv_c_bigendian" >&6; } case $ac_cv_c_bigendian in #( yes) - printf "%s\n" "#define WORDS_BIGENDIAN 1" >>confdefs.h + printf '%s\n' "#define WORDS_BIGENDIAN 1" >>confdefs.h ;; #( no) ;; #( universal) -printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h +printf '%s\n' "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) @@ -17685,13 +17885,13 @@ printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether long double and double are the same" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether long double and double are the same" >&5 printf %s "checking whether long double and double are the same... " >&6; } if test ${gl_cv_long_double_equals_double+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -17710,17 +17910,19 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_long_double_equals_double=yes -else $as_nop - gl_cv_long_double_equals_double=no +else case e in #( + e) gl_cv_long_double_equals_double=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_long_double_equals_double" >&5 -printf "%s\n" "$gl_cv_long_double_equals_double" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_long_double_equals_double" >&5 +printf '%s\n' "$gl_cv_long_double_equals_double" >&6; } if test $gl_cv_long_double_equals_double = yes; then -printf "%s\n" "#define HAVE_SAME_LONG_DOUBLE_AS_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define HAVE_SAME_LONG_DOUBLE_AS_DOUBLE 1" >>confdefs.h HAVE_SAME_LONG_DOUBLE_AS_DOUBLE=1 else @@ -17735,18 +17937,18 @@ printf "%s\n" "#define HAVE_SAME_LONG_DOUBLE_AS_DOUBLE 1" >>confdefs.h if test -n "$gl_printf_safe"; then -printf "%s\n" "#define CHECK_PRINTF_SAFE 1" >>confdefs.h +printf '%s\n' "#define CHECK_PRINTF_SAFE 1" >>confdefs.h fi case "$gl_cv_func_printf_long_double" in *yes) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports infinite 'long double' arguments" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports infinite 'long double' arguments" >&5 printf %s "checking whether printf supports infinite 'long double' arguments... " >&6; } if test ${gl_cv_func_printf_infinite_long_double+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_cpu" in @@ -17780,11 +17982,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_printf_infinite_long_double="guessing yes" -else $as_nop - gl_cv_func_printf_infinite_long_double="guessing no" +else case e in #( + e) gl_cv_func_printf_infinite_long_double="guessing no" ;; +esac fi rm -rf conftest* @@ -17795,8 +17998,8 @@ rm -rf conftest* ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -18064,17 +18267,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_infinite_long_double=yes -else $as_nop - gl_cv_func_printf_infinite_long_double=no +else case e in #( + e) gl_cv_func_printf_infinite_long_double=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_infinite_long_double" >&5 -printf "%s\n" "$gl_cv_func_printf_infinite_long_double" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_infinite_long_double" >&5 +printf '%s\n' "$gl_cv_func_printf_infinite_long_double" >&6; } ;; *) gl_cv_func_printf_infinite_long_double="irrelevant" @@ -18083,13 +18289,13 @@ printf "%s\n" "$gl_cv_func_printf_infinite_long_double" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports the 'a' and 'A' directives" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports the 'a' and 'A' directives" >&5 printf %s "checking whether printf supports the 'a' and 'A' directives... " >&6; } if test ${gl_cv_func_printf_directive_a+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -18108,11 +18314,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "BZ2908" >/dev/null 2>&1 + $EGREP_TRADITIONAL "BZ2908" >/dev/null 2>&1 then : gl_cv_func_printf_directive_a="guessing yes" -else $as_nop - gl_cv_func_printf_directive_a="guessing no" +else case e in #( + e) gl_cv_func_printf_directive_a="guessing no" ;; +esac fi rm -rf conftest* @@ -18127,8 +18334,8 @@ rm -rf conftest* *) gl_cv_func_printf_directive_a="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -18190,27 +18397,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_directive_a=yes -else $as_nop - gl_cv_func_printf_directive_a=no +else case e in #( + e) gl_cv_func_printf_directive_a=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_directive_a" >&5 -printf "%s\n" "$gl_cv_func_printf_directive_a" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_directive_a" >&5 +printf '%s\n' "$gl_cv_func_printf_directive_a" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports the 'F' directive" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports the 'F' directive" >&5 printf %s "checking whether printf supports the 'F' directive... " >&6; } if test ${gl_cv_func_printf_directive_f+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -18244,11 +18454,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_printf_directive_f="guessing yes" -else $as_nop - gl_cv_func_printf_directive_f="guessing no" +else case e in #( + e) gl_cv_func_printf_directive_f="guessing no" ;; +esac fi rm -rf conftest* @@ -18257,8 +18468,8 @@ rm -rf conftest* *) gl_cv_func_printf_directive_f="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -18284,27 +18495,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_directive_f=yes -else $as_nop - gl_cv_func_printf_directive_f=no +else case e in #( + e) gl_cv_func_printf_directive_f=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_directive_f" >&5 -printf "%s\n" "$gl_cv_func_printf_directive_f" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_directive_f" >&5 +printf '%s\n' "$gl_cv_func_printf_directive_f" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports the 'n' directive" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports the 'n' directive" >&5 printf %s "checking whether printf supports the 'n' directive... " >&6; } if test ${gl_cv_func_printf_directive_n+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -18319,8 +18533,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_printf_directive_n="guessing yes" -else $as_nop - gl_cv_func_printf_directive_n="guessing no" +else case e in #( + e) gl_cv_func_printf_directive_n="guessing no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -18331,8 +18546,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext *) gl_cv_func_printf_directive_n="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -18374,27 +18589,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_directive_n=yes -else $as_nop - gl_cv_func_printf_directive_n=no +else case e in #( + e) gl_cv_func_printf_directive_n=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_directive_n" >&5 -printf "%s\n" "$gl_cv_func_printf_directive_n" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_directive_n" >&5 +printf '%s\n' "$gl_cv_func_printf_directive_n" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports the 'ls' directive" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports the 'ls' directive" >&5 printf %s "checking whether printf supports the 'ls' directive... " >&6; } if test ${gl_cv_func_printf_directive_ls+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -18413,8 +18631,8 @@ then : *) gl_cv_func_printf_directive_ls="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -18464,27 +18682,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_directive_ls=yes -else $as_nop - gl_cv_func_printf_directive_ls=no +else case e in #( + e) gl_cv_func_printf_directive_ls=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_directive_ls" >&5 -printf "%s\n" "$gl_cv_func_printf_directive_ls" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_directive_ls" >&5 +printf '%s\n' "$gl_cv_func_printf_directive_ls" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports POSIX/XSI format strings with positions" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports POSIX/XSI format strings with positions" >&5 printf %s "checking whether printf supports POSIX/XSI format strings with positions... " >&6; } if test ${gl_cv_func_printf_positions+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -18499,8 +18720,8 @@ then : *) gl_cv_func_printf_positions="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -18518,27 +18739,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_positions=yes -else $as_nop - gl_cv_func_printf_positions=no +else case e in #( + e) gl_cv_func_printf_positions=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_positions" >&5 -printf "%s\n" "$gl_cv_func_printf_positions" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_positions" >&5 +printf '%s\n' "$gl_cv_func_printf_positions" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports the grouping flag" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports the grouping flag" >&5 printf %s "checking whether printf supports the grouping flag... " >&6; } if test ${gl_cv_func_printf_flag_grouping+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -18552,8 +18776,8 @@ then : *) gl_cv_func_printf_flag_grouping="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -18570,27 +18794,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_flag_grouping=yes -else $as_nop - gl_cv_func_printf_flag_grouping=no +else case e in #( + e) gl_cv_func_printf_flag_grouping=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_flag_grouping" >&5 -printf "%s\n" "$gl_cv_func_printf_flag_grouping" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_flag_grouping" >&5 +printf '%s\n' "$gl_cv_func_printf_flag_grouping" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports the left-adjust flag correctly" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports the left-adjust flag correctly" >&5 printf %s "checking whether printf supports the left-adjust flag correctly... " >&6; } if test ${gl_cv_func_printf_flag_leftadjust+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -18607,8 +18834,8 @@ then : *) gl_cv_func_printf_flag_leftadjust="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -18626,27 +18853,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_flag_leftadjust=yes -else $as_nop - gl_cv_func_printf_flag_leftadjust=no +else case e in #( + e) gl_cv_func_printf_flag_leftadjust=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_flag_leftadjust" >&5 -printf "%s\n" "$gl_cv_func_printf_flag_leftadjust" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_flag_leftadjust" >&5 +printf '%s\n' "$gl_cv_func_printf_flag_leftadjust" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports the zero flag correctly" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports the zero flag correctly" >&5 printf %s "checking whether printf supports the zero flag correctly... " >&6; } if test ${gl_cv_func_printf_flag_zero+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -18665,8 +18895,8 @@ then : *) gl_cv_func_printf_flag_zero="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -18685,27 +18915,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_flag_zero=yes -else $as_nop - gl_cv_func_printf_flag_zero=no +else case e in #( + e) gl_cv_func_printf_flag_zero=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_flag_zero" >&5 -printf "%s\n" "$gl_cv_func_printf_flag_zero" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_flag_zero" >&5 +printf '%s\n' "$gl_cv_func_printf_flag_zero" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports large precisions" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports large precisions" >&5 printf %s "checking whether printf supports large precisions... " >&6; } if test ${gl_cv_func_printf_precision+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -18719,8 +18952,8 @@ then : *) gl_cv_func_printf_precision="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -18749,26 +18982,29 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_precision=yes -else $as_nop - gl_cv_func_printf_precision=no +else case e in #( + e) gl_cv_func_printf_precision=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_precision" >&5 -printf "%s\n" "$gl_cv_func_printf_precision" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_precision" >&5 +printf '%s\n' "$gl_cv_func_printf_precision" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler produces multi-arch binaries" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the compiler produces multi-arch binaries" >&5 printf %s "checking whether the compiler produces multi-arch binaries... " >&6; } if test ${gl_cv_c_multiarch+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_cv_c_multiarch=no +else case e in #( + e) gl_cv_c_multiarch=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __APPLE_CC__ @@ -18803,10 +19039,11 @@ then : fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_c_multiarch" >&5 -printf "%s\n" "$gl_cv_c_multiarch" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_c_multiarch" >&5 +printf '%s\n' "$gl_cv_c_multiarch" >&6; } if test $gl_cv_c_multiarch = yes; then APPLE_UNIVERSAL_BUILD=1 else @@ -18817,13 +19054,13 @@ printf "%s\n" "$gl_cv_c_multiarch" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf survives out-of-memory conditions" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf survives out-of-memory conditions" >&5 printf %s "checking whether printf survives out-of-memory conditions... " >&6; } if test ${gl_cv_func_printf_enomem+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_cv_func_printf_enomem="guessing no" if test "$cross_compiling" = no; then if test $APPLE_UNIVERSAL_BUILD = 0; then @@ -18993,11 +19230,11 @@ _ACEOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest$ac_exeext; then (./conftest 2>&5 result=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $result" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $result" >&5 if test $result != 0 && test $result != 77; then result=1; fi exit $result ) >/dev/null 2>/dev/null @@ -19042,10 +19279,11 @@ _ACEOF *) gl_cv_func_printf_enomem="$gl_cross_guess_normal";; esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_enomem" >&5 -printf "%s\n" "$gl_cv_func_printf_enomem" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_enomem" >&5 +printf '%s\n' "$gl_cv_func_printf_enomem" >&6; } @@ -19054,20 +19292,20 @@ printf "%s\n" "$gl_cv_func_printf_enomem" >&6; } ;; *) -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wchar_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for wchar_t" >&5 printf %s "checking for wchar_t... " >&6; } if test ${gt_cv_c_wchar_t+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include wchar_t foo = (wchar_t)'\0'; @@ -19082,27 +19320,29 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gt_cv_c_wchar_t=yes -else $as_nop - gt_cv_c_wchar_t=no +else case e in #( + e) gt_cv_c_wchar_t=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_c_wchar_t" >&5 -printf "%s\n" "$gt_cv_c_wchar_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_c_wchar_t" >&5 +printf '%s\n' "$gt_cv_c_wchar_t" >&6; } if test $gt_cv_c_wchar_t = yes; then -printf "%s\n" "#define HAVE_WCHAR_T 1" >>confdefs.h +printf '%s\n' "#define HAVE_WCHAR_T 1" >>confdefs.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wint_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for wint_t" >&5 printf %s "checking for wint_t... " >&6; } if test ${gt_cv_c_wint_t+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include wint_t foo = (wchar_t)'\0'; @@ -19117,25 +19357,27 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gt_cv_c_wint_t=yes -else $as_nop - gt_cv_c_wint_t=no +else case e in #( + e) gt_cv_c_wint_t=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_c_wint_t" >&5 -printf "%s\n" "$gt_cv_c_wint_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_c_wint_t" >&5 +printf '%s\n' "$gt_cv_c_wint_t" >&6; } if test $gt_cv_c_wint_t = yes; then -printf "%s\n" "#define HAVE_WINT_T 1" >>confdefs.h +printf '%s\n' "#define HAVE_WINT_T 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether wint_t is large enough" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether wint_t is large enough" >&5 printf %s "checking whether wint_t is large enough... " >&6; } if test ${gl_cv_type_wint_t_large_enough+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int verify[sizeof (wint_t) < sizeof (int) ? -1 : 1]; @@ -19151,13 +19393,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_type_wint_t_large_enough=yes -else $as_nop - gl_cv_type_wint_t_large_enough=no +else case e in #( + e) gl_cv_type_wint_t_large_enough=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_wint_t_large_enough" >&5 -printf "%s\n" "$gl_cv_type_wint_t_large_enough" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_wint_t_large_enough" >&5 +printf '%s\n' "$gl_cv_type_wint_t_large_enough" >&6; } if test $gl_cv_type_wint_t_large_enough = no; then GNULIBHEADERS_OVERRIDE_WINT_T=1 else @@ -19181,13 +19425,13 @@ printf "%s\n" "$gl_cv_type_wint_t_large_enough" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for intmax_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for intmax_t" >&5 printf %s "checking for intmax_t... " >&6; } if test ${gt_cv_c_intmax_t+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -19210,31 +19454,33 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gt_cv_c_intmax_t=yes -else $as_nop - gt_cv_c_intmax_t=no +else case e in #( + e) gt_cv_c_intmax_t=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_c_intmax_t" >&5 -printf "%s\n" "$gt_cv_c_intmax_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_c_intmax_t" >&5 +printf '%s\n' "$gt_cv_c_intmax_t" >&6; } if test $gt_cv_c_intmax_t = yes; then -printf "%s\n" "#define HAVE_INTMAX_T 1" >>confdefs.h +printf '%s\n' "#define HAVE_INTMAX_T 1" >>confdefs.h else -printf "%s\n" "#define intmax_t long long" >>confdefs.h +printf '%s\n' "#define intmax_t long long" >>confdefs.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'double'" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'double'" >&5 printf %s "checking where to find the exponent in a 'double'... " >&6; } if test ${gl_cv_cc_double_expbit0+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -19247,17 +19493,17 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "mixed_endianness" >/dev/null 2>&1 + $EGREP_TRADITIONAL "mixed_endianness" >/dev/null 2>&1 then : gl_cv_cc_double_expbit0="unknown" -else $as_nop - +else case e in #( + e) : if test ${ac_cv_c_bigendian+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_cv_c_bigendian=unknown +else case e in #( + e) ac_cv_c_bigendian=unknown # See if we're dealing with a universal compiler. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -19303,8 +19549,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext int main (void) { -#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ - && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \\ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \\ && LITTLE_ENDIAN) bogus endian macros #endif @@ -19335,8 +19581,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes -else $as_nop - ac_cv_c_bigendian=no +else case e in #( + e) ac_cv_c_bigendian=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi @@ -19380,8 +19627,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_c_bigendian=yes -else $as_nop - ac_cv_c_bigendian=no +else case e in #( + e) ac_cv_c_bigendian=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi @@ -19408,22 +19656,23 @@ unsigned short int ascii_mm[] = int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } - extern int foo; - -int -main (void) -{ -return use_ascii (foo) == use_ebcdic (foo); - ; - return 0; -} + int + main (int argc, char **argv) + { + /* Intimidate the compiler so that it does not + optimize the arrays away. */ + char *p = argv[0]; + ascii_mm[1] = *p++; ebcdic_mm[1] = *p++; + ascii_ii[1] = *p++; ebcdic_ii[1] = *p++; + return use_ascii (argc) == use_ebcdic (*p); + } _ACEOF -if ac_fn_c_try_compile "$LINENO" +if ac_fn_c_try_link "$LINENO" then : - if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + if grep BIGenDianSyS conftest$ac_exeext >/dev/null; then ac_cv_c_bigendian=yes fi - if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if grep LiTTleEnDian conftest$ac_exeext >/dev/null ; then if test "$ac_cv_c_bigendian" = unknown; then ac_cv_c_bigendian=no else @@ -19432,9 +19681,10 @@ then : fi fi fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int @@ -19457,14 +19707,17 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_c_bigendian=no -else $as_nop - ac_cv_c_bigendian=yes +else case e in #( + e) ac_cv_c_bigendian=yes ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - fi + fi ;; +esac fi : case $ac_cv_c_bigendian in #( @@ -19474,20 +19727,21 @@ fi gl_cv_cc_double_expbit0="word 1 bit 20" ;; #( universal) -printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h +printf '%s\n' "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h ;; #( *) gl_cv_cc_double_expbit0="unknown" ;; esac - + ;; +esac fi rm -rf conftest* -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -19557,27 +19811,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_cc_double_expbit0=`cat conftest.out` -else $as_nop - gl_cv_cc_double_expbit0="unknown" +else case e in #( + e) gl_cv_cc_double_expbit0="unknown" ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.out - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_double_expbit0" >&5 -printf "%s\n" "$gl_cv_cc_double_expbit0" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_double_expbit0" >&5 +printf '%s\n' "$gl_cv_cc_double_expbit0" >&6; } case "$gl_cv_cc_double_expbit0" in word*bit*) word=`echo "$gl_cv_cc_double_expbit0" | sed -e 's/word //' -e 's/ bit.*//'` bit=`echo "$gl_cv_cc_double_expbit0" | sed -e 's/word.*bit //'` -printf "%s\n" "#define DBL_EXPBIT0_WORD $word" >>confdefs.h +printf '%s\n' "#define DBL_EXPBIT0_WORD $word" >>confdefs.h -printf "%s\n" "#define DBL_EXPBIT0_BIT $bit" >>confdefs.h +printf '%s\n' "#define DBL_EXPBIT0_BIT $bit" >>confdefs.h ;; esac @@ -19589,13 +19846,13 @@ printf "%s\n" "#define DBL_EXPBIT0_BIT $bit" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether snprintf returns a byte count as in C99" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether snprintf returns a byte count as in C99" >&5 printf %s "checking whether snprintf returns a byte count as in C99... " >&6; } if test ${gl_cv_func_snprintf_retval_c99+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -19638,11 +19895,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_snprintf_retval_c99="guessing yes" -else $as_nop - gl_cv_func_snprintf_retval_c99="guessing no" +else case e in #( + e) gl_cv_func_snprintf_retval_c99="guessing no" ;; +esac fi rm -rf conftest* @@ -19651,8 +19909,8 @@ rm -rf conftest* *) gl_cv_func_snprintf_retval_c99="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -19687,28 +19945,31 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_snprintf_retval_c99=yes -else $as_nop - gl_cv_func_snprintf_retval_c99=no +else case e in #( + e) gl_cv_func_snprintf_retval_c99=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_retval_c99" >&5 -printf "%s\n" "$gl_cv_func_snprintf_retval_c99" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_retval_c99" >&5 +printf '%s\n' "$gl_cv_func_snprintf_retval_c99" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether snprintf truncates the result as in C99" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether snprintf truncates the result as in C99" >&5 printf %s "checking whether snprintf truncates the result as in C99... " >&6; } if test ${gl_cv_func_snprintf_truncation_c99+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -19757,8 +20018,8 @@ then : *) gl_cv_func_snprintf_truncation_c99="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -19790,17 +20051,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_snprintf_truncation_c99=yes -else $as_nop - gl_cv_func_snprintf_truncation_c99=no +else case e in #( + e) gl_cv_func_snprintf_truncation_c99=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_truncation_c99" >&5 -printf "%s\n" "$gl_cv_func_snprintf_truncation_c99" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_truncation_c99" >&5 +printf '%s\n' "$gl_cv_func_snprintf_truncation_c99" >&6; } @@ -19809,56 +20073,57 @@ printf "%s\n" "$gl_cv_func_snprintf_truncation_c99" >&6; } ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" if test "x$ac_cv_func_snprintf" = xyes then : - printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h + printf '%s\n' "#define HAVE_SNPRINTF 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "strnlen" "ac_cv_func_strnlen" if test "x$ac_cv_func_strnlen" = xyes then : - printf "%s\n" "#define HAVE_STRNLEN 1" >>confdefs.h + printf '%s\n' "#define HAVE_STRNLEN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "wcslen" "ac_cv_func_wcslen" if test "x$ac_cv_func_wcslen" = xyes then : - printf "%s\n" "#define HAVE_WCSLEN 1" >>confdefs.h + printf '%s\n' "#define HAVE_WCSLEN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "wcsnlen" "ac_cv_func_wcsnlen" if test "x$ac_cv_func_wcsnlen" = xyes then : - printf "%s\n" "#define HAVE_WCSNLEN 1" >>confdefs.h + printf '%s\n' "#define HAVE_WCSNLEN 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "mbrtowc" "ac_cv_func_mbrtowc" if test "x$ac_cv_func_mbrtowc" = xyes then : - printf "%s\n" "#define HAVE_MBRTOWC 1" >>confdefs.h + printf '%s\n' "#define HAVE_MBRTOWC 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "wcrtomb" "ac_cv_func_wcrtomb" if test "x$ac_cv_func_wcrtomb" = xyes then : - printf "%s\n" "#define HAVE_WCRTOMB 1" >>confdefs.h + printf '%s\n' "#define HAVE_WCRTOMB 1" >>confdefs.h fi ac_fn_check_decl "$LINENO" "_snprintf" "ac_cv_have_decl__snprintf" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl__snprintf" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL__SNPRINTF $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL__SNPRINTF $ac_have_decl" >>confdefs.h case "$gl_cv_func_snprintf_retval_c99" in *yes) -printf "%s\n" "#define HAVE_SNPRINTF_RETVAL_C99 1" >>confdefs.h +printf '%s\n' "#define HAVE_SNPRINTF_RETVAL_C99 1" >>confdefs.h ;; esac @@ -19866,7 +20131,7 @@ printf "%s\n" "#define HAVE_SNPRINTF_RETVAL_C99 1" >>confdefs.h case "$gl_cv_func_snprintf_truncation_c99" in *yes) -printf "%s\n" "#define HAVE_SNPRINTF_TRUNCATION_C99 1" >>confdefs.h +printf '%s\n' "#define HAVE_SNPRINTF_TRUNCATION_C99 1" >>confdefs.h ;; esac @@ -20049,13 +20314,13 @@ printf "%s\n" "#define HAVE_SNPRINTF_TRUNCATION_C99 1" >>confdefs.h REPLACE_TRUNCL=0; - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether frexp() can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether frexp() can be used without linking with libm" >&5 printf %s "checking whether frexp() can be used without linking with libm... " >&6; } if test ${gl_cv_func_frexp_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -20071,24 +20336,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_frexp_no_libm=yes -else $as_nop - gl_cv_func_frexp_no_libm=no +else case e in #( + e) gl_cv_func_frexp_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexp_no_libm" >&5 -printf "%s\n" "$gl_cv_func_frexp_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexp_no_libm" >&5 +printf '%s\n' "$gl_cv_func_frexp_no_libm" >&6; } -ac_fn_check_decl "$LINENO" "alarm" "ac_cv_have_decl_alarm" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "alarm" "ac_cv_have_decl_alarm" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_alarm" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_ALARM $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_ALARM $ac_have_decl" >>confdefs.h @@ -20499,13 +20767,13 @@ printf "%s\n" "#define HAVE_DECL_ALARM $ac_have_decl" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getcwd (NULL, 0) allocates memory for result" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether getcwd (NULL, 0) allocates memory for result" >&5 printf %s "checking whether getcwd (NULL, 0) allocates memory for result... " >&6; } if test ${gl_cv_func_getcwd_null+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on glibc systems. @@ -20518,8 +20786,8 @@ then : *) gl_cv_func_getcwd_null="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include @@ -20567,25 +20835,28 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_getcwd_null=yes -else $as_nop - gl_cv_func_getcwd_null=no +else case e in #( + e) gl_cv_func_getcwd_null=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getcwd_null" >&5 -printf "%s\n" "$gl_cv_func_getcwd_null" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getcwd_null" >&5 +printf '%s\n' "$gl_cv_func_getcwd_null" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getcwd with POSIX signature" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for getcwd with POSIX signature" >&5 printf %s "checking for getcwd with POSIX signature... " >&6; } if test ${gl_cv_func_getcwd_posix_signature+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -20609,34 +20880,37 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_getcwd_posix_signature=yes -else $as_nop - gl_cv_func_getcwd_posix_signature=no +else case e in #( + e) gl_cv_func_getcwd_posix_signature=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getcwd_posix_signature" >&5 -printf "%s\n" "$gl_cv_func_getcwd_posix_signature" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getcwd_posix_signature" >&5 +printf '%s\n' "$gl_cv_func_getcwd_posix_signature" >&6; } -ac_fn_check_decl "$LINENO" "getcwd" "ac_cv_have_decl_getcwd" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "getcwd" "ac_cv_have_decl_getcwd" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_getcwd" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_GETCWD $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_GETCWD $ac_have_decl" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for d_ino member in directory struct" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for d_ino member in directory struct" >&5 printf %s "checking for d_ino member in directory struct... " >&6; } if test ${gl_cv_struct_dirent_d_ino+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on glibc systems with Linux kernel. @@ -20649,8 +20923,8 @@ then : *) gl_cv_struct_dirent_d_ino="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -20681,20 +20955,23 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_struct_dirent_d_ino=yes -else $as_nop - gl_cv_struct_dirent_d_ino=no +else case e in #( + e) gl_cv_struct_dirent_d_ino=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_struct_dirent_d_ino" >&5 -printf "%s\n" "$gl_cv_struct_dirent_d_ino" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_struct_dirent_d_ino" >&5 +printf '%s\n' "$gl_cv_struct_dirent_d_ino" >&6; } case "$gl_cv_struct_dirent_d_ino" in *yes) -printf "%s\n" "#define D_INO_IN_DIRENT 1" >>confdefs.h +printf '%s\n' "#define D_INO_IN_DIRENT 1" >>confdefs.h ;; esac @@ -20702,13 +20979,13 @@ printf "%s\n" "#define D_INO_IN_DIRENT 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for arithmetic hrtime_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for arithmetic hrtime_t" >&5 printf %s "checking for arithmetic hrtime_t... " >&6; } if test ${gl_cv_arithmetic_hrtime_t+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -20722,16 +20999,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_arithmetic_hrtime_t=yes -else $as_nop - gl_cv_arithmetic_hrtime_t=no +else case e in #( + e) gl_cv_arithmetic_hrtime_t=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_arithmetic_hrtime_t" >&5 -printf "%s\n" "$gl_cv_arithmetic_hrtime_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_arithmetic_hrtime_t" >&5 +printf '%s\n' "$gl_cv_arithmetic_hrtime_t" >&6; } if test $gl_cv_arithmetic_hrtime_t = yes; then -printf "%s\n" "#define HAVE_ARITHMETIC_HRTIME_T 1" >>confdefs.h +printf '%s\n' "#define HAVE_ARITHMETIC_HRTIME_T 1" >>confdefs.h fi @@ -20757,13 +21036,13 @@ printf "%s\n" "#define HAVE_ARITHMETIC_HRTIME_T 1" >>confdefs.h if test $gl_cv_have_include_next = yes; then gl_cv_next_getopt_h='<'getopt.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_getopt_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_getopt_h = yes; then @@ -20805,10 +21084,11 @@ _ACEOF gl_cv_next_getopt_h='<'getopt.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_getopt_h" >&5 -printf "%s\n" "$gl_cv_next_getopt_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_getopt_h" >&5 +printf '%s\n' "$gl_cv_next_getopt_h" >&6; } fi NEXT_GETOPT_H=$gl_cv_next_getopt_h @@ -20839,10 +21119,11 @@ do : ac_fn_c_check_header_compile "$LINENO" "getopt.h" "ac_cv_header_getopt_h" "$ac_includes_default" if test "x$ac_cv_header_getopt_h" = xyes then : - printf "%s\n" "#define HAVE_GETOPT_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_GETOPT_H 1" >>confdefs.h -else $as_nop - gl_replace_getopt=yes +else case e in #( + e) gl_replace_getopt=yes ;; +esac fi done @@ -20855,32 +21136,33 @@ do : ac_fn_c_check_func "$LINENO" "getopt_long_only" "ac_cv_func_getopt_long_only" if test "x$ac_cv_func_getopt_long_only" = xyes then : - printf "%s\n" "#define HAVE_GETOPT_LONG_ONLY 1" >>confdefs.h + printf '%s\n' "#define HAVE_GETOPT_LONG_ONLY 1" >>confdefs.h -else $as_nop - gl_replace_getopt=yes +else case e in #( + e) gl_replace_getopt=yes ;; +esac fi done fi if test -z "$gl_replace_getopt"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getopt is POSIX compatible" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether getopt is POSIX compatible" >&5 printf %s "checking whether getopt is POSIX compatible... " >&6; } if test ${gl_cv_func_getopt_posix+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $cross_compiling = no; then if test "$cross_compiling" = yes then : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -20912,22 +21194,24 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_getopt_posix=maybe -else $as_nop - gl_cv_func_getopt_posix=no +else case e in #( + e) gl_cv_func_getopt_posix=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi if test $gl_cv_func_getopt_posix = maybe; then if test "$cross_compiling" = yes then : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -20973,23 +21257,25 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_getopt_posix=maybe -else $as_nop - gl_cv_func_getopt_posix=no +else case e in #( + e) gl_cv_func_getopt_posix=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi if test $gl_cv_func_getopt_posix = maybe; then if test "$cross_compiling" = yes then : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -21017,11 +21303,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_getopt_posix=yes -else $as_nop - gl_cv_func_getopt_posix=no +else case e in #( + e) gl_cv_func_getopt_posix=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi @@ -21031,23 +21319,24 @@ fi *) gl_cv_func_getopt_posix="guessing yes";; esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getopt_posix" >&5 -printf "%s\n" "$gl_cv_func_getopt_posix" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getopt_posix" >&5 +printf '%s\n' "$gl_cv_func_getopt_posix" >&6; } case "$gl_cv_func_getopt_posix" in *no) gl_replace_getopt=yes ;; esac fi if test -z "$gl_replace_getopt" && test $gl_getopt_required = GNU; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working GNU getopt function" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working GNU getopt function" >&5 printf %s "checking for working GNU getopt function... " >&6; } if test ${gl_cv_func_getopt_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - # Even with POSIXLY_CORRECT, the GNU extension of leading '-' in the +else case e in #( + e) # Even with POSIXLY_CORRECT, the GNU extension of leading '-' in the # optstring is necessary for programs like m4 that have POSIX-mandated # semantics for supporting options interspersed with files. # Also, since getopt_long is a GNU extension, we require optind=0. @@ -21065,8 +21354,8 @@ else $as_nop then : gl_cv_func_getopt_gnu="$gl_cross_guess_normal" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -21268,11 +21557,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_getopt_gnu=yes -else $as_nop - gl_cv_func_getopt_gnu=no +else case e in #( + e) gl_cv_func_getopt_gnu=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi case $gl_had_POSIXLY_CORRECT in @@ -21280,28 +21571,29 @@ fi yes) { POSIXLY_CORRECT=; unset POSIXLY_CORRECT;}; POSIXLY_CORRECT=1 ;; *) { POSIXLY_CORRECT=; unset POSIXLY_CORRECT;} ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getopt_gnu" >&5 -printf "%s\n" "$gl_cv_func_getopt_gnu" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getopt_gnu" >&5 +printf '%s\n' "$gl_cv_func_getopt_gnu" >&6; } if test "$gl_cv_func_getopt_gnu" != yes; then gl_replace_getopt=yes else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working GNU getopt_long function" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working GNU getopt_long function" >&5 printf %s "checking for working GNU getopt_long function... " >&6; } if test ${gl_cv_func_getopt_long_gnu+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in openbsd*) gl_cv_func_getopt_long_gnu="guessing no";; *) gl_cv_func_getopt_long_gnu="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -21337,17 +21629,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_getopt_long_gnu=yes -else $as_nop - gl_cv_func_getopt_long_gnu=no +else case e in #( + e) gl_cv_func_getopt_long_gnu=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getopt_long_gnu" >&5 -printf "%s\n" "$gl_cv_func_getopt_long_gnu" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getopt_long_gnu" >&5 +printf '%s\n' "$gl_cv_func_getopt_long_gnu" >&6; } case "$gl_cv_func_getopt_long_gnu" in *yes) ;; *) gl_replace_getopt=yes ;; @@ -21394,13 +21689,13 @@ printf "%s\n" "$gl_cv_func_getopt_long_gnu" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_sys_time_h='<'sys/time.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_sys_time_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_sys_time_h = yes; then @@ -21442,10 +21737,11 @@ _ACEOF gl_cv_next_sys_time_h='<'sys/time.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_time_h" >&5 -printf "%s\n" "$gl_cv_next_sys_time_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_time_h" >&5 +printf '%s\n' "$gl_cv_next_sys_time_h" >&6; } fi NEXT_SYS_TIME_H=$gl_cv_next_sys_time_h @@ -21474,7 +21770,7 @@ printf "%s\n" "$gl_cv_next_sys_time_h" >&6; } ac_fn_c_check_header_compile "$LINENO" "winsock2.h" "ac_cv_header_winsock2_h" "$ac_includes_default" if test "x$ac_cv_header_winsock2_h" = xyes then : - printf "%s\n" "#define HAVE_WINSOCK2_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_WINSOCK2_H 1" >>confdefs.h fi @@ -21488,13 +21784,13 @@ fi fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct timeval" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for struct timeval" >&5 printf %s "checking for struct timeval... " >&6; } if test ${gl_cv_sys_struct_timeval+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_SYS_TIME_H #include @@ -21515,24 +21811,26 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_sys_struct_timeval=yes -else $as_nop - gl_cv_sys_struct_timeval=no +else case e in #( + e) gl_cv_sys_struct_timeval=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timeval" >&5 -printf "%s\n" "$gl_cv_sys_struct_timeval" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timeval" >&5 +printf '%s\n' "$gl_cv_sys_struct_timeval" >&6; } if test $gl_cv_sys_struct_timeval != yes; then HAVE_STRUCT_TIMEVAL=0 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wide-enough struct timeval.tv_sec member" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for wide-enough struct timeval.tv_sec member" >&5 printf %s "checking for wide-enough struct timeval.tv_sec member... " >&6; } if test ${gl_cv_sys_struct_timeval_tv_sec+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_SYS_TIME_H #include @@ -21557,14 +21855,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_sys_struct_timeval_tv_sec=yes -else $as_nop - gl_cv_sys_struct_timeval_tv_sec=no +else case e in #( + e) gl_cv_sys_struct_timeval_tv_sec=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timeval_tv_sec" >&5 -printf "%s\n" "$gl_cv_sys_struct_timeval_tv_sec" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timeval_tv_sec" >&5 +printf '%s\n' "$gl_cv_sys_struct_timeval_tv_sec" >&6; } if test $gl_cv_sys_struct_timeval_tv_sec != yes; then REPLACE_STRUCT_TIMEVAL=1 fi @@ -22126,13 +22426,13 @@ fi done - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 printf %s "checking for iconv... " >&6; } if test ${am_cv_func_iconv+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -22185,18 +22485,19 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$am_save_LIBS" fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 -printf "%s\n" "$am_cv_func_iconv" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 +printf '%s\n' "$am_cv_func_iconv" >&6; } if test "$am_cv_func_iconv" = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working iconv" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working iconv" >&5 printf %s "checking for working iconv... " >&6; } if test ${am_cv_func_iconv_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) am_save_LIBS="$LIBS" if test $am_cv_lib_iconv = yes; then LIBS="$LIBS $LIBICONV" @@ -22209,8 +22510,8 @@ then : aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; *) am_cv_func_iconv_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -22339,16 +22640,18 @@ then : am_cv_func_iconv_works=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi test "$am_cv_func_iconv_works" = no || break done LIBS="$am_save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv_works" >&5 -printf "%s\n" "$am_cv_func_iconv_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv_works" >&5 +printf '%s\n' "$am_cv_func_iconv_works" >&6; } case "$am_cv_func_iconv_works" in *no) am_func_iconv=no am_cv_lib_iconv=no ;; *) am_func_iconv=yes ;; @@ -22358,14 +22661,14 @@ printf "%s\n" "$am_cv_func_iconv_works" >&6; } fi if test "$am_func_iconv" = yes; then -printf "%s\n" "#define HAVE_ICONV 1" >>confdefs.h +printf '%s\n' "#define HAVE_ICONV 1" >>confdefs.h fi if test "$am_cv_lib_iconv" = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 printf %s "checking how to link with libiconv... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 -printf "%s\n" "$LIBICONV" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 +printf '%s\n' "$LIBICONV" >&6; } else CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= @@ -22375,13 +22678,13 @@ printf "%s\n" "$LIBICONV" >&6; } if test "$am_cv_func_iconv" = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether iconv is compatible with its POSIX signature" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether iconv is compatible with its POSIX signature" >&5 printf %s "checking whether iconv is compatible with its POSIX signature... " >&6; } if test ${gl_cv_iconv_nonconst+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -22403,14 +22706,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_iconv_nonconst=yes -else $as_nop - gl_cv_iconv_nonconst=no +else case e in #( + e) gl_cv_iconv_nonconst=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_iconv_nonconst" >&5 -printf "%s\n" "$gl_cv_iconv_nonconst" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_iconv_nonconst" >&5 +printf '%s\n' "$gl_cv_iconv_nonconst" >&6; } else gl_cv_iconv_nonconst=yes fi @@ -22420,7 +22725,7 @@ printf "%s\n" "$gl_cv_iconv_nonconst" >&6; } iconv_arg1="const" fi -printf "%s\n" "#define ICONV_CONST $iconv_arg1" >>confdefs.h +printf '%s\n' "#define ICONV_CONST $iconv_arg1" >>confdefs.h if test $gl_cv_iconv_nonconst != yes; then @@ -22450,13 +22755,13 @@ printf "%s\n" "#define ICONV_CONST $iconv_arg1" >>confdefs.h if test $gl_cv_have_include_next = yes; then gl_cv_next_iconv_h='<'iconv.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_iconv_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_iconv_h = yes; then @@ -22498,10 +22803,11 @@ _ACEOF gl_cv_next_iconv_h='<'iconv.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_iconv_h" >&5 -printf "%s\n" "$gl_cv_next_iconv_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_iconv_h" >&5 +printf '%s\n' "$gl_cv_next_iconv_h" >&6; } fi NEXT_ICONV_H=$gl_cv_next_iconv_h @@ -22538,13 +22844,13 @@ printf "%s\n" "$gl_cv_next_iconv_h" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_limits_h='<'limits.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_limits_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_limits_h = yes; then @@ -22586,10 +22892,11 @@ _ACEOF gl_cv_next_limits_h='<'limits.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_limits_h" >&5 -printf "%s\n" "$gl_cv_next_limits_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_limits_h" >&5 +printf '%s\n' "$gl_cv_next_limits_h" >&6; } fi NEXT_LIMITS_H=$gl_cv_next_limits_h @@ -22606,13 +22913,13 @@ printf "%s\n" "$gl_cv_next_limits_h" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether limits.h has WORD_BIT, BOOL_WIDTH etc." >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether limits.h has WORD_BIT, BOOL_WIDTH etc." >&5 printf %s "checking whether limits.h has WORD_BIT, BOOL_WIDTH etc.... " >&6; } if test ${gl_cv_header_limits_width+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __STDC_WANT_IEC_60559_BFP_EXT__ #define __STDC_WANT_IEC_60559_BFP_EXT__ 1 @@ -22634,13 +22941,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_header_limits_width=yes -else $as_nop - gl_cv_header_limits_width=no +else case e in #( + e) gl_cv_header_limits_width=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_limits_width" >&5 -printf "%s\n" "$gl_cv_header_limits_width" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_limits_width" >&5 +printf '%s\n' "$gl_cv_header_limits_width" >&6; } if test "$gl_cv_header_limits_width" = yes; then LIMITS_H= else @@ -22662,10 +22971,10 @@ fi -printf "%s\n" "#define HAVE_LONG_LONG_INT 1" >>confdefs.h +printf '%s\n' "#define HAVE_LONG_LONG_INT 1" >>confdefs.h -printf "%s\n" "#define HAVE_UNSIGNED_LONG_LONG_INT 1" >>confdefs.h +printf '%s\n' "#define HAVE_UNSIGNED_LONG_LONG_INT 1" >>confdefs.h @@ -22704,13 +23013,13 @@ printf "%s\n" "#define HAVE_UNSIGNED_LONG_LONG_INT 1" >>confdefs.h if test $gl_cv_have_include_next = yes; then gl_cv_next_stdint_h='<'stdint.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_stdint_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_stdint_h = yes; then @@ -22752,10 +23061,11 @@ _ACEOF gl_cv_next_stdint_h='<'stdint.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stdint_h" >&5 -printf "%s\n" "$gl_cv_next_stdint_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stdint_h" >&5 +printf '%s\n' "$gl_cv_next_stdint_h" >&6; } fi NEXT_STDINT_H=$gl_cv_next_stdint_h @@ -22779,13 +23089,13 @@ printf "%s\n" "$gl_cv_next_stdint_h" >&6; } if test $ac_cv_header_stdint_h = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stdint.h conforms to C99" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether stdint.h conforms to C99" >&5 printf %s "checking whether stdint.h conforms to C99... " >&6; } if test ${gl_cv_header_working_stdint_h+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_cv_header_working_stdint_h=no +else case e in #( + e) gl_cv_header_working_stdint_h=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -22967,8 +23277,8 @@ then : *) gl_cv_header_working_stdint_h="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -23046,16 +23356,18 @@ then : gl_cv_header_working_stdint_h=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_working_stdint_h" >&5 -printf "%s\n" "$gl_cv_header_working_stdint_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_working_stdint_h" >&5 +printf '%s\n' "$gl_cv_header_working_stdint_h" >&6; } fi HAVE_C99_STDINT_H=0 @@ -23065,13 +23377,13 @@ printf "%s\n" "$gl_cv_header_working_stdint_h" >&6; } case "$gl_cv_header_working_stdint_h" in *yes) HAVE_C99_STDINT_H=1 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stdint.h works without ISO C predefines" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether stdint.h works without ISO C predefines" >&5 printf %s "checking whether stdint.h works without ISO C predefines... " >&6; } if test ${gl_cv_header_stdint_without_STDC_macros+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_cv_header_stdint_without_STDC_macros=no +else case e in #( + e) gl_cv_header_stdint_without_STDC_macros=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -23103,26 +23415,27 @@ then : gl_cv_header_stdint_without_STDC_macros=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_stdint_without_STDC_macros" >&5 -printf "%s\n" "$gl_cv_header_stdint_without_STDC_macros" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_stdint_without_STDC_macros" >&5 +printf '%s\n' "$gl_cv_header_stdint_without_STDC_macros" >&6; } if test $gl_cv_header_stdint_without_STDC_macros = no; then -printf "%s\n" "#define __STDC_CONSTANT_MACROS 1" >>confdefs.h +printf '%s\n' "#define __STDC_CONSTANT_MACROS 1" >>confdefs.h -printf "%s\n" "#define __STDC_LIMIT_MACROS 1" >>confdefs.h +printf '%s\n' "#define __STDC_LIMIT_MACROS 1" >>confdefs.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stdint.h has UINTMAX_WIDTH etc." >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether stdint.h has UINTMAX_WIDTH etc." >&5 printf %s "checking whether stdint.h has UINTMAX_WIDTH etc.... " >&6; } if test ${gl_cv_header_stdint_width+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_cv_header_stdint_width=no +else case e in #( + e) gl_cv_header_stdint_width=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -23153,10 +23466,11 @@ if ac_fn_c_try_compile "$LINENO" then : gl_cv_header_stdint_width=yes fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_stdint_width" >&5 -printf "%s\n" "$gl_cv_header_stdint_width" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_stdint_width" >&5 +printf '%s\n' "$gl_cv_header_stdint_width" >&6; } if test "$gl_cv_header_stdint_width" = yes; then STDINT_H= fi @@ -23165,13 +23479,13 @@ printf "%s\n" "$gl_cv_header_stdint_width" >&6; } ac_fn_c_check_header_compile "$LINENO" "sys/inttypes.h" "ac_cv_header_sys_inttypes_h" "$ac_includes_default" if test "x$ac_cv_header_sys_inttypes_h" = xyes then : - printf "%s\n" "#define HAVE_SYS_INTTYPES_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_SYS_INTTYPES_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "sys/bitypes.h" "ac_cv_header_sys_bitypes_h" "$ac_includes_default" if test "x$ac_cv_header_sys_bitypes_h" = xyes then : - printf "%s\n" "#define HAVE_SYS_BITYPES_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_SYS_BITYPES_H 1" >>confdefs.h fi @@ -23187,13 +23501,13 @@ fi for gltype in ptrdiff_t size_t ; do - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for bit size of $gltype" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for bit size of $gltype" >&5 printf %s "checking for bit size of $gltype... " >&6; } if eval test \${gl_cv_bitsizeof_${gltype}+y} then : printf %s "(cached) " >&6 -else $as_nop - if ac_fn_c_compute_int "$LINENO" "sizeof ($gltype) * CHAR_BIT" "result" " +else case e in #( + e) if ac_fn_c_compute_int "$LINENO" "sizeof ($gltype) * CHAR_BIT" "result" " #include #include #if HAVE_WCHAR_H @@ -23203,22 +23517,26 @@ else $as_nop #include " then : -else $as_nop - result=unknown +else case e in #( + e) result=unknown ;; +esac fi eval gl_cv_bitsizeof_${gltype}=\$result - + ;; +esac fi eval ac_res=\$gl_cv_bitsizeof_${gltype} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } eval result=\$gl_cv_bitsizeof_${gltype} if test $result = unknown; then result=0 fi GLTYPE=`echo "$gltype" | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'` - printf "%s\n" "#define BITSIZEOF_${GLTYPE} $result" >>confdefs.h + cat >>confdefs.h <<_ACEOF +#define BITSIZEOF_${GLTYPE} $result +_ACEOF eval BITSIZEOF_${GLTYPE}=\$result done @@ -23228,13 +23546,13 @@ printf "%s\n" "$ac_res" >&6; } for gltype in sig_atomic_t wchar_t wint_t ; do - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for bit size of $gltype" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for bit size of $gltype" >&5 printf %s "checking for bit size of $gltype... " >&6; } if eval test \${gl_cv_bitsizeof_${gltype}+y} then : printf %s "(cached) " >&6 -else $as_nop - if ac_fn_c_compute_int "$LINENO" "sizeof ($gltype) * CHAR_BIT" "result" " +else case e in #( + e) if ac_fn_c_compute_int "$LINENO" "sizeof ($gltype) * CHAR_BIT" "result" " #include #include #if HAVE_WCHAR_H @@ -23244,22 +23562,26 @@ else $as_nop #include " then : -else $as_nop - result=unknown +else case e in #( + e) result=unknown ;; +esac fi eval gl_cv_bitsizeof_${gltype}=\$result - + ;; +esac fi eval ac_res=\$gl_cv_bitsizeof_${gltype} - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } eval result=\$gl_cv_bitsizeof_${gltype} if test $result = unknown; then result=0 fi GLTYPE=`echo "$gltype" | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'` - printf "%s\n" "#define BITSIZEOF_${GLTYPE} $result" >>confdefs.h + cat >>confdefs.h <<_ACEOF +#define BITSIZEOF_${GLTYPE} $result +_ACEOF eval BITSIZEOF_${GLTYPE}=\$result done @@ -23268,13 +23590,13 @@ printf "%s\n" "$ac_res" >&6; } for gltype in sig_atomic_t wchar_t wint_t ; do - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $gltype is signed" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether $gltype is signed" >&5 printf %s "checking whether $gltype is signed... " >&6; } if eval test \${gl_cv_type_${gltype}_signed+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -23295,20 +23617,24 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : result=yes -else $as_nop - result=no +else case e in #( + e) result=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval gl_cv_type_${gltype}_signed=\$result - + ;; +esac fi eval ac_res=\$gl_cv_type_${gltype}_signed - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } eval result=\$gl_cv_type_${gltype}_signed GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'` if test "$result" = yes; then - printf "%s\n" "#define HAVE_SIGNED_${GLTYPE} 1" >>confdefs.h + cat >>confdefs.h <<_ACEOF +#define HAVE_SIGNED_${GLTYPE} 1 +_ACEOF eval HAVE_SIGNED_${GLTYPE}=1 else @@ -23323,13 +23649,13 @@ printf "%s\n" "$ac_res" >&6; } for gltype in ptrdiff_t size_t ; do - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $gltype integer literal suffix" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $gltype integer literal suffix" >&5 printf %s "checking for $gltype integer literal suffix... " >&6; } if eval test \${gl_cv_type_${gltype}_suffix+y} then : printf %s "(cached) " >&6 -else $as_nop - eval gl_cv_type_${gltype}_suffix=no +else case e in #( + e) eval gl_cv_type_${gltype}_suffix=no eval result=\$gl_cv_type_${gltype}_signed if test "$result" = yes; then glsufu= @@ -23373,16 +23699,19 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval result=\$gl_cv_type_${gltype}_suffix test "$result" != no && break - done + done ;; +esac fi eval ac_res=\$gl_cv_type_${gltype}_suffix - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'` eval result=\$gl_cv_type_${gltype}_suffix test "$result" = no && result= eval ${GLTYPE}_SUFFIX=\$result - printf "%s\n" "#define ${GLTYPE}_SUFFIX $result" >>confdefs.h + cat >>confdefs.h <<_ACEOF +#define ${GLTYPE}_SUFFIX $result +_ACEOF done @@ -23391,13 +23720,13 @@ printf "%s\n" "$ac_res" >&6; } for gltype in sig_atomic_t wchar_t wint_t ; do - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $gltype integer literal suffix" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $gltype integer literal suffix" >&5 printf %s "checking for $gltype integer literal suffix... " >&6; } if eval test \${gl_cv_type_${gltype}_suffix+y} then : printf %s "(cached) " >&6 -else $as_nop - eval gl_cv_type_${gltype}_suffix=no +else case e in #( + e) eval gl_cv_type_${gltype}_suffix=no eval result=\$gl_cv_type_${gltype}_signed if test "$result" = yes; then glsufu= @@ -23441,16 +23770,19 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext eval result=\$gl_cv_type_${gltype}_suffix test "$result" != no && break - done + done ;; +esac fi eval ac_res=\$gl_cv_type_${gltype}_suffix - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } GLTYPE=`echo $gltype | tr 'abcdefghijklmnopqrstuvwxyz ' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ_'` eval result=\$gl_cv_type_${gltype}_suffix test "$result" = no && result= eval ${GLTYPE}_SUFFIX=\$result - printf "%s\n" "#define ${GLTYPE}_SUFFIX $result" >>confdefs.h + cat >>confdefs.h <<_ACEOF +#define ${GLTYPE}_SUFFIX $result +_ACEOF done @@ -23520,13 +23852,13 @@ fi if test $gl_cv_have_include_next = yes; then gl_cv_next_inttypes_h='<'inttypes.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_inttypes_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_inttypes_h = yes; then @@ -23568,10 +23900,11 @@ _ACEOF gl_cv_next_inttypes_h='<'inttypes.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_inttypes_h" >&5 -printf "%s\n" "$gl_cv_next_inttypes_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_inttypes_h" >&5 +printf '%s\n' "$gl_cv_next_inttypes_h" >&6; } fi NEXT_INTTYPES_H=$gl_cv_next_inttypes_h @@ -23620,8 +23953,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : PRIPTR_PREFIX='"l"' -else $as_nop - PRIPTR_PREFIX='"ll"' +else case e in #( + e) PRIPTR_PREFIX='"ll"' ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext else @@ -23656,13 +23990,13 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether INT32_MAX < INTMAX_MAX" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether INT32_MAX < INTMAX_MAX" >&5 printf %s "checking whether INT32_MAX < INTMAX_MAX... " >&6; } if test ${gl_cv_test_INT32_MAX_LT_INTMAX_MAX+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Work also in C++ mode. */ #define __STDC_LIMIT_MACROS 1 @@ -23692,13 +24026,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_test_INT32_MAX_LT_INTMAX_MAX=yes -else $as_nop - gl_cv_test_INT32_MAX_LT_INTMAX_MAX=no +else case e in #( + e) gl_cv_test_INT32_MAX_LT_INTMAX_MAX=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_test_INT32_MAX_LT_INTMAX_MAX" >&5 -printf "%s\n" "$gl_cv_test_INT32_MAX_LT_INTMAX_MAX" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_test_INT32_MAX_LT_INTMAX_MAX" >&5 +printf '%s\n' "$gl_cv_test_INT32_MAX_LT_INTMAX_MAX" >&6; } if test $gl_cv_test_INT32_MAX_LT_INTMAX_MAX = yes; then INT32_MAX_LT_INTMAX_MAX=1; else @@ -23708,13 +24044,13 @@ printf "%s\n" "$gl_cv_test_INT32_MAX_LT_INTMAX_MAX" >&6; } if test $APPLE_UNIVERSAL_BUILD = 0; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether INT64_MAX == LONG_MAX" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether INT64_MAX == LONG_MAX" >&5 printf %s "checking whether INT64_MAX == LONG_MAX... " >&6; } if test ${gl_cv_test_INT64_MAX_EQ_LONG_MAX+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Work also in C++ mode. */ #define __STDC_LIMIT_MACROS 1 @@ -23744,13 +24080,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_test_INT64_MAX_EQ_LONG_MAX=yes -else $as_nop - gl_cv_test_INT64_MAX_EQ_LONG_MAX=no +else case e in #( + e) gl_cv_test_INT64_MAX_EQ_LONG_MAX=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_test_INT64_MAX_EQ_LONG_MAX" >&5 -printf "%s\n" "$gl_cv_test_INT64_MAX_EQ_LONG_MAX" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_test_INT64_MAX_EQ_LONG_MAX" >&5 +printf '%s\n' "$gl_cv_test_INT64_MAX_EQ_LONG_MAX" >&6; } if test $gl_cv_test_INT64_MAX_EQ_LONG_MAX = yes; then INT64_MAX_EQ_LONG_MAX=1; else @@ -23762,13 +24100,13 @@ printf "%s\n" "$gl_cv_test_INT64_MAX_EQ_LONG_MAX" >&6; } INT64_MAX_EQ_LONG_MAX=-1 fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether UINT32_MAX < UINTMAX_MAX" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether UINT32_MAX < UINTMAX_MAX" >&5 printf %s "checking whether UINT32_MAX < UINTMAX_MAX... " >&6; } if test ${gl_cv_test_UINT32_MAX_LT_UINTMAX_MAX+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Work also in C++ mode. */ #define __STDC_LIMIT_MACROS 1 @@ -23798,13 +24136,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_test_UINT32_MAX_LT_UINTMAX_MAX=yes -else $as_nop - gl_cv_test_UINT32_MAX_LT_UINTMAX_MAX=no +else case e in #( + e) gl_cv_test_UINT32_MAX_LT_UINTMAX_MAX=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_test_UINT32_MAX_LT_UINTMAX_MAX" >&5 -printf "%s\n" "$gl_cv_test_UINT32_MAX_LT_UINTMAX_MAX" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_test_UINT32_MAX_LT_UINTMAX_MAX" >&5 +printf '%s\n' "$gl_cv_test_UINT32_MAX_LT_UINTMAX_MAX" >&6; } if test $gl_cv_test_UINT32_MAX_LT_UINTMAX_MAX = yes; then UINT32_MAX_LT_UINTMAX_MAX=1; else @@ -23814,13 +24154,13 @@ printf "%s\n" "$gl_cv_test_UINT32_MAX_LT_UINTMAX_MAX" >&6; } if test $APPLE_UNIVERSAL_BUILD = 0; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether UINT64_MAX == ULONG_MAX" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether UINT64_MAX == ULONG_MAX" >&5 printf %s "checking whether UINT64_MAX == ULONG_MAX... " >&6; } if test ${gl_cv_test_UINT64_MAX_EQ_ULONG_MAX+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Work also in C++ mode. */ #define __STDC_LIMIT_MACROS 1 @@ -23850,13 +24190,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_test_UINT64_MAX_EQ_ULONG_MAX=yes -else $as_nop - gl_cv_test_UINT64_MAX_EQ_ULONG_MAX=no +else case e in #( + e) gl_cv_test_UINT64_MAX_EQ_ULONG_MAX=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_test_UINT64_MAX_EQ_ULONG_MAX" >&5 -printf "%s\n" "$gl_cv_test_UINT64_MAX_EQ_ULONG_MAX" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_test_UINT64_MAX_EQ_ULONG_MAX" >&5 +printf '%s\n' "$gl_cv_test_UINT64_MAX_EQ_ULONG_MAX" >&6; } if test $gl_cv_test_UINT64_MAX_EQ_ULONG_MAX = yes; then UINT64_MAX_EQ_ULONG_MAX=1; else @@ -23888,18 +24230,18 @@ printf "%s\n" "$gl_cv_test_UINT64_MAX_EQ_ULONG_MAX" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'float'" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'float'" >&5 printf %s "checking where to find the exponent in a 'float'... " >&6; } if test ${gl_cv_cc_float_expbit0+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : gl_cv_cc_float_expbit0="word 0 bit 23" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -23970,27 +24312,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_cc_float_expbit0=`cat conftest.out` -else $as_nop - gl_cv_cc_float_expbit0="unknown" +else case e in #( + e) gl_cv_cc_float_expbit0="unknown" ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.out - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_float_expbit0" >&5 -printf "%s\n" "$gl_cv_cc_float_expbit0" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_float_expbit0" >&5 +printf '%s\n' "$gl_cv_cc_float_expbit0" >&6; } case "$gl_cv_cc_float_expbit0" in word*bit*) word=`echo "$gl_cv_cc_float_expbit0" | sed -e 's/word //' -e 's/ bit.*//'` bit=`echo "$gl_cv_cc_float_expbit0" | sed -e 's/word.*bit //'` -printf "%s\n" "#define FLT_EXPBIT0_WORD $word" >>confdefs.h +printf '%s\n' "#define FLT_EXPBIT0_WORD $word" >>confdefs.h -printf "%s\n" "#define FLT_EXPBIT0_BIT $bit" >>confdefs.h +printf '%s\n' "#define FLT_EXPBIT0_BIT $bit" >>confdefs.h ;; esac @@ -23999,13 +24344,13 @@ printf "%s\n" "#define FLT_EXPBIT0_BIT $bit" >>confdefs.h ISNANF_LIBM= - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) can be used without linking with libm" >&5 printf %s "checking whether isnan(float) can be used without linking with libm... " >&6; } if test ${gl_cv_func_isnanf_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -24028,25 +24373,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnanf_no_libm=yes -else $as_nop - gl_cv_func_isnanf_no_libm=no +else case e in #( + e) gl_cv_func_isnanf_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_no_libm" >&5 -printf "%s\n" "$gl_cv_func_isnanf_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_no_libm" >&5 +printf '%s\n' "$gl_cv_func_isnanf_no_libm" >&6; } if test $gl_cv_func_isnanf_no_libm = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) can be used with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) can be used with libm" >&5 printf %s "checking whether isnan(float) can be used with libm... " >&6; } if test ${gl_cv_func_isnanf_in_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) save_LIBS="$LIBS" LIBS="$LIBS -lm" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -24071,16 +24418,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnanf_in_libm=yes -else $as_nop - gl_cv_func_isnanf_in_libm=no +else case e in #( + e) gl_cv_func_isnanf_in_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_in_libm" >&5 -printf "%s\n" "$gl_cv_func_isnanf_in_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_in_libm" >&5 +printf '%s\n' "$gl_cv_func_isnanf_in_libm" >&6; } if test $gl_cv_func_isnanf_in_libm = yes; then ISNANF_LIBM=-lm @@ -24093,13 +24442,13 @@ printf "%s\n" "$gl_cv_func_isnanf_in_libm" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) works" >&5 printf %s "checking whether isnan(float) works... " >&6; } if test ${gl_cv_func_isnanf_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -24114,11 +24463,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_isnanf_works="guessing yes" -else $as_nop - gl_cv_func_isnanf_works="guessing no" +else case e in #( + e) gl_cv_func_isnanf_works="guessing no" ;; +esac fi rm -rf conftest* @@ -24126,8 +24476,8 @@ rm -rf conftest* *) gl_cv_func_isnanf_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -24185,17 +24535,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_isnanf_works=yes -else $as_nop - gl_cv_func_isnanf_works=no +else case e in #( + e) gl_cv_func_isnanf_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_works" >&5 -printf "%s\n" "$gl_cv_func_isnanf_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_works" >&5 +printf '%s\n' "$gl_cv_func_isnanf_works" >&6; } LIBS="$save_LIBS" case "$gl_cv_func_isnanf_works" in @@ -24214,13 +24567,13 @@ printf "%s\n" "$gl_cv_func_isnanf_works" >&6; } ISNAND_LIBM= - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(double) can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(double) can be used without linking with libm" >&5 printf %s "checking whether isnan(double) can be used without linking with libm... " >&6; } if test ${gl_cv_func_isnand_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -24243,25 +24596,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnand_no_libm=yes -else $as_nop - gl_cv_func_isnand_no_libm=no +else case e in #( + e) gl_cv_func_isnand_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnand_no_libm" >&5 -printf "%s\n" "$gl_cv_func_isnand_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnand_no_libm" >&5 +printf '%s\n' "$gl_cv_func_isnand_no_libm" >&6; } if test $gl_cv_func_isnand_no_libm = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(double) can be used with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(double) can be used with libm" >&5 printf %s "checking whether isnan(double) can be used with libm... " >&6; } if test ${gl_cv_func_isnand_in_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) save_LIBS="$LIBS" LIBS="$LIBS -lm" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -24286,16 +24641,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnand_in_libm=yes -else $as_nop - gl_cv_func_isnand_in_libm=no +else case e in #( + e) gl_cv_func_isnand_in_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnand_in_libm" >&5 -printf "%s\n" "$gl_cv_func_isnand_in_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnand_in_libm" >&5 +printf '%s\n' "$gl_cv_func_isnand_in_libm" >&6; } if test $gl_cv_func_isnand_in_libm = yes; then ISNAND_LIBM=-lm @@ -24314,13 +24671,13 @@ printf "%s\n" "$gl_cv_func_isnand_in_libm" >&6; } ISNANL_LIBM= - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(long double) can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(long double) can be used without linking with libm" >&5 printf %s "checking whether isnan(long double) can be used without linking with libm... " >&6; } if test ${gl_cv_func_isnanl_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -24343,25 +24700,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnanl_no_libm=yes -else $as_nop - gl_cv_func_isnanl_no_libm=no +else case e in #( + e) gl_cv_func_isnanl_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_no_libm" >&5 -printf "%s\n" "$gl_cv_func_isnanl_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_no_libm" >&5 +printf '%s\n' "$gl_cv_func_isnanl_no_libm" >&6; } if test $gl_cv_func_isnanl_no_libm = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(long double) can be used with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(long double) can be used with libm" >&5 printf %s "checking whether isnan(long double) can be used with libm... " >&6; } if test ${gl_cv_func_isnanl_in_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) save_LIBS="$LIBS" LIBS="$LIBS -lm" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -24386,16 +24745,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnanl_in_libm=yes -else $as_nop - gl_cv_func_isnanl_in_libm=no +else case e in #( + e) gl_cv_func_isnanl_in_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_in_libm" >&5 -printf "%s\n" "$gl_cv_func_isnanl_in_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_in_libm" >&5 +printf '%s\n' "$gl_cv_func_isnanl_in_libm" >&6; } if test $gl_cv_func_isnanl_in_libm = yes; then ISNANL_LIBM=-lm @@ -24409,13 +24770,13 @@ printf "%s\n" "$gl_cv_func_isnanl_in_libm" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnanl works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnanl works" >&5 printf %s "checking whether isnanl works... " >&6; } if test ${gl_cv_func_isnanl_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -24429,11 +24790,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_isnanl_works="guessing yes" -else $as_nop - gl_cv_func_isnanl_works="guessing no" +else case e in #( + e) gl_cv_func_isnanl_works="guessing no" ;; +esac fi rm -rf conftest* @@ -24441,8 +24803,8 @@ rm -rf conftest* *) gl_cv_func_isnanl_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -24558,17 +24920,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_isnanl_works=yes -else $as_nop - gl_cv_func_isnanl_works=no +else case e in #( + e) gl_cv_func_isnanl_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_works" >&5 -printf "%s\n" "$gl_cv_func_isnanl_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_works" >&5 +printf '%s\n' "$gl_cv_func_isnanl_works" >&6; } LIBS="$save_LIBS" case "$gl_cv_func_isnanl_works" in @@ -24637,13 +25002,13 @@ printf "%s\n" "$gl_cv_func_isnanl_works" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_wctype_h='<'wctype.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_wctype_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_wctype_h = yes; then @@ -24685,10 +25050,11 @@ _ACEOF gl_cv_next_wctype_h='<'wctype.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_wctype_h" >&5 -printf "%s\n" "$gl_cv_next_wctype_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_wctype_h" >&5 +printf '%s\n' "$gl_cv_next_wctype_h" >&6; } fi NEXT_WCTYPE_H=$gl_cv_next_wctype_h @@ -24706,13 +25072,13 @@ printf "%s\n" "$gl_cv_next_wctype_h" >&6; } if test $ac_cv_header_wctype_h = yes; then if test $ac_cv_func_iswcntrl = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether iswcntrl works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether iswcntrl works" >&5 printf %s "checking whether iswcntrl works... " >&6; } if test ${gl_cv_func_iswcntrl_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -24732,13 +25098,14 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_iswcntrl_works="guessing yes" -else $as_nop - gl_cv_func_iswcntrl_works="guessing no" +else case e in #( + e) gl_cv_func_iswcntrl_works="guessing no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -24749,17 +25116,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_iswcntrl_works=yes -else $as_nop - gl_cv_func_iswcntrl_works=no +else case e in #( + e) gl_cv_func_iswcntrl_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_iswcntrl_works" >&5 -printf "%s\n" "$gl_cv_func_iswcntrl_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_iswcntrl_works" >&5 +printf '%s\n' "$gl_cv_func_iswcntrl_works" >&6; } fi HAVE_WCTYPE_H=1 else @@ -24787,7 +25157,7 @@ printf "%s\n" "$gl_cv_func_iswcntrl_works" >&6; } ac_fn_c_check_func "$LINENO" "towlower" "ac_cv_func_towlower" if test "x$ac_cv_func_towlower" = xyes then : - printf "%s\n" "#define HAVE_TOWLOWER 1" >>confdefs.h + printf '%s\n' "#define HAVE_TOWLOWER 1" >>confdefs.h fi @@ -24799,14 +25169,15 @@ fi # include #endif -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_towlower" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_TOWLOWER $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_TOWLOWER $ac_have_decl" >>confdefs.h if test $ac_cv_have_decl_towlower = yes; then REPLACE_TOWLOWER=1 @@ -24821,13 +25192,13 @@ printf "%s\n" "#define HAVE_DECL_TOWLOWER $ac_have_decl" >>confdefs.h : fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wctype_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for wctype_t" >&5 printf %s "checking for wctype_t... " >&6; } if test ${gl_cv_type_wctype_t+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #if HAVE_WCTYPE_H @@ -24846,25 +25217,27 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_type_wctype_t=yes -else $as_nop - gl_cv_type_wctype_t=no +else case e in #( + e) gl_cv_type_wctype_t=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_wctype_t" >&5 -printf "%s\n" "$gl_cv_type_wctype_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_wctype_t" >&5 +printf '%s\n' "$gl_cv_type_wctype_t" >&6; } if test $gl_cv_type_wctype_t = no; then HAVE_WCTYPE_T=0 fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wctrans_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for wctrans_t" >&5 printf %s "checking for wctrans_t... " >&6; } if test ${gl_cv_type_wctrans_t+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -24881,14 +25254,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_type_wctrans_t=yes -else $as_nop - gl_cv_type_wctrans_t=no +else case e in #( + e) gl_cv_type_wctrans_t=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_wctrans_t" >&5 -printf "%s\n" "$gl_cv_type_wctrans_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_wctrans_t" >&5 +printf '%s\n' "$gl_cv_type_wctrans_t" >&6; } if test $gl_cv_type_wctrans_t = no; then HAVE_WCTRANS_T=0 fi @@ -24929,13 +25304,13 @@ printf "%s\n" "$gl_cv_type_wctrans_t" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo and CODESET" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo and CODESET" >&5 printf %s "checking for nl_langinfo and CODESET... " >&6; } if test ${am_cv_langinfo_codeset+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -24949,31 +25324,33 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : am_cv_langinfo_codeset=yes -else $as_nop - am_cv_langinfo_codeset=no +else case e in #( + e) am_cv_langinfo_codeset=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_langinfo_codeset" >&5 -printf "%s\n" "$am_cv_langinfo_codeset" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_langinfo_codeset" >&5 +printf '%s\n' "$am_cv_langinfo_codeset" >&6; } if test $am_cv_langinfo_codeset = yes; then -printf "%s\n" "#define HAVE_LANGINFO_CODESET 1" >>confdefs.h +printf '%s\n' "#define HAVE_LANGINFO_CODESET 1" >>confdefs.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a traditional french locale" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a traditional french locale" >&5 printf %s "checking for a traditional french locale... " >&6; } if test ${gt_cv_locale_fr+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -25046,7 +25423,7 @@ _ACEOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest$ac_exeext; then case "$host_os" in # Handle native Windows specially, because there setlocale() interprets @@ -25100,23 +25477,24 @@ _ACEOF esac fi rm -fr conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_locale_fr" >&5 -printf "%s\n" "$gt_cv_locale_fr" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_locale_fr" >&5 +printf '%s\n' "$gt_cv_locale_fr" >&6; } LOCALE_FR=$gt_cv_locale_fr - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a traditional japanese locale" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a traditional japanese locale" >&5 printf %s "checking for a traditional japanese locale... " >&6; } if test ${gt_cv_locale_ja+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -25193,7 +25571,7 @@ _ACEOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest$ac_exeext; then case "$host_os" in # Handle native Windows specially, because there setlocale() interprets @@ -25249,22 +25627,23 @@ _ACEOF esac fi rm -fr conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_locale_ja" >&5 -printf "%s\n" "$gt_cv_locale_ja" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_locale_ja" >&5 +printf '%s\n' "$gt_cv_locale_ja" >&6; } LOCALE_JA=$gt_cv_locale_ja - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a french Unicode locale" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a french Unicode locale" >&5 printf %s "checking for a french Unicode locale... " >&6; } if test ${gt_cv_locale_fr_utf8+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -25334,7 +25713,7 @@ _ACEOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest$ac_exeext; then case "$host_os" in # Handle native Windows specially, because there setlocale() interprets @@ -25378,23 +25757,24 @@ _ACEOF esac fi rm -fr conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_locale_fr_utf8" >&5 -printf "%s\n" "$gt_cv_locale_fr_utf8" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_locale_fr_utf8" >&5 +printf '%s\n' "$gt_cv_locale_fr_utf8" >&6; } LOCALE_FR_UTF8=$gt_cv_locale_fr_utf8 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a transitional chinese locale" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a transitional chinese locale" >&5 printf %s "checking for a transitional chinese locale... " >&6; } if test ${gt_cv_locale_zh_CN+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -25472,7 +25852,7 @@ _ACEOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest$ac_exeext; then case "$host_os" in # Handle native Windows specially, because there setlocale() interprets @@ -25521,10 +25901,11 @@ _ACEOF gt_cv_locale_zh_CN=none fi rm -fr conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_locale_zh_CN" >&5 -printf "%s\n" "$gt_cv_locale_zh_CN" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_locale_zh_CN" >&5 +printf '%s\n' "$gt_cv_locale_zh_CN" >&6; } LOCALE_ZH_CN=$gt_cv_locale_zh_CN @@ -25532,13 +25913,13 @@ printf "%s\n" "$gt_cv_locale_zh_CN" >&6; } case "$host_os" in mingw*) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit off_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for 64-bit off_t" >&5 printf %s "checking for 64-bit off_t... " >&6; } if test ${gl_cv_type_off_t_64+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int verify_off_t_size[sizeof (off_t) >= 8 ? 1 : -1]; @@ -25554,26 +25935,28 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_type_off_t_64=yes -else $as_nop - gl_cv_type_off_t_64=no +else case e in #( + e) gl_cv_type_off_t_64=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_off_t_64" >&5 -printf "%s\n" "$gl_cv_type_off_t_64" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_off_t_64" >&5 +printf '%s\n' "$gl_cv_type_off_t_64" >&6; } if test $gl_cv_type_off_t_64 = no; then WINDOWS_64_BIT_OFF_T=1 else WINDOWS_64_BIT_OFF_T=0 fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for 64-bit st_size" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for 64-bit st_size" >&5 printf %s "checking for 64-bit st_size... " >&6; } if test ${gl_cv_member_st_size_64+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include struct stat buf; @@ -25590,14 +25973,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_member_st_size_64=yes -else $as_nop - gl_cv_member_st_size_64=no +else case e in #( + e) gl_cv_member_st_size_64=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_member_st_size_64" >&5 -printf "%s\n" "$gl_cv_member_st_size_64" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_member_st_size_64" >&5 +printf '%s\n' "$gl_cv_member_st_size_64" >&6; } if test $gl_cv_member_st_size_64 = no; then WINDOWS_64_BIT_ST_SIZE=1 else @@ -25611,13 +25996,13 @@ printf "%s\n" "$gl_cv_member_st_size_64" >&6; } esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ldexp() can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ldexp() can be used without linking with libm" >&5 printf %s "checking whether ldexp() can be used without linking with libm... " >&6; } if test ${gl_cv_func_ldexp_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __NO_MATH_INLINES @@ -25637,27 +26022,29 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_ldexp_no_libm=yes -else $as_nop - gl_cv_func_ldexp_no_libm=no +else case e in #( + e) gl_cv_func_ldexp_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexp_no_libm" >&5 -printf "%s\n" "$gl_cv_func_ldexp_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexp_no_libm" >&5 +printf '%s\n' "$gl_cv_func_ldexp_no_libm" >&6; } LDEXP_LIBM= if test $gl_cv_func_ldexp_no_libm = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ldexp() can be used with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ldexp() can be used with libm" >&5 printf %s "checking whether ldexp() can be used with libm... " >&6; } if test ${gl_cv_func_ldexp_in_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) save_LIBS="$LIBS" LIBS="$LIBS -lm" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -25679,16 +26066,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_ldexp_in_libm=yes -else $as_nop - gl_cv_func_ldexp_in_libm=no +else case e in #( + e) gl_cv_func_ldexp_in_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexp_in_libm" >&5 -printf "%s\n" "$gl_cv_func_ldexp_in_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexp_in_libm" >&5 +printf '%s\n' "$gl_cv_func_ldexp_in_libm" >&6; } if test $gl_cv_func_ldexp_in_libm = yes; then LDEXP_LIBM=-lm fi @@ -25706,13 +26095,13 @@ printf "%s\n" "$gl_cv_func_ldexp_in_libm" >&6; } if test "$gl_use_threads" != no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether imported symbols can be declared weak" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether imported symbols can be declared weak" >&5 printf %s "checking whether imported symbols can be declared weak... " >&6; } if test ${gl_cv_have_weak+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in cygwin*) gl_cv_have_weak="guessing no" ;; @@ -25747,17 +26136,18 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Extensible Linking Format" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Extensible Linking Format" >/dev/null 2>&1 then : gl_cv_have_weak="guessing yes" -else $as_nop - gl_cv_have_weak="guessing no" +else case e in #( + e) gl_cv_have_weak="guessing no" ;; +esac fi rm -rf conftest* -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -25770,11 +26160,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_have_weak=yes -else $as_nop - gl_cv_have_weak=no +else case e in #( + e) gl_cv_have_weak=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi @@ -25804,14 +26196,15 @@ EOF esac ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_weak" >&5 -printf "%s\n" "$gl_cv_have_weak" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_weak" >&5 +printf '%s\n' "$gl_cv_have_weak" >&6; } case "$gl_cv_have_weak" in *yes) -printf "%s\n" "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h +printf '%s\n' "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h ;; esac @@ -25839,8 +26232,9 @@ printf "%s\n" "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h if test "x$ac_cv_header_pthread_h" = xyes then : gl_have_pthread_h=yes -else $as_nop - gl_have_pthread_h=no +else case e in #( + e) gl_have_pthread_h=no ;; +esac fi if test "$gl_have_pthread_h" = yes; then @@ -25883,8 +26277,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ LIBS=$save_LIBS test $gl_pthread_api = yes && break done - echo "$as_me:25886: gl_pthread_api=$gl_pthread_api" >&5 - echo "$as_me:25887: LIBPTHREAD=$LIBPTHREAD" >&5 + echo "$as_me:26280: gl_pthread_api=$gl_pthread_api" >&5 + echo "$as_me:26281: LIBPTHREAD=$LIBPTHREAD" >&5 gl_pthread_in_glibc=no # On Linux with glibc >= 2.34, libc contains the fully functional @@ -25902,7 +26296,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Lucky user" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Lucky user" >/dev/null 2>&1 then : gl_pthread_in_glibc=yes fi @@ -25910,28 +26304,34 @@ rm -rf conftest* ;; esac - echo "$as_me:25913: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 + echo "$as_me:26307: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 # Test for libpthread by looking for pthread_kill. (Not pthread_self, # since it is defined as a macro on OSF/1.) if test $gl_pthread_api = yes && test -z "$LIBPTHREAD"; then # The program links fine without libpthread. But it may actually # need to link with libpthread in order to create multiple threads. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 printf %s "checking for pthread_kill in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_kill+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pthread_kill (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_kill (void); int main (void) { @@ -25943,15 +26343,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_kill=yes -else $as_nop - ac_cv_lib_pthread_pthread_kill=no +else case e in #( + e) ac_cv_lib_pthread_pthread_kill=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 -printf "%s\n" "$ac_cv_lib_pthread_pthread_kill" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 +printf '%s\n' "$ac_cv_lib_pthread_pthread_kill" >&6; } if test "x$ac_cv_lib_pthread_pthread_kill" = xyes then : if test $gl_pthread_in_glibc = yes; then @@ -25967,7 +26369,7 @@ then : case "$host_os" in solaris | solaris2.1-9 | solaris2.1-9.* | hpux*) -printf "%s\n" "#define PTHREAD_IN_USE_DETECTION_HARD 1" >>confdefs.h +printf '%s\n' "#define PTHREAD_IN_USE_DETECTION_HARD 1" >>confdefs.h esac fi @@ -25976,21 +26378,27 @@ fi elif test $gl_pthread_api != yes; then # Some library is needed. Try libpthread and libc_r. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 printf %s "checking for pthread_kill in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_kill+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pthread_kill (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_kill (void); int main (void) { @@ -26002,15 +26410,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_kill=yes -else $as_nop - ac_cv_lib_pthread_pthread_kill=no +else case e in #( + e) ac_cv_lib_pthread_pthread_kill=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 -printf "%s\n" "$ac_cv_lib_pthread_pthread_kill" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 +printf '%s\n' "$ac_cv_lib_pthread_pthread_kill" >&6; } if test "x$ac_cv_lib_pthread_pthread_kill" = xyes then : gl_pthread_api=yes @@ -26020,21 +26430,27 @@ fi if test $gl_pthread_api != yes; then # For FreeBSD 4. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lc_r" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lc_r" >&5 printf %s "checking for pthread_kill in -lc_r... " >&6; } if test ${ac_cv_lib_c_r_pthread_kill+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pthread_kill (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_kill (void); int main (void) { @@ -26046,15 +26462,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_c_r_pthread_kill=yes -else $as_nop - ac_cv_lib_c_r_pthread_kill=no +else case e in #( + e) ac_cv_lib_c_r_pthread_kill=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_kill" >&5 -printf "%s\n" "$ac_cv_lib_c_r_pthread_kill" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_kill" >&5 +printf '%s\n' "$ac_cv_lib_c_r_pthread_kill" >&6; } if test "x$ac_cv_lib_c_r_pthread_kill" = xyes then : gl_pthread_api=yes @@ -26064,17 +26482,17 @@ fi fi fi - echo "$as_me:26067: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 + echo "$as_me:26485: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5 printf %s "checking whether POSIX threads API is available... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_pthread_api" >&5 -printf "%s\n" "$gl_pthread_api" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_pthread_api" >&5 +printf '%s\n' "$gl_pthread_api" >&6; } if test $gl_pthread_api = yes; then -printf "%s\n" "#define HAVE_PTHREAD_API 1" >>confdefs.h +printf '%s\n' "#define HAVE_PTHREAD_API 1" >>confdefs.h fi @@ -26093,22 +26511,28 @@ if ac_fn_c_try_link "$LINENO" then : LIB_SCHED_YIELD= -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lrt" >&5 +else case e in #( + e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lrt" >&5 printf %s "checking for sched_yield in -lrt... " >&6; } if test ${ac_cv_lib_rt_sched_yield+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sched_yield (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char sched_yield (void); int main (void) { @@ -26120,34 +26544,42 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_rt_sched_yield=yes -else $as_nop - ac_cv_lib_rt_sched_yield=no +else case e in #( + e) ac_cv_lib_rt_sched_yield=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_sched_yield" >&5 -printf "%s\n" "$ac_cv_lib_rt_sched_yield" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_sched_yield" >&5 +printf '%s\n' "$ac_cv_lib_rt_sched_yield" >&6; } if test "x$ac_cv_lib_rt_sched_yield" = xyes then : LIB_SCHED_YIELD=-lrt -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lposix4" >&5 +else case e in #( + e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lposix4" >&5 printf %s "checking for sched_yield in -lposix4... " >&6; } if test ${ac_cv_lib_posix4_sched_yield+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lposix4 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sched_yield (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char sched_yield (void); int main (void) { @@ -26159,23 +26591,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_posix4_sched_yield=yes -else $as_nop - ac_cv_lib_posix4_sched_yield=no +else case e in #( + e) ac_cv_lib_posix4_sched_yield=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix4_sched_yield" >&5 -printf "%s\n" "$ac_cv_lib_posix4_sched_yield" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix4_sched_yield" >&5 +printf '%s\n' "$ac_cv_lib_posix4_sched_yield" >&6; } if test "x$ac_cv_lib_posix4_sched_yield" = xyes then : LIB_SCHED_YIELD=-lposix4 fi - + ;; +esac fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -26190,22 +26626,22 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ if test "$gl_use_threads" = isoc+posix && test "$gl_have_isoc_threads" = yes; then gl_threads_api='isoc+posix' -printf "%s\n" "#define USE_ISOC_AND_POSIX_THREADS 1" >>confdefs.h +printf '%s\n' "#define USE_ISOC_AND_POSIX_THREADS 1" >>confdefs.h LIBTHREAD= LTLIBTHREAD= else gl_threads_api=posix -printf "%s\n" "#define USE_POSIX_THREADS 1" >>confdefs.h +printf '%s\n' "#define USE_POSIX_THREADS 1" >>confdefs.h if test -z "$LIBMULTITHREAD" && test -z "$LTLIBMULTITHREAD"; then -printf "%s\n" "#define USE_POSIX_THREADS_FROM_LIBC 1" >>confdefs.h +printf '%s\n' "#define USE_POSIX_THREADS_FROM_LIBC 1" >>confdefs.h else if case "$gl_cv_have_weak" in *yes) true;; *) false;; esac; then -printf "%s\n" "#define USE_POSIX_THREADS_WEAK 1" >>confdefs.h +printf '%s\n' "#define USE_POSIX_THREADS_WEAK 1" >>confdefs.h LIBTHREAD= LTLIBTHREAD= else @@ -26213,7 +26649,7 @@ printf "%s\n" "#define USE_POSIX_THREADS_WEAK 1" >>confdefs.h freebsd* | dragonfly* | midnightbsd*) if test "x$LIBTHREAD" != "x$LIBMULTITHREAD"; then -printf "%s\n" "#define PTHREAD_IN_USE_DETECTION_HARD 1" >>confdefs.h +printf '%s\n' "#define PTHREAD_IN_USE_DETECTION_HARD 1" >>confdefs.h fi ;; @@ -26248,8 +26684,9 @@ printf "%s\n" "#define PTHREAD_IN_USE_DETECTION_HARD 1" >>confdefs.h if test "x$ac_cv_header_pthread_h" = xyes then : gl_have_pthread_h=yes -else $as_nop - gl_have_pthread_h=no +else case e in #( + e) gl_have_pthread_h=no ;; +esac fi if test "$gl_have_pthread_h" = yes; then @@ -26292,8 +26729,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ LIBS=$save_LIBS test $gl_pthread_api = yes && break done - echo "$as_me:26295: gl_pthread_api=$gl_pthread_api" >&5 - echo "$as_me:26296: LIBPTHREAD=$LIBPTHREAD" >&5 + echo "$as_me:26732: gl_pthread_api=$gl_pthread_api" >&5 + echo "$as_me:26733: LIBPTHREAD=$LIBPTHREAD" >&5 gl_pthread_in_glibc=no # On Linux with glibc >= 2.34, libc contains the fully functional @@ -26311,7 +26748,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Lucky user" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Lucky user" >/dev/null 2>&1 then : gl_pthread_in_glibc=yes fi @@ -26319,28 +26756,34 @@ rm -rf conftest* ;; esac - echo "$as_me:26322: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 + echo "$as_me:26759: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 # Test for libpthread by looking for pthread_kill. (Not pthread_self, # since it is defined as a macro on OSF/1.) if test $gl_pthread_api = yes && test -z "$LIBPTHREAD"; then # The program links fine without libpthread. But it may actually # need to link with libpthread in order to create multiple threads. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 printf %s "checking for pthread_kill in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_kill+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pthread_kill (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_kill (void); int main (void) { @@ -26352,15 +26795,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_kill=yes -else $as_nop - ac_cv_lib_pthread_pthread_kill=no +else case e in #( + e) ac_cv_lib_pthread_pthread_kill=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 -printf "%s\n" "$ac_cv_lib_pthread_pthread_kill" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 +printf '%s\n' "$ac_cv_lib_pthread_pthread_kill" >&6; } if test "x$ac_cv_lib_pthread_pthread_kill" = xyes then : if test $gl_pthread_in_glibc = yes; then @@ -26376,7 +26821,7 @@ then : case "$host_os" in solaris | solaris2.1-9 | solaris2.1-9.* | hpux*) -printf "%s\n" "#define PTHREAD_IN_USE_DETECTION_HARD 1" >>confdefs.h +printf '%s\n' "#define PTHREAD_IN_USE_DETECTION_HARD 1" >>confdefs.h esac fi @@ -26385,21 +26830,27 @@ fi elif test $gl_pthread_api != yes; then # Some library is needed. Try libpthread and libc_r. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 printf %s "checking for pthread_kill in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_kill+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pthread_kill (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_kill (void); int main (void) { @@ -26411,15 +26862,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_kill=yes -else $as_nop - ac_cv_lib_pthread_pthread_kill=no +else case e in #( + e) ac_cv_lib_pthread_pthread_kill=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 -printf "%s\n" "$ac_cv_lib_pthread_pthread_kill" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 +printf '%s\n' "$ac_cv_lib_pthread_pthread_kill" >&6; } if test "x$ac_cv_lib_pthread_pthread_kill" = xyes then : gl_pthread_api=yes @@ -26429,21 +26882,27 @@ fi if test $gl_pthread_api != yes; then # For FreeBSD 4. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lc_r" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lc_r" >&5 printf %s "checking for pthread_kill in -lc_r... " >&6; } if test ${ac_cv_lib_c_r_pthread_kill+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pthread_kill (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_kill (void); int main (void) { @@ -26455,15 +26914,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_c_r_pthread_kill=yes -else $as_nop - ac_cv_lib_c_r_pthread_kill=no +else case e in #( + e) ac_cv_lib_c_r_pthread_kill=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_kill" >&5 -printf "%s\n" "$ac_cv_lib_c_r_pthread_kill" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_kill" >&5 +printf '%s\n' "$ac_cv_lib_c_r_pthread_kill" >&6; } if test "x$ac_cv_lib_c_r_pthread_kill" = xyes then : gl_pthread_api=yes @@ -26473,17 +26934,17 @@ fi fi fi - echo "$as_me:26476: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 + echo "$as_me:26937: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5 printf %s "checking whether POSIX threads API is available... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_pthread_api" >&5 -printf "%s\n" "$gl_pthread_api" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_pthread_api" >&5 +printf '%s\n' "$gl_pthread_api" >&6; } if test $gl_pthread_api = yes; then -printf "%s\n" "#define HAVE_PTHREAD_API 1" >>confdefs.h +printf '%s\n' "#define HAVE_PTHREAD_API 1" >>confdefs.h fi @@ -26502,22 +26963,28 @@ if ac_fn_c_try_link "$LINENO" then : LIB_SCHED_YIELD= -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lrt" >&5 +else case e in #( + e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lrt" >&5 printf %s "checking for sched_yield in -lrt... " >&6; } if test ${ac_cv_lib_rt_sched_yield+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sched_yield (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char sched_yield (void); int main (void) { @@ -26529,34 +26996,42 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_rt_sched_yield=yes -else $as_nop - ac_cv_lib_rt_sched_yield=no +else case e in #( + e) ac_cv_lib_rt_sched_yield=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_sched_yield" >&5 -printf "%s\n" "$ac_cv_lib_rt_sched_yield" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_sched_yield" >&5 +printf '%s\n' "$ac_cv_lib_rt_sched_yield" >&6; } if test "x$ac_cv_lib_rt_sched_yield" = xyes then : LIB_SCHED_YIELD=-lrt -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lposix4" >&5 +else case e in #( + e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lposix4" >&5 printf %s "checking for sched_yield in -lposix4... " >&6; } if test ${ac_cv_lib_posix4_sched_yield+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lposix4 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sched_yield (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char sched_yield (void); int main (void) { @@ -26568,23 +27043,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_posix4_sched_yield=yes -else $as_nop - ac_cv_lib_posix4_sched_yield=no +else case e in #( + e) ac_cv_lib_posix4_sched_yield=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix4_sched_yield" >&5 -printf "%s\n" "$ac_cv_lib_posix4_sched_yield" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix4_sched_yield" >&5 +printf '%s\n' "$ac_cv_lib_posix4_sched_yield" >&6; } if test "x$ac_cv_lib_posix4_sched_yield" = xyes then : LIB_SCHED_YIELD=-lposix4 fi - + ;; +esac fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -26597,28 +27076,34 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ ac_fn_c_check_func "$LINENO" "thrd_create" "ac_cv_func_thrd_create" if test "x$ac_cv_func_thrd_create" = xyes then : - printf "%s\n" "#define HAVE_THRD_CREATE 1" >>confdefs.h + printf '%s\n' "#define HAVE_THRD_CREATE 1" >>confdefs.h fi if test $ac_cv_func_thrd_create = yes; then LIBSTDTHREAD= else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for thrd_create in -lstdthreads" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for thrd_create in -lstdthreads" >&5 printf %s "checking for thrd_create in -lstdthreads... " >&6; } if test ${ac_cv_lib_stdthreads_thrd_create+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lstdthreads $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char thrd_create (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char thrd_create (void); int main (void) { @@ -26630,24 +27115,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_stdthreads_thrd_create=yes -else $as_nop - ac_cv_lib_stdthreads_thrd_create=no +else case e in #( + e) ac_cv_lib_stdthreads_thrd_create=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_stdthreads_thrd_create" >&5 -printf "%s\n" "$ac_cv_lib_stdthreads_thrd_create" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_stdthreads_thrd_create" >&5 +printf '%s\n' "$ac_cv_lib_stdthreads_thrd_create" >&6; } if test "x$ac_cv_lib_stdthreads_thrd_create" = xyes then : LIBSTDTHREAD='-lstdthreads -lpthread' -else $as_nop - +else case e in #( + e) LIBSTDTHREAD="$LIBPMULTITHREAD" - + ;; +esac fi fi @@ -26658,10 +27146,10 @@ fi esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ISO C threads API is available" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ISO C threads API is available" >&5 printf %s "checking whether ISO C threads API is available... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_threads_h" >&5 -printf "%s\n" "$ac_cv_header_threads_h" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_threads_h" >&5 +printf '%s\n' "$ac_cv_header_threads_h" >&6; } gl_stdthreadlib_body_done=done fi @@ -26669,7 +27157,7 @@ printf "%s\n" "$ac_cv_header_threads_h" >&6; } LIBMULTITHREAD=$LIBSTDTHREAD LTLIBMULTITHREAD=$LIBSTDTHREAD gl_threads_api=isoc -printf "%s\n" "#define USE_ISOC_THREADS 1" >>confdefs.h +printf '%s\n' "#define USE_ISOC_THREADS 1" >>confdefs.h fi fi @@ -26683,17 +27171,17 @@ printf "%s\n" "#define USE_ISOC_THREADS 1" >>confdefs.h }; then gl_threads_api=windows -printf "%s\n" "#define USE_WINDOWS_THREADS 1" >>confdefs.h +printf '%s\n' "#define USE_WINDOWS_THREADS 1" >>confdefs.h fi ;; esac fi fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for multithread API to use" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for multithread API to use" >&5 printf %s "checking for multithread API to use... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_threads_api" >&5 -printf "%s\n" "$gl_threads_api" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_threads_api" >&5 +printf '%s\n' "$gl_threads_api" >&6; } @@ -26703,13 +27191,13 @@ printf "%s\n" "$gl_threads_api" >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 printf %s "checking for a sed that does not truncate output... " >&6; } if test ${ac_cv_path_SED+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ +else case e in #( + e) ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done @@ -26734,9 +27222,10 @@ do as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in +case `"$ac_path_SED" --version 2>&1` in #( *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +#( *) ac_count=0 printf %s 0123456789 >"conftest.in" @@ -26745,7 +27234,7 @@ case `"$ac_path_SED" --version 2>&1` in cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" - printf "%s\n" '' >> "conftest.nl" + printf '%s\n' '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val @@ -26771,13 +27260,85 @@ IFS=$as_save_IFS else ac_cv_path_SED=$SED fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -printf "%s\n" "$ac_cv_path_SED" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +printf '%s\n' "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +printf %s "checking for grep that handles long lines and -e... " >&6; } +if test ${ac_cv_path_GREP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in grep ggrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in #( +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +#( +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf '%s\n' 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + ;; +esac +fi +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +printf '%s\n' "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + @@ -26793,13 +27354,13 @@ printf "%s\n" "$ac_cv_path_SED" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_math_h='<'math.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_math_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_math_h = yes; then @@ -26841,10 +27402,11 @@ _ACEOF gl_cv_next_math_h='<'math.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_math_h" >&5 -printf "%s\n" "$gl_cv_next_math_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_math_h" >&5 +printf '%s\n' "$gl_cv_next_math_h" >&6; } fi NEXT_MATH_H=$gl_cv_next_math_h @@ -26861,13 +27423,13 @@ printf "%s\n" "$gl_cv_next_math_h" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether NAN macro works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether NAN macro works" >&5 printf %s "checking whether NAN macro works... " >&6; } if test ${gl_cv_header_math_nan_works+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -26888,23 +27450,25 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_header_math_nan_works=yes -else $as_nop - gl_cv_header_math_nan_works=no +else case e in #( + e) gl_cv_header_math_nan_works=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_math_nan_works" >&5 -printf "%s\n" "$gl_cv_header_math_nan_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_math_nan_works" >&5 +printf '%s\n' "$gl_cv_header_math_nan_works" >&6; } if test $gl_cv_header_math_nan_works = no; then REPLACE_NAN=1 fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether HUGE_VAL works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether HUGE_VAL works" >&5 printf %s "checking whether HUGE_VAL works... " >&6; } if test ${gl_cv_header_math_huge_val_works+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -26920,13 +27484,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_header_math_huge_val_works=yes -else $as_nop - gl_cv_header_math_huge_val_works=no +else case e in #( + e) gl_cv_header_math_huge_val_works=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_math_huge_val_works" >&5 -printf "%s\n" "$gl_cv_header_math_huge_val_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_math_huge_val_works" >&5 +printf '%s\n' "$gl_cv_header_math_huge_val_works" >&6; } if test $gl_cv_header_math_huge_val_works = no; then REPLACE_HUGE_VAL=1 fi @@ -26937,13 +27503,13 @@ printf "%s\n" "$gl_cv_header_math_huge_val_works" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mbstate_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for mbstate_t" >&5 printf %s "checking for mbstate_t... " >&6; } if test ${ac_cv_type_mbstate_t+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include @@ -26958,20 +27524,22 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_type_mbstate_t=yes -else $as_nop - ac_cv_type_mbstate_t=no +else case e in #( + e) ac_cv_type_mbstate_t=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_mbstate_t" >&5 -printf "%s\n" "$ac_cv_type_mbstate_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_mbstate_t" >&5 +printf '%s\n' "$ac_cv_type_mbstate_t" >&6; } if test $ac_cv_type_mbstate_t = yes; then -printf "%s\n" "#define HAVE_MBSTATE_T 1" >>confdefs.h +printf '%s\n' "#define HAVE_MBSTATE_T 1" >>confdefs.h else -printf "%s\n" "#define mbstate_t int" >>confdefs.h +printf '%s\n' "#define mbstate_t int" >>confdefs.h fi @@ -27048,8 +27616,9 @@ printf "%s\n" "#define mbstate_t int" >>confdefs.h if test "x$ac_cv_header_pthread_h" = xyes then : gl_have_pthread_h=yes -else $as_nop - gl_have_pthread_h=no +else case e in #( + e) gl_have_pthread_h=no ;; +esac fi if test "$gl_have_pthread_h" = yes; then @@ -27092,8 +27661,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ LIBS=$save_LIBS test $gl_pthread_api = yes && break done - echo "$as_me:27095: gl_pthread_api=$gl_pthread_api" >&5 - echo "$as_me:27096: LIBPTHREAD=$LIBPTHREAD" >&5 + echo "$as_me:27664: gl_pthread_api=$gl_pthread_api" >&5 + echo "$as_me:27665: LIBPTHREAD=$LIBPTHREAD" >&5 gl_pthread_in_glibc=no # On Linux with glibc >= 2.34, libc contains the fully functional @@ -27111,7 +27680,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Lucky user" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Lucky user" >/dev/null 2>&1 then : gl_pthread_in_glibc=yes fi @@ -27119,28 +27688,34 @@ rm -rf conftest* ;; esac - echo "$as_me:27122: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 + echo "$as_me:27691: gl_pthread_in_glibc=$gl_pthread_in_glibc" >&5 # Test for libpthread by looking for pthread_kill. (Not pthread_self, # since it is defined as a macro on OSF/1.) if test $gl_pthread_api = yes && test -z "$LIBPTHREAD"; then # The program links fine without libpthread. But it may actually # need to link with libpthread in order to create multiple threads. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 printf %s "checking for pthread_kill in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_kill+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pthread_kill (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_kill (void); int main (void) { @@ -27152,15 +27727,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_kill=yes -else $as_nop - ac_cv_lib_pthread_pthread_kill=no +else case e in #( + e) ac_cv_lib_pthread_pthread_kill=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 -printf "%s\n" "$ac_cv_lib_pthread_pthread_kill" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 +printf '%s\n' "$ac_cv_lib_pthread_pthread_kill" >&6; } if test "x$ac_cv_lib_pthread_pthread_kill" = xyes then : if test $gl_pthread_in_glibc = yes; then @@ -27176,7 +27753,7 @@ then : case "$host_os" in solaris | solaris2.1-9 | solaris2.1-9.* | hpux*) -printf "%s\n" "#define PTHREAD_IN_USE_DETECTION_HARD 1" >>confdefs.h +printf '%s\n' "#define PTHREAD_IN_USE_DETECTION_HARD 1" >>confdefs.h esac fi @@ -27185,21 +27762,27 @@ fi elif test $gl_pthread_api != yes; then # Some library is needed. Try libpthread and libc_r. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lpthread" >&5 printf %s "checking for pthread_kill in -lpthread... " >&6; } if test ${ac_cv_lib_pthread_pthread_kill+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pthread_kill (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_kill (void); int main (void) { @@ -27211,15 +27794,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_pthread_pthread_kill=yes -else $as_nop - ac_cv_lib_pthread_pthread_kill=no +else case e in #( + e) ac_cv_lib_pthread_pthread_kill=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 -printf "%s\n" "$ac_cv_lib_pthread_pthread_kill" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_kill" >&5 +printf '%s\n' "$ac_cv_lib_pthread_pthread_kill" >&6; } if test "x$ac_cv_lib_pthread_pthread_kill" = xyes then : gl_pthread_api=yes @@ -27229,21 +27814,27 @@ fi if test $gl_pthread_api != yes; then # For FreeBSD 4. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lc_r" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for pthread_kill in -lc_r" >&5 printf %s "checking for pthread_kill in -lc_r... " >&6; } if test ${ac_cv_lib_c_r_pthread_kill+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lc_r $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char pthread_kill (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_kill (void); int main (void) { @@ -27255,15 +27846,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_c_r_pthread_kill=yes -else $as_nop - ac_cv_lib_c_r_pthread_kill=no +else case e in #( + e) ac_cv_lib_c_r_pthread_kill=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_kill" >&5 -printf "%s\n" "$ac_cv_lib_c_r_pthread_kill" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_r_pthread_kill" >&5 +printf '%s\n' "$ac_cv_lib_c_r_pthread_kill" >&6; } if test "x$ac_cv_lib_c_r_pthread_kill" = xyes then : gl_pthread_api=yes @@ -27273,17 +27866,17 @@ fi fi fi - echo "$as_me:27276: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 + echo "$as_me:27869: LIBPMULTITHREAD=$LIBPMULTITHREAD" >&5 fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads API is available" >&5 printf %s "checking whether POSIX threads API is available... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_pthread_api" >&5 -printf "%s\n" "$gl_pthread_api" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_pthread_api" >&5 +printf '%s\n' "$gl_pthread_api" >&6; } if test $gl_pthread_api = yes; then -printf "%s\n" "#define HAVE_PTHREAD_API 1" >>confdefs.h +printf '%s\n' "#define HAVE_PTHREAD_API 1" >>confdefs.h fi @@ -27302,22 +27895,28 @@ if ac_fn_c_try_link "$LINENO" then : LIB_SCHED_YIELD= -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lrt" >&5 +else case e in #( + e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lrt" >&5 printf %s "checking for sched_yield in -lrt... " >&6; } if test ${ac_cv_lib_rt_sched_yield+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sched_yield (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char sched_yield (void); int main (void) { @@ -27329,34 +27928,42 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_rt_sched_yield=yes -else $as_nop - ac_cv_lib_rt_sched_yield=no +else case e in #( + e) ac_cv_lib_rt_sched_yield=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_sched_yield" >&5 -printf "%s\n" "$ac_cv_lib_rt_sched_yield" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_sched_yield" >&5 +printf '%s\n' "$ac_cv_lib_rt_sched_yield" >&6; } if test "x$ac_cv_lib_rt_sched_yield" = xyes then : LIB_SCHED_YIELD=-lrt -else $as_nop - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lposix4" >&5 +else case e in #( + e) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sched_yield in -lposix4" >&5 printf %s "checking for sched_yield in -lposix4... " >&6; } if test ${ac_cv_lib_posix4_sched_yield+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_check_lib_save_LIBS=$LIBS +else case e in #( + e) ac_check_lib_save_LIBS=$LIBS LIBS="-lposix4 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char sched_yield (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char sched_yield (void); int main (void) { @@ -27368,23 +27975,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_posix4_sched_yield=yes -else $as_nop - ac_cv_lib_posix4_sched_yield=no +else case e in #( + e) ac_cv_lib_posix4_sched_yield=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS +LIBS=$ac_check_lib_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix4_sched_yield" >&5 -printf "%s\n" "$ac_cv_lib_posix4_sched_yield" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix4_sched_yield" >&5 +printf '%s\n' "$ac_cv_lib_posix4_sched_yield" >&6; } if test "x$ac_cv_lib_posix4_sched_yield" = xyes then : LIB_SCHED_YIELD=-lposix4 fi - + ;; +esac fi - + ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -27577,15 +28188,16 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ if test "x$ac_cv_func_mmap" = xyes then : gl_have_mmap=yes -else $as_nop - gl_have_mmap=no +else case e in #( + e) gl_have_mmap=no ;; +esac fi # Try to allow MAP_ANONYMOUS. gl_have_mmap_anonymous=no if test $gl_have_mmap = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for MAP_ANONYMOUS" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for MAP_ANONYMOUS" >&5 printf %s "checking for MAP_ANONYMOUS... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -27597,7 +28209,7 @@ printf %s "checking for MAP_ANONYMOUS... " >&6; } _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "I cannot identify this map" >/dev/null 2>&1 + $EGREP_TRADITIONAL "I cannot identify this map" >/dev/null 2>&1 then : gl_have_mmap_anonymous=yes fi @@ -27614,21 +28226,21 @@ rm -rf conftest* _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "I cannot identify this map" >/dev/null 2>&1 + $EGREP_TRADITIONAL "I cannot identify this map" >/dev/null 2>&1 then : -printf "%s\n" "#define MAP_ANONYMOUS MAP_ANON" >>confdefs.h +printf '%s\n' "#define MAP_ANONYMOUS MAP_ANON" >>confdefs.h gl_have_mmap_anonymous=yes fi rm -rf conftest* fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_have_mmap_anonymous" >&5 -printf "%s\n" "$gl_have_mmap_anonymous" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_have_mmap_anonymous" >&5 +printf '%s\n' "$gl_have_mmap_anonymous" >&6; } if test $gl_have_mmap_anonymous = yes; then -printf "%s\n" "#define HAVE_MAP_ANONYMOUS 1" >>confdefs.h +printf '%s\n' "#define HAVE_MAP_ANONYMOUS 1" >>confdefs.h fi fi @@ -27651,13 +28263,13 @@ printf "%s\n" "#define HAVE_MAP_ANONYMOUS 1" >>confdefs.h # memchr should cast the second argument to 'unsigned char'. # This bug exists in Android 4.3. # Assume that memchr works on platforms that lack mprotect. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether memchr works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether memchr works" >&5 printf %s "checking whether memchr works... " >&6; } if test ${gl_cv_func_memchr_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess no on Android. @@ -27668,8 +28280,8 @@ then : *) gl_cv_func_memchr_works="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -27740,17 +28352,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_memchr_works=yes -else $as_nop - gl_cv_func_memchr_works=no +else case e in #( + e) gl_cv_func_memchr_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_memchr_works" >&5 -printf "%s\n" "$gl_cv_func_memchr_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_memchr_works" >&5 +printf '%s\n' "$gl_cv_func_memchr_works" >&6; } case "$gl_cv_func_memchr_works" in *yes) ;; *) REPLACE_MEMCHR=1 ;; @@ -27760,13 +28375,13 @@ printf "%s\n" "$gl_cv_func_memchr_works" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether defines MIN and MAX" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether defines MIN and MAX" >&5 printf %s "checking whether defines MIN and MAX... " >&6; } if test ${gl_cv_minmax_in_limits_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int x = MIN (42, 17); @@ -27781,16 +28396,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_minmax_in_limits_h=yes -else $as_nop - gl_cv_minmax_in_limits_h=no +else case e in #( + e) gl_cv_minmax_in_limits_h=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_minmax_in_limits_h" >&5 -printf "%s\n" "$gl_cv_minmax_in_limits_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_minmax_in_limits_h" >&5 +printf '%s\n' "$gl_cv_minmax_in_limits_h" >&6; } if test $gl_cv_minmax_in_limits_h = yes; then -printf "%s\n" "#define HAVE_MINMAX_IN_LIMITS_H 1" >>confdefs.h +printf '%s\n' "#define HAVE_MINMAX_IN_LIMITS_H 1" >>confdefs.h fi @@ -27799,13 +28416,13 @@ printf "%s\n" "#define HAVE_MINMAX_IN_LIMITS_H 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether defines MIN and MAX" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether defines MIN and MAX" >&5 printf %s "checking whether defines MIN and MAX... " >&6; } if test ${gl_cv_minmax_in_sys_param_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int x = MIN (42, 17); @@ -27820,16 +28437,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_minmax_in_sys_param_h=yes -else $as_nop - gl_cv_minmax_in_sys_param_h=no +else case e in #( + e) gl_cv_minmax_in_sys_param_h=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_minmax_in_sys_param_h" >&5 -printf "%s\n" "$gl_cv_minmax_in_sys_param_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_minmax_in_sys_param_h" >&5 +printf '%s\n' "$gl_cv_minmax_in_sys_param_h" >&6; } if test $gl_cv_minmax_in_sys_param_h = yes; then -printf "%s\n" "#define HAVE_MINMAX_IN_SYS_PARAM_H 1" >>confdefs.h +printf '%s\n' "#define HAVE_MINMAX_IN_SYS_PARAM_H 1" >>confdefs.h fi @@ -27840,23 +28459,24 @@ printf "%s\n" "#define HAVE_MINMAX_IN_SYS_PARAM_H 1" >>confdefs.h -ac_fn_check_decl "$LINENO" "obstack_printf" "ac_cv_have_decl_obstack_printf" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "obstack_printf" "ac_cv_have_decl_obstack_printf" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_obstack_printf" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_OBSTACK_PRINTF $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_OBSTACK_PRINTF $ac_have_decl" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for O_CLOEXEC" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for O_CLOEXEC" >&5 printf %s "checking for O_CLOEXEC... " >&6; } if test ${gl_cv_macro_O_CLOEXEC+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #ifndef O_CLOEXEC @@ -27874,23 +28494,25 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_macro_O_CLOEXEC=yes -else $as_nop - gl_cv_macro_O_CLOEXEC=no +else case e in #( + e) gl_cv_macro_O_CLOEXEC=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_macro_O_CLOEXEC" >&5 -printf "%s\n" "$gl_cv_macro_O_CLOEXEC" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_macro_O_CLOEXEC" >&5 +printf '%s\n' "$gl_cv_macro_O_CLOEXEC" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for promoted mode_t type" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for promoted mode_t type" >&5 printf %s "checking for promoted mode_t type... " >&6; } if test ${gl_cv_promoted_mode_t+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -27905,27 +28527,29 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_promoted_mode_t='int' -else $as_nop - gl_cv_promoted_mode_t='mode_t' +else case e in #( + e) gl_cv_promoted_mode_t='mode_t' ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_promoted_mode_t" >&5 -printf "%s\n" "$gl_cv_promoted_mode_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_promoted_mode_t" >&5 +printf '%s\n' "$gl_cv_promoted_mode_t" >&6; } -printf "%s\n" "#define PROMOTED_MODE_T $gl_cv_promoted_mode_t" >>confdefs.h +printf '%s\n' "#define PROMOTED_MODE_T $gl_cv_promoted_mode_t" >>confdefs.h REPLACE_STRERROR_0=0 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strerror(0) succeeds" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether strerror(0) succeeds" >&5 printf %s "checking whether strerror(0) succeeds... " >&6; } if test ${gl_cv_func_strerror_0_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on glibc systems. @@ -27938,8 +28562,8 @@ then : *) gl_cv_func_strerror_0_works="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -27963,23 +28587,26 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_strerror_0_works=yes -else $as_nop - gl_cv_func_strerror_0_works=no +else case e in #( + e) gl_cv_func_strerror_0_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strerror_0_works" >&5 -printf "%s\n" "$gl_cv_func_strerror_0_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strerror_0_works" >&5 +printf '%s\n' "$gl_cv_func_strerror_0_works" >&6; } case "$gl_cv_func_strerror_0_works" in *yes) ;; *) REPLACE_STRERROR_0=1 -printf "%s\n" "#define REPLACE_STRERROR_0 1" >>confdefs.h +printf '%s\n' "#define REPLACE_STRERROR_0 1" >>confdefs.h ;; esac @@ -27996,13 +28623,13 @@ printf "%s\n" "#define REPLACE_STRERROR_0 1" >>confdefs.h if test $ac_cv_func_strerror_r = yes; then if test "$ERRNO_H:$REPLACE_STRERROR_0" = :0; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for strerror_r with POSIX signature" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for strerror_r with POSIX signature" >&5 printf %s "checking for strerror_r with POSIX signature... " >&6; } if test ${gl_cv_func_strerror_r_posix_signature+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int strerror_r (int, char *, size_t); @@ -28018,22 +28645,24 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_strerror_r_posix_signature=yes -else $as_nop - gl_cv_func_strerror_r_posix_signature=no +else case e in #( + e) gl_cv_func_strerror_r_posix_signature=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strerror_r_posix_signature" >&5 -printf "%s\n" "$gl_cv_func_strerror_r_posix_signature" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strerror_r_posix_signature" >&5 +printf '%s\n' "$gl_cv_func_strerror_r_posix_signature" >&6; } if test $gl_cv_func_strerror_r_posix_signature = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strerror_r works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether strerror_r works" >&5 printf %s "checking whether strerror_r works... " >&6; } if test ${gl_cv_func_strerror_r_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -28047,8 +28676,8 @@ then : *) gl_cv_func_strerror_r_works="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -28087,32 +28716,35 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_strerror_r_works=yes -else $as_nop - gl_cv_func_strerror_r_works=no +else case e in #( + e) gl_cv_func_strerror_r_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strerror_r_works" >&5 -printf "%s\n" "$gl_cv_func_strerror_r_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strerror_r_works" >&5 +printf '%s\n' "$gl_cv_func_strerror_r_works" >&6; } else if test $ac_cv_func___xpg_strerror_r = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether __xpg_strerror_r works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether __xpg_strerror_r works" >&5 printf %s "checking whether __xpg_strerror_r works... " >&6; } if test ${gl_cv_func_strerror_r_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : gl_cv_func_strerror_r_works="$gl_cross_guess_normal" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -28146,17 +28778,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_strerror_r_works=yes -else $as_nop - gl_cv_func_strerror_r_works=no +else case e in #( + e) gl_cv_func_strerror_r_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strerror_r_works" >&5 -printf "%s\n" "$gl_cv_func_strerror_r_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strerror_r_works" >&5 +printf '%s\n' "$gl_cv_func_strerror_r_works" >&6; } fi fi fi @@ -28214,20 +28849,26 @@ printf "%s\n" "$gl_cv_func_strerror_r_works" >&6; } LIB_POSIX_SPAWN= gl_saved_libs=$LIBS - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing posix_spawn" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for library containing posix_spawn" >&5 printf %s "checking for library containing posix_spawn... " >&6; } if test ${ac_cv_search_posix_spawn+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char posix_spawn (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char posix_spawn (void); int main (void) { @@ -28258,14 +28899,16 @@ done if test ${ac_cv_search_posix_spawn+y} then : -else $as_nop - ac_cv_search_posix_spawn=no +else case e in #( + e) ac_cv_search_posix_spawn=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_posix_spawn" >&5 -printf "%s\n" "$ac_cv_search_posix_spawn" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_posix_spawn" >&5 +printf '%s\n' "$ac_cv_search_posix_spawn" >&6; } ac_res=$ac_cv_search_posix_spawn if test "$ac_res" != no then : @@ -28277,7 +28920,7 @@ fi ac_fn_c_check_func "$LINENO" "posix_spawn" "ac_cv_func_posix_spawn" if test "x$ac_cv_func_posix_spawn" = xyes then : - printf "%s\n" "#define HAVE_POSIX_SPAWN 1" >>confdefs.h + printf '%s\n' "#define HAVE_POSIX_SPAWN 1" >>confdefs.h fi @@ -28292,14 +28935,15 @@ fi ac_fn_check_decl "$LINENO" "posix_spawn" "ac_cv_have_decl_posix_spawn" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_posix_spawn" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_POSIX_SPAWN $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_POSIX_SPAWN $ac_have_decl" >>confdefs.h if test $ac_cv_func_posix_spawn = yes; then @@ -28311,13 +28955,13 @@ printf "%s\n" "#define HAVE_DECL_POSIX_SPAWN $ac_have_decl" >>confdefs.h if test $REPLACE_POSIX_SPAWN = 0; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether posix_spawn works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether posix_spawn works" >&5 printf %s "checking whether posix_spawn works... " >&6; } if test ${gl_cv_func_posix_spawn_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test $cross_compiling = no; then +else case e in #( + e) if test $cross_compiling = no; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -28466,20 +29110,21 @@ then : else gl_cv_func_posix_spawn_works=no fi -else $as_nop - gl_cv_func_posix_spawn_works=no +else case e in #( + e) gl_cv_func_posix_spawn_works=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext if test $gl_cv_func_posix_spawn_works = yes; then if test "$cross_compiling" = yes then : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Test whether posix_spawn_file_actions_addopen supports filename arguments @@ -28640,11 +29285,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : -else $as_nop - gl_cv_func_posix_spawn_works=no +else case e in #( + e) gl_cv_func_posix_spawn_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi @@ -28654,10 +29301,11 @@ fi *) gl_cv_func_posix_spawn_works="guessing yes";; esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawn_works" >&5 -printf "%s\n" "$gl_cv_func_posix_spawn_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawn_works" >&5 +printf '%s\n' "$gl_cv_func_posix_spawn_works" >&6; } case "$gl_cv_func_posix_spawn_works" in *yes) ;; @@ -28667,13 +29315,13 @@ printf "%s\n" "$gl_cv_func_posix_spawn_works" >&6; } if test $REPLACE_POSIX_SPAWN = 0; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether posix_spawn rejects scripts without shebang" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether posix_spawn rejects scripts without shebang" >&5 printf %s "checking whether posix_spawn rejects scripts without shebang... " >&6; } if test ${gl_cv_func_posix_spawn_secure_exec+y} then : printf %s "(cached) " >&6 -else $as_nop - echo ':' > conftest.scr +else case e in #( + e) echo ':' > conftest.scr chmod a+x conftest.scr if test "$cross_compiling" = yes then : @@ -28686,8 +29334,8 @@ then : gl_cv_func_posix_spawn_secure_exec="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -28723,25 +29371,28 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_posix_spawn_secure_exec=yes -else $as_nop - gl_cv_func_posix_spawn_secure_exec=no +else case e in #( + e) gl_cv_func_posix_spawn_secure_exec=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.scr - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawn_secure_exec" >&5 -printf "%s\n" "$gl_cv_func_posix_spawn_secure_exec" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether posix_spawnp rejects scripts without shebang" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawn_secure_exec" >&5 +printf '%s\n' "$gl_cv_func_posix_spawn_secure_exec" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether posix_spawnp rejects scripts without shebang" >&5 printf %s "checking whether posix_spawnp rejects scripts without shebang... " >&6; } if test ${gl_cv_func_posix_spawnp_secure_exec+y} then : printf %s "(cached) " >&6 -else $as_nop - echo ':' > conftest.scr +else case e in #( + e) echo ':' > conftest.scr chmod a+x conftest.scr if test "$cross_compiling" = yes then : @@ -28759,8 +29410,8 @@ then : gl_cv_func_posix_spawnp_secure_exec="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -28796,18 +29447,21 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_posix_spawnp_secure_exec=yes -else $as_nop - gl_cv_func_posix_spawnp_secure_exec=no +else case e in #( + e) gl_cv_func_posix_spawnp_secure_exec=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.scr - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawnp_secure_exec" >&5 -printf "%s\n" "$gl_cv_func_posix_spawnp_secure_exec" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawnp_secure_exec" >&5 +printf '%s\n' "$gl_cv_func_posix_spawnp_secure_exec" >&6; } case "$gl_cv_func_posix_spawn_secure_exec" in *yes) ;; @@ -28819,13 +29473,13 @@ printf "%s\n" "$gl_cv_func_posix_spawnp_secure_exec" >&6; } esac fi if test $REPLACE_POSIX_SPAWN = 0; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether posix_spawnattr_setschedpolicy is supported" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether posix_spawnattr_setschedpolicy is supported" >&5 printf %s "checking whether posix_spawnattr_setschedpolicy is supported... " >&6; } if test ${gl_cv_func_spawnattr_setschedpolicy+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -28835,25 +29489,27 @@ else $as_nop _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "POSIX scheduling supported" >/dev/null 2>&1 + $EGREP_TRADITIONAL "POSIX scheduling supported" >/dev/null 2>&1 then : gl_cv_func_spawnattr_setschedpolicy=yes -else $as_nop - gl_cv_func_spawnattr_setschedpolicy=no +else case e in #( + e) gl_cv_func_spawnattr_setschedpolicy=no ;; +esac fi rm -rf conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_spawnattr_setschedpolicy" >&5 -printf "%s\n" "$gl_cv_func_spawnattr_setschedpolicy" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether posix_spawnattr_setschedparam is supported" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_spawnattr_setschedpolicy" >&5 +printf '%s\n' "$gl_cv_func_spawnattr_setschedpolicy" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether posix_spawnattr_setschedparam is supported" >&5 printf %s "checking whether posix_spawnattr_setschedparam is supported... " >&6; } if test ${gl_cv_func_spawnattr_setschedparam+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -28863,18 +29519,20 @@ else $as_nop _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "POSIX scheduling supported" >/dev/null 2>&1 + $EGREP_TRADITIONAL "POSIX scheduling supported" >/dev/null 2>&1 then : gl_cv_func_spawnattr_setschedparam=yes -else $as_nop - gl_cv_func_spawnattr_setschedparam=no +else case e in #( + e) gl_cv_func_spawnattr_setschedparam=no ;; +esac fi rm -rf conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_spawnattr_setschedparam" >&5 -printf "%s\n" "$gl_cv_func_spawnattr_setschedparam" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_spawnattr_setschedparam" >&5 +printf '%s\n' "$gl_cv_func_spawnattr_setschedparam" >&6; } fi else if test $ac_cv_have_decl_posix_spawn = yes; then @@ -28883,7 +29541,7 @@ printf "%s\n" "$gl_cv_func_spawnattr_setschedparam" >&6; } fi if test $ac_cv_func_posix_spawn != yes || test $REPLACE_POSIX_SPAWN = 1; then -printf "%s\n" "#define REPLACE_POSIX_SPAWN 1" >>confdefs.h +printf '%s\n' "#define REPLACE_POSIX_SPAWN 1" >>confdefs.h fi @@ -29066,7 +29724,7 @@ printf "%s\n" "#define REPLACE_POSIX_SPAWN 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; esac @@ -29081,7 +29739,7 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -29095,12 +29753,12 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : - printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h + printf '%s\n' "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi @@ -29114,7 +29772,7 @@ fi ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; esac @@ -29126,7 +29784,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; esac @@ -29138,7 +29796,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; esac @@ -29150,7 +29808,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; esac @@ -29162,7 +29820,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; esac @@ -29174,13 +29832,13 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -29192,13 +29850,13 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -29247,7 +29905,7 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h if test $ac_cv_func_vasnprintf = yes; then -printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h +printf '%s\n' "#define REPLACE_VASNPRINTF 1" >>confdefs.h fi @@ -29263,11 +29921,12 @@ printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h if test "x$ac_cv_type_ptrdiff_t" = xyes then : -else $as_nop - -printf "%s\n" "#define ptrdiff_t long" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define ptrdiff_t long" >>confdefs.h + ;; +esac fi @@ -29290,12 +29949,89 @@ fi REPLACE_VFPRINTF=1 -printf "%s\n" "#define REPLACE_VFPRINTF_POSIX 1" >>confdefs.h +printf '%s\n' "#define REPLACE_VFPRINTF_POSIX 1" >>confdefs.h : fi +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +printf %s "checking for egrep... " >&6; } +if test ${ac_cv_path_EGREP+y} +then : + printf %s "(cached) " >&6 +else case e in #( + e) if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_prog in egrep + do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in #( +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +#( +*) + ac_count=0 + printf %s 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + printf '%s\n' 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi ;; +esac +fi +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +printf '%s\n' "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + EGREP_TRADITIONAL=$EGREP + ac_cv_path_EGREP_TRADITIONAL=$EGREP + cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -29306,7 +30042,7 @@ MicrosoftCompiler _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "MicrosoftCompiler" >/dev/null 2>&1 + $EGREP_TRADITIONAL "MicrosoftCompiler" >/dev/null 2>&1 then : rm -f conftest* echo 'int dummy;' > conftest.c @@ -29314,7 +30050,7 @@ then : { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 (eval $ac_try) 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } >/dev/null 2>&1 if test -f conftest.o; then gl_asmext='s' @@ -29325,10 +30061,11 @@ then : fi rm -f conftest* -else $as_nop - gl_asmext='s' +else case e in #( + e) gl_asmext='s' gl_c_asm_opt='-S' - + ;; +esac fi rm -rf conftest* @@ -29336,13 +30073,13 @@ rm -rf conftest* - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether C symbols are prefixed with underscore at the linker level" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether C symbols are prefixed with underscore at the linker level" >&5 printf %s "checking whether C symbols are prefixed with underscore at the linker level... " >&6; } if test ${gl_cv_prog_as_underscore+y} then : printf %s "(cached) " >&6 -else $as_nop - cat > conftest.c < conftest.c <&5 (eval $ac_try) 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; } >/dev/null 2>&1 if LC_ALL=C $EGREP '(^|[^a-zA-Z0-9_])_foo([^a-zA-Z0-9_]|$)' conftest.$gl_asmext >/dev/null; then gl_cv_prog_as_underscore=yes @@ -29361,17 +30098,18 @@ EOF gl_cv_prog_as_underscore=no fi rm -f conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_prog_as_underscore" >&5 -printf "%s\n" "$gl_cv_prog_as_underscore" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_prog_as_underscore" >&5 +printf '%s\n' "$gl_cv_prog_as_underscore" >&6; } if test $gl_cv_prog_as_underscore = yes; then USER_LABEL_PREFIX=_ else USER_LABEL_PREFIX= fi -printf "%s\n" "#define USER_LABEL_PREFIX $USER_LABEL_PREFIX" >>confdefs.h +printf '%s\n' "#define USER_LABEL_PREFIX $USER_LABEL_PREFIX" >>confdefs.h ASM_SYMBOL_PREFIX='"'${USER_LABEL_PREFIX}'"' @@ -29401,11 +30139,12 @@ printf "%s\n" "#define USER_LABEL_PREFIX $USER_LABEL_PREFIX" >>confdefs.h if test "x$ac_cv_type_sigset_t" = xyes then : -printf "%s\n" "#define HAVE_SIGSET_T 1" >>confdefs.h +printf '%s\n' "#define HAVE_SIGSET_T 1" >>confdefs.h gl_cv_type_sigset_t=yes -else $as_nop - gl_cv_type_sigset_t=no +else case e in #( + e) gl_cv_type_sigset_t=no ;; +esac fi if test $gl_cv_type_sigset_t != yes; then @@ -29443,26 +30182,27 @@ fi fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for shared library path variable" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for shared library path variable" >&5 printf %s "checking for shared library path variable... " >&6; } if test ${acl_cv_libpath+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) LD="$LD" \ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.libpath" "$host" > conftest.sh . ./conftest.sh rm -f ./conftest.sh acl_cv_libpath=${acl_cv_shlibpath_var:-none} - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $acl_cv_libpath" >&5 -printf "%s\n" "$acl_cv_libpath" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $acl_cv_libpath" >&5 +printf '%s\n' "$acl_cv_libpath" >&6; } shlibpath_var="$acl_cv_shlibpath_var" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to activate relocatable installation" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to activate relocatable installation" >&5 printf %s "checking whether to activate relocatable installation... " >&6; } # Check whether --enable-relocatable was given. if test ${enable_relocatable+y} @@ -29473,13 +30213,14 @@ then : RELOCATABLE=no fi -else $as_nop - RELOCATABLE=no +else case e in #( + e) RELOCATABLE=no ;; +esac fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RELOCATABLE" >&5 -printf "%s\n" "$RELOCATABLE" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $RELOCATABLE" >&5 +printf '%s\n' "$RELOCATABLE" >&6; } @@ -29489,11 +30230,13 @@ printf "%s\n" "$RELOCATABLE" >&6; } reloc_final_prefix="$prefix" fi -printf "%s\n" "#define INSTALLPREFIX \"${reloc_final_prefix}\"" >>confdefs.h +cat >>confdefs.h <<_ACEOF +#define INSTALLPREFIX "${reloc_final_prefix}" +_ACEOF if test $RELOCATABLE = yes; then -printf "%s\n" "#define ENABLE_RELOCATABLE 1" >>confdefs.h +printf '%s\n' "#define ENABLE_RELOCATABLE 1" >>confdefs.h fi @@ -29514,14 +30257,14 @@ printf "%s\n" "#define ENABLE_RELOCATABLE 1" >>confdefs.h ac_fn_c_check_header_compile "$LINENO" "mach-o/dyld.h" "ac_cv_header_mach_o_dyld_h" "$ac_includes_default" if test "x$ac_cv_header_mach_o_dyld_h" = xyes then : - printf "%s\n" "#define HAVE_MACH_O_DYLD_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_MACH_O_DYLD_H 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "_NSGetExecutablePath" "ac_cv_func__NSGetExecutablePath" if test "x$ac_cv_func__NSGetExecutablePath" = xyes then : - printf "%s\n" "#define HAVE__NSGETEXECUTABLEPATH 1" >>confdefs.h + printf '%s\n' "#define HAVE__NSGETEXECUTABLEPATH 1" >>confdefs.h fi @@ -29540,7 +30283,7 @@ fi ac_fn_c_check_func "$LINENO" "copy_file_range" "ac_cv_func_copy_file_range" if test "x$ac_cv_func_copy_file_range" = xyes then : - printf "%s\n" "#define HAVE_COPY_FILE_RANGE 1" >>confdefs.h + printf '%s\n' "#define HAVE_COPY_FILE_RANGE 1" >>confdefs.h fi @@ -29626,13 +30369,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether malloc (0) returns nonnull" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether malloc (0) returns nonnull" >&5 printf %s "checking whether malloc (0) returns nonnull... " >&6; } if test ${ac_cv_func_malloc_0_nonnull+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on platforms where we know the result. @@ -29644,8 +30387,8 @@ then : *) ac_cv_func_malloc_0_nonnull="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -29664,17 +30407,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_malloc_0_nonnull=yes -else $as_nop - ac_cv_func_malloc_0_nonnull=no +else case e in #( + e) ac_cv_func_malloc_0_nonnull=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 -printf "%s\n" "$ac_cv_func_malloc_0_nonnull" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 +printf '%s\n' "$ac_cv_func_malloc_0_nonnull" >&6; } case $ac_cv_func_malloc_0_nonnull in #( *yes) : gl_cv_func_malloc_0_nonnull=1 ;; #( @@ -29683,17 +30429,18 @@ printf "%s\n" "$ac_cv_func_malloc_0_nonnull" >&6; } esac -printf "%s\n" "#define MALLOC_0_IS_NONNULL $gl_cv_func_malloc_0_nonnull" >>confdefs.h +printf '%s\n' "#define MALLOC_0_IS_NONNULL $gl_cv_func_malloc_0_nonnull" >>confdefs.h -ac_fn_check_decl "$LINENO" "setenv" "ac_cv_have_decl_setenv" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "setenv" "ac_cv_have_decl_setenv" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_setenv" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_SETENV $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_SETENV $ac_have_decl" >>confdefs.h @@ -29714,7 +30461,7 @@ printf "%s\n" "#define HAVE_DECL_SETENV $ac_have_decl" >>confdefs.h " if test "x$ac_cv_header_sched_h" = xyes then : - printf "%s\n" "#define HAVE_SCHED_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_SCHED_H 1" >>confdefs.h fi @@ -29729,13 +30476,13 @@ fi if test $gl_cv_have_include_next = yes; then gl_cv_next_sched_h='<'sched.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_sched_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -29771,10 +30518,11 @@ _ACEOF gl_header=$gl_cv_absolute_sched_h gl_cv_next_sched_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sched_h" >&5 -printf "%s\n" "$gl_cv_next_sched_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sched_h" >&5 +printf '%s\n' "$gl_cv_next_sched_h" >&6; } fi NEXT_SCHED_H=$gl_cv_next_sched_h @@ -29808,8 +30556,9 @@ printf "%s\n" "$gl_cv_next_sched_h" >&6; } if test "x$ac_cv_type_struct_sched_param" = xyes then : HAVE_STRUCT_SCHED_PARAM=1 -else $as_nop - HAVE_STRUCT_SCHED_PARAM=0 +else case e in #( + e) HAVE_STRUCT_SCHED_PARAM=0 ;; +esac fi else @@ -29857,36 +30606,26 @@ fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for uid_t in sys/types.h" >&5 -printf %s "checking for uid_t in sys/types.h... " >&6; } -if test ${ac_cv_type_uid_t+y} +ac_fn_c_check_type "$LINENO" "uid_t" "ac_cv_type_uid_t" "$ac_includes_default" +if test "x$ac_cv_type_uid_t" = xyes then : - printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "uid_t" >/dev/null 2>&1 +else case e in #( + e) +printf '%s\n' "#define uid_t int" >>confdefs.h + ;; +esac +fi + +ac_fn_c_check_type "$LINENO" "gid_t" "ac_cv_type_gid_t" "$ac_includes_default" +if test "x$ac_cv_type_gid_t" = xyes then : - ac_cv_type_uid_t=yes -else $as_nop - ac_cv_type_uid_t=no -fi -rm -rf conftest* - -fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_uid_t" >&5 -printf "%s\n" "$ac_cv_type_uid_t" >&6; } -if test $ac_cv_type_uid_t = no; then - -printf "%s\n" "#define uid_t int" >>confdefs.h - - -printf "%s\n" "#define gid_t int" >>confdefs.h +else case e in #( + e) +printf '%s\n' "#define gid_t int" >>confdefs.h + ;; +esac fi @@ -29905,13 +30644,13 @@ fi if test $gl_cv_have_include_next = yes; then gl_cv_next_signal_h='<'signal.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_signal_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -29947,10 +30686,11 @@ _ACEOF gl_header=$gl_cv_absolute_signal_h gl_cv_next_signal_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_signal_h" >&5 -printf "%s\n" "$gl_cv_next_signal_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_signal_h" >&5 +printf '%s\n' "$gl_cv_next_signal_h" >&6; } fi NEXT_SIGNAL_H=$gl_cv_next_signal_h @@ -29976,8 +30716,9 @@ printf "%s\n" "$gl_cv_next_signal_h" >&6; } if test "x$ac_cv_type_volatile_sig_atomic_t" = xyes then : -else $as_nop - HAVE_TYPE_VOLATILE_SIG_ATOMIC_T=0 +else case e in #( + e) HAVE_TYPE_VOLATILE_SIG_ATOMIC_T=0 ;; +esac fi @@ -29993,8 +30734,9 @@ fi if test "x$ac_cv_type_sighandler_t" = xyes then : -else $as_nop - HAVE_SIGHANDLER_T=0 +else case e in #( + e) HAVE_SIGHANDLER_T=0 ;; +esac fi @@ -30004,14 +30746,15 @@ fi -ac_fn_check_decl "$LINENO" "snprintf" "ac_cv_have_decl_snprintf" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "snprintf" "ac_cv_have_decl_snprintf" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_snprintf" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_SNPRINTF $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_SNPRINTF $ac_have_decl" >>confdefs.h @@ -30029,13 +30772,13 @@ printf "%s\n" "#define HAVE_DECL_SNPRINTF $ac_have_decl" >>confdefs.h if test $gl_cv_have_include_next = yes; then gl_cv_next_spawn_h='<'spawn.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_spawn_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_spawn_h = yes; then @@ -30077,10 +30820,11 @@ _ACEOF gl_cv_next_spawn_h='<'spawn.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_spawn_h" >&5 -printf "%s\n" "$gl_cv_next_spawn_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_spawn_h" >&5 +printf '%s\n' "$gl_cv_next_spawn_h" >&6; } fi NEXT_SPAWN_H=$gl_cv_next_spawn_h @@ -30106,11 +30850,12 @@ printf "%s\n" "$gl_cv_next_spawn_h" >&6; } if test "x$ac_cv_type_posix_spawnattr_t" = xyes then : -printf "%s\n" "#define HAVE_POSIX_SPAWNATTR_T 1" >>confdefs.h +printf '%s\n' "#define HAVE_POSIX_SPAWNATTR_T 1" >>confdefs.h -else $as_nop - HAVE_POSIX_SPAWNATTR_T=0 +else case e in #( + e) HAVE_POSIX_SPAWNATTR_T=0 ;; +esac fi ac_fn_c_check_type "$LINENO" "posix_spawn_file_actions_t" "ac_cv_type_posix_spawn_file_actions_t" " @@ -30120,11 +30865,12 @@ fi if test "x$ac_cv_type_posix_spawn_file_actions_t" = xyes then : -printf "%s\n" "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_T 1" >>confdefs.h +printf '%s\n' "#define HAVE_POSIX_SPAWN_FILE_ACTIONS_T 1" >>confdefs.h -else $as_nop - HAVE_POSIX_SPAWN_FILE_ACTIONS_T=0 +else case e in #( + e) HAVE_POSIX_SPAWN_FILE_ACTIONS_T=0 ;; +esac fi else @@ -30172,13 +30918,13 @@ fi REPLACE_STAT=0; REPLACE_UTIMENSAT=0; -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stat file-mode macros are broken" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether stat file-mode macros are broken" >&5 printf %s "checking whether stat file-mode macros are broken... " >&6; } if test ${ac_cv_header_stat_broken+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -30203,16 +30949,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_header_stat_broken=no -else $as_nop - ac_cv_header_stat_broken=yes +else case e in #( + e) ac_cv_header_stat_broken=yes ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stat_broken" >&5 -printf "%s\n" "$ac_cv_header_stat_broken" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stat_broken" >&5 +printf '%s\n' "$ac_cv_header_stat_broken" >&6; } if test $ac_cv_header_stat_broken = yes; then -printf "%s\n" "#define STAT_MACROS_BROKEN 1" >>confdefs.h +printf '%s\n' "#define STAT_MACROS_BROKEN 1" >>confdefs.h fi @@ -30233,13 +30981,13 @@ fi if test $gl_cv_have_include_next = yes; then gl_cv_next_sys_stat_h='<'sys/stat.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_sys_stat_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_sys_stat_h = yes; then @@ -30281,10 +31029,11 @@ _ACEOF gl_cv_next_sys_stat_h='<'sys/stat.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_stat_h" >&5 -printf "%s\n" "$gl_cv_next_sys_stat_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_stat_h" >&5 +printf '%s\n' "$gl_cv_next_sys_stat_h" >&6; } fi NEXT_SYS_STAT_H=$gl_cv_next_sys_stat_h @@ -30319,10 +31068,11 @@ printf "%s\n" "$gl_cv_next_sys_stat_h" >&6; } if test "x$ac_cv_type_nlink_t" = xyes then : -else $as_nop - -printf "%s\n" "#define nlink_t int" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define nlink_t int" >>confdefs.h + ;; +esac fi @@ -30339,7 +31089,7 @@ fi ac_fn_c_check_header_compile "$LINENO" "sdkddkver.h" "ac_cv_header_sdkddkver_h" "$ac_includes_default" if test "x$ac_cv_header_sdkddkver_h" = xyes then : - printf "%s\n" "#define HAVE_SDKDDKVER_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_SDKDDKVER_H 1" >>confdefs.h fi @@ -30428,13 +31178,13 @@ fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for stdbool.h that conforms to C99" >&5 printf %s "checking for stdbool.h that conforms to C99... " >&6; } if test ${ac_cv_header_stdbool_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -30507,18 +31257,20 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_header_stdbool_h=yes -else $as_nop - ac_cv_header_stdbool_h=no +else case e in #( + e) ac_cv_header_stdbool_h=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 -printf "%s\n" "$ac_cv_header_stdbool_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdbool_h" >&5 +printf '%s\n' "$ac_cv_header_stdbool_h" >&6; } ac_fn_c_check_type "$LINENO" "_Bool" "ac_cv_type__Bool" "$ac_includes_default" if test "x$ac_cv_type__Bool" = xyes then : -printf "%s\n" "#define HAVE__BOOL 1" >>confdefs.h +printf '%s\n' "#define HAVE__BOOL 1" >>confdefs.h fi @@ -30537,13 +31289,13 @@ fi STDDEF_H= - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for good max_align_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for good max_align_t" >&5 printf %s "checking for good max_align_t... " >&6; } if test ${gl_cv_type_max_align_t+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include unsigned int s = sizeof (max_align_t); @@ -30570,14 +31322,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_type_max_align_t=yes -else $as_nop - gl_cv_type_max_align_t=no +else case e in #( + e) gl_cv_type_max_align_t=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_max_align_t" >&5 -printf "%s\n" "$gl_cv_type_max_align_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_type_max_align_t" >&5 +printf '%s\n' "$gl_cv_type_max_align_t" >&6; } if test $gl_cv_type_max_align_t = no; then HAVE_MAX_ALIGN_T=0 STDDEF_H=stddef.h @@ -30588,13 +31342,13 @@ printf "%s\n" "$gl_cv_type_max_align_t" >&6; } STDDEF_H=stddef.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether NULL can be used in arbitrary expressions" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether NULL can be used in arbitrary expressions" >&5 printf %s "checking whether NULL can be used in arbitrary expressions... " >&6; } if test ${gl_cv_decl_null_works+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int test[2 * (sizeof NULL == sizeof (void *)) -1]; @@ -30610,13 +31364,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_decl_null_works=yes -else $as_nop - gl_cv_decl_null_works=no +else case e in #( + e) gl_cv_decl_null_works=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_decl_null_works" >&5 -printf "%s\n" "$gl_cv_decl_null_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_decl_null_works" >&5 +printf '%s\n' "$gl_cv_decl_null_works" >&6; } if test $gl_cv_decl_null_works = no; then REPLACE_NULL=1 STDDEF_H=stddef.h @@ -30643,13 +31399,13 @@ fi if test $gl_cv_have_include_next = yes; then gl_cv_next_stddef_h='<'stddef.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_stddef_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -30685,10 +31441,11 @@ _ACEOF gl_header=$gl_cv_absolute_stddef_h gl_cv_next_stddef_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stddef_h" >&5 -printf "%s\n" "$gl_cv_next_stddef_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stddef_h" >&5 +printf '%s\n' "$gl_cv_next_stddef_h" >&6; } fi NEXT_STDDEF_H=$gl_cv_next_stddef_h @@ -30708,19 +31465,20 @@ printf "%s\n" "$gl_cv_next_stddef_h" >&6; } -ac_fn_check_decl "$LINENO" "fcloseall" "ac_cv_have_decl_fcloseall" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "fcloseall" "ac_cv_have_decl_fcloseall" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_fcloseall" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FCLOSEALL $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FCLOSEALL $ac_have_decl" >>confdefs.h - printf "%s\n" "#define __USE_MINGW_ANSI_STDIO 1" >>confdefs.h + printf '%s\n' "#define __USE_MINGW_ANSI_STDIO 1" >>confdefs.h @@ -30733,13 +31491,13 @@ printf "%s\n" "#define HAVE_DECL_FCLOSEALL $ac_have_decl" >>confdefs.h if test $gl_cv_have_include_next = yes; then gl_cv_next_stdio_h='<'stdio.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_stdio_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -30775,10 +31533,11 @@ _ACEOF gl_header=$gl_cv_absolute_stdio_h gl_cv_next_stdio_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stdio_h" >&5 -printf "%s\n" "$gl_cv_next_stdio_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stdio_h" >&5 +printf '%s\n' "$gl_cv_next_stdio_h" >&6; } fi NEXT_STDIO_H=$gl_cv_next_stdio_h @@ -30795,13 +31554,13 @@ printf "%s\n" "$gl_cv_next_stdio_h" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which flavor of printf attribute matches inttypes macros" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking which flavor of printf attribute matches inttypes macros" >&5 printf %s "checking which flavor of printf attribute matches inttypes macros... " >&6; } if test ${gl_cv_func_printf_attribute_flavor+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define __STDC_FORMAT_MACROS 1 @@ -30826,16 +31585,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_printf_attribute_flavor=system -else $as_nop - gl_cv_func_printf_attribute_flavor=gnu +else case e in #( + e) gl_cv_func_printf_attribute_flavor=gnu ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_attribute_flavor" >&5 -printf "%s\n" "$gl_cv_func_printf_attribute_flavor" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_attribute_flavor" >&5 +printf '%s\n' "$gl_cv_func_printf_attribute_flavor" >&6; } if test "$gl_cv_func_printf_attribute_flavor" = gnu; then -printf "%s\n" "#define GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU 1" >>confdefs.h +printf '%s\n' "#define GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU 1" >>confdefs.h fi @@ -30855,32 +31616,35 @@ printf "%s\n" "#define GNULIB_PRINTF_ATTRIBUTE_FLAVOR_GNU 1" >>confdefs.h HAVE_DECL_FCLOSEALL=0 fi -ac_fn_check_decl "$LINENO" "ecvt" "ac_cv_have_decl_ecvt" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "ecvt" "ac_cv_have_decl_ecvt" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_ecvt" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_ECVT $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_ECVT $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "fcvt" "ac_cv_have_decl_fcvt" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "fcvt" "ac_cv_have_decl_fcvt" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_fcvt" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FCVT $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FCVT $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "gcvt" "ac_cv_have_decl_gcvt" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "gcvt" "ac_cv_have_decl_gcvt" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_gcvt" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_GCVT $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_GCVT $ac_have_decl" >>confdefs.h @@ -30895,13 +31659,13 @@ printf "%s\n" "#define HAVE_DECL_GCVT $ac_have_decl" >>confdefs.h if test $gl_cv_have_include_next = yes; then gl_cv_next_stdlib_h='<'stdlib.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_stdlib_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -30937,10 +31701,11 @@ _ACEOF gl_header=$gl_cv_absolute_stdlib_h gl_cv_next_stdlib_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stdlib_h" >&5 -printf "%s\n" "$gl_cv_next_stdlib_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_stdlib_h" >&5 +printf '%s\n' "$gl_cv_next_stdlib_h" >&6; } fi NEXT_STDLIB_H=$gl_cv_next_stdlib_h @@ -30976,24 +31741,26 @@ printf "%s\n" "$gl_cv_next_stdlib_h" >&6; } HAVE_DECL_GCVT=0 fi -ac_fn_check_decl "$LINENO" "stpncpy" "ac_cv_have_decl_stpncpy" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "stpncpy" "ac_cv_have_decl_stpncpy" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_stpncpy" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_STPNCPY $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_STPNCPY $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "strdup" "ac_cv_have_decl_strdup" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "strdup" "ac_cv_have_decl_strdup" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_strdup" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_STRDUP $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_STRDUP $ac_have_decl" >>confdefs.h @@ -31008,13 +31775,13 @@ printf "%s\n" "#define HAVE_DECL_STRDUP $ac_have_decl" >>confdefs.h if test $gl_cv_have_include_next = yes; then gl_cv_next_string_h='<'string.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_string_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -31050,10 +31817,11 @@ _ACEOF gl_header=$gl_cv_absolute_string_h gl_cv_next_string_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_string_h" >&5 -printf "%s\n" "$gl_cv_next_string_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_string_h" >&5 +printf '%s\n' "$gl_cv_next_string_h" >&6; } fi NEXT_STRING_H=$gl_cv_next_string_h @@ -31076,14 +31844,15 @@ printf "%s\n" "$gl_cv_next_string_h" >&6; } -ac_fn_check_decl "$LINENO" "strndup" "ac_cv_have_decl_strndup" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "strndup" "ac_cv_have_decl_strndup" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_strndup" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_STRNDUP $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_STRNDUP $ac_have_decl" >>confdefs.h @@ -31093,13 +31862,13 @@ printf "%s\n" "#define HAVE_DECL_STRNDUP $ac_have_decl" >>confdefs.h if test $ac_cv_header_sys_ioctl_h = yes; then HAVE_SYS_IOCTL_H=1 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether declares ioctl" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether declares ioctl" >&5 printf %s "checking whether declares ioctl... " >&6; } if test ${gl_cv_decl_ioctl_in_sys_ioctl_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -31113,14 +31882,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_decl_ioctl_in_sys_ioctl_h=yes -else $as_nop - gl_cv_decl_ioctl_in_sys_ioctl_h=no +else case e in #( + e) gl_cv_decl_ioctl_in_sys_ioctl_h=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_decl_ioctl_in_sys_ioctl_h" >&5 -printf "%s\n" "$gl_cv_decl_ioctl_in_sys_ioctl_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_decl_ioctl_in_sys_ioctl_h" >&5 +printf '%s\n' "$gl_cv_decl_ioctl_in_sys_ioctl_h" >&6; } else HAVE_SYS_IOCTL_H=0 fi @@ -31137,13 +31908,13 @@ printf "%s\n" "$gl_cv_decl_ioctl_in_sys_ioctl_h" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_sys_ioctl_h='<'sys/ioctl.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_sys_ioctl_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_sys_ioctl_h = yes; then @@ -31185,10 +31956,11 @@ _ACEOF gl_cv_next_sys_ioctl_h='<'sys/ioctl.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_ioctl_h" >&5 -printf "%s\n" "$gl_cv_next_sys_ioctl_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_ioctl_h" >&5 +printf '%s\n' "$gl_cv_next_sys_ioctl_h" >&6; } fi NEXT_SYS_IOCTL_H=$gl_cv_next_sys_ioctl_h @@ -31230,13 +32002,13 @@ printf "%s\n" "$gl_cv_next_sys_ioctl_h" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_sys_resource_h='<'sys/resource.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_sys_resource_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_sys_resource_h = yes; then @@ -31278,10 +32050,11 @@ _ACEOF gl_cv_next_sys_resource_h='<'sys/resource.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_resource_h" >&5 -printf "%s\n" "$gl_cv_next_sys_resource_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_resource_h" >&5 +printf '%s\n' "$gl_cv_next_sys_resource_h" >&6; } fi NEXT_SYS_RESOURCE_H=$gl_cv_next_sys_resource_h @@ -31328,13 +32101,13 @@ printf "%s\n" "$gl_cv_next_sys_resource_h" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_sys_times_h='<'sys/times.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_sys_times_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_sys_times_h = yes; then @@ -31376,10 +32149,11 @@ _ACEOF gl_cv_next_sys_times_h='<'sys/times.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_times_h" >&5 -printf "%s\n" "$gl_cv_next_sys_times_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_times_h" >&5 +printf '%s\n' "$gl_cv_next_sys_times_h" >&6; } fi NEXT_SYS_TIMES_H=$gl_cv_next_sys_times_h @@ -31404,11 +32178,12 @@ printf "%s\n" "$gl_cv_next_sys_times_h" >&6; } if test "x$ac_cv_type_struct_tms" = xyes then : -printf "%s\n" "#define HAVE_STRUCT_TMS 1" >>confdefs.h +printf '%s\n' "#define HAVE_STRUCT_TMS 1" >>confdefs.h -else $as_nop - HAVE_STRUCT_TMS=0 +else case e in #( + e) HAVE_STRUCT_TMS=0 ;; +esac fi else @@ -31439,7 +32214,7 @@ fi -printf "%s\n" "#define _USE_STD_STAT 1" >>confdefs.h +printf '%s\n' "#define _USE_STD_STAT 1" >>confdefs.h @@ -31453,13 +32228,13 @@ printf "%s\n" "#define _USE_STD_STAT 1" >>confdefs.h if test $gl_cv_have_include_next = yes; then gl_cv_next_sys_types_h='<'sys/types.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_sys_types_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -31495,10 +32270,11 @@ _ACEOF gl_header=$gl_cv_absolute_sys_types_h gl_cv_next_sys_types_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_types_h" >&5 -printf "%s\n" "$gl_cv_next_sys_types_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_types_h" >&5 +printf '%s\n' "$gl_cv_next_sys_types_h" >&6; } fi NEXT_SYS_TYPES_H=$gl_cv_next_sys_types_h @@ -31546,13 +32322,13 @@ printf "%s\n" "$gl_cv_next_sys_types_h" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_sys_wait_h='<'sys/wait.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_sys_wait_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_sys_wait_h = yes; then @@ -31594,10 +32370,11 @@ _ACEOF gl_cv_next_sys_wait_h='<'sys/wait.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_wait_h" >&5 -printf "%s\n" "$gl_cv_next_sys_wait_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_sys_wait_h" >&5 +printf '%s\n' "$gl_cv_next_sys_wait_h" >&6; } fi NEXT_SYS_WAIT_H=$gl_cv_next_sys_wait_h @@ -31646,13 +32423,13 @@ printf "%s\n" "$gl_cv_next_sys_wait_h" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_termios_h='<'termios.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_termios_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_termios_h = yes; then @@ -31694,10 +32471,11 @@ _ACEOF gl_cv_next_termios_h='<'termios.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_termios_h" >&5 -printf "%s\n" "$gl_cv_next_termios_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_termios_h" >&5 +printf '%s\n' "$gl_cv_next_termios_h" >&6; } fi NEXT_TERMIOS_H=$gl_cv_next_termios_h @@ -31750,13 +32528,13 @@ printf "%s\n" "$gl_cv_next_termios_h" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct timespec in " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for struct timespec in " >&5 printf %s "checking for struct timespec in ... " >&6; } if test ${gl_cv_sys_struct_timespec_in_time_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -31771,13 +32549,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_sys_struct_timespec_in_time_h=yes -else $as_nop - gl_cv_sys_struct_timespec_in_time_h=no +else case e in #( + e) gl_cv_sys_struct_timespec_in_time_h=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_time_h" >&5 -printf "%s\n" "$gl_cv_sys_struct_timespec_in_time_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_time_h" >&5 +printf '%s\n' "$gl_cv_sys_struct_timespec_in_time_h" >&6; } TIME_H_DEFINES_STRUCT_TIMESPEC=0 SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=0 @@ -31786,13 +32566,13 @@ printf "%s\n" "$gl_cv_sys_struct_timespec_in_time_h" >&6; } if test $gl_cv_sys_struct_timespec_in_time_h = yes; then TIME_H_DEFINES_STRUCT_TIMESPEC=1 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct timespec in " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for struct timespec in " >&5 printf %s "checking for struct timespec in ... " >&6; } if test ${gl_cv_sys_struct_timespec_in_sys_time_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -31807,23 +32587,25 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_sys_struct_timespec_in_sys_time_h=yes -else $as_nop - gl_cv_sys_struct_timespec_in_sys_time_h=no +else case e in #( + e) gl_cv_sys_struct_timespec_in_sys_time_h=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_sys_time_h" >&5 -printf "%s\n" "$gl_cv_sys_struct_timespec_in_sys_time_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_sys_time_h" >&5 +printf '%s\n' "$gl_cv_sys_struct_timespec_in_sys_time_h" >&6; } if test $gl_cv_sys_struct_timespec_in_sys_time_h = yes; then SYS_TIME_H_DEFINES_STRUCT_TIMESPEC=1 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct timespec in " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for struct timespec in " >&5 printf %s "checking for struct timespec in ... " >&6; } if test ${gl_cv_sys_struct_timespec_in_pthread_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -31838,23 +32620,25 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_sys_struct_timespec_in_pthread_h=yes -else $as_nop - gl_cv_sys_struct_timespec_in_pthread_h=no +else case e in #( + e) gl_cv_sys_struct_timespec_in_pthread_h=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_pthread_h" >&5 -printf "%s\n" "$gl_cv_sys_struct_timespec_in_pthread_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_pthread_h" >&5 +printf '%s\n' "$gl_cv_sys_struct_timespec_in_pthread_h" >&6; } if test $gl_cv_sys_struct_timespec_in_pthread_h = yes; then PTHREAD_H_DEFINES_STRUCT_TIMESPEC=1 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for struct timespec in " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for struct timespec in " >&5 printf %s "checking for struct timespec in ... " >&6; } if test ${gl_cv_sys_struct_timespec_in_unistd_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -31869,13 +32653,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_sys_struct_timespec_in_unistd_h=yes -else $as_nop - gl_cv_sys_struct_timespec_in_unistd_h=no +else case e in #( + e) gl_cv_sys_struct_timespec_in_unistd_h=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_unistd_h" >&5 -printf "%s\n" "$gl_cv_sys_struct_timespec_in_unistd_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_timespec_in_unistd_h" >&5 +printf '%s\n' "$gl_cv_sys_struct_timespec_in_unistd_h" >&6; } if test $gl_cv_sys_struct_timespec_in_unistd_h = yes; then UNISTD_H_DEFINES_STRUCT_TIMESPEC=1 fi @@ -31901,13 +32687,13 @@ printf "%s\n" "$gl_cv_sys_struct_timespec_in_unistd_h" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_time_h='<'time.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_time_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -31943,10 +32729,11 @@ _ACEOF gl_header=$gl_cv_absolute_time_h gl_cv_next_time_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_time_h" >&5 -printf "%s\n" "$gl_cv_next_time_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_time_h" >&5 +printf '%s\n' "$gl_cv_next_time_h" >&6; } fi NEXT_TIME_H=$gl_cv_next_time_h @@ -31966,13 +32753,13 @@ printf "%s\n" "$gl_cv_next_time_h" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for TIME_UTC in " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for TIME_UTC in " >&5 printf %s "checking for TIME_UTC in ... " >&6; } if test ${gl_cv_time_h_has_TIME_UTC+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -31987,13 +32774,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_time_h_has_TIME_UTC=yes -else $as_nop - gl_cv_time_h_has_TIME_UTC=no +else case e in #( + e) gl_cv_time_h_has_TIME_UTC=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_time_h_has_TIME_UTC" >&5 -printf "%s\n" "$gl_cv_time_h_has_TIME_UTC" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_time_h_has_TIME_UTC" >&5 +printf '%s\n' "$gl_cv_time_h_has_TIME_UTC" >&6; } if test $gl_cv_time_h_has_TIME_UTC = yes; then TIME_H_DEFINES_TIME_UTC=1 else @@ -32055,18 +32844,19 @@ printf "%s\n" "$gl_cv_time_h_has_TIME_UTC" >&6; } case "$host_os" in *-musl*) -printf "%s\n" "#define MUSL_LIBC 1" >>confdefs.h +printf '%s\n' "#define MUSL_LIBC 1" >>confdefs.h ;; esac -ac_fn_check_decl "$LINENO" "execvpe" "ac_cv_have_decl_execvpe" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "execvpe" "ac_cv_have_decl_execvpe" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_execvpe" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_EXECVPE $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_EXECVPE $ac_have_decl" >>confdefs.h @@ -32083,13 +32873,13 @@ printf "%s\n" "#define HAVE_DECL_EXECVPE $ac_have_decl" >>confdefs.h if test $gl_cv_have_include_next = yes; then gl_cv_next_unistd_h='<'unistd.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_unistd_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_unistd_h = yes; then @@ -32131,10 +32921,11 @@ _ACEOF gl_cv_next_unistd_h='<'unistd.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_unistd_h" >&5 -printf "%s\n" "$gl_cv_next_unistd_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_unistd_h" >&5 +printf '%s\n' "$gl_cv_next_unistd_h" >&6; } fi NEXT_UNISTD_H=$gl_cv_next_unistd_h @@ -32201,150 +32992,165 @@ q LIBUNISTRING_VERSION_SUBMINOR=`echo "$LIBUNISTRING_VERSION" | sed -n -e "$gl_libunistring_sed_extract_subminor"` fi -ac_fn_check_decl "$LINENO" "clearerr_unlocked" "ac_cv_have_decl_clearerr_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "clearerr_unlocked" "ac_cv_have_decl_clearerr_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_clearerr_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_CLEARERR_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_CLEARERR_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "feof_unlocked" "ac_cv_have_decl_feof_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "feof_unlocked" "ac_cv_have_decl_feof_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_feof_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FEOF_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FEOF_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "ferror_unlocked" "ac_cv_have_decl_ferror_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "ferror_unlocked" "ac_cv_have_decl_ferror_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_ferror_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FERROR_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FERROR_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "fflush_unlocked" "ac_cv_have_decl_fflush_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "fflush_unlocked" "ac_cv_have_decl_fflush_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_fflush_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FFLUSH_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FFLUSH_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "fgets_unlocked" "ac_cv_have_decl_fgets_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "fgets_unlocked" "ac_cv_have_decl_fgets_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_fgets_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FGETS_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FGETS_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "fputc_unlocked" "ac_cv_have_decl_fputc_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "fputc_unlocked" "ac_cv_have_decl_fputc_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_fputc_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FPUTC_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FPUTC_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "fputs_unlocked" "ac_cv_have_decl_fputs_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "fputs_unlocked" "ac_cv_have_decl_fputs_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_fputs_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FPUTS_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FPUTS_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "fread_unlocked" "ac_cv_have_decl_fread_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "fread_unlocked" "ac_cv_have_decl_fread_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_fread_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FREAD_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FREAD_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "fwrite_unlocked" "ac_cv_have_decl_fwrite_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "fwrite_unlocked" "ac_cv_have_decl_fwrite_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_fwrite_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FWRITE_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FWRITE_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "getc_unlocked" "ac_cv_have_decl_getc_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "getc_unlocked" "ac_cv_have_decl_getc_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_getc_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_GETC_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_GETC_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "getchar_unlocked" "ac_cv_have_decl_getchar_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "getchar_unlocked" "ac_cv_have_decl_getchar_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_getchar_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_GETCHAR_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_GETCHAR_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "putc_unlocked" "ac_cv_have_decl_putc_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "putc_unlocked" "ac_cv_have_decl_putc_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_putc_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_PUTC_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_PUTC_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "putchar_unlocked" "ac_cv_have_decl_putchar_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "putchar_unlocked" "ac_cv_have_decl_putchar_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_putchar_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_PUTCHAR_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_PUTCHAR_UNLOCKED $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "unsetenv" "ac_cv_have_decl_unsetenv" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "unsetenv" "ac_cv_have_decl_unsetenv" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_unsetenv" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_UNSETENV $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_UNSETENV $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "vsnprintf" "ac_cv_have_decl_vsnprintf" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "vsnprintf" "ac_cv_have_decl_vsnprintf" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_vsnprintf" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_VSNPRINTF $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_VSNPRINTF $ac_have_decl" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether uses 'inline' correctly" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether uses 'inline' correctly" >&5 printf %s "checking whether uses 'inline' correctly... " >&6; } if test ${gl_cv_header_wchar_h_correct_inline+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_cv_header_wchar_h_correct_inline=yes +else case e in #( + e) gl_cv_header_wchar_h_correct_inline=yes case "$host_os" in *-gnu* | gnu*) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -32363,7 +33169,7 @@ _ACEOF && { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -32379,7 +33185,7 @@ _ACEOF && { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? - printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if $CC -o conftest$ac_exeext $CFLAGS $LDFLAGS conftest1.$ac_objext conftest2.$ac_objext $LIBS >&5 2>&1; then : @@ -32392,10 +33198,11 @@ _ACEOF rm -f conftest12.c conftest12.$ac_objext conftest$ac_exeext ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_wchar_h_correct_inline" >&5 -printf "%s\n" "$gl_cv_header_wchar_h_correct_inline" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_wchar_h_correct_inline" >&5 +printf '%s\n' "$gl_cv_header_wchar_h_correct_inline" >&6; } if test $gl_cv_header_wchar_h_correct_inline = no; then as_fn_error $? " cannot be used with this compiler ($CC $CFLAGS $CPPFLAGS). This is a known interoperability problem of glibc <= 2.5 with gcc >= 4.3 in @@ -32423,13 +33230,13 @@ Configuration aborted." "$LINENO" 5 if test $gl_cv_have_include_next = yes; then gl_cv_next_wchar_h='<'wchar.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_wchar_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_wchar_h = yes; then @@ -32471,10 +33278,11 @@ _ACEOF gl_cv_next_wchar_h='<'wchar.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_wchar_h" >&5 -printf "%s\n" "$gl_cv_next_wchar_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_wchar_h" >&5 +printf '%s\n' "$gl_cv_next_wchar_h" >&6; } fi NEXT_WCHAR_H=$gl_cv_next_wchar_h @@ -32518,27 +33326,28 @@ printf "%s\n" "$gl_cv_next_wchar_h" >&6; } ac_fn_check_decl "$LINENO" "wcsdup" "ac_cv_have_decl_wcsdup" " #include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_wcsdup" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_WCSDUP $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_WCSDUP $ac_have_decl" >>confdefs.h if test $ac_cv_have_decl_wcsdup = no; then HAVE_DECL_WCSDUP=0 fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking POSIX termios" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking POSIX termios" >&5 printf %s "checking POSIX termios... " >&6; } if test ${ac_cv_sys_posix_termios+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -32556,23 +33365,25 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_sys_posix_termios=yes -else $as_nop - ac_cv_sys_posix_termios=no +else case e in #( + e) ac_cv_sys_posix_termios=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext + conftest$ac_exeext conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_posix_termios" >&5 -printf "%s\n" "$ac_cv_sys_posix_termios" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_posix_termios" >&5 +printf '%s\n' "$ac_cv_sys_posix_termios" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether use of TIOCGWINSZ requires termios.h" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether use of TIOCGWINSZ requires termios.h" >&5 printf %s "checking whether use of TIOCGWINSZ requires termios.h... " >&6; } if test ${gl_cv_sys_tiocgwinsz_needs_termios_h+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_cv_sys_tiocgwinsz_needs_termios_h=no +else case e in #( + e) gl_cv_sys_tiocgwinsz_needs_termios_h=no if test $ac_cv_sys_posix_termios = yes; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -32585,17 +33396,18 @@ else $as_nop _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : gl_cv_sys_tiocgwinsz_needs_termios_h=yes fi rm -rf conftest* fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_tiocgwinsz_needs_termios_h" >&5 -printf "%s\n" "$gl_cv_sys_tiocgwinsz_needs_termios_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_tiocgwinsz_needs_termios_h" >&5 +printf '%s\n' "$gl_cv_sys_tiocgwinsz_needs_termios_h" >&6; } HAVE_OPENDIR=1; @@ -32666,13 +33478,13 @@ printf "%s\n" "$gl_cv_sys_tiocgwinsz_needs_termios_h" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_dirent_h='<'dirent.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_dirent_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_dirent_h = yes; then @@ -32714,10 +33526,11 @@ _ACEOF gl_cv_next_dirent_h='<'dirent.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_dirent_h" >&5 -printf "%s\n" "$gl_cv_next_dirent_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_dirent_h" >&5 +printf '%s\n' "$gl_cv_next_dirent_h" >&6; } fi NEXT_DIRENT_H=$gl_cv_next_dirent_h @@ -32744,14 +33557,15 @@ printf "%s\n" "$gl_cv_next_dirent_h" >&6; } -ac_fn_check_decl "$LINENO" "fchdir" "ac_cv_have_decl_fchdir" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "fchdir" "ac_cv_have_decl_fchdir" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_fchdir" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FCHDIR $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FCHDIR $ac_have_decl" >>confdefs.h @@ -32768,47 +33582,50 @@ printf "%s\n" "#define HAVE_DECL_FCHDIR $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "getdelim" "ac_cv_have_decl_getdelim" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "getdelim" "ac_cv_have_decl_getdelim" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_getdelim" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_GETDELIM $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_GETDELIM $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "getdtablesize" "ac_cv_have_decl_getdtablesize" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "getdtablesize" "ac_cv_have_decl_getdtablesize" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_getdtablesize" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_GETDTABLESIZE $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_GETDTABLESIZE $ac_have_decl" >>confdefs.h -ac_fn_check_decl "$LINENO" "getline" "ac_cv_have_decl_getline" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "getline" "ac_cv_have_decl_getline" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_getline" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_GETLINE $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_GETLINE $ac_have_decl" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether setlocale (LC_ALL, NULL) is multithread-safe" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether setlocale (LC_ALL, NULL) is multithread-safe" >&5 printf %s "checking whether setlocale (LC_ALL, NULL) is multithread-safe... " >&6; } if test ${gl_cv_func_setlocale_null_all_mtsafe+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in # Guess no on musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin. *-musl* | darwin* | freebsd* | midnightbsd* | netbsd* | openbsd* | aix* | haiku* | cygwin*) gl_cv_func_setlocale_null_all_mtsafe=no ;; @@ -32819,10 +33636,11 @@ else $as_nop *) gl_cv_func_setlocale_null_all_mtsafe="$gl_cross_guess_normal" ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_setlocale_null_all_mtsafe" >&5 -printf "%s\n" "$gl_cv_func_setlocale_null_all_mtsafe" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_setlocale_null_all_mtsafe" >&5 +printf '%s\n' "$gl_cv_func_setlocale_null_all_mtsafe" >&6; } case "$host_os" in mingw*) ;; *) @@ -32836,16 +33654,16 @@ printf "%s\n" "$gl_cv_func_setlocale_null_all_mtsafe" >&6; } *) SETLOCALE_NULL_ALL_MTSAFE=0 ;; esac -printf "%s\n" "#define SETLOCALE_NULL_ALL_MTSAFE $SETLOCALE_NULL_ALL_MTSAFE" >>confdefs.h +printf '%s\n' "#define SETLOCALE_NULL_ALL_MTSAFE $SETLOCALE_NULL_ALL_MTSAFE" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether setlocale (category, NULL) is multithread-safe" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether setlocale (category, NULL) is multithread-safe" >&5 printf %s "checking whether setlocale (category, NULL) is multithread-safe... " >&6; } if test ${gl_cv_func_setlocale_null_one_mtsafe+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in # Guess no on OpenBSD, AIX. openbsd* | aix*) gl_cv_func_setlocale_null_one_mtsafe=no ;; @@ -32856,10 +33674,11 @@ else $as_nop *) gl_cv_func_setlocale_null_one_mtsafe="$gl_cross_guess_normal" ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_setlocale_null_one_mtsafe" >&5 -printf "%s\n" "$gl_cv_func_setlocale_null_one_mtsafe" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_setlocale_null_one_mtsafe" >&5 +printf '%s\n' "$gl_cv_func_setlocale_null_one_mtsafe" >&6; } case "$host_os" in mingw*) ;; *) @@ -32873,7 +33692,7 @@ printf "%s\n" "$gl_cv_func_setlocale_null_one_mtsafe" >&6; } *) SETLOCALE_NULL_ONE_MTSAFE=0 ;; esac -printf "%s\n" "#define SETLOCALE_NULL_ONE_MTSAFE $SETLOCALE_NULL_ONE_MTSAFE" >>confdefs.h +printf '%s\n' "#define SETLOCALE_NULL_ONE_MTSAFE $SETLOCALE_NULL_ONE_MTSAFE" >>confdefs.h if test $SETLOCALE_NULL_ALL_MTSAFE = 0 || test $SETLOCALE_NULL_ONE_MTSAFE = 0; then @@ -32882,13 +33701,13 @@ printf "%s\n" "#define SETLOCALE_NULL_ONE_MTSAFE $SETLOCALE_NULL_ONE_MTSAFE" >>c *) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether imported symbols can be declared weak" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether imported symbols can be declared weak" >&5 printf %s "checking whether imported symbols can be declared weak... " >&6; } if test ${gl_cv_have_weak+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in cygwin*) gl_cv_have_weak="guessing no" ;; @@ -32923,17 +33742,18 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Extensible Linking Format" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Extensible Linking Format" >/dev/null 2>&1 then : gl_cv_have_weak="guessing yes" -else $as_nop - gl_cv_have_weak="guessing no" +else case e in #( + e) gl_cv_have_weak="guessing no" ;; +esac fi rm -rf conftest* -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -32946,11 +33766,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_have_weak=yes -else $as_nop - gl_cv_have_weak=no +else case e in #( + e) gl_cv_have_weak=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi @@ -32980,14 +33802,15 @@ EOF esac ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_weak" >&5 -printf "%s\n" "$gl_cv_have_weak" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_weak" >&5 +printf '%s\n' "$gl_cv_have_weak" >&6; } case "$gl_cv_have_weak" in *yes) -printf "%s\n" "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h +printf '%s\n' "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h ;; esac @@ -33019,13 +33842,13 @@ printf "%s\n" "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether locale.h defines locale_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether locale.h defines locale_t" >&5 printf %s "checking whether locale.h defines locale_t... " >&6; } if test ${gl_cv_header_locale_has_locale_t+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include locale_t x; @@ -33040,14 +33863,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_header_locale_has_locale_t=yes -else $as_nop - gl_cv_header_locale_has_locale_t=no +else case e in #( + e) gl_cv_header_locale_has_locale_t=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_locale_has_locale_t" >&5 -printf "%s\n" "$gl_cv_header_locale_has_locale_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_locale_has_locale_t" >&5 +printf '%s\n' "$gl_cv_header_locale_has_locale_t" >&6; } if test $ac_cv_header_xlocale_h = yes; then @@ -33082,18 +33907,18 @@ printf "%s\n" "$gl_cv_header_locale_has_locale_t" >&6; } case "$host_os" in solaris*) -printf "%s\n" "#define _LCONV_C99 1" >>confdefs.h +printf '%s\n' "#define _LCONV_C99 1" >>confdefs.h ;; esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether locale.h conforms to POSIX:2001" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether locale.h conforms to POSIX:2001" >&5 printf %s "checking whether locale.h conforms to POSIX:2001... " >&6; } if test ${gl_cv_header_locale_h_posix2001+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int x = LC_MESSAGES; @@ -33109,21 +33934,23 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_header_locale_h_posix2001=yes -else $as_nop - gl_cv_header_locale_h_posix2001=no +else case e in #( + e) gl_cv_header_locale_h_posix2001=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_locale_h_posix2001" >&5 -printf "%s\n" "$gl_cv_header_locale_h_posix2001" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_locale_h_posix2001" >&5 +printf '%s\n' "$gl_cv_header_locale_h_posix2001" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether struct lconv is properly defined" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether struct lconv is properly defined" >&5 printf %s "checking whether struct lconv is properly defined... " >&6; } if test ${gl_cv_sys_struct_lconv_ok+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include struct lconv l; @@ -33140,14 +33967,16 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_sys_struct_lconv_ok=yes -else $as_nop - gl_cv_sys_struct_lconv_ok=no +else case e in #( + e) gl_cv_sys_struct_lconv_ok=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_lconv_ok" >&5 -printf "%s\n" "$gl_cv_sys_struct_lconv_ok" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_lconv_ok" >&5 +printf '%s\n' "$gl_cv_sys_struct_lconv_ok" >&6; } if test $gl_cv_sys_struct_lconv_ok = no; then case "$host_os" in mingw*) @@ -33160,11 +33989,12 @@ printf "%s\n" "$gl_cv_sys_struct_lconv_ok" >&6; } _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Special" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Special" >/dev/null 2>&1 then : -else $as_nop - REPLACE_STRUCT_LCONV=1 +else case e in #( + e) REPLACE_STRUCT_LCONV=1 ;; +esac fi rm -rf conftest* @@ -33184,13 +34014,13 @@ rm -rf conftest* if test $gl_cv_have_include_next = yes; then gl_cv_next_locale_h='<'locale.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_locale_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -33226,10 +34056,11 @@ _ACEOF gl_header=$gl_cv_absolute_locale_h gl_cv_next_locale_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_locale_h" >&5 -printf "%s\n" "$gl_cv_next_locale_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_locale_h" >&5 +printf '%s\n' "$gl_cv_next_locale_h" >&6; } fi NEXT_LOCALE_H=$gl_cv_next_locale_h @@ -33272,14 +34103,15 @@ printf "%s\n" "$gl_cv_next_locale_h" >&6; } -ac_fn_check_decl "$LINENO" "memrchr" "ac_cv_have_decl_memrchr" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "memrchr" "ac_cv_have_decl_memrchr" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_memrchr" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_MEMRCHR $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_MEMRCHR $ac_have_decl" >>confdefs.h @@ -33298,13 +34130,13 @@ printf "%s\n" "#define HAVE_DECL_MEMRCHR $ac_have_decl" >>confdefs.h if test $gl_cv_have_include_next = yes; then gl_cv_next_strings_h='<'strings.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_strings_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test $ac_cv_header_strings_h = yes; then @@ -33346,10 +34178,11 @@ _ACEOF gl_cv_next_strings_h='<'strings.h'>' fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_strings_h" >&5 -printf "%s\n" "$gl_cv_next_strings_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_strings_h" >&5 +printf '%s\n' "$gl_cv_next_strings_h" >&6; } fi NEXT_STRINGS_H=$gl_cv_next_strings_h @@ -33376,14 +34209,15 @@ printf "%s\n" "$gl_cv_next_strings_h" >&6; } -ac_fn_check_decl "$LINENO" "strnlen" "ac_cv_have_decl_strnlen" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" +ac_fn_check_decl "$LINENO" "strnlen" "ac_cv_have_decl_strnlen" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_strnlen" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_STRNLEN $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_STRNLEN $ac_have_decl" >>confdefs.h if false; then @@ -33445,7 +34279,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_ACCESS 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_ACCESS 1" >>confdefs.h @@ -33457,13 +34291,13 @@ printf "%s\n" "#define GNULIB_TEST_ACCESS 1" >>confdefs.h # Define an additional variable used in the Makefile substitution. if test $ac_cv_working_alloca_h = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for alloca as a compiler built-in" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for alloca as a compiler built-in" >&5 printf %s "checking for alloca as a compiler built-in... " >&6; } if test ${gl_cv_rpl_alloca+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -33473,21 +34307,23 @@ else $as_nop _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Need own alloca" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Need own alloca" >/dev/null 2>&1 then : gl_cv_rpl_alloca=yes -else $as_nop - gl_cv_rpl_alloca=no +else case e in #( + e) gl_cv_rpl_alloca=no ;; +esac fi rm -rf conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_rpl_alloca" >&5 -printf "%s\n" "$gl_cv_rpl_alloca" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_rpl_alloca" >&5 +printf '%s\n' "$gl_cv_rpl_alloca" >&6; } if test $gl_cv_rpl_alloca = yes; then -printf "%s\n" "#define HAVE_ALLOCA 1" >>confdefs.h +printf '%s\n' "#define HAVE_ALLOCA 1" >>confdefs.h ALLOCA_H=alloca.h else @@ -33514,7 +34350,7 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable assertions" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to enable assertions" >&5 printf %s "checking whether to enable assertions... " >&6; } # Check whether --enable-assert was given. if test ${enable_assert+y} @@ -33522,30 +34358,31 @@ then : enableval=$enable_assert; if test "x$enableval" = xno then : -printf "%s\n" "#define NDEBUG 1" >>confdefs.h +printf '%s\n' "#define NDEBUG 1" >>confdefs.h elif test "x$enableval" != xyes then : - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: invalid argument supplied to --enable-assert" >&5 -printf "%s\n" "$as_me: WARNING: invalid argument supplied to --enable-assert" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: invalid argument supplied to --enable-assert" >&5 +printf '%s\n' "$as_me: WARNING: invalid argument supplied to --enable-assert" >&2;} enable_assert=yes fi -else $as_nop - enable_assert=yes +else case e in #( + e) enable_assert=yes ;; +esac fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_assert" >&5 -printf "%s\n" "$enable_assert" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $enable_assert" >&5 +printf '%s\n' "$enable_assert" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __builtin_expect" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for __builtin_expect" >&5 printf %s "checking for __builtin_expect... " >&6; } if test ${gl_cv___builtin_expect+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int @@ -33558,8 +34395,8 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv___builtin_expect=yes -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -33573,22 +34410,25 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv___builtin_expect="in " -else $as_nop - gl_cv___builtin_expect=no +else case e in #( + e) gl_cv___builtin_expect=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext + conftest$ac_exeext conftest.$ac_ext ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext + conftest$ac_exeext conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv___builtin_expect" >&5 -printf "%s\n" "$gl_cv___builtin_expect" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv___builtin_expect" >&5 +printf '%s\n' "$gl_cv___builtin_expect" >&6; } if test "$gl_cv___builtin_expect" = yes; then - printf "%s\n" "#define HAVE___BUILTIN_EXPECT 1" >>confdefs.h + printf '%s\n' "#define HAVE___BUILTIN_EXPECT 1" >>confdefs.h elif test "$gl_cv___builtin_expect" = "in "; then - printf "%s\n" "#define HAVE___BUILTIN_EXPECT 2" >>confdefs.h + printf '%s\n' "#define HAVE___BUILTIN_EXPECT 2" >>confdefs.h fi @@ -33598,22 +34438,22 @@ printf "%s\n" "$gl_cv___builtin_expect" >&6; } if test $REPLACE_CALLOC = 0; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether calloc (0, n) and calloc (n, 0) return nonnull" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether calloc (0, n) and calloc (n, 0) return nonnull" >&5 printf %s "checking whether calloc (0, n) and calloc (n, 0) return nonnull... " >&6; } if test ${ac_cv_func_calloc_0_nonnull+y} then : printf %s "(cached) " >&6 -else $as_nop - if test $cross_compiling != yes; then +else case e in #( + e) if test $cross_compiling != yes; then ac_cv_func_calloc_0_nonnull=yes if test "$cross_compiling" = yes then : - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling -See \`config.log' for more details" "$LINENO" 5; } -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +See 'config.log' for more details" "$LINENO" 5; } +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int @@ -33633,11 +34473,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : -else $as_nop - ac_cv_func_calloc_0_nonnull=no +else case e in #( + e) ac_cv_func_calloc_0_nonnull=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi else @@ -33652,10 +34494,11 @@ fi *) ac_cv_func_calloc_0_nonnull="$gl_cross_guess_normal" ;; esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_calloc_0_nonnull" >&5 -printf "%s\n" "$ac_cv_func_calloc_0_nonnull" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_calloc_0_nonnull" >&5 +printf '%s\n' "$ac_cv_func_calloc_0_nonnull" >&6; } case $ac_cv_func_calloc_0_nonnull in #( *yes) : ;; #( @@ -33711,7 +34554,7 @@ esac -printf "%s\n" "#define GNULIB_TEST_CALLOC_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_CALLOC_POSIX 1" >>confdefs.h @@ -33732,12 +34575,12 @@ printf "%s\n" "#define GNULIB_TEST_CALLOC_POSIX 1" >>confdefs.h -printf "%s\n" "#define GNULIB_CANONICALIZE 1" >>confdefs.h +printf '%s\n' "#define GNULIB_CANONICALIZE 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_CANONICALIZE 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_CANONICALIZE 1" >>confdefs.h @@ -33755,7 +34598,7 @@ printf "%s\n" "#define GNULIB_TEST_CANONICALIZE 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_CANONICALIZE_FILE_NAME 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_CANONICALIZE_FILE_NAME 1" >>confdefs.h @@ -33797,7 +34640,7 @@ printf "%s\n" "#define GNULIB_TEST_CANONICALIZE_FILE_NAME 1" >>confdefs.h fi -printf "%s\n" "#define GNULIB_CANONICALIZE_LGPL 1" >>confdefs.h +printf '%s\n' "#define GNULIB_CANONICALIZE_LGPL 1" >>confdefs.h @@ -33815,7 +34658,7 @@ printf "%s\n" "#define GNULIB_CANONICALIZE_LGPL 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_CANONICALIZE_FILE_NAME 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_CANONICALIZE_FILE_NAME 1" >>confdefs.h @@ -33834,7 +34677,7 @@ printf "%s\n" "#define GNULIB_TEST_CANONICALIZE_FILE_NAME 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_REALPATH 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_REALPATH 1" >>confdefs.h @@ -33852,20 +34695,26 @@ printf "%s\n" "#define GNULIB_TEST_REALPATH 1" >>confdefs.h LIB_CLOCK_GETTIME= gl_saved_libs=$LIBS - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5 printf %s "checking for library containing clock_gettime... " >&6; } if test ${ac_cv_search_clock_gettime+y} then : printf %s "(cached) " >&6 -else $as_nop - ac_func_search_save_LIBS=$LIBS +else case e in #( + e) ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -char clock_gettime (); + builtin and then its argument prototype would still apply. + The 'extern "C"' is for builds by C++ compilers; + although this is not generally supported in C code supporting it here + has little cost and some practical benefit (sr 110532). */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (void); int main (void) { @@ -33896,14 +34745,16 @@ done if test ${ac_cv_search_clock_gettime+y} then : -else $as_nop - ac_cv_search_clock_gettime=no +else case e in #( + e) ac_cv_search_clock_gettime=no ;; +esac fi rm conftest.$ac_ext -LIBS=$ac_func_search_save_LIBS +LIBS=$ac_func_search_save_LIBS ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 -printf "%s\n" "$ac_cv_search_clock_gettime" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5 +printf '%s\n' "$ac_cv_search_clock_gettime" >&6; } ac_res=$ac_cv_search_clock_gettime if test "$ac_res" != no then : @@ -33915,13 +34766,13 @@ fi ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime" if test "x$ac_cv_func_clock_gettime" = xyes then : - printf "%s\n" "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h + printf '%s\n' "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "clock_settime" "ac_cv_func_clock_settime" if test "x$ac_cv_func_clock_settime" = xyes then : - printf "%s\n" "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h + printf '%s\n' "#define HAVE_CLOCK_SETTIME 1" >>confdefs.h fi @@ -33929,7 +34780,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_CLOEXEC 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_CLOEXEC 1" >>confdefs.h @@ -33949,7 +34800,7 @@ printf "%s\n" "#define GNULIB_TEST_CLOEXEC 1" >>confdefs.h ac_fn_c_check_header_compile "$LINENO" "winsock2.h" "ac_cv_header_winsock2_h" "$ac_includes_default" if test "x$ac_cv_header_winsock2_h" = xyes then : - printf "%s\n" "#define HAVE_WINSOCK2_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_WINSOCK2_H 1" >>confdefs.h fi @@ -34009,13 +34860,13 @@ fi -printf "%s\n" "#define GNULIB_TEST_CLOSE 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_CLOSE 1" >>confdefs.h -printf "%s\n" "#define GNULIB_CLOSE_STREAM 1" >>confdefs.h +printf '%s\n' "#define GNULIB_CLOSE_STREAM 1" >>confdefs.h @@ -34034,18 +34885,18 @@ printf "%s\n" "#define GNULIB_CLOSE_STREAM 1" >>confdefs.h -printf "%s\n" "#define GNULIB_DIRNAME 1" >>confdefs.h +printf '%s\n' "#define GNULIB_DIRNAME 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether // is distinct from /" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether // is distinct from /" >&5 printf %s "checking whether // is distinct from /... " >&6; } if test ${gl_cv_double_slash_root+y} then : printf %s "(cached) " >&6 -else $as_nop - if test x"$cross_compiling" = xyes ; then +else case e in #( + e) if test x"$cross_compiling" = xyes ; then # When cross-compiling, there is no way to tell whether // is special # short of a list of hosts. However, the only known hosts to date # that have a distinct // are Apollo DomainOS (too old to port to), @@ -34067,26 +34918,27 @@ else $as_nop else gl_cv_double_slash_root=yes fi - fi + fi ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_double_slash_root" >&5 -printf "%s\n" "$gl_cv_double_slash_root" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_double_slash_root" >&5 +printf '%s\n' "$gl_cv_double_slash_root" >&6; } if test "$gl_cv_double_slash_root" = yes; then -printf "%s\n" "#define DOUBLE_SLASH_IS_DISTINCT_ROOT 1" >>confdefs.h +printf '%s\n' "#define DOUBLE_SLASH_IS_DISTINCT_ROOT 1" >>confdefs.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether dup2 works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether dup2 works" >&5 printf %s "checking whether dup2 works... " >&6; } if test ${gl_cv_func_dup2_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in mingw*) # on this platform, dup2 always returns 0 for success @@ -34105,8 +34957,8 @@ then : gl_cv_func_dup2_works="guessing no" ;; *) gl_cv_func_dup2_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -34176,17 +35028,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_dup2_works=yes -else $as_nop - gl_cv_func_dup2_works=no +else case e in #( + e) gl_cv_func_dup2_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_dup2_works" >&5 -printf "%s\n" "$gl_cv_func_dup2_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_dup2_works" >&5 +printf '%s\n' "$gl_cv_func_dup2_works" >&6; } case "$gl_cv_func_dup2_works" in *yes) ;; *) @@ -34194,7 +35049,7 @@ printf "%s\n" "$gl_cv_func_dup2_works" >&6; } ac_fn_c_check_func "$LINENO" "setdtablesize" "ac_cv_func_setdtablesize" if test "x$ac_cv_func_setdtablesize" = xyes then : - printf "%s\n" "#define HAVE_SETDTABLESIZE 1" >>confdefs.h + printf '%s\n' "#define HAVE_SETDTABLESIZE 1" >>confdefs.h fi @@ -34241,7 +35096,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_DUP2 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_DUP2 1" >>confdefs.h @@ -34261,19 +35116,19 @@ printf "%s\n" "#define GNULIB_TEST_DUP2 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_ENVIRON 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_ENVIRON 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for error_at_line" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for error_at_line" >&5 printf %s "checking for error_at_line... " >&6; } if test ${ac_cv_lib_error_at_line+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -34287,14 +35142,16 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_error_at_line=yes -else $as_nop - ac_cv_lib_error_at_line=no +else case e in #( + e) ac_cv_lib_error_at_line=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext + conftest$ac_exeext conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_error_at_line" >&5 -printf "%s\n" "$ac_cv_lib_error_at_line" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_error_at_line" >&5 +printf '%s\n' "$ac_cv_lib_error_at_line" >&6; } if test "$ac_cv_lib_error_at_line" = no then : @@ -34350,21 +35207,21 @@ fi fi else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether fcntl handles F_DUPFD correctly" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether fcntl handles F_DUPFD correctly" >&5 printf %s "checking whether fcntl handles F_DUPFD correctly... " >&6; } if test ${gl_cv_func_fcntl_f_dupfd_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case $host_os in aix* | cygwin* | haiku*) gl_cv_func_fcntl_f_dupfd_works="guessing no" ;; *) gl_cv_func_fcntl_f_dupfd_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -34417,16 +35274,19 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_fcntl_f_dupfd_works=yes -else $as_nop - gl_cv_func_fcntl_f_dupfd_works=no +else case e in #( + e) gl_cv_func_fcntl_f_dupfd_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fcntl_f_dupfd_works" >&5 -printf "%s\n" "$gl_cv_func_fcntl_f_dupfd_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fcntl_f_dupfd_works" >&5 +printf '%s\n' "$gl_cv_func_fcntl_f_dupfd_works" >&6; } case $gl_cv_func_fcntl_f_dupfd_works in *yes) ;; *) @@ -34439,17 +35299,17 @@ printf "%s\n" "$gl_cv_func_fcntl_f_dupfd_works" >&6; } fi -printf "%s\n" "#define FCNTL_DUPFD_BUGGY 1" >>confdefs.h +printf '%s\n' "#define FCNTL_DUPFD_BUGGY 1" >>confdefs.h ;; esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether fcntl understands F_DUPFD_CLOEXEC" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether fcntl understands F_DUPFD_CLOEXEC" >&5 printf %s "checking whether fcntl understands F_DUPFD_CLOEXEC... " >&6; } if test ${gl_cv_func_fcntl_f_dupfd_cloexec+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess no on NetBSD. @@ -34457,8 +35317,8 @@ then : *) gl_cv_func_fcntl_f_dupfd_cloexec="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -34500,22 +35360,26 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_fcntl_f_dupfd_cloexec=yes -else $as_nop - gl_cv_func_fcntl_f_dupfd_cloexec="needs runtime check" +else case e in #( + e) gl_cv_func_fcntl_f_dupfd_cloexec="needs runtime check" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -else $as_nop - gl_cv_func_fcntl_f_dupfd_cloexec=no +else case e in #( + e) gl_cv_func_fcntl_f_dupfd_cloexec=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fcntl_f_dupfd_cloexec" >&5 -printf "%s\n" "$gl_cv_func_fcntl_f_dupfd_cloexec" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fcntl_f_dupfd_cloexec" >&5 +printf '%s\n' "$gl_cv_func_fcntl_f_dupfd_cloexec" >&6; } case "$gl_cv_func_fcntl_f_dupfd_cloexec" in *yes) ;; *) @@ -34578,7 +35442,7 @@ printf "%s\n" "$gl_cv_func_fcntl_f_dupfd_cloexec" >&6; } -printf "%s\n" "#define GNULIB_TEST_FCNTL 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FCNTL 1" >>confdefs.h @@ -34590,7 +35454,7 @@ printf "%s\n" "#define GNULIB_TEST_FCNTL 1" >>confdefs.h -printf "%s\n" "#define GNULIB_FD_SAFER_FLAG 1" >>confdefs.h +printf '%s\n' "#define GNULIB_FD_SAFER_FLAG 1" >>confdefs.h @@ -34630,7 +35494,7 @@ printf "%s\n" "#define GNULIB_FD_SAFER_FLAG 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FFSL 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FFSL 1" >>confdefs.h @@ -34666,8 +35530,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - FLOAT_H=float.h +else case e in #( + e) FLOAT_H=float.h ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -34690,13 +35555,13 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext esac REPLACE_ITOLD=0 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether conversion from 'int' to 'long double' works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether conversion from 'int' to 'long double' works" >&5 printf %s "checking whether conversion from 'int' to 'long double' works... " >&6; } if test ${gl_cv_func_itold_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host" in @@ -34713,8 +35578,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_itold_works="guessing no" -else $as_nop - gl_cv_func_itold_works="guessing yes" +else case e in #( + e) gl_cv_func_itold_works="guessing yes" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -34723,8 +35589,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext *) gl_cv_func_itold_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int i = -1; @@ -34740,17 +35606,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_itold_works=yes -else $as_nop - gl_cv_func_itold_works=no +else case e in #( + e) gl_cv_func_itold_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_itold_works" >&5 -printf "%s\n" "$gl_cv_func_itold_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_itold_works" >&5 +printf '%s\n' "$gl_cv_func_itold_works" >&6; } case "$gl_cv_func_itold_works" in *no) REPLACE_ITOLD=1 @@ -34770,13 +35639,13 @@ printf "%s\n" "$gl_cv_func_itold_works" >&6; } if test $gl_cv_have_include_next = yes; then gl_cv_next_float_h='<'float.h'>' else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking absolute name of " >&5 printf %s "checking absolute name of ... " >&6; } if test ${gl_cv_next_float_h+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -34812,10 +35681,11 @@ _ACEOF gl_header=$gl_cv_absolute_float_h gl_cv_next_float_h='"'$gl_header'"' - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_float_h" >&5 -printf "%s\n" "$gl_cv_next_float_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_next_float_h" >&5 +printf '%s\n' "$gl_cv_next_float_h" >&6; } fi NEXT_FLOAT_H=$gl_cv_next_float_h @@ -34876,13 +35746,13 @@ fi gl_cv_func_fopen_slash="guessing no" ;; *) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether fopen recognizes a trailing slash" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether fopen recognizes a trailing slash" >&5 printf %s "checking whether fopen recognizes a trailing slash... " >&6; } if test ${gl_cv_func_fopen_slash+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -34893,8 +35763,8 @@ then : gl_cv_func_fopen_slash="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -34911,24 +35781,27 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_fopen_slash=yes -else $as_nop - gl_cv_func_fopen_slash=no +else case e in #( + e) gl_cv_func_fopen_slash=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.sl - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fopen_slash" >&5 -printf "%s\n" "$gl_cv_func_fopen_slash" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fopen_slash" >&5 +printf '%s\n' "$gl_cv_func_fopen_slash" >&6; } ;; esac case "$gl_cv_func_fopen_slash" in *no) -printf "%s\n" "#define FOPEN_TRAILING_SLASH_BUG 1" >>confdefs.h +printf '%s\n' "#define FOPEN_TRAILING_SLASH_BUG 1" >>confdefs.h REPLACE_FOPEN=1 ;; @@ -34962,19 +35835,19 @@ printf "%s\n" "#define FOPEN_TRAILING_SLASH_BUG 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FOPEN 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FOPEN 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether fopen supports the mode character 'x'" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether fopen supports the mode character 'x'" >&5 printf %s "checking whether fopen supports the mode character 'x'... " >&6; } if test ${gl_cv_func_fopen_mode_x+y} then : printf %s "(cached) " >&6 -else $as_nop - rm -f conftest.x +else case e in #( + e) rm -f conftest.x if test "$cross_compiling" = yes then : case "$host_os" in @@ -34986,8 +35859,8 @@ then : gl_cv_func_fopen_mode_x="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -35011,25 +35884,28 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_fopen_mode_x=yes -else $as_nop - gl_cv_func_fopen_mode_x=no +else case e in #( + e) gl_cv_func_fopen_mode_x=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.x - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fopen_mode_x" >&5 -printf "%s\n" "$gl_cv_func_fopen_mode_x" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether fopen supports the mode character 'e'" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fopen_mode_x" >&5 +printf '%s\n' "$gl_cv_func_fopen_mode_x" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether fopen supports the mode character 'e'" >&5 printf %s "checking whether fopen supports the mode character 'e'... " >&6; } if test ${gl_cv_func_fopen_mode_e+y} then : printf %s "(cached) " >&6 -else $as_nop - echo foo > conftest.x +else case e in #( + e) echo foo > conftest.x if test "$cross_compiling" = yes then : case "$host_os" in @@ -35044,8 +35920,8 @@ then : gl_cv_func_fopen_mode_e="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -35074,18 +35950,21 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_fopen_mode_e=yes -else $as_nop - gl_cv_func_fopen_mode_e=no +else case e in #( + e) gl_cv_func_fopen_mode_e=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.x - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fopen_mode_e" >&5 -printf "%s\n" "$gl_cv_func_fopen_mode_e" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fopen_mode_e" >&5 +printf '%s\n' "$gl_cv_func_fopen_mode_e" >&6; } case "$gl_cv_func_fopen_mode_x" in *no) REPLACE_FOPEN=1 ;; esac @@ -35108,12 +35987,12 @@ printf "%s\n" "$gl_cv_func_fopen_mode_e" >&6; } fi -printf "%s\n" "#define GNULIB_FOPEN_GNU 1" >>confdefs.h +printf '%s\n' "#define GNULIB_FOPEN_GNU 1" >>confdefs.h -printf "%s\n" "#define GNULIB_FOPEN_SAFER 1" >>confdefs.h +printf '%s\n' "#define GNULIB_FOPEN_SAFER 1" >>confdefs.h @@ -35124,13 +36003,13 @@ printf "%s\n" "#define GNULIB_FOPEN_SAFER 1" >>confdefs.h # include #endif ' - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for __fpending" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for __fpending" >&5 printf %s "checking for __fpending... " >&6; } if test ${gl_cv_func___fpending+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $fp_headers @@ -35145,25 +36024,28 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func___fpending=yes -else $as_nop - gl_cv_func___fpending=no +else case e in #( + e) gl_cv_func___fpending=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func___fpending" >&5 -printf "%s\n" "$gl_cv_func___fpending" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func___fpending" >&5 +printf '%s\n' "$gl_cv_func___fpending" >&6; } if test $gl_cv_func___fpending = yes; then ac_fn_check_decl "$LINENO" "__fpending" "ac_cv_have_decl___fpending" "$fp_headers -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl___fpending" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL___FPENDING $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL___FPENDING $ac_have_decl" >>confdefs.h fi @@ -35263,7 +36145,7 @@ printf "%s\n" "#define HAVE_DECL___FPENDING $ac_have_decl" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; esac @@ -35278,7 +36160,7 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -35292,12 +36174,12 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : - printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h + printf '%s\n' "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi @@ -35311,7 +36193,7 @@ fi ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; esac @@ -35323,7 +36205,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; esac @@ -35335,7 +36217,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; esac @@ -35347,7 +36229,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; esac @@ -35359,7 +36241,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; esac @@ -35371,13 +36253,13 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -35389,13 +36271,13 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -35444,7 +36326,7 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h if test $ac_cv_func_vasnprintf = yes; then -printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h +printf '%s\n' "#define REPLACE_VASNPRINTF 1" >>confdefs.h fi @@ -35460,11 +36342,12 @@ printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h if test "x$ac_cv_type_ptrdiff_t" = xyes then : -else $as_nop - -printf "%s\n" "#define ptrdiff_t long" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define ptrdiff_t long" >>confdefs.h + ;; +esac fi @@ -35487,7 +36370,7 @@ fi REPLACE_FPRINTF=1 -printf "%s\n" "#define REPLACE_FPRINTF_POSIX 1" >>confdefs.h +printf '%s\n' "#define REPLACE_FPRINTF_POSIX 1" >>confdefs.h : @@ -35508,20 +36391,20 @@ printf "%s\n" "#define REPLACE_FPRINTF_POSIX 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FPRINTF_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FPRINTF_POSIX 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether free is known to preserve errno" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether free is known to preserve errno" >&5 printf %s "checking whether free is known to preserve errno... " >&6; } if test ${gl_cv_func_free_preserves_errno+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -35542,19 +36425,21 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_free_preserves_errno=yes -else $as_nop - gl_cv_func_free_preserves_errno=no +else case e in #( + e) gl_cv_func_free_preserves_errno=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_free_preserves_errno" >&5 -printf "%s\n" "$gl_cv_func_free_preserves_errno" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_free_preserves_errno" >&5 +printf '%s\n' "$gl_cv_func_free_preserves_errno" >&6; } case $gl_cv_func_free_preserves_errno in *yes) -printf "%s\n" "#define HAVE_FREE_POSIX 1" >>confdefs.h +printf '%s\n' "#define HAVE_FREE_POSIX 1" >>confdefs.h ;; *) REPLACE_FREE=1 ;; @@ -35588,7 +36473,7 @@ printf "%s\n" "#define HAVE_FREE_POSIX 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FREE_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FREE_POSIX 1" >>confdefs.h @@ -35599,13 +36484,13 @@ printf "%s\n" "#define GNULIB_TEST_FREE_POSIX 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether frexp works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether frexp works" >&5 printf %s "checking whether frexp works... " >&6; } if test ${gl_cv_func_frexp_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -35620,11 +36505,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Good" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Good" >/dev/null 2>&1 then : gl_cv_func_frexp_works="guessing yes" -else $as_nop - gl_cv_func_frexp_works="guessing no" +else case e in #( + e) gl_cv_func_frexp_works="guessing no" ;; +esac fi rm -rf conftest* @@ -35632,8 +36518,8 @@ rm -rf conftest* *) gl_cv_func_frexp_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -35703,17 +36589,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_frexp_works=yes -else $as_nop - gl_cv_func_frexp_works=no +else case e in #( + e) gl_cv_func_frexp_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexp_works" >&5 -printf "%s\n" "$gl_cv_func_frexp_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexp_works" >&5 +printf '%s\n' "$gl_cv_func_frexp_works" >&6; } case "$gl_cv_func_frexp_works" in *yes) gl_func_frexp_no_libm=yes ;; @@ -35725,7 +36614,7 @@ printf "%s\n" "$gl_cv_func_frexp_works" >&6; } fi if test $gl_func_frexp_no_libm = yes; then -printf "%s\n" "#define HAVE_FREXP_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_FREXP_IN_LIBC 1" >>confdefs.h fi @@ -35756,7 +36645,7 @@ printf "%s\n" "#define HAVE_FREXP_IN_LIBC 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FREXP 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FREXP 1" >>confdefs.h @@ -35764,22 +36653,23 @@ printf "%s\n" "#define GNULIB_TEST_FREXP 1" >>confdefs.h ac_fn_check_decl "$LINENO" "frexpl" "ac_cv_have_decl_frexpl" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_frexpl" = xyes then : -else $as_nop - HAVE_DECL_FREXPL=0 +else case e in #( + e) HAVE_DECL_FREXPL=0 ;; +esac fi if test $HAVE_DECL_FREXPL = 1; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether frexpl() can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether frexpl() can be used without linking with libm" >&5 printf %s "checking whether frexpl() can be used without linking with libm... " >&6; } if test ${gl_cv_func_frexpl_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -35795,26 +36685,28 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_frexpl_no_libm=yes -else $as_nop - gl_cv_func_frexpl_no_libm=no +else case e in #( + e) gl_cv_func_frexpl_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexpl_no_libm" >&5 -printf "%s\n" "$gl_cv_func_frexpl_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexpl_no_libm" >&5 +printf '%s\n' "$gl_cv_func_frexpl_no_libm" >&6; } if test $gl_cv_func_frexpl_no_libm = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether frexpl works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether frexpl works" >&5 printf %s "checking whether frexpl works... " >&6; } if test ${gl_cv_func_frexpl_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -35824,8 +36716,8 @@ then : *) gl_cv_func_frexpl_works="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -35926,17 +36818,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_frexpl_works=yes -else $as_nop - gl_cv_func_frexpl_works=no +else case e in #( + e) gl_cv_func_frexpl_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexpl_works" >&5 -printf "%s\n" "$gl_cv_func_frexpl_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexpl_works" >&5 +printf '%s\n' "$gl_cv_func_frexpl_works" >&6; } case "$gl_cv_func_frexpl_works" in *yes) gl_func_frexpl_no_libm=yes ;; @@ -35948,7 +36843,7 @@ printf "%s\n" "$gl_cv_func_frexpl_works" >&6; } fi if test $gl_func_frexpl_no_libm = yes; then -printf "%s\n" "#define HAVE_FREXPL_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_FREXPL_IN_LIBC 1" >>confdefs.h fi fi @@ -35980,7 +36875,7 @@ printf "%s\n" "#define HAVE_FREXPL_IN_LIBC 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FREXPL 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FREXPL 1" >>confdefs.h @@ -36019,7 +36914,7 @@ printf "%s\n" "#define GNULIB_TEST_FREXPL 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FSYNC 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FSYNC 1" >>confdefs.h @@ -36039,13 +36934,13 @@ printf "%s\n" "#define GNULIB_TEST_FSYNC 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getcwd handles long file names properly" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether getcwd handles long file names properly" >&5 printf %s "checking whether getcwd handles long file names properly... " >&6; } if test ${gl_cv_func_getcwd_path_max+y} then : printf %s "(cached) " >&6 -else $as_nop - # Arrange for deletion of the temporary directory this test creates. +else case e in #( + e) # Arrange for deletion of the temporary directory this test creates. ac_clean_files="$ac_clean_files confdir3" if test "$cross_compiling" = yes then : @@ -36065,8 +36960,8 @@ then : gl_cv_func_getcwd_path_max="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -36277,22 +37172,25 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_getcwd_path_max=yes -else $as_nop - case $? in +else case e in #( + e) case $? in 10|11|12) gl_cv_func_getcwd_path_max='no, but it is partly working';; 31) gl_cv_func_getcwd_path_max='no, it has the AIX bug';; 32) gl_cv_func_getcwd_path_max='yes, but with shorter paths';; *) gl_cv_func_getcwd_path_max=no;; - esac + esac ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getcwd_path_max" >&5 -printf "%s\n" "$gl_cv_func_getcwd_path_max" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getcwd_path_max" >&5 +printf '%s\n' "$gl_cv_func_getcwd_path_max" >&6; } case "$gl_cv_func_getcwd_null" in *yes) @@ -36302,13 +37200,13 @@ printf "%s\n" "$gl_cv_func_getcwd_path_max" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for getpagesize" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for getpagesize" >&5 printf %s "checking for getpagesize... " >&6; } if test ${gl_cv_func_getpagesize+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -36323,29 +37221,31 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_getpagesize=yes -else $as_nop - gl_cv_func_getpagesize=no +else case e in #( + e) gl_cv_func_getpagesize=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getpagesize" >&5 -printf "%s\n" "$gl_cv_func_getpagesize" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getpagesize" >&5 +printf '%s\n' "$gl_cv_func_getpagesize" >&6; } if test $gl_cv_func_getpagesize = yes; then -printf "%s\n" "#define HAVE_GETPAGESIZE 1" >>confdefs.h +printf '%s\n' "#define HAVE_GETPAGESIZE 1" >>confdefs.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getcwd succeeds when 4k < cwd_length < 16k" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether getcwd succeeds when 4k < cwd_length < 16k" >&5 printf %s "checking whether getcwd succeeds when 4k < cwd_length < 16k... " >&6; } if test ${gl_cv_func_getcwd_succeeds_beyond_4k+y} then : printf %s "(cached) " >&6 -else $as_nop - # Remove any remnants of a previous test. +else case e in #( + e) # Remove any remnants of a previous test. rm -rf confdir-14B--- # Arrange for deletion of the temporary directory this test creates. ac_clean_files="$ac_clean_files confdir-14B---" @@ -36356,8 +37256,8 @@ then : *) gl_cv_func_getcwd_succeeds_beyond_4k="guessing no" esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -36479,23 +37379,26 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_getcwd_succeeds_beyond_4k=yes -else $as_nop - ret=$? +else case e in #( + e) ret=$? if test $ret -ge 128 || test $ret = 4; then gl_cv_func_getcwd_succeeds_beyond_4k=no else gl_cv_func_getcwd_succeeds_beyond_4k=yes fi - + ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getcwd_succeeds_beyond_4k" >&5 -printf "%s\n" "$gl_cv_func_getcwd_succeeds_beyond_4k" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getcwd_succeeds_beyond_4k" >&5 +printf '%s\n' "$gl_cv_func_getcwd_succeeds_beyond_4k" >&6; } case "$gl_cv_func_getcwd_succeeds_beyond_4k" in *no) gl_abort_bug=yes @@ -36513,19 +37416,19 @@ printf "%s\n" "$gl_cv_func_getcwd_succeeds_beyond_4k" >&6; } *"no" | *"no, it has the AIX bug") ;; *) -printf "%s\n" "#define HAVE_MINIMALLY_WORKING_GETCWD 1" >>confdefs.h +printf '%s\n' "#define HAVE_MINIMALLY_WORKING_GETCWD 1" >>confdefs.h ;; esac case "$gl_cv_func_getcwd_path_max" in *"no, but it is partly working") -printf "%s\n" "#define HAVE_PARTLY_WORKING_GETCWD 1" >>confdefs.h +printf '%s\n' "#define HAVE_PARTLY_WORKING_GETCWD 1" >>confdefs.h ;; *"yes, but with shorter paths") -printf "%s\n" "#define HAVE_GETCWD_SHORTER 1" >>confdefs.h +printf '%s\n' "#define HAVE_GETCWD_SHORTER 1" >>confdefs.h ;; esac @@ -36556,7 +37459,7 @@ printf "%s\n" "#define HAVE_GETCWD_SHORTER 1" >>confdefs.h fi -printf "%s\n" "#define GNULIB_GETCWD 1" >>confdefs.h +printf '%s\n' "#define GNULIB_GETCWD 1" >>confdefs.h @@ -36574,7 +37477,7 @@ printf "%s\n" "#define GNULIB_GETCWD 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_GETCWD 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_GETCWD 1" >>confdefs.h @@ -36583,14 +37486,15 @@ printf "%s\n" "#define GNULIB_TEST_GETCWD 1" >>confdefs.h ac_fn_check_decl "$LINENO" "gethrtime" "ac_cv_have_decl_gethrtime" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_gethrtime" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_GETHRTIME $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_GETHRTIME $ac_have_decl" >>confdefs.h LIB_GETHRXTIME= if test $ac_cv_have_decl_gethrtime = no \ @@ -36601,13 +37505,13 @@ printf "%s\n" "#define HAVE_DECL_GETHRTIME $ac_have_decl" >>confdefs.h if test $ac_cv_func_nanouptime != yes \ && { test $ac_cv_have_decl_gethrtime = no \ || test $gl_cv_arithmetic_hrtime_t = no; }; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether CLOCK_MONOTONIC or CLOCK_REALTIME is defined" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether CLOCK_MONOTONIC or CLOCK_REALTIME is defined" >&5 printf %s "checking whether CLOCK_MONOTONIC or CLOCK_REALTIME is defined... " >&6; } if test ${gl_cv_have_clock_gettime_macro+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include @@ -36617,17 +37521,19 @@ else $as_nop _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "have_clock_gettime_macro" >/dev/null 2>&1 + $EGREP_TRADITIONAL "have_clock_gettime_macro" >/dev/null 2>&1 then : gl_cv_have_clock_gettime_macro=yes -else $as_nop - gl_cv_have_clock_gettime_macro=no +else case e in #( + e) gl_cv_have_clock_gettime_macro=no ;; +esac fi rm -rf conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_clock_gettime_macro" >&5 -printf "%s\n" "$gl_cv_have_clock_gettime_macro" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_clock_gettime_macro" >&5 +printf '%s\n' "$gl_cv_have_clock_gettime_macro" >&6; } if test $gl_cv_have_clock_gettime_macro = yes; then LIB_GETHRXTIME=$LIB_CLOCK_GETTIME fi @@ -36660,7 +37566,7 @@ printf "%s\n" "$gl_cv_have_clock_gettime_macro" >&6; } -printf "%s\n" "#define __GETOPT_PREFIX rpl_" >>confdefs.h +printf '%s\n' "#define __GETOPT_PREFIX rpl_" >>confdefs.h GETOPT_H=getopt.h GETOPT_CDEFS_H=getopt-cdefs.h @@ -36715,7 +37621,7 @@ printf "%s\n" "#define __GETOPT_PREFIX rpl_" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_GETOPT_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_GETOPT_POSIX 1" >>confdefs.h @@ -36724,42 +37630,45 @@ printf "%s\n" "#define GNULIB_TEST_GETOPT_POSIX 1" >>confdefs.h ac_found=0 ac_fn_check_decl "$LINENO" "program_invocation_name" "ac_cv_have_decl_program_invocation_name" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_program_invocation_name" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_PROGRAM_INVOCATION_NAME $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_PROGRAM_INVOCATION_NAME $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 then : ac_found=1 fi ac_fn_check_decl "$LINENO" "program_invocation_short_name" "ac_cv_have_decl_program_invocation_short_name" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_program_invocation_short_name" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 then : ac_found=1 fi ac_fn_check_decl "$LINENO" "__argv" "ac_cv_have_decl___argv" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl___argv" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL___ARGV $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL___ARGV $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 then : ac_found=1 @@ -36770,13 +37679,13 @@ fi if test $ac_found = 0; then # On OpenBSD 5.1, using the global __progname variable appears to be # the only way to implement getprogname. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether __progname is defined in default libraries" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether __progname is defined in default libraries" >&5 printf %s "checking whether __progname is defined in default libraries... " >&6; } if test ${gl_cv_var___progname+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_cv_var___progname= cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -36798,13 +37707,14 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_var___progname" >&5 -printf "%s\n" "$gl_cv_var___progname" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_var___progname" >&5 +printf '%s\n' "$gl_cv_var___progname" >&6; } if test "$gl_cv_var___progname" = yes; then -printf "%s\n" "#define HAVE_VAR___PROGNAME 1" >>confdefs.h +printf '%s\n' "#define HAVE_VAR___PROGNAME 1" >>confdefs.h fi fi @@ -36843,7 +37753,7 @@ printf "%s\n" "#define HAVE_VAR___PROGNAME 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_GETRUSAGE 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_GETRUSAGE 1" >>confdefs.h @@ -36865,13 +37775,13 @@ printf "%s\n" "#define GNULIB_TEST_GETRUSAGE 1" >>confdefs.h if test $ac_cv_func_gettimeofday != yes; then HAVE_GETTIMEOFDAY=0 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gettimeofday with POSIX signature" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for gettimeofday with POSIX signature" >&5 printf %s "checking for gettimeofday with POSIX signature... " >&6; } if test ${gl_cv_func_gettimeofday_posix_signature+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include struct timeval c; @@ -36897,8 +37807,8 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_gettimeofday_posix_signature=yes -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int gettimeofday (struct timeval *restrict, struct timezone *restrict); @@ -36914,15 +37824,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_gettimeofday_posix_signature=almost -else $as_nop - gl_cv_func_gettimeofday_posix_signature=no +else case e in #( + e) gl_cv_func_gettimeofday_posix_signature=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_gettimeofday_posix_signature" >&5 -printf "%s\n" "$gl_cv_func_gettimeofday_posix_signature" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_gettimeofday_posix_signature" >&5 +printf '%s\n' "$gl_cv_func_gettimeofday_posix_signature" >&6; } if test $gl_cv_func_gettimeofday_posix_signature = almost; then gl_gettimeofday_timezone='struct timezone' elif test $gl_cv_func_gettimeofday_posix_signature != yes; then @@ -36936,7 +37849,7 @@ printf "%s\n" "$gl_cv_func_gettimeofday_posix_signature" >&6; } esac fi -printf "%s\n" "#define GETTIMEOFDAY_TIMEZONE $gl_gettimeofday_timezone" >>confdefs.h +printf '%s\n' "#define GETTIMEOFDAY_TIMEZONE $gl_gettimeofday_timezone" >>confdefs.h if test $HAVE_GETTIMEOFDAY = 0 || test $REPLACE_GETTIMEOFDAY = 1; then @@ -36967,7 +37880,7 @@ printf "%s\n" "#define GETTIMEOFDAY_TIMEZONE $gl_gettimeofday_timezone" >>confde -printf "%s\n" "#define GNULIB_TEST_GETTIMEOFDAY 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_GETTIMEOFDAY 1" >>confdefs.h @@ -37032,11 +37945,12 @@ fi _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "gnu_iconv" >/dev/null 2>&1 + $EGREP_TRADITIONAL "gnu_iconv" >/dev/null 2>&1 then : gl_func_iconv_gnu=yes -else $as_nop - gl_func_iconv_gnu=no +else case e in #( + e) gl_func_iconv_gnu=no ;; +esac fi rm -rf conftest* @@ -37052,7 +37966,7 @@ rm -rf conftest* esac if test -n "$iconv_flavor"; then -printf "%s\n" "#define ICONV_FLAVOR $iconv_flavor" >>confdefs.h +printf '%s\n' "#define ICONV_FLAVOR $iconv_flavor" >>confdefs.h @@ -37114,13 +38028,13 @@ fi fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler generally respects inline" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the compiler generally respects inline" >&5 printf %s "checking whether the compiler generally respects inline... " >&6; } if test ${gl_cv_c_inline_effective+y} then : printf %s "(cached) " >&6 -else $as_nop - if test $ac_cv_c_inline = no; then +else case e in #( + e) if test $ac_cv_c_inline = no; then gl_cv_c_inline_effective=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -37139,18 +38053,20 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_c_inline_effective=yes -else $as_nop - gl_cv_c_inline_effective=no +else case e in #( + e) gl_cv_c_inline_effective=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_c_inline_effective" >&5 -printf "%s\n" "$gl_cv_c_inline_effective" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_c_inline_effective" >&5 +printf '%s\n' "$gl_cv_c_inline_effective" >&6; } if test $gl_cv_c_inline_effective = yes; then -printf "%s\n" "#define HAVE_INLINE 1" >>confdefs.h +printf '%s\n' "#define HAVE_INLINE 1" >>confdefs.h fi @@ -37170,13 +38086,13 @@ printf "%s\n" "#define HAVE_INLINE 1" >>confdefs.h # If we replaced any of the underlying isnan* functions, replace # the isnan macro; it undoubtedly suffers from the same flaws. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan macro works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan macro works" >&5 printf %s "checking whether isnan macro works... " >&6; } if test $gl_func_isnanf = yes \ && test $gl_func_isnand = yes \ && test $gl_func_isnanl = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -printf "%s\n" "yes" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf '%s\n' "yes" >&6; } ISNAN_LIBM= case " $ISNAN_LIBM " in *" $ISNANF_LIBM "*) ;; @@ -37191,8 +38107,8 @@ printf "%s\n" "yes" >&6; } *) ISNAN_LIBM="$ISNAN_LIBM $ISNANL_LIBM" ;; esac else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } REPLACE_ISNAN=1 ISNAN_LIBM= fi @@ -37213,7 +38129,7 @@ printf "%s\n" "no" >&6; } -printf "%s\n" "#define GNULIB_TEST_ISNAN 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_ISNAN 1" >>confdefs.h @@ -37221,13 +38137,13 @@ printf "%s\n" "#define GNULIB_TEST_ISNAN 1" >>confdefs.h ISNAND_LIBM= - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(double) can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(double) can be used without linking with libm" >&5 printf %s "checking whether isnan(double) can be used without linking with libm... " >&6; } if test ${gl_cv_func_isnand_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -37250,25 +38166,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnand_no_libm=yes -else $as_nop - gl_cv_func_isnand_no_libm=no +else case e in #( + e) gl_cv_func_isnand_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnand_no_libm" >&5 -printf "%s\n" "$gl_cv_func_isnand_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnand_no_libm" >&5 +printf '%s\n' "$gl_cv_func_isnand_no_libm" >&6; } if test $gl_cv_func_isnand_no_libm = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(double) can be used with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(double) can be used with libm" >&5 printf %s "checking whether isnan(double) can be used with libm... " >&6; } if test ${gl_cv_func_isnand_in_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) save_LIBS="$LIBS" LIBS="$LIBS -lm" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -37293,16 +38211,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnand_in_libm=yes -else $as_nop - gl_cv_func_isnand_in_libm=no +else case e in #( + e) gl_cv_func_isnand_in_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnand_in_libm" >&5 -printf "%s\n" "$gl_cv_func_isnand_in_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnand_in_libm" >&5 +printf '%s\n' "$gl_cv_func_isnand_in_libm" >&6; } if test $gl_cv_func_isnand_in_libm = yes; then ISNAND_LIBM=-lm @@ -37350,19 +38270,19 @@ printf "%s\n" "$gl_cv_func_isnand_in_libm" >&6; } -printf "%s\n" "#define GNULIB_TEST_ISNAND 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_ISNAND 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(double) can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(double) can be used without linking with libm" >&5 printf %s "checking whether isnan(double) can be used without linking with libm... " >&6; } if test ${gl_cv_func_isnand_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -37385,20 +38305,22 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnand_no_libm=yes -else $as_nop - gl_cv_func_isnand_no_libm=no +else case e in #( + e) gl_cv_func_isnand_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnand_no_libm" >&5 -printf "%s\n" "$gl_cv_func_isnand_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnand_no_libm" >&5 +printf '%s\n' "$gl_cv_func_isnand_no_libm" >&6; } gl_func_isnand_no_libm=$gl_cv_func_isnand_no_libm if test $gl_cv_func_isnand_no_libm = yes; then -printf "%s\n" "#define HAVE_ISNAND_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_ISNAND_IN_LIBC 1" >>confdefs.h fi @@ -37421,13 +38343,13 @@ printf "%s\n" "#define HAVE_ISNAND_IN_LIBC 1" >>confdefs.h ISNANF_LIBM= - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) can be used without linking with libm" >&5 printf %s "checking whether isnan(float) can be used without linking with libm... " >&6; } if test ${gl_cv_func_isnanf_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -37450,25 +38372,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnanf_no_libm=yes -else $as_nop - gl_cv_func_isnanf_no_libm=no +else case e in #( + e) gl_cv_func_isnanf_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_no_libm" >&5 -printf "%s\n" "$gl_cv_func_isnanf_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_no_libm" >&5 +printf '%s\n' "$gl_cv_func_isnanf_no_libm" >&6; } if test $gl_cv_func_isnanf_no_libm = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) can be used with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) can be used with libm" >&5 printf %s "checking whether isnan(float) can be used with libm... " >&6; } if test ${gl_cv_func_isnanf_in_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) save_LIBS="$LIBS" LIBS="$LIBS -lm" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -37493,16 +38417,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnanf_in_libm=yes -else $as_nop - gl_cv_func_isnanf_in_libm=no +else case e in #( + e) gl_cv_func_isnanf_in_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_in_libm" >&5 -printf "%s\n" "$gl_cv_func_isnanf_in_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_in_libm" >&5 +printf '%s\n' "$gl_cv_func_isnanf_in_libm" >&6; } if test $gl_cv_func_isnanf_in_libm = yes; then ISNANF_LIBM=-lm @@ -37515,13 +38441,13 @@ printf "%s\n" "$gl_cv_func_isnanf_in_libm" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) works" >&5 printf %s "checking whether isnan(float) works... " >&6; } if test ${gl_cv_func_isnanf_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -37536,11 +38462,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_isnanf_works="guessing yes" -else $as_nop - gl_cv_func_isnanf_works="guessing no" +else case e in #( + e) gl_cv_func_isnanf_works="guessing no" ;; +esac fi rm -rf conftest* @@ -37548,8 +38475,8 @@ rm -rf conftest* *) gl_cv_func_isnanf_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -37607,17 +38534,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_isnanf_works=yes -else $as_nop - gl_cv_func_isnanf_works=no +else case e in #( + e) gl_cv_func_isnanf_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_works" >&5 -printf "%s\n" "$gl_cv_func_isnanf_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_works" >&5 +printf '%s\n' "$gl_cv_func_isnanf_works" >&6; } LIBS="$save_LIBS" case "$gl_cv_func_isnanf_works" in @@ -37648,18 +38578,18 @@ printf "%s\n" "$gl_cv_func_isnanf_works" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'float'" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'float'" >&5 printf %s "checking where to find the exponent in a 'float'... " >&6; } if test ${gl_cv_cc_float_expbit0+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : gl_cv_cc_float_expbit0="word 0 bit 23" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -37730,27 +38660,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_cc_float_expbit0=`cat conftest.out` -else $as_nop - gl_cv_cc_float_expbit0="unknown" +else case e in #( + e) gl_cv_cc_float_expbit0="unknown" ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.out - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_float_expbit0" >&5 -printf "%s\n" "$gl_cv_cc_float_expbit0" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_float_expbit0" >&5 +printf '%s\n' "$gl_cv_cc_float_expbit0" >&6; } case "$gl_cv_cc_float_expbit0" in word*bit*) word=`echo "$gl_cv_cc_float_expbit0" | sed -e 's/word //' -e 's/ bit.*//'` bit=`echo "$gl_cv_cc_float_expbit0" | sed -e 's/word.*bit //'` -printf "%s\n" "#define FLT_EXPBIT0_WORD $word" >>confdefs.h +printf '%s\n' "#define FLT_EXPBIT0_WORD $word" >>confdefs.h -printf "%s\n" "#define FLT_EXPBIT0_BIT $bit" >>confdefs.h +printf '%s\n' "#define FLT_EXPBIT0_BIT $bit" >>confdefs.h ;; esac @@ -37772,7 +38705,7 @@ printf "%s\n" "#define FLT_EXPBIT0_BIT $bit" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_ISNANF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_ISNANF 1" >>confdefs.h @@ -37780,13 +38713,13 @@ printf "%s\n" "#define GNULIB_TEST_ISNANF 1" >>confdefs.h ISNANL_LIBM= - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(long double) can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(long double) can be used without linking with libm" >&5 printf %s "checking whether isnan(long double) can be used without linking with libm... " >&6; } if test ${gl_cv_func_isnanl_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -37809,25 +38742,27 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnanl_no_libm=yes -else $as_nop - gl_cv_func_isnanl_no_libm=no +else case e in #( + e) gl_cv_func_isnanl_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_no_libm" >&5 -printf "%s\n" "$gl_cv_func_isnanl_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_no_libm" >&5 +printf '%s\n' "$gl_cv_func_isnanl_no_libm" >&6; } if test $gl_cv_func_isnanl_no_libm = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(long double) can be used with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(long double) can be used with libm" >&5 printf %s "checking whether isnan(long double) can be used with libm... " >&6; } if test ${gl_cv_func_isnanl_in_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) save_LIBS="$LIBS" LIBS="$LIBS -lm" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -37852,16 +38787,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnanl_in_libm=yes -else $as_nop - gl_cv_func_isnanl_in_libm=no +else case e in #( + e) gl_cv_func_isnanl_in_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_in_libm" >&5 -printf "%s\n" "$gl_cv_func_isnanl_in_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_in_libm" >&5 +printf '%s\n' "$gl_cv_func_isnanl_in_libm" >&6; } if test $gl_cv_func_isnanl_in_libm = yes; then ISNANL_LIBM=-lm @@ -37875,13 +38812,13 @@ printf "%s\n" "$gl_cv_func_isnanl_in_libm" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnanl works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnanl works" >&5 printf %s "checking whether isnanl works... " >&6; } if test ${gl_cv_func_isnanl_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -37895,11 +38832,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_isnanl_works="guessing yes" -else $as_nop - gl_cv_func_isnanl_works="guessing no" +else case e in #( + e) gl_cv_func_isnanl_works="guessing no" ;; +esac fi rm -rf conftest* @@ -37907,8 +38845,8 @@ rm -rf conftest* *) gl_cv_func_isnanl_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -38024,17 +38962,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_isnanl_works=yes -else $as_nop - gl_cv_func_isnanl_works=no +else case e in #( + e) gl_cv_func_isnanl_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_works" >&5 -printf "%s\n" "$gl_cv_func_isnanl_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_works" >&5 +printf '%s\n' "$gl_cv_func_isnanl_works" >&6; } LIBS="$save_LIBS" case "$gl_cv_func_isnanl_works" in @@ -38066,13 +39007,13 @@ printf "%s\n" "$gl_cv_func_isnanl_works" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'long double'" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'long double'" >&5 printf %s "checking where to find the exponent in a 'long double'... " >&6; } if test ${gl_cv_cc_long_double_expbit0+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -38089,7 +39030,7 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_cc_long_double_expbit0="word 2 bit 0" fi @@ -38104,7 +39045,7 @@ rm -rf conftest* _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_cc_long_double_expbit0="word 1 bit 20" fi @@ -38113,8 +39054,8 @@ rm -rf conftest* ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -38184,27 +39125,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_cc_long_double_expbit0=`cat conftest.out` -else $as_nop - gl_cv_cc_long_double_expbit0="unknown" +else case e in #( + e) gl_cv_cc_long_double_expbit0="unknown" ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.out - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_long_double_expbit0" >&5 -printf "%s\n" "$gl_cv_cc_long_double_expbit0" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_long_double_expbit0" >&5 +printf '%s\n' "$gl_cv_cc_long_double_expbit0" >&6; } case "$gl_cv_cc_long_double_expbit0" in word*bit*) word=`echo "$gl_cv_cc_long_double_expbit0" | sed -e 's/word //' -e 's/ bit.*//'` bit=`echo "$gl_cv_cc_long_double_expbit0" | sed -e 's/word.*bit //'` -printf "%s\n" "#define LDBL_EXPBIT0_WORD $word" >>confdefs.h +printf '%s\n' "#define LDBL_EXPBIT0_WORD $word" >>confdefs.h -printf "%s\n" "#define LDBL_EXPBIT0_BIT $bit" >>confdefs.h +printf '%s\n' "#define LDBL_EXPBIT0_BIT $bit" >>confdefs.h ;; esac @@ -38227,19 +39171,19 @@ printf "%s\n" "#define LDBL_EXPBIT0_BIT $bit" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_ISNANL 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_ISNANL 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(long double) can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(long double) can be used without linking with libm" >&5 printf %s "checking whether isnan(long double) can be used without linking with libm... " >&6; } if test ${gl_cv_func_isnanl_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -38262,15 +39206,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnanl_no_libm=yes -else $as_nop - gl_cv_func_isnanl_no_libm=no +else case e in #( + e) gl_cv_func_isnanl_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_no_libm" >&5 -printf "%s\n" "$gl_cv_func_isnanl_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_no_libm" >&5 +printf '%s\n' "$gl_cv_func_isnanl_no_libm" >&6; } gl_func_isnanl_no_libm=$gl_cv_func_isnanl_no_libm if test $gl_func_isnanl_no_libm = yes; then @@ -38278,13 +39224,13 @@ printf "%s\n" "$gl_cv_func_isnanl_no_libm" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnanl works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnanl works" >&5 printf %s "checking whether isnanl works... " >&6; } if test ${gl_cv_func_isnanl_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -38298,11 +39244,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_isnanl_works="guessing yes" -else $as_nop - gl_cv_func_isnanl_works="guessing no" +else case e in #( + e) gl_cv_func_isnanl_works="guessing no" ;; +esac fi rm -rf conftest* @@ -38310,8 +39257,8 @@ rm -rf conftest* *) gl_cv_func_isnanl_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -38427,17 +39374,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_isnanl_works=yes -else $as_nop - gl_cv_func_isnanl_works=no +else case e in #( + e) gl_cv_func_isnanl_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_works" >&5 -printf "%s\n" "$gl_cv_func_isnanl_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanl_works" >&5 +printf '%s\n' "$gl_cv_func_isnanl_works" >&6; } case "$gl_cv_func_isnanl_works" in *yes) ;; @@ -38446,7 +39396,7 @@ printf "%s\n" "$gl_cv_func_isnanl_works" >&6; } fi if test $gl_func_isnanl_no_libm = yes; then -printf "%s\n" "#define HAVE_ISNANL_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_ISNANL_IN_LIBC 1" >>confdefs.h fi @@ -38464,13 +39414,13 @@ printf "%s\n" "#define HAVE_ISNANL_IN_LIBC 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'long double'" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'long double'" >&5 printf %s "checking where to find the exponent in a 'long double'... " >&6; } if test ${gl_cv_cc_long_double_expbit0+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -38487,7 +39437,7 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_cc_long_double_expbit0="word 2 bit 0" fi @@ -38502,7 +39452,7 @@ rm -rf conftest* _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_cc_long_double_expbit0="word 1 bit 20" fi @@ -38511,8 +39461,8 @@ rm -rf conftest* ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -38582,27 +39532,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_cc_long_double_expbit0=`cat conftest.out` -else $as_nop - gl_cv_cc_long_double_expbit0="unknown" +else case e in #( + e) gl_cv_cc_long_double_expbit0="unknown" ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.out - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_long_double_expbit0" >&5 -printf "%s\n" "$gl_cv_cc_long_double_expbit0" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_long_double_expbit0" >&5 +printf '%s\n' "$gl_cv_cc_long_double_expbit0" >&6; } case "$gl_cv_cc_long_double_expbit0" in word*bit*) word=`echo "$gl_cv_cc_long_double_expbit0" | sed -e 's/word //' -e 's/ bit.*//'` bit=`echo "$gl_cv_cc_long_double_expbit0" | sed -e 's/word.*bit //'` -printf "%s\n" "#define LDBL_EXPBIT0_WORD $word" >>confdefs.h +printf '%s\n' "#define LDBL_EXPBIT0_WORD $word" >>confdefs.h -printf "%s\n" "#define LDBL_EXPBIT0_BIT $bit" >>confdefs.h +printf '%s\n' "#define LDBL_EXPBIT0_BIT $bit" >>confdefs.h ;; esac @@ -38619,14 +39572,15 @@ printf "%s\n" "#define LDBL_EXPBIT0_BIT $bit" >>confdefs.h #include #include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_iswblank" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_ISWBLANK $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_ISWBLANK $ac_have_decl" >>confdefs.h if test $ac_cv_func_iswblank = no; then HAVE_ISWBLANK=0 @@ -38674,7 +39628,7 @@ printf "%s\n" "#define HAVE_DECL_ISWBLANK $ac_have_decl" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_ISWBLANK 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_ISWBLANK 1" >>confdefs.h @@ -38689,13 +39643,13 @@ printf "%s\n" "#define GNULIB_TEST_ISWBLANK 1" >>confdefs.h if test $HAVE_ISWCNTRL = 0 || test $REPLACE_ISWCNTRL = 1; then REPLACE_ISWDIGIT="$REPLACE_ISWCNTRL" else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether iswdigit is ISO C compliant" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether iswdigit is ISO C compliant" >&5 printf %s "checking whether iswdigit is ISO C compliant... " >&6; } if test ${gl_cv_func_iswdigit_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess no on FreeBSD, NetBSD, Solaris, native Windows. freebsd* | dragonfly* | netbsd* | solaris* | mingw*) @@ -38707,8 +39661,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -38783,18 +39737,21 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_iswdigit_works=yes -else $as_nop - gl_cv_func_iswdigit_works=no +else case e in #( + e) gl_cv_func_iswdigit_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_iswdigit_works" >&5 -printf "%s\n" "$gl_cv_func_iswdigit_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_iswdigit_works" >&5 +printf '%s\n' "$gl_cv_func_iswdigit_works" >&6; } case "$gl_cv_func_iswdigit_works" in *yes) ;; *) REPLACE_ISWDIGIT=1 ;; @@ -38832,7 +39789,7 @@ printf "%s\n" "$gl_cv_func_iswdigit_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_ISWDIGIT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_ISWDIGIT 1" >>confdefs.h @@ -38846,13 +39803,13 @@ printf "%s\n" "#define GNULIB_TEST_ISWDIGIT 1" >>confdefs.h if test $HAVE_ISWCNTRL = 0 || test $REPLACE_ISWCNTRL = 1; then REPLACE_ISWXDIGIT="$REPLACE_ISWCNTRL" else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether iswxdigit is ISO C compliant" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether iswxdigit is ISO C compliant" >&5 printf %s "checking whether iswxdigit is ISO C compliant... " >&6; } if test ${gl_cv_func_iswxdigit_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess no on FreeBSD, NetBSD, Solaris, native Windows. freebsd* | dragonfly* | netbsd* | solaris* | mingw*) @@ -38864,8 +39821,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -38932,18 +39889,21 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_iswxdigit_works=yes -else $as_nop - gl_cv_func_iswxdigit_works=no +else case e in #( + e) gl_cv_func_iswxdigit_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_iswxdigit_works" >&5 -printf "%s\n" "$gl_cv_func_iswxdigit_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_iswxdigit_works" >&5 +printf '%s\n' "$gl_cv_func_iswxdigit_works" >&6; } case "$gl_cv_func_iswxdigit_works" in *yes) ;; *) REPLACE_ISWXDIGIT=1 ;; @@ -38981,7 +39941,7 @@ printf "%s\n" "$gl_cv_func_iswxdigit_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_ISWXDIGIT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_ISWXDIGIT 1" >>confdefs.h @@ -38999,24 +39959,25 @@ printf "%s\n" "#define GNULIB_TEST_ISWXDIGIT 1" >>confdefs.h ac_fn_check_decl "$LINENO" "ldexpl" "ac_cv_have_decl_ldexpl" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_ldexpl" = xyes then : -else $as_nop - HAVE_DECL_LDEXPL=0 +else case e in #( + e) HAVE_DECL_LDEXPL=0 ;; +esac fi LDEXPL_LIBM= if test $HAVE_DECL_LDEXPL = 1; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ldexpl() can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ldexpl() can be used without linking with libm" >&5 printf %s "checking whether ldexpl() can be used without linking with libm... " >&6; } if test ${gl_cv_func_ldexpl_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -39032,24 +39993,26 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_ldexpl_no_libm=yes -else $as_nop - gl_cv_func_ldexpl_no_libm=no +else case e in #( + e) gl_cv_func_ldexpl_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexpl_no_libm" >&5 -printf "%s\n" "$gl_cv_func_ldexpl_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexpl_no_libm" >&5 +printf '%s\n' "$gl_cv_func_ldexpl_no_libm" >&6; } if test $gl_cv_func_ldexpl_no_libm = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ldexpl() can be used with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ldexpl() can be used with libm" >&5 printf %s "checking whether ldexpl() can be used with libm... " >&6; } if test ${gl_cv_func_ldexpl_in_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) save_LIBS="$LIBS" LIBS="$LIBS -lm" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -39067,16 +40030,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_ldexpl_in_libm=yes -else $as_nop - gl_cv_func_ldexpl_in_libm=no +else case e in #( + e) gl_cv_func_ldexpl_in_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexpl_in_libm" >&5 -printf "%s\n" "$gl_cv_func_ldexpl_in_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexpl_in_libm" >&5 +printf '%s\n' "$gl_cv_func_ldexpl_in_libm" >&6; } if test $gl_cv_func_ldexpl_in_libm = yes; then LDEXPL_LIBM=-lm fi @@ -39087,13 +40052,13 @@ printf "%s\n" "$gl_cv_func_ldexpl_in_libm" >&6; } LIBS="$LIBS $LDEXPL_LIBM" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ldexpl works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ldexpl works" >&5 printf %s "checking whether ldexpl works... " >&6; } if test ${gl_cv_func_ldexpl_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -39104,8 +40069,8 @@ then : *) gl_cv_func_ldexpl_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -39135,17 +40100,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_ldexpl_works=yes -else $as_nop - gl_cv_func_ldexpl_works=no +else case e in #( + e) gl_cv_func_ldexpl_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexpl_works" >&5 -printf "%s\n" "$gl_cv_func_ldexpl_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexpl_works" >&5 +printf '%s\n' "$gl_cv_func_ldexpl_works" >&6; } LIBS="$save_LIBS" case "$gl_cv_func_ldexpl_works" in @@ -39157,7 +40125,7 @@ printf "%s\n" "$gl_cv_func_ldexpl_works" >&6; } fi if test $gl_func_ldexpl = yes; then -printf "%s\n" "#define HAVE_LDEXPL 1" >>confdefs.h +printf '%s\n' "#define HAVE_LDEXPL 1" >>confdefs.h fi fi @@ -39198,18 +40166,18 @@ printf "%s\n" "#define HAVE_LDEXPL 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_LDEXPL 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_LDEXPL 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the __inline keyword" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports the __inline keyword" >&5 printf %s "checking whether the compiler supports the __inline keyword... " >&6; } if test ${gl_cv_c___inline+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ typedef int foo_t; static __inline foo_t foo (void) { return 0; } @@ -39224,16 +40192,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_c___inline=yes -else $as_nop - gl_cv_c___inline=no +else case e in #( + e) gl_cv_c___inline=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_c___inline" >&5 -printf "%s\n" "$gl_cv_c___inline" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_c___inline" >&5 +printf '%s\n' "$gl_cv_c___inline" >&6; } if test $gl_cv_c___inline = yes; then -printf "%s\n" "#define HAVE___INLINE 1" >>confdefs.h +printf '%s\n' "#define HAVE___INLINE 1" >>confdefs.h fi @@ -39257,20 +40227,20 @@ if test "x$ac_cv_type_pthread_rwlock_t" = xyes then : has_rwlock=true -printf "%s\n" "#define HAVE_PTHREAD_RWLOCK 1" >>confdefs.h +printf '%s\n' "#define HAVE_PTHREAD_RWLOCK 1" >>confdefs.h fi if $has_rwlock; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_rwlock_rdlock prefers a writer to a reader" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether pthread_rwlock_rdlock prefers a writer to a reader" >&5 printf %s "checking whether pthread_rwlock_rdlock prefers a writer to a reader... " >&6; } if test ${gl_cv_pthread_rwlock_rdlock_prefer_writer+y} then : printf %s "(cached) " >&6 -else $as_nop - save_LIBS="$LIBS" +else case e in #( + e) save_LIBS="$LIBS" LIBS="$LIBS $LIBMULTITHREAD" if test "$cross_compiling" = yes then : @@ -39293,8 +40263,8 @@ then : *) gl_cv_pthread_rwlock_rdlock_prefer_writer="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -39412,22 +40382,25 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_pthread_rwlock_rdlock_prefer_writer=yes -else $as_nop - gl_cv_pthread_rwlock_rdlock_prefer_writer=no +else case e in #( + e) gl_cv_pthread_rwlock_rdlock_prefer_writer=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi LIBS="$save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_pthread_rwlock_rdlock_prefer_writer" >&5 -printf "%s\n" "$gl_cv_pthread_rwlock_rdlock_prefer_writer" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_pthread_rwlock_rdlock_prefer_writer" >&5 +printf '%s\n' "$gl_cv_pthread_rwlock_rdlock_prefer_writer" >&6; } case "$gl_cv_pthread_rwlock_rdlock_prefer_writer" in *yes) -printf "%s\n" "#define HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER 1" >>confdefs.h +printf '%s\n' "#define HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER 1" >>confdefs.h ;; esac @@ -39459,7 +40432,7 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -printf "%s\n" "#define HAVE_PTHREAD_MUTEX_RECURSIVE 1" >>confdefs.h +printf '%s\n' "#define HAVE_PTHREAD_MUTEX_RECURSIVE 1" >>confdefs.h fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext @@ -39468,7 +40441,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext -printf "%s\n" "#define GNULIB_LOCK 1" >>confdefs.h +printf '%s\n' "#define GNULIB_LOCK 1" >>confdefs.h @@ -39479,13 +40452,13 @@ printf "%s\n" "#define GNULIB_LOCK 1" >>confdefs.h if test $REPLACE_MALLOC = 0; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether malloc (0) returns nonnull" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether malloc (0) returns nonnull" >&5 printf %s "checking whether malloc (0) returns nonnull... " >&6; } if test ${ac_cv_func_malloc_0_nonnull+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on platforms where we know the result. @@ -39497,8 +40470,8 @@ then : *) ac_cv_func_malloc_0_nonnull="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -39517,17 +40490,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_malloc_0_nonnull=yes -else $as_nop - ac_cv_func_malloc_0_nonnull=no +else case e in #( + e) ac_cv_func_malloc_0_nonnull=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 -printf "%s\n" "$ac_cv_func_malloc_0_nonnull" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 +printf '%s\n' "$ac_cv_func_malloc_0_nonnull" >&6; } case $ac_cv_func_malloc_0_nonnull in #( *yes) : ;; #( @@ -39577,7 +40553,7 @@ esac -printf "%s\n" "#define GNULIB_TEST_MALLOC_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_MALLOC_POSIX 1" >>confdefs.h @@ -39616,13 +40592,13 @@ printf "%s\n" "#define GNULIB_TEST_MALLOC_POSIX 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc handles incomplete characters" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc handles incomplete characters" >&5 printf %s "checking whether mbrtowc handles incomplete characters... " >&6; } if test ${gl_cv_func_mbrtowc_incomplete_state+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess no on AIX and OSF/1. aix* | osf*) gl_cv_func_mbrtowc_incomplete_state="guessing no" ;; @@ -39633,8 +40609,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -39659,11 +40635,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_incomplete_state=yes -else $as_nop - gl_cv_func_mbrtowc_incomplete_state=no +else case e in #( + e) gl_cv_func_mbrtowc_incomplete_state=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi else @@ -39671,8 +40649,8 @@ fi if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -39697,30 +40675,33 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_incomplete_state=yes -else $as_nop - gl_cv_func_mbrtowc_incomplete_state=no +else case e in #( + e) gl_cv_func_mbrtowc_incomplete_state=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_incomplete_state" >&5 -printf "%s\n" "$gl_cv_func_mbrtowc_incomplete_state" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_incomplete_state" >&5 +printf '%s\n' "$gl_cv_func_mbrtowc_incomplete_state" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc works as well as mbtowc" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc works as well as mbtowc" >&5 printf %s "checking whether mbrtowc works as well as mbtowc... " >&6; } if test ${gl_cv_func_mbrtowc_sanitycheck+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess no on Solaris 8. solaris2.8) gl_cv_func_mbrtowc_sanitycheck="guessing no" ;; @@ -39731,8 +40712,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -39761,18 +40742,21 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_sanitycheck=yes -else $as_nop - gl_cv_func_mbrtowc_sanitycheck=no +else case e in #( + e) gl_cv_func_mbrtowc_sanitycheck=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_sanitycheck" >&5 -printf "%s\n" "$gl_cv_func_mbrtowc_sanitycheck" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_sanitycheck" >&5 +printf '%s\n' "$gl_cv_func_mbrtowc_sanitycheck" >&6; } REPLACE_MBSTATE_T=0 case "$gl_cv_func_mbrtowc_incomplete_state" in @@ -39794,14 +40778,15 @@ printf "%s\n" "$gl_cv_func_mbrtowc_sanitycheck" >&6; } ac_fn_check_decl "$LINENO" "mbrtowc" "ac_cv_have_decl_mbrtowc" " #include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_mbrtowc" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_MBRTOWC $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_MBRTOWC $ac_have_decl" >>confdefs.h if test $ac_cv_have_decl_mbrtowc = yes; then REPLACE_MBRTOWC=1 @@ -39813,13 +40798,13 @@ printf "%s\n" "#define HAVE_DECL_MBRTOWC $ac_have_decl" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc handles a NULL pwc argument" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc handles a NULL pwc argument" >&5 printf %s "checking whether mbrtowc handles a NULL pwc argument... " >&6; } if test ${gl_cv_func_mbrtowc_null_arg1+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess no on Solaris. solaris*) gl_cv_func_mbrtowc_null_arg1="guessing no" ;; @@ -39830,8 +40815,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -39870,29 +40855,32 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_null_arg1=yes -else $as_nop - gl_cv_func_mbrtowc_null_arg1=no +else case e in #( + e) gl_cv_func_mbrtowc_null_arg1=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_null_arg1" >&5 -printf "%s\n" "$gl_cv_func_mbrtowc_null_arg1" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_null_arg1" >&5 +printf '%s\n' "$gl_cv_func_mbrtowc_null_arg1" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc handles a NULL string argument" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc handles a NULL string argument" >&5 printf %s "checking whether mbrtowc handles a NULL string argument... " >&6; } if test ${gl_cv_func_mbrtowc_null_arg2+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess no on OSF/1. osf*) gl_cv_func_mbrtowc_null_arg2="guessing no" ;; @@ -39903,8 +40891,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -39931,31 +40919,34 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_null_arg2=yes -else $as_nop - gl_cv_func_mbrtowc_null_arg2=no +else case e in #( + e) gl_cv_func_mbrtowc_null_arg2=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_null_arg2" >&5 -printf "%s\n" "$gl_cv_func_mbrtowc_null_arg2" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_null_arg2" >&5 +printf '%s\n' "$gl_cv_func_mbrtowc_null_arg2" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc has a correct return value" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc has a correct return value" >&5 printf %s "checking whether mbrtowc has a correct return value... " >&6; } if test ${gl_cv_func_mbrtowc_retval+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess no on HP-UX, Solaris, native Windows. hpux* | solaris* | mingw*) gl_cv_func_mbrtowc_retval="guessing no" ;; @@ -39967,8 +40958,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -40062,32 +41053,35 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_retval=yes -else $as_nop - if test $? != 77; then +else case e in #( + e) if test $? != 77; then gl_cv_func_mbrtowc_retval=no fi - + ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_retval" >&5 -printf "%s\n" "$gl_cv_func_mbrtowc_retval" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_retval" >&5 +printf '%s\n' "$gl_cv_func_mbrtowc_retval" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc returns 0 when parsing a NUL character" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc returns 0 when parsing a NUL character" >&5 printf %s "checking whether mbrtowc returns 0 when parsing a NUL character... " >&6; } if test ${gl_cv_func_mbrtowc_nul_retval+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess no on Solaris 8 and 9. solaris2.[89]) gl_cv_func_mbrtowc_nul_retval="guessing no" ;; @@ -40098,8 +41092,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -40123,28 +41117,31 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_nul_retval=yes -else $as_nop - gl_cv_func_mbrtowc_nul_retval=no +else case e in #( + e) gl_cv_func_mbrtowc_nul_retval=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_nul_retval" >&5 -printf "%s\n" "$gl_cv_func_mbrtowc_nul_retval" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_nul_retval" >&5 +printf '%s\n' "$gl_cv_func_mbrtowc_nul_retval" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc stores incomplete characters" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc stores incomplete characters" >&5 printf %s "checking whether mbrtowc stores incomplete characters... " >&6; } if test ${gl_cv_func_mbrtowc_stores_incomplete+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess yes on native Windows. mingw*) gl_cv_func_mbrtowc_stores_incomplete="guessing yes" ;; @@ -40155,8 +41152,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -40211,11 +41208,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_stores_incomplete=no -else $as_nop - gl_cv_func_mbrtowc_stores_incomplete=yes +else case e in #( + e) gl_cv_func_mbrtowc_stores_incomplete=yes ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi ;; @@ -40225,8 +41224,8 @@ fi if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -40250,30 +41249,33 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_stores_incomplete=no -else $as_nop - gl_cv_func_mbrtowc_stores_incomplete=yes +else case e in #( + e) gl_cv_func_mbrtowc_stores_incomplete=yes ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_stores_incomplete" >&5 -printf "%s\n" "$gl_cv_func_mbrtowc_stores_incomplete" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_stores_incomplete" >&5 +printf '%s\n' "$gl_cv_func_mbrtowc_stores_incomplete" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc works on empty input" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc works on empty input" >&5 printf %s "checking whether mbrtowc works on empty input... " >&6; } if test ${gl_cv_func_mbrtowc_empty_input+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess no on AIX and glibc systems. aix* | *-gnu* | gnu*) gl_cv_func_mbrtowc_empty_input="guessing no" ;; @@ -40284,8 +41286,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -40300,26 +41302,29 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_empty_input=yes -else $as_nop - gl_cv_func_mbrtowc_empty_input=no +else case e in #( + e) gl_cv_func_mbrtowc_empty_input=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_empty_input" >&5 -printf "%s\n" "$gl_cv_func_mbrtowc_empty_input" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_empty_input" >&5 +printf '%s\n' "$gl_cv_func_mbrtowc_empty_input" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C locale is free of encoding errors" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the C locale is free of encoding errors" >&5 printf %s "checking whether the C locale is free of encoding errors... " >&6; } if test ${gl_cv_func_mbrtowc_C_locale_sans_EILSEQ+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_cv_func_mbrtowc_C_locale_sans_EILSEQ="$gl_cross_guess_normal" if test "$cross_compiling" = yes @@ -40329,8 +41334,8 @@ then : mingw*) gl_cv_func_mbrtowc_C_locale_sans_EILSEQ="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -40362,22 +41367,25 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_C_locale_sans_EILSEQ=yes -else $as_nop - gl_cv_func_mbrtowc_C_locale_sans_EILSEQ=no +else case e in #( + e) gl_cv_func_mbrtowc_C_locale_sans_EILSEQ=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_C_locale_sans_EILSEQ" >&5 -printf "%s\n" "$gl_cv_func_mbrtowc_C_locale_sans_EILSEQ" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_C_locale_sans_EILSEQ" >&5 +printf '%s\n' "$gl_cv_func_mbrtowc_C_locale_sans_EILSEQ" >&6; } case "$gl_cv_func_mbrtowc_null_arg1" in *yes) ;; *) -printf "%s\n" "#define MBRTOWC_NULL_ARG1_BUG 1" >>confdefs.h +printf '%s\n' "#define MBRTOWC_NULL_ARG1_BUG 1" >>confdefs.h REPLACE_MBRTOWC=1 ;; @@ -40385,7 +41393,7 @@ printf "%s\n" "#define MBRTOWC_NULL_ARG1_BUG 1" >>confdefs.h case "$gl_cv_func_mbrtowc_null_arg2" in *yes) ;; *) -printf "%s\n" "#define MBRTOWC_NULL_ARG2_BUG 1" >>confdefs.h +printf '%s\n' "#define MBRTOWC_NULL_ARG2_BUG 1" >>confdefs.h REPLACE_MBRTOWC=1 ;; @@ -40393,7 +41401,7 @@ printf "%s\n" "#define MBRTOWC_NULL_ARG2_BUG 1" >>confdefs.h case "$gl_cv_func_mbrtowc_retval" in *yes) ;; *) -printf "%s\n" "#define MBRTOWC_RETVAL_BUG 1" >>confdefs.h +printf '%s\n' "#define MBRTOWC_RETVAL_BUG 1" >>confdefs.h REPLACE_MBRTOWC=1 ;; @@ -40401,7 +41409,7 @@ printf "%s\n" "#define MBRTOWC_RETVAL_BUG 1" >>confdefs.h case "$gl_cv_func_mbrtowc_nul_retval" in *yes) ;; *) -printf "%s\n" "#define MBRTOWC_NUL_RETVAL_BUG 1" >>confdefs.h +printf '%s\n' "#define MBRTOWC_NUL_RETVAL_BUG 1" >>confdefs.h REPLACE_MBRTOWC=1 ;; @@ -40409,7 +41417,7 @@ printf "%s\n" "#define MBRTOWC_NUL_RETVAL_BUG 1" >>confdefs.h case "$gl_cv_func_mbrtowc_stores_incomplete" in *no) ;; *) -printf "%s\n" "#define MBRTOWC_STORES_INCOMPLETE_BUG 1" >>confdefs.h +printf '%s\n' "#define MBRTOWC_STORES_INCOMPLETE_BUG 1" >>confdefs.h REPLACE_MBRTOWC=1 ;; @@ -40417,7 +41425,7 @@ printf "%s\n" "#define MBRTOWC_STORES_INCOMPLETE_BUG 1" >>confdefs.h case "$gl_cv_func_mbrtowc_empty_input" in *yes) ;; *) -printf "%s\n" "#define MBRTOWC_EMPTY_INPUT_BUG 1" >>confdefs.h +printf '%s\n' "#define MBRTOWC_EMPTY_INPUT_BUG 1" >>confdefs.h REPLACE_MBRTOWC=1 ;; @@ -40425,7 +41433,7 @@ printf "%s\n" "#define MBRTOWC_EMPTY_INPUT_BUG 1" >>confdefs.h case "$gl_cv_func_mbrtowc_C_locale_sans_EILSEQ" in *yes) ;; *) -printf "%s\n" "#define MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ 1" >>confdefs.h +printf '%s\n' "#define MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ 1" >>confdefs.h REPLACE_MBRTOWC=1 ;; @@ -40438,13 +41446,13 @@ printf "%s\n" "#define MBRTOWC_IN_C_LOCALE_MAYBE_EILSEQ 1" >>confdefs.h *) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether imported symbols can be declared weak" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether imported symbols can be declared weak" >&5 printf %s "checking whether imported symbols can be declared weak... " >&6; } if test ${gl_cv_have_weak+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in cygwin*) gl_cv_have_weak="guessing no" ;; @@ -40479,17 +41487,18 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Extensible Linking Format" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Extensible Linking Format" >/dev/null 2>&1 then : gl_cv_have_weak="guessing yes" -else $as_nop - gl_cv_have_weak="guessing no" +else case e in #( + e) gl_cv_have_weak="guessing no" ;; +esac fi rm -rf conftest* -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -40502,11 +41511,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_have_weak=yes -else $as_nop - gl_cv_have_weak=no +else case e in #( + e) gl_cv_have_weak=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi @@ -40536,14 +41547,15 @@ EOF esac ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_weak" >&5 -printf "%s\n" "$gl_cv_have_weak" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_weak" >&5 +printf '%s\n' "$gl_cv_have_weak" >&6; } case "$gl_cv_have_weak" in *yes) -printf "%s\n" "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h +printf '%s\n' "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h ;; esac @@ -40597,13 +41609,13 @@ printf "%s\n" "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h CFLAG_VISIBILITY= HAVE_VISIBILITY=0 if test -n "$GCC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the -Werror option is usable" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the -Werror option is usable" >&5 printf %s "checking whether the -Werror option is usable... " >&6; } if test ${gl_cv_cc_vis_werror+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_save_CFLAGS="$CFLAGS" +else case e in #( + e) gl_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -40619,22 +41631,24 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_cc_vis_werror=yes -else $as_nop - gl_cv_cc_vis_werror=no +else case e in #( + e) gl_cv_cc_vis_werror=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$gl_save_CFLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_vis_werror" >&5 -printf "%s\n" "$gl_cv_cc_vis_werror" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for simple visibility declarations" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_vis_werror" >&5 +printf '%s\n' "$gl_cv_cc_vis_werror" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for simple visibility declarations" >&5 printf %s "checking for simple visibility declarations... " >&6; } if test ${gl_cv_cc_visibility+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_save_CFLAGS="$CFLAGS" +else case e in #( + e) gl_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden" if test $gl_cv_cc_vis_werror = yes; then CFLAGS="$CFLAGS -Werror" @@ -40663,15 +41677,17 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_cc_visibility=yes -else $as_nop - gl_cv_cc_visibility=no +else case e in #( + e) gl_cv_cc_visibility=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$gl_save_CFLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_visibility" >&5 -printf "%s\n" "$gl_cv_cc_visibility" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_visibility" >&5 +printf '%s\n' "$gl_cv_cc_visibility" >&6; } if test $gl_cv_cc_visibility = yes; then CFLAG_VISIBILITY="-fvisibility=hidden" HAVE_VISIBILITY=1 @@ -40680,7 +41696,7 @@ printf "%s\n" "$gl_cv_cc_visibility" >&6; } -printf "%s\n" "#define HAVE_VISIBILITY $HAVE_VISIBILITY" >>confdefs.h +printf '%s\n' "#define HAVE_VISIBILITY $HAVE_VISIBILITY" >>confdefs.h @@ -40705,7 +41721,7 @@ printf "%s\n" "#define HAVE_VISIBILITY $HAVE_VISIBILITY" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_MBRTOWC 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_MBRTOWC 1" >>confdefs.h @@ -40730,13 +41746,13 @@ printf "%s\n" "#define GNULIB_TEST_MBRTOWC 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc handles incomplete characters" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc handles incomplete characters" >&5 printf %s "checking whether mbrtowc handles incomplete characters... " >&6; } if test ${gl_cv_func_mbrtowc_incomplete_state+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess no on AIX and OSF/1. aix* | osf*) gl_cv_func_mbrtowc_incomplete_state="guessing no" ;; @@ -40747,8 +41763,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -40773,11 +41789,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_incomplete_state=yes -else $as_nop - gl_cv_func_mbrtowc_incomplete_state=no +else case e in #( + e) gl_cv_func_mbrtowc_incomplete_state=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi else @@ -40785,8 +41803,8 @@ fi if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -40811,30 +41829,33 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_incomplete_state=yes -else $as_nop - gl_cv_func_mbrtowc_incomplete_state=no +else case e in #( + e) gl_cv_func_mbrtowc_incomplete_state=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_incomplete_state" >&5 -printf "%s\n" "$gl_cv_func_mbrtowc_incomplete_state" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_incomplete_state" >&5 +printf '%s\n' "$gl_cv_func_mbrtowc_incomplete_state" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc works as well as mbtowc" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether mbrtowc works as well as mbtowc" >&5 printf %s "checking whether mbrtowc works as well as mbtowc... " >&6; } if test ${gl_cv_func_mbrtowc_sanitycheck+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) case "$host_os" in # Guess no on Solaris 8. solaris2.8) gl_cv_func_mbrtowc_sanitycheck="guessing no" ;; @@ -40845,8 +41866,8 @@ else $as_nop if test "$cross_compiling" = yes then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -40875,18 +41896,21 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_mbrtowc_sanitycheck=yes -else $as_nop - gl_cv_func_mbrtowc_sanitycheck=no +else case e in #( + e) gl_cv_func_mbrtowc_sanitycheck=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_sanitycheck" >&5 -printf "%s\n" "$gl_cv_func_mbrtowc_sanitycheck" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_mbrtowc_sanitycheck" >&5 +printf '%s\n' "$gl_cv_func_mbrtowc_sanitycheck" >&6; } REPLACE_MBSTATE_T=0 case "$gl_cv_func_mbrtowc_incomplete_state" in @@ -40908,14 +41932,15 @@ printf "%s\n" "$gl_cv_func_mbrtowc_sanitycheck" >&6; } ac_fn_check_decl "$LINENO" "mbsinit" "ac_cv_have_decl_mbsinit" " #include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_mbsinit" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_MBSINIT $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_MBSINIT $ac_have_decl" >>confdefs.h if test $ac_cv_have_decl_mbsinit = yes; then REPLACE_MBSINIT=1 @@ -40960,7 +41985,7 @@ printf "%s\n" "#define HAVE_DECL_MBSINIT $ac_have_decl" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_MBSINIT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_MBSINIT 1" >>confdefs.h @@ -40968,13 +41993,13 @@ printf "%s\n" "#define GNULIB_TEST_MBSINIT 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether mbswidth is declared in " >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether mbswidth is declared in " >&5 printf %s "checking whether mbswidth is declared in ... " >&6; } if test ${ac_cv_have_decl_mbswidth+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -40991,31 +42016,33 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_have_decl_mbswidth=yes -else $as_nop - ac_cv_have_decl_mbswidth=no +else case e in #( + e) ac_cv_have_decl_mbswidth=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_decl_mbswidth" >&5 -printf "%s\n" "$ac_cv_have_decl_mbswidth" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_have_decl_mbswidth" >&5 +printf '%s\n' "$ac_cv_have_decl_mbswidth" >&6; } if test $ac_cv_have_decl_mbswidth = yes; then ac_val=1 else ac_val=0 fi -printf "%s\n" "#define HAVE_DECL_MBSWIDTH_IN_WCHAR_H $ac_val" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_MBSWIDTH_IN_WCHAR_H $ac_val" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for mbstate_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for mbstate_t" >&5 printf %s "checking for mbstate_t... " >&6; } if test ${ac_cv_type_mbstate_t+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default #include @@ -41030,20 +42057,22 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_type_mbstate_t=yes -else $as_nop - ac_cv_type_mbstate_t=no +else case e in #( + e) ac_cv_type_mbstate_t=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_mbstate_t" >&5 -printf "%s\n" "$ac_cv_type_mbstate_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_mbstate_t" >&5 +printf '%s\n' "$ac_cv_type_mbstate_t" >&6; } if test $ac_cv_type_mbstate_t = yes; then -printf "%s\n" "#define HAVE_MBSTATE_T 1" >>confdefs.h +printf '%s\n' "#define HAVE_MBSTATE_T 1" >>confdefs.h else -printf "%s\n" "#define mbstate_t int" >>confdefs.h +printf '%s\n' "#define mbstate_t int" >>confdefs.h fi @@ -41064,7 +42093,7 @@ printf "%s\n" "#define mbstate_t int" >>confdefs.h ac_fn_c_check_header_compile "$LINENO" "bp-sym.h" "ac_cv_header_bp_sym_h" "$ac_includes_default" if test "x$ac_cv_header_bp_sym_h" = xyes then : - printf "%s\n" "#define HAVE_BP_SYM_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_BP_SYM_H 1" >>confdefs.h fi @@ -41085,7 +42114,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_MEMCHR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_MEMCHR 1" >>confdefs.h @@ -41098,7 +42127,7 @@ printf "%s\n" "#define GNULIB_TEST_MEMCHR 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "mempcpy" "ac_cv_func_mempcpy" if test "x$ac_cv_func_mempcpy" = xyes then : - printf "%s\n" "#define HAVE_MEMPCPY 1" >>confdefs.h + printf '%s\n' "#define HAVE_MEMPCPY 1" >>confdefs.h fi @@ -41136,7 +42165,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_MEMPCPY 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_MEMPCPY 1" >>confdefs.h @@ -41171,7 +42200,7 @@ printf "%s\n" "#define GNULIB_TEST_MEMPCPY 1" >>confdefs.h fi -printf "%s\n" "#define GNULIB_MSVC_NOTHROW 1" >>confdefs.h +printf '%s\n' "#define GNULIB_MSVC_NOTHROW 1" >>confdefs.h @@ -41188,13 +42217,13 @@ printf "%s\n" "#define GNULIB_MSVC_NOTHROW 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for obstacks that work with any size object" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for obstacks that work with any size object" >&5 printf %s "checking for obstacks that work with any size object... " >&6; } if test ${ac_cv_func_obstack+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include "obstack.h" void *obstack_chunk_alloc (size_t n) { return 0; } @@ -41216,17 +42245,19 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_func_obstack=yes -else $as_nop - ac_cv_func_obstack=no +else case e in #( + e) ac_cv_func_obstack=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext + conftest$ac_exeext conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_obstack" >&5 -printf "%s\n" "$ac_cv_func_obstack" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_obstack" >&5 +printf '%s\n' "$ac_cv_func_obstack" >&6; } if test "$ac_cv_func_obstack" = yes; then -printf "%s\n" "#define HAVE_OBSTACK 1" >>confdefs.h +printf '%s\n' "#define HAVE_OBSTACK 1" >>confdefs.h else @@ -41289,7 +42320,7 @@ printf "%s\n" "#define HAVE_OBSTACK 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_OBSTACK_PRINTF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_OBSTACK_PRINTF 1" >>confdefs.h @@ -41307,13 +42338,13 @@ printf "%s\n" "#define GNULIB_TEST_OBSTACK_PRINTF 1" >>confdefs.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether open recognizes a trailing slash" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether open recognizes a trailing slash" >&5 printf %s "checking whether open recognizes a trailing slash... " >&6; } if test ${gl_cv_func_open_slash+y} then : printf %s "(cached) " >&6 -else $as_nop - # Assume that if we have lstat, we can also check symlinks. +else case e in #( + e) # Assume that if we have lstat, we can also check symlinks. if test $ac_cv_func_lstat = yes; then touch conftest.tmp ln -s conftest.tmp conftest.lnk @@ -41328,8 +42359,8 @@ then : gl_cv_func_open_slash="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -41355,22 +42386,25 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_open_slash=yes -else $as_nop - gl_cv_func_open_slash=no +else case e in #( + e) gl_cv_func_open_slash=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.sl conftest.tmp conftest.lnk - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_open_slash" >&5 -printf "%s\n" "$gl_cv_func_open_slash" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_open_slash" >&5 +printf '%s\n' "$gl_cv_func_open_slash" >&6; } case "$gl_cv_func_open_slash" in *no) -printf "%s\n" "#define OPEN_TRAILING_SLASH_BUG 1" >>confdefs.h +printf '%s\n' "#define OPEN_TRAILING_SLASH_BUG 1" >>confdefs.h ;; esac @@ -41429,7 +42463,7 @@ printf "%s\n" "#define OPEN_TRAILING_SLASH_BUG 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_OPEN 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_OPEN 1" >>confdefs.h @@ -41446,13 +42480,13 @@ printf "%s\n" "#define GNULIB_TEST_OPEN 1" >>confdefs.h fi case ${gl_cv_func_strerror_r_works-unset} in unset|*yes) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether perror matches strerror" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether perror matches strerror" >&5 printf %s "checking whether perror matches strerror... " >&6; } if test ${gl_cv_func_perror_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on musl systems. @@ -41463,8 +42497,8 @@ then : *) gl_cv_func_perror_works="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -41495,17 +42529,20 @@ then : gl_cv_func_perror_works=no fi rm -rf conftest.txt1 conftest.txt2 -else $as_nop - gl_cv_func_perror_works=no +else case e in #( + e) gl_cv_func_perror_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_perror_works" >&5 -printf "%s\n" "$gl_cv_func_perror_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_perror_works" >&5 +printf '%s\n' "$gl_cv_func_perror_works" >&6; } case "$gl_cv_func_perror_works" in *yes) ;; *) REPLACE_PERROR=1 ;; @@ -41543,7 +42580,7 @@ printf "%s\n" "$gl_cv_func_perror_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_PERROR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_PERROR 1" >>confdefs.h @@ -41582,7 +42619,7 @@ printf "%s\n" "#define GNULIB_TEST_PERROR 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_PIPE 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_PIPE 1" >>confdefs.h @@ -41611,13 +42648,13 @@ printf "%s\n" "#define GNULIB_TEST_PIPE 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_PIPE2 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_PIPE2 1" >>confdefs.h -printf "%s\n" "#define GNULIB_PIPE2_SAFER 1" >>confdefs.h +printf '%s\n' "#define GNULIB_PIPE2_SAFER 1" >>confdefs.h @@ -41650,7 +42687,7 @@ printf "%s\n" "#define GNULIB_PIPE2_SAFER 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWN 1" >>confdefs.h @@ -41694,7 +42731,7 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR 1" >>confdefs.h @@ -41707,13 +42744,13 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR 1" >>confde if test $REPLACE_POSIX_SPAWN = 1; then REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether posix_spawn_file_actions_addclose works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether posix_spawn_file_actions_addclose works" >&5 printf %s "checking whether posix_spawn_file_actions_addclose works... " >&6; } if test ${gl_cv_func_posix_spawn_file_actions_addclose_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : # Guess no on musl libc and Solaris, yes otherwise. case "$host_os" in @@ -41724,8 +42761,8 @@ then : *) gl_cv_func_posix_spawn_file_actions_addclose_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -41742,17 +42779,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_posix_spawn_file_actions_addclose_works=yes -else $as_nop - gl_cv_func_posix_spawn_file_actions_addclose_works=no +else case e in #( + e) gl_cv_func_posix_spawn_file_actions_addclose_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawn_file_actions_addclose_works" >&5 -printf "%s\n" "$gl_cv_func_posix_spawn_file_actions_addclose_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawn_file_actions_addclose_works" >&5 +printf '%s\n' "$gl_cv_func_posix_spawn_file_actions_addclose_works" >&6; } case "$gl_cv_func_posix_spawn_file_actions_addclose_works" in *yes) ;; *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE=1 ;; @@ -41786,7 +42826,7 @@ printf "%s\n" "$gl_cv_func_posix_spawn_file_actions_addclose_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE 1" >>confdefs.h @@ -41799,13 +42839,13 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDCLOSE 1" >>confde if test $REPLACE_POSIX_SPAWN = 1; then REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether posix_spawn_file_actions_adddup2 works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether posix_spawn_file_actions_adddup2 works" >&5 printf %s "checking whether posix_spawn_file_actions_adddup2 works... " >&6; } if test ${gl_cv_func_posix_spawn_file_actions_adddup2_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : # Guess no on musl libc and Solaris, yes otherwise. case "$host_os" in @@ -41816,8 +42856,8 @@ then : *) gl_cv_func_posix_spawn_file_actions_adddup2_works="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -41834,17 +42874,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_posix_spawn_file_actions_adddup2_works=yes -else $as_nop - gl_cv_func_posix_spawn_file_actions_adddup2_works=no +else case e in #( + e) gl_cv_func_posix_spawn_file_actions_adddup2_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawn_file_actions_adddup2_works" >&5 -printf "%s\n" "$gl_cv_func_posix_spawn_file_actions_adddup2_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawn_file_actions_adddup2_works" >&5 +printf '%s\n' "$gl_cv_func_posix_spawn_file_actions_adddup2_works" >&6; } case "$gl_cv_func_posix_spawn_file_actions_adddup2_works" in *yes) ;; *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2=1 ;; @@ -41878,7 +42921,7 @@ printf "%s\n" "$gl_cv_func_posix_spawn_file_actions_adddup2_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2 1" >>confdefs.h @@ -41891,13 +42934,13 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDDUP2 1" >>confdef if test $REPLACE_POSIX_SPAWN = 1; then REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether posix_spawn_file_actions_addopen works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether posix_spawn_file_actions_addopen works" >&5 printf %s "checking whether posix_spawn_file_actions_addopen works... " >&6; } if test ${gl_cv_func_posix_spawn_file_actions_addopen_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : # Guess no on musl libc and Solaris, yes otherwise. case "$host_os" in @@ -41908,8 +42951,8 @@ then : *) gl_cv_func_posix_spawn_file_actions_addopen_works="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -41928,17 +42971,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_posix_spawn_file_actions_addopen_works=yes -else $as_nop - gl_cv_func_posix_spawn_file_actions_addopen_works=no +else case e in #( + e) gl_cv_func_posix_spawn_file_actions_addopen_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawn_file_actions_addopen_works" >&5 -printf "%s\n" "$gl_cv_func_posix_spawn_file_actions_addopen_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_posix_spawn_file_actions_addopen_works" >&5 +printf '%s\n' "$gl_cv_func_posix_spawn_file_actions_addopen_works" >&6; } case "$gl_cv_func_posix_spawn_file_actions_addopen_works" in *yes) ;; *) REPLACE_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN=1 ;; @@ -41972,7 +43018,7 @@ printf "%s\n" "$gl_cv_func_posix_spawn_file_actions_addopen_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN 1" >>confdefs.h @@ -42006,7 +43052,7 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_ADDOPEN 1" >>confdef -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_DESTROY 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_DESTROY 1" >>confdefs.h @@ -42040,7 +43086,7 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_DESTROY 1" >>confdef -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_INIT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_INIT 1" >>confdefs.h @@ -42074,7 +43120,7 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWN_FILE_ACTIONS_INIT 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNATTR_DESTROY 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWNATTR_DESTROY 1" >>confdefs.h @@ -42108,7 +43154,7 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNATTR_DESTROY 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNATTR_INIT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWNATTR_INIT 1" >>confdefs.h @@ -42142,7 +43188,7 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNATTR_INIT 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNATTR_SETFLAGS 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWNATTR_SETFLAGS 1" >>confdefs.h @@ -42176,7 +43222,7 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNATTR_SETFLAGS 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNATTR_SETPGROUP 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWNATTR_SETPGROUP 1" >>confdefs.h @@ -42210,7 +43256,7 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNATTR_SETPGROUP 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNATTR_SETSIGMASK 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWNATTR_SETSIGMASK 1" >>confdefs.h @@ -42244,7 +43290,7 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNATTR_SETSIGMASK 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNP 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_POSIX_SPAWNP 1" >>confdefs.h @@ -42254,13 +43300,13 @@ printf "%s\n" "#define GNULIB_TEST_POSIX_SPAWNP 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether frexp works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether frexp works" >&5 printf %s "checking whether frexp works... " >&6; } if test ${gl_cv_func_frexp_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -42275,11 +43321,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Good" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Good" >/dev/null 2>&1 then : gl_cv_func_frexp_works="guessing yes" -else $as_nop - gl_cv_func_frexp_works="guessing no" +else case e in #( + e) gl_cv_func_frexp_works="guessing no" ;; +esac fi rm -rf conftest* @@ -42287,8 +43334,8 @@ rm -rf conftest* *) gl_cv_func_frexp_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -42358,34 +43405,37 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_frexp_works=yes -else $as_nop - gl_cv_func_frexp_works=no +else case e in #( + e) gl_cv_func_frexp_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexp_works" >&5 -printf "%s\n" "$gl_cv_func_frexp_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexp_works" >&5 +printf '%s\n' "$gl_cv_func_frexp_works" >&6; } case "$gl_cv_func_frexp_works" in *yes) -printf "%s\n" "#define HAVE_FREXP_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_FREXP_IN_LIBC 1" >>confdefs.h ;; esac fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ldexp can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ldexp can be used without linking with libm" >&5 printf %s "checking whether ldexp can be used without linking with libm... " >&6; } if test ${gl_cv_func_ldexp_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -42402,18 +43452,20 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_ldexp_no_libm=yes -else $as_nop - gl_cv_func_ldexp_no_libm=no +else case e in #( + e) gl_cv_func_ldexp_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexp_no_libm" >&5 -printf "%s\n" "$gl_cv_func_ldexp_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexp_no_libm" >&5 +printf '%s\n' "$gl_cv_func_ldexp_no_libm" >&6; } if test $gl_cv_func_ldexp_no_libm = yes; then -printf "%s\n" "#define HAVE_LDEXP_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_LDEXP_IN_LIBC 1" >>confdefs.h fi @@ -42422,13 +43474,13 @@ printf "%s\n" "#define HAVE_LDEXP_IN_LIBC 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether frexpl() can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether frexpl() can be used without linking with libm" >&5 printf %s "checking whether frexpl() can be used without linking with libm... " >&6; } if test ${gl_cv_func_frexpl_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -42444,26 +43496,28 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_frexpl_no_libm=yes -else $as_nop - gl_cv_func_frexpl_no_libm=no +else case e in #( + e) gl_cv_func_frexpl_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexpl_no_libm" >&5 -printf "%s\n" "$gl_cv_func_frexpl_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexpl_no_libm" >&5 +printf '%s\n' "$gl_cv_func_frexpl_no_libm" >&6; } if test $gl_cv_func_frexpl_no_libm = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether frexpl works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether frexpl works" >&5 printf %s "checking whether frexpl works... " >&6; } if test ${gl_cv_func_frexpl_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -42473,8 +43527,8 @@ then : *) gl_cv_func_frexpl_works="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -42575,17 +43629,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_frexpl_works=yes -else $as_nop - gl_cv_func_frexpl_works=no +else case e in #( + e) gl_cv_func_frexpl_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexpl_works" >&5 -printf "%s\n" "$gl_cv_func_frexpl_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_frexpl_works" >&5 +printf '%s\n' "$gl_cv_func_frexpl_works" >&6; } case "$gl_cv_func_frexpl_works" in *yes) gl_func_frexpl_no_libm=yes ;; @@ -42597,26 +43654,27 @@ printf "%s\n" "$gl_cv_func_frexpl_works" >&6; } fi if test $gl_func_frexpl_no_libm = yes; then -printf "%s\n" "#define HAVE_FREXPL_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_FREXPL_IN_LIBC 1" >>confdefs.h ac_fn_check_decl "$LINENO" "frexpl" "ac_cv_have_decl_frexpl" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_frexpl" = xyes then : -else $as_nop - HAVE_DECL_FREXPL=0 +else case e in #( + e) HAVE_DECL_FREXPL=0 ;; +esac fi fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ldexpl() can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ldexpl() can be used without linking with libm" >&5 printf %s "checking whether ldexpl() can be used without linking with libm... " >&6; } if test ${gl_cv_func_ldexpl_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -42632,26 +43690,28 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_ldexpl_no_libm=yes -else $as_nop - gl_cv_func_ldexpl_no_libm=no +else case e in #( + e) gl_cv_func_ldexpl_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexpl_no_libm" >&5 -printf "%s\n" "$gl_cv_func_ldexpl_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexpl_no_libm" >&5 +printf '%s\n' "$gl_cv_func_ldexpl_no_libm" >&6; } if test $gl_cv_func_ldexpl_no_libm = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ldexpl works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ldexpl works" >&5 printf %s "checking whether ldexpl works... " >&6; } if test ${gl_cv_func_ldexpl_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -42662,8 +43722,8 @@ then : *) gl_cv_func_ldexpl_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -42693,30 +43753,34 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_ldexpl_works=yes -else $as_nop - gl_cv_func_ldexpl_works=no +else case e in #( + e) gl_cv_func_ldexpl_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexpl_works" >&5 -printf "%s\n" "$gl_cv_func_ldexpl_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexpl_works" >&5 +printf '%s\n' "$gl_cv_func_ldexpl_works" >&6; } case "$gl_cv_func_ldexpl_works" in *yes) -printf "%s\n" "#define HAVE_LDEXPL_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_LDEXPL_IN_LIBC 1" >>confdefs.h ac_fn_check_decl "$LINENO" "ldexpl" "ac_cv_have_decl_ldexpl" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_ldexpl" = xyes then : -else $as_nop - HAVE_DECL_LDEXPL=0 +else case e in #( + e) HAVE_DECL_LDEXPL=0 ;; +esac fi ;; esac @@ -42740,7 +43804,7 @@ fi REPLACE_PRINTF=1 -printf "%s\n" "#define REPLACE_PRINTF_POSIX 1" >>confdefs.h +printf '%s\n' "#define REPLACE_PRINTF_POSIX 1" >>confdefs.h : @@ -42761,30 +43825,32 @@ printf "%s\n" "#define REPLACE_PRINTF_POSIX 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_PRINTF_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_PRINTF_POSIX 1" >>confdefs.h ac_fn_check_decl "$LINENO" "program_invocation_name" "ac_cv_have_decl_program_invocation_name" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_program_invocation_name" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_PROGRAM_INVOCATION_NAME $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_PROGRAM_INVOCATION_NAME $ac_have_decl" >>confdefs.h ac_fn_check_decl "$LINENO" "program_invocation_short_name" "ac_cv_have_decl_program_invocation_short_name" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_program_invocation_short_name" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME $ac_have_decl" >>confdefs.h : @@ -42799,7 +43865,7 @@ printf "%s\n" "#define HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME $ac_have_decl" >> ac_fn_c_check_func "$LINENO" "raise" "ac_cv_func_raise" if test "x$ac_cv_func_raise" = xyes then : - printf "%s\n" "#define HAVE_RAISE 1" >>confdefs.h + printf '%s\n' "#define HAVE_RAISE 1" >>confdefs.h fi @@ -42860,7 +43926,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_RAISE 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_RAISE 1" >>confdefs.h @@ -42871,7 +43937,7 @@ printf "%s\n" "#define GNULIB_TEST_RAISE 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "rawmemchr" "ac_cv_func_rawmemchr" if test "x$ac_cv_func_rawmemchr" = xyes then : - printf "%s\n" "#define HAVE_RAWMEMCHR 1" >>confdefs.h + printf '%s\n' "#define HAVE_RAWMEMCHR 1" >>confdefs.h fi @@ -42907,7 +43973,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_RAWMEMCHR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_RAWMEMCHR 1" >>confdefs.h @@ -43433,13 +44499,13 @@ fi done - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for readline" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for readline" >&5 printf %s "checking for readline... " >&6; } if test ${gl_cv_lib_readline+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_cv_lib_readline=no am_save_LIBS="$LIBS" for extra_lib in "" ncurses termcap curses; do @@ -43475,24 +44541,25 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ fi done LIBS="$am_save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_lib_readline" >&5 -printf "%s\n" "$gl_cv_lib_readline" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_lib_readline" >&5 +printf '%s\n' "$gl_cv_lib_readline" >&6; } if test "$gl_cv_lib_readline" != no; then -printf "%s\n" "#define HAVE_READLINE 1" >>confdefs.h +printf '%s\n' "#define HAVE_READLINE 1" >>confdefs.h extra_lib=`echo "$gl_cv_lib_readline" | sed -n -e 's/yes, requires //p'` if test -n "$extra_lib"; then LIBREADLINE="$LIBREADLINE $extra_lib" LTLIBREADLINE="$LTLIBREADLINE $extra_lib" fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to link with libreadline" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to link with libreadline" >&5 printf %s "checking how to link with libreadline... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIBREADLINE" >&5 -printf "%s\n" "$LIBREADLINE" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LIBREADLINE" >&5 +printf '%s\n' "$LIBREADLINE" >&6; } else CPPFLAGS="$am_save_CPPFLAGS" LIBREADLINE= @@ -43504,13 +44571,13 @@ printf "%s\n" "$LIBREADLINE" >&6; } ac_fn_c_check_header_compile "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default" if test "x$ac_cv_header_readline_readline_h" = xyes then : - printf "%s\n" "#define HAVE_READLINE_READLINE_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_READLINE_READLINE_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "readline/history.h" "ac_cv_header_readline_history_h" "$ac_includes_default" if test "x$ac_cv_header_readline_history_h" = xyes then : - printf "%s\n" "#define HAVE_READLINE_HISTORY_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_READLINE_HISTORY_H 1" >>confdefs.h fi @@ -43536,13 +44603,13 @@ fi if test $ac_cv_func_readlink = no; then HAVE_READLINK=0 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether readlink signature is correct" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether readlink signature is correct" >&5 printf %s "checking whether readlink signature is correct... " >&6; } if test ${gl_cv_decl_readlink_works+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Cause compilation failure if original declaration has wrong type. */ @@ -43558,20 +44625,22 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_decl_readlink_works=yes -else $as_nop - gl_cv_decl_readlink_works=no +else case e in #( + e) gl_cv_decl_readlink_works=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_decl_readlink_works" >&5 -printf "%s\n" "$gl_cv_decl_readlink_works" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether readlink handles trailing slash correctly" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_decl_readlink_works" >&5 +printf '%s\n' "$gl_cv_decl_readlink_works" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether readlink handles trailing slash correctly" >&5 printf %s "checking whether readlink handles trailing slash correctly... " >&6; } if test ${gl_cv_func_readlink_trailing_slash+y} then : printf %s "(cached) " >&6 -else $as_nop - # We have readlink, so assume ln -s works. +else case e in #( + e) # We have readlink, so assume ln -s works. ln -s conftest.no-such conftest.link ln -s conftest.link conftest.lnk2 if test "$cross_compiling" = yes @@ -43588,8 +44657,8 @@ then : gl_cv_func_readlink_trailing_slash="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -43605,17 +44674,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_readlink_trailing_slash=yes -else $as_nop - gl_cv_func_readlink_trailing_slash=no +else case e in #( + e) gl_cv_func_readlink_trailing_slash=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - rm -f conftest.link conftest.lnk2 + rm -f conftest.link conftest.lnk2 ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_readlink_trailing_slash" >&5 -printf "%s\n" "$gl_cv_func_readlink_trailing_slash" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_readlink_trailing_slash" >&5 +printf '%s\n' "$gl_cv_func_readlink_trailing_slash" >&6; } case "$gl_cv_func_readlink_trailing_slash" in *yes) if test "$gl_cv_decl_readlink_works" != yes; then @@ -43624,19 +44696,19 @@ printf "%s\n" "$gl_cv_func_readlink_trailing_slash" >&6; } ;; *) -printf "%s\n" "#define READLINK_TRAILING_SLASH_BUG 1" >>confdefs.h +printf '%s\n' "#define READLINK_TRAILING_SLASH_BUG 1" >>confdefs.h REPLACE_READLINK=1 ;; esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether readlink truncates results correctly" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether readlink truncates results correctly" >&5 printf %s "checking whether readlink truncates results correctly... " >&6; } if test ${gl_cv_func_readlink_truncate+y} then : printf %s "(cached) " >&6 -else $as_nop - # We have readlink, so assume ln -s works. +else case e in #( + e) # We have readlink, so assume ln -s works. ln -s ab conftest.link if test "$cross_compiling" = yes then : @@ -43652,8 +44724,8 @@ then : gl_cv_func_readlink_truncate="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -43669,17 +44741,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_readlink_truncate=yes -else $as_nop - gl_cv_func_readlink_truncate=no +else case e in #( + e) gl_cv_func_readlink_truncate=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - rm -f conftest.link conftest.lnk2 + rm -f conftest.link conftest.lnk2 ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_readlink_truncate" >&5 -printf "%s\n" "$gl_cv_func_readlink_truncate" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_readlink_truncate" >&5 +printf '%s\n' "$gl_cv_func_readlink_truncate" >&6; } case $gl_cv_func_readlink_truncate in *yes) if test "$gl_cv_decl_readlink_works" != yes; then @@ -43688,7 +44763,7 @@ printf "%s\n" "$gl_cv_func_readlink_truncate" >&6; } ;; *) -printf "%s\n" "#define READLINK_TRUNCATE_BUG 1" >>confdefs.h +printf '%s\n' "#define READLINK_TRUNCATE_BUG 1" >>confdefs.h REPLACE_READLINK=1 ;; @@ -43725,7 +44800,7 @@ printf "%s\n" "#define READLINK_TRUNCATE_BUG 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_READLINK 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_READLINK 1" >>confdefs.h @@ -43734,13 +44809,13 @@ printf "%s\n" "#define GNULIB_TEST_READLINK 1" >>confdefs.h if test $REPLACE_REALLOC = 0; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether realloc (0, 0) returns nonnull" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether realloc (0, 0) returns nonnull" >&5 printf %s "checking whether realloc (0, 0) returns nonnull... " >&6; } if test ${ac_cv_func_realloc_0_nonnull+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on platforms where we know the result. @@ -43752,8 +44827,8 @@ then : *) ac_cv_func_realloc_0_nonnull="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -43772,17 +44847,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_realloc_0_nonnull=yes -else $as_nop - ac_cv_func_realloc_0_nonnull=no +else case e in #( + e) ac_cv_func_realloc_0_nonnull=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 -printf "%s\n" "$ac_cv_func_realloc_0_nonnull" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 +printf '%s\n' "$ac_cv_func_realloc_0_nonnull" >&6; } case $ac_cv_func_realloc_0_nonnull in #( *yes) : ;; #( @@ -43838,7 +44916,7 @@ esac -printf "%s\n" "#define GNULIB_TEST_REALLOC_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_REALLOC_POSIX 1" >>confdefs.h @@ -43850,7 +44928,7 @@ printf "%s\n" "#define GNULIB_TEST_REALLOC_POSIX 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" if test "x$ac_cv_func_reallocarray" = xyes then : - printf "%s\n" "#define HAVE_REALLOCARRAY 1" >>confdefs.h + printf '%s\n' "#define HAVE_REALLOCARRAY 1" >>confdefs.h fi @@ -43875,7 +44953,7 @@ fi fi -printf "%s\n" "#define GNULIB_REALLOCARRAY 1" >>confdefs.h +printf '%s\n' "#define GNULIB_REALLOCARRAY 1" >>confdefs.h @@ -43893,7 +44971,7 @@ printf "%s\n" "#define GNULIB_REALLOCARRAY 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_REALLOCARRAY 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_REALLOCARRAY 1" >>confdefs.h @@ -43946,7 +45024,7 @@ printf "%s\n" "#define GNULIB_TEST_REALLOCARRAY 1" >>confdefs.h *) ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" if test "x$ac_cv_func_getcwd" = xyes then : - printf "%s\n" "#define HAVE_GETCWD 1" >>confdefs.h + printf '%s\n' "#define HAVE_GETCWD 1" >>confdefs.h fi ;; @@ -43962,7 +45040,7 @@ fi if test "$gl_cv_func_malloc_posix" = yes; then -printf "%s\n" "#define HAVE_MALLOC_POSIX 1" >>confdefs.h +printf '%s\n' "#define HAVE_MALLOC_POSIX 1" >>confdefs.h else REPLACE_MALLOC=1 @@ -43978,13 +45056,13 @@ printf "%s\n" "#define HAVE_MALLOC_POSIX 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether free is known to preserve errno" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether free is known to preserve errno" >&5 printf %s "checking whether free is known to preserve errno... " >&6; } if test ${gl_cv_func_free_preserves_errno+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -44005,19 +45083,21 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_free_preserves_errno=yes -else $as_nop - gl_cv_func_free_preserves_errno=no +else case e in #( + e) gl_cv_func_free_preserves_errno=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_free_preserves_errno" >&5 -printf "%s\n" "$gl_cv_func_free_preserves_errno" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_free_preserves_errno" >&5 +printf '%s\n' "$gl_cv_func_free_preserves_errno" >&6; } case $gl_cv_func_free_preserves_errno in *yes) -printf "%s\n" "#define HAVE_FREE_POSIX 1" >>confdefs.h +printf '%s\n' "#define HAVE_FREE_POSIX 1" >>confdefs.h ;; *) REPLACE_FREE=1 ;; @@ -44032,7 +45112,7 @@ printf "%s\n" "#define HAVE_FREE_POSIX 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "mempcpy" "ac_cv_func_mempcpy" if test "x$ac_cv_func_mempcpy" = xyes then : - printf "%s\n" "#define HAVE_MEMPCPY 1" >>confdefs.h + printf '%s\n' "#define HAVE_MEMPCPY 1" >>confdefs.h fi @@ -44047,7 +45127,7 @@ fi ac_fn_c_check_func "$LINENO" "rawmemchr" "ac_cv_func_rawmemchr" if test "x$ac_cv_func_rawmemchr" = xyes then : - printf "%s\n" "#define HAVE_RAWMEMCHR 1" >>confdefs.h + printf '%s\n' "#define HAVE_RAWMEMCHR 1" >>confdefs.h fi @@ -44075,14 +45155,14 @@ fi ac_fn_c_check_header_compile "$LINENO" "search.h" "ac_cv_header_search_h" "$ac_includes_default" if test "x$ac_cv_header_search_h" = xyes then : - printf "%s\n" "#define HAVE_SEARCH_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_SEARCH_H 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "tsearch" "ac_cv_func_tsearch" if test "x$ac_cv_func_tsearch" = xyes then : - printf "%s\n" "#define HAVE_TSEARCH 1" >>confdefs.h + printf '%s\n' "#define HAVE_TSEARCH 1" >>confdefs.h fi @@ -44096,13 +45176,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether rename honors trailing slash on destination" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether rename honors trailing slash on destination" >&5 printf %s "checking whether rename honors trailing slash on destination... " >&6; } if test ${gl_cv_func_rename_slash_dst_works+y} then : printf %s "(cached) " >&6 -else $as_nop - rm -rf conftest.f conftest.f1 conftest.f2 conftest.d1 conftest.d2 conftest.lnk +else case e in #( + e) rm -rf conftest.f conftest.f1 conftest.f2 conftest.d1 conftest.d2 conftest.lnk touch conftest.f && touch conftest.f1 && mkdir conftest.d1 || as_fn_error $? "cannot create temporary files" "$LINENO" 5 # Assume that if we have lstat, we can also check symlinks. @@ -44122,8 +45202,8 @@ then : *) gl_cv_func_rename_slash_dst_works="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include @@ -44150,35 +45230,38 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_rename_slash_dst_works=yes -else $as_nop - gl_cv_func_rename_slash_dst_works=no +else case e in #( + e) gl_cv_func_rename_slash_dst_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -rf conftest.f conftest.f1 conftest.f2 conftest.d1 conftest.d2 conftest.lnk - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_rename_slash_dst_works" >&5 -printf "%s\n" "$gl_cv_func_rename_slash_dst_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_rename_slash_dst_works" >&5 +printf '%s\n' "$gl_cv_func_rename_slash_dst_works" >&6; } case "$gl_cv_func_rename_slash_dst_works" in *yes) ;; *) REPLACE_RENAME=1 -printf "%s\n" "#define RENAME_TRAILING_SLASH_DEST_BUG 1" >>confdefs.h +printf '%s\n' "#define RENAME_TRAILING_SLASH_DEST_BUG 1" >>confdefs.h ;; esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether rename honors trailing slash on source" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether rename honors trailing slash on source" >&5 printf %s "checking whether rename honors trailing slash on source... " >&6; } if test ${gl_cv_func_rename_slash_src_works+y} then : printf %s "(cached) " >&6 -else $as_nop - rm -rf conftest.f conftest.f1 conftest.d1 conftest.d2 conftest.d3 conftest.lnk +else case e in #( + e) rm -rf conftest.f conftest.f1 conftest.d1 conftest.d2 conftest.d3 conftest.lnk touch conftest.f && touch conftest.f1 && mkdir conftest.d1 || as_fn_error $? "cannot create temporary files" "$LINENO" 5 # Assume that if we have lstat, we can also check symlinks. @@ -44198,8 +45281,8 @@ then : *) gl_cv_func_rename_slash_src_works="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include @@ -44226,36 +45309,39 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_rename_slash_src_works=yes -else $as_nop - gl_cv_func_rename_slash_src_works=no +else case e in #( + e) gl_cv_func_rename_slash_src_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -rf conftest.f conftest.f1 conftest.d1 conftest.d2 conftest.d3 conftest.lnk - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_rename_slash_src_works" >&5 -printf "%s\n" "$gl_cv_func_rename_slash_src_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_rename_slash_src_works" >&5 +printf '%s\n' "$gl_cv_func_rename_slash_src_works" >&6; } case "$gl_cv_func_rename_slash_src_works" in *yes) ;; *) REPLACE_RENAME=1 -printf "%s\n" "#define RENAME_TRAILING_SLASH_SOURCE_BUG 1" >>confdefs.h +printf '%s\n' "#define RENAME_TRAILING_SLASH_SOURCE_BUG 1" >>confdefs.h ;; esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether rename manages hard links correctly" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether rename manages hard links correctly" >&5 printf %s "checking whether rename manages hard links correctly... " >&6; } if test ${gl_cv_func_rename_link_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test $ac_cv_func_link = yes; then +else case e in #( + e) if test $ac_cv_func_link = yes; then if test $cross_compiling != yes; then rm -rf conftest.f conftest.f1 conftest.f2 if touch conftest.f conftest.f2 && ln conftest.f conftest.f1 && @@ -44264,8 +45350,8 @@ else $as_nop then : : -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include @@ -44305,11 +45391,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_rename_link_works=yes -else $as_nop - gl_cv_func_rename_link_works=no +else case e in #( + e) gl_cv_func_rename_link_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi else @@ -44331,27 +45419,28 @@ fi else gl_cv_func_rename_link_works=yes fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_rename_link_works" >&5 -printf "%s\n" "$gl_cv_func_rename_link_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_rename_link_works" >&5 +printf '%s\n' "$gl_cv_func_rename_link_works" >&6; } case "$gl_cv_func_rename_link_works" in *yes) ;; *) REPLACE_RENAME=1 -printf "%s\n" "#define RENAME_HARD_LINK_BUG 1" >>confdefs.h +printf '%s\n' "#define RENAME_HARD_LINK_BUG 1" >>confdefs.h ;; esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether rename manages existing destinations correctly" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether rename manages existing destinations correctly" >&5 printf %s "checking whether rename manages existing destinations correctly... " >&6; } if test ${gl_cv_func_rename_dest_works+y} then : printf %s "(cached) " >&6 -else $as_nop - rm -rf conftest.f conftest.d1 conftest.d2 +else case e in #( + e) rm -rf conftest.f conftest.d1 conftest.d2 touch conftest.f && mkdir conftest.d1 conftest.d2 || as_fn_error $? "cannot create temporary files" "$LINENO" 5 if test "$cross_compiling" = yes @@ -44367,8 +45456,8 @@ then : *) gl_cv_func_rename_dest_works="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include @@ -44391,24 +45480,27 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_rename_dest_works=yes -else $as_nop - gl_cv_func_rename_dest_works=no +else case e in #( + e) gl_cv_func_rename_dest_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -rf conftest.f conftest.d1 conftest.d2 - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_rename_dest_works" >&5 -printf "%s\n" "$gl_cv_func_rename_dest_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_rename_dest_works" >&5 +printf '%s\n' "$gl_cv_func_rename_dest_works" >&6; } case "$gl_cv_func_rename_dest_works" in *yes) ;; *) REPLACE_RENAME=1 -printf "%s\n" "#define RENAME_DEST_EXISTS_BUG 1" >>confdefs.h +printf '%s\n' "#define RENAME_DEST_EXISTS_BUG 1" >>confdefs.h ;; esac @@ -44440,7 +45532,7 @@ printf "%s\n" "#define RENAME_DEST_EXISTS_BUG 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_RENAME 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_RENAME 1" >>confdefs.h @@ -44460,7 +45552,7 @@ printf "%s\n" "#define GNULIB_TEST_RENAME 1" >>confdefs.h if test "x$ac_cv_member_struct_sigaction_sa_sigaction" = xyes then : -printf "%s\n" "#define HAVE_STRUCT_SIGACTION_SA_SIGACTION 1" >>confdefs.h +printf '%s\n' "#define HAVE_STRUCT_SIGACTION_SA_SIGACTION 1" >>confdefs.h fi @@ -44496,7 +45588,7 @@ fi if test "x$ac_cv_type_siginfo_t" = xyes then : -printf "%s\n" "#define HAVE_SIGINFO_T 1" >>confdefs.h +printf '%s\n' "#define HAVE_SIGINFO_T 1" >>confdefs.h fi @@ -44521,7 +45613,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_SIGACTION 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_SIGACTION 1" >>confdefs.h @@ -44534,13 +45626,13 @@ printf "%s\n" "#define GNULIB_TEST_SIGACTION 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for signbit macro" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for signbit macro" >&5 printf %s "checking for signbit macro... " >&6; } if test ${gl_cv_func_signbit+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -44554,8 +45646,8 @@ then : *) gl_cv_func_signbit="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -44648,24 +45740,27 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_signbit=yes -else $as_nop - gl_cv_func_signbit=no +else case e in #( + e) gl_cv_func_signbit=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_signbit" >&5 -printf "%s\n" "$gl_cv_func_signbit" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for signbit compiler built-ins" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_signbit" >&5 +printf '%s\n' "$gl_cv_func_signbit" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for signbit compiler built-ins" >&5 printf %s "checking for signbit compiler built-ins... " >&6; } if test ${gl_cv_func_signbit_builtins+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -44684,8 +45779,8 @@ then : *) gl_cv_func_signbit_builtins="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if (__GNUC__ >= 4) || (__clang_major__ >= 4) @@ -44775,17 +45870,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_signbit_builtins=yes -else $as_nop - gl_cv_func_signbit_builtins=no +else case e in #( + e) gl_cv_func_signbit_builtins=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_signbit_builtins" >&5 -printf "%s\n" "$gl_cv_func_signbit_builtins" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_signbit_builtins" >&5 +printf '%s\n' "$gl_cv_func_signbit_builtins" >&6; } case "$gl_cv_func_signbit_builtins" in *yes) REPLACE_SIGNBIT_USING_BUILTINS=1 @@ -44807,20 +45905,20 @@ printf "%s\n" "$gl_cv_func_signbit_builtins" >&6; } if test $REPLACE_SIGNBIT = 1; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking where to find the sign bit in a 'float'" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking where to find the sign bit in a 'float'" >&5 printf %s "checking where to find the sign bit in a 'float'... " >&6; } if test ${gl_cv_cc_float_signbit+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : gl_cv_cc_float_signbit="unknown" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -44885,27 +45983,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_cc_float_signbit=`cat conftest.out` -else $as_nop - gl_cv_cc_float_signbit="unknown" +else case e in #( + e) gl_cv_cc_float_signbit="unknown" ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.out - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_float_signbit" >&5 -printf "%s\n" "$gl_cv_cc_float_signbit" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_float_signbit" >&5 +printf '%s\n' "$gl_cv_cc_float_signbit" >&6; } case "$gl_cv_cc_float_signbit" in word*bit*) word=`echo "$gl_cv_cc_float_signbit" | sed -e 's/word //' -e 's/ bit.*//'` bit=`echo "$gl_cv_cc_float_signbit" | sed -e 's/word.*bit //'` -printf "%s\n" "#define FLT_SIGNBIT_WORD $word" >>confdefs.h +printf '%s\n' "#define FLT_SIGNBIT_WORD $word" >>confdefs.h -printf "%s\n" "#define FLT_SIGNBIT_BIT $bit" >>confdefs.h +printf '%s\n' "#define FLT_SIGNBIT_BIT $bit" >>confdefs.h ;; esac @@ -44913,20 +46014,20 @@ printf "%s\n" "#define FLT_SIGNBIT_BIT $bit" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking where to find the sign bit in a 'double'" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking where to find the sign bit in a 'double'" >&5 printf %s "checking where to find the sign bit in a 'double'... " >&6; } if test ${gl_cv_cc_double_signbit+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : gl_cv_cc_double_signbit="unknown" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -44991,27 +46092,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_cc_double_signbit=`cat conftest.out` -else $as_nop - gl_cv_cc_double_signbit="unknown" +else case e in #( + e) gl_cv_cc_double_signbit="unknown" ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.out - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_double_signbit" >&5 -printf "%s\n" "$gl_cv_cc_double_signbit" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_double_signbit" >&5 +printf '%s\n' "$gl_cv_cc_double_signbit" >&6; } case "$gl_cv_cc_double_signbit" in word*bit*) word=`echo "$gl_cv_cc_double_signbit" | sed -e 's/word //' -e 's/ bit.*//'` bit=`echo "$gl_cv_cc_double_signbit" | sed -e 's/word.*bit //'` -printf "%s\n" "#define DBL_SIGNBIT_WORD $word" >>confdefs.h +printf '%s\n' "#define DBL_SIGNBIT_WORD $word" >>confdefs.h -printf "%s\n" "#define DBL_SIGNBIT_BIT $bit" >>confdefs.h +printf '%s\n' "#define DBL_SIGNBIT_BIT $bit" >>confdefs.h ;; esac @@ -45019,20 +46123,20 @@ printf "%s\n" "#define DBL_SIGNBIT_BIT $bit" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking where to find the sign bit in a 'long double'" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking where to find the sign bit in a 'long double'" >&5 printf %s "checking where to find the sign bit in a 'long double'... " >&6; } if test ${gl_cv_cc_long_double_signbit+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : gl_cv_cc_long_double_signbit="unknown" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -45097,27 +46201,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_cc_long_double_signbit=`cat conftest.out` -else $as_nop - gl_cv_cc_long_double_signbit="unknown" +else case e in #( + e) gl_cv_cc_long_double_signbit="unknown" ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.out - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_long_double_signbit" >&5 -printf "%s\n" "$gl_cv_cc_long_double_signbit" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_long_double_signbit" >&5 +printf '%s\n' "$gl_cv_cc_long_double_signbit" >&6; } case "$gl_cv_cc_long_double_signbit" in word*bit*) word=`echo "$gl_cv_cc_long_double_signbit" | sed -e 's/word //' -e 's/ bit.*//'` bit=`echo "$gl_cv_cc_long_double_signbit" | sed -e 's/word.*bit //'` -printf "%s\n" "#define LDBL_SIGNBIT_WORD $word" >>confdefs.h +printf '%s\n' "#define LDBL_SIGNBIT_WORD $word" >>confdefs.h -printf "%s\n" "#define LDBL_SIGNBIT_BIT $bit" >>confdefs.h +printf '%s\n' "#define LDBL_SIGNBIT_BIT $bit" >>confdefs.h ;; esac @@ -45125,23 +46232,24 @@ printf "%s\n" "#define LDBL_SIGNBIT_BIT $bit" >>confdefs.h if test "$gl_cv_cc_float_signbit" = unknown; then ac_fn_check_decl "$LINENO" "copysignf" "ac_cv_have_decl_copysignf" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_copysignf" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_COPYSIGNF $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_COPYSIGNF $ac_have_decl" >>confdefs.h if test "$ac_cv_have_decl_copysignf" = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether copysignf can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether copysignf can be used without linking with libm" >&5 printf %s "checking whether copysignf can be used without linking with libm... " >&6; } if test ${gl_cv_func_copysignf_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -45157,41 +46265,44 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_copysignf_no_libm=yes -else $as_nop - gl_cv_func_copysignf_no_libm=no +else case e in #( + e) gl_cv_func_copysignf_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_copysignf_no_libm" >&5 -printf "%s\n" "$gl_cv_func_copysignf_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_copysignf_no_libm" >&5 +printf '%s\n' "$gl_cv_func_copysignf_no_libm" >&6; } if test $gl_cv_func_copysignf_no_libm = yes; then -printf "%s\n" "#define HAVE_COPYSIGNF_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_COPYSIGNF_IN_LIBC 1" >>confdefs.h fi fi fi if test "$gl_cv_cc_double_signbit" = unknown; then ac_fn_check_decl "$LINENO" "copysign" "ac_cv_have_decl_copysign" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_copysign" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_COPYSIGN $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_COPYSIGN $ac_have_decl" >>confdefs.h if test "$ac_cv_have_decl_copysign" = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether copysign can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether copysign can be used without linking with libm" >&5 printf %s "checking whether copysign can be used without linking with libm... " >&6; } if test ${gl_cv_func_copysign_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -45207,41 +46318,44 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_copysign_no_libm=yes -else $as_nop - gl_cv_func_copysign_no_libm=no +else case e in #( + e) gl_cv_func_copysign_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_copysign_no_libm" >&5 -printf "%s\n" "$gl_cv_func_copysign_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_copysign_no_libm" >&5 +printf '%s\n' "$gl_cv_func_copysign_no_libm" >&6; } if test $gl_cv_func_copysign_no_libm = yes; then -printf "%s\n" "#define HAVE_COPYSIGN_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_COPYSIGN_IN_LIBC 1" >>confdefs.h fi fi fi if test "$gl_cv_cc_long_double_signbit" = unknown; then ac_fn_check_decl "$LINENO" "copysignl" "ac_cv_have_decl_copysignl" "#include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_copysignl" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_COPYSIGNL $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_COPYSIGNL $ac_have_decl" >>confdefs.h if test "$ac_cv_have_decl_copysignl" = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether copysignl can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether copysignl can be used without linking with libm" >&5 printf %s "checking whether copysignl can be used without linking with libm... " >&6; } if test ${gl_cv_func_copysignl_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -45257,18 +46371,20 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_copysignl_no_libm=yes -else $as_nop - gl_cv_func_copysignl_no_libm=no +else case e in #( + e) gl_cv_func_copysignl_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_copysignl_no_libm" >&5 -printf "%s\n" "$gl_cv_func_copysignl_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_copysignl_no_libm" >&5 +printf '%s\n' "$gl_cv_func_copysignl_no_libm" >&6; } if test $gl_cv_func_copysignl_no_libm = yes; then -printf "%s\n" "#define HAVE_COPYSIGNL_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_COPYSIGNL_IN_LIBC 1" >>confdefs.h fi fi @@ -45322,7 +46438,7 @@ printf "%s\n" "#define HAVE_COPYSIGNL_IN_LIBC 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_SIGNBIT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_SIGNBIT 1" >>confdefs.h @@ -45367,7 +46483,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_SIGPROCMASK 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_SIGPROCMASK 1" >>confdefs.h @@ -45375,17 +46491,17 @@ printf "%s\n" "#define GNULIB_TEST_SIGPROCMASK 1" >>confdefs.h ac_fn_c_check_header_compile "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" if test "x$ac_cv_header_stdint_h" = xyes then : - printf "%s\n" "#define HAVE_STDINT_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_STDINT_H 1" >>confdefs.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SIZE_MAX" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for SIZE_MAX" >&5 printf %s "checking for SIZE_MAX... " >&6; } if test ${gl_cv_size_max+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) gl_cv_size_max=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -45400,7 +46516,7 @@ Found it _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Found it" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Found it" >/dev/null 2>&1 then : gl_cv_size_max=yes fi @@ -45411,15 +46527,17 @@ rm -rf conftest* #include " then : -else $as_nop - size_t_bits_minus_1= +else case e in #( + e) size_t_bits_minus_1= ;; +esac fi if ac_fn_c_compute_int "$LINENO" "sizeof (size_t) <= sizeof (unsigned int)" "fits_in_uint" "#include " then : -else $as_nop - fits_in_uint= +else case e in #( + e) fits_in_uint= ;; +esac fi if test -n "$size_t_bits_minus_1" && test -n "$fits_in_uint"; then @@ -45453,13 +46571,14 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext gl_cv_size_max='((size_t)~(size_t)0)' fi fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_size_max" >&5 -printf "%s\n" "$gl_cv_size_max" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_size_max" >&5 +printf '%s\n' "$gl_cv_size_max" >&6; } if test "$gl_cv_size_max" != yes; then -printf "%s\n" "#define SIZE_MAX $gl_cv_size_max" >>confdefs.h +printf '%s\n' "#define SIZE_MAX $gl_cv_size_max" >>confdefs.h fi @@ -45470,7 +46589,7 @@ printf "%s\n" "#define SIZE_MAX $gl_cv_size_max" >>confdefs.h ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" if test "x$ac_cv_func_snprintf" = xyes then : - printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h + printf '%s\n' "#define HAVE_SNPRINTF 1" >>confdefs.h fi @@ -45478,13 +46597,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether snprintf respects a size of 1" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether snprintf respects a size of 1" >&5 printf %s "checking whether snprintf respects a size of 1... " >&6; } if test ${gl_cv_func_snprintf_size1+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -45495,8 +46614,8 @@ then : *) gl_cv_func_snprintf_size1="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -45524,17 +46643,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_snprintf_size1=yes -else $as_nop - gl_cv_func_snprintf_size1=no +else case e in #( + e) gl_cv_func_snprintf_size1=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_size1" >&5 -printf "%s\n" "$gl_cv_func_snprintf_size1" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_size1" >&5 +printf '%s\n' "$gl_cv_func_snprintf_size1" >&6; } case "$gl_cv_func_snprintf_size1" in *yes) @@ -45543,13 +46665,13 @@ printf "%s\n" "$gl_cv_func_snprintf_size1" >&6; } *yes) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports POSIX/XSI format strings with positions" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports POSIX/XSI format strings with positions" >&5 printf %s "checking whether printf supports POSIX/XSI format strings with positions... " >&6; } if test ${gl_cv_func_printf_positions+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -45564,8 +46686,8 @@ then : *) gl_cv_func_printf_positions="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -45583,17 +46705,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_positions=yes -else $as_nop - gl_cv_func_printf_positions=no +else case e in #( + e) gl_cv_func_printf_positions=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_positions" >&5 -printf "%s\n" "$gl_cv_func_printf_positions" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_positions" >&5 +printf '%s\n' "$gl_cv_func_printf_positions" >&6; } case "$gl_cv_func_printf_positions" in *yes) @@ -45649,13 +46774,13 @@ printf "%s\n" "$gl_cv_func_printf_positions" >&6; } -printf "%s\n" "#define GNULIB_TEST_SNPRINTF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_SNPRINTF 1" >>confdefs.h -printf "%s\n" "#define GNULIB_SNPRINTF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_SNPRINTF 1" >>confdefs.h @@ -45677,7 +46802,7 @@ printf "%s\n" "#define GNULIB_SNPRINTF 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "snprintf" "ac_cv_func_snprintf" if test "x$ac_cv_func_snprintf" = xyes then : - printf "%s\n" "#define HAVE_SNPRINTF 1" >>confdefs.h + printf '%s\n' "#define HAVE_SNPRINTF 1" >>confdefs.h fi @@ -45687,13 +46812,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether snprintf fully supports the 'n' directive" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether snprintf fully supports the 'n' directive" >&5 printf %s "checking whether snprintf fully supports the 'n' directive... " >&6; } if test ${gl_cv_func_snprintf_directive_n+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -45709,8 +46834,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_snprintf_directive_n="guessing yes" -else $as_nop - gl_cv_func_snprintf_directive_n="guessing no" +else case e in #( + e) gl_cv_func_snprintf_directive_n="guessing no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -45749,8 +46875,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext *) gl_cv_func_snprintf_directive_n="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -45787,28 +46913,31 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_snprintf_directive_n=yes -else $as_nop - gl_cv_func_snprintf_directive_n=no +else case e in #( + e) gl_cv_func_snprintf_directive_n=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_directive_n" >&5 -printf "%s\n" "$gl_cv_func_snprintf_directive_n" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_directive_n" >&5 +printf '%s\n' "$gl_cv_func_snprintf_directive_n" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether snprintf respects a size of 1" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether snprintf respects a size of 1" >&5 printf %s "checking whether snprintf respects a size of 1... " >&6; } if test ${gl_cv_func_snprintf_size1+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -45819,8 +46948,8 @@ then : *) gl_cv_func_snprintf_size1="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -45848,27 +46977,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_snprintf_size1=yes -else $as_nop - gl_cv_func_snprintf_size1=no +else case e in #( + e) gl_cv_func_snprintf_size1=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_size1" >&5 -printf "%s\n" "$gl_cv_func_snprintf_size1" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_size1" >&5 +printf '%s\n' "$gl_cv_func_snprintf_size1" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether vsnprintf respects a zero size as in C99" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether vsnprintf respects a zero size as in C99" >&5 printf %s "checking whether vsnprintf respects a zero size as in C99... " >&6; } if test ${gl_cv_func_vsnprintf_zerosize_c99+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -45909,8 +47041,8 @@ then : *) gl_cv_func_vsnprintf_zerosize_c99="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -45934,17 +47066,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_vsnprintf_zerosize_c99=yes -else $as_nop - gl_cv_func_vsnprintf_zerosize_c99=no +else case e in #( + e) gl_cv_func_vsnprintf_zerosize_c99=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_vsnprintf_zerosize_c99" >&5 -printf "%s\n" "$gl_cv_func_vsnprintf_zerosize_c99" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_vsnprintf_zerosize_c99" >&5 +printf '%s\n' "$gl_cv_func_vsnprintf_zerosize_c99" >&6; } case "$gl_cv_func_printf_sizes_c99" in *yes) @@ -46035,7 +47170,7 @@ printf "%s\n" "$gl_cv_func_vsnprintf_zerosize_c99" >&6; } ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; esac @@ -46050,7 +47185,7 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -46064,12 +47199,12 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : - printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h + printf '%s\n' "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi @@ -46083,7 +47218,7 @@ fi ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; esac @@ -46095,7 +47230,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; esac @@ -46107,7 +47242,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; esac @@ -46119,7 +47254,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; esac @@ -46131,7 +47266,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; esac @@ -46143,13 +47278,13 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -46161,13 +47296,13 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -46216,7 +47351,7 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h if test $ac_cv_func_vasnprintf = yes; then -printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h +printf '%s\n' "#define REPLACE_VASNPRINTF 1" >>confdefs.h fi @@ -46232,11 +47367,12 @@ printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h if test "x$ac_cv_type_ptrdiff_t" = xyes then : -else $as_nop - -printf "%s\n" "#define ptrdiff_t long" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define ptrdiff_t long" >>confdefs.h + ;; +esac fi @@ -46377,7 +47513,7 @@ fi ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; esac @@ -46392,7 +47528,7 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -46406,12 +47542,12 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : - printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h + printf '%s\n' "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi @@ -46425,7 +47561,7 @@ fi ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; esac @@ -46437,7 +47573,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; esac @@ -46449,7 +47585,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; esac @@ -46461,7 +47597,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; esac @@ -46473,7 +47609,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; esac @@ -46485,13 +47621,13 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -46503,13 +47639,13 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -46558,7 +47694,7 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h if test $ac_cv_func_vasnprintf = yes; then -printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h +printf '%s\n' "#define REPLACE_VASNPRINTF 1" >>confdefs.h fi @@ -46574,11 +47710,12 @@ printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h if test "x$ac_cv_type_ptrdiff_t" = xyes then : -else $as_nop - -printf "%s\n" "#define ptrdiff_t long" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define ptrdiff_t long" >>confdefs.h + ;; +esac fi @@ -46619,18 +47756,18 @@ fi -printf "%s\n" "#define GNULIB_TEST_SPRINTF_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_SPRINTF_POSIX 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ssize_t" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ssize_t" >&5 printf %s "checking for ssize_t... " >&6; } if test ${gt_cv_ssize_t+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int @@ -46645,16 +47782,18 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gt_cv_ssize_t=yes -else $as_nop - gt_cv_ssize_t=no +else case e in #( + e) gt_cv_ssize_t=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_ssize_t" >&5 -printf "%s\n" "$gt_cv_ssize_t" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_ssize_t" >&5 +printf '%s\n' "$gt_cv_ssize_t" >&6; } if test $gt_cv_ssize_t = no; then -printf "%s\n" "#define ssize_t int" >>confdefs.h +printf '%s\n' "#define ssize_t int" >>confdefs.h fi @@ -46667,13 +47806,13 @@ printf "%s\n" "#define ssize_t int" >>confdefs.h REPLACE_STAT=1 ;; *) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether stat handles trailing slashes on files" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether stat handles trailing slashes on files" >&5 printf %s "checking whether stat handles trailing slashes on files... " >&6; } if test ${gl_cv_func_stat_file_slash+y} then : printf %s "(cached) " >&6 -else $as_nop - touch conftest.tmp +else case e in #( + e) touch conftest.tmp # Assume that if we have lstat, we can also check symlinks. if test $ac_cv_func_lstat = yes; then ln -s conftest.tmp conftest.lnk @@ -46689,8 +47828,8 @@ then : *) gl_cv_func_stat_file_slash="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -46714,22 +47853,25 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_stat_file_slash=yes -else $as_nop - gl_cv_func_stat_file_slash=no +else case e in #( + e) gl_cv_func_stat_file_slash=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - rm -f conftest.tmp conftest.lnk + rm -f conftest.tmp conftest.lnk ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_stat_file_slash" >&5 -printf "%s\n" "$gl_cv_func_stat_file_slash" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_stat_file_slash" >&5 +printf '%s\n' "$gl_cv_func_stat_file_slash" >&6; } case $gl_cv_func_stat_file_slash in *no) REPLACE_STAT=1 -printf "%s\n" "#define REPLACE_FUNC_STAT_FILE 1" >>confdefs.h +printf '%s\n' "#define REPLACE_FUNC_STAT_FILE 1" >>confdefs.h ;; esac case $host_os in @@ -46785,18 +47927,18 @@ printf "%s\n" "#define REPLACE_FUNC_STAT_FILE 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_STAT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_STAT 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working stdalign.h" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working stdalign.h" >&5 printf %s "checking for working stdalign.h... " >&6; } if test ${gl_cv_header_working_stdalign_h+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -46841,13 +47983,15 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_header_working_stdalign_h=yes -else $as_nop - gl_cv_header_working_stdalign_h=no +else case e in #( + e) gl_cv_header_working_stdalign_h=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_working_stdalign_h" >&5 -printf "%s\n" "$gl_cv_header_working_stdalign_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_header_working_stdalign_h" >&5 +printf '%s\n' "$gl_cv_header_working_stdalign_h" >&6; } if test $gl_cv_header_working_stdalign_h = yes; then STDALIGN_H='' @@ -46930,13 +48074,13 @@ fi -printf "%s\n" "#define GNULIB_TEST_FSCANF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FSCANF 1" >>confdefs.h -printf "%s\n" "#define GNULIB_FSCANF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_FSCANF 1" >>confdefs.h @@ -46954,13 +48098,13 @@ printf "%s\n" "#define GNULIB_FSCANF 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_SCANF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_SCANF 1" >>confdefs.h -printf "%s\n" "#define GNULIB_SCANF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_SCANF 1" >>confdefs.h @@ -46978,7 +48122,7 @@ printf "%s\n" "#define GNULIB_SCANF 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FGETC 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FGETC 1" >>confdefs.h @@ -46997,7 +48141,7 @@ printf "%s\n" "#define GNULIB_TEST_FGETC 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_GETC 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_GETC 1" >>confdefs.h @@ -47016,7 +48160,7 @@ printf "%s\n" "#define GNULIB_TEST_GETC 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_GETCHAR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_GETCHAR 1" >>confdefs.h @@ -47035,7 +48179,7 @@ printf "%s\n" "#define GNULIB_TEST_GETCHAR 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FGETS 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FGETS 1" >>confdefs.h @@ -47054,7 +48198,7 @@ printf "%s\n" "#define GNULIB_TEST_FGETS 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FREAD 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FREAD 1" >>confdefs.h @@ -47073,7 +48217,7 @@ printf "%s\n" "#define GNULIB_TEST_FREAD 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FPRINTF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FPRINTF 1" >>confdefs.h @@ -47092,7 +48236,7 @@ printf "%s\n" "#define GNULIB_TEST_FPRINTF 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_PRINTF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_PRINTF 1" >>confdefs.h @@ -47111,7 +48255,7 @@ printf "%s\n" "#define GNULIB_TEST_PRINTF 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_VFPRINTF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_VFPRINTF 1" >>confdefs.h @@ -47130,7 +48274,7 @@ printf "%s\n" "#define GNULIB_TEST_VFPRINTF 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_VPRINTF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_VPRINTF 1" >>confdefs.h @@ -47149,7 +48293,7 @@ printf "%s\n" "#define GNULIB_TEST_VPRINTF 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FPUTC 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FPUTC 1" >>confdefs.h @@ -47168,7 +48312,7 @@ printf "%s\n" "#define GNULIB_TEST_FPUTC 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_PUTC 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_PUTC 1" >>confdefs.h @@ -47187,7 +48331,7 @@ printf "%s\n" "#define GNULIB_TEST_PUTC 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_PUTCHAR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_PUTCHAR 1" >>confdefs.h @@ -47206,7 +48350,7 @@ printf "%s\n" "#define GNULIB_TEST_PUTCHAR 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FPUTS 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FPUTS 1" >>confdefs.h @@ -47225,7 +48369,7 @@ printf "%s\n" "#define GNULIB_TEST_FPUTS 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_PUTS 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_PUTS 1" >>confdefs.h @@ -47244,7 +48388,7 @@ printf "%s\n" "#define GNULIB_TEST_PUTS 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FWRITE 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FWRITE 1" >>confdefs.h @@ -47263,7 +48407,7 @@ printf "%s\n" "#define GNULIB_TEST_FWRITE 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "stpcpy" "ac_cv_func_stpcpy" if test "x$ac_cv_func_stpcpy" = xyes then : - printf "%s\n" "#define HAVE_STPCPY 1" >>confdefs.h + printf '%s\n' "#define HAVE_STPCPY 1" >>confdefs.h fi @@ -47301,7 +48445,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_STPCPY 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_STPCPY 1" >>confdefs.h @@ -47317,13 +48461,13 @@ printf "%s\n" "#define GNULIB_TEST_STPCPY 1" >>confdefs.h if test $ac_cv_func_stpncpy = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working stpncpy" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working stpncpy" >&5 printf %s "checking for working stpncpy... " >&6; } if test ${gl_cv_func_stpncpy+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -47336,21 +48480,22 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Thanks for using GNU" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Thanks for using GNU" >/dev/null 2>&1 then : gl_cv_func_stpncpy="guessing yes" -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in *-musl*) gl_cv_func_stpncpy="guessing yes" ;; *) gl_cv_func_stpncpy="$gl_cross_guess_normal" ;; esac - + ;; +esac fi rm -rf conftest* -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -47393,21 +48538,24 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_stpncpy=yes -else $as_nop - gl_cv_func_stpncpy=no +else case e in #( + e) gl_cv_func_stpncpy=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_stpncpy" >&5 -printf "%s\n" "$gl_cv_func_stpncpy" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_stpncpy" >&5 +printf '%s\n' "$gl_cv_func_stpncpy" >&6; } case "$gl_cv_func_stpncpy" in *yes) -printf "%s\n" "#define HAVE_STPNCPY 1" >>confdefs.h +printf '%s\n' "#define HAVE_STPNCPY 1" >>confdefs.h ;; *) @@ -47448,7 +48596,7 @@ printf "%s\n" "#define HAVE_STPNCPY 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_STPNCPY 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_STPNCPY 1" >>confdefs.h @@ -47491,7 +48639,7 @@ printf "%s\n" "#define GNULIB_TEST_STPNCPY 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_STRDUP 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_STRDUP 1" >>confdefs.h @@ -47503,13 +48651,13 @@ printf "%s\n" "#define GNULIB_TEST_STRDUP 1" >>confdefs.h if test "$ERRNO_H:$REPLACE_STRERROR_0" = :0; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working strerror function" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working strerror function" >&5 printf %s "checking for working strerror function... " >&6; } if test ${gl_cv_func_working_strerror+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on glibc systems. @@ -47520,8 +48668,8 @@ then : *) gl_cv_func_working_strerror="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -47536,17 +48684,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_working_strerror=yes -else $as_nop - gl_cv_func_working_strerror=no +else case e in #( + e) gl_cv_func_working_strerror=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_working_strerror" >&5 -printf "%s\n" "$gl_cv_func_working_strerror" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_working_strerror" >&5 +printf '%s\n' "$gl_cv_func_working_strerror" >&6; } case "$gl_cv_func_working_strerror" in *yes) ;; *) @@ -47576,7 +48727,7 @@ printf "%s\n" "$gl_cv_func_working_strerror" >&6; } fi -printf "%s\n" "#define GNULIB_STRERROR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_STRERROR 1" >>confdefs.h @@ -47594,7 +48745,7 @@ printf "%s\n" "#define GNULIB_STRERROR 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_STRERROR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_STRERROR 1" >>confdefs.h @@ -47617,13 +48768,13 @@ printf "%s\n" "#define GNULIB_TEST_STRERROR 1" >>confdefs.h if test $ac_cv_func_strndup = yes; then HAVE_STRNDUP=1 # AIX 4.3.3, AIX 5.1 have a function that fails to add the terminating '\0'. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working strndup" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working strndup" >&5 printf %s "checking for working strndup... " >&6; } if test ${gl_cv_func_strndup_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case $host_os in @@ -47631,8 +48782,8 @@ then : *) gl_cv_func_strndup_works="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -47663,16 +48814,19 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_strndup_works=yes -else $as_nop - gl_cv_func_strndup_works=no +else case e in #( + e) gl_cv_func_strndup_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strndup_works" >&5 -printf "%s\n" "$gl_cv_func_strndup_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strndup_works" >&5 +printf '%s\n' "$gl_cv_func_strndup_works" >&6; } case $gl_cv_func_strndup_works in *no) REPLACE_STRNDUP=1 ;; esac @@ -47707,7 +48861,7 @@ printf "%s\n" "$gl_cv_func_strndup_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_STRNDUP 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_STRNDUP 1" >>confdefs.h @@ -47715,13 +48869,13 @@ printf "%s\n" "#define GNULIB_TEST_STRNDUP 1" >>confdefs.h if test $HAVE_STRTOD = 1; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strtod obeys C99" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether strtod obeys C99" >&5 printf %s "checking whether strtod obeys C99... " >&6; } if test ${gl_cv_func_strtod_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -47736,24 +48890,25 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Lucky user" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Lucky user" >/dev/null 2>&1 then : gl_cv_func_strtod_works="guessing yes" -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in # Guess yes on musl systems. *-musl*) gl_cv_func_strtod_works="guessing yes" ;; # Guess yes on native Windows. mingw*) gl_cv_func_strtod_works="guessing yes" ;; *) gl_cv_func_strtod_works="$gl_cross_guess_normal" ;; esac - + ;; +esac fi rm -rf conftest* -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -47844,17 +48999,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_strtod_works=yes -else $as_nop - gl_cv_func_strtod_works=no +else case e in #( + e) gl_cv_func_strtod_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strtod_works" >&5 -printf "%s\n" "$gl_cv_func_strtod_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strtod_works" >&5 +printf '%s\n' "$gl_cv_func_strtod_works" >&6; } case "$gl_cv_func_strtod_works" in *yes) ;; *) @@ -47878,13 +49036,13 @@ printf "%s\n" "$gl_cv_func_strtod_works" >&6; } if test $gl_cv_func_ldexp_no_libm = yes; then -printf "%s\n" "#define HAVE_LDEXP_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_LDEXP_IN_LIBC 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : - printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h + printf '%s\n' "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi @@ -47905,7 +49063,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_STRTOD 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_STRTOD 1" >>confdefs.h @@ -47916,7 +49074,7 @@ printf "%s\n" "#define GNULIB_TEST_STRTOD 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "strverscmp" "ac_cv_func_strverscmp" if test "x$ac_cv_func_strverscmp" = xyes then : - printf "%s\n" "#define HAVE_STRVERSCMP 1" >>confdefs.h + printf '%s\n' "#define HAVE_STRVERSCMP 1" >>confdefs.h fi @@ -47954,7 +49112,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_STRVERSCMP 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_STRVERSCMP 1" >>confdefs.h @@ -48016,7 +49174,7 @@ printf "%s\n" "#define GNULIB_TEST_STRVERSCMP 1" >>confdefs.h ac_fn_c_check_header_compile "$LINENO" "sys/single_threaded.h" "ac_cv_header_sys_single_threaded_h" "$ac_includes_default" if test "x$ac_cv_header_sys_single_threaded_h" = xyes then : - printf "%s\n" "#define HAVE_SYS_SINGLE_THREADED_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_SYS_SINGLE_THREADED_H 1" >>confdefs.h fi @@ -48072,7 +49230,7 @@ fi -printf "%s\n" "#define GNULIB_UNISTR_U8_MBTOUCR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_UNISTR_U8_MBTOUCR 1" >>confdefs.h @@ -48106,7 +49264,7 @@ fi -printf "%s\n" "#define GNULIB_UNISTR_U8_UCTOMB 1" >>confdefs.h +printf '%s\n' "#define GNULIB_UNISTR_U8_UCTOMB 1" >>confdefs.h @@ -48227,13 +49385,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether unlink honors trailing slashes" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether unlink honors trailing slashes" >&5 printf %s "checking whether unlink honors trailing slashes... " >&6; } if test ${gl_cv_func_unlink_honors_slashes+y} then : printf %s "(cached) " >&6 -else $as_nop - touch conftest.file +else case e in #( + e) touch conftest.file # Assume that if we have lstat, we can also check symlinks. if test $ac_cv_func_lstat = yes; then ln -s conftest.file conftest.lnk @@ -48251,8 +49409,8 @@ then : *) gl_cv_func_unlink_honors_slashes="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if HAVE_UNISTD_H # include @@ -48287,30 +49445,33 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_unlink_honors_slashes=yes -else $as_nop - gl_cv_func_unlink_honors_slashes=no +else case e in #( + e) gl_cv_func_unlink_honors_slashes=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - rm -f conftest.file conftest.lnk + rm -f conftest.file conftest.lnk ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_unlink_honors_slashes" >&5 -printf "%s\n" "$gl_cv_func_unlink_honors_slashes" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_unlink_honors_slashes" >&5 +printf '%s\n' "$gl_cv_func_unlink_honors_slashes" >&6; } case "$gl_cv_func_unlink_honors_slashes" in *no) REPLACE_UNLINK=1 ;; esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether unlink of a parent directory fails as it should" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether unlink of a parent directory fails as it should" >&5 printf %s "checking whether unlink of a parent directory fails as it should... " >&6; } if test ${gl_cv_func_unlink_parent_fails+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in darwin*) if { # Use the mktemp program if available. If not available, hide the error @@ -48335,8 +49496,8 @@ then : # If we don't know, obey --enable-cross-guesses. gl_cv_func_unlink_parent_fails="$gl_cross_guess_normal" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -48364,11 +49525,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_unlink_parent_fails=yes -else $as_nop - gl_cv_func_unlink_parent_fails=no +else case e in #( + e) gl_cv_func_unlink_parent_fails=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi unset GL_SUBDIR_FOR_UNLINK @@ -48381,15 +49544,16 @@ fi gl_cv_func_unlink_parent_fails="guessing yes" ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_unlink_parent_fails" >&5 -printf "%s\n" "$gl_cv_func_unlink_parent_fails" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_unlink_parent_fails" >&5 +printf '%s\n' "$gl_cv_func_unlink_parent_fails" >&6; } case "$gl_cv_func_unlink_parent_fails" in *no) REPLACE_UNLINK=1 -printf "%s\n" "#define UNLINK_PARENT_BUG 1" >>confdefs.h +printf '%s\n' "#define UNLINK_PARENT_BUG 1" >>confdefs.h ;; esac @@ -48421,15 +49585,15 @@ printf "%s\n" "#define UNLINK_PARENT_BUG 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_UNLINK 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_UNLINK 1" >>confdefs.h -printf "%s\n" "#define GNULIB_STDIO_SINGLE_THREAD 1" >>confdefs.h +printf '%s\n' "#define GNULIB_STDIO_SINGLE_THREAD 1" >>confdefs.h -printf "%s\n" "#define USE_UNLOCKED_IO GNULIB_STDIO_SINGLE_THREAD" >>confdefs.h +printf '%s\n' "#define USE_UNLOCKED_IO GNULIB_STDIO_SINGLE_THREAD" >>confdefs.h @@ -48457,7 +49621,7 @@ printf "%s\n" "#define USE_UNLOCKED_IO GNULIB_STDIO_SINGLE_THREAD" >>confdefs.h ac_fn_c_check_func "$LINENO" "unsetenv" "ac_cv_func_unsetenv" if test "x$ac_cv_func_unsetenv" = xyes then : - printf "%s\n" "#define HAVE_UNSETENV 1" >>confdefs.h + printf '%s\n' "#define HAVE_UNSETENV 1" >>confdefs.h fi @@ -48465,13 +49629,13 @@ fi HAVE_UNSETENV=0 else HAVE_UNSETENV=1 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for unsetenv() return type" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for unsetenv() return type" >&5 printf %s "checking for unsetenv() return type... " >&6; } if test ${gt_cv_func_unsetenv_ret+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #undef _BSD @@ -48494,27 +49658,29 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gt_cv_func_unsetenv_ret='int' -else $as_nop - gt_cv_func_unsetenv_ret='void' +else case e in #( + e) gt_cv_func_unsetenv_ret='void' ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_unsetenv_ret" >&5 -printf "%s\n" "$gt_cv_func_unsetenv_ret" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_unsetenv_ret" >&5 +printf '%s\n' "$gt_cv_func_unsetenv_ret" >&6; } if test $gt_cv_func_unsetenv_ret = 'void'; then -printf "%s\n" "#define VOID_UNSETENV 1" >>confdefs.h +printf '%s\n' "#define VOID_UNSETENV 1" >>confdefs.h REPLACE_UNSETENV=1 fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether unsetenv obeys POSIX" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether unsetenv obeys POSIX" >&5 printf %s "checking whether unsetenv obeys POSIX... " >&6; } if test ${gl_cv_func_unsetenv_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on glibc systems. @@ -48523,8 +49689,8 @@ then : *) gl_cv_func_unsetenv_works="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -48561,17 +49727,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_unsetenv_works=yes -else $as_nop - gl_cv_func_unsetenv_works=no +else case e in #( + e) gl_cv_func_unsetenv_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_unsetenv_works" >&5 -printf "%s\n" "$gl_cv_func_unsetenv_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_unsetenv_works" >&5 +printf '%s\n' "$gl_cv_func_unsetenv_works" >&6; } case "$gl_cv_func_unsetenv_works" in *yes) ;; *) @@ -48611,7 +49780,7 @@ printf "%s\n" "$gl_cv_func_unsetenv_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_UNSETENV 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_UNSETENV 1" >>confdefs.h @@ -48663,7 +49832,7 @@ printf "%s\n" "#define GNULIB_TEST_UNSETENV 1" >>confdefs.h if test $ac_cv_func_vasnprintf = yes; then -printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h +printf '%s\n' "#define REPLACE_VASNPRINTF 1" >>confdefs.h fi @@ -48679,11 +49848,12 @@ printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h if test "x$ac_cv_type_ptrdiff_t" = xyes then : -else $as_nop - -printf "%s\n" "#define ptrdiff_t long" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define ptrdiff_t long" >>confdefs.h + ;; +esac fi @@ -48698,7 +49868,7 @@ fi ac_fn_c_check_func "$LINENO" "vasprintf" "ac_cv_func_vasprintf" if test "x$ac_cv_func_vasprintf" = xyes then : - printf "%s\n" "#define HAVE_VASPRINTF 1" >>confdefs.h + printf '%s\n' "#define HAVE_VASPRINTF 1" >>confdefs.h fi @@ -48755,7 +49925,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_VASPRINTF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_VASPRINTF 1" >>confdefs.h @@ -48786,7 +49956,7 @@ printf "%s\n" "#define GNULIB_TEST_VASPRINTF 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "vasprintf" "ac_cv_func_vasprintf" if test "x$ac_cv_func_vasprintf" = xyes then : - printf "%s\n" "#define HAVE_VASPRINTF 1" >>confdefs.h + printf '%s\n' "#define HAVE_VASPRINTF 1" >>confdefs.h fi @@ -48860,7 +50030,7 @@ fi ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; esac @@ -48875,7 +50045,7 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -48889,12 +50059,12 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : - printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h + printf '%s\n' "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi @@ -48908,7 +50078,7 @@ fi ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; esac @@ -48920,7 +50090,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; esac @@ -48932,7 +50102,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; esac @@ -48944,7 +50114,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; esac @@ -48956,7 +50126,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; esac @@ -48968,13 +50138,13 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -48986,13 +50156,13 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -49041,7 +50211,7 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h if test $ac_cv_func_vasnprintf = yes; then -printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h +printf '%s\n' "#define REPLACE_VASNPRINTF 1" >>confdefs.h fi @@ -49057,11 +50227,12 @@ printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h if test "x$ac_cv_type_ptrdiff_t" = xyes then : -else $as_nop - -printf "%s\n" "#define ptrdiff_t long" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define ptrdiff_t long" >>confdefs.h + ;; +esac fi @@ -49113,7 +50284,7 @@ fi ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf" if test "x$ac_cv_func_vsnprintf" = xyes then : - printf "%s\n" "#define HAVE_VSNPRINTF 1" >>confdefs.h + printf '%s\n' "#define HAVE_VSNPRINTF 1" >>confdefs.h fi @@ -49121,13 +50292,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether snprintf respects a size of 1" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether snprintf respects a size of 1" >&5 printf %s "checking whether snprintf respects a size of 1... " >&6; } if test ${gl_cv_func_snprintf_size1+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -49138,8 +50309,8 @@ then : *) gl_cv_func_snprintf_size1="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -49167,17 +50338,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_snprintf_size1=yes -else $as_nop - gl_cv_func_snprintf_size1=no +else case e in #( + e) gl_cv_func_snprintf_size1=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_size1" >&5 -printf "%s\n" "$gl_cv_func_snprintf_size1" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_size1" >&5 +printf '%s\n' "$gl_cv_func_snprintf_size1" >&6; } case "$gl_cv_func_snprintf_size1" in *yes) @@ -49186,13 +50360,13 @@ printf "%s\n" "$gl_cv_func_snprintf_size1" >&6; } *yes) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether printf supports POSIX/XSI format strings with positions" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether printf supports POSIX/XSI format strings with positions" >&5 printf %s "checking whether printf supports POSIX/XSI format strings with positions... " >&6; } if test ${gl_cv_func_printf_positions+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -49207,8 +50381,8 @@ then : *) gl_cv_func_printf_positions="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -49226,17 +50400,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_printf_positions=yes -else $as_nop - gl_cv_func_printf_positions=no +else case e in #( + e) gl_cv_func_printf_positions=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_positions" >&5 -printf "%s\n" "$gl_cv_func_printf_positions" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_printf_positions" >&5 +printf '%s\n' "$gl_cv_func_printf_positions" >&6; } case "$gl_cv_func_printf_positions" in *yes) @@ -49292,7 +50469,7 @@ printf "%s\n" "$gl_cv_func_printf_positions" >&6; } -printf "%s\n" "#define GNULIB_TEST_VSNPRINTF 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_VSNPRINTF 1" >>confdefs.h @@ -49315,7 +50492,7 @@ printf "%s\n" "#define GNULIB_TEST_VSNPRINTF 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "vsnprintf" "ac_cv_func_vsnprintf" if test "x$ac_cv_func_vsnprintf" = xyes then : - printf "%s\n" "#define HAVE_VSNPRINTF 1" >>confdefs.h + printf '%s\n' "#define HAVE_VSNPRINTF 1" >>confdefs.h fi @@ -49325,13 +50502,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether snprintf fully supports the 'n' directive" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether snprintf fully supports the 'n' directive" >&5 printf %s "checking whether snprintf fully supports the 'n' directive... " >&6; } if test ${gl_cv_func_snprintf_directive_n+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -49347,8 +50524,9 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_func_snprintf_directive_n="guessing yes" -else $as_nop - gl_cv_func_snprintf_directive_n="guessing no" +else case e in #( + e) gl_cv_func_snprintf_directive_n="guessing no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; @@ -49387,8 +50565,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext *) gl_cv_func_snprintf_directive_n="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -49425,28 +50603,31 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_snprintf_directive_n=yes -else $as_nop - gl_cv_func_snprintf_directive_n=no +else case e in #( + e) gl_cv_func_snprintf_directive_n=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_directive_n" >&5 -printf "%s\n" "$gl_cv_func_snprintf_directive_n" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_directive_n" >&5 +printf '%s\n' "$gl_cv_func_snprintf_directive_n" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether snprintf respects a size of 1" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether snprintf respects a size of 1" >&5 printf %s "checking whether snprintf respects a size of 1... " >&6; } if test ${gl_cv_func_snprintf_size1+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -49457,8 +50638,8 @@ then : *) gl_cv_func_snprintf_size1="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -49486,27 +50667,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_snprintf_size1=yes -else $as_nop - gl_cv_func_snprintf_size1=no +else case e in #( + e) gl_cv_func_snprintf_size1=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_size1" >&5 -printf "%s\n" "$gl_cv_func_snprintf_size1" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_snprintf_size1" >&5 +printf '%s\n' "$gl_cv_func_snprintf_size1" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether vsnprintf respects a zero size as in C99" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether vsnprintf respects a zero size as in C99" >&5 printf %s "checking whether vsnprintf respects a zero size as in C99... " >&6; } if test ${gl_cv_func_vsnprintf_zerosize_c99+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -49547,8 +50731,8 @@ then : *) gl_cv_func_vsnprintf_zerosize_c99="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -49572,17 +50756,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_vsnprintf_zerosize_c99=yes -else $as_nop - gl_cv_func_vsnprintf_zerosize_c99=no +else case e in #( + e) gl_cv_func_vsnprintf_zerosize_c99=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_vsnprintf_zerosize_c99" >&5 -printf "%s\n" "$gl_cv_func_vsnprintf_zerosize_c99" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_vsnprintf_zerosize_c99" >&5 +printf '%s\n' "$gl_cv_func_vsnprintf_zerosize_c99" >&6; } case "$gl_cv_func_printf_sizes_c99" in *yes) @@ -49673,7 +50860,7 @@ printf "%s\n" "$gl_cv_func_vsnprintf_zerosize_c99" >&6; } ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; esac @@ -49688,7 +50875,7 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -49702,12 +50889,12 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : - printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h + printf '%s\n' "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi @@ -49721,7 +50908,7 @@ fi ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; esac @@ -49733,7 +50920,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; esac @@ -49745,7 +50932,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; esac @@ -49757,7 +50944,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; esac @@ -49769,7 +50956,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; esac @@ -49781,13 +50968,13 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -49799,13 +50986,13 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -49854,7 +51041,7 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h if test $ac_cv_func_vasnprintf = yes; then -printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h +printf '%s\n' "#define REPLACE_VASNPRINTF 1" >>confdefs.h fi @@ -49870,11 +51057,12 @@ printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h if test "x$ac_cv_type_ptrdiff_t" = xyes then : -else $as_nop - -printf "%s\n" "#define ptrdiff_t long" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define ptrdiff_t long" >>confdefs.h + ;; +esac fi @@ -49991,7 +51179,7 @@ fi ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; esac @@ -50006,7 +51194,7 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -50020,12 +51208,12 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : - printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h + printf '%s\n' "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi @@ -50039,7 +51227,7 @@ fi ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; esac @@ -50051,7 +51239,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; esac @@ -50063,7 +51251,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; esac @@ -50075,7 +51263,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; esac @@ -50087,7 +51275,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; esac @@ -50099,13 +51287,13 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -50117,13 +51305,13 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -50172,7 +51360,7 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h if test $ac_cv_func_vasnprintf = yes; then -printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h +printf '%s\n' "#define REPLACE_VASNPRINTF 1" >>confdefs.h fi @@ -50188,11 +51376,12 @@ printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h if test "x$ac_cv_type_ptrdiff_t" = xyes then : -else $as_nop - -printf "%s\n" "#define ptrdiff_t long" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define ptrdiff_t long" >>confdefs.h + ;; +esac fi @@ -50233,7 +51422,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_VSPRINTF_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_VSPRINTF_POSIX 1" >>confdefs.h @@ -50242,7 +51431,7 @@ printf "%s\n" "#define GNULIB_TEST_VSPRINTF_POSIX 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "waitid" "ac_cv_func_waitid" if test "x$ac_cv_func_waitid" = xyes then : - printf "%s\n" "#define HAVE_WAITID 1" >>confdefs.h + printf '%s\n' "#define HAVE_WAITID 1" >>confdefs.h fi @@ -50281,7 +51470,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_WAITPID 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_WAITPID 1" >>confdefs.h @@ -50311,27 +51500,28 @@ printf "%s\n" "#define GNULIB_TEST_WAITPID 1" >>confdefs.h ac_fn_check_decl "$LINENO" "wcwidth" "ac_cv_have_decl_wcwidth" " #include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_wcwidth" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_WCWIDTH $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_WCWIDTH $ac_have_decl" >>confdefs.h if test $ac_cv_have_decl_wcwidth != yes; then HAVE_DECL_WCWIDTH=0 fi if test $ac_cv_func_wcwidth != yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether wcwidth is a macro" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether wcwidth is a macro" >&5 printf %s "checking whether wcwidth is a macro... " >&6; } if test ${gl_cv_func_wcwidth_macro+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -50340,29 +51530,31 @@ else $as_nop #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "wchar_header_defines_wcwidth" >/dev/null 2>&1 + $EGREP_TRADITIONAL "wchar_header_defines_wcwidth" >/dev/null 2>&1 then : gl_cv_func_wcwidth_macro=yes -else $as_nop - gl_cv_func_wcwidth_macro=no +else case e in #( + e) gl_cv_func_wcwidth_macro=no ;; +esac fi rm -rf conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_wcwidth_macro" >&5 -printf "%s\n" "$gl_cv_func_wcwidth_macro" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_wcwidth_macro" >&5 +printf '%s\n' "$gl_cv_func_wcwidth_macro" >&6; } fi if test $ac_cv_func_wcwidth = yes || test $gl_cv_func_wcwidth_macro = yes; then HAVE_WCWIDTH=1 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether wcwidth works reasonably in UTF-8 locales" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether wcwidth works reasonably in UTF-8 locales" >&5 printf %s "checking whether wcwidth works reasonably in UTF-8 locales... " >&6; } if test ${gl_cv_func_wcwidth_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : @@ -50376,8 +51568,8 @@ then : *) gl_cv_func_wcwidth_works="$gl_cross_guess_normal";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -50411,17 +51603,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_wcwidth_works=yes -else $as_nop - gl_cv_func_wcwidth_works=no +else case e in #( + e) gl_cv_func_wcwidth_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_wcwidth_works" >&5 -printf "%s\n" "$gl_cv_func_wcwidth_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_wcwidth_works" >&5 +printf '%s\n' "$gl_cv_func_wcwidth_works" >&6; } case "$gl_cv_func_wcwidth_works" in *yes) ;; *no) REPLACE_WCWIDTH=1 ;; @@ -50461,7 +51656,7 @@ printf "%s\n" "$gl_cv_func_wcwidth_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_WCWIDTH 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_WCWIDTH 1" >>confdefs.h @@ -50481,13 +51676,13 @@ printf "%s\n" "#define GNULIB_TEST_WCWIDTH 1" >>confdefs.h ;; esac - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether use of TIOCGWINSZ requires sys/ioctl.h" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether use of TIOCGWINSZ requires sys/ioctl.h" >&5 printf %s "checking whether use of TIOCGWINSZ requires sys/ioctl.h... " >&6; } if test ${gl_cv_sys_tiocgwinsz_needs_sys_ioctl_h+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_cv_sys_tiocgwinsz_needs_sys_ioctl_h=no +else case e in #( + e) gl_cv_sys_tiocgwinsz_needs_sys_ioctl_h=no if test $gl_cv_sys_tiocgwinsz_needs_termios_h = no; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -50500,31 +51695,32 @@ else $as_nop _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : gl_cv_sys_tiocgwinsz_needs_sys_ioctl_h=yes fi rm -rf conftest* fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_tiocgwinsz_needs_sys_ioctl_h" >&5 -printf "%s\n" "$gl_cv_sys_tiocgwinsz_needs_sys_ioctl_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_tiocgwinsz_needs_sys_ioctl_h" >&5 +printf '%s\n' "$gl_cv_sys_tiocgwinsz_needs_sys_ioctl_h" >&6; } if test $gl_cv_sys_tiocgwinsz_needs_sys_ioctl_h = yes; then -printf "%s\n" "#define GWINSZ_IN_SYS_IOCTL 1" >>confdefs.h +printf '%s\n' "#define GWINSZ_IN_SYS_IOCTL 1" >>confdefs.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether use of TIOCGWINSZ requires termios.h" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether use of TIOCGWINSZ requires termios.h" >&5 printf %s "checking whether use of TIOCGWINSZ requires termios.h... " >&6; } if test ${gl_cv_sys_tiocgwinsz_needs_termios_h+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_cv_sys_tiocgwinsz_needs_termios_h=no +else case e in #( + e) gl_cv_sys_tiocgwinsz_needs_termios_h=no if test $ac_cv_sys_posix_termios = yes; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -50537,27 +51733,28 @@ else $as_nop _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "yes" >/dev/null 2>&1 + $EGREP_TRADITIONAL "yes" >/dev/null 2>&1 then : gl_cv_sys_tiocgwinsz_needs_termios_h=yes fi rm -rf conftest* fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_tiocgwinsz_needs_termios_h" >&5 -printf "%s\n" "$gl_cv_sys_tiocgwinsz_needs_termios_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_tiocgwinsz_needs_termios_h" >&5 +printf '%s\n' "$gl_cv_sys_tiocgwinsz_needs_termios_h" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether use of struct winsize requires sys/ptem.h" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether use of struct winsize requires sys/ptem.h" >&5 printf %s "checking whether use of struct winsize requires sys/ptem.h... " >&6; } if test ${gl_cv_sys_struct_winsize_needs_sys_ptem_h+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_cv_sys_struct_winsize_needs_sys_ptem_h=yes +else case e in #( + e) gl_cv_sys_struct_winsize_needs_sys_ptem_h=yes if test $ac_cv_sys_posix_termios = yes; then cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -50593,29 +51790,31 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : -else $as_nop - gl_cv_sys_struct_winsize_needs_sys_ptem_h=no +else case e in #( + e) gl_cv_sys_struct_winsize_needs_sys_ptem_h=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext - fi + fi ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_winsize_needs_sys_ptem_h" >&5 -printf "%s\n" "$gl_cv_sys_struct_winsize_needs_sys_ptem_h" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_struct_winsize_needs_sys_ptem_h" >&5 +printf '%s\n' "$gl_cv_sys_struct_winsize_needs_sys_ptem_h" >&6; } if test $gl_cv_sys_struct_winsize_needs_sys_ptem_h = yes; then -printf "%s\n" "#define WINSIZE_IN_PTEM 1" >>confdefs.h +printf '%s\n' "#define WINSIZE_IN_PTEM 1" >>confdefs.h fi : -printf "%s\n" "#define GNULIB_XALLOC 1" >>confdefs.h +printf '%s\n' "#define GNULIB_XALLOC 1" >>confdefs.h -printf "%s\n" "#define GNULIB_XALLOC_DIE 1" >>confdefs.h +printf '%s\n' "#define GNULIB_XALLOC_DIE 1" >>confdefs.h @@ -50623,7 +51822,7 @@ printf "%s\n" "#define GNULIB_XALLOC_DIE 1" >>confdefs.h ac_fn_c_check_header_compile "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" if test "x$ac_cv_header_stdint_h" = xyes then : - printf "%s\n" "#define HAVE_STDINT_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_STDINT_H 1" >>confdefs.h fi @@ -50708,7 +51907,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_CHDIR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_CHDIR 1" >>confdefs.h @@ -50720,13 +51919,13 @@ printf "%s\n" "#define GNULIB_TEST_CHDIR 1" >>confdefs.h if ! $gl_gnulib_enabled_8198daae261b932d64a998f8586f5005; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether this system supports file names of any length" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether this system supports file names of any length" >&5 printf %s "checking whether this system supports file names of any length... " >&6; } if test ${gl_cv_have_unlimited_file_name_length+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Arrange to define PATH_MAX, like "pathmax.h" does. */ @@ -50754,17 +51953,19 @@ have_arbitrary_file_name_length_limit #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "have_arbitrary_file_name_length_limit" >/dev/null 2>&1 + $EGREP_TRADITIONAL "have_arbitrary_file_name_length_limit" >/dev/null 2>&1 then : gl_cv_have_unlimited_file_name_length=no -else $as_nop - gl_cv_have_unlimited_file_name_length=yes +else case e in #( + e) gl_cv_have_unlimited_file_name_length=yes ;; +esac fi rm -rf conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_unlimited_file_name_length" >&5 -printf "%s\n" "$gl_cv_have_unlimited_file_name_length" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_unlimited_file_name_length" >&5 +printf '%s\n' "$gl_cv_have_unlimited_file_name_length" >&6; } if test $gl_cv_have_unlimited_file_name_length = no; then @@ -50801,7 +52002,7 @@ printf "%s\n" "$gl_cv_have_unlimited_file_name_length" >&6; } ac_fn_c_check_func "$LINENO" "closedir" "ac_cv_func_closedir" if test "x$ac_cv_func_closedir" = xyes then : - printf "%s\n" "#define HAVE_CLOSEDIR 1" >>confdefs.h + printf '%s\n' "#define HAVE_CLOSEDIR 1" >>confdefs.h fi @@ -50854,7 +52055,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_CLOSEDIR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_CLOSEDIR 1" >>confdefs.h @@ -50868,13 +52069,13 @@ printf "%s\n" "#define GNULIB_TEST_CLOSEDIR 1" >>confdefs.h func_gl_gnulib_m4code_75c65a2c014cf8235dd95289676302a4 () { if ! $gl_gnulib_enabled_75c65a2c014cf8235dd95289676302a4; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for d_ino member in directory struct" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for d_ino member in directory struct" >&5 printf %s "checking for d_ino member in directory struct... " >&6; } if test ${gl_cv_struct_dirent_d_ino+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on glibc systems with Linux kernel. @@ -50887,8 +52088,8 @@ then : *) gl_cv_struct_dirent_d_ino="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -50919,20 +52120,23 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_struct_dirent_d_ino=yes -else $as_nop - gl_cv_struct_dirent_d_ino=no +else case e in #( + e) gl_cv_struct_dirent_d_ino=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_struct_dirent_d_ino" >&5 -printf "%s\n" "$gl_cv_struct_dirent_d_ino" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_struct_dirent_d_ino" >&5 +printf '%s\n' "$gl_cv_struct_dirent_d_ino" >&6; } case "$gl_cv_struct_dirent_d_ino" in *yes) -printf "%s\n" "#define D_INO_IN_DIRENT 1" >>confdefs.h +printf '%s\n' "#define D_INO_IN_DIRENT 1" >>confdefs.h ;; esac @@ -50964,32 +52168,33 @@ printf "%s\n" "#define D_INO_IN_DIRENT 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "dirfd" "ac_cv_func_dirfd" if test "x$ac_cv_func_dirfd" = xyes then : - printf "%s\n" "#define HAVE_DIRFD 1" >>confdefs.h + printf '%s\n' "#define HAVE_DIRFD 1" >>confdefs.h fi ac_fn_check_decl "$LINENO" "dirfd" "ac_cv_have_decl_dirfd" "#include #include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_dirfd" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_DIRFD $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_DIRFD $ac_have_decl" >>confdefs.h if test $ac_cv_have_decl_dirfd = no; then HAVE_DECL_DIRFD=0 fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether dirfd is a macro" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether dirfd is a macro" >&5 printf %s "checking whether dirfd is a macro... " >&6; } if test ${gl_cv_func_dirfd_macro+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -50999,17 +52204,19 @@ else $as_nop #endif _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "dirent_header_defines_dirfd" >/dev/null 2>&1 + $EGREP_TRADITIONAL "dirent_header_defines_dirfd" >/dev/null 2>&1 then : gl_cv_func_dirfd_macro=yes -else $as_nop - gl_cv_func_dirfd_macro=no +else case e in #( + e) gl_cv_func_dirfd_macro=no ;; +esac fi rm -rf conftest* - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_dirfd_macro" >&5 -printf "%s\n" "$gl_cv_func_dirfd_macro" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_dirfd_macro" >&5 +printf '%s\n' "$gl_cv_func_dirfd_macro" >&6; } # Use the replacement if we have no function or macro with that name, # or if OS/2 kLIBC whose dirfd() does not work. @@ -51018,7 +52225,7 @@ printf "%s\n" "$gl_cv_func_dirfd_macro" >&6; } no,no,*,yes | *,*,os2*,yes) REPLACE_DIRFD=1 -printf "%s\n" "#define REPLACE_DIRFD 1" >>confdefs.h +printf '%s\n' "#define REPLACE_DIRFD 1" >>confdefs.h ;; esac @@ -51035,13 +52242,13 @@ printf "%s\n" "#define REPLACE_DIRFD 1" >>confdefs.h gl_LIBOBJS="$gl_LIBOBJS dirfd.$ac_objext" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to get the file descriptor associated with an open DIR*" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to get the file descriptor associated with an open DIR*" >&5 printf %s "checking how to get the file descriptor associated with an open DIR*... " >&6; } if test ${gl_cv_sys_dir_fd_member_name+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) dirfd_save_CFLAGS=$CFLAGS for ac_expr in d_fd dd_fd; do @@ -51072,13 +52279,14 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext gl_cv_sys_dir_fd_member_name=$ac_expr - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_dir_fd_member_name" >&5 -printf "%s\n" "$gl_cv_sys_dir_fd_member_name" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_sys_dir_fd_member_name" >&5 +printf '%s\n' "$gl_cv_sys_dir_fd_member_name" >&6; } if test $gl_cv_sys_dir_fd_member_name != no_such_member; then -printf "%s\n" "#define DIR_FD_MEMBER_NAME $gl_cv_sys_dir_fd_member_name" >>confdefs.h +printf '%s\n' "#define DIR_FD_MEMBER_NAME $gl_cv_sys_dir_fd_member_name" >>confdefs.h fi @@ -51099,7 +52307,7 @@ printf "%s\n" "#define DIR_FD_MEMBER_NAME $gl_cv_sys_dir_fd_member_name" >>confd -printf "%s\n" "#define GNULIB_TEST_DIRFD 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_DIRFD 1" >>confdefs.h @@ -51130,13 +52338,13 @@ printf "%s\n" "#define GNULIB_TEST_DIRFD 1" >>confdefs.h REPLACE_DUP=1 fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether dup works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether dup works" >&5 printf %s "checking whether dup works... " >&6; } if test ${gl_cv_func_dup_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess no on native Windows. @@ -51144,8 +52352,8 @@ then : *) gl_cv_func_dup_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -51169,17 +52377,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_dup_works=yes -else $as_nop - gl_cv_func_dup_works=no +else case e in #( + e) gl_cv_func_dup_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_dup_works" >&5 -printf "%s\n" "$gl_cv_func_dup_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_dup_works" >&5 +printf '%s\n' "$gl_cv_func_dup_works" >&6; } case "$gl_cv_func_dup_works" in *yes) ;; *) @@ -51215,7 +52426,7 @@ printf "%s\n" "$gl_cv_func_dup_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_DUP 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_DUP 1" >>confdefs.h @@ -51248,15 +52459,15 @@ printf "%s\n" "#define GNULIB_TEST_DUP 1" >>confdefs.h : -printf "%s\n" "#define REPLACE_FCHDIR 1" >>confdefs.h +printf '%s\n' "#define REPLACE_FCHDIR 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether open can visit directories" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether open can visit directories" >&5 printf %s "checking whether open can visit directories... " >&6; } if test ${gl_cv_func_open_directory_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on Linux systems. @@ -51269,8 +52480,8 @@ then : *) gl_cv_func_open_directory_works="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -51288,21 +52499,24 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_open_directory_works=yes -else $as_nop - gl_cv_func_open_directory_works=no +else case e in #( + e) gl_cv_func_open_directory_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_open_directory_works" >&5 -printf "%s\n" "$gl_cv_func_open_directory_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_open_directory_works" >&5 +printf '%s\n' "$gl_cv_func_open_directory_works" >&6; } case "$gl_cv_func_open_directory_works" in *yes) ;; *) -printf "%s\n" "#define REPLACE_OPEN_DIRECTORY 1" >>confdefs.h +printf '%s\n' "#define REPLACE_OPEN_DIRECTORY 1" >>confdefs.h ;; esac @@ -51323,7 +52537,7 @@ printf "%s\n" "#define REPLACE_OPEN_DIRECTORY 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FCHDIR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FCHDIR 1" >>confdefs.h @@ -51365,32 +52579,34 @@ printf "%s\n" "#define GNULIB_TEST_FCHDIR 1" >>confdefs.h ac_fn_check_decl "$LINENO" "fdopendir" "ac_cv_have_decl_fdopendir" " #include -" "$ac_c_undeclared_builtin_options" "CFLAGS" +" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_fdopendir" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_FDOPENDIR $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_FDOPENDIR $ac_have_decl" >>confdefs.h if test $ac_have_decl = 1 then : -else $as_nop - HAVE_DECL_FDOPENDIR=0 +else case e in #( + e) HAVE_DECL_FDOPENDIR=0 ;; +esac fi if test $ac_cv_func_fdopendir = no; then HAVE_FDOPENDIR=0 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether fdopendir works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether fdopendir works" >&5 printf %s "checking whether fdopendir works... " >&6; } if test ${gl_cv_func_fdopendir_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in # Guess yes on glibc systems. @@ -51401,8 +52617,8 @@ then : *) gl_cv_func_fdopendir_works="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -51437,16 +52653,19 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_fdopendir_works=yes -else $as_nop - gl_cv_func_fdopendir_works=no +else case e in #( + e) gl_cv_func_fdopendir_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fdopendir_works" >&5 -printf "%s\n" "$gl_cv_func_fdopendir_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fdopendir_works" >&5 +printf '%s\n' "$gl_cv_func_fdopendir_works" >&6; } case "$gl_cv_func_fdopendir_works" in *yes) ;; *) @@ -51482,13 +52701,13 @@ printf "%s\n" "$gl_cv_func_fdopendir_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_FDOPENDIR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FDOPENDIR 1" >>confdefs.h -printf "%s\n" "#define GNULIB_FDOPENDIR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_FDOPENDIR 1" >>confdefs.h gl_gnulib_enabled_fdopendir=true @@ -51525,13 +52744,13 @@ printf "%s\n" "#define GNULIB_FDOPENDIR 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ffs" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for ffs" >&5 printf %s "checking for ffs... " >&6; } if test ${gl_cv_func_ffs+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int x; @@ -51550,15 +52769,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_ffs=yes -else $as_nop - gl_cv_func_ffs=no +else case e in #( + e) gl_cv_func_ffs=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ffs" >&5 -printf "%s\n" "$gl_cv_func_ffs" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ffs" >&5 +printf '%s\n' "$gl_cv_func_ffs" >&6; } if test $gl_cv_func_ffs = no; then HAVE_FFS=0 fi @@ -51700,7 +52921,7 @@ printf "%s\n" "$gl_cv_func_ffs" >&6; } -printf "%s\n" "#define GNULIB_TEST_FSTAT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FSTAT 1" >>confdefs.h @@ -51723,21 +52944,21 @@ printf "%s\n" "#define GNULIB_TEST_FSTAT 1" >>confdefs.h if test $ac_cv_func_fstatat = no; then HAVE_FSTATAT=0 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether fstatat (..., 0) works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether fstatat (..., 0) works" >&5 printf %s "checking whether fstatat (..., 0) works... " >&6; } if test ${gl_cv_func_fstatat_zero_flag+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in aix*) gl_cv_func_fstatat_zero_flag="guessing no";; *) gl_cv_func_fstatat_zero_flag="guessing yes";; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -51753,17 +52974,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_fstatat_zero_flag=yes -else $as_nop - gl_cv_func_fstatat_zero_flag=no +else case e in #( + e) gl_cv_func_fstatat_zero_flag=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fstatat_zero_flag" >&5 -printf "%s\n" "$gl_cv_func_fstatat_zero_flag" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_fstatat_zero_flag" >&5 +printf '%s\n' "$gl_cv_func_fstatat_zero_flag" >&6; } case $gl_cv_func_fstatat_zero_flag+$gl_cv_func_lstat_dereferences_slashed_symlink in *yes+*yes) ;; @@ -51778,7 +53002,7 @@ printf "%s\n" "$gl_cv_func_fstatat_zero_flag" >&6; } case $REPLACE_FSTATAT,$gl_cv_func_fstatat_zero_flag in 1,*yes) -printf "%s\n" "#define HAVE_WORKING_FSTATAT_ZERO_FLAG 1" >>confdefs.h +printf '%s\n' "#define HAVE_WORKING_FSTATAT_ZERO_FLAG 1" >>confdefs.h ;; esac @@ -51811,7 +53035,7 @@ printf "%s\n" "#define HAVE_WORKING_FSTATAT_ZERO_FLAG 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_FSTATAT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_FSTATAT 1" >>confdefs.h @@ -51881,7 +53105,7 @@ printf "%s\n" "#define GNULIB_TEST_FSTATAT 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_GETCWD 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_GETCWD 1" >>confdefs.h @@ -51901,13 +53125,13 @@ printf "%s\n" "#define GNULIB_TEST_GETCWD 1" >>confdefs.h if test $ac_cv_func_getdelim = yes; then HAVE_GETDELIM=1 - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working getdelim function" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working getdelim function" >&5 printf %s "checking for working getdelim function... " >&6; } if test ${gl_cv_func_working_getdelim+y} then : printf %s "(cached) " >&6 -else $as_nop - echo fooNbarN | tr -d '\012' | tr N '\012' > conftest.data +else case e in #( + e) echo fooNbarN | tr -d '\012' | tr N '\012' > conftest.data if test "$cross_compiling" = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -51922,21 +53146,22 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Lucky GNU user" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Lucky GNU user" >/dev/null 2>&1 then : gl_cv_func_working_getdelim="guessing yes" -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in *-musl*) gl_cv_func_working_getdelim="guessing yes" ;; *) gl_cv_func_working_getdelim="$gl_cross_guess_normal" ;; esac - + ;; +esac fi rm -rf conftest* -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include @@ -51974,17 +53199,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_working_getdelim=yes -else $as_nop - gl_cv_func_working_getdelim=no +else case e in #( + e) gl_cv_func_working_getdelim=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_working_getdelim" >&5 -printf "%s\n" "$gl_cv_func_working_getdelim" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_working_getdelim" >&5 +printf '%s\n' "$gl_cv_func_working_getdelim" >&6; } case "$gl_cv_func_working_getdelim" in *yes) ;; *) REPLACE_GETDELIM=1 ;; @@ -52012,24 +53240,25 @@ printf "%s\n" "$gl_cv_func_working_getdelim" >&6; } ac_fn_c_check_func "$LINENO" "flockfile" "ac_cv_func_flockfile" if test "x$ac_cv_func_flockfile" = xyes then : - printf "%s\n" "#define HAVE_FLOCKFILE 1" >>confdefs.h + printf '%s\n' "#define HAVE_FLOCKFILE 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "funlockfile" "ac_cv_func_funlockfile" if test "x$ac_cv_func_funlockfile" = xyes then : - printf "%s\n" "#define HAVE_FUNLOCKFILE 1" >>confdefs.h + printf '%s\n' "#define HAVE_FUNLOCKFILE 1" >>confdefs.h fi - ac_fn_check_decl "$LINENO" "getc_unlocked" "ac_cv_have_decl_getc_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options" "CFLAGS" + ac_fn_check_decl "$LINENO" "getc_unlocked" "ac_cv_have_decl_getc_unlocked" "$ac_includes_default" "$ac_c_undeclared_builtin_options$ac_c_future_darwin_options" "CFLAGS" if test "x$ac_cv_have_decl_getc_unlocked" = xyes then : ac_have_decl=1 -else $as_nop - ac_have_decl=0 +else case e in #( + e) ac_have_decl=0 ;; +esac fi -printf "%s\n" "#define HAVE_DECL_GETC_UNLOCKED $ac_have_decl" >>confdefs.h +printf '%s\n' "#define HAVE_DECL_GETC_UNLOCKED $ac_have_decl" >>confdefs.h fi @@ -52048,7 +53277,7 @@ printf "%s\n" "#define HAVE_DECL_GETC_UNLOCKED $ac_have_decl" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_GETDELIM 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_GETDELIM 1" >>confdefs.h @@ -52065,13 +53294,13 @@ printf "%s\n" "#define GNULIB_TEST_GETDELIM 1" >>confdefs.h if test $ac_cv_func_getdtablesize = yes && test $ac_cv_have_decl_getdtablesize = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether getdtablesize works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether getdtablesize works" >&5 printf %s "checking whether getdtablesize works... " >&6; } if test ${gl_cv_func_getdtablesize_works+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in vms*) gl_cv_func_getdtablesize_works="no (limitation)" ;; *) if test "$cross_compiling" = yes @@ -52082,8 +53311,8 @@ then : *) gl_cv_func_getdtablesize_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -52108,19 +53337,22 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_getdtablesize_works=yes -else $as_nop - gl_cv_func_getdtablesize_works=no +else case e in #( + e) gl_cv_func_getdtablesize_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getdtablesize_works" >&5 -printf "%s\n" "$gl_cv_func_getdtablesize_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_getdtablesize_works" >&5 +printf '%s\n' "$gl_cv_func_getdtablesize_works" >&6; } case "$gl_cv_func_getdtablesize_works" in *yes | "no (limitation)") ;; *) REPLACE_GETDTABLESIZE=1 ;; @@ -52157,7 +53389,7 @@ printf "%s\n" "$gl_cv_func_getdtablesize_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_GETDTABLESIZE 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_GETDTABLESIZE 1" >>confdefs.h @@ -52179,18 +53411,19 @@ printf "%s\n" "#define GNULIB_TEST_GETDTABLESIZE 1" >>confdefs.h if test "x$ac_cv_func_getline" = xyes then : gl_getline_needs_run_time_check=yes -else $as_nop - am_cv_func_working_getline=no +else case e in #( + e) am_cv_func_working_getline=no ;; +esac fi if test $gl_getline_needs_run_time_check = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working getline function" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working getline function" >&5 printf %s "checking for working getline function... " >&6; } if test ${am_cv_func_working_getline+y} then : printf %s "(cached) " >&6 -else $as_nop - echo fooNbarN | tr -d '\012' | tr N '\012' > conftest.data +else case e in #( + e) echo fooNbarN | tr -d '\012' | tr N '\012' > conftest.data if test "$cross_compiling" = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -52205,21 +53438,22 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Lucky GNU user" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Lucky GNU user" >/dev/null 2>&1 then : am_cv_func_working_getline="guessing yes" -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in *-musl*) am_cv_func_working_getline="guessing yes" ;; *) am_cv_func_working_getline="$gl_cross_guess_normal" ;; esac - + ;; +esac fi rm -rf conftest* -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ # include @@ -52257,17 +53491,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : am_cv_func_working_getline=yes -else $as_nop - am_cv_func_working_getline=no +else case e in #( + e) am_cv_func_working_getline=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_working_getline" >&5 -printf "%s\n" "$am_cv_func_working_getline" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_working_getline" >&5 +printf '%s\n' "$am_cv_func_working_getline" >&6; } fi if test $ac_cv_have_decl_getline = no; then @@ -52311,7 +53548,7 @@ printf "%s\n" "$am_cv_func_working_getline" >&6; } -printf "%s\n" "#define GNULIB_TEST_GETLINE 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_GETLINE 1" >>confdefs.h @@ -52336,13 +53573,13 @@ printf "%s\n" "#define GNULIB_TEST_GETLINE 1" >>confdefs.h if ! $gl_gnulib_enabled_3f0e593033d1fc2c127581960f641b66; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) can be used without linking with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) can be used without linking with libm" >&5 printf %s "checking whether isnan(float) can be used without linking with libm... " >&6; } if test ${gl_cv_func_isnanf_no_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -52365,27 +53602,29 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_isnanf_no_libm=yes -else $as_nop - gl_cv_func_isnanf_no_libm=no +else case e in #( + e) gl_cv_func_isnanf_no_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_no_libm" >&5 -printf "%s\n" "$gl_cv_func_isnanf_no_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_no_libm" >&5 +printf '%s\n' "$gl_cv_func_isnanf_no_libm" >&6; } if test $gl_cv_func_isnanf_no_libm = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether isnan(float) works" >&5 printf %s "checking whether isnan(float) works... " >&6; } if test ${gl_cv_func_isnanf_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : case "$host_os" in @@ -52400,11 +53639,12 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Known" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Known" >/dev/null 2>&1 then : gl_cv_func_isnanf_works="guessing yes" -else $as_nop - gl_cv_func_isnanf_works="guessing no" +else case e in #( + e) gl_cv_func_isnanf_works="guessing no" ;; +esac fi rm -rf conftest* @@ -52412,8 +53652,8 @@ rm -rf conftest* *) gl_cv_func_isnanf_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -52471,17 +53711,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_isnanf_works=yes -else $as_nop - gl_cv_func_isnanf_works=no +else case e in #( + e) gl_cv_func_isnanf_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_works" >&5 -printf "%s\n" "$gl_cv_func_isnanf_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_isnanf_works" >&5 +printf '%s\n' "$gl_cv_func_isnanf_works" >&6; } fi if test $gl_cv_func_isnanf_no_libm = yes \ @@ -52492,7 +53735,7 @@ printf "%s\n" "$gl_cv_func_isnanf_works" >&6; } }; then gl_func_isnanf_no_libm=yes -printf "%s\n" "#define HAVE_ISNANF_IN_LIBC 1" >>confdefs.h +printf '%s\n' "#define HAVE_ISNANF_IN_LIBC 1" >>confdefs.h else gl_func_isnanf_no_libm=no @@ -52511,18 +53754,18 @@ printf "%s\n" "#define HAVE_ISNANF_IN_LIBC 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'float'" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking where to find the exponent in a 'float'" >&5 printf %s "checking where to find the exponent in a 'float'... " >&6; } if test ${gl_cv_cc_float_expbit0+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) if test "$cross_compiling" = yes then : gl_cv_cc_float_expbit0="word 0 bit 23" -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -52593,27 +53836,30 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_cc_float_expbit0=`cat conftest.out` -else $as_nop - gl_cv_cc_float_expbit0="unknown" +else case e in #( + e) gl_cv_cc_float_expbit0="unknown" ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi rm -f conftest.out - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_float_expbit0" >&5 -printf "%s\n" "$gl_cv_cc_float_expbit0" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_float_expbit0" >&5 +printf '%s\n' "$gl_cv_cc_float_expbit0" >&6; } case "$gl_cv_cc_float_expbit0" in word*bit*) word=`echo "$gl_cv_cc_float_expbit0" | sed -e 's/word //' -e 's/ bit.*//'` bit=`echo "$gl_cv_cc_float_expbit0" | sed -e 's/word.*bit //'` -printf "%s\n" "#define FLT_EXPBIT0_WORD $word" >>confdefs.h +printf '%s\n' "#define FLT_EXPBIT0_WORD $word" >>confdefs.h -printf "%s\n" "#define FLT_EXPBIT0_BIT $bit" >>confdefs.h +printf '%s\n' "#define FLT_EXPBIT0_BIT $bit" >>confdefs.h ;; esac @@ -52630,13 +53876,13 @@ printf "%s\n" "#define FLT_EXPBIT0_BIT $bit" >>confdefs.h LDEXP_LIBM= if test $gl_cv_func_ldexp_no_libm = no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ldexp() can be used with libm" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether ldexp() can be used with libm" >&5 printf %s "checking whether ldexp() can be used with libm... " >&6; } if test ${gl_cv_func_ldexp_in_libm+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) save_LIBS="$LIBS" LIBS="$LIBS -lm" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -52658,16 +53904,18 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gl_cv_func_ldexp_in_libm=yes -else $as_nop - gl_cv_func_ldexp_in_libm=no +else case e in #( + e) gl_cv_func_ldexp_in_libm=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexp_in_libm" >&5 -printf "%s\n" "$gl_cv_func_ldexp_in_libm" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_ldexp_in_libm" >&5 +printf '%s\n' "$gl_cv_func_ldexp_in_libm" >&6; } if test $gl_cv_func_ldexp_in_libm = yes; then LDEXP_LIBM=-lm fi @@ -52735,7 +53983,7 @@ printf "%s\n" "$gl_cv_func_ldexp_in_libm" >&6; } -printf "%s\n" "#define GNULIB_TEST_LSTAT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_LSTAT 1" >>confdefs.h @@ -52769,7 +54017,7 @@ printf "%s\n" "#define GNULIB_TEST_LSTAT 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "memrchr" "ac_cv_func_memrchr" if test "x$ac_cv_func_memrchr" = xyes then : - printf "%s\n" "#define HAVE_MEMRCHR 1" >>confdefs.h + printf '%s\n' "#define HAVE_MEMRCHR 1" >>confdefs.h fi @@ -52802,7 +54050,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_MEMRCHR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_MEMRCHR 1" >>confdefs.h @@ -52850,7 +54098,7 @@ printf "%s\n" "#define GNULIB_TEST_MEMRCHR 1" >>confdefs.h fi -printf "%s\n" "#define GNULIB_OPENAT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_OPENAT 1" >>confdefs.h @@ -52867,7 +54115,7 @@ printf "%s\n" "#define GNULIB_OPENAT 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_OPENAT 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_OPENAT 1" >>confdefs.h @@ -52914,7 +54162,7 @@ printf "%s\n" "#define GNULIB_TEST_OPENAT 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "opendir" "ac_cv_func_opendir" if test "x$ac_cv_func_opendir" = xyes then : - printf "%s\n" "#define HAVE_OPENDIR 1" >>confdefs.h + printf '%s\n' "#define HAVE_OPENDIR 1" >>confdefs.h fi @@ -52967,7 +54215,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_OPENDIR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_OPENDIR 1" >>confdefs.h @@ -53002,44 +54250,44 @@ printf "%s\n" "#define GNULIB_TEST_OPENDIR 1" >>confdefs.h ac_fn_c_check_header_compile "$LINENO" "paths.h" "ac_cv_header_paths_h" "$ac_includes_default" if test "x$ac_cv_header_paths_h" = xyes then : - printf "%s\n" "#define HAVE_PATHS_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_PATHS_H 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "confstr" "ac_cv_func_confstr" if test "x$ac_cv_func_confstr" = xyes then : - printf "%s\n" "#define HAVE_CONFSTR 1" >>confdefs.h + printf '%s\n' "#define HAVE_CONFSTR 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sched_setparam" "ac_cv_func_sched_setparam" if test "x$ac_cv_func_sched_setparam" = xyes then : - printf "%s\n" "#define HAVE_SCHED_SETPARAM 1" >>confdefs.h + printf '%s\n' "#define HAVE_SCHED_SETPARAM 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "sched_setscheduler" "ac_cv_func_sched_setscheduler" if test "x$ac_cv_func_sched_setscheduler" = xyes then : - printf "%s\n" "#define HAVE_SCHED_SETSCHEDULER 1" >>confdefs.h + printf '%s\n' "#define HAVE_SCHED_SETSCHEDULER 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "setegid" "ac_cv_func_setegid" if test "x$ac_cv_func_setegid" = xyes then : - printf "%s\n" "#define HAVE_SETEGID 1" >>confdefs.h + printf '%s\n' "#define HAVE_SETEGID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "seteuid" "ac_cv_func_seteuid" if test "x$ac_cv_func_seteuid" = xyes then : - printf "%s\n" "#define HAVE_SETEUID 1" >>confdefs.h + printf '%s\n' "#define HAVE_SETEUID 1" >>confdefs.h fi ac_fn_c_check_func "$LINENO" "vfork" "ac_cv_func_vfork" if test "x$ac_cv_func_vfork" = xyes then : - printf "%s\n" "#define HAVE_VFORK 1" >>confdefs.h + printf '%s\n' "#define HAVE_VFORK 1" >>confdefs.h fi @@ -53062,7 +54310,7 @@ fi ac_fn_c_check_func "$LINENO" "readdir" "ac_cv_func_readdir" if test "x$ac_cv_func_readdir" = xyes then : - printf "%s\n" "#define HAVE_READDIR 1" >>confdefs.h + printf '%s\n' "#define HAVE_READDIR 1" >>confdefs.h fi @@ -53097,7 +54345,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_READDIR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_READDIR 1" >>confdefs.h @@ -53114,7 +54362,7 @@ printf "%s\n" "#define GNULIB_TEST_READDIR 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "rewinddir" "ac_cv_func_rewinddir" if test "x$ac_cv_func_rewinddir" = xyes then : - printf "%s\n" "#define HAVE_REWINDDIR 1" >>confdefs.h + printf '%s\n' "#define HAVE_REWINDDIR 1" >>confdefs.h fi @@ -53149,7 +54397,7 @@ fi -printf "%s\n" "#define GNULIB_TEST_REWINDDIR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_REWINDDIR 1" >>confdefs.h @@ -53163,13 +54411,13 @@ printf "%s\n" "#define GNULIB_TEST_REWINDDIR 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether rmdir works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether rmdir works" >&5 printf %s "checking whether rmdir works... " >&6; } if test ${gl_cv_func_rmdir_works+y} then : printf %s "(cached) " >&6 -else $as_nop - mkdir conftest.dir +else case e in #( + e) mkdir conftest.dir touch conftest.file if test "$cross_compiling" = yes then : @@ -53184,8 +54432,8 @@ then : *) gl_cv_func_rmdir_works="$gl_cross_guess_normal" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include @@ -53217,17 +54465,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_rmdir_works=yes -else $as_nop - gl_cv_func_rmdir_works=no +else case e in #( + e) gl_cv_func_rmdir_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - rm -rf conftest.dir conftest.file + rm -rf conftest.dir conftest.file ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_rmdir_works" >&5 -printf "%s\n" "$gl_cv_func_rmdir_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_rmdir_works" >&5 +printf '%s\n' "$gl_cv_func_rmdir_works" >&6; } case "$gl_cv_func_rmdir_works" in *yes) ;; *) @@ -53262,7 +54513,7 @@ printf "%s\n" "$gl_cv_func_rmdir_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_RMDIR 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_RMDIR 1" >>confdefs.h @@ -53289,13 +54540,13 @@ printf "%s\n" "#define GNULIB_TEST_RMDIR 1" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether setlocale (LC_ALL, NULL) is multithread-safe" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether setlocale (LC_ALL, NULL) is multithread-safe" >&5 printf %s "checking whether setlocale (LC_ALL, NULL) is multithread-safe... " >&6; } if test ${gl_cv_func_setlocale_null_all_mtsafe+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in # Guess no on musl libc, macOS, FreeBSD, NetBSD, OpenBSD, AIX, Haiku, Cygwin. *-musl* | darwin* | freebsd* | midnightbsd* | netbsd* | openbsd* | aix* | haiku* | cygwin*) gl_cv_func_setlocale_null_all_mtsafe=no ;; @@ -53306,10 +54557,11 @@ else $as_nop *) gl_cv_func_setlocale_null_all_mtsafe="$gl_cross_guess_normal" ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_setlocale_null_all_mtsafe" >&5 -printf "%s\n" "$gl_cv_func_setlocale_null_all_mtsafe" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_setlocale_null_all_mtsafe" >&5 +printf '%s\n' "$gl_cv_func_setlocale_null_all_mtsafe" >&6; } case "$host_os" in mingw*) ;; *) @@ -53323,16 +54575,16 @@ printf "%s\n" "$gl_cv_func_setlocale_null_all_mtsafe" >&6; } *) SETLOCALE_NULL_ALL_MTSAFE=0 ;; esac -printf "%s\n" "#define SETLOCALE_NULL_ALL_MTSAFE $SETLOCALE_NULL_ALL_MTSAFE" >>confdefs.h +printf '%s\n' "#define SETLOCALE_NULL_ALL_MTSAFE $SETLOCALE_NULL_ALL_MTSAFE" >>confdefs.h - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether setlocale (category, NULL) is multithread-safe" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether setlocale (category, NULL) is multithread-safe" >&5 printf %s "checking whether setlocale (category, NULL) is multithread-safe... " >&6; } if test ${gl_cv_func_setlocale_null_one_mtsafe+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in # Guess no on OpenBSD, AIX. openbsd* | aix*) gl_cv_func_setlocale_null_one_mtsafe=no ;; @@ -53343,10 +54595,11 @@ else $as_nop *) gl_cv_func_setlocale_null_one_mtsafe="$gl_cross_guess_normal" ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_setlocale_null_one_mtsafe" >&5 -printf "%s\n" "$gl_cv_func_setlocale_null_one_mtsafe" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_setlocale_null_one_mtsafe" >&5 +printf '%s\n' "$gl_cv_func_setlocale_null_one_mtsafe" >&6; } case "$host_os" in mingw*) ;; *) @@ -53360,7 +54613,7 @@ printf "%s\n" "$gl_cv_func_setlocale_null_one_mtsafe" >&6; } *) SETLOCALE_NULL_ONE_MTSAFE=0 ;; esac -printf "%s\n" "#define SETLOCALE_NULL_ONE_MTSAFE $SETLOCALE_NULL_ONE_MTSAFE" >>confdefs.h +printf '%s\n' "#define SETLOCALE_NULL_ONE_MTSAFE $SETLOCALE_NULL_ONE_MTSAFE" >>confdefs.h if test $SETLOCALE_NULL_ALL_MTSAFE = 0 || test $SETLOCALE_NULL_ONE_MTSAFE = 0; then @@ -53369,13 +54622,13 @@ printf "%s\n" "#define SETLOCALE_NULL_ONE_MTSAFE $SETLOCALE_NULL_ONE_MTSAFE" >>c *) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether imported symbols can be declared weak" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether imported symbols can be declared weak" >&5 printf %s "checking whether imported symbols can be declared weak... " >&6; } if test ${gl_cv_have_weak+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$host_os" in +else case e in #( + e) case "$host_os" in cygwin*) gl_cv_have_weak="guessing no" ;; @@ -53410,17 +54663,18 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Extensible Linking Format" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Extensible Linking Format" >/dev/null 2>&1 then : gl_cv_have_weak="guessing yes" -else $as_nop - gl_cv_have_weak="guessing no" +else case e in #( + e) gl_cv_have_weak="guessing no" ;; +esac fi rm -rf conftest* -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -53433,11 +54687,13 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_have_weak=yes -else $as_nop - gl_cv_have_weak=no +else case e in #( + e) gl_cv_have_weak=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi fi @@ -53467,14 +54723,15 @@ EOF esac ;; esac - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_weak" >&5 -printf "%s\n" "$gl_cv_have_weak" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_have_weak" >&5 +printf '%s\n' "$gl_cv_have_weak" >&6; } case "$gl_cv_have_weak" in *yes) -printf "%s\n" "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h +printf '%s\n' "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h ;; esac @@ -53507,13 +54764,13 @@ printf "%s\n" "#define HAVE_WEAK_SYMBOLS 1" >>confdefs.h CFLAG_VISIBILITY= HAVE_VISIBILITY=0 if test -n "$GCC"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the -Werror option is usable" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether the -Werror option is usable" >&5 printf %s "checking whether the -Werror option is usable... " >&6; } if test ${gl_cv_cc_vis_werror+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_save_CFLAGS="$CFLAGS" +else case e in #( + e) gl_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -Werror" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -53529,22 +54786,24 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_cc_vis_werror=yes -else $as_nop - gl_cv_cc_vis_werror=no +else case e in #( + e) gl_cv_cc_vis_werror=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$gl_save_CFLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_vis_werror" >&5 -printf "%s\n" "$gl_cv_cc_vis_werror" >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for simple visibility declarations" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_vis_werror" >&5 +printf '%s\n' "$gl_cv_cc_vis_werror" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for simple visibility declarations" >&5 printf %s "checking for simple visibility declarations... " >&6; } if test ${gl_cv_cc_visibility+y} then : printf %s "(cached) " >&6 -else $as_nop - gl_save_CFLAGS="$CFLAGS" +else case e in #( + e) gl_save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -fvisibility=hidden" if test $gl_cv_cc_vis_werror = yes; then CFLAGS="$CFLAGS -Werror" @@ -53573,15 +54832,17 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : gl_cv_cc_visibility=yes -else $as_nop - gl_cv_cc_visibility=no +else case e in #( + e) gl_cv_cc_visibility=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="$gl_save_CFLAGS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_visibility" >&5 -printf "%s\n" "$gl_cv_cc_visibility" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_cc_visibility" >&5 +printf '%s\n' "$gl_cv_cc_visibility" >&6; } if test $gl_cv_cc_visibility = yes; then CFLAG_VISIBILITY="-fvisibility=hidden" HAVE_VISIBILITY=1 @@ -53590,7 +54851,7 @@ printf "%s\n" "$gl_cv_cc_visibility" >&6; } -printf "%s\n" "#define HAVE_VISIBILITY $HAVE_VISIBILITY" >>confdefs.h +printf '%s\n' "#define HAVE_VISIBILITY $HAVE_VISIBILITY" >>confdefs.h @@ -53610,7 +54871,7 @@ printf "%s\n" "#define HAVE_VISIBILITY $HAVE_VISIBILITY" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_SETLOCALE_NULL 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_SETLOCALE_NULL 1" >>confdefs.h @@ -53640,15 +54901,15 @@ printf "%s\n" "#define GNULIB_TEST_SETLOCALE_NULL 1" >>confdefs.h if test "x$ac_cv_member_struct_stat_st_atim_tv_nsec" = xyes then : -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 1" >>confdefs.h +printf '%s\n' "#define HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC 1" >>confdefs.h -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether struct stat.st_atim is of type struct timespec" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether struct stat.st_atim is of type struct timespec" >&5 printf %s "checking whether struct stat.st_atim is of type struct timespec... " >&6; } if test ${ac_cv_typeof_struct_stat_st_atim_is_struct_timespec+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -53673,54 +54934,59 @@ _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_typeof_struct_stat_st_atim_is_struct_timespec=yes -else $as_nop - ac_cv_typeof_struct_stat_st_atim_is_struct_timespec=no +else case e in #( + e) ac_cv_typeof_struct_stat_st_atim_is_struct_timespec=no ;; +esac fi -rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_typeof_struct_stat_st_atim_is_struct_timespec" >&5 -printf "%s\n" "$ac_cv_typeof_struct_stat_st_atim_is_struct_timespec" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_typeof_struct_stat_st_atim_is_struct_timespec" >&5 +printf '%s\n' "$ac_cv_typeof_struct_stat_st_atim_is_struct_timespec" >&6; } if test $ac_cv_typeof_struct_stat_st_atim_is_struct_timespec = yes; then -printf "%s\n" "#define TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC 1" >>confdefs.h +printf '%s\n' "#define TYPEOF_STRUCT_STAT_ST_ATIM_IS_STRUCT_TIMESPEC 1" >>confdefs.h fi -else $as_nop - ac_fn_c_check_member "$LINENO" "struct stat" "st_atimespec.tv_nsec" "ac_cv_member_struct_stat_st_atimespec_tv_nsec" "#include +else case e in #( + e) ac_fn_c_check_member "$LINENO" "struct stat" "st_atimespec.tv_nsec" "ac_cv_member_struct_stat_st_atimespec_tv_nsec" "#include #include " if test "x$ac_cv_member_struct_stat_st_atimespec_tv_nsec" = xyes then : -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC 1" >>confdefs.h +printf '%s\n' "#define HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC 1" >>confdefs.h -else $as_nop - ac_fn_c_check_member "$LINENO" "struct stat" "st_atimensec" "ac_cv_member_struct_stat_st_atimensec" "#include +else case e in #( + e) ac_fn_c_check_member "$LINENO" "struct stat" "st_atimensec" "ac_cv_member_struct_stat_st_atimensec" "#include #include " if test "x$ac_cv_member_struct_stat_st_atimensec" = xyes then : -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_ATIMENSEC 1" >>confdefs.h +printf '%s\n' "#define HAVE_STRUCT_STAT_ST_ATIMENSEC 1" >>confdefs.h -else $as_nop - ac_fn_c_check_member "$LINENO" "struct stat" "st_atim.st__tim.tv_nsec" "ac_cv_member_struct_stat_st_atim_st__tim_tv_nsec" "#include +else case e in #( + e) ac_fn_c_check_member "$LINENO" "struct stat" "st_atim.st__tim.tv_nsec" "ac_cv_member_struct_stat_st_atim_st__tim_tv_nsec" "#include #include " if test "x$ac_cv_member_struct_stat_st_atim_st__tim_tv_nsec" = xyes then : -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC 1" >>confdefs.h +printf '%s\n' "#define HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC 1" >>confdefs.h fi - + ;; +esac fi - + ;; +esac fi - + ;; +esac fi @@ -53733,33 +54999,35 @@ fi if test "x$ac_cv_member_struct_stat_st_birthtimespec_tv_nsec" = xyes then : -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1" >>confdefs.h +printf '%s\n' "#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1" >>confdefs.h -else $as_nop - ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtimensec" "ac_cv_member_struct_stat_st_birthtimensec" "#include +else case e in #( + e) ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtimensec" "ac_cv_member_struct_stat_st_birthtimensec" "#include #include " if test "x$ac_cv_member_struct_stat_st_birthtimensec" = xyes then : -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC 1" >>confdefs.h +printf '%s\n' "#define HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC 1" >>confdefs.h -else $as_nop - ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtim.tv_nsec" "ac_cv_member_struct_stat_st_birthtim_tv_nsec" "#include +else case e in #( + e) ac_fn_c_check_member "$LINENO" "struct stat" "st_birthtim.tv_nsec" "ac_cv_member_struct_stat_st_birthtim_tv_nsec" "#include #include " if test "x$ac_cv_member_struct_stat_st_birthtim_tv_nsec" = xyes then : -printf "%s\n" "#define HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC 1" >>confdefs.h +printf '%s\n' "#define HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC 1" >>confdefs.h fi - + ;; +esac fi - + ;; +esac fi @@ -53776,20 +55044,20 @@ fi ac_fn_c_check_func "$LINENO" "strchrnul" "ac_cv_func_strchrnul" if test "x$ac_cv_func_strchrnul" = xyes then : - printf "%s\n" "#define HAVE_STRCHRNUL 1" >>confdefs.h + printf '%s\n' "#define HAVE_STRCHRNUL 1" >>confdefs.h fi if test $ac_cv_func_strchrnul = no; then HAVE_STRCHRNUL=0 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether strchrnul works" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether strchrnul works" >&5 printf %s "checking whether strchrnul works... " >&6; } if test ${gl_cv_func_strchrnul_works+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -53805,17 +55073,18 @@ then : _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "Lucky user" >/dev/null 2>&1 + $EGREP_TRADITIONAL "Lucky user" >/dev/null 2>&1 then : gl_cv_func_strchrnul_works="guessing yes" -else $as_nop - gl_cv_func_strchrnul_works="guessing no" +else case e in #( + e) gl_cv_func_strchrnul_works="guessing no" ;; +esac fi rm -rf conftest* -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* for strchrnul */ @@ -53833,17 +55102,20 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : gl_cv_func_strchrnul_works=yes -else $as_nop - gl_cv_func_strchrnul_works=no +else case e in #( + e) gl_cv_func_strchrnul_works=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strchrnul_works" >&5 -printf "%s\n" "$gl_cv_func_strchrnul_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gl_cv_func_strchrnul_works" >&5 +printf '%s\n' "$gl_cv_func_strchrnul_works" >&6; } case "$gl_cv_func_strchrnul_works" in *yes) ;; *) REPLACE_STRCHRNUL=1 ;; @@ -53878,7 +55150,7 @@ printf "%s\n" "$gl_cv_func_strchrnul_works" >&6; } -printf "%s\n" "#define GNULIB_TEST_STRCHRNUL 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_STRCHRNUL 1" >>confdefs.h @@ -53909,7 +55181,7 @@ printf "%s\n" "#define GNULIB_TEST_STRCHRNUL 1" >>confdefs.h ac_fn_c_check_header_compile "$LINENO" "winsock2.h" "ac_cv_header_winsock2_h" "$ac_includes_default" if test "x$ac_cv_header_winsock2_h" = xyes then : - printf "%s\n" "#define HAVE_WINSOCK2_H 1" >>confdefs.h + printf '%s\n' "#define HAVE_WINSOCK2_H 1" >>confdefs.h fi @@ -53989,13 +55261,13 @@ fi -printf "%s\n" "#define GNULIB_TEST_STRERROR_R 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_STRERROR_R 1" >>confdefs.h -printf "%s\n" "#define GNULIB_STRERROR_R_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_STRERROR_R_POSIX 1" >>confdefs.h gl_gnulib_enabled_1f32594a85e6221ba15f884daeee8c2a=true @@ -54029,42 +55301,68 @@ printf "%s\n" "#define GNULIB_STRERROR_R_POSIX 1" >>confdefs.h HAVE_DECL_STRNLEN=0 else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working strnlen" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working strnlen" >&5 printf %s "checking for working strnlen... " >&6; } if test ${ac_cv_func_strnlen_working+y} then : printf %s "(cached) " >&6 -else $as_nop - if test "$cross_compiling" = yes +else case e in #( + e) if test "$cross_compiling" = yes then : - # Guess no on AIX systems, yes otherwise. - case "$host_os" in - aix*) ac_cv_func_strnlen_working=no;; - *) ac_cv_func_strnlen_working=yes;; - esac -else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main (void) { +#if defined _AIX && !defined _AIX51 + #error "AIX pre 5.1 is buggy" + #endif + #ifdef __ANDROID__ + #include + #if __ANDROID_API__ < 22 + #error "Android API < 22 is buggy" + #endif + #endif -#define S "foobar" -#define S_LEN (sizeof S - 1) - - /* At least one implementation is buggy: that of AIX 4.3 would - give strnlen (S, 1) == 3. */ - - int i; - for (i = 0; i < S_LEN + 1; ++i) - { - int expected = i <= S_LEN ? i : S_LEN; - if (strnlen (S, i) != expected) - return 1; - } + ; return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_func_strnlen_working=yes +else case e in #( + e) ac_cv_func_strnlen_working=no ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + /* Use pstrnlen to test; 'volatile' prevents the compiler + from optimizing the strnlen calls away. */ + size_t (*volatile pstrnlen) (char const *, size_t) = strnlen; + char const s[] = "foobar"; + int s_len = sizeof s - 1; +int +main (void) +{ + + /* AIX 4.3 is buggy: strnlen (S, 1) == 3. */ + int i; + for (i = 0; i < s_len + 1; ++i) + { + int expected = i <= s_len ? i : s_len; + if (pstrnlen (s, i) != expected) + return 1; + } + + /* Android 5.0 (API 21) strnlen ("", SIZE_MAX) incorrectly crashes. */ + if (pstrnlen ("", -1) != 0) + return 1; ; return 0; } @@ -54072,16 +55370,19 @@ _ACEOF if ac_fn_c_try_run "$LINENO" then : ac_cv_func_strnlen_working=yes -else $as_nop - ac_cv_func_strnlen_working=no +else case e in #( + e) ac_cv_func_strnlen_working=no ;; +esac fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strnlen_working" >&5 -printf "%s\n" "$ac_cv_func_strnlen_working" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strnlen_working" >&5 +printf '%s\n' "$ac_cv_func_strnlen_working" >&6; } test $ac_cv_func_strnlen_working = no && : @@ -54118,7 +55419,7 @@ test $ac_cv_func_strnlen_working = no && : -printf "%s\n" "#define GNULIB_TEST_STRNLEN 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_STRNLEN 1" >>confdefs.h @@ -54212,7 +55513,7 @@ printf "%s\n" "#define GNULIB_TEST_STRNLEN 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; esac @@ -54227,7 +55528,7 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -54241,12 +55542,12 @@ printf "%s\n" "#define NEED_PRINTF_INFINITE_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_A 1" >>confdefs.h ac_fn_c_check_func "$LINENO" "nl_langinfo" "ac_cv_func_nl_langinfo" if test "x$ac_cv_func_nl_langinfo" = xyes then : - printf "%s\n" "#define HAVE_NL_LANGINFO 1" >>confdefs.h + printf '%s\n' "#define HAVE_NL_LANGINFO 1" >>confdefs.h fi @@ -54260,7 +55561,7 @@ fi ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; esac @@ -54272,7 +55573,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_F 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; esac @@ -54284,7 +55585,7 @@ printf "%s\n" "#define NEED_PRINTF_DIRECTIVE_LS 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; esac @@ -54296,7 +55597,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_GROUPING 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; esac @@ -54308,7 +55609,7 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_LEFTADJUST 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; esac @@ -54320,13 +55621,13 @@ printf "%s\n" "#define NEED_PRINTF_FLAG_ZERO 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_UNBOUNDED_PRECISION 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -54338,13 +55639,13 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; *) -printf "%s\n" "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_ENOMEM 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_DOUBLE 1" >>confdefs.h -printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h +printf '%s\n' "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h ;; esac @@ -54393,7 +55694,7 @@ printf "%s\n" "#define NEED_PRINTF_LONG_DOUBLE 1" >>confdefs.h if test $ac_cv_func_vasnprintf = yes; then -printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h +printf '%s\n' "#define REPLACE_VASNPRINTF 1" >>confdefs.h fi @@ -54409,11 +55710,12 @@ printf "%s\n" "#define REPLACE_VASNPRINTF 1" >>confdefs.h if test "x$ac_cv_type_ptrdiff_t" = xyes then : -else $as_nop - -printf "%s\n" "#define ptrdiff_t long" >>confdefs.h - +else case e in #( + e) +printf '%s\n' "#define ptrdiff_t long" >>confdefs.h + ;; +esac fi @@ -54436,7 +55738,7 @@ fi REPLACE_VFPRINTF=1 -printf "%s\n" "#define REPLACE_VFPRINTF_POSIX 1" >>confdefs.h +printf '%s\n' "#define REPLACE_VFPRINTF_POSIX 1" >>confdefs.h : @@ -54457,13 +55759,13 @@ printf "%s\n" "#define REPLACE_VFPRINTF_POSIX 1" >>confdefs.h -printf "%s\n" "#define GNULIB_TEST_VFPRINTF_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_TEST_VFPRINTF_POSIX 1" >>confdefs.h -printf "%s\n" "#define GNULIB_VFPRINTF_POSIX 1" >>confdefs.h +printf '%s\n' "#define GNULIB_VFPRINTF_POSIX 1" >>confdefs.h gl_gnulib_enabled_ed5616be3593d355b981ffab56b9f37b=true @@ -55155,18 +56457,19 @@ fi # We use gnulib, which is only guaranteed to work properly with the # latest Gettext. - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether NLS is requested" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether NLS is requested" >&5 printf %s "checking whether NLS is requested... " >&6; } # Check whether --enable-nls was given. if test ${enable_nls+y} then : enableval=$enable_nls; USE_NLS=$enableval -else $as_nop - USE_NLS=yes +else case e in #( + e) USE_NLS=yes ;; +esac fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 -printf "%s\n" "$USE_NLS" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 +printf '%s\n' "$USE_NLS" >&6; } @@ -55205,13 +56508,13 @@ rm -f conf$$.file # Extract the first word of "msgfmt", so it can be a program name with args. set dummy msgfmt; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_MSGFMT+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$MSGFMT" in +else case e in #( + e) case "$MSGFMT" in [\\/]* | ?:[\\/]*) ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. ;; @@ -55234,26 +56537,27 @@ else $as_nop IFS="$ac_save_IFS" test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":" ;; +esac ;; esac fi MSGFMT="$ac_cv_path_MSGFMT" if test "$MSGFMT" != ":"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 -printf "%s\n" "$MSGFMT" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 +printf '%s\n' "$MSGFMT" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi # Extract the first word of "gmsgfmt", so it can be a program name with args. set dummy gmsgfmt; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_GMSGFMT+y} then : printf %s "(cached) " >&6 -else $as_nop - case $GMSGFMT in +else case e in #( + e) case $GMSGFMT in [\\/]* | ?:[\\/]*) ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. ;; @@ -55270,7 +56574,7 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_path_GMSGFMT="$as_dir$ac_word$ac_exec_ext" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -55279,15 +56583,16 @@ IFS=$as_save_IFS test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" ;; +esac ;; esac fi GMSGFMT=$ac_cv_path_GMSGFMT if test -n "$GMSGFMT"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $GMSGFMT" >&5 -printf "%s\n" "$GMSGFMT" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $GMSGFMT" >&5 +printf '%s\n' "$GMSGFMT" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -55333,13 +56638,13 @@ rm -f conf$$.file # Extract the first word of "xgettext", so it can be a program name with args. set dummy xgettext; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_XGETTEXT+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$XGETTEXT" in +else case e in #( + e) case "$XGETTEXT" in [\\/]* | ?:[\\/]*) ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. ;; @@ -55362,15 +56667,16 @@ else $as_nop IFS="$ac_save_IFS" test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" ;; +esac ;; esac fi XGETTEXT="$ac_cv_path_XGETTEXT" if test "$XGETTEXT" != ":"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $XGETTEXT" >&5 -printf "%s\n" "$XGETTEXT" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $XGETTEXT" >&5 +printf '%s\n' "$XGETTEXT" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi rm -f messages.po @@ -55411,13 +56717,13 @@ rm -f conf$$.file # Extract the first word of "msgmerge", so it can be a program name with args. set dummy msgmerge; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_path_MSGMERGE+y} then : printf %s "(cached) " >&6 -else $as_nop - case "$MSGMERGE" in +else case e in #( + e) case "$MSGMERGE" in [\\/]* | ?:[\\/]*) ac_cv_path_MSGMERGE="$MSGMERGE" # Let the user override the test with a path. ;; @@ -55439,15 +56745,16 @@ else $as_nop IFS="$ac_save_IFS" test -z "$ac_cv_path_MSGMERGE" && ac_cv_path_MSGMERGE=":" ;; +esac ;; esac fi MSGMERGE="$ac_cv_path_MSGMERGE" if test "$MSGMERGE" != ":"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MSGMERGE" >&5 -printf "%s\n" "$MSGMERGE" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $MSGMERGE" >&5 +printf '%s\n' "$MSGMERGE" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -55484,13 +56791,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for CFPreferencesCopyAppValue" >&5 printf %s "checking for CFPreferencesCopyAppValue... " >&6; } if test ${gt_cv_func_CFPreferencesCopyAppValue+y} then : printf %s "(cached) " >&6 -else $as_nop - gt_save_LIBS="$LIBS" +else case e in #( + e) gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -55506,27 +56813,29 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gt_cv_func_CFPreferencesCopyAppValue=yes -else $as_nop - gt_cv_func_CFPreferencesCopyAppValue=no +else case e in #( + e) gt_cv_func_CFPreferencesCopyAppValue=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - LIBS="$gt_save_LIBS" + LIBS="$gt_save_LIBS" ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5 -printf "%s\n" "$gt_cv_func_CFPreferencesCopyAppValue" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFPreferencesCopyAppValue" >&5 +printf '%s\n' "$gt_cv_func_CFPreferencesCopyAppValue" >&6; } if test $gt_cv_func_CFPreferencesCopyAppValue = yes; then -printf "%s\n" "#define HAVE_CFPREFERENCESCOPYAPPVALUE 1" >>confdefs.h +printf '%s\n' "#define HAVE_CFPREFERENCESCOPYAPPVALUE 1" >>confdefs.h fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyCurrent" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for CFLocaleCopyCurrent" >&5 printf %s "checking for CFLocaleCopyCurrent... " >&6; } if test ${gt_cv_func_CFLocaleCopyCurrent+y} then : printf %s "(cached) " >&6 -else $as_nop - gt_save_LIBS="$LIBS" +else case e in #( + e) gt_save_LIBS="$LIBS" LIBS="$LIBS -Wl,-framework -Wl,CoreFoundation" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -55542,18 +56851,20 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : gt_cv_func_CFLocaleCopyCurrent=yes -else $as_nop - gt_cv_func_CFLocaleCopyCurrent=no +else case e in #( + e) gt_cv_func_CFLocaleCopyCurrent=no ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext - LIBS="$gt_save_LIBS" + LIBS="$gt_save_LIBS" ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyCurrent" >&5 -printf "%s\n" "$gt_cv_func_CFLocaleCopyCurrent" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_cv_func_CFLocaleCopyCurrent" >&5 +printf '%s\n' "$gt_cv_func_CFLocaleCopyCurrent" >&6; } if test $gt_cv_func_CFLocaleCopyCurrent = yes; then -printf "%s\n" "#define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h +printf '%s\n' "#define HAVE_CFLOCALECOPYCURRENT 1" >>confdefs.h fi INTL_MACOSX_LIBS= @@ -55598,13 +56909,13 @@ typedef int array [2 * (__GNU_GETTEXT_SUPPORTED_REVISION(0) >= 1) - 1]; gt_expression_test_code= fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libc" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libc" >&5 printf %s "checking for GNU gettext in libc... " >&6; } if eval test \${$gt_func_gnugettext_libc+y} then : printf %s "(cached) " >&6 -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -55626,15 +56937,17 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$gt_func_gnugettext_libc=yes" -else $as_nop - eval "$gt_func_gnugettext_libc=no" +else case e in #( + e) eval "$gt_func_gnugettext_libc=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ - conftest$ac_exeext conftest.$ac_ext + conftest$ac_exeext conftest.$ac_ext ;; +esac fi eval ac_res=\$$gt_func_gnugettext_libc - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" != "yes"; }; then @@ -55667,13 +56980,13 @@ printf "%s\n" "$ac_res" >&6; } done - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for iconv" >&5 printf %s "checking for iconv... " >&6; } if test ${am_cv_func_iconv+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) am_cv_func_iconv="no, consider installing GNU libiconv" am_cv_lib_iconv=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -55726,18 +57039,19 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$am_save_LIBS" fi - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 -printf "%s\n" "$am_cv_func_iconv" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv" >&5 +printf '%s\n' "$am_cv_func_iconv" >&6; } if test "$am_cv_func_iconv" = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for working iconv" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for working iconv" >&5 printf %s "checking for working iconv... " >&6; } if test ${am_cv_func_iconv_works+y} then : printf %s "(cached) " >&6 -else $as_nop - +else case e in #( + e) am_save_LIBS="$LIBS" if test $am_cv_lib_iconv = yes; then LIBS="$LIBS $LIBICONV" @@ -55750,8 +57064,8 @@ then : aix* | hpux*) am_cv_func_iconv_works="guessing no" ;; *) am_cv_func_iconv_works="guessing yes" ;; esac -else $as_nop - cat confdefs.h - <<_ACEOF >conftest.$ac_ext +else case e in #( + e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include @@ -55880,16 +57194,18 @@ then : am_cv_func_iconv_works=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext + conftest.$ac_objext conftest.beam conftest.$ac_ext ;; +esac fi test "$am_cv_func_iconv_works" = no || break done LIBS="$am_save_LIBS" - + ;; +esac fi -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv_works" >&5 -printf "%s\n" "$am_cv_func_iconv_works" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $am_cv_func_iconv_works" >&5 +printf '%s\n' "$am_cv_func_iconv_works" >&6; } case "$am_cv_func_iconv_works" in *no) am_func_iconv=no am_cv_lib_iconv=no ;; *) am_func_iconv=yes ;; @@ -55899,14 +57215,14 @@ printf "%s\n" "$am_cv_func_iconv_works" >&6; } fi if test "$am_func_iconv" = yes; then -printf "%s\n" "#define HAVE_ICONV 1" >>confdefs.h +printf '%s\n' "#define HAVE_ICONV 1" >>confdefs.h fi if test "$am_cv_lib_iconv" = yes; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to link with libiconv" >&5 printf %s "checking how to link with libiconv... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 -printf "%s\n" "$LIBICONV" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LIBICONV" >&5 +printf '%s\n' "$LIBICONV" >&6; } else CPPFLAGS="$am_save_CPPFLAGS" LIBICONV= @@ -56407,13 +57723,13 @@ fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libintl" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for GNU gettext in libintl" >&5 printf %s "checking for GNU gettext in libintl... " >&6; } if eval test \${$gt_func_gnugettext_libintl+y} then : printf %s "(cached) " >&6 -else $as_nop - gt_save_CPPFLAGS="$CPPFLAGS" +else case e in #( + e) gt_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $INCINTL" gt_save_LIBS="$LIBS" LIBS="$LIBS $LIBINTL" @@ -56443,8 +57759,9 @@ _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$gt_func_gnugettext_libintl=yes" -else $as_nop - eval "$gt_func_gnugettext_libintl=no" +else case e in #( + e) eval "$gt_func_gnugettext_libintl=no" ;; +esac fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext @@ -56484,11 +57801,12 @@ rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi CPPFLAGS="$gt_save_CPPFLAGS" - LIBS="$gt_save_LIBS" + LIBS="$gt_save_LIBS" ;; +esac fi eval ac_res=\$$gt_func_gnugettext_libintl - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -printf "%s\n" "$ac_res" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +printf '%s\n' "$ac_res" >&6; } fi if { eval "gt_val=\$$gt_func_gnugettext_libc"; test "$gt_val" = "yes"; } \ @@ -56515,19 +57833,19 @@ printf "%s\n" "$ac_res" >&6; } if test "$gt_use_preinstalled_gnugettext" = "yes" \ || test "$nls_cv_use_gnu_gettext" = "yes"; then -printf "%s\n" "#define ENABLE_NLS 1" >>confdefs.h +printf '%s\n' "#define ENABLE_NLS 1" >>confdefs.h else USE_NLS=no fi fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use NLS" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking whether to use NLS" >&5 printf %s "checking whether to use NLS... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 -printf "%s\n" "$USE_NLS" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 +printf '%s\n' "$USE_NLS" >&6; } if test "$USE_NLS" = "yes"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking where the gettext function comes from" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking where the gettext function comes from" >&5 printf %s "checking where the gettext function comes from... " >&6; } if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then @@ -56538,18 +57856,18 @@ printf %s "checking where the gettext function comes from... " >&6; } else gt_source="included intl directory" fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $gt_source" >&5 -printf "%s\n" "$gt_source" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $gt_source" >&5 +printf '%s\n' "$gt_source" >&6; } fi if test "$USE_NLS" = "yes"; then if test "$gt_use_preinstalled_gnugettext" = "yes"; then if { eval "gt_val=\$$gt_func_gnugettext_libintl"; test "$gt_val" = "yes"; }; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to link with libintl" >&5 + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking how to link with libintl" >&5 printf %s "checking how to link with libintl... " >&6; } - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LIBINTL" >&5 -printf "%s\n" "$LIBINTL" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $LIBINTL" >&5 +printf '%s\n' "$LIBINTL" >&6; } for element in $INCINTL; do haveit= @@ -56576,10 +57894,10 @@ printf "%s\n" "$LIBINTL" >&6; } fi -printf "%s\n" "#define HAVE_GETTEXT 1" >>confdefs.h +printf '%s\n' "#define HAVE_GETTEXT 1" >>confdefs.h -printf "%s\n" "#define HAVE_DCGETTEXT 1" >>confdefs.h +printf '%s\n' "#define HAVE_DCGETTEXT 1" >>confdefs.h fi @@ -56617,7 +57935,7 @@ printf "%s\n" "#define HAVE_DCGETTEXT 1" >>confdefs.h fi if test $BISON_USE_NLS = yes; then -printf "%s\n" "#define YYENABLE_NLS 1" >>confdefs.h +printf '%s\n' "#define YYENABLE_NLS 1" >>confdefs.h fi @@ -56647,13 +57965,13 @@ for ac_prog in valgrind do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_VALGRIND+y} then : printf %s "(cached) " >&6 -else $as_nop - if test -n "$VALGRIND"; then +else case e in #( + e) if test -n "$VALGRIND"; then ac_cv_prog_VALGRIND="$VALGRIND" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR @@ -56668,22 +57986,23 @@ do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_VALGRIND="$ac_prog" - printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS -fi +fi ;; +esac fi VALGRIND=$ac_cv_prog_VALGRIND if test -n "$VALGRIND"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $VALGRIND" >&5 -printf "%s\n" "$VALGRIND" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $VALGRIND" >&5 +printf '%s\n' "$VALGRIND" >&6; } else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 -printf "%s\n" "no" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf '%s\n' "no" >&6; } fi @@ -56705,10 +58024,10 @@ case $VALGRIND:$uname in fi ;; esac -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking Valgrind suppression file" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking Valgrind suppression file" >&5 printf %s "checking Valgrind suppression file... " >&6; } -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $suppfile" >&5 -printf "%s\n" "$suppfile" >&6; } +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $suppfile" >&5 +printf '%s\n' "$suppfile" >&6; } # Whether we cannot run the compiled bison. if test "$cross_compiling" = yes; then @@ -56757,50 +58076,13 @@ cat >confcache <<\_ACEOF # 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 overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the +# 'ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* 'ac_cv_foo' will be assigned the # following values. _ACEOF -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | +ac_cache_dump | sed ' /^ac_cv_env_/b end t clear @@ -56812,8 +58094,8 @@ printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -printf "%s\n" "$as_me: updating cache $cache_file" >&6;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf '%s\n' "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else @@ -56827,8 +58109,8 @@ printf "%s\n" "$as_me: updating cache $cache_file" >&6;} fi fi else - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf '%s\n' "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -56845,7 +58127,7 @@ U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` + ac_i=`printf '%s\n' "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" @@ -56856,14 +58138,14 @@ LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 printf %s "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 -printf "%s\n" "done" >&6; } + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: done" >&5 +printf '%s\n' "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' @@ -57274,13 +58556,21 @@ fi : "${CONFIG_STATUS=./config.status}" +case $CONFIG_STATUS in #( + -*) : + CONFIG_STATUS=./$CONFIG_STATUS ;; #( + */*) : + ;; #( + *) : + CONFIG_STATUS=./$CONFIG_STATUS ;; +esac + ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} +ac_clean_CONFIG_STATUS='"$CONFIG_STATUS"' +{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf '%s\n' "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +cat >"$CONFIG_STATUS" <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. @@ -57294,28 +58584,28 @@ ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +cat >>"$CONFIG_STATUS" <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. + # contradicts POSIX and common usage. Disable this. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST -else $as_nop - case `(set -o) 2>/dev/null` in #( +else case e in #( + e) case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; +esac ;; esac fi @@ -57387,13 +58677,13 @@ IFS=$as_save_IFS ;; esac -# We did not find ourselves, most probably we were run as `sh COMMAND' +# We did not find ourselves, most probably we were run as 'sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then - printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + printf '%s\n' "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi @@ -57409,14 +58699,13 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - printf "%s\n" "$as_me: error: $2" >&2 + printf '%s\n' "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error - # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -57456,11 +58745,12 @@ then : { eval $1+=\$2 }' -else $as_nop - as_fn_append () +else case e in #( + e) as_fn_append () { eval $1=\$$1\$2 - } + } ;; +esac fi # as_fn_append # as_fn_arith ARG... @@ -57474,11 +58764,12 @@ then : { as_val=$(( $* )) }' -else $as_nop - as_fn_arith () +else case e in #( + e) as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` - } + } ;; +esac fi # as_fn_arith @@ -57505,7 +58796,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X/"$0" | +printf '%s\n' X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -57527,29 +58818,6 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits - -# Determine whether it's possible to make 'echo' print without a newline. -# These variables are no longer used directly by Autoconf, but are AC_SUBSTed -# for compatibility with existing Makefiles. -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -# For backward compatibility with old third-party macros, we provide -# the shell variables $as_echo and $as_echo_n. New code should use -# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. -as_echo='printf %s\n' -as_echo_n='printf %s' - rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -57561,9 +58829,9 @@ if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -pR'. + # 1) On MSYS, both 'ln -s file dir' and 'ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; 'ln -s' creates a wrapper executable. + # In both cases, we have to default to 'cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then @@ -57591,7 +58859,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf '%s\n' "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -57600,7 +58868,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$as_dir" | +printf '%s\n' X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -57644,26 +58912,28 @@ as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" +as_sed_cpp="y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g" +as_tr_cpp="eval sed '$as_sed_cpp'" # deprecated # Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" +as_sed_sh="y%*+%pp%;s%[^_$as_cr_alnum]%_%g" +as_tr_sh="eval sed '$as_sed_sh'" # deprecated exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## +## ------------------------------------- ## +## Main body of "$CONFIG_STATUS" script. ## +## ------------------------------------- ## _ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 +test $as_write_fail = 0 && chmod +x "$CONFIG_STATUS" || ac_write_fail=1 -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by GNU Bison $as_me 3.8.2, which was -generated by GNU Autoconf 2.71. Invocation command line was +generated by GNU Autoconf 2.73. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -57685,7 +58955,7 @@ case $ac_config_headers in *" esac -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" @@ -57694,9 +58964,9 @@ config_commands="$ac_config_commands" _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions +'$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. @@ -57731,16 +59001,16 @@ GNU Bison home page: . General help using GNU software: ." _ACEOF -ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` -ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config=`printf '%s\n' "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` +cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ GNU Bison config.status 3.8.2 -configured by $0, generated by GNU Autoconf 2.71, +configured by $0, generated by GNU Autoconf 2.73, with options \\"\$ac_cs_config\\" -Copyright (C) 2021 Free Software Foundation, Inc. +Copyright (C) 2026 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -57749,10 +59019,14 @@ srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' -test -n "\$AWK" || AWK=awk +test -n "\$AWK" || { + awk '' >$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 @@ -57780,15 +59054,15 @@ do -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - printf "%s\n" "$ac_cs_version"; exit ;; + printf '%s\n' "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - printf "%s\n" "$ac_cs_config"; exit ;; + printf '%s\n' "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" @@ -57796,23 +59070,23 @@ do --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in - *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + *\'*) ac_optarg=`printf '%s\n' "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; + as_fn_error $? "ambiguous option: '$1' +Try '$0 --help' for more information.";; --help | --hel | -h ) - printf "%s\n" "$ac_cs_usage"; exit ;; + printf '%s\n' "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; + -*) as_fn_error $? "unrecognized option: '$1' +Try '$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; @@ -57829,29 +59103,29 @@ if $ac_cs_silent; then fi _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift - \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 + \printf '%s\n' "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - printf "%s\n" "$ac_log" + printf '%s\n' "$ac_log" } >&5 _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # @@ -57869,7 +59143,7 @@ ac_cv_exeext="$ac_cv_exeext" _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets @@ -57892,7 +59166,7 @@ do "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;; "doc/yacc.1") CONFIG_FILES="$CONFIG_FILES doc/yacc.1" ;; - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + *) as_fn_error $? "invalid argument: '$ac_config_target'" "$LINENO" 5;; esac done @@ -57913,7 +59187,7 @@ fi # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. +# after its creation but before its name has been assigned to '$tmp'. $debug || { tmp= ac_tmp= @@ -57937,7 +59211,7 @@ ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. +# This happens for instance with './config.status config.h'. if test -n "$CONFIG_FILES"; then if $AWK 'BEGIN { getline <"/dev/null" }' /dev/null; then @@ -57955,7 +59229,7 @@ else print "|#_!!_#|" print "cat " F[key] " &&" '$ac_cs_awk_pipe_init - # The final `:' finishes the AND list. + # The final ':' finishes the AND list. ac_cs_awk_pipe_fini='END { print "|#_!!_#|"; print ":" }' fi ac_cr=`echo X | tr X '\015'` @@ -57977,9 +59251,9 @@ _ACEOF # Create commands to substitute file output variables. { - echo "cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1" && - echo 'cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&' && - echo "$ac_subst_files" | sed 's/.*/F["&"]="$&"/' && + echo 'cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1' && + printf '%s\n' 'cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&' && + printf '%s\n' "$ac_subst_files" | sed 's/.*/F["&"]="$&"/' && echo "_ACAWK" && echo "_ACEOF" } >conf$$files.sh && @@ -57993,13 +59267,13 @@ rm -f conf$$files.sh echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim_num=`echo "$ac_subst_vars" | sed -n '$='` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | sed -n '$='` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then @@ -58010,7 +59284,7 @@ for ac_last_try in false false false false false :; do done rm -f conf$$subs.sh -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' @@ -58055,9 +59329,9 @@ t delim N s/\n// } -' >>$CONFIG_STATUS || ac_write_fail=1 +' >>"$CONFIG_STATUS" || ac_write_fail=1 rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 @@ -58092,7 +59366,7 @@ cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && \$ac_cs_awk_pipe_fini _ACAWK _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else @@ -58124,18 +59398,18 @@ s/^[^=]*=[ ]*$// }' fi -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. +# This happens for instance with './config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF -# Transform confdefs.h into an awk script `defines.awk', embedded as +# Transform confdefs.h into an awk script 'defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. @@ -58195,9 +59469,9 @@ s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 +"/g' >>"$CONFIG_STATUS" || ac_write_fail=1 -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } @@ -58215,8 +59489,12 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { + suffix = P[macro] D[macro] + while (suffix ~ /[\t ]$/) { + suffix = substr(suffix, 1, length(suffix) - 1) + } # Preserve the white space surrounding the "#". - print prefix "define", macro P[macro] D[macro] + print prefix "define", macro suffix next } else { # Replace #undef with comments. This is necessary, for example, @@ -58231,7 +59509,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 { print } _ACAWK _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" @@ -58245,7 +59523,7 @@ do esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :L* | :C*:*) as_fn_error $? "invalid tag '$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -58267,33 +59545,33 @@ do -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. + # because $ac_f cannot contain ':'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + as_fn_error 1 "cannot find input file: '$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf '%s\n' "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done - # Let's still pretend it is `configure' which instantiates (i.e., don't + # Let's still pretend it is 'configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` - printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + printf '%s\n' "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -printf "%s\n" "$as_me: creating $ac_file" >&6;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf '%s\n' "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) - ac_sed_conf_input=`printf "%s\n" "$configure_input" | + ac_sed_conf_input=`printf '%s\n' "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -58310,7 +59588,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$ac_file" | +printf '%s\n' X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -58334,9 +59612,9 @@ printf "%s\n" X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf '%s\n' "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + ac_top_builddir_sub=`printf '%s\n' "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; @@ -58381,7 +59659,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix esac _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= @@ -58398,10 +59676,10 @@ ac_sed_dataroot=' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf '%s\n' "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g @@ -58412,14 +59690,14 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 esac _ACEOF -# Neutralize VPATH when `$srcdir' = `.'. +# Neutralize VPATH when '$srcdir' = '.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t @@ -58448,9 +59726,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&5 -printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +printf '%s\n' "$as_me: WARNING: $ac_file contains a reference to the variable 'datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" @@ -58466,20 +59744,20 @@ which seems to be undefined. Please make sure it is defined" >&2;} # if test x"$ac_file" != x-; then { - printf "%s\n" "/* $configure_input */" >&1 \ + printf '%s\n' "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -printf "%s\n" "$as_me: $ac_file is unchanged" >&6;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +printf '%s\n' "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else - printf "%s\n" "/* $configure_input */" >&1 \ + printf '%s\n' "/* $configure_input */" >&1 \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi @@ -58499,7 +59777,7 @@ $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$_am_arg" | +printf '%s\n' X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -58531,8 +59809,8 @@ printf "%s\n" X"$_am_arg" | ac_source=$srcdir/$ac_source fi - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: linking $ac_source to $ac_file" >&5 -printf "%s\n" "$as_me: linking $ac_source to $ac_file" >&6;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: linking $ac_source to $ac_file" >&5 +printf '%s\n' "$as_me: linking $ac_source to $ac_file" >&6;} if test ! -r "$ac_source"; then as_fn_error $? "$ac_source: file not found" "$LINENO" 5 @@ -58550,8 +59828,8 @@ printf "%s\n" "$as_me: linking $ac_source to $ac_file" >&6;} as_fn_error $? "cannot link or copy $ac_source to $ac_file" "$LINENO" 5 fi ;; - :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -printf "%s\n" "$as_me: executing $ac_file commands" >&6;} + :C) { printf '%s\n' "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +printf '%s\n' "$as_me: executing $ac_file commands" >&6;} ;; esac @@ -58577,7 +59855,7 @@ esac for am_mf do # Strip MF so we end up with the name of the file. - am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` + am_mf=`printf '%s\n' "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line @@ -58589,7 +59867,7 @@ $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X"$am_mf" | +printf '%s\n' X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -58611,7 +59889,7 @@ printf "%s\n" X"$am_mf" | $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || -printf "%s\n" X/"$am_mf" | +printf '%s\n' X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -58636,15 +59914,15 @@ printf "%s\n" X/"$am_mf" | (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then - { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { { printf '%s\n' "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5 +printf '%s\n' "$as_me: error: in '$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). -See \`config.log' for more details" "$LINENO" 5; } +See 'config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} @@ -58772,7 +60050,7 @@ See \`config.log' for more details" "$LINENO" 5; } "tests/atconfig":C) cat >tests/atconfig </dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + $SHELL $ac_no_opts "$CONFIG_STATUS" $ac_config_status_args || + ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} + { printf '%s\n' "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf '%s\n' "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi diff --git a/local/recipes/dev/bison/source/doc/bison.info b/local/recipes/dev/bison/source/doc/bison.info index 4f4fb08267..fea740eb9e 100644 --- a/local/recipes/dev/bison/source/doc/bison.info +++ b/local/recipes/dev/bison/source/doc/bison.info @@ -1,22 +1,22 @@ -This is bison.info, produced by makeinfo version 6.8 from bison.texi. +This is bison.info, produced by makeinfo version 7.3 from bison.texi. -This manual (12 September 2021) is for GNU Bison (version 3.8.2), the -GNU parser generator. +This manual (15 May 2026) is for GNU Bison (version 3.8.2), the GNU +parser generator. - Copyright © 1988–1993, 1995, 1998–2015, 2018–2021 Free Software + Copyright © 1988-1993, 1995, 1998-2015, 2018-2021 Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover texts - being “A GNU Manual,” and with the Back-Cover Texts as in (a) + being "A GNU Manual," and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled - “GNU Free Documentation License.” + "GNU Free Documentation License." - (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and + (a) The FSF's Back-Cover Text is: "You have the freedom to copy and modify this GNU manual. Buying copies from the FSF supports it in - developing GNU and promoting software freedom.” + developing GNU and promoting software freedom." INFO-DIR-SECTION Software development START-INFO-DIR-ENTRY * bison: (bison). GNU parser generator (Yacc replacement). @@ -28,23 +28,23 @@ File: bison.info, Node: Top, Next: Introduction, Up: (dir) Bison ***** -This manual (12 September 2021) is for GNU Bison (version 3.8.2), the -GNU parser generator. +This manual (15 May 2026) is for GNU Bison (version 3.8.2), the GNU +parser generator. - Copyright © 1988–1993, 1995, 1998–2015, 2018–2021 Free Software + Copyright © 1988-1993, 1995, 1998-2015, 2018-2021 Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover texts - being “A GNU Manual,” and with the Back-Cover Texts as in (a) + being "A GNU Manual," and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled - “GNU Free Documentation License.” + "GNU Free Documentation License." - (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and + (a) The FSF's Back-Cover Text is: "You have the freedom to copy and modify this GNU manual. Buying copies from the FSF supports it in - developing GNU and promoting software freedom.” + developing GNU and promoting software freedom." * Menu: @@ -76,20 +76,20 @@ Reference sections: * Bibliography:: Publications cited in this manual. * Index of Terms:: Cross-references to the text. - — The Detailed Node Listing — + -- The Detailed Node Listing -- The Concepts of Bison * Language and Grammar:: Languages and context-free grammars, as mathematical ideas. -* Grammar in Bison:: How we represent grammars for Bison’s sake. +* Grammar in Bison:: How we represent grammars for Bison's sake. * Semantic Values:: Each token or syntactic grouping can have a semantic value (the value of an integer, the name of an identifier, etc.). * Semantic Actions:: Each rule can have an action containing C code. * GLR Parsers:: Writing parsers for general context-free languages. * Locations:: Overview of location tracking. -* Bison Parser:: What are Bison’s input and output, +* Bison Parser:: What are Bison's input and output, how is the output used? * Stages:: Stages in writing and running Bison grammars. * Grammar Layout:: Overall structure of a Bison grammar file. @@ -211,7 +211,7 @@ Bison Declarations * Pure Decl:: Requesting a reentrant parser. * Push Decl:: Requesting a push parser. * Decl Summary:: Table of all Bison declarations. -* %define Summary:: Defining variables to adjust Bison’s behavior. +* %define Summary:: Defining variables to adjust Bison's behavior. * %code Summary:: Inserting code into the parser source. Parser C-Language Interface @@ -222,7 +222,7 @@ Parser C-Language Interface which reads tokens. * Error Reporting:: Passing error messages to the user. * Action Features:: Special features for use in actions. -* Internationalization:: How to let the parser speak in the user’s +* Internationalization:: How to let the parser speak in the user's native language. The Lexical Analyzer Function ‘yylex’ @@ -253,7 +253,7 @@ The Bison Parser Algorithm * Lookahead:: Parser looks one token ahead when deciding what to do. * Shift/Reduce:: Conflicts: when either shifting or reduction is valid. * Precedence:: Operator precedence works by resolving conflicts. -* Contextual Precedence:: When an operator’s precedence depends on context. +* Contextual Precedence:: When an operator's precedence depends on context. * Parser States:: The parser is a finite-state-machine with stack. * Reduce/Reduce:: When two rules are applicable in the same situation. * Mysterious Conflicts:: Conflicts that look unjustified. @@ -401,7 +401,6 @@ Copying This Manual * GNU Free Documentation License:: Copying and sharing this manual -  File: bison.info, Node: Introduction, Next: Conditions, Prev: Top, Up: Top @@ -423,7 +422,7 @@ understand this manual. We begin with tutorial chapters that explain the basic concepts of using Bison and show three explained examples, each building on the -last. If you don’t know Bison or Yacc, start by reading these chapters. +last. If you don't know Bison or Yacc, start by reading these chapters. Reference chapters follow, which describe specific aspects of Bison in detail. @@ -454,24 +453,24 @@ software. The reason Bison was different was not due to a special policy decision; it resulted from applying the usual General Public License to all of the Bison source code. - The main output of the Bison utility—the Bison parser implementation -file—contains a verbatim copy of a sizable piece of Bison, which is the -code for the parser’s implementation. (The actions from your grammar + The main output of the Bison utility--the Bison parser implementation +file--contains a verbatim copy of a sizable piece of Bison, which is the +code for the parser's implementation. (The actions from your grammar are inserted into this implementation at one point, but most of the rest of the implementation is not changed.) When we applied the GPL terms to -the skeleton code for the parser’s implementation, the effect was to +the skeleton code for the parser's implementation, the effect was to restrict the use of Bison output to free software. - We didn’t change the terms because of sympathy for people who want to + We didn't change the terms because of sympathy for people who want to make software proprietary. *Software should be free.* But we concluded -that limiting Bison’s use to free software was doing little to encourage +that limiting Bison's use to free software was doing little to encourage people to make other software free. So we decided to make the practical conditions for using Bison match the practical conditions for using the other GNU tools. This exception applies when Bison is generating code for a parser. You can tell whether the exception applies to a Bison output file by -inspecting the file for text beginning with “As a special exception...”. +inspecting the file for text beginning with "As a special exception...". The text spells out the exact terms of the exception.  @@ -496,7 +495,7 @@ and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program—to make sure it remains free +share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to @@ -524,16 +523,16 @@ know their rights. (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. - For the developers’ and authors’ protection, the GPL clearly explains -that there is no warranty for this free software. For both users’ and -authors’ sake, the GPL requires that modified versions be marked as + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of -protecting users’ freedom to change the software. The systematic +protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those @@ -556,25 +555,25 @@ TERMS AND CONDITIONS 0. Definitions. - “This License” refers to version 3 of the GNU General Public + "This License" refers to version 3 of the GNU General Public License. - “Copyright” also means copyright-like laws that apply to other + "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - “The Program” refers to any copyrightable work licensed under this - License. Each licensee is addressed as “you”. “Licensees” and - “recipients” may be individuals or organizations. + "The Program" refers to any copyrightable work licensed under this + License. Each licensee is addressed as "you". "Licensees" and + "recipients" may be individuals or organizations. - To “modify” a work means to copy from or adapt all or part of the + To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the - making of an exact copy. The resulting work is called a “modified - version” of the earlier work or a work “based on” the earlier work. + making of an exact copy. The resulting work is called a "modified + version" of the earlier work or a work "based on" the earlier work. - A “covered work” means either the unmodified Program or a work + A "covered work" means either the unmodified Program or a work based on the Program. - To “propagate” a work means to do anything with it that, without + To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes @@ -582,12 +581,12 @@ TERMS AND CONDITIONS available to the public, and in some countries other activities as well. - To “convey” a work means any kind of propagation that enables other + To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. - An interactive user interface displays “Appropriate Legal Notices” + An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to @@ -599,33 +598,33 @@ TERMS AND CONDITIONS 1. Source Code. - The “source code” for a work means the preferred form of the work - for making modifications to it. “Object code” means any non-source + The "source code" for a work means the preferred form of the work + for making modifications to it. "Object code" means any non-source form of a work. - A “Standard Interface” means an interface that either is an + A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - The “System Libraries” of an executable work include anything, + The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code - form. A “Major Component”, in this context, means a major + form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - The “Corresponding Source” for a work in object code form means all + The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the - work’s System Libraries, or general-purpose tools or generally + work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated @@ -669,7 +668,7 @@ TERMS AND CONDITIONS the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - 3. Protecting Users’ Legal Rights From Anti-Circumvention Law. + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under @@ -682,12 +681,12 @@ TERMS AND CONDITIONS circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of - enforcing, against the work’s users, your or third parties’ legal + enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. - You may convey verbatim copies of the Program’s source code as you + You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any @@ -711,7 +710,7 @@ TERMS AND CONDITIONS b. The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in - section 4 to “keep intact all notices”. + section 4 to "keep intact all notices". c. You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This @@ -731,9 +730,9 @@ TERMS AND CONDITIONS works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is - called an “aggregate” if the compilation and its resulting + called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the - compilation’s users beyond what the individual works permit. + compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. @@ -791,13 +790,13 @@ TERMS AND CONDITIONS excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. - A “User Product” is either (1) a “consumer product”, which means + A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, - “normally used” refers to a typical or common use of that class of + "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product @@ -805,7 +804,7 @@ TERMS AND CONDITIONS industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. - “Installation Information” for a User Product means any methods, + "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. @@ -841,7 +840,7 @@ TERMS AND CONDITIONS 7. Additional Terms. - “Additional permissions” are terms that supplement the terms of + "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in @@ -886,8 +885,8 @@ TERMS AND CONDITIONS the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. - All other non-permissive additional terms are considered “further - restrictions” within the meaning of section 10. If the Program as + All other non-permissive additional terms are considered "further + restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document @@ -953,12 +952,12 @@ TERMS AND CONDITIONS responsible for enforcing compliance by third parties with this License. - An “entity transaction” is a transaction transferring control of an + An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever - licenses to the work the party’s predecessor in interest had or + licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable @@ -975,31 +974,31 @@ TERMS AND CONDITIONS 11. Patents. - A “contributor” is a copyright holder who authorizes use under this + A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. - The work thus licensed is called the contributor’s “contributor - version”. + The work thus licensed is called the contributor's "contributor + version". - A contributor’s “essential patent claims” are all patent claims + A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the - contributor version. For purposes of this definition, “control” + contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, - royalty-free patent license under the contributor’s essential + royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - In the following three paragraphs, a “patent license” is any + In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a - patent or covenant not to sue for patent infringement). To “grant” + patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. @@ -1012,9 +1011,9 @@ TERMS AND CONDITIONS yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream - recipients. “Knowingly relying” means you have actual knowledge + recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work - in a country, or your recipient’s use of the covered work in a + in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. @@ -1026,7 +1025,7 @@ TERMS AND CONDITIONS patent license you grant is automatically extended to all recipients of the covered work and works based on it. - A patent license is “discriminatory” if it does not include within + A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a @@ -1046,7 +1045,7 @@ TERMS AND CONDITIONS any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. - 12. No Surrender of Others’ Freedom. + 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they @@ -1079,7 +1078,7 @@ TERMS AND CONDITIONS Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU - General Public License “or any later version” applies to it, you + General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version @@ -1088,7 +1087,7 @@ TERMS AND CONDITIONS If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that - proxy’s public statement of acceptance of a version permanently + proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different @@ -1100,7 +1099,7 @@ TERMS AND CONDITIONS THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE - COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” + COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE @@ -1144,7 +1143,7 @@ terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the -“copyright” line and a pointer to where the full notice is found. +"copyright" line and a pointer to where the full notice is found. ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. Copyright (C) YEAR NAME OF AUTHOR @@ -1175,11 +1174,11 @@ notice like this when it starts in an interactive mode: The hypothetical commands ‘show w’ and ‘show c’ should show the appropriate parts of the General Public License. Of course, your -program’s commands might be different; for a GUI interface, you would -use an “about box”. +program's commands might be different; for a GUI interface, you would +use an "about box". You should also get your employer (if you work as a programmer) or -school, if any, to sign a “copyright disclaimer” for the program, if +school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . @@ -1205,14 +1204,14 @@ carefully. * Language and Grammar:: Languages and context-free grammars, as mathematical ideas. -* Grammar in Bison:: How we represent grammars for Bison’s sake. +* Grammar in Bison:: How we represent grammars for Bison's sake. * Semantic Values:: Each token or syntactic grouping can have a semantic value (the value of an integer, the name of an identifier, etc.). * Semantic Actions:: Each rule can have an action containing C code. * GLR Parsers:: Writing parsers for general context-free languages. * Locations:: Overview of location tracking. -* Bison Parser:: What are Bison’s input and output, +* Bison Parser:: What are Bison's input and output, how is the output used? * Stages:: Stages in writing and running Bison grammars. * Grammar Layout:: Overall structure of a Bison grammar file. @@ -1227,14 +1226,14 @@ In order for Bison to parse a language, it must be described by a “context-free grammar”. This means that you specify one or more “syntactic groupings” and give rules for constructing them from their parts. For example, in the C language, one kind of grouping is called -an ‘expression’. One rule for making an expression might be, “An -expression can be made of a minus sign and another expression”. Another -would be, “An expression can be an integer”. As you can see, rules are +an 'expression'. One rule for making an expression might be, "An +expression can be made of a minus sign and another expression". Another +would be, "An expression can be an integer". As you can see, rules are often recursive, but there must be at least one rule which leads out of the recursion. The most common formal system for presenting such rules for humans to -read is “Backus-Naur Form” or “BNF”, which was developed in order to +read is “Backus-Naur Form” or "BNF", which was developed in order to specify the language Algol 60. Any grammar expressed in BNF is a context-free grammar. The input to Bison is essentially machine-readable BNF. @@ -1259,14 +1258,14 @@ rules to get the same inputs. Even unambiguous grammars can be “nondeterministic”, meaning that no fixed lookahead always suffices to determine the next grammar rule to apply. With the proper declarations, Bison is also able to parse these more general context-free grammars, -using a technique known as GLR parsing (for Generalized LR). Bison’s GLR +using a technique known as GLR parsing (for Generalized LR). Bison's GLR parsers are able to handle any context-free grammar for which the number of possible parses of any given string is finite. In the formal grammatical rules for a language, each kind of syntactic unit or grouping is named by a “symbol”. Those which are built by grouping smaller constructs according to grammatical rules are -called “nonterminal symbols”; those which can’t be subdivided are called +called “nonterminal symbols”; those which can't be subdivided are called “terminal symbols” or “token kinds”. We call a piece of input corresponding to a single terminal symbol a “token”, and a piece corresponding to a single nonterminal symbol a “grouping”. @@ -1275,26 +1274,26 @@ corresponding to a single nonterminal symbol a “grouping”. nonterminal, mean. The tokens of C are identifiers, constants (numeric and string), and the various keywords, arithmetic operators and punctuation marks. So the terminal symbols of a grammar for C include -‘identifier’, ‘number’, ‘string’, plus one symbol for each keyword, -operator or punctuation mark: ‘if’, ‘return’, ‘const’, ‘static’, ‘int’, -‘char’, ‘plus-sign’, ‘open-brace’, ‘close-brace’, ‘comma’ and many more. +'identifier', 'number', 'string', plus one symbol for each keyword, +operator or punctuation mark: 'if', 'return', 'const', 'static', 'int', +'char', 'plus-sign', 'open-brace', 'close-brace', 'comma' and many more. (These tokens can be subdivided into characters, but that is a matter of lexicography, not grammar.) Here is a simple C function subdivided into tokens: - int /* keyword ‘int’ */ - square (int x) /* identifier, open-paren, keyword ‘int’, + int /* keyword 'int' */ + square (int x) /* identifier, open-paren, keyword 'int', identifier, close-paren */ { /* open-brace */ - return x * x; /* keyword ‘return’, identifier, asterisk, + return x * x; /* keyword 'return', identifier, asterisk, identifier, semicolon */ } /* close-brace */ The syntactic groupings of C include the expression, the statement, the declaration, and the function definition. These are represented in -the grammar of C by nonterminal symbols ‘expression’, ‘statement’, -‘declaration’ and ‘function definition’. The full grammar uses dozens +the grammar of C by nonterminal symbols 'expression', 'statement', +'declaration' and 'function definition'. The full grammar uses dozens of additional language constructs, each with its own nonterminal symbol, in order to express the meanings of these four. The example above is a function definition; it contains one declaration, and one statement. In @@ -1305,28 +1304,28 @@ made out of simpler constructs. For example, one kind of C statement is the ‘return’ statement; this would be described with a grammar rule which reads informally as follows: - A ‘statement’ can be made of a ‘return’ keyword, an ‘expression’ - and a ‘semicolon’. + A 'statement' can be made of a 'return' keyword, an 'expression' + and a 'semicolon'. -There would be many other rules for ‘statement’, one for each kind of +There would be many other rules for 'statement', one for each kind of statement in C. One nonterminal symbol must be distinguished as the special one which defines a complete utterance in the language. It is called the “start symbol”. In a compiler, this means a complete input program. In the C -language, the nonterminal symbol ‘sequence of definitions and -declarations’ plays this role. +language, the nonterminal symbol 'sequence of definitions and +declarations' plays this role. - For example, ‘1 + 2’ is a valid C expression—a valid part of a C -program—but it is not valid as an _entire_ C program. In the -context-free grammar of C, this follows from the fact that ‘expression’ + For example, ‘1 + 2’ is a valid C expression--a valid part of a C +program--but it is not valid as an _entire_ C program. In the +context-free grammar of C, this follows from the fact that 'expression' is not the start symbol. The Bison parser reads a sequence of tokens as its input, and groups the tokens using the grammar rules. If the input is valid, the end result is that the entire token sequence reduces to a single grouping -whose symbol is the grammar’s start symbol. If we use a grammar for C, -the entire input must be a ‘sequence of definitions and declarations’. +whose symbol is the grammar's start symbol. If we use a grammar for C, +the entire input must be a 'sequence of definitions and declarations'. If not, the parser reports a syntax error.  @@ -1378,7 +1377,7 @@ File: bison.info, Node: Semantic Values, Next: Semantic Actions, Prev: Gramma =================== A formal grammar selects tokens only by their classifications: for -example, if a rule mentions the terminal symbol ‘integer constant’, it +example, if a rule mentions the terminal symbol 'integer constant', it means that _any_ integer constant is grammatically valid in that position. The precise value of the constant is irrelevant to how to parse the input: if ‘x+4’ is grammatical then ‘x+1’ or ‘x+3989’ is @@ -1398,7 +1397,7 @@ kinds. The semantic value has all the rest of the information about the meaning of the token, such as the value of an integer, or the name of an -identifier. (A token such as ‘','’ which is just punctuation doesn’t +identifier. (A token such as ‘','’ which is just punctuation doesn't need to have any semantic value.) For example, an input token might be classified as token kind @@ -1406,7 +1405,7 @@ need to have any semantic value.) the same token kind ‘INTEGER’ but value 3989. When a grammar rule says that ‘INTEGER’ is allowed, either of these tokens is acceptable because each is an ‘INTEGER’. When the parser accepts the token, it keeps track -of the token’s semantic value. +of the token's semantic value. Each grouping can also have a semantic value as well as its nonterminal symbol. For example, in a calculator, an expression @@ -1448,7 +1447,7 @@ File: bison.info, Node: GLR Parsers, Next: Locations, Prev: Semantic Actions, 1.5 Writing GLR Parsers ======================= -In some grammars, Bison’s deterministic LR(1) parsing algorithm cannot +In some grammars, Bison's deterministic LR(1) parsing algorithm cannot decide whether to apply a certain grammar rule at a given point. That is, it may not be able to decide (on the basis of the input read so far) which of two possible reductions (applications of a grammar rule) @@ -1534,7 +1533,7 @@ become a new identifier to represent the enumeration value, while in the former case ‘a’ must be evaluated with its current meaning, which may be a constant or even a function call. - You could parse ‘(a)’ as an “unspecified identifier in parentheses”, + You could parse ‘(a)’ as an "unspecified identifier in parentheses", to be resolved later, but this typically requires substantial contortions in both semantic actions and large parts of the grammar, where the parentheses are nested in the recursive rules for expressions. @@ -1542,7 +1541,7 @@ where the parentheses are nested in the recursive rules for expressions. You might think of using the lexer to distinguish between the two forms by returning different tokens for currently defined and undefined identifiers. But if these declarations occur in a local scope, and ‘a’ -is defined in an outer scope, then both forms are possible—either +is defined in an outer scope, then both forms are possible--either locally redefining ‘a’, or using the value of ‘a’ from the outer scope. So this approach cannot work. @@ -1560,7 +1559,7 @@ split. If the input is syntactically incorrect, both branches fail and the parser reports a syntax error as usual. - The effect of all this is that the parser seems to “guess” the + The effect of all this is that the parser seems to "guess" the correct branch to take, or in other words, it seems to use more lookahead than the underlying LR(1) algorithm actually allows for. In this example, LR(2) would suffice, but also some cases that are not @@ -1652,7 +1651,7 @@ File: bison.info, Node: Merging GLR Parses, Next: GLR Semantic Actions, Prev: 1.5.2 Using GLR to Resolve Ambiguities -------------------------------------- -Let’s consider an example, vastly simplified from a C++ grammar.(1) +Let's consider an example, vastly simplified from a C++ grammar.(1) %{ #include @@ -1701,7 +1700,7 @@ Let’s consider an example, vastly simplified from a C++ grammar.(1) | '(' declarator ')' ; -This models a problematic part of the C++ grammar—the ambiguity between +This models a problematic part of the C++ grammar--the ambiguity between certain declarations and statements. For example, T (x) = y+z; @@ -1713,10 +1712,10 @@ ID’, which it cannot resolve at the time it encounters ‘x’ in the example above. Since this is a GLR parser, it therefore splits the problem into two parses, one for each choice of resolving the reduce/reduce conflict. Unlike the example from the previous section -(*note Simple GLR Parsers::), however, neither of these parses “dies,” +(*note Simple GLR Parsers::), however, neither of these parses "dies," because the grammar as it stands is ambiguous. One of the parsers eventually reduces ‘stmt : expr ';'’ and the other reduces ‘stmt : -decl’, after which both parsers are in an identical state: they’ve seen +decl’, after which both parsers are in an identical state: they've seen ‘prog stmt’ and have the same unprocessed input remaining. We say that these parses have “merged.” @@ -1834,11 +1833,11 @@ features you might use in a semantic action in a GLR parser. kind of the lookahead token present at the time of the associated reduction. After checking that ‘yychar’ is not set to ‘YYEMPTY’ or ‘YYEOF’, you can then examine ‘yylval’ and ‘yylloc’ to determine the -lookahead token’s semantic value and location, if any. In a nondeferred +lookahead token's semantic value and location, if any. In a nondeferred semantic action, you can also modify any of these variables to influence syntax analysis. *Note Lookahead::. - In a deferred semantic action, it’s too late to influence syntax + In a deferred semantic action, it's too late to influence syntax analysis. In this case, ‘yychar’, ‘yylval’, and ‘yylloc’ are set to shallow copies of the values they had at the time of the associated reduction. For this reason alone, modifying them is dangerous. @@ -1967,14 +1966,14 @@ distinct programs: the Bison utility is a program whose output is the Bison parser implementation file that becomes part of your program. The job of the Bison parser is to group tokens into groupings -according to the grammar rules—for example, to build identifiers and +according to the grammar rules--for example, to build identifiers and operators into expressions. As it does this, it runs the actions for the grammar rules it uses. The tokens come from a function called the “lexical analyzer” that you must supply in some fashion (such as by writing it in C). The Bison parser calls the lexical analyzer each time it wants a new token. It -doesn’t know what is “inside” the tokens (though their semantic values +doesn't know what is "inside" the tokens (though their semantic values may reflect this). Typically the lexical analyzer makes the tokens by parsing characters of text, but Bison does not depend on this. *Note Lexical::. @@ -2092,9 +2091,9 @@ File: bison.info, Node: Examples, Next: Grammar File, Prev: Concepts, Up: To Now we show and explain several sample programs written using Bison: a Reverse Polish Notation calculator, an algebraic (infix) notation -calculator — later extended to track “locations” — and a multi-function -calculator. All produce usable, though limited, interactive desk-top -calculators. +calculator -- later extended to track "locations" -- and a +multi-function calculator. All produce usable, though limited, +interactive desk-top calculators. These examples are simple, but Bison grammars for real programming languages are written the same way. You can copy these examples into a @@ -2188,13 +2187,13 @@ about the tokens and their types (*note Bison Declarations::). The ‘%define’ directive defines the variable ‘api.value.type’, thus specifying the C data type for semantic values of both tokens and groupings (*note Value Type::). The Bison parser will use whatever type -‘api.value.type’ is defined as; if you don’t define it, ‘int’ is the +‘api.value.type’ is defined as; if you don't define it, ‘int’ is the default. Because we specify ‘{double}’, each token and each expression has an associated value, which is a floating point number. C code can use ‘YYSTYPE’ to refer to the value ‘api.value.type’. Each terminal symbol that is not a single-character literal must be -declared. (Single-character literals normally don’t need to be +declared. (Single-character literals normally don't need to be declared.) In this example, all the arithmetic operators are designated by single-character literals, so the only terminal symbol that needs to be declared is ‘NUM’, the token kind for numeric constants. @@ -2228,11 +2227,11 @@ Here are the grammar rules for the Reverse Polish Notation calculator. ; %% - The groupings of the rpcalc “language” defined here are the + The groupings of the rpcalc "language" defined here are the expression (given the name ‘exp’), the line of input (‘line’), and the complete input transcript (‘input’). Each of these nonterminal symbols has several alternate rules, joined by the vertical bar ‘|’ which is -read as “or”. The following sections explain what these rules mean. +read as "or". The following sections explain what these rules mean. The semantics of the language is determined by the actions taken when a grouping is recognized. The actions are the C code that appears @@ -2264,25 +2263,25 @@ Consider the definition of ‘input’: | input line ; - This definition reads as follows: “A complete input is either an -empty string, or a complete input followed by an input line”. Notice -that “complete input” is defined in terms of itself. This definition is + This definition reads as follows: "A complete input is either an +empty string, or a complete input followed by an input line". Notice +that "complete input" is defined in terms of itself. This definition is said to be “left recursive” since ‘input’ appears always as the leftmost symbol in the sequence. *Note Recursion::. The first alternative is empty because there are no symbols between the colon and the first ‘|’; this means that ‘input’ can match an empty string of input (no tokens). We write the rules this way because it is -legitimate to type ‘Ctrl-d’ right after you start the calculator. It’s +legitimate to type ‘Ctrl-d’ right after you start the calculator. It's conventional to put an empty alternative first and to use the (optional) ‘%empty’ directive, or to write the comment ‘/* empty */’ in it (*note Empty Rules::). The second alternate rule (‘input line’) handles all nontrivial -input. It means, “After reading any number of lines, read one more line -if possible.” The left recursion makes this rule into a loop. Since the -first alternative matches empty input, the loop can be executed zero or -more times. +input. It means, "After reading any number of lines, read one more line +if possible." The left recursion makes this rule into a loop. Since +the first alternative matches empty input, the loop can be executed zero +or more times. The parser function ‘yyparse’ continues to process input until a grammatical error is seen or the lexical analyzer says there are no more @@ -2313,8 +2312,8 @@ for. This action is unusual because it does not assign a value to ‘$$’. As a consequence, the semantic value associated with the ‘line’ is uninitialized (its value will be unpredictable). This would be a bug if -that value were ever used, but we don’t use it: once rpcalc has printed -the value of the user’s input line, that value is no longer needed. +that value were ever used, but we don't use it: once rpcalc has printed +the value of the user's input line, that value is no longer needed.  File: bison.info, Node: Rpcalc Exp, Prev: Rpcalc Line, Up: Rpcalc Rules @@ -2352,10 +2351,10 @@ associated semantic value, but if it had one you could refer to it as }’. When ‘yyparse’ recognizes a sum expression using this rule, the sum -of the two subexpressions’ values is produced as the value of the entire +of the two subexpressions' values is produced as the value of the entire expression. *Note Actions::. - You don’t have to give an action for every rule. When a rule has no + You don't have to give an action for every rule. When a rule has no action, Bison by default copies the value of ‘$1’ into ‘$$’. This is what happens in the first rule (the one that uses ‘NUM’). @@ -2381,14 +2380,14 @@ File: bison.info, Node: Rpcalc Lexer, Next: Rpcalc Main, Prev: Rpcalc Rules, 2.1.3 The ‘rpcalc’ Lexical Analyzer ----------------------------------- -The lexical analyzer’s job is low-level parsing: converting characters +The lexical analyzer's job is low-level parsing: converting characters or sequences of characters into tokens. The Bison parser gets its tokens by calling the lexical analyzer. *Note Lexical::. Only a simple lexical analyzer is needed for the RPN calculator. This lexical analyzer skips blanks and tabs, then reads in numbers as ‘double’ and returns them as ‘NUM’ tokens. Any other character that -isn’t part of a number is a separate token. Note that the token-code +isn't part of a number is a separate token. Note that the token-code for such a single-character token is the character itself. The return value of the lexical analyzer function is a numeric code @@ -2507,8 +2506,8 @@ command to convert it into a parser implementation file: $ bison FILE.y -In this example, the grammar file is called ‘rpcalc.y’ (for “Reverse -Polish CALCulator”). Bison produces a parser implementation file named +In this example, the grammar file is called ‘rpcalc.y’ (for "Reverse +Polish CALCulator"). Bison produces a parser implementation file named ‘FILE.tab.c’, removing the ‘.y’ from the grammar file name. The parser implementation file contains the source code for ‘yyparse’. The additional functions in the grammar file (‘yylex’, ‘yyerror’ and ‘main’) @@ -2611,7 +2610,7 @@ kinds and says they are left-associative operators. The declarations ‘%left’ and ‘%right’ (right associativity) take the place of ‘%token’ which is used to declare a token kind name without associativity/precedence. (These tokens are single-character literals, -which ordinarily don’t need to be declared. We declare them here to +which ordinarily don't need to be declared. We declare them here to specify the associativity/precedence.) Operator precedence is determined by the line ordering of the @@ -2623,7 +2622,7 @@ matters (‘%precedence’. *Note Precedence::. The other important new feature is the ‘%prec’ in the grammar section for the unary minus operator. The ‘%prec’ simply instructs Bison that -the rule ‘| '-' exp’ has the same precedence as ‘NEG’—in this case the +the rule ‘| '-' exp’ has the same precedence as ‘NEG’--in this case the next-to-highest. *Note Contextual Precedence::. Here is a sample run of ‘calc.y’: @@ -2649,7 +2648,7 @@ File: bison.info, Node: Simple Error Recovery, Next: Location Tracking Calc, ========================= Up to this point, this manual has not addressed the issue of “error -recovery”—how to continue parsing after the parser detects a syntax +recovery”--how to continue parsing after the parser detects a syntax error. All we have handled is error reporting with ‘yyerror’. Recall that by default ‘yyparse’ returns after calling ‘yyerror’. This means that an erroneous input line causes the calculator program to exit. Now @@ -2679,7 +2678,7 @@ other kinds of errors; for example, division by zero, which raises an exception signal that is normally fatal. A real calculator program must handle this signal and use ‘longjmp’ to return to ‘main’ and resume parsing input lines; it would also have to discard the rest of the -current line of input. We won’t discuss this issue further because it +current line of input. We won't discuss this issue further because it is not specific to Bison programs.  @@ -2785,7 +2784,7 @@ the wrong expressions or subexpressions. using the pseudo-variables ‘@N’ for rule components, and the pseudo-variable ‘@$’ for groupings. - We don’t need to assign a value to ‘@$’: the output parser does it + We don't need to assign a value to ‘@$’: the output parser does it automatically. By default, before executing the C code of each action, ‘@$’ is set to range from the beginning of ‘@1’ to the end of ‘@N’, for a rule with N components. This behavior can be redefined (*note @@ -2798,7 +2797,7 @@ File: bison.info, Node: Ltcalc Lexer, Prev: Ltcalc Rules, Up: Location Tracki 2.4.3 The ‘ltcalc’ Lexical Analyzer. ------------------------------------ -Until now, we relied on Bison’s defaults to enable location tracking. +Until now, we relied on Bison's defaults to enable location tracking. The next step is to rewrite the lexical analyzer, and make it able to feed the parser with the token locations, as it already does for semantic values. @@ -2851,7 +2850,7 @@ input text, to avoid the computed locations of being fuzzy or wrong: Basically, the lexical analyzer performs the same processing as before: it skips blanks and tabs, and reads numbers or single-character tokens. In addition, it updates ‘yylloc’, the global variable (of type -‘YYLTYPE’) containing the token’s location. +‘YYLTYPE’) containing the token's location. Now, each time this function returns a token, the parser has its kind as well as its semantic value, and its location in the text. The last @@ -3018,7 +3017,7 @@ File: bison.info, Node: Mfcalc Symbol Table, Next: Mfcalc Lexer, Prev: Mfcalc ------------------------------- The multi-function calculator requires a symbol table to keep track of -the names and meanings of variables and functions. This doesn’t affect +the names and meanings of variables and functions. This doesn't affect the grammar rules (except for the actions) or the Bison declarations, but it requires some additional C functions for support. @@ -3315,7 +3314,7 @@ The PROLOGUE section contains macro definitions and declarations of functions and variables that are used in the actions in the grammar rules. These are copied to the beginning of the parser implementation file so that they precede the definition of ‘yyparse’. You can use -‘#include’ to get the declarations from a header file. If you don’t +‘#include’ to get the declarations from a header file. If you don't need any C declarations, you may omit the ‘%{’ and ‘%}’ delimiters that bracket this section. @@ -3384,9 +3383,9 @@ qualifier can be omitted for the default location, or it can be one of ... -Notice that there are two PROLOGUE sections here, but there’s a subtle +Notice that there are two PROLOGUE sections here, but there's a subtle distinction between their functionality. For example, if you decide to -override Bison’s default definition for ‘YYLTYPE’, in which PROLOGUE +override Bison's default definition for ‘YYLTYPE’, in which PROLOGUE section should you write your new definition?(1) You should write it in the first since Bison will insert that code into the parser implementation file _before_ the default ‘YYLTYPE’ definition. In which @@ -3403,7 +3402,7 @@ Second, what if there is no ‘%union’? In that case, the second kind of PROLOGUE section is not available. This behavior is not intuitive. To avoid this subtle ‘%union’ dependency, rewrite the example using a -‘%code top’ and an unqualified ‘%code’. Let’s go ahead and add the new +‘%code top’ and an unqualified ‘%code’. Let's go ahead and add the new ‘YYLTYPE’ definition and the ‘trace_token’ prototype at the same time: %code top { @@ -3438,7 +3437,7 @@ PROLOGUE section is not available. This behavior is not intuitive. ... In this way, ‘%code top’ and the unqualified ‘%code’ achieve the same -functionality as the two kinds of PROLOGUE sections, but it’s always +functionality as the two kinds of PROLOGUE sections, but it's always explicit which kind you intend. Moreover, both kinds are always available even in the absence of ‘%union’. @@ -3446,7 +3445,7 @@ available even in the absence of ‘%union’. two lines before the warning need to appear near the top of the parser implementation file. The first line after the warning is required by ‘YYSTYPE’ and thus also needs to appear in the parser implementation -file. However, if you’ve instructed Bison to generate a parser header +file. However, if you've instructed Bison to generate a parser header file (*note Decl Summary::), you probably want that line to appear before the ‘YYSTYPE’ definition in that header file as well. The ‘YYLTYPE’ definition should also appear in the parser header file to @@ -3510,7 +3509,7 @@ provide ‘trace_token’ to modules that are external to your parser. Thus, you might wish for Bison to insert the prototype into both the parser header file and the parser implementation file. Since this function is not a dependency required by ‘YYSTYPE’ or ‘YYLTYPE’, it -doesn’t make sense to move its prototype to a ‘%code requires’. More +doesn't make sense to move its prototype to a ‘%code requires’. More importantly, since it depends upon ‘YYLTYPE’ and ‘yytoken_kind_t’, ‘%code requires’ is not sufficient. Instead, move its prototype from the unqualified ‘%code’ to a ‘%code provides’: @@ -3583,7 +3582,7 @@ semantic-type-related directives by semantic type: You could even place each of the above directive groups in the rules section of the grammar file next to the set of rules that uses the associated semantic type. (In the rules section, you must terminate -each of those directives with a semicolon.) And you don’t have to worry +each of those directives with a semicolon.) And you don't have to worry that some directive (like a ‘%union’) in the definitions section is going to adversely affect their functionality in some counter-intuitive manner just because it comes first. Such an organization is not @@ -3591,7 +3590,7 @@ possible using PROLOGUE sections. This section has been concerned with explaining the advantages of the four PROLOGUE alternatives over the original Yacc PROLOGUE. However, in -most cases when using these directives, you shouldn’t need to think +most cases when using these directives, you shouldn't need to think about all the low-level ordering issues discussed here. Instead, you should simply use these directives to label each block of your code according to its purpose and let Bison handle the ordering. ‘%code’ is @@ -3664,7 +3663,7 @@ of syntactically equivalent tokens. You use the symbol in grammar rules to mean that a token in that class is allowed. The symbol is represented in the Bison parser by a numeric code, and the ‘yylex’ function returns a token kind code to indicate what kind of token has -been read. You don’t need to know what the code value is; you can use +been read. You don't need to know what the code value is; you can use the symbol to stand for it. A “nonterminal symbol” stands for a class of syntactically equivalent @@ -3690,7 +3689,7 @@ token names. • A “character token kind” (or “literal character token”) is written in the grammar using the same syntax used in C for character constants; for example, ‘'+'’ is a character token kind. A - character token kind doesn’t need to be declared unless you need to + character token kind doesn't need to be declared unless you need to specify its semantic value data type (*note Value Type::), associativity, or precedence (*note Precedence::). @@ -3709,13 +3708,13 @@ token names. • A “literal string token” is written like a C string constant; for example, ‘"<="’ is a literal string token. A literal string token - doesn’t need to be declared unless you need to specify its semantic + doesn't need to be declared unless you need to specify its semantic value data type (*note Value Type::), associativity, or precedence (*note Precedence::). You can associate the literal string token with a symbolic name as an alias, using the ‘%token’ declaration (*note Token Decl::). If - you don’t do that, the lexical analyzer has to retrieve the token + you don't do that, the lexical analyzer has to retrieve the token code for the literal string token from the ‘yytname’ table (*note Calling Convention::). @@ -3748,7 +3747,7 @@ token kind is simply the positive numeric code of the character, so though you may need to convert it to ‘unsigned char’ to avoid sign-extension on hosts where ‘char’ is signed. Each named token kind becomes a C macro in the parser implementation file, so ‘yylex’ can use -the name to stand for the code. (This is why periods don’t make sense +the name to stand for the code. (This is why periods don't make sense in terminal symbols.) *Note Calling Convention::. If ‘yylex’ is defined in a separate file, you need to arrange for the @@ -3777,7 +3776,7 @@ that are incompatible with ASCII must rebuild those files before compiling them. The symbol ‘error’ is a terminal symbol reserved for error recovery -(*note Error Recovery::); you shouldn’t use it for any other purpose. +(*note Error Recovery::); you shouldn't use it for any other purpose. In particular, ‘yylex’ should never return this value. The default value of the error token is 256, unless you explicitly assigned 256 to one of your tokens with a ‘%token’ declaration. @@ -3996,14 +3995,14 @@ or The value of ‘api.value.type’ should be a type name that does not contain parentheses or square brackets. - Alternatively in C, instead of relying of Bison’s ‘%define’ support, + Alternatively in C, instead of relying of Bison's ‘%define’ support, you may rely on the C preprocessor and define ‘YYSTYPE’ as a macro: #define YYSTYPE double This macro definition must go in the prologue of the grammar file (*note Grammar Outline::). If compatibility with POSIX Yacc matters to you, -use this. Note however that Bison cannot know ‘YYSTYPE’’s value, not +use this. Note however that Bison cannot know ‘YYSTYPE’'s value, not even whether it is defined, so there are services it cannot provide. Besides this works only for C. @@ -4223,18 +4222,18 @@ references construct. Note that the vertical-bar character ‘|’ is really a rule separator, and actions are attached to a single rule. This is a difference with -tools like Flex, for which ‘|’ stands for either “or”, or “the same -action as that of the next rule”. In the following example, the action +tools like Flex, for which ‘|’ stands for either "or", or "the same +action as that of the next rule". In the following example, the action is triggered only when ‘b’ is found: a-or-b: 'a'|'b' { a_or_b_found = 1; }; - If you don’t specify an action for a rule, Bison supplies a default: + If you don't specify an action for a rule, Bison supplies a default: ‘$$ = $1’. Thus, the value of the first symbol in the rule becomes the value of the whole rule. Of course, the default action is valid only if the two data types match. There is no meaningful default action for an empty rule; every empty rule must have an explicit action unless the -rule’s value does not matter. +rule's value does not matter. ‘$N’ with N zero or negative is allowed for reference to tokens and groupings on the stack _before_ those that match the current rule. This @@ -4384,7 +4383,7 @@ readability and maintainability (*note Named References::): After the embedded statement is parsed, its semantic value becomes the value of the entire ‘let’-statement. Then the semantic value from the earlier action is used to restore the prior list of variables. This -removes the temporary ‘let’-variable from the list so that it won’t +removes the temporary ‘let’-variable from the list so that it won't appear to exist while the rest of the program is parsed. Because the types of the semantic values of midrule actions are @@ -4410,7 +4409,7 @@ without restoring it. Thus, ‘$5’ needs a destructor (*note Destructor Decl::), and Bison needs the type of the semantic value (‘context’) to select the right destructor. - As an extension to Yacc’s midrule actions, Bison offers a means to + As an extension to Yacc's midrule actions, Bison offers a means to type their semantic value: specify its type tag (‘<...>’ before the midrule action. @@ -4522,7 +4521,6 @@ a destructor for that symbol: declare_variable ($var); }; -  File: bison.info, Node: Midrule Conflicts, Prev: Midrule Action Translation, Up: Midrule Actions @@ -4733,7 +4731,7 @@ File: bison.info, Node: Printing Locations, Next: Location Default Action, Pr ------------------------ When using the default location type, the debug traces report the -symbols’ location. The generated parser does so using the +symbols' location. The generated parser does so using the ‘YYLOCATION_PRINT’ macro. -- Macro: YYLOCATION_PRINT (FILE, LOC); @@ -4757,7 +4755,7 @@ locations are much more general than semantic values, there is room in the output parser to redefine the default action to take for each rule. The ‘YYLLOC_DEFAULT’ macro is invoked each time a rule is matched, before the associated action is run. It is also invoked while -processing a syntax error, to compute the error’s location. Before +processing a syntax error, to compute the error's location. Before reporting an unresolvable syntactic ambiguity, a GLR parser invokes ‘YYLLOC_DEFAULT’ recursively to compute the location of that ambiguity. @@ -4768,7 +4766,7 @@ dedicated code from semantic actions. the location of the grouping (the result of the computation). When a rule is matched, the second parameter identifies locations of all right hand side elements of the rule being matched, and the third parameter is -the size of the rule’s right hand side. When a GLR parser reports an +the size of the rule's right hand side. When a GLR parser reports an ambiguity, which of multiple candidate right hand sides it passes to ‘YYLLOC_DEFAULT’ is undefined. When processing a syntax error, the second parameter identifies locations of the symbols that were discarded @@ -4863,7 +4861,6 @@ closing brace of the midrule action code: exp[res]: exp[x] '+' {$left = $x;}[left] exp[right] { $res = $left + $right; } - In references, in order to specify names containing dots and dashes, an explicit bracketed syntax ‘$[name]’ and ‘@[name]’ must be used: if-stmt: "if" '(' expr ')' "then" then.stmt ';' @@ -4911,7 +4908,7 @@ must declare it explicitly (*note Language and Grammar::). * Pure Decl:: Requesting a reentrant parser. * Push Decl:: Requesting a push parser. * Decl Summary:: Table of all Bison declarations. -* %define Summary:: Defining variables to adjust Bison’s behavior. +* %define Summary:: Defining variables to adjust Bison's behavior. * %code Summary:: Inserting code into the parser source.  @@ -4944,7 +4941,7 @@ follows: Bison will convert this into a definition in the parser, so that the function ‘yylex’ (if it is in this file) can use the name NAME to stand -for this token kind’s code. +for this token kind's code. Alternatively, you can use ‘%left’, ‘%right’, ‘%precedence’, or ‘%nonassoc’ instead of ‘%token’, if you wish to specify associativity @@ -4960,7 +4957,7 @@ field immediately following the token name: %token XNUM 0x12d // a GNU extension It is generally best, however, to let Bison choose the numeric codes for -all token kinds. Bison will automatically select codes that don’t +all token kinds. Bison will automatically select codes that don't conflict with each other or with normal characters. In the event that the stack type is a union, you must augment the @@ -5124,7 +5121,7 @@ code. -- Directive: %initial-action { CODE } Declare that the braced CODE must be invoked before parsing each time ‘yyparse’ is called. The CODE may use ‘$$’ (or ‘$$’) and - ‘@$’ — initial value and location of the lookahead — and the + ‘@$’ -- initial value and location of the lookahead -- and the ‘%parse-param’. For instance, if your locations use a file name, you may use @@ -5221,7 +5218,7 @@ the end token (token 0) if you redefine it from ‘$end’ to, for example, Finally, Bison will never invoke a ‘%destructor’ for an unreferenced midrule semantic value (*note Midrule Actions::). That is, Bison does not consider a midrule to have a semantic value if you do not reference -‘$$’ in the midrule’s action or ‘$N’ (where N is the right-hand side +‘$$’ in the midrule's action or ‘$N’ (where N is the right-hand side symbol position of the midrule) in any later action in that rule. However, if you do reference either, the Bison-generated parser will invoke the ‘<>’ ‘%destructor’ whenever it discards the midrule symbol. @@ -5354,7 +5351,7 @@ document this fact with an ‘%expect’ modifier as follows: Mid-rule actions generate implicit rules that are also subject to conflicts (*note Midrule Conflicts::). To attach an ‘%expect’ or -‘%expect-rr’ annotation to an implicit mid-rule action’s rule, put it +‘%expect-rr’ annotation to an implicit mid-rule action's rule, put it before the action. For example, %glr-parser @@ -5377,7 +5374,7 @@ other, and we should expect one reduce/reduce conflict for each. a verbose list of where the conflicts occur. Bison will also print the number of conflicts. - • Check each of the conflicts to make sure that Bison’s default + • Check each of the conflicts to make sure that Bison's default resolution is what you really want. If not, rewrite the grammar and go back to the beginning. @@ -5457,7 +5454,7 @@ completely parsed. A push parser, on the other hand, is called each time a new token is made available. A push parser is typically useful when the parser is part of a main -event loop in the client’s application. This is typically a requirement +event loop in the client's application. This is typically a requirement of a GUI, when the main event loop needs to be triggered within a certain time period. @@ -5484,7 +5481,7 @@ parser at a time. When a push parser is selected, Bison will generate some new symbols in the generated parser. ‘yypstate’ is a structure that the generated -parser uses to store the parser’s state. ‘yypstate_new’ is the function +parser uses to store the parser's state. ‘yypstate_new’ is the function that will create a new parser instance. ‘yypstate_delete’ will free the resources associated with the corresponding parser instance. Finally, ‘yypush_parse’ is the function that should be called whenever a token is @@ -5514,7 +5511,7 @@ would thus look like this: } while (status == YYPUSH_MORE); yypstate_delete (ps); - That’s it. Notice the next token is put into the global variable + That's it. Notice the next token is put into the global variable ‘yychar’ for use by the next invocation of the ‘yypush_parse’ function. Bison also supports both the push parser interface along with the @@ -5581,7 +5578,7 @@ Here is a summary of the declarations used to define a grammar: Decl::). -- Directive: %start - Specify the grammar’s start symbol (*note Start Decl::). + Specify the grammar's start symbol (*note Start Decl::). -- Directive: %expect Declare the expected number of shift/reduce conflicts, either @@ -5609,7 +5606,7 @@ directives: -- Directive: %define VARIABLE VALUE -- Directive: %define VARIABLE {VALUE} -- Directive: %define VARIABLE "VALUE" - Define a variable to adjust Bison’s behavior. *Note %define + Define a variable to adjust Bison's behavior. *Note %define Summary::. -- Directive: %defines @@ -5703,7 +5700,7 @@ directives: ‘yytoken_kind_t’, ‘YYSTYPE’, ‘YYLTYPE’. -- Directive: %no-lines - Don’t generate any ‘#line’ preprocessor commands in the parser + Don't generate any ‘#line’ preprocessor commands in the parser implementation file. Ordinarily Bison writes these commands in the parser implementation file so that the C compiler and debuggers will associate errors and object code with your source file (the @@ -5762,7 +5759,7 @@ directives: ‘YYNSTATES’ The number of parser states (*note Parser States::). - Here’s code for looking up a multicharacter token in ‘yytname’, + Here's code for looking up a multicharacter token in ‘yytname’, assuming that the characters of the token are stored in ‘token_buffer’, and assuming that the token does not contain any characters like ‘"’ that require escaping. @@ -5804,7 +5801,7 @@ File: bison.info, Node: %define Summary, Next: %code Summary, Prev: Decl Summ 3.7.14 %define Summary ---------------------- -There are many features of Bison’s behavior that can be controlled by +There are many features of Bison's behavior that can be controlled by assigning the feature a single value. For historical reasons, some such features are assigned values by dedicated directives, such as ‘%start’, which assigns the start symbol. However, newer such features are @@ -5853,7 +5850,7 @@ described below. • Language(s): C++ - • Purpose: Define the type of file names in Bison’s default + • Purpose: Define the type of file names in Bison's default location and position types. *Note Exposing the Location Classes::. @@ -5892,7 +5889,7 @@ described below. Using ‘api.header.include’ does not change the name of the generated header, only how it is included. - To work around limitations of Automake’s ‘ylwrap’ (which runs + To work around limitations of Automake's ‘ylwrap’ (which runs ‘bison’ with ‘--yacc’), ‘api.header.include’ is _not_ predefined when the output file is ‘y.tab.c’. Define it to avoid the duplication. @@ -5913,7 +5910,7 @@ described below. • Language(s): C++ - • Purpose: Define the name of the file in which Bison’s default + • Purpose: Define the name of the file in which Bison's default location and position types are generated. *Note Exposing the Location Classes::. @@ -5930,7 +5927,7 @@ described below. • Default Value: Not applicable if locations are not enabled, or if a user location type is specified (see - ‘api.location.type’). Otherwise, Bison’s ‘location’ is + ‘api.location.type’). Otherwise, Bison's ‘location’ is generated in ‘location.hh’ (*note C++ location::). • History: Introduced in Bison 3.2. @@ -6103,7 +6100,7 @@ described below. • Accepted Values: Any non empty string. Must be a valid identifier in the target language (typically a non empty - sequence of letters, underscores, and —not at the beginning— + sequence of letters, underscores, and --not at the beginning-- digits). The empty prefix is (generally) invalid: @@ -6163,7 +6160,7 @@ described below. • Accepted Values: Any string. Must be a valid identifier prefix in the target language (typically, a possibly empty - sequence of letters, underscores, and —not at the beginning— + sequence of letters, underscores, and --not at the beginning-- digits). • Default Value: empty @@ -6250,7 +6247,7 @@ described below. properly supported yet. ‘union-directive’ (C, C++, D) The type is defined thanks to the ‘%union’ directive. - You don’t have to define ‘api.value.type’ in that case, + You don't have to define ‘api.value.type’ in that case, using ‘%union’ suffices. *Note Union Decl::. For instance: %define api.value.type union-directive @@ -6373,7 +6370,7 @@ described below. In C++, when variants are used (*note C++ Variants::), symbols must be constructed and destroyed properly. This option checks these constraints using runtime type information - (RTTI). Therefore the generated code cannot be compiled with + (RTTI). Therefore the generated code cannot be compiled with RTTI disabled (via compiler options such as ‘-fno-rtti’). • Accepted Values: Boolean @@ -6487,9 +6484,9 @@ qualifiers produce an error. Some of the accepted qualifiers are: • Purpose: This is the best place to write dependency code required for the value and location types (‘YYSTYPE’ and - ‘YYLTYPE’ in C). In other words, it’s the best place to define + ‘YYLTYPE’ in C). In other words, it's the best place to define types referenced in ‘%union’ directives. In C, if you use - ‘#define’ to override Bison’s default ‘YYSTYPE’ and ‘YYLTYPE’ + ‘#define’ to override Bison's default ‘YYSTYPE’ and ‘YYLTYPE’ definitions, then it is also the best place. However you should rather ‘%define’ ‘api.value.type’ and ‘api.location.type’. @@ -6571,7 +6568,7 @@ by PREFIX (i.e., PREFIX upper-cased) instead of ‘YY’. ‘yylval’, ‘yylloc’, ‘yychar’ and ‘yydebug’. If you use a push parser, ‘yypush_parse’, ‘yypull_parse’, ‘yypstate’, ‘yypstate_new’ and ‘yypstate_delete’ will also be renamed. The renamed macros include -‘YYSTYPE’, ‘YYLTYPE’, and ‘YYDEBUG’, which is treated specifically — +‘YYSTYPE’, ‘YYLTYPE’, and ‘YYDEBUG’, which is treated specifically -- more about this below. For example, if you use ‘%define api.prefix {c}’, the names become @@ -6609,7 +6606,7 @@ beginning of the parser implementation file, defining ‘yyparse’ as int yyparse (void); This effectively substitutes one name for the other in the entire -parser implementation file, thus the “original” names (‘yylex’, +parser implementation file, thus the "original" names (‘yylex’, ‘YYSTYPE’, ...) are also usable in the parser implementation file. However, in the parser header file, the symbols are defined renamed, @@ -6667,7 +6664,7 @@ grammar file, you are likely to run into trouble. which reads tokens. * Error Reporting:: Passing error messages to the user. * Action Features:: Special features for use in actions. -* Internationalization:: How to let the parser speak in the user’s +* Internationalization:: How to let the parser speak in the user's native language.  @@ -6714,7 +6711,7 @@ declaration ‘%parse-param’: declaring functions or prototypes. The last identifier in ARGUMENT-DECLARATION must be the argument name. - Here’s an example. Write this in the parser: + Here's an example. Write this in the parser: %parse-param {int *nastiness} {int *randomness} @@ -6903,7 +6900,7 @@ that there is nothing left afterwards. *Note Calling Convention::, for an example. Returning ‘YYUNDEF’ tells the parser that some lexical error was -found. It will emit an error message about an “invalid token”, and +found. It will emit an error message about an "invalid token", and enter error-recovery (*note Error Recovery::). Returning an unknown token kind results in the exact same behavior. @@ -6974,9 +6971,9 @@ if the type is ‘int’ (the default), you might write this in ‘yylex’: return INT; /* Return the kind of the token. */ ... - When you are using multiple data types, ‘yylval’’s type is a union + When you are using multiple data types, ‘yylval’'s type is a union made from the ‘%union’ declaration (*note Union Decl::). So when you -store a token’s value, you must use the proper member of the union. If +store a token's value, you must use the proper member of the union. If the ‘%union’ declaration looks like this: %union { @@ -7117,7 +7114,7 @@ incorrect information if LAC is not enabled (*note LAC::). The parser can detect one other kind of error: memory exhaustion. This can happen when the input contains constructions that are very -deeply nested. It isn’t likely you will encounter this, since the Bison +deeply nested. It isn't likely you will encounter this, since the Bison parser normally extends its stack automatically up to a very large limit. But if memory is exhausted, ‘yyparse’ calls ‘yyerror’ in the usual fashion, except that the argument string is ‘"memory exhausted"’. @@ -7175,9 +7172,9 @@ then the parser no longer passes syntax error messages to ‘yyerror’, rather it delegates that task to the user by calling the ‘yyreport_syntax_error’ function. - The following functions and types are “‘static’”: they are defined in + The following functions and types are "‘static’": they are defined in the implementation file (‘*.c’) and available only from there. They are -meant to be used from the grammar’s epilogue. +meant to be used from the grammar's epilogue. -- Function: static int yyreport_syntax_error (const yypcontext_t *CTX) Report a syntax error to the user. Return 0 on success, ‘YYENOMEM’ @@ -7211,7 +7208,7 @@ meant to be used from the grammar’s epilogue. -- Function: static yysymbol_kind_t yypcontext_token (const yypcontext_t *CTX) - The “unexpected” token: the symbol kind of the lookahead token that + The "unexpected" token: the symbol kind of the lookahead token that caused the syntax error. Returns ‘YYSYMBOL_YYEMPTY’ if there is no lookahead. @@ -7392,12 +7389,12 @@ File: bison.info, Node: Internationalization, Prev: Action Features, Up: Inte A Bison-generated parser can print diagnostics, including error and tracing messages. By default, they appear in English. However, Bison -also supports outputting diagnostics in the user’s native language. To +also supports outputting diagnostics in the user's native language. To make this work, the user should set the usual environment variables. -*Note The User’s View: (gettext)Users. For example, the shell command -‘export LC_ALL=fr_CA.UTF-8’ might set the user’s locale to French +*Note The User's View: (gettext)Users. For example, the shell command +‘export LC_ALL=fr_CA.UTF-8’ might set the user's locale to French Canadian using the UTF-8 encoding. The exact set of available locales -depends on the user’s installation. +depends on the user's installation. * Menu: @@ -7411,13 +7408,13 @@ File: bison.info, Node: Enabling I18n, Next: Token I18n, Up: Internationaliza ----------------------------------- The maintainer of a package that uses a Bison-generated parser enables -the internationalization of the parser’s output through the following +the internationalization of the parser's output through the following steps. Here we assume a package that uses GNU Autoconf and GNU Automake. 1. Into the directory containing the GNU Autoconf macros used by the - package —often called ‘m4’— copy the ‘bison-i18n.m4’ file installed - by Bison under ‘share/aclocal/bison-i18n.m4’ in Bison’s + package --often called ‘m4’-- copy the ‘bison-i18n.m4’ file + installed by Bison under ‘share/aclocal/bison-i18n.m4’ in Bison's installation directory. For example: cp /usr/local/share/aclocal/bison-i18n.m4 m4/bison-i18n.m4 @@ -7430,7 +7427,7 @@ Automake. to enable translations in the Bison-generated parser. 3. In the ‘main’ function of your program, designate the directory - containing Bison’s runtime message catalog, through a call to + containing Bison's runtime message catalog, through a call to ‘bindtextdomain’ with domain name ‘bison-runtime’. For example: bindtextdomain ("bison-runtime", BISON_LOCALEDIR); @@ -7478,17 +7475,17 @@ internationalization marker (‘_("function")’). parser will use both ‘N_’ and ‘_’, that must be defined (*note The Programmer’s View: (gettext)Programmers.). They are used only on string aliases marked for translation. In other words, even if your catalog -features a translation for “function”, then with +features a translation for "function", then with %token FUN "function" VAR _("variable") -“function” will appear untranslated in debug traces and error messages. +"function" will appear untranslated in debug traces and error messages. Unless defined by the user, the end-of-file token, ‘YYEOF’, is -provided “end of file” as an alias. It is also internationalized if the +provided "end of file" as an alias. It is also internationalized if the user internationalized tokens. To map it to another string, use: %token END 0 _("end of input") @@ -7512,11 +7509,11 @@ When the last N tokens and groupings shifted match the components of a grammar rule, they can be combined according to that rule. This is called “reduction”. Those tokens and groupings are replaced on the stack by a single grouping whose symbol is the result (left hand side) -of that rule. Running the rule’s action is part of the process of +of that rule. Running the rule's action is part of the process of reduction, because this is what computes the semantic value of the resulting grouping. - For example, if the infix calculator’s parser stack contains this: + For example, if the infix calculator's parser stack contains this: 1 + 5 * 3 @@ -7533,7 +7530,7 @@ At this point, another reduction can be made, resulting in the single value 16. Then the newline token can be shifted. The parser tries, by shifts and reductions, to reduce the entire -input down to a single grouping whose symbol is the grammar’s +input down to a single grouping whose symbol is the grammar's start-symbol (*note Language and Grammar::). This kind of parser is known in the literature as a bottom-up parser. @@ -7543,7 +7540,7 @@ start-symbol (*note Language and Grammar::). * Lookahead:: Parser looks one token ahead when deciding what to do. * Shift/Reduce:: Conflicts: when either shifting or reduction is valid. * Precedence:: Operator precedence works by resolving conflicts. -* Contextual Precedence:: When an operator’s precedence depends on context. +* Contextual Precedence:: When an operator's precedence depends on context. * Parser States:: The parser is a finite-state-machine with stack. * Reduce/Reduce:: When two rules are applicable in the same situation. * Mysterious Conflicts:: Conflicts that look unjustified. @@ -7560,7 +7557,7 @@ File: bison.info, Node: Lookahead, Next: Shift/Reduce, Up: Algorithm The Bison parser does _not_ always reduce immediately as soon as the last N tokens and groupings match a rule. This is because such a simple strategy is inadequate to handle most languages. Instead, when a -reduction is possible, the parser sometimes “looks ahead” at the next +reduction is possible, the parser sometimes "looks ahead" at the next token in order to decide what to do. When a token is read, it is not immediately shifted; first it becomes @@ -7630,7 +7627,7 @@ rule. This situation, where either a shift or a reduction would be valid, is called a “shift/reduce conflict”. Bison is designed to resolve these conflicts by choosing to shift, unless otherwise directed by operator -precedence declarations. To see the reason for this, let’s contrast it +precedence declarations. To see the reason for this, let's contrast it with the other alternative. Since the parser prefers to shift the ‘"else"’, the result is to @@ -7657,10 +7654,10 @@ Bison accomplishes by choosing to shift rather than reduce. (It would ideally be cleaner to write an unambiguous grammar, but that is very hard to do in this case.) This particular ambiguity was first encountered in the specifications of Algol 60 and is called the -“dangling ‘else’” ambiguity. +"dangling ‘else’" ambiguity. To assist the grammar author in understanding the nature of each -conflict, Bison can be asked to generate “counterexamples”. In the +conflict, Bison can be asked to generate "counterexamples". In the present case it actually even proves that the grammar is ambiguous by exhibiting a string with two different parses: @@ -7684,7 +7681,7 @@ exhibiting a string with two different parses: shift/reduce conflicts, you can use the ‘%expect N’ declaration. There will be no warning as long as the number of shift/reduce conflicts is exactly N, and Bison will report an error if there is a different -number. *Note Expect Decl::. However, we don’t recommend the use of +number. *Note Expect Decl::. However, we don't recommend the use of ‘%expect’ (except ‘%expect 0’!), as an equal number of conflicts does not mean that they are the _same_. When possible, you should rather use precedence directives to _fix_ the conflicts explicitly (*note Non @@ -7784,7 +7781,7 @@ list of tokens, which are operators whose precedence and associativity is being declared. The ‘%left’ declaration makes all those operators left-associative and the ‘%right’ declaration makes them right-associative. A third alternative is ‘%nonassoc’, which declares -that it is a syntax error to find the same operator twice “in a row”. +that it is a syntax error to find the same operator twice "in a row". The last alternative, ‘%precedence’, allows to define only precedence and no associativity at all. As a result, any associativity-related conflict that remains will be reported as an compile-time error. The @@ -7873,8 +7870,8 @@ Precedence::.) Finally, the resolution of conflicts works by comparing the precedence of the rule being considered with that of the lookahead -token. If the token’s precedence is higher, the choice is to shift. If -the rule’s precedence is higher, the choice is to reduce. If they have +token. If the token's precedence is higher, the choice is to shift. If +the rule's precedence is higher, the choice is to reduce. If they have equal precedence, the choice is made based on the associativity of that precedence level. The verbose output file made by ‘-v’ (*note Invocation::) says how each conflict was resolved. @@ -7890,7 +7887,7 @@ File: bison.info, Node: Non Operators, Prev: How Precedence, Up: Precedence Using properly precedence and associativity directives can help fixing shift/reduce conflicts that do not involve arithmetic-like operators. -For instance, the “dangling ‘else’” problem (*note Shift/Reduce::) can +For instance, the "dangling ‘else’" problem (*note Shift/Reduce::) can be solved elegantly in two different ways. In the present case, the conflict is between the token ‘"else"’ @@ -7910,12 +7907,12 @@ action, use right associativity: %right "then" "else" Neither solution is perfect however. Since Bison does not provide, -so far, “scoped” precedence, both force you to declare the precedence of +so far, "scoped" precedence, both force you to declare the precedence of these keywords with respect to the other operators your grammar. Therefore, instead of being warned about new conflicts you would be unaware of (e.g., a shift/reduce conflict due to ‘if test then 1 else 2 + 3’ being ambiguous: ‘if test then 1 else (2 + 3)’ or ‘(if test then 1 -else 2) + 3’?), the conflict will be already “fixed”. +else 2) + 3’?), the conflict will be already "fixed".  File: bison.info, Node: Contextual Precedence, Next: Parser States, Prev: Precedence, Up: Algorithm @@ -7936,8 +7933,8 @@ the ‘%prec’ modifier for rules. The ‘%prec’ modifier declares the precedence of a particular rule by specifying a terminal symbol whose precedence should be used for that -rule. It’s not necessary for that symbol to appear otherwise in the -rule. The modifier’s syntax is: +rule. It's not necessary for that symbol to appear otherwise in the +rule. The modifier's syntax is: %prec TERMINAL-SYMBOL @@ -7980,9 +7977,9 @@ do next. Each time a lookahead token is read, the current parser state together with the kind of lookahead token are looked up in a table. -This table entry can say, “Shift the lookahead token.” In this case, it +This table entry can say, "Shift the lookahead token." In this case, it also specifies the new parser state, which is pushed onto the top of the -parser stack. Or it can say, “Reduce using rule number N.” This means +parser stack. Or it can say, "Reduce using rule number N." This means that a certain number of tokens or groupings are taken off the top of the stack, and replaced by one grouping. In other words, that number of states are popped from the stack, and one new state is pushed. @@ -8030,8 +8027,8 @@ via ‘maybeword’ and then the second rule. You might think that this is a distinction without a difference, because it does not change whether any particular input is valid or not. But it does affect which actions are run. One parsing order runs the -second rule’s action; the other runs the first rule’s action and the -third rule’s action. In this example, the output of the program +second rule's action; the other runs the first rule's action and the +third rule's action. In this example, the output of the program changes. Bison resolves a reduce/reduce conflict by choosing to use the rule @@ -8147,7 +8144,7 @@ File: bison.info, Node: Mysterious Conflicts, Next: Tuning LR, Prev: Reduce/R 5.7 Mysterious Conflicts ======================== -Sometimes reduce/reduce conflicts can occur that don’t look warranted. +Sometimes reduce/reduce conflicts can occur that don't look warranted. Here is an example: %% @@ -8182,7 +8179,7 @@ default_, for historical reasons. In this grammar, two contexts, that after an ‘"id"’ at the beginning of a ‘param_spec’ and likewise at the beginning of a ‘return_spec’, are similar enough that Bison assumes they are the same. They appear similar because the same set of rules would -be active—the rule for reducing to a ‘name’ and that for reducing to a +be active--the rule for reducing to a ‘name’ and that for reducing to a ‘type’. Bison is unable to determine at that stage of processing that the rules would require different lookahead tokens in the two contexts, so it makes a single parser state for them both. Combining the two @@ -8197,7 +8194,7 @@ algorithm. Either IELR(1) or canonical LR(1) would suffice, but the former is more efficient and easier to debug during development. *Note LR Table Construction::, for details. - If you instead wish to work around LALR(1)’s limitations, you can + If you instead wish to work around LALR(1)'s limitations, you can often fix a mysterious conflict by identifying the two parser states that are being confused, and adding something to make them look distinct. In the above example, adding one rule to ‘return_spec’ as @@ -8243,11 +8240,11 @@ File: bison.info, Node: Tuning LR, Next: Generalized LR Parsing, Prev: Myster 5.8 Tuning LR ============= -The default behavior of Bison’s LR-based parsers is chosen mostly for +The default behavior of Bison's LR-based parsers is chosen mostly for historical reasons, but that behavior is often not robust. For example, in the previous section, we discussed the mysterious conflicts that can -be produced by LALR(1), Bison’s default parser table construction -algorithm. Another example is Bison’s ‘%define parse.error verbose’ +be produced by LALR(1), Bison's default parser table construction +algorithm. Another example is Bison's ‘%define parse.error verbose’ directive, which instructs the generated parser to produce verbose syntax error messages, which can sometimes contain incorrect information. @@ -8310,7 +8307,7 @@ use IELR will result in unnecessarily large parser tables. That is, IELR generates LALR tables when LALR (using a deterministic parsing algorithm) is sufficient to support the full language-recognition power of LR. Thus, by enabling IELR at the start of grammar development, you -can safely and completely eliminate the need to consider LALR’s +can safely and completely eliminate the need to consider LALR's shortcomings. While IELR is almost always preferable, there are circumstances where @@ -8335,7 +8332,7 @@ each parser table construction algorithm within Bison: to resolve conflicts statically, GLR behaves more like a deterministic parser in the syntactic contexts where those conflicts appear, and so either IELR or canonical LR can then - be helpful to avoid LALR’s mysterious behavior. + be helpful to avoid LALR's mysterious behavior. • Malformed grammars. @@ -8354,7 +8351,7 @@ each parser table construction algorithm within Bison: sentences. However, like LALR, IELR merges parser states during parser table construction so that the number of parser states is often an order of magnitude less than for canonical LR. More - importantly, because canonical LR’s extra parser states may contain + importantly, because canonical LR's extra parser states may contain duplicate conflicts in the case of non-LR grammars, the number of conflicts for IELR is often an order of magnitude less as well. This effect can significantly reduce the complexity of developing a @@ -8533,7 +8530,7 @@ enable default reductions in consistent states, canonical LR and IELR behave almost exactly the same for both syntactically acceptable and syntactically unacceptable input. While LALR still does not support the full language-recognition power of canonical LR and IELR, LAC at least -enables LALR’s syntax error handling to correctly reflect LALR’s +enables LALR's syntax error handling to correctly reflect LALR's language-recognition power. There are a few caveats to consider when using LAC: @@ -8564,7 +8561,7 @@ language-recognition power. reductions in consistent states and shift actions, the parser never has to initiate an exploratory parse. Moreover, the most time-consuming tasks in a parse are often the file I/O, the lexical - analysis performed by the scanner, and the user’s semantic actions, + analysis performed by the scanner, and the user's semantic actions, but none of these are performed during the exploratory parse. Finally, the base of the temporary stack used during an exploratory parse is a pointer into the normal parser state stack so that the @@ -8582,7 +8579,7 @@ File: bison.info, Node: Unreachable States, Prev: LAC, Up: Tuning LR 5.8.4 Unreachable States ------------------------ -If there exists no sequence of transitions from the parser’s start state +If there exists no sequence of transitions from the parser's start state to some state S, then Bison considers S to be an “unreachable state”. A state can become unreachable during conflict resolution if Bison disables a shift action leading to it from a predecessor state. @@ -8602,7 +8599,7 @@ understand the relationship between the parser and the grammar. Unreachable states may contain conflicts and may use rules not used in any other state. Thus, keeping unreachable states may induce - warnings that are irrelevant to your parser’s behavior, and it may + warnings that are irrelevant to your parser's behavior, and it may eliminate warnings that are relevant. Of course, the change in warnings may actually be relevant to a parser table analysis that wants to keep unreachable states, so this behavior will likely @@ -8635,7 +8632,7 @@ The same is true of languages that require more than one symbol of lookahead, since the parser lacks the information necessary to make a decision at the point it must be made in a shift/reduce parser. Finally, as previously mentioned (*note Mysterious Conflicts::), there -are languages where Bison’s default choice of how to summarize the input +are languages where Bison's default choice of how to summarize the input seen so far loses necessary information. When you use the ‘%glr-parser’ declaration in your grammar file, @@ -8685,7 +8682,7 @@ length of the input times the maximum number of stacks required for any prefix of the input. Thus, really ambiguous or nondeterministic grammars can require exponential time and space to process. Such badly behaving examples, however, are not generally of practical interest. -Usually, nondeterminism in a grammar is local—the parser is “in doubt” +Usually, nondeterminism in a grammar is local--the parser is "in doubt" only for a few tokens at a time. Therefore, the current data structure should generally be adequate. On LR(1) portions of a grammar, in particular, it is only slightly slower than with the deterministic LR(1) @@ -8837,14 +8834,14 @@ shifted will error messages resume. as any other rules can. You can make error messages resume immediately by using the macro -‘yyerrok’ in an action. If you do this in the error rule’s action, no +‘yyerrok’ in an action. If you do this in the error rule's action, no error messages will be suppressed. This macro requires no arguments; ‘yyerrok;’ is a valid C statement. The previous lookahead token is reanalyzed immediately after an error. If this is unacceptable, then the macro ‘yyclearin’ may be used to clear this token. Write the statement ‘yyclearin;’ in the error -rule’s action. *Note Action Features::. +rule's action. *Note Action Features::. For example, suppose that on a syntax error, an error handling routine is called that advances the input stream to some point where @@ -8875,7 +8872,7 @@ for such languages. * Tie-in Recovery:: Lexical tie-ins have implications for how error recovery rules must be written. - (Actually, “kludge” means any technique that gets its job done but is + (Actually, "kludge" means any technique that gets its job done but is neither clean nor robust.)  @@ -8904,7 +8901,7 @@ choice of token kind to recognize. ‘IDENTIFIER’ is accepted as an expression, but ‘TYPENAME’ is not. ‘TYPENAME’ can start a declaration, but ‘IDENTIFIER’ cannot. In contexts where the meaning of the identifier is _not_ significant, such as in declarations that can shadow -a typedef name, either ‘TYPENAME’ or ‘IDENTIFIER’ is accepted—there is +a typedef name, either ‘TYPENAME’ or ‘IDENTIFIER’ is accepted--there is one rule for each of the two token kinds. This technique is simple to use if the decision of which kinds of @@ -8922,13 +8919,13 @@ earlier: } Unfortunately, the name being declared is separated from the -declaration construct itself by a complicated syntactic structure—the -“declarator”. +declaration construct itself by a complicated syntactic structure--the +"declarator". As a result, part of the Bison parser for C needs to be duplicated, with all the nonterminal names changed: once for parsing a declaration in which a typedef name can be redefined, and once for parsing a -declaration in which that can’t be done. Here is a part of the +declaration in which that can't be done. Here is a part of the duplication, with actions omitted for brevity: initdcl: @@ -9050,7 +9047,7 @@ way you can write the action to determine whether a ‘hex’ construct is being aborted or not. So if you are using a lexical tie-in, you had better make sure your error recovery rules are not of this kind. Each rule must be such that you can be sure that it always will, or always -won’t, have to clear the flag. +won't, have to clear the flag.  File: bison.info, Node: Debugging, Next: Invocation, Prev: Context Dependency, Up: Top @@ -9058,7 +9055,7 @@ File: bison.info, Node: Debugging, Next: Invocation, Prev: Context Dependency 8 Debugging Your Parser *********************** -Developing a parser can be a challenge, especially if you don’t +Developing a parser can be a challenge, especially if you don't understand the algorithm (*note Algorithm::). This chapter explains how to understand and debug a parser. @@ -9118,7 +9115,7 @@ features one shift/reduce conflict: else.y: warning: 1 shift/reduce conflict [-Wconflicts-sr] else.y: note: rerun with option '-Wcounterexamples' to generate conflict counterexamples -Let’s rerun ‘bison’ with the option ‘-Wcex’/‘-Wcounterexamples’(the +Let's rerun ‘bison’ with the option ‘-Wcex’/‘-Wcounterexamples’(the following output is actually in color): else.y: warning: 1 shift/reduce conflict [-Wconflicts-sr] @@ -9205,7 +9202,7 @@ shows that the grammar accepts the empty input in two different ways. two ways. In these cases, counterexample generation will provide two examples that are the same up until the dot. Most notably, this will happen when your grammar requires a stronger parser (more lookahead, LR -instead of LALR). The following example isn’t LR(1): +instead of LALR). The following example isn't LR(1): %token ID %% @@ -9309,7 +9306,7 @@ might vary, but the interpretation is the same. The first section reports useless tokens, nonterminals and rules. Useless nonterminals and rules are removed in order to produce a smaller parser, but useless tokens are preserved, since they might be used by -the scanner (note the difference between “useless” and “unused” below): +the scanner (note the difference between "useless" and "unused" below): Nonterminals useless in grammar useless @@ -9373,14 +9370,14 @@ input cursor. exp go to state 2 - This reads as follows: “state 0 corresponds to being at the very + This reads as follows: "state 0 corresponds to being at the very beginning of the parsing, in the initial rule, right before the start symbol (here, ‘exp’). When the parser returns to this state right after having reduced a rule that produced an ‘exp’, the control flow jumps to state 2. If there is no such transition on a nonterminal symbol, and the lookahead is a ‘NUM’, then this token is shifted onto the parse stack, and the control flow jumps to state 1. Any other lookahead -triggers a syntax error.” +triggers a syntax error." Even though the only active rule in state 0 seems to be rule 0, the report lists ‘NUM’ as a lookahead token because ‘NUM’ can be at the @@ -9749,7 +9746,7 @@ distinguished by a red filling color on these nodes, just like how they are reported between square brackets in the verbose file. The reduction corresponding to the rule number 0 is the acceptation -state. It is shown as a blue diamond, labeled “Acc”. +state. It is shown as a blue diamond, labeled "Acc". Graphical Representation of Gotos --------------------------------- @@ -9802,7 +9799,7 @@ File: bison.info, Node: Tracing, Prev: Xml, Up: Debugging 8.5 Tracing Your Parser ======================= -When a Bison grammar compiles properly but parses “incorrectly”, the +When a Bison grammar compiles properly but parses "incorrectly", the ‘yydebug’ parser-trace feature helps figuring out why. * Menu: @@ -9890,7 +9887,7 @@ arrive at the place where something undesirable happens, and you will see which parts of the grammar are to blame. The parser implementation file is a C/C++/D/Java program and you can -use debuggers on it, but it’s not easy to interpret what it is doing. +use debuggers on it, but it's not easy to interpret what it is doing. The parser function is a finite-state machine interpreter, and aside from the actions it executes the same code over and over. Only the values of variables show where in the grammar it is working. @@ -9923,7 +9920,7 @@ its prologue: The ‘%define’ directive instructs Bison to generate run-time trace support. Then, activation of these traces is controlled at run-time by the ‘yydebug’ variable, which is disabled by default. Because these -traces will refer to the “states” of the parser, it is helpful to ask +traces will refer to the "states" of the parser, it is helpful to ask for the creation of a description of that parser; this is the purpose of (admittedly ill-named) ‘%verbose’ directive. @@ -10059,10 +10056,10 @@ The usual way to invoke Bison is as follows: $ bison FILE Here FILE is the grammar file name, which usually ends in ‘.y’. The -parser implementation file’s name is made by replacing the ‘.y’ with +parser implementation file's name is made by replacing the ‘.y’ with ‘.tab.c’ and removing any leading directory. Thus, the ‘bison foo.y’ file name yields ‘foo.tab.c’, and the ‘bison hack/foo.y’ file name -yields ‘foo.tab.c’. It’s also possible, in case you are writing C++ +yields ‘foo.tab.c’. It's also possible, in case you are writing C++ code instead of C in your grammar file, to name it ‘foo.ypp’ or ‘foo.y++’. Then, the output files will take an extension like the given one as input (respectively ‘foo.tab.cpp’ and ‘foo.tab.c++’). This @@ -10183,8 +10180,8 @@ Options controlling the global behavior of ‘bison’. Activate miscellaneous FEATUREs. FEATURE can be one of: ‘caret’ ‘diagnostics-show-caret’ - Show caret errors, in a manner similar to GCC’s - ‘-fdiagnostics-show-caret’, or Clang’s ‘-fcaret-diagnostics’. + Show caret errors, in a manner similar to GCC's + ‘-fdiagnostics-show-caret’, or Clang's ‘-fcaret-diagnostics’. The location provided with the message is used to quote the corresponding line of the source file, underlining the important part of it with carets (‘^’). Here is an example, @@ -10225,8 +10222,8 @@ Options controlling the global behavior of ‘bison’. ‘fixit’ ‘diagnostics-parseable-fixits’ - Show machine-readable fixes, in a manner similar to GCC’s and - Clang’s ‘-fdiagnostics-parseable-fixits’. + Show machine-readable fixes, in a manner similar to GCC's and + Clang's ‘-fdiagnostics-parseable-fixits’. Fix-its are generated for duplicate directives: @@ -10307,8 +10304,8 @@ Options controlling the diagnostics. %type cond "condition" - does not define “condition” as a string alias to - ‘cond’—nonterminal symbols do not have string aliases. It is + does not define "condition" as a string alias to + ‘cond’--nonterminal symbols do not have string aliases. It is rather equivalent to %nterm cond @@ -10450,7 +10447,7 @@ Options controlling the diagnostics. ‘-Wno-error=CATEGORY’ Deactivate the error treatment for this CATEGORY. However, the - warning itself won’t be disabled, or enabled, by this option. + warning itself won't be disabled, or enabled, by this option. ‘--color’ Equivalent to ‘--color=always’. @@ -10539,7 +10536,7 @@ Options changing the generated parsers. ‘-l’ ‘--no-lines’ - Don’t put any ‘#line’ preprocessor commands in the parser + Don't put any ‘#line’ preprocessor commands in the parser implementation file. Ordinarily Bison puts them in the parser implementation file so that the C compiler and debuggers will associate errors with your source file, the grammar file. This @@ -10574,11 +10571,11 @@ Options changing the generated parsers. void yyerror (const char *); As a Bison extension, additional arguments required by ‘%pure-parser’, ‘%locations’, ‘%lex-param’ and ‘%parse-param’ - are taken into account. You may disable ‘yyerror’’s prototype + are taken into account. You may disable ‘yyerror’'s prototype with ‘#define yyerror yyerror’ (as specified by POSIX), or with ‘#define YYERROR_IS_DECLARED’ (a Bison extension). Likewise for ‘yylex’. - • Imitate Yacc’s output file name conventions, so that the + • Imitate Yacc's output file name conventions, so that the parser implementation file is called ‘y.tab.c’, and the other outputs are called ‘y.output’ and ‘y.tab.h’. Do not use ‘--yacc’ just to change the output file names since it also @@ -10636,7 +10633,7 @@ Options controlling the output. ‘state’ Description of the grammar, conflicts (resolved and - unresolved), and parser’s automaton. + unresolved), and parser's automaton. ‘itemset’ Implies ‘state’ and augments the description of the automaton @@ -10645,7 +10642,7 @@ Options controlling the output. ‘lookahead’ Implies ‘state’ and augments the description of the automaton - with each rule’s lookahead set. + with each rule's lookahead set. ‘solved’ Implies ‘state’. Explain how conflicts were solved thanks to @@ -10682,7 +10679,7 @@ Options controlling the output. ‘-g [FILE]’ ‘--graph[=FILE]’ - Output a graphical representation of the parser’s automaton + Output a graphical representation of the parser's automaton computed by Bison, in Graphviz (https://www.graphviz.org/) DOT (https://www.graphviz.org/doc/info/lang.html) format. ‘FILE’ is optional. If omitted and the grammar file is ‘foo.y’, the output @@ -10690,7 +10687,7 @@ Options controlling the output. ‘-x [FILE]’ ‘--xml[=FILE]’ - Output an XML report of the parser’s automaton computed by Bison. + Output an XML report of the parser's automaton computed by Bison. ‘FILE’ is optional. If omitted and the grammar file is ‘foo.y’, the output file will be ‘foo.xml’. @@ -10749,18 +10746,18 @@ File: bison.info, Node: Yacc Library, Prev: Option Cross Key, Up: Invocation The Yacc library contains default implementations of the ‘yyerror’ and ‘main’ functions. These default implementations are normally not useful, but POSIX requires them. To use the Yacc library, link your -program with the ‘-ly’ option. Note that Bison’s implementation of the +program with the ‘-ly’ option. Note that Bison's implementation of the Yacc library is distributed under the terms of the GNU General Public License (*note Copying::). - If you use the Yacc library’s ‘yyerror’ function, you should declare + If you use the Yacc library's ‘yyerror’ function, you should declare ‘yyerror’ as follows: int yyerror (char const *); The ‘int’ value returned by this ‘yyerror’ is ignored. - The implementation of Yacc library’s ‘main’ function is: + The implementation of Yacc library's ‘main’ function is: int main (void) { @@ -10783,7 +10780,7 @@ File: bison.info, Node: Other Languages, Next: History, Prev: Invocation, Up In addition to C, Bison can generate parsers in C++, D and Java. This chapter is devoted to these languages. The reader is expected to understand how Bison works; read the introductory chapters first if you -don’t. +don't. * Menu: @@ -10832,7 +10829,7 @@ and that we generate C++. %require "3.2" %language "c++" - Let’s dive directly into the middle part: the grammar. Our input is + Let's dive directly into the middle part: the grammar. Our input is a simple list of strings, that we display once the parsing is done. %% @@ -10847,7 +10844,7 @@ a simple list of strings, that we display once the parsing is done. ; We used a vector of strings as a semantic value! To use genuine C++ -objects as semantic values—not just PODs—we cannot rely on the union +objects as semantic values--not just PODs--we cannot rely on the union that Bison uses by default to store them, we need _variants_ (*note C++ Variants::): @@ -11017,7 +11014,7 @@ argument for its constructor. A structure that contains (only) the ‘token_kind_type’ enumeration, which defines the tokens. To refer to the token ‘FOO’, use ‘yy::parser::token::FOO’. The scanner can use ‘typedef - yy::parser::token token;’ to “import” the token enumeration (*note + yy::parser::token token;’ to "import" the token enumeration (*note Calc++ Scanner::). -- Type of parser: token_kind_type @@ -11151,7 +11148,7 @@ section, and in particular, object types can be used without pointers. To enable variant-based semantic values, set the ‘%define’ variable ‘api.value.type’ to ‘variant’ (*note %define Summary::). Then ‘%union’ is ignored; instead of using the name of the fields of the ‘%union’ to -“type” the symbols, use genuine types. +"type" the symbols, use genuine types. For instance, instead of: @@ -11196,14 +11193,14 @@ Typed Midrule Actions::). from the variadic forwarding references U.... *Warning*: We do not use Boost.Variant, for two reasons. First, it -appeared unacceptable to require Boost on the user’s machine (i.e., the +appeared unacceptable to require Boost on the user's machine (i.e., the machine on which the generated parser will be compiled, not the machine on which ‘bison’ was run). Second, for each possible semantic value, Boost.Variant not only stores the value, but also a tag specifying its -type. But the parser already “knows” the type of the semantic value, so +type. But the parser already "knows" the type of the semantic value, so that would be duplicating the information. - We do not use C++17’s ‘std::variant’ either: we want to support all + We do not use C++17's ‘std::variant’ either: we want to support all the C++ standards, and of course ‘std::variant’ also stores a tag to record the current type. @@ -11363,13 +11360,13 @@ File: bison.info, Node: Exposing the Location Classes, Next: User Defined Loca ...................................... When both ‘%header’ and ‘%locations’ are enabled, Bison generates an -additional file: ‘location.hh’. If you don’t use locations outside of +additional file: ‘location.hh’. If you don't use locations outside of the parser, you may avoid its creation with ‘%define api.location.file none’. However this file is useful if, for instance, your parser builds an -abstract syntax tree decorated with locations: you may use Bison’s -‘location’ type independently of Bison’s parser. You may name the file +abstract syntax tree decorated with locations: you may use Bison's +‘location’ type independently of Bison's parser. You may name the file differently, e.g., ‘%define api.location.file "include/ast/location.hh"’: this name can have directory components, or even be absolute. The way the location file is included is controlled @@ -11489,7 +11486,7 @@ Function::), the user must define the following function. typedef symbol_kind::symbol_kind_t symbol_kind_type; -- Method on context: const symbol_type& lookahead () const - The “unexpected” token: the lookahead that caused the syntax error. + The "unexpected" token: the lookahead that caused the syntax error. -- Method on context: symbol_kind_type token () const The symbol kind of the lookahead token that caused the syntax @@ -11636,7 +11633,7 @@ expects ‘yylex’ to have the following prototype. yield additional arguments. -- Type of parser: symbol_type - A “complete symbol”, that binds together its kind, value and (when + A "complete symbol", that binds together its kind, value and (when applicable) location. -- Method on symbol_type: symbol_kind_type kind () const @@ -11763,8 +11760,8 @@ interface with.  File: bison.info, Node: Calc++ --- C++ Calculator, Next: Calc++ Parsing Driver, Up: A Complete C++ Example -10.1.8.1 Calc++ — C++ Calculator -................................ +10.1.8.1 Calc++ -- C++ Calculator +................................. Of course the grammar is dedicated to arithmetic, a single expression, possibly preceded by variable assignments. An environment containing @@ -11782,7 +11779,7 @@ File: bison.info, Node: Calc++ Parsing Driver, Next: Calc++ Parser, Prev: Cal .............................. To support a pure interface with the parser (and the scanner) the -technique of the “parsing context” is convenient: a structure containing +technique of the "parsing context" is convenient: a structure containing all the data to exchange. Since, in addition to simply launch the parsing, there are several auxiliary tasks to execute (open the file for scanning, instantiate the parser etc.), we recommend transforming the @@ -11894,7 +11891,7 @@ conversions. This example uses genuine C++ objects as semantic values, therefore, we require the variant-based storage of semantic values. To make sure we properly use it, we enable assertions. To fully benefit from -type-safety and more natural definition of “symbol”, we enable +type-safety and more natural definition of "symbol", we enable ‘api.token.constructor’. %define api.token.constructor @@ -11905,8 +11902,8 @@ Then come the declarations/inclusions needed by the semantic values. Because the parser uses the parsing driver and reciprocally, both would like to include the header of the other, which is, of course, insane. This mutual dependency will be broken using forward declarations. -Because the driver’s header needs detailed knowledge about the parser -class (in particular its inner types), it is the parser’s header which +Because the driver's header needs detailed knowledge about the parser +class (in particular its inner types), it is the parser's header which will use a forward declaration of the driver. *Note %code Summary::. %code requires { @@ -12008,8 +12005,8 @@ File: bison.info, Node: Calc++ Scanner, Next: Calc++ Top Level, Prev: Calc++ 10.1.8.4 Calc++ Scanner ....................... -In addition to standard headers, the Flex scanner includes the driver’s, -then the parser’s to get the set of defined tokens. +In addition to standard headers, the Flex scanner includes the driver's, +then the parser's to get the set of defined tokens. %{ /* -*- C++ -*- */ # include @@ -12021,8 +12018,8 @@ then the parser’s to get the set of defined tokens. # include "parser.hh" %} -Since our calculator has no ‘#include’-like feature, we don’t need -‘yywrap’. We don’t need the ‘unput’ and ‘input’ functions either, and +Since our calculator has no ‘#include’-like feature, we don't need +‘yywrap’. We don't need the ‘unput’ and ‘input’ functions either, and we parse an actual file, this is not an interactive session with the user. Finally, we enable scanner tracing. @@ -12098,8 +12095,8 @@ report errors. return yy::parser::make_NUMBER ((int) n, loc); } -Finally, because the scanner-related driver’s member-functions depend on -the scanner’s data, it is simpler to implement them in this file. +Finally, because the scanner-related driver's member-functions depend on +the scanner's data, it is simpler to implement them in this file. void driver::scan_begin () @@ -12209,7 +12206,7 @@ garbage collection. The parser will try to hold references to semantic values for as little time as needed. D parsers support ‘%printer’. An example for the output of type -‘int’, where ‘yyo’ is the parser’s debug output: +‘int’, where ‘yyo’ is the parser's debug output: %printer { yyo.write($$); } @@ -12518,7 +12515,7 @@ Summary::). returned if more input is required to finish parsing the input. If ‘api.push-pull’ is defined as ‘both’, then the generated parser -class will also implement the ‘parse’ method. This method’s body is a +class will also implement the ‘parse’ method. This method's body is a loop that repeatedly invokes the scanner and then passes the values obtained from the scanner to the ‘pushParse’ method. @@ -12581,7 +12578,7 @@ contains a single class for the parser. Contrary to C parsers, Java parsers do not use global variables; the state of the parser is always local to an instance of the parser class. -Therefore, all Java parsers are “pure”, and the ‘%define api.pure’ +Therefore, all Java parsers are "pure", and the ‘%define api.pure’ directive does nothing when used in Java. GLR parsers are currently unsupported in Java. Do not use the @@ -12598,7 +12595,7 @@ parser, so use ‘%define parse.trace’ explicitly if needed. Also, in the future the ‘%token-table’ directive might enable a public interface to access the token names and codes. - Getting a “code too large” error from the Java compiler means the + Getting a "code too large" error from the Java compiler means the code hit the 64KB bytecode per method limitation of the Java class file. Try reducing the amount of code in actions and static initializers; otherwise, report a bug so that the parser skeleton will be improved. @@ -12610,7 +12607,7 @@ File: bison.info, Node: Java Semantic Values, Next: Java Location Values, Pre --------------------------- There is no ‘%union’ directive in Java parsers. Instead, the semantic -values’ types (class names) should be specified in the ‘%nterm’ or +values' types (class names) should be specified in the ‘%nterm’ or ‘%token’ directive: %nterm expr assignment_expr term factor @@ -12776,7 +12773,7 @@ them automatically. must provide the parser with the following function: -- Static Method of YYParser: String i18n (string S) - Return the translation of S in the user’s language. As an example: + Return the translation of S in the user's language. As an example: %code { static ResourceBundle myResources @@ -13034,7 +13031,7 @@ following: 0 (success), 1 (abort), 2 (memory exhaustion), or input is required to finish parsing the grammar. If ‘api.push-pull’ is defined as ‘both’, then the generated parser -class will also implement the ‘parse’ method. This method’s body is a +class will also implement the ‘parse’ method. This method's body is a loop that repeatedly invokes the scanner and then passes the values obtained from the scanner to the ‘push_parse’ method. @@ -13265,7 +13262,7 @@ File: bison.info, Node: Yacc, Next: yacchack, Up: History 11.1 The ancestral Yacc ======================= -Bison originated as a workalike of a program called Yacc — Yet Another +Bison originated as a workalike of a program called Yacc -- Yet Another Compiler Compiler.(1) Yacc was written at Bell Labs as part of the very early development of Unix; one of its first uses was to develop the original Portable C Compiler, pcc. The same person, Steven C. Johnson, @@ -13289,13 +13286,13 @@ with less restrictive licenses and more features became available. Original Yacc became generally available when Caldera released the sources of old versions of Unix up to V7 and 32V in 2002. By that time -it had been long superseded in practical use by Bison even on Yacc’s +it had been long superseded in practical use by Bison even on Yacc's native Unix variants. ---------- Footnotes ---------- - (1) Because of the acronym, the name is sometimes given as “YACC”, -but Johnson used “Yacc” in the descriptive paper included in the Version + (1) Because of the acronym, the name is sometimes given as "YACC", +but Johnson used "Yacc" in the descriptive paper included in the Version 7 Unix Manual (https://s3.amazonaws.com/plan9-bell-labs/7thEdMan/v7vol2b.pdf). @@ -13309,7 +13306,7 @@ File: bison.info, Node: yacchack, Next: Byacc, Prev: Yacc, Up: History One of the deficiencies of original Yacc was its inability to produce reentrant parsers. This was first remedied by a set of drop-in -modifications called “yacchack”, published by Eric S. Raymond on USENET +modifications called "yacchack", published by Eric S. Raymond on USENET around 1983. This code was quickly forgotten when zoo and Berkeley Yacc became available a few years later. @@ -13320,14 +13317,14 @@ File: bison.info, Node: Byacc, Next: Bison, Prev: yacchack, Up: History ================== Berkeley Yacc was originated in 1985 by Robert Corbett (*note Corbett -1984::). It was originally named “zoo”, but by October 1989 it became +1984::). It was originally named "zoo", but by October 1989 it became known as Berkeley Yacc or byacc. Berkeley Yacc had three advantages over the ancestral Yacc: it generated faster parsers, it could generate reentrant parsers, and the source code was released to the public domain rather than being under an AT&T proprietary license. The better performance came from implementing -techniques from DeRemer and Penello’s seminal paper on LALR parsing +techniques from DeRemer and Penello's seminal paper on LALR parsing (*note DeRemer 1982::). Use of byacc spread rapidly due to its public domain license. @@ -13341,12 +13338,12 @@ File: bison.info, Node: Bison, Next: Other Ungulates, Prev: Byacc, Up: Histo ========== Robert Corbett actually wrote two (closely related) LALR parsers in -1985, both using the DeRemer/Penello techniques. One was “zoo”, the -other was “Byson”. In 1987 Richard Stallman began working on Byson; the +1985, both using the DeRemer/Penello techniques. One was "zoo", the +other was "Byson". In 1987 Richard Stallman began working on Byson; the name changed to Bison and the interface became Yacc-compatible. The main visible difference between Yacc and Byson/Bison at the time -of Byson’s first release is that Byson supported the ‘@N’ construct +of Byson's first release is that Byson supported the ‘@N’ construct (giving access to the starting and ending line number and character number associated with any of the symbols in the current rule). @@ -13391,8 +13388,8 @@ the early ports are extinct along with the languages that hosted them; others have been superseded by parser skeletons shipped with Bison. However, independent implementations persist. One of the best-known -still in use is David Beazley’s “PLY” (Python Lex-Yacc) for Python. -Another is goyacc, supporting the Go language. An “ocamlyacc” is +still in use is David Beazley's "PLY" (Python Lex-Yacc) for Python. +Another is goyacc, supporting the Go language. An "ocamlyacc" is shipped as part of the Ocaml compiler suite.  @@ -13574,7 +13571,7 @@ manipulate multiple input buffers. If your Flex-generated scanner uses start conditions (*note Start conditions: (flex)Start conditions.), you might also want to reset the -scanner’s state, i.e., go back to the initial start condition, through a +scanner's state, i.e., go back to the initial start condition, through a call to ‘BEGIN (0)’.  @@ -13587,7 +13584,7 @@ File: bison.info, Node: Strings are Destroyed, Next: Implementing Gotos/Loops, them. Instead of reporting ‘"foo", "bar"’, it reports ‘"bar", "bar"’, or even ‘"foo\nbar", "bar"’. - This error is probably the single most frequent “bug report” sent to + This error is probably the single most frequent "bug report" sent to Bison lists, but is only concerned with a misunderstanding of the role of the scanner. Consider the following Lex code: @@ -13639,9 +13636,9 @@ File: bison.info, Node: Implementing Gotos/Loops, Next: Multiple start-symbols functions, but how can I implement gotos, or loops? Although very pedagogical, the examples included in the document blur -the distinction to make between the parser—whose job is to recover the +the distinction to make between the parser--whose job is to recover the structure of a text and to transmit it to subsequent modules of the -program—and the processing (such as the execution) of this structure. +program--and the processing (such as the execution) of this structure. This works well with so called straight line programs, i.e., precisely those that have a straightforward execution model: execute simple instructions one after the others. @@ -13709,7 +13706,7 @@ File: bison.info, Node: Secure? Conform?, Next: Enabling Relocatability, Prev Is Bison secure? Does it conform to POSIX? - If you’re looking for a guarantee or certification, we don’t provide + If you're looking for a guarantee or certification, we don't provide it. However, Bison is intended to be a reliable program that conforms to the POSIX specification for Yacc. If you run into problems, please send us a bug report. @@ -13728,7 +13725,7 @@ through ‘configure; make; make install’ with all its dependencies, options, and hurdles. Most package management systems, that allow the user to install -pre-built binaries of the packages, solve the “ease of installation” +pre-built binaries of the packages, solve the "ease of installation" problem, but they hardwire path names, usually to ‘/usr’ or ‘/usr/local’. This means that users need root privileges to install a binary package, and prevents installing two different versions of the @@ -13760,7 +13757,7 @@ also do not recommend prefixes that might be behind an automounter (e.g. ‘$HOME/inst$$’) because of the performance impact of directory searching. - Here’s a sample installation run that takes into account all these + Here's a sample installation run that takes into account all these recommendations: ./configure --enable-relocatable --prefix=/nonexistent @@ -13779,29 +13776,29 @@ executes the real program).  File: bison.info, Node: I can't build Bison, Next: Where can I find help?, Prev: Enabling Relocatability, Up: FAQ -13.8 I can’t build Bison +13.8 I can't build Bison ======================== - I can’t build Bison because ‘make’ complains that ‘msgfmt’ is not + I can't build Bison because ‘make’ complains that ‘msgfmt’ is not found. What should I do? Like most GNU packages with internationalization support, that feature is turned on by default. If you have problems building in the -‘po’ subdirectory, it indicates that your system’s internationalization +‘po’ subdirectory, it indicates that your system's internationalization support is lacking. You can re-configure Bison with ‘--disable-nls’ to turn off this support, or you can install GNU gettext from and re-configure Bison. See the file ‘ABOUT-NLS’ for more information. - I can’t build Bison because my C compiler is too old. + I can't build Bison because my C compiler is too old. Except for GLR parsers (which require C99), the C code that Bison generates requires only C89 or later. However, Bison itself requires -common C99 features such as declarations after statements. Bison’s +common C99 features such as declarations after statements. Bison's ‘configure’ script attempts to enable C99 (or later) support on compilers that default to pre-C99. If your compiler lacks these C99 features entirely, GCC may well be a better choice; or you can try -upgrading to your compiler’s latest version. +upgrading to your compiler's latest version.  File: bison.info, Node: Where can I find help?, Next: Bug Reports, Prev: I can't build Bison, Up: FAQ @@ -13809,7 +13806,7 @@ File: bison.info, Node: Where can I find help?, Next: Bug Reports, Prev: I ca 13.9 Where can I find help? =========================== - I’m having trouble using Bison. Where can I find help? + I'm having trouble using Bison. Where can I find help? First, read this fine manual. Beyond that, you can send mail to . This mailing list is intended to be populated @@ -13842,7 +13839,7 @@ to edit or add anything). The smaller and simpler the grammar, the easier it will be to fix the bug. Include information about your compilation environment, including -your operating system’s name and version and your compiler’s name and +your operating system's name and version and your compiler's name and version. If you have trouble compiling, you should also include a transcript of the build session, starting with the invocation of ‘configure’. Depending on the nature of the bug, you may be asked to @@ -13862,7 +13859,7 @@ File: bison.info, Node: More Languages, Next: Beta Testing, Prev: Bug Reports Will Bison ever have C++ and Java support? How about INSERT YOUR FAVORITE LANGUAGE HERE? - C++, D and Java are supported. We’d love to add other languages; + C++, D and Java are supported. We'd love to add other languages; contributions are welcome.  @@ -13873,7 +13870,7 @@ File: bison.info, Node: Beta Testing, Next: Mailing Lists, Prev: More Languag What is involved in being a beta tester? - It’s not terribly involved. Basically, you would download a test + It's not terribly involved. Basically, you would download a test release, compile it, and use it to build and run a parser or two. After that, you would submit either a bug report or a message saying that everything is okay. It is important to report successes as well as @@ -13959,7 +13956,7 @@ Appendix A Bison Symbols Comments, as in C/C++. -- Delimiter: : - Separates a rule’s result from its components. *Note Rules::. + Separates a rule's result from its components. *Note Rules::. -- Delimiter: ; Terminates a rule. *Note Rules::. @@ -13998,7 +13995,7 @@ Appendix A Bison Symbols -- Directive: %define VARIABLE VALUE -- Directive: %define VARIABLE {VALUE} -- Directive: %define VARIABLE "VALUE" - Define a variable to adjust Bison’s behavior. *Note %define + Define a variable to adjust Bison's behavior. *Note %define Summary::. -- Directive: %defines @@ -14242,7 +14239,7 @@ Appendix A Bison Symbols External variable in which ‘yylex’ should place the line and column numbers associated with a token. (In a pure parser, it is a local variable within ‘yyparse’, and its address is passed to ‘yylex’.) - You can ignore this variable if you don’t use the ‘@’ feature in + You can ignore this variable if you don't use the ‘@’ feature in the grammar actions. *Note Token Locations::. In semantic actions, it stores the location of the lookahead token. *Note Actions and Locations::. @@ -14352,7 +14349,7 @@ Accepting state A state whose only action is the accept action. The accepting state is thus a consistent state. *Note Understanding::. -Backus-Naur Form (BNF; also called “Backus Normal Form”) +Backus-Naur Form (BNF; also called "Backus Normal Form") Formal method of specifying context-free grammars originally proposed by John Backus, and slightly improved by Peter Naur in his 1960-01-02 committee document contributing to what became the Algol @@ -14401,7 +14398,7 @@ Empty string character string of length zero. Finite-state stack machine - A “machine” that has discrete states in which it is said to exist + A "machine" that has discrete states in which it is said to exist at each instant in time. As input to the machine is processed, the machine moves from state to state as specified by the logic of the machine. In the case of the parser, the input is the language @@ -14411,14 +14408,14 @@ Finite-state stack machine Generalized LR (GLR) A parsing algorithm that can handle all context-free grammars, including those that are not LR(1). It resolves situations that - Bison’s deterministic parsing algorithm cannot by effectively + Bison's deterministic parsing algorithm cannot by effectively splitting off multiple parsers, trying all possible parsers, and discarding those that fail in the light of additional right context. *Note Generalized LR Parsing::. Grouping A language construct that is (in general) grammatically divisible; - for example, ‘expression’ or ‘declaration’ in C. *Note Language + for example, 'expression' or 'declaration' in C. *Note Language and Grammar::. IELR(1) (Inadequacy Elimination LR(1)) @@ -14427,7 +14424,7 @@ IELR(1) (Inadequacy Elimination LR(1)) with the full language-recognition power of canonical LR(1) but with nearly the same number of parser states as LALR(1). This reduction in parser states is often an order of magnitude. More - importantly, because canonical LR(1)’s extra parser states may + importantly, because canonical LR(1)'s extra parser states may contain duplicate conflicts in the case of non-LR(1) grammars, the number of conflicts for IELR(1) is often an order of magnitude less as well. This can significantly reduce the complexity of @@ -14441,25 +14438,25 @@ Input stream A continuous flow of data between devices or programs. Kind - “Token” and “symbol” are each overloaded to mean either a grammar + "Token" and "symbol" are each overloaded to mean either a grammar symbol (kind) or all parse info (kind, value, location) associated with occurrences of that grammar symbol from the input. To disambiguate, - • we use “token kind” and “symbol kind” to mean both grammar + • we use "token kind" and "symbol kind" to mean both grammar symbols and the values that represent them in a base programming language (C, C++, etc.). The names of the types of these values are typically ‘token_kind_t’, or ‘token_kind_type’, or ‘TokenKind’, depending on the programming language. - • we use “token” and “symbol” without the word “kind” to mean - parsed occurrences, and we append the word “type” to refer to + • we use "token" and "symbol" without the word "kind" to mean + parsed occurrences, and we append the word "type" to refer to the types that represent them in a base programming language. - In summary: When you see “kind”, interpret “symbol” or “token” to - mean a _grammar symbol_. When you don’t see “kind” (including when - you see “type”), interpret “symbol” or “token” to mean a _parsed + In summary: When you see "kind", interpret "symbol" or "token" to + mean a _grammar symbol_. When you don't see "kind" (including when + you see "type"), interpret "symbol" or "token" to mean a _parsed symbol_. LAC (Lookahead Correction) @@ -14594,7 +14591,7 @@ Token kind Unreachable state A parser state to which there does not exist a sequence of - transitions from the parser’s start state. A state can become + transitions from the parser's start state. A state can become unreachable during conflict resolution. *Note Unreachable States::. @@ -14622,7 +14619,7 @@ Appendix C GNU Free Documentation License author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. - This License is a kind of “copyleft”, which means that derivative + This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. @@ -14643,18 +14640,18 @@ Appendix C GNU Free Documentation License be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The - “Document”, below, refers to any such manual or work. Any member - of the public is a licensee, and is addressed as “you”. You accept + "Document", below, refers to any such manual or work. Any member + of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. - A “Modified Version” of the Document means any work containing the + A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. - A “Secondary Section” is a named appendix or a front-matter section + A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the - publishers or authors of the Document to the Document’s overall + publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not @@ -14663,7 +14660,7 @@ Appendix C GNU Free Documentation License of legal, commercial, philosophical, ethical or political position regarding them. - The “Invariant Sections” are certain Secondary Sections whose + The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it @@ -14671,13 +14668,13 @@ Appendix C GNU Free Documentation License contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. - The “Cover Texts” are certain short passages of text that are + The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. - A “Transparent” copy of the Document means a machine-readable copy, + A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed @@ -14689,7 +14686,7 @@ Appendix C GNU Free Documentation License been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not - “Transparent” is called “Opaque”. + "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, @@ -14702,23 +14699,23 @@ Appendix C GNU Free Documentation License the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. - The “Title Page” means, for a printed book, the title page itself, + The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For - works in formats which do not have any title page as such, “Title - Page” means the text near the most prominent appearance of the - work’s title, preceding the beginning of the body of the text. + works in formats which do not have any title page as such, "Title + Page" means the text near the most prominent appearance of the + work's title, preceding the beginning of the body of the text. - The “publisher” means any person or entity that distributes copies + The "publisher" means any person or entity that distributes copies of the Document to the public. - A section “Entitled XYZ” means a named subunit of the Document + A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as - “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) - To “Preserve the Title” of such a section when you modify the - Document means that it remains a section “Entitled XYZ” according + "Acknowledgements", "Dedications", "Endorsements", or "History".) + To "Preserve the Title" of such a section when you modify the + Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice @@ -14748,7 +14745,7 @@ Appendix C GNU Free Documentation License If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and - the Document’s license notice requires Cover Texts, you must + the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly @@ -14820,15 +14817,15 @@ Appendix C GNU Free Documentation License the Addendum below. G. Preserve in that license notice the full lists of Invariant - Sections and required Cover Texts given in the Document’s + Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. - I. Preserve the section Entitled “History”, Preserve its Title, + I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the - Title Page. If there is no section Entitled “History” in the + Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the @@ -14838,12 +14835,12 @@ Appendix C GNU Free Documentation License for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the - “History” section. You may omit a network location for a work + "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. - K. For any section Entitled “Acknowledgements” or “Dedications”, + K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. @@ -14852,11 +14849,11 @@ Appendix C GNU Free Documentation License in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. - M. Delete any section Entitled “Endorsements”. Such a section + M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled - “Endorsements” or to conflict in title with any Invariant + "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. @@ -14865,15 +14862,15 @@ Appendix C GNU Free Documentation License appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their - titles to the list of Invariant Sections in the Modified Version’s + titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. - You may add a section Entitled “Endorsements”, provided it contains + You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various - parties—for example, statements of peer review or that the text has - been approved by an organization as the authoritative definition of - a standard. + parties--for example, statements of peer review or that the text + has been approved by an organization as the authoritative + definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of @@ -14911,10 +14908,10 @@ Appendix C GNU Free Documentation License combined work. In the combination, you must combine any sections Entitled - “History” in the various original documents, forming one section - Entitled “History”; likewise combine any sections Entitled - “Acknowledgements”, and any sections Entitled “Dedications”. You - must delete all sections Entitled “Endorsements.” + "History" in the various original documents, forming one section + Entitled "History"; likewise combine any sections Entitled + "Acknowledgements", and any sections Entitled "Dedications". You + must delete all sections Entitled "Endorsements." 6. COLLECTIONS OF DOCUMENTS @@ -14935,16 +14932,16 @@ Appendix C GNU Free Documentation License A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a - storage or distribution medium, is called an “aggregate” if the + storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the - legal rights of the compilation’s users beyond what the individual + legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half - of the entire aggregate, the Document’s Cover Texts may be placed + of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket @@ -14966,8 +14963,8 @@ Appendix C GNU Free Documentation License this License or a notice or disclaimer, the original version will prevail. - If a section in the Document is Entitled “Acknowledgements”, - “Dedications”, or “History”, the requirement (section 4) to + If a section in the Document is Entitled "Acknowledgements", + "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. @@ -15008,7 +15005,7 @@ Appendix C GNU Free Documentation License Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered - version of this License “or any later version” applies to it, you + version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the @@ -15016,29 +15013,29 @@ Appendix C GNU Free Documentation License choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that - proxy’s public statement of acceptance of a version permanently + proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Document. 11. RELICENSING - “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any + "Massive Multiauthor Collaboration Site" (or "MMC Site") means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. - A “Massive Multiauthor Collaboration” (or “MMC”) contained in the + A "Massive Multiauthor Collaboration" (or "MMC") contained in the site means any set of copyrightable works thus published on the MMC site. - “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 + "CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization. - “Incorporate” means to publish or republish a Document, in whole or + "Incorporate" means to publish or republish a Document, in whole or in part, as part of another Document. - An MMC is “eligible for relicensing” if it is licensed under this + An MMC is "eligible for relicensing" if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover @@ -15065,7 +15062,7 @@ notices just after the title page: Free Documentation License''. If you have Invariant Sections, Front-Cover Texts and Back-Cover -Texts, replace the “with...Texts.” line with this: +Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts @@ -15088,7 +15085,7 @@ Bibliography [Corbett 1984] Robert Paul Corbett, Static Semantics in Compiler Error Recovery - Ph.D. Dissertation, Report No. UCB/CSD 85/251, Department of + Ph.D. Dissertation, Report No. UCB/CSD 85/251, Department of Electrical Engineering and Computer Science, Compute Science Division, University of California, Berkeley, California (June 1985). @@ -15097,7 +15094,7 @@ Bibliography Joel E. Denny and Brian A. Malloy, IELR(1): Practical LR(1) Parser Tables for Non-LR(1) Grammars with Conflict Resolution, in ‘Proceedings of the 2008 ACM Symposium on Applied Computing’ - (SAC’08), ACM, New York, NY, USA, pp. 240–245. + (SAC'08), ACM, New York, NY, USA, pp. 240-245. [Denny 2010 May] @@ -15110,32 +15107,32 @@ Bibliography Joel E. Denny and Brian A. Malloy, The IELR(1) Algorithm for Generating Minimal LR(1) Parser Tables for Non-LR(1) Grammars with Conflict Resolution, in ‘Science of Computer Programming’, Vol. 75, - Issue 11 (November 2010), pp. 943–979. + Issue 11 (November 2010), pp. 943-979. [DeRemer 1982] Frank DeRemer and Thomas Pennello, Efficient Computation of LALR(1) Look-Ahead Sets, in ‘ACM Transactions on Programming Languages and - Systems’, Vol. 4, No. 4 (October 1982), pp. 615–649. + Systems’, Vol. 4, No. 4 (October 1982), pp. 615-649. [Isradisaikul 2015] Chinawat Isradisaikul, Andrew Myers, Finding Counterexamples from Parsing Conflicts, in ‘Proceedings of the 36th ACM SIGPLAN Conference on Programming Language Design and Implementation’ (PLDI - ’15), ACM, pp. 555–564. + '15), ACM, pp. 555-564. [Johnson 1978] Steven C. Johnson, A portable compiler: theory and practice, in ‘Proceedings of the 5th ACM SIGACT-SIGPLAN symposium on Principles - of programming languages’ (POPL ’78), pp. 97–104. + of programming languages’ (POPL '78), pp. 97-104. . [Knuth 1965] Donald E. Knuth, On the Translation of Languages from Left to Right, in ‘Information and Control’, Vol. 8, Issue 6 (December - 1965), pp. 607–639. + 1965), pp. 607-639. [Scott 2000] @@ -15154,39 +15151,42 @@ Index of Terms [index] * Menu: -* $$: Actions. (line 6) -* $$ <1>: Java Action Features. - (line 20) -* $$ <2>: Action Features. (line 9) -* $$ <3>: D Action Features. (line 9) -* $$ <4>: Table of Symbols. (line 28) -* $$: Java Action Features. - (line 28) -* $$ <1>: Action Features. (line 17) -* $N: Java Action Features. - (line 16) -* $N <1>: Action Features. (line 21) -* $@N: Midrule Action Translation. +* ;: Table of Symbols. (line 65) +* :: Table of Symbols. (line 62) +* @[NAME]: Actions and Locations. (line 6) -* $@N <1>: Table of Symbols. (line 23) -* $accept: Table of Symbols. (line 84) -* $end: Table of Symbols. (line 122) -* $N: Actions. (line 6) -* $N <1>: Java Action Features. - (line 12) -* $N <2>: Action Features. (line 13) -* $N <3>: D Action Features. (line 13) -* $N <4>: Table of Symbols. (line 32) -* $NAME: Actions. (line 6) -* $NAME <1>: Table of Symbols. (line 36) -* $undefined: Table of Symbols. (line 253) -* $[NAME]: Actions. (line 6) -* $[NAME] <1>: Table of Symbols. (line 37) +* @[NAME] <1>: Table of Symbols. (line 19) +* @$: Actions and Locations. + (line 6) +* @$ <1>: Java Action Features. + (line 38) +* @$ <2>: Action Features. (line 99) +* @$ <3>: Table of Symbols. (line 6) +* @N: Midrule Action Translation. + (line 6) +* @N <1>: Actions and Locations. + (line 6) +* @N <2>: Java Action Features. + (line 34) +* @N <3>: Action Features. (line 104) +* @N <4>: Action Features. (line 105) +* @N <5>: Table of Symbols. (line 10) +* @N <6>: Table of Symbols. (line 11) +* @NAME: Actions and Locations. + (line 6) +* @NAME <1>: Table of Symbols. (line 18) +* /*: Table of Symbols. (line 58) +* /* ... */: Grammar Outline. (line 6) +* //: Table of Symbols. (line 59) +* // ...: Grammar Outline. (line 6) +* %?: Semantic Predicates. (line 6) +* %?{EXPRESSION}: Table of Symbols. (line 50) +* %{: Java Declarations Summary. + (line 51) +* %{CODE%}: Table of Symbols. (line 45) * %%: Java Declarations Summary. (line 47) * %% <1>: Table of Symbols. (line 41) -* %?: Semantic Predicates. (line 6) -* %?{EXPRESSION}: Table of Symbols. (line 50) * %code: Prologue Alternatives. (line 6) * %code <1>: Decl Summary. (line 52) @@ -15443,45 +15443,42 @@ Index of Terms * %union <3>: Table of Symbols. (line 258) * %verbose: Decl Summary. (line 241) * %yacc: Decl Summary. (line 246) -* %{: Java Declarations Summary. - (line 51) -* %{CODE%}: Table of Symbols. (line 45) -* /*: Table of Symbols. (line 58) -* /* ... */: Grammar Outline. (line 6) -* //: Table of Symbols. (line 59) -* // ...: Grammar Outline. (line 6) -* :: Table of Symbols. (line 62) -* ;: Table of Symbols. (line 65) * <*>: Destructor Decl. (line 6) * <*> <1>: Printer Decl. (line 6) * <*> <2>: Table of Symbols. (line 72) * <>: Destructor Decl. (line 6) * <> <1>: Printer Decl. (line 6) * <> <2>: Table of Symbols. (line 78) -* @$: Actions and Locations. - (line 6) -* @$ <1>: Java Action Features. - (line 38) -* @$ <2>: Action Features. (line 99) -* @$ <3>: Table of Symbols. (line 6) -* @N: Midrule Action Translation. - (line 6) -* @N <1>: Actions and Locations. - (line 6) -* @N <2>: Java Action Features. - (line 34) -* @N <3>: Action Features. (line 104) -* @N <4>: Action Features. (line 105) -* @N <5>: Table of Symbols. (line 10) -* @N <6>: Table of Symbols. (line 11) -* @NAME: Actions and Locations. - (line 6) -* @NAME <1>: Table of Symbols. (line 18) -* @[NAME]: Actions and Locations. - (line 6) -* @[NAME] <1>: Table of Symbols. (line 19) * |: Rules Syntax. (line 48) * | <1>: Table of Symbols. (line 68) +* $[NAME]: Actions. (line 6) +* $[NAME] <1>: Table of Symbols. (line 37) +* $@N: Midrule Action Translation. + (line 6) +* $@N <1>: Table of Symbols. (line 23) +* $$: Java Action Features. + (line 28) +* $$ <1>: Action Features. (line 17) +* $N: Java Action Features. + (line 16) +* $N <1>: Action Features. (line 21) +* $$: Actions. (line 6) +* $$ <1>: Java Action Features. + (line 20) +* $$ <2>: Action Features. (line 9) +* $$ <3>: D Action Features. (line 9) +* $$ <4>: Table of Symbols. (line 28) +* $accept: Table of Symbols. (line 84) +* $end: Table of Symbols. (line 122) +* $N: Actions. (line 6) +* $N <1>: Java Action Features. + (line 12) +* $N <2>: Action Features. (line 13) +* $N <3>: D Action Features. (line 13) +* $N <4>: Table of Symbols. (line 32) +* $NAME: Actions. (line 6) +* $NAME <1>: Table of Symbols. (line 36) +* $undefined: Table of Symbols. (line 253) * abstract syntax tree: Implementing Gotos/Loops. (line 17) * accepting state: Understanding. (line 185) @@ -15517,6 +15514,8 @@ Index of Terms * Bison parser algorithm: Algorithm. (line 6) * Bison symbols, table of: Table of Symbols. (line 6) * Bison utility: Bison Parser. (line 6) +* BISON_I18N: Enabling I18n. (line 18) +* BISON_LOCALEDIR: Enabling I18n. (line 18) * bison-i18n.m4: Enabling I18n. (line 11) * bison-po: Internationalization. (line 6) @@ -15526,8 +15525,6 @@ Index of Terms * bisonVersion of YYParser: D Parser Interface. (line 69) * bisonVersion of YYParser <1>: Java Parser Interface. (line 91) -* BISON_I18N: Enabling I18n. (line 18) -* BISON_LOCALEDIR: Enabling I18n. (line 18) * BNF: Language and Grammar. (line 16) * braced code: Rules Syntax. (line 29) @@ -15567,19 +15564,19 @@ Index of Terms (line 6) * controlling function: Rpcalc Main. (line 6) * core, item set: Understanding. (line 132) +* counter_type: C++ position. (line 11) * counterexample, nonunifying: Glossary. (line 31) * counterexample, unifying: Glossary. (line 31) * counterexamples: Counterexamples. (line 6) -* counter_type: C++ position. (line 11) * dangling else: Shift/Reduce. (line 6) * data type of locations: Location Type. (line 6) * data types in actions: Action Types. (line 6) * data types of semantic values: Value Type. (line 6) -* debugging: Tracing. (line 6) * debug_level on parser: C++ Parser Interface. (line 91) * debug_stream on parser: C++ Parser Interface. (line 86) +* debugging: Tracing. (line 6) * declaration summary: Decl Summary. (line 6) * declarations: Prologue. (line 6) * declarations section: Prologue. (line 6) @@ -15781,10 +15778,10 @@ Index of Terms (line 27) * location tracking calculator: Location Tracking Calc. (line 6) -* location, textual: Locations. (line 6) -* location, textual <1>: Tracking Locations. (line 6) * location_type: C++ Parser Interface. (line 49) +* location, textual: Locations. (line 6) +* location, textual <1>: Tracking Locations. (line 6) * lookahead correction: LAC. (line 6) * lookahead on context: C++ Parser Context. (line 43) * lookahead token: Lookahead. (line 6) @@ -15824,6 +15821,10 @@ Index of Terms * nonunifying counterexample: Glossary. (line 31) * operator precedence: Precedence. (line 6) * operator precedence, declaring: Precedence Decl. (line 6) +* operator- on location: C++ location. (line 30) +* operator- on position: C++ position. (line 45) +* operator-= on location: C++ location. (line 31) +* operator-= on position: C++ position. (line 44) * operator!= on location: C++ location. (line 43) * operator!= on position: C++ position. (line 49) * operator() on parser: C++ Parser Interface. @@ -15834,10 +15835,6 @@ Index of Terms * operator+= on location: C++ location. (line 29) * operator+= on location <1>: C++ location. (line 35) * operator+= on position: C++ position. (line 42) -* operator- on location: C++ location. (line 30) -* operator- on position: C++ position. (line 45) -* operator-= on location: C++ location. (line 31) -* operator-= on position: C++ position. (line 44) * operator<<: C++ position. (line 52) * operator<< <1>: C++ location. (line 47) * operator== on location: C++ location. (line 42) @@ -15875,14 +15872,14 @@ Index of Terms * pure parser: Pure Decl. (line 6) * push parser: Push Decl. (line 6) * push parser <1>: Push Decl. (line 6) -* pushParse on YYParser: D Push Parser Interface. - (line 18) * push_parse on YYParser: Java Push Parser Interface. (line 18) * push_parse on YYParser <1>: Java Push Parser Interface. (line 19) * push_parse on YYParser <2>: Java Push Parser Interface. (line 21) +* pushParse on YYParser: D Push Parser Interface. + (line 18) * questions: FAQ. (line 6) * recovering: Java Action Features. (line 54) @@ -15897,11 +15894,11 @@ Index of Terms * reduce/reduce conflicts <2>: Merging GLR Parses. (line 6) * reduction: Algorithm. (line 6) * reentrant parser: Pure Decl. (line 6) +* report_syntax_error on parser: C++ Parser Context. (line 9) * reportSyntaxError on Lexer: Java Scanner Interface. (line 59) * reportSyntaxError(YYParser.Context on Lexer: D Scanner Interface. (line 34) -* report_syntax_error on parser: C++ Parser Context. (line 9) * requiring a version of Bison: Require Decl. (line 6) * Reverse Polish Notation: RPN Calc. (line 6) * right recursion: Recursion. (line 17) @@ -15917,6 +15914,10 @@ Index of Terms * Semantic predicates in GLR parsers: Semantic Predicates. (line 6) * semantic value: Semantic Values. (line 6) * semantic value type: Value Type. (line 6) +* set_debug_level on parser: C++ Parser Interface. + (line 92) +* set_debug_stream on parser: C++ Parser Interface. + (line 87) * setDebugLevel on YYParser: Java Parser Interface. (line 87) * setDebugLevel(int on YYParser: D Parser Interface. (line 65) @@ -15926,10 +15927,6 @@ Index of Terms * setErrorVerbose on YYParser: Java Parser Interface. (line 65) * setErrorVerbose(boolean on YYParser: D Parser Interface. (line 44) -* set_debug_level on parser: C++ Parser Interface. - (line 92) -* set_debug_stream on parser: C++ Parser Interface. - (line 87) * shift/reduce conflicts: GLR Parsers. (line 6) * shift/reduce conflicts <1>: Simple GLR Parsers. (line 6) * shift/reduce conflicts <2>: Shift/Reduce. (line 6) @@ -15950,13 +15947,6 @@ Index of Terms * suppressing conflict warnings: Expect Decl. (line 6) * symbol: Symbols. (line 6) * symbol table example: Mfcalc Symbol Table. (line 6) -* SymbolKind: D Parser Context Interface. - (line 9) -* SymbolKind <1>: Java Parser Context Interface. - (line 9) -* symbols (abstract): Language and Grammar. - (line 46) -* symbols in Bison, table of: Table of Symbols. (line 6) * symbol_kind_type: C++ Parser Context. (line 19) * symbol_name on parser: C++ Parser Context. (line 68) * symbol_type: Complete Symbols. (line 17) @@ -15964,6 +15954,13 @@ Index of Terms * symbol_type on parser::symbol_type <1>: Complete Symbols. (line 34) * symbol_type on parser::symbol_type <2>: Complete Symbols. (line 36) * symbol_type on parser::symbol_type <3>: Complete Symbols. (line 38) +* SymbolKind: D Parser Context Interface. + (line 9) +* SymbolKind <1>: Java Parser Context Interface. + (line 9) +* symbols (abstract): Language and Grammar. + (line 46) +* symbols in Bison, table of: Table of Symbols. (line 6) * syntactic grouping: Language and Grammar. (line 46) * syntax error: Error Reporting Function. @@ -15978,8 +15975,8 @@ Index of Terms * terminal symbol: Symbols. (line 6) * textual location: Locations. (line 6) * textual location <1>: Tracking Locations. (line 6) -* this(Lexer on YYParser: D Parser Interface. (line 34) * this(LEX_PARAM, on YYParser: D Parser Interface. (line 29) +* this(Lexer on YYParser: D Parser Interface. (line 34) * this(Position on Location: D Location Values. (line 14) * this(Position on Location <1>: D Location Values. (line 18) * token: Language and Grammar. @@ -15989,9 +15986,9 @@ Index of Terms * token kind: Symbols. (line 6) * token kind names, declaring: Token Decl. (line 6) * token on context: C++ Parser Context. (line 46) -* token, useless: Understanding. (line 56) * token_kind_type: C++ Parser Interface. (line 21) +* token, useless: Understanding. (line 56) * toString on Location: Java Location Values. (line 30) * toString() on Location: D Location Values. (line 21) @@ -16011,9 +16008,9 @@ Index of Terms * value types, declaring <2>: Structured Value Type. (line 6) * value types, nonterminals, declaring: Type Decl. (line 6) -* value, semantic: Semantic Values. (line 6) * value_type: C++ Parser Interface. (line 46) +* value, semantic: Semantic Values. (line 6) * version: Versioning. (line 6) * version requirement: Require Decl. (line 6) * warnings, preventing: Expect Decl. (line 6) @@ -16181,270 +16178,269 @@ Index of Terms * YYUNDEF: Table of Symbols. (line 443) * zoo: Bison. (line 6) -  Tag Table: -Node: Top1066 -Node: Introduction18219 -Node: Conditions19794 -Node: Copying21717 -Node: Concepts59459 -Node: Language and Grammar60655 -Node: Grammar in Bison66769 -Node: Semantic Values68685 -Node: Semantic Actions70821 -Node: GLR Parsers71998 -Node: Simple GLR Parsers74773 -Node: Merging GLR Parses81253 -Ref: Merging GLR Parses-Footnote-186591 -Node: GLR Semantic Actions86732 -Node: Semantic Predicates89333 -Node: Locations91786 -Node: Bison Parser93264 -Node: Stages96464 -Node: Grammar Layout97689 -Node: Examples99051 -Node: RPN Calc100544 -Ref: RPN Calc-Footnote-1101596 -Node: Rpcalc Declarations101674 -Node: Rpcalc Rules103730 -Node: Rpcalc Input105629 -Node: Rpcalc Line107208 -Node: Rpcalc Exp108360 -Node: Rpcalc Lexer110373 -Node: Rpcalc Main113070 -Node: Rpcalc Error113481 -Node: Rpcalc Generate114509 -Node: Rpcalc Compile115757 -Node: Infix Calc116721 -Ref: Infix Calc-Footnote-1119567 -Node: Simple Error Recovery119720 -Node: Location Tracking Calc121658 -Node: Ltcalc Declarations122358 -Node: Ltcalc Rules123453 -Node: Ltcalc Lexer125295 -Node: Multi-function Calc127636 -Ref: Multi-function Calc-Footnote-1129413 -Node: Mfcalc Declarations129491 -Node: Mfcalc Rules131515 -Node: Mfcalc Symbol Table132793 -Node: Mfcalc Lexer136255 -Node: Mfcalc Main138828 -Node: Exercises139704 -Node: Grammar File140231 -Node: Grammar Outline141081 -Node: Prologue141939 -Node: Prologue Alternatives143740 -Ref: Prologue Alternatives-Footnote-1153440 -Node: Bison Declarations153545 -Node: Grammar Rules153955 -Node: Epilogue154411 -Node: Symbols155462 -Node: Rules162497 -Node: Rules Syntax162812 -Node: Empty Rules164877 -Node: Recursion165964 -Node: Semantics167622 -Node: Value Type168928 -Node: Multiple Types170216 -Node: Type Generation171666 -Node: Union Decl173596 -Node: Structured Value Type174989 -Node: Actions176015 -Node: Action Types179899 -Node: Midrule Actions181252 -Node: Using Midrule Actions181906 -Node: Typed Midrule Actions185445 -Node: Midrule Action Translation186995 -Node: Midrule Conflicts189488 -Node: Tracking Locations192097 -Node: Location Type192829 -Node: Actions and Locations194352 -Node: Printing Locations196734 -Node: Location Default Action197496 -Node: Named References201033 -Node: Declarations203630 -Node: Require Decl205319 -Node: Token Decl205833 -Node: Precedence Decl208750 -Node: Type Decl211026 -Node: Symbol Decls211977 -Node: Initial Action Decl212932 -Node: Destructor Decl213747 -Node: Printer Decl219393 -Node: Expect Decl221662 -Node: Start Decl225663 -Node: Pure Decl226057 -Node: Push Decl227805 -Node: Decl Summary232244 -Ref: %header234925 -Node: %define Summary243258 -Ref: api-filename-type245169 -Ref: api-token-prefix256117 -Node: %code Summary268123 -Node: Multiple Parsers272379 -Node: Interface276239 -Node: Parser Function277348 -Node: Push Parser Interface279841 -Ref: yypstate_new280226 -Ref: yypstate_delete280667 -Ref: yypush_parse281081 -Ref: yypull_parse282093 -Node: Lexical283096 -Node: Calling Convention284671 -Node: Special Tokens286200 -Node: Tokens from Literals287639 -Node: Token Values288720 -Node: Token Locations289888 -Node: Pure Calling290820 -Node: Error Reporting293417 -Node: Error Reporting Function293940 -Node: Syntax Error Reporting Function297312 -Node: Action Features301923 -Node: Internationalization306263 -Node: Enabling I18n307123 -Node: Token I18n309241 -Node: Algorithm310644 -Node: Lookahead313066 -Node: Shift/Reduce315280 -Node: Precedence319347 -Node: Why Precedence320119 -Node: Using Precedence322034 -Node: Precedence Only323534 -Node: Precedence Examples325336 -Node: How Precedence325860 -Node: Non Operators327005 -Node: Contextual Precedence328578 -Node: Parser States330324 -Node: Reduce/Reduce331579 -Node: Mysterious Conflicts336388 -Node: Tuning LR340015 -Node: LR Table Construction341221 -Node: Default Reductions346839 -Node: LAC351626 -Node: Unreachable States357132 -Node: Generalized LR Parsing359139 -Node: Memory Management363524 -Node: Error Recovery365908 -Node: Context Dependency371188 -Node: Semantic Tokens372045 -Node: Lexical Tie-ins375121 -Node: Tie-in Recovery376577 -Node: Debugging378709 -Node: Counterexamples380174 -Node: Understanding386180 -Ref: state-8392904 -Node: Graphviz398455 -Node: Xml402776 -Node: Tracing404514 -Node: Enabling Traces404891 -Node: Mfcalc Traces409019 -Node: Invocation414230 -Node: Bison Options416336 -Node: Operation Modes417183 -Node: Diagnostics422900 -Ref: Wconflicts-sr423208 -Ref: Wconflicts-rr423232 -Ref: Wcounterexamples423620 -Ref: Wdangling-alias423933 -Ref: Wdeprecated425263 -Ref: Wempty-rule425387 -Ref: Wmidrule-values425599 -Ref: Wprecedence426310 -Ref: Wyacc427444 -Ref: Wother427506 -Ref: Wall427810 -Ref: Wnone427930 -Ref: Werror428206 -Node: Tuning the Parser430013 -Ref: option-yacc433427 -Ref: Tuning the Parser-Footnote-1435280 -Node: Output Files435346 -Node: Option Cross Key438623 -Node: Yacc Library440761 -Node: Other Languages441834 -Node: C++ Parsers442459 -Node: A Simple C++ Example443188 -Ref: A Simple C++ Example-Footnote-1447342 -Node: C++ Bison Interface447425 -Node: C++ Parser Interface449015 -Node: C++ Semantic Values453602 -Node: C++ Unions454152 -Node: C++ Variants454945 -Node: C++ Location Values458718 -Node: C++ position459657 -Node: C++ location462026 -Node: Exposing the Location Classes464216 -Node: User Defined Location Type466115 -Node: C++ Parser Context467694 -Node: C++ Scanner Interface471661 -Node: Split Symbols472229 -Node: Complete Symbols473964 -Node: A Complete C++ Example478719 -Node: Calc++ --- C++ Calculator479662 -Node: Calc++ Parsing Driver480183 -Node: Calc++ Parser483150 -Node: Calc++ Scanner487273 -Node: Calc++ Top Level491228 -Node: D Parsers491927 -Node: D Bison Interface492631 -Node: D Semantic Values493744 -Node: D Location Values494577 -Node: D Parser Interface495448 -Node: D Parser Context Interface500364 -Node: D Scanner Interface501807 -Node: D Action Features504747 -Node: D Push Parser Interface505516 -Node: D Complete Symbols506992 -Node: Java Parsers507708 -Node: Java Bison Interface508524 -Node: Java Semantic Values510715 -Node: Java Location Values512412 -Node: Java Parser Interface514010 -Node: Java Parser Context Interface519267 -Node: Java Scanner Interface521352 -Node: Java Action Features525424 -Node: Java Push Parser Interface528175 -Node: Java Differences531170 -Ref: Java Differences-Footnote-1533833 -Node: Java Declarations Summary533987 -Node: History539020 -Node: Yacc539476 -Ref: Yacc-Footnote-1540972 -Ref: Yacc-Footnote-2541203 -Node: yacchack541273 -Node: Byacc541700 -Node: Bison542519 -Node: Other Ungulates544537 -Node: Versioning545127 -Node: FAQ548550 -Node: Memory Exhausted549577 -Node: How Can I Reset the Parser549879 -Node: Strings are Destroyed552473 -Node: Implementing Gotos/Loops554178 -Node: Multiple start-symbols555471 -Node: Secure? Conform?557051 -Node: Enabling Relocatability557505 -Node: I can't build Bison560429 -Node: Where can I find help?561701 -Node: Bug Reports562496 -Node: More Languages563975 -Node: Beta Testing564312 -Node: Mailing Lists565188 -Node: Table of Symbols565400 -Node: Glossary582432 -Node: GNU Free Documentation License592794 -Node: Bibliography618148 -Ref: Corbett 1984618288 -Ref: Denny 2008618638 -Ref: Denny 2010 May618964 -Ref: Denny 2010 November619239 -Ref: DeRemer 1982619577 -Ref: Isradisaikul 2015619849 -Ref: Johnson 1978620178 -Ref: Knuth 1965620447 -Ref: Scott 2000620683 -Node: Index of Terms621000 +Node: Top1040 +Node: Introduction18154 +Node: Conditions19727 +Node: Copying21636 +Node: Concepts59175 +Node: Language and Grammar60367 +Node: Grammar in Bison66345 +Node: Semantic Values68261 +Node: Semantic Actions70389 +Node: GLR Parsers71566 +Node: Simple GLR Parsers74339 +Node: Merging GLR Parses80810 +Ref: Merging GLR Parses-Footnote-186139 +Node: GLR Semantic Actions86280 +Node: Semantic Predicates88877 +Node: Locations91330 +Node: Bison Parser92808 +Node: Stages96001 +Node: Grammar Layout97226 +Node: Examples98588 +Node: RPN Calc100075 +Ref: RPN Calc-Footnote-1101127 +Node: Rpcalc Declarations101205 +Node: Rpcalc Rules103257 +Node: Rpcalc Input105148 +Node: Rpcalc Line106714 +Node: Rpcalc Exp107862 +Node: Rpcalc Lexer109871 +Node: Rpcalc Main112564 +Node: Rpcalc Error112975 +Node: Rpcalc Generate114003 +Node: Rpcalc Compile115247 +Node: Infix Calc116211 +Ref: Infix Calc-Footnote-1119054 +Node: Simple Error Recovery119207 +Node: Location Tracking Calc121142 +Node: Ltcalc Declarations121842 +Node: Ltcalc Rules122937 +Node: Ltcalc Lexer124777 +Node: Multi-function Calc127114 +Ref: Multi-function Calc-Footnote-1128891 +Node: Mfcalc Declarations128969 +Node: Mfcalc Rules130993 +Node: Mfcalc Symbol Table132271 +Node: Mfcalc Lexer135731 +Node: Mfcalc Main138304 +Node: Exercises139180 +Node: Grammar File139707 +Node: Grammar Outline140557 +Node: Prologue141415 +Node: Prologue Alternatives143214 +Ref: Prologue Alternatives-Footnote-1152898 +Node: Bison Declarations153003 +Node: Grammar Rules153413 +Node: Epilogue153869 +Node: Symbols154920 +Node: Rules161943 +Node: Rules Syntax162258 +Node: Empty Rules164323 +Node: Recursion165410 +Node: Semantics167068 +Node: Value Type168374 +Node: Multiple Types169658 +Node: Type Generation171108 +Node: Union Decl173038 +Node: Structured Value Type174431 +Node: Actions175457 +Node: Action Types179329 +Node: Midrule Actions180682 +Node: Using Midrule Actions181336 +Node: Typed Midrule Actions184873 +Node: Midrule Action Translation186421 +Node: Midrule Conflicts188913 +Node: Tracking Locations191522 +Node: Location Type192254 +Node: Actions and Locations193777 +Node: Printing Locations196159 +Node: Location Default Action196919 +Node: Named References200452 +Node: Declarations203048 +Node: Require Decl204735 +Node: Token Decl205249 +Node: Precedence Decl208162 +Node: Type Decl210438 +Node: Symbol Decls211389 +Node: Initial Action Decl212344 +Node: Destructor Decl213157 +Node: Printer Decl218801 +Node: Expect Decl221070 +Node: Start Decl225067 +Node: Pure Decl225461 +Node: Push Decl227209 +Node: Decl Summary231642 +Ref: %header234319 +Node: %define Summary242648 +Ref: api-filename-type244557 +Ref: api-token-prefix255495 +Node: %code Summary267498 +Node: Multiple Parsers271750 +Node: Interface275605 +Node: Parser Function276712 +Node: Push Parser Interface279203 +Ref: yypstate_new279588 +Ref: yypstate_delete280029 +Ref: yypush_parse280443 +Ref: yypull_parse281455 +Node: Lexical282458 +Node: Calling Convention284033 +Node: Special Tokens285562 +Node: Tokens from Literals286997 +Node: Token Values288078 +Node: Token Locations289242 +Node: Pure Calling290174 +Node: Error Reporting292771 +Node: Error Reporting Function293294 +Node: Syntax Error Reporting Function296664 +Node: Action Features301265 +Node: Internationalization305605 +Node: Enabling I18n306457 +Node: Token I18n308567 +Node: Algorithm309958 +Node: Lookahead312372 +Node: Shift/Reduce314582 +Node: Precedence318637 +Node: Why Precedence319409 +Node: Using Precedence321324 +Node: Precedence Only322820 +Node: Precedence Examples324622 +Node: How Precedence325146 +Node: Non Operators326287 +Node: Contextual Precedence327848 +Node: Parser States329590 +Node: Reduce/Reduce330839 +Node: Mysterious Conflicts335642 +Node: Tuning LR339264 +Node: LR Table Construction340464 +Node: Default Reductions346076 +Node: LAC350863 +Node: Unreachable States356363 +Node: Generalized LR Parsing358366 +Node: Memory Management362744 +Node: Error Recovery365128 +Node: Context Dependency370404 +Node: Semantic Tokens371257 +Node: Lexical Tie-ins374325 +Node: Tie-in Recovery375781 +Node: Debugging377911 +Node: Counterexamples379374 +Node: Understanding385376 +Ref: state-8392088 +Node: Graphviz397639 +Node: Xml401956 +Node: Tracing403694 +Node: Enabling Traces404067 +Node: Mfcalc Traces408193 +Node: Invocation413400 +Node: Bison Options415502 +Node: Operation Modes416349 +Node: Diagnostics422058 +Ref: Wconflicts-sr422366 +Ref: Wconflicts-rr422390 +Ref: Wcounterexamples422778 +Ref: Wdangling-alias423091 +Ref: Wdeprecated424416 +Ref: Wempty-rule424540 +Ref: Wmidrule-values424752 +Ref: Wprecedence425463 +Ref: Wyacc426597 +Ref: Wother426659 +Ref: Wall426963 +Ref: Wnone427083 +Ref: Werror427359 +Node: Tuning the Parser429164 +Ref: option-yacc432576 +Ref: Tuning the Parser-Footnote-1434425 +Node: Output Files434491 +Node: Option Cross Key437760 +Node: Yacc Library439898 +Node: Other Languages440965 +Node: C++ Parsers441588 +Node: A Simple C++ Example442317 +Ref: A Simple C++ Example-Footnote-1446467 +Node: C++ Bison Interface446550 +Node: C++ Parser Interface448140 +Node: C++ Semantic Values452723 +Node: C++ Unions453273 +Node: C++ Variants454066 +Node: C++ Location Values457827 +Node: C++ position458766 +Node: C++ location461135 +Node: Exposing the Location Classes463325 +Node: User Defined Location Type465218 +Node: C++ Parser Context466797 +Node: C++ Scanner Interface470760 +Node: Split Symbols471328 +Node: Complete Symbols473063 +Node: A Complete C++ Example477814 +Node: Calc++ --- C++ Calculator478757 +Node: Calc++ Parsing Driver479278 +Node: Calc++ Parser482241 +Node: Calc++ Scanner486356 +Node: Calc++ Top Level490299 +Node: D Parsers490998 +Node: D Bison Interface491702 +Node: D Semantic Values492815 +Node: D Location Values493646 +Node: D Parser Interface494517 +Node: D Parser Context Interface499433 +Node: D Scanner Interface500876 +Node: D Action Features503816 +Node: D Push Parser Interface504585 +Node: D Complete Symbols506059 +Node: Java Parsers506775 +Node: Java Bison Interface507591 +Node: Java Semantic Values509774 +Node: Java Location Values511469 +Node: Java Parser Interface513067 +Node: Java Parser Context Interface518322 +Node: Java Scanner Interface520407 +Node: Java Action Features524479 +Node: Java Push Parser Interface527230 +Node: Java Differences530223 +Ref: Java Differences-Footnote-1532886 +Node: Java Declarations Summary533040 +Node: History538073 +Node: Yacc538529 +Ref: Yacc-Footnote-1540022 +Ref: Yacc-Footnote-2540245 +Node: yacchack540315 +Node: Byacc540738 +Node: Bison541551 +Node: Other Ungulates543559 +Node: Versioning544139 +Node: FAQ547562 +Node: Memory Exhausted548589 +Node: How Can I Reset the Parser548891 +Node: Strings are Destroyed551483 +Node: Implementing Gotos/Loops553184 +Node: Multiple start-symbols554475 +Node: Secure? Conform?556055 +Node: Enabling Relocatability556505 +Node: I can't build Bison559423 +Node: Where can I find help?560683 +Node: Bug Reports561476 +Node: More Languages562951 +Node: Beta Testing563286 +Node: Mailing Lists564160 +Node: Table of Symbols564372 +Node: Glossary581398 +Node: GNU Free Documentation License591676 +Node: Bibliography616829 +Ref: Corbett 1984616969 +Ref: Denny 2008617320 +Ref: Denny 2010 May617642 +Ref: Denny 2010 November617917 +Ref: DeRemer 1982618253 +Ref: Isradisaikul 2015618523 +Ref: Johnson 1978618848 +Ref: Knuth 1965619113 +Ref: Scott 2000619347 +Node: Index of Terms619664  End Tag Table diff --git a/local/recipes/dev/bison/source/doc/bison.info.bak b/local/recipes/dev/bison/source/doc/bison.info.bak index 4f4fb08267..fea740eb9e 100644 --- a/local/recipes/dev/bison/source/doc/bison.info.bak +++ b/local/recipes/dev/bison/source/doc/bison.info.bak @@ -1,22 +1,22 @@ -This is bison.info, produced by makeinfo version 6.8 from bison.texi. +This is bison.info, produced by makeinfo version 7.3 from bison.texi. -This manual (12 September 2021) is for GNU Bison (version 3.8.2), the -GNU parser generator. +This manual (15 May 2026) is for GNU Bison (version 3.8.2), the GNU +parser generator. - Copyright © 1988–1993, 1995, 1998–2015, 2018–2021 Free Software + Copyright © 1988-1993, 1995, 1998-2015, 2018-2021 Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover texts - being “A GNU Manual,” and with the Back-Cover Texts as in (a) + being "A GNU Manual," and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled - “GNU Free Documentation License.” + "GNU Free Documentation License." - (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and + (a) The FSF's Back-Cover Text is: "You have the freedom to copy and modify this GNU manual. Buying copies from the FSF supports it in - developing GNU and promoting software freedom.” + developing GNU and promoting software freedom." INFO-DIR-SECTION Software development START-INFO-DIR-ENTRY * bison: (bison). GNU parser generator (Yacc replacement). @@ -28,23 +28,23 @@ File: bison.info, Node: Top, Next: Introduction, Up: (dir) Bison ***** -This manual (12 September 2021) is for GNU Bison (version 3.8.2), the -GNU parser generator. +This manual (15 May 2026) is for GNU Bison (version 3.8.2), the GNU +parser generator. - Copyright © 1988–1993, 1995, 1998–2015, 2018–2021 Free Software + Copyright © 1988-1993, 1995, 1998-2015, 2018-2021 Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover texts - being “A GNU Manual,” and with the Back-Cover Texts as in (a) + being "A GNU Manual," and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled - “GNU Free Documentation License.” + "GNU Free Documentation License." - (a) The FSF’s Back-Cover Text is: “You have the freedom to copy and + (a) The FSF's Back-Cover Text is: "You have the freedom to copy and modify this GNU manual. Buying copies from the FSF supports it in - developing GNU and promoting software freedom.” + developing GNU and promoting software freedom." * Menu: @@ -76,20 +76,20 @@ Reference sections: * Bibliography:: Publications cited in this manual. * Index of Terms:: Cross-references to the text. - — The Detailed Node Listing — + -- The Detailed Node Listing -- The Concepts of Bison * Language and Grammar:: Languages and context-free grammars, as mathematical ideas. -* Grammar in Bison:: How we represent grammars for Bison’s sake. +* Grammar in Bison:: How we represent grammars for Bison's sake. * Semantic Values:: Each token or syntactic grouping can have a semantic value (the value of an integer, the name of an identifier, etc.). * Semantic Actions:: Each rule can have an action containing C code. * GLR Parsers:: Writing parsers for general context-free languages. * Locations:: Overview of location tracking. -* Bison Parser:: What are Bison’s input and output, +* Bison Parser:: What are Bison's input and output, how is the output used? * Stages:: Stages in writing and running Bison grammars. * Grammar Layout:: Overall structure of a Bison grammar file. @@ -211,7 +211,7 @@ Bison Declarations * Pure Decl:: Requesting a reentrant parser. * Push Decl:: Requesting a push parser. * Decl Summary:: Table of all Bison declarations. -* %define Summary:: Defining variables to adjust Bison’s behavior. +* %define Summary:: Defining variables to adjust Bison's behavior. * %code Summary:: Inserting code into the parser source. Parser C-Language Interface @@ -222,7 +222,7 @@ Parser C-Language Interface which reads tokens. * Error Reporting:: Passing error messages to the user. * Action Features:: Special features for use in actions. -* Internationalization:: How to let the parser speak in the user’s +* Internationalization:: How to let the parser speak in the user's native language. The Lexical Analyzer Function ‘yylex’ @@ -253,7 +253,7 @@ The Bison Parser Algorithm * Lookahead:: Parser looks one token ahead when deciding what to do. * Shift/Reduce:: Conflicts: when either shifting or reduction is valid. * Precedence:: Operator precedence works by resolving conflicts. -* Contextual Precedence:: When an operator’s precedence depends on context. +* Contextual Precedence:: When an operator's precedence depends on context. * Parser States:: The parser is a finite-state-machine with stack. * Reduce/Reduce:: When two rules are applicable in the same situation. * Mysterious Conflicts:: Conflicts that look unjustified. @@ -401,7 +401,6 @@ Copying This Manual * GNU Free Documentation License:: Copying and sharing this manual -  File: bison.info, Node: Introduction, Next: Conditions, Prev: Top, Up: Top @@ -423,7 +422,7 @@ understand this manual. We begin with tutorial chapters that explain the basic concepts of using Bison and show three explained examples, each building on the -last. If you don’t know Bison or Yacc, start by reading these chapters. +last. If you don't know Bison or Yacc, start by reading these chapters. Reference chapters follow, which describe specific aspects of Bison in detail. @@ -454,24 +453,24 @@ software. The reason Bison was different was not due to a special policy decision; it resulted from applying the usual General Public License to all of the Bison source code. - The main output of the Bison utility—the Bison parser implementation -file—contains a verbatim copy of a sizable piece of Bison, which is the -code for the parser’s implementation. (The actions from your grammar + The main output of the Bison utility--the Bison parser implementation +file--contains a verbatim copy of a sizable piece of Bison, which is the +code for the parser's implementation. (The actions from your grammar are inserted into this implementation at one point, but most of the rest of the implementation is not changed.) When we applied the GPL terms to -the skeleton code for the parser’s implementation, the effect was to +the skeleton code for the parser's implementation, the effect was to restrict the use of Bison output to free software. - We didn’t change the terms because of sympathy for people who want to + We didn't change the terms because of sympathy for people who want to make software proprietary. *Software should be free.* But we concluded -that limiting Bison’s use to free software was doing little to encourage +that limiting Bison's use to free software was doing little to encourage people to make other software free. So we decided to make the practical conditions for using Bison match the practical conditions for using the other GNU tools. This exception applies when Bison is generating code for a parser. You can tell whether the exception applies to a Bison output file by -inspecting the file for text beginning with “As a special exception...”. +inspecting the file for text beginning with "As a special exception...". The text spells out the exact terms of the exception.  @@ -496,7 +495,7 @@ and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program—to make sure it remains free +share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to @@ -524,16 +523,16 @@ know their rights. (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. - For the developers’ and authors’ protection, the GPL clearly explains -that there is no warranty for this free software. For both users’ and -authors’ sake, the GPL requires that modified versions be marked as + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of -protecting users’ freedom to change the software. The systematic +protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those @@ -556,25 +555,25 @@ TERMS AND CONDITIONS 0. Definitions. - “This License” refers to version 3 of the GNU General Public + "This License" refers to version 3 of the GNU General Public License. - “Copyright” also means copyright-like laws that apply to other + "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - “The Program” refers to any copyrightable work licensed under this - License. Each licensee is addressed as “you”. “Licensees” and - “recipients” may be individuals or organizations. + "The Program" refers to any copyrightable work licensed under this + License. Each licensee is addressed as "you". "Licensees" and + "recipients" may be individuals or organizations. - To “modify” a work means to copy from or adapt all or part of the + To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the - making of an exact copy. The resulting work is called a “modified - version” of the earlier work or a work “based on” the earlier work. + making of an exact copy. The resulting work is called a "modified + version" of the earlier work or a work "based on" the earlier work. - A “covered work” means either the unmodified Program or a work + A "covered work" means either the unmodified Program or a work based on the Program. - To “propagate” a work means to do anything with it that, without + To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes @@ -582,12 +581,12 @@ TERMS AND CONDITIONS available to the public, and in some countries other activities as well. - To “convey” a work means any kind of propagation that enables other + To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. - An interactive user interface displays “Appropriate Legal Notices” + An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to @@ -599,33 +598,33 @@ TERMS AND CONDITIONS 1. Source Code. - The “source code” for a work means the preferred form of the work - for making modifications to it. “Object code” means any non-source + The "source code" for a work means the preferred form of the work + for making modifications to it. "Object code" means any non-source form of a work. - A “Standard Interface” means an interface that either is an + A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. - The “System Libraries” of an executable work include anything, + The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code - form. A “Major Component”, in this context, means a major + form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. - The “Corresponding Source” for a work in object code form means all + The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the - work’s System Libraries, or general-purpose tools or generally + work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated @@ -669,7 +668,7 @@ TERMS AND CONDITIONS the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. - 3. Protecting Users’ Legal Rights From Anti-Circumvention Law. + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under @@ -682,12 +681,12 @@ TERMS AND CONDITIONS circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of - enforcing, against the work’s users, your or third parties’ legal + enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. - You may convey verbatim copies of the Program’s source code as you + You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any @@ -711,7 +710,7 @@ TERMS AND CONDITIONS b. The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in - section 4 to “keep intact all notices”. + section 4 to "keep intact all notices". c. You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This @@ -731,9 +730,9 @@ TERMS AND CONDITIONS works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is - called an “aggregate” if the compilation and its resulting + called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the - compilation’s users beyond what the individual works permit. + compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. @@ -791,13 +790,13 @@ TERMS AND CONDITIONS excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. - A “User Product” is either (1) a “consumer product”, which means + A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, - “normally used” refers to a typical or common use of that class of + "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product @@ -805,7 +804,7 @@ TERMS AND CONDITIONS industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. - “Installation Information” for a User Product means any methods, + "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. @@ -841,7 +840,7 @@ TERMS AND CONDITIONS 7. Additional Terms. - “Additional permissions” are terms that supplement the terms of + "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in @@ -886,8 +885,8 @@ TERMS AND CONDITIONS the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. - All other non-permissive additional terms are considered “further - restrictions” within the meaning of section 10. If the Program as + All other non-permissive additional terms are considered "further + restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document @@ -953,12 +952,12 @@ TERMS AND CONDITIONS responsible for enforcing compliance by third parties with this License. - An “entity transaction” is a transaction transferring control of an + An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever - licenses to the work the party’s predecessor in interest had or + licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable @@ -975,31 +974,31 @@ TERMS AND CONDITIONS 11. Patents. - A “contributor” is a copyright holder who authorizes use under this + A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. - The work thus licensed is called the contributor’s “contributor - version”. + The work thus licensed is called the contributor's "contributor + version". - A contributor’s “essential patent claims” are all patent claims + A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the - contributor version. For purposes of this definition, “control” + contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, - royalty-free patent license under the contributor’s essential + royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. - In the following three paragraphs, a “patent license” is any + In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a - patent or covenant not to sue for patent infringement). To “grant” + patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. @@ -1012,9 +1011,9 @@ TERMS AND CONDITIONS yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream - recipients. “Knowingly relying” means you have actual knowledge + recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work - in a country, or your recipient’s use of the covered work in a + in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. @@ -1026,7 +1025,7 @@ TERMS AND CONDITIONS patent license you grant is automatically extended to all recipients of the covered work and works based on it. - A patent license is “discriminatory” if it does not include within + A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a @@ -1046,7 +1045,7 @@ TERMS AND CONDITIONS any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. - 12. No Surrender of Others’ Freedom. + 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they @@ -1079,7 +1078,7 @@ TERMS AND CONDITIONS Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU - General Public License “or any later version” applies to it, you + General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version @@ -1088,7 +1087,7 @@ TERMS AND CONDITIONS If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that - proxy’s public statement of acceptance of a version permanently + proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different @@ -1100,7 +1099,7 @@ TERMS AND CONDITIONS THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE - COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” + COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE @@ -1144,7 +1143,7 @@ terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the -“copyright” line and a pointer to where the full notice is found. +"copyright" line and a pointer to where the full notice is found. ONE LINE TO GIVE THE PROGRAM'S NAME AND A BRIEF IDEA OF WHAT IT DOES. Copyright (C) YEAR NAME OF AUTHOR @@ -1175,11 +1174,11 @@ notice like this when it starts in an interactive mode: The hypothetical commands ‘show w’ and ‘show c’ should show the appropriate parts of the General Public License. Of course, your -program’s commands might be different; for a GUI interface, you would -use an “about box”. +program's commands might be different; for a GUI interface, you would +use an "about box". You should also get your employer (if you work as a programmer) or -school, if any, to sign a “copyright disclaimer” for the program, if +school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . @@ -1205,14 +1204,14 @@ carefully. * Language and Grammar:: Languages and context-free grammars, as mathematical ideas. -* Grammar in Bison:: How we represent grammars for Bison’s sake. +* Grammar in Bison:: How we represent grammars for Bison's sake. * Semantic Values:: Each token or syntactic grouping can have a semantic value (the value of an integer, the name of an identifier, etc.). * Semantic Actions:: Each rule can have an action containing C code. * GLR Parsers:: Writing parsers for general context-free languages. * Locations:: Overview of location tracking. -* Bison Parser:: What are Bison’s input and output, +* Bison Parser:: What are Bison's input and output, how is the output used? * Stages:: Stages in writing and running Bison grammars. * Grammar Layout:: Overall structure of a Bison grammar file. @@ -1227,14 +1226,14 @@ In order for Bison to parse a language, it must be described by a “context-free grammar”. This means that you specify one or more “syntactic groupings” and give rules for constructing them from their parts. For example, in the C language, one kind of grouping is called -an ‘expression’. One rule for making an expression might be, “An -expression can be made of a minus sign and another expression”. Another -would be, “An expression can be an integer”. As you can see, rules are +an 'expression'. One rule for making an expression might be, "An +expression can be made of a minus sign and another expression". Another +would be, "An expression can be an integer". As you can see, rules are often recursive, but there must be at least one rule which leads out of the recursion. The most common formal system for presenting such rules for humans to -read is “Backus-Naur Form” or “BNF”, which was developed in order to +read is “Backus-Naur Form” or "BNF", which was developed in order to specify the language Algol 60. Any grammar expressed in BNF is a context-free grammar. The input to Bison is essentially machine-readable BNF. @@ -1259,14 +1258,14 @@ rules to get the same inputs. Even unambiguous grammars can be “nondeterministic”, meaning that no fixed lookahead always suffices to determine the next grammar rule to apply. With the proper declarations, Bison is also able to parse these more general context-free grammars, -using a technique known as GLR parsing (for Generalized LR). Bison’s GLR +using a technique known as GLR parsing (for Generalized LR). Bison's GLR parsers are able to handle any context-free grammar for which the number of possible parses of any given string is finite. In the formal grammatical rules for a language, each kind of syntactic unit or grouping is named by a “symbol”. Those which are built by grouping smaller constructs according to grammatical rules are -called “nonterminal symbols”; those which can’t be subdivided are called +called “nonterminal symbols”; those which can't be subdivided are called “terminal symbols” or “token kinds”. We call a piece of input corresponding to a single terminal symbol a “token”, and a piece corresponding to a single nonterminal symbol a “grouping”. @@ -1275,26 +1274,26 @@ corresponding to a single nonterminal symbol a “grouping”. nonterminal, mean. The tokens of C are identifiers, constants (numeric and string), and the various keywords, arithmetic operators and punctuation marks. So the terminal symbols of a grammar for C include -‘identifier’, ‘number’, ‘string’, plus one symbol for each keyword, -operator or punctuation mark: ‘if’, ‘return’, ‘const’, ‘static’, ‘int’, -‘char’, ‘plus-sign’, ‘open-brace’, ‘close-brace’, ‘comma’ and many more. +'identifier', 'number', 'string', plus one symbol for each keyword, +operator or punctuation mark: 'if', 'return', 'const', 'static', 'int', +'char', 'plus-sign', 'open-brace', 'close-brace', 'comma' and many more. (These tokens can be subdivided into characters, but that is a matter of lexicography, not grammar.) Here is a simple C function subdivided into tokens: - int /* keyword ‘int’ */ - square (int x) /* identifier, open-paren, keyword ‘int’, + int /* keyword 'int' */ + square (int x) /* identifier, open-paren, keyword 'int', identifier, close-paren */ { /* open-brace */ - return x * x; /* keyword ‘return’, identifier, asterisk, + return x * x; /* keyword 'return', identifier, asterisk, identifier, semicolon */ } /* close-brace */ The syntactic groupings of C include the expression, the statement, the declaration, and the function definition. These are represented in -the grammar of C by nonterminal symbols ‘expression’, ‘statement’, -‘declaration’ and ‘function definition’. The full grammar uses dozens +the grammar of C by nonterminal symbols 'expression', 'statement', +'declaration' and 'function definition'. The full grammar uses dozens of additional language constructs, each with its own nonterminal symbol, in order to express the meanings of these four. The example above is a function definition; it contains one declaration, and one statement. In @@ -1305,28 +1304,28 @@ made out of simpler constructs. For example, one kind of C statement is the ‘return’ statement; this would be described with a grammar rule which reads informally as follows: - A ‘statement’ can be made of a ‘return’ keyword, an ‘expression’ - and a ‘semicolon’. + A 'statement' can be made of a 'return' keyword, an 'expression' + and a 'semicolon'. -There would be many other rules for ‘statement’, one for each kind of +There would be many other rules for 'statement', one for each kind of statement in C. One nonterminal symbol must be distinguished as the special one which defines a complete utterance in the language. It is called the “start symbol”. In a compiler, this means a complete input program. In the C -language, the nonterminal symbol ‘sequence of definitions and -declarations’ plays this role. +language, the nonterminal symbol 'sequence of definitions and +declarations' plays this role. - For example, ‘1 + 2’ is a valid C expression—a valid part of a C -program—but it is not valid as an _entire_ C program. In the -context-free grammar of C, this follows from the fact that ‘expression’ + For example, ‘1 + 2’ is a valid C expression--a valid part of a C +program--but it is not valid as an _entire_ C program. In the +context-free grammar of C, this follows from the fact that 'expression' is not the start symbol. The Bison parser reads a sequence of tokens as its input, and groups the tokens using the grammar rules. If the input is valid, the end result is that the entire token sequence reduces to a single grouping -whose symbol is the grammar’s start symbol. If we use a grammar for C, -the entire input must be a ‘sequence of definitions and declarations’. +whose symbol is the grammar's start symbol. If we use a grammar for C, +the entire input must be a 'sequence of definitions and declarations'. If not, the parser reports a syntax error.  @@ -1378,7 +1377,7 @@ File: bison.info, Node: Semantic Values, Next: Semantic Actions, Prev: Gramma =================== A formal grammar selects tokens only by their classifications: for -example, if a rule mentions the terminal symbol ‘integer constant’, it +example, if a rule mentions the terminal symbol 'integer constant', it means that _any_ integer constant is grammatically valid in that position. The precise value of the constant is irrelevant to how to parse the input: if ‘x+4’ is grammatical then ‘x+1’ or ‘x+3989’ is @@ -1398,7 +1397,7 @@ kinds. The semantic value has all the rest of the information about the meaning of the token, such as the value of an integer, or the name of an -identifier. (A token such as ‘','’ which is just punctuation doesn’t +identifier. (A token such as ‘','’ which is just punctuation doesn't need to have any semantic value.) For example, an input token might be classified as token kind @@ -1406,7 +1405,7 @@ need to have any semantic value.) the same token kind ‘INTEGER’ but value 3989. When a grammar rule says that ‘INTEGER’ is allowed, either of these tokens is acceptable because each is an ‘INTEGER’. When the parser accepts the token, it keeps track -of the token’s semantic value. +of the token's semantic value. Each grouping can also have a semantic value as well as its nonterminal symbol. For example, in a calculator, an expression @@ -1448,7 +1447,7 @@ File: bison.info, Node: GLR Parsers, Next: Locations, Prev: Semantic Actions, 1.5 Writing GLR Parsers ======================= -In some grammars, Bison’s deterministic LR(1) parsing algorithm cannot +In some grammars, Bison's deterministic LR(1) parsing algorithm cannot decide whether to apply a certain grammar rule at a given point. That is, it may not be able to decide (on the basis of the input read so far) which of two possible reductions (applications of a grammar rule) @@ -1534,7 +1533,7 @@ become a new identifier to represent the enumeration value, while in the former case ‘a’ must be evaluated with its current meaning, which may be a constant or even a function call. - You could parse ‘(a)’ as an “unspecified identifier in parentheses”, + You could parse ‘(a)’ as an "unspecified identifier in parentheses", to be resolved later, but this typically requires substantial contortions in both semantic actions and large parts of the grammar, where the parentheses are nested in the recursive rules for expressions. @@ -1542,7 +1541,7 @@ where the parentheses are nested in the recursive rules for expressions. You might think of using the lexer to distinguish between the two forms by returning different tokens for currently defined and undefined identifiers. But if these declarations occur in a local scope, and ‘a’ -is defined in an outer scope, then both forms are possible—either +is defined in an outer scope, then both forms are possible--either locally redefining ‘a’, or using the value of ‘a’ from the outer scope. So this approach cannot work. @@ -1560,7 +1559,7 @@ split. If the input is syntactically incorrect, both branches fail and the parser reports a syntax error as usual. - The effect of all this is that the parser seems to “guess” the + The effect of all this is that the parser seems to "guess" the correct branch to take, or in other words, it seems to use more lookahead than the underlying LR(1) algorithm actually allows for. In this example, LR(2) would suffice, but also some cases that are not @@ -1652,7 +1651,7 @@ File: bison.info, Node: Merging GLR Parses, Next: GLR Semantic Actions, Prev: 1.5.2 Using GLR to Resolve Ambiguities -------------------------------------- -Let’s consider an example, vastly simplified from a C++ grammar.(1) +Let's consider an example, vastly simplified from a C++ grammar.(1) %{ #include @@ -1701,7 +1700,7 @@ Let’s consider an example, vastly simplified from a C++ grammar.(1) | '(' declarator ')' ; -This models a problematic part of the C++ grammar—the ambiguity between +This models a problematic part of the C++ grammar--the ambiguity between certain declarations and statements. For example, T (x) = y+z; @@ -1713,10 +1712,10 @@ ID’, which it cannot resolve at the time it encounters ‘x’ in the example above. Since this is a GLR parser, it therefore splits the problem into two parses, one for each choice of resolving the reduce/reduce conflict. Unlike the example from the previous section -(*note Simple GLR Parsers::), however, neither of these parses “dies,” +(*note Simple GLR Parsers::), however, neither of these parses "dies," because the grammar as it stands is ambiguous. One of the parsers eventually reduces ‘stmt : expr ';'’ and the other reduces ‘stmt : -decl’, after which both parsers are in an identical state: they’ve seen +decl’, after which both parsers are in an identical state: they've seen ‘prog stmt’ and have the same unprocessed input remaining. We say that these parses have “merged.” @@ -1834,11 +1833,11 @@ features you might use in a semantic action in a GLR parser. kind of the lookahead token present at the time of the associated reduction. After checking that ‘yychar’ is not set to ‘YYEMPTY’ or ‘YYEOF’, you can then examine ‘yylval’ and ‘yylloc’ to determine the -lookahead token’s semantic value and location, if any. In a nondeferred +lookahead token's semantic value and location, if any. In a nondeferred semantic action, you can also modify any of these variables to influence syntax analysis. *Note Lookahead::. - In a deferred semantic action, it’s too late to influence syntax + In a deferred semantic action, it's too late to influence syntax analysis. In this case, ‘yychar’, ‘yylval’, and ‘yylloc’ are set to shallow copies of the values they had at the time of the associated reduction. For this reason alone, modifying them is dangerous. @@ -1967,14 +1966,14 @@ distinct programs: the Bison utility is a program whose output is the Bison parser implementation file that becomes part of your program. The job of the Bison parser is to group tokens into groupings -according to the grammar rules—for example, to build identifiers and +according to the grammar rules--for example, to build identifiers and operators into expressions. As it does this, it runs the actions for the grammar rules it uses. The tokens come from a function called the “lexical analyzer” that you must supply in some fashion (such as by writing it in C). The Bison parser calls the lexical analyzer each time it wants a new token. It -doesn’t know what is “inside” the tokens (though their semantic values +doesn't know what is "inside" the tokens (though their semantic values may reflect this). Typically the lexical analyzer makes the tokens by parsing characters of text, but Bison does not depend on this. *Note Lexical::. @@ -2092,9 +2091,9 @@ File: bison.info, Node: Examples, Next: Grammar File, Prev: Concepts, Up: To Now we show and explain several sample programs written using Bison: a Reverse Polish Notation calculator, an algebraic (infix) notation -calculator — later extended to track “locations” — and a multi-function -calculator. All produce usable, though limited, interactive desk-top -calculators. +calculator -- later extended to track "locations" -- and a +multi-function calculator. All produce usable, though limited, +interactive desk-top calculators. These examples are simple, but Bison grammars for real programming languages are written the same way. You can copy these examples into a @@ -2188,13 +2187,13 @@ about the tokens and their types (*note Bison Declarations::). The ‘%define’ directive defines the variable ‘api.value.type’, thus specifying the C data type for semantic values of both tokens and groupings (*note Value Type::). The Bison parser will use whatever type -‘api.value.type’ is defined as; if you don’t define it, ‘int’ is the +‘api.value.type’ is defined as; if you don't define it, ‘int’ is the default. Because we specify ‘{double}’, each token and each expression has an associated value, which is a floating point number. C code can use ‘YYSTYPE’ to refer to the value ‘api.value.type’. Each terminal symbol that is not a single-character literal must be -declared. (Single-character literals normally don’t need to be +declared. (Single-character literals normally don't need to be declared.) In this example, all the arithmetic operators are designated by single-character literals, so the only terminal symbol that needs to be declared is ‘NUM’, the token kind for numeric constants. @@ -2228,11 +2227,11 @@ Here are the grammar rules for the Reverse Polish Notation calculator. ; %% - The groupings of the rpcalc “language” defined here are the + The groupings of the rpcalc "language" defined here are the expression (given the name ‘exp’), the line of input (‘line’), and the complete input transcript (‘input’). Each of these nonterminal symbols has several alternate rules, joined by the vertical bar ‘|’ which is -read as “or”. The following sections explain what these rules mean. +read as "or". The following sections explain what these rules mean. The semantics of the language is determined by the actions taken when a grouping is recognized. The actions are the C code that appears @@ -2264,25 +2263,25 @@ Consider the definition of ‘input’: | input line ; - This definition reads as follows: “A complete input is either an -empty string, or a complete input followed by an input line”. Notice -that “complete input” is defined in terms of itself. This definition is + This definition reads as follows: "A complete input is either an +empty string, or a complete input followed by an input line". Notice +that "complete input" is defined in terms of itself. This definition is said to be “left recursive” since ‘input’ appears always as the leftmost symbol in the sequence. *Note Recursion::. The first alternative is empty because there are no symbols between the colon and the first ‘|’; this means that ‘input’ can match an empty string of input (no tokens). We write the rules this way because it is -legitimate to type ‘Ctrl-d’ right after you start the calculator. It’s +legitimate to type ‘Ctrl-d’ right after you start the calculator. It's conventional to put an empty alternative first and to use the (optional) ‘%empty’ directive, or to write the comment ‘/* empty */’ in it (*note Empty Rules::). The second alternate rule (‘input line’) handles all nontrivial -input. It means, “After reading any number of lines, read one more line -if possible.” The left recursion makes this rule into a loop. Since the -first alternative matches empty input, the loop can be executed zero or -more times. +input. It means, "After reading any number of lines, read one more line +if possible." The left recursion makes this rule into a loop. Since +the first alternative matches empty input, the loop can be executed zero +or more times. The parser function ‘yyparse’ continues to process input until a grammatical error is seen or the lexical analyzer says there are no more @@ -2313,8 +2312,8 @@ for. This action is unusual because it does not assign a value to ‘$$’. As a consequence, the semantic value associated with the ‘line’ is uninitialized (its value will be unpredictable). This would be a bug if -that value were ever used, but we don’t use it: once rpcalc has printed -the value of the user’s input line, that value is no longer needed. +that value were ever used, but we don't use it: once rpcalc has printed +the value of the user's input line, that value is no longer needed.  File: bison.info, Node: Rpcalc Exp, Prev: Rpcalc Line, Up: Rpcalc Rules @@ -2352,10 +2351,10 @@ associated semantic value, but if it had one you could refer to it as }’. When ‘yyparse’ recognizes a sum expression using this rule, the sum -of the two subexpressions’ values is produced as the value of the entire +of the two subexpressions' values is produced as the value of the entire expression. *Note Actions::. - You don’t have to give an action for every rule. When a rule has no + You don't have to give an action for every rule. When a rule has no action, Bison by default copies the value of ‘$1’ into ‘$$’. This is what happens in the first rule (the one that uses ‘NUM’). @@ -2381,14 +2380,14 @@ File: bison.info, Node: Rpcalc Lexer, Next: Rpcalc Main, Prev: Rpcalc Rules, 2.1.3 The ‘rpcalc’ Lexical Analyzer ----------------------------------- -The lexical analyzer’s job is low-level parsing: converting characters +The lexical analyzer's job is low-level parsing: converting characters or sequences of characters into tokens. The Bison parser gets its tokens by calling the lexical analyzer. *Note Lexical::. Only a simple lexical analyzer is needed for the RPN calculator. This lexical analyzer skips blanks and tabs, then reads in numbers as ‘double’ and returns them as ‘NUM’ tokens. Any other character that -isn’t part of a number is a separate token. Note that the token-code +isn't part of a number is a separate token. Note that the token-code for such a single-character token is the character itself. The return value of the lexical analyzer function is a numeric code @@ -2507,8 +2506,8 @@ command to convert it into a parser implementation file: $ bison FILE.y -In this example, the grammar file is called ‘rpcalc.y’ (for “Reverse -Polish CALCulator”). Bison produces a parser implementation file named +In this example, the grammar file is called ‘rpcalc.y’ (for "Reverse +Polish CALCulator"). Bison produces a parser implementation file named ‘FILE.tab.c’, removing the ‘.y’ from the grammar file name. The parser implementation file contains the source code for ‘yyparse’. The additional functions in the grammar file (‘yylex’, ‘yyerror’ and ‘main’) @@ -2611,7 +2610,7 @@ kinds and says they are left-associative operators. The declarations ‘%left’ and ‘%right’ (right associativity) take the place of ‘%token’ which is used to declare a token kind name without associativity/precedence. (These tokens are single-character literals, -which ordinarily don’t need to be declared. We declare them here to +which ordinarily don't need to be declared. We declare them here to specify the associativity/precedence.) Operator precedence is determined by the line ordering of the @@ -2623,7 +2622,7 @@ matters (‘%precedence’. *Note Precedence::. The other important new feature is the ‘%prec’ in the grammar section for the unary minus operator. The ‘%prec’ simply instructs Bison that -the rule ‘| '-' exp’ has the same precedence as ‘NEG’—in this case the +the rule ‘| '-' exp’ has the same precedence as ‘NEG’--in this case the next-to-highest. *Note Contextual Precedence::. Here is a sample run of ‘calc.y’: @@ -2649,7 +2648,7 @@ File: bison.info, Node: Simple Error Recovery, Next: Location Tracking Calc, ========================= Up to this point, this manual has not addressed the issue of “error -recovery”—how to continue parsing after the parser detects a syntax +recovery”--how to continue parsing after the parser detects a syntax error. All we have handled is error reporting with ‘yyerror’. Recall that by default ‘yyparse’ returns after calling ‘yyerror’. This means that an erroneous input line causes the calculator program to exit. Now @@ -2679,7 +2678,7 @@ other kinds of errors; for example, division by zero, which raises an exception signal that is normally fatal. A real calculator program must handle this signal and use ‘longjmp’ to return to ‘main’ and resume parsing input lines; it would also have to discard the rest of the -current line of input. We won’t discuss this issue further because it +current line of input. We won't discuss this issue further because it is not specific to Bison programs.  @@ -2785,7 +2784,7 @@ the wrong expressions or subexpressions. using the pseudo-variables ‘@N’ for rule components, and the pseudo-variable ‘@$’ for groupings. - We don’t need to assign a value to ‘@$’: the output parser does it + We don't need to assign a value to ‘@$’: the output parser does it automatically. By default, before executing the C code of each action, ‘@$’ is set to range from the beginning of ‘@1’ to the end of ‘@N’, for a rule with N components. This behavior can be redefined (*note @@ -2798,7 +2797,7 @@ File: bison.info, Node: Ltcalc Lexer, Prev: Ltcalc Rules, Up: Location Tracki 2.4.3 The ‘ltcalc’ Lexical Analyzer. ------------------------------------ -Until now, we relied on Bison’s defaults to enable location tracking. +Until now, we relied on Bison's defaults to enable location tracking. The next step is to rewrite the lexical analyzer, and make it able to feed the parser with the token locations, as it already does for semantic values. @@ -2851,7 +2850,7 @@ input text, to avoid the computed locations of being fuzzy or wrong: Basically, the lexical analyzer performs the same processing as before: it skips blanks and tabs, and reads numbers or single-character tokens. In addition, it updates ‘yylloc’, the global variable (of type -‘YYLTYPE’) containing the token’s location. +‘YYLTYPE’) containing the token's location. Now, each time this function returns a token, the parser has its kind as well as its semantic value, and its location in the text. The last @@ -3018,7 +3017,7 @@ File: bison.info, Node: Mfcalc Symbol Table, Next: Mfcalc Lexer, Prev: Mfcalc ------------------------------- The multi-function calculator requires a symbol table to keep track of -the names and meanings of variables and functions. This doesn’t affect +the names and meanings of variables and functions. This doesn't affect the grammar rules (except for the actions) or the Bison declarations, but it requires some additional C functions for support. @@ -3315,7 +3314,7 @@ The PROLOGUE section contains macro definitions and declarations of functions and variables that are used in the actions in the grammar rules. These are copied to the beginning of the parser implementation file so that they precede the definition of ‘yyparse’. You can use -‘#include’ to get the declarations from a header file. If you don’t +‘#include’ to get the declarations from a header file. If you don't need any C declarations, you may omit the ‘%{’ and ‘%}’ delimiters that bracket this section. @@ -3384,9 +3383,9 @@ qualifier can be omitted for the default location, or it can be one of ... -Notice that there are two PROLOGUE sections here, but there’s a subtle +Notice that there are two PROLOGUE sections here, but there's a subtle distinction between their functionality. For example, if you decide to -override Bison’s default definition for ‘YYLTYPE’, in which PROLOGUE +override Bison's default definition for ‘YYLTYPE’, in which PROLOGUE section should you write your new definition?(1) You should write it in the first since Bison will insert that code into the parser implementation file _before_ the default ‘YYLTYPE’ definition. In which @@ -3403,7 +3402,7 @@ Second, what if there is no ‘%union’? In that case, the second kind of PROLOGUE section is not available. This behavior is not intuitive. To avoid this subtle ‘%union’ dependency, rewrite the example using a -‘%code top’ and an unqualified ‘%code’. Let’s go ahead and add the new +‘%code top’ and an unqualified ‘%code’. Let's go ahead and add the new ‘YYLTYPE’ definition and the ‘trace_token’ prototype at the same time: %code top { @@ -3438,7 +3437,7 @@ PROLOGUE section is not available. This behavior is not intuitive. ... In this way, ‘%code top’ and the unqualified ‘%code’ achieve the same -functionality as the two kinds of PROLOGUE sections, but it’s always +functionality as the two kinds of PROLOGUE sections, but it's always explicit which kind you intend. Moreover, both kinds are always available even in the absence of ‘%union’. @@ -3446,7 +3445,7 @@ available even in the absence of ‘%union’. two lines before the warning need to appear near the top of the parser implementation file. The first line after the warning is required by ‘YYSTYPE’ and thus also needs to appear in the parser implementation -file. However, if you’ve instructed Bison to generate a parser header +file. However, if you've instructed Bison to generate a parser header file (*note Decl Summary::), you probably want that line to appear before the ‘YYSTYPE’ definition in that header file as well. The ‘YYLTYPE’ definition should also appear in the parser header file to @@ -3510,7 +3509,7 @@ provide ‘trace_token’ to modules that are external to your parser. Thus, you might wish for Bison to insert the prototype into both the parser header file and the parser implementation file. Since this function is not a dependency required by ‘YYSTYPE’ or ‘YYLTYPE’, it -doesn’t make sense to move its prototype to a ‘%code requires’. More +doesn't make sense to move its prototype to a ‘%code requires’. More importantly, since it depends upon ‘YYLTYPE’ and ‘yytoken_kind_t’, ‘%code requires’ is not sufficient. Instead, move its prototype from the unqualified ‘%code’ to a ‘%code provides’: @@ -3583,7 +3582,7 @@ semantic-type-related directives by semantic type: You could even place each of the above directive groups in the rules section of the grammar file next to the set of rules that uses the associated semantic type. (In the rules section, you must terminate -each of those directives with a semicolon.) And you don’t have to worry +each of those directives with a semicolon.) And you don't have to worry that some directive (like a ‘%union’) in the definitions section is going to adversely affect their functionality in some counter-intuitive manner just because it comes first. Such an organization is not @@ -3591,7 +3590,7 @@ possible using PROLOGUE sections. This section has been concerned with explaining the advantages of the four PROLOGUE alternatives over the original Yacc PROLOGUE. However, in -most cases when using these directives, you shouldn’t need to think +most cases when using these directives, you shouldn't need to think about all the low-level ordering issues discussed here. Instead, you should simply use these directives to label each block of your code according to its purpose and let Bison handle the ordering. ‘%code’ is @@ -3664,7 +3663,7 @@ of syntactically equivalent tokens. You use the symbol in grammar rules to mean that a token in that class is allowed. The symbol is represented in the Bison parser by a numeric code, and the ‘yylex’ function returns a token kind code to indicate what kind of token has -been read. You don’t need to know what the code value is; you can use +been read. You don't need to know what the code value is; you can use the symbol to stand for it. A “nonterminal symbol” stands for a class of syntactically equivalent @@ -3690,7 +3689,7 @@ token names. • A “character token kind” (or “literal character token”) is written in the grammar using the same syntax used in C for character constants; for example, ‘'+'’ is a character token kind. A - character token kind doesn’t need to be declared unless you need to + character token kind doesn't need to be declared unless you need to specify its semantic value data type (*note Value Type::), associativity, or precedence (*note Precedence::). @@ -3709,13 +3708,13 @@ token names. • A “literal string token” is written like a C string constant; for example, ‘"<="’ is a literal string token. A literal string token - doesn’t need to be declared unless you need to specify its semantic + doesn't need to be declared unless you need to specify its semantic value data type (*note Value Type::), associativity, or precedence (*note Precedence::). You can associate the literal string token with a symbolic name as an alias, using the ‘%token’ declaration (*note Token Decl::). If - you don’t do that, the lexical analyzer has to retrieve the token + you don't do that, the lexical analyzer has to retrieve the token code for the literal string token from the ‘yytname’ table (*note Calling Convention::). @@ -3748,7 +3747,7 @@ token kind is simply the positive numeric code of the character, so though you may need to convert it to ‘unsigned char’ to avoid sign-extension on hosts where ‘char’ is signed. Each named token kind becomes a C macro in the parser implementation file, so ‘yylex’ can use -the name to stand for the code. (This is why periods don’t make sense +the name to stand for the code. (This is why periods don't make sense in terminal symbols.) *Note Calling Convention::. If ‘yylex’ is defined in a separate file, you need to arrange for the @@ -3777,7 +3776,7 @@ that are incompatible with ASCII must rebuild those files before compiling them. The symbol ‘error’ is a terminal symbol reserved for error recovery -(*note Error Recovery::); you shouldn’t use it for any other purpose. +(*note Error Recovery::); you shouldn't use it for any other purpose. In particular, ‘yylex’ should never return this value. The default value of the error token is 256, unless you explicitly assigned 256 to one of your tokens with a ‘%token’ declaration. @@ -3996,14 +3995,14 @@ or The value of ‘api.value.type’ should be a type name that does not contain parentheses or square brackets. - Alternatively in C, instead of relying of Bison’s ‘%define’ support, + Alternatively in C, instead of relying of Bison's ‘%define’ support, you may rely on the C preprocessor and define ‘YYSTYPE’ as a macro: #define YYSTYPE double This macro definition must go in the prologue of the grammar file (*note Grammar Outline::). If compatibility with POSIX Yacc matters to you, -use this. Note however that Bison cannot know ‘YYSTYPE’’s value, not +use this. Note however that Bison cannot know ‘YYSTYPE’'s value, not even whether it is defined, so there are services it cannot provide. Besides this works only for C. @@ -4223,18 +4222,18 @@ references construct. Note that the vertical-bar character ‘|’ is really a rule separator, and actions are attached to a single rule. This is a difference with -tools like Flex, for which ‘|’ stands for either “or”, or “the same -action as that of the next rule”. In the following example, the action +tools like Flex, for which ‘|’ stands for either "or", or "the same +action as that of the next rule". In the following example, the action is triggered only when ‘b’ is found: a-or-b: 'a'|'b' { a_or_b_found = 1; }; - If you don’t specify an action for a rule, Bison supplies a default: + If you don't specify an action for a rule, Bison supplies a default: ‘$$ = $1’. Thus, the value of the first symbol in the rule becomes the value of the whole rule. Of course, the default action is valid only if the two data types match. There is no meaningful default action for an empty rule; every empty rule must have an explicit action unless the -rule’s value does not matter. +rule's value does not matter. ‘$N’ with N zero or negative is allowed for reference to tokens and groupings on the stack _before_ those that match the current rule. This @@ -4384,7 +4383,7 @@ readability and maintainability (*note Named References::): After the embedded statement is parsed, its semantic value becomes the value of the entire ‘let’-statement. Then the semantic value from the earlier action is used to restore the prior list of variables. This -removes the temporary ‘let’-variable from the list so that it won’t +removes the temporary ‘let’-variable from the list so that it won't appear to exist while the rest of the program is parsed. Because the types of the semantic values of midrule actions are @@ -4410,7 +4409,7 @@ without restoring it. Thus, ‘$5’ needs a destructor (*note Destructor Decl::), and Bison needs the type of the semantic value (‘context’) to select the right destructor. - As an extension to Yacc’s midrule actions, Bison offers a means to + As an extension to Yacc's midrule actions, Bison offers a means to type their semantic value: specify its type tag (‘<...>’ before the midrule action. @@ -4522,7 +4521,6 @@ a destructor for that symbol: declare_variable ($var); }; -  File: bison.info, Node: Midrule Conflicts, Prev: Midrule Action Translation, Up: Midrule Actions @@ -4733,7 +4731,7 @@ File: bison.info, Node: Printing Locations, Next: Location Default Action, Pr ------------------------ When using the default location type, the debug traces report the -symbols’ location. The generated parser does so using the +symbols' location. The generated parser does so using the ‘YYLOCATION_PRINT’ macro. -- Macro: YYLOCATION_PRINT (FILE, LOC); @@ -4757,7 +4755,7 @@ locations are much more general than semantic values, there is room in the output parser to redefine the default action to take for each rule. The ‘YYLLOC_DEFAULT’ macro is invoked each time a rule is matched, before the associated action is run. It is also invoked while -processing a syntax error, to compute the error’s location. Before +processing a syntax error, to compute the error's location. Before reporting an unresolvable syntactic ambiguity, a GLR parser invokes ‘YYLLOC_DEFAULT’ recursively to compute the location of that ambiguity. @@ -4768,7 +4766,7 @@ dedicated code from semantic actions. the location of the grouping (the result of the computation). When a rule is matched, the second parameter identifies locations of all right hand side elements of the rule being matched, and the third parameter is -the size of the rule’s right hand side. When a GLR parser reports an +the size of the rule's right hand side. When a GLR parser reports an ambiguity, which of multiple candidate right hand sides it passes to ‘YYLLOC_DEFAULT’ is undefined. When processing a syntax error, the second parameter identifies locations of the symbols that were discarded @@ -4863,7 +4861,6 @@ closing brace of the midrule action code: exp[res]: exp[x] '+' {$left = $x;}[left] exp[right] { $res = $left + $right; } - In references, in order to specify names containing dots and dashes, an explicit bracketed syntax ‘$[name]’ and ‘@[name]’ must be used: if-stmt: "if" '(' expr ')' "then" then.stmt ';' @@ -4911,7 +4908,7 @@ must declare it explicitly (*note Language and Grammar::). * Pure Decl:: Requesting a reentrant parser. * Push Decl:: Requesting a push parser. * Decl Summary:: Table of all Bison declarations. -* %define Summary:: Defining variables to adjust Bison’s behavior. +* %define Summary:: Defining variables to adjust Bison's behavior. * %code Summary:: Inserting code into the parser source.  @@ -4944,7 +4941,7 @@ follows: Bison will convert this into a definition in the parser, so that the function ‘yylex’ (if it is in this file) can use the name NAME to stand -for this token kind’s code. +for this token kind's code. Alternatively, you can use ‘%left’, ‘%right’, ‘%precedence’, or ‘%nonassoc’ instead of ‘%token’, if you wish to specify associativity @@ -4960,7 +4957,7 @@ field immediately following the token name: %token XNUM 0x12d // a GNU extension It is generally best, however, to let Bison choose the numeric codes for -all token kinds. Bison will automatically select codes that don’t +all token kinds. Bison will automatically select codes that don't conflict with each other or with normal characters. In the event that the stack type is a union, you must augment the @@ -5124,7 +5121,7 @@ code. -- Directive: %initial-action { CODE } Declare that the braced CODE must be invoked before parsing each time ‘yyparse’ is called. The CODE may use ‘$$’ (or ‘$$’) and - ‘@$’ — initial value and location of the lookahead — and the + ‘@$’ -- initial value and location of the lookahead -- and the ‘%parse-param’. For instance, if your locations use a file name, you may use @@ -5221,7 +5218,7 @@ the end token (token 0) if you redefine it from ‘$end’ to, for example, Finally, Bison will never invoke a ‘%destructor’ for an unreferenced midrule semantic value (*note Midrule Actions::). That is, Bison does not consider a midrule to have a semantic value if you do not reference -‘$$’ in the midrule’s action or ‘$N’ (where N is the right-hand side +‘$$’ in the midrule's action or ‘$N’ (where N is the right-hand side symbol position of the midrule) in any later action in that rule. However, if you do reference either, the Bison-generated parser will invoke the ‘<>’ ‘%destructor’ whenever it discards the midrule symbol. @@ -5354,7 +5351,7 @@ document this fact with an ‘%expect’ modifier as follows: Mid-rule actions generate implicit rules that are also subject to conflicts (*note Midrule Conflicts::). To attach an ‘%expect’ or -‘%expect-rr’ annotation to an implicit mid-rule action’s rule, put it +‘%expect-rr’ annotation to an implicit mid-rule action's rule, put it before the action. For example, %glr-parser @@ -5377,7 +5374,7 @@ other, and we should expect one reduce/reduce conflict for each. a verbose list of where the conflicts occur. Bison will also print the number of conflicts. - • Check each of the conflicts to make sure that Bison’s default + • Check each of the conflicts to make sure that Bison's default resolution is what you really want. If not, rewrite the grammar and go back to the beginning. @@ -5457,7 +5454,7 @@ completely parsed. A push parser, on the other hand, is called each time a new token is made available. A push parser is typically useful when the parser is part of a main -event loop in the client’s application. This is typically a requirement +event loop in the client's application. This is typically a requirement of a GUI, when the main event loop needs to be triggered within a certain time period. @@ -5484,7 +5481,7 @@ parser at a time. When a push parser is selected, Bison will generate some new symbols in the generated parser. ‘yypstate’ is a structure that the generated -parser uses to store the parser’s state. ‘yypstate_new’ is the function +parser uses to store the parser's state. ‘yypstate_new’ is the function that will create a new parser instance. ‘yypstate_delete’ will free the resources associated with the corresponding parser instance. Finally, ‘yypush_parse’ is the function that should be called whenever a token is @@ -5514,7 +5511,7 @@ would thus look like this: } while (status == YYPUSH_MORE); yypstate_delete (ps); - That’s it. Notice the next token is put into the global variable + That's it. Notice the next token is put into the global variable ‘yychar’ for use by the next invocation of the ‘yypush_parse’ function. Bison also supports both the push parser interface along with the @@ -5581,7 +5578,7 @@ Here is a summary of the declarations used to define a grammar: Decl::). -- Directive: %start - Specify the grammar’s start symbol (*note Start Decl::). + Specify the grammar's start symbol (*note Start Decl::). -- Directive: %expect Declare the expected number of shift/reduce conflicts, either @@ -5609,7 +5606,7 @@ directives: -- Directive: %define VARIABLE VALUE -- Directive: %define VARIABLE {VALUE} -- Directive: %define VARIABLE "VALUE" - Define a variable to adjust Bison’s behavior. *Note %define + Define a variable to adjust Bison's behavior. *Note %define Summary::. -- Directive: %defines @@ -5703,7 +5700,7 @@ directives: ‘yytoken_kind_t’, ‘YYSTYPE’, ‘YYLTYPE’. -- Directive: %no-lines - Don’t generate any ‘#line’ preprocessor commands in the parser + Don't generate any ‘#line’ preprocessor commands in the parser implementation file. Ordinarily Bison writes these commands in the parser implementation file so that the C compiler and debuggers will associate errors and object code with your source file (the @@ -5762,7 +5759,7 @@ directives: ‘YYNSTATES’ The number of parser states (*note Parser States::). - Here’s code for looking up a multicharacter token in ‘yytname’, + Here's code for looking up a multicharacter token in ‘yytname’, assuming that the characters of the token are stored in ‘token_buffer’, and assuming that the token does not contain any characters like ‘"’ that require escaping. @@ -5804,7 +5801,7 @@ File: bison.info, Node: %define Summary, Next: %code Summary, Prev: Decl Summ 3.7.14 %define Summary ---------------------- -There are many features of Bison’s behavior that can be controlled by +There are many features of Bison's behavior that can be controlled by assigning the feature a single value. For historical reasons, some such features are assigned values by dedicated directives, such as ‘%start’, which assigns the start symbol. However, newer such features are @@ -5853,7 +5850,7 @@ described below. • Language(s): C++ - • Purpose: Define the type of file names in Bison’s default + • Purpose: Define the type of file names in Bison's default location and position types. *Note Exposing the Location Classes::. @@ -5892,7 +5889,7 @@ described below. Using ‘api.header.include’ does not change the name of the generated header, only how it is included. - To work around limitations of Automake’s ‘ylwrap’ (which runs + To work around limitations of Automake's ‘ylwrap’ (which runs ‘bison’ with ‘--yacc’), ‘api.header.include’ is _not_ predefined when the output file is ‘y.tab.c’. Define it to avoid the duplication. @@ -5913,7 +5910,7 @@ described below. • Language(s): C++ - • Purpose: Define the name of the file in which Bison’s default + • Purpose: Define the name of the file in which Bison's default location and position types are generated. *Note Exposing the Location Classes::. @@ -5930,7 +5927,7 @@ described below. • Default Value: Not applicable if locations are not enabled, or if a user location type is specified (see - ‘api.location.type’). Otherwise, Bison’s ‘location’ is + ‘api.location.type’). Otherwise, Bison's ‘location’ is generated in ‘location.hh’ (*note C++ location::). • History: Introduced in Bison 3.2. @@ -6103,7 +6100,7 @@ described below. • Accepted Values: Any non empty string. Must be a valid identifier in the target language (typically a non empty - sequence of letters, underscores, and —not at the beginning— + sequence of letters, underscores, and --not at the beginning-- digits). The empty prefix is (generally) invalid: @@ -6163,7 +6160,7 @@ described below. • Accepted Values: Any string. Must be a valid identifier prefix in the target language (typically, a possibly empty - sequence of letters, underscores, and —not at the beginning— + sequence of letters, underscores, and --not at the beginning-- digits). • Default Value: empty @@ -6250,7 +6247,7 @@ described below. properly supported yet. ‘union-directive’ (C, C++, D) The type is defined thanks to the ‘%union’ directive. - You don’t have to define ‘api.value.type’ in that case, + You don't have to define ‘api.value.type’ in that case, using ‘%union’ suffices. *Note Union Decl::. For instance: %define api.value.type union-directive @@ -6373,7 +6370,7 @@ described below. In C++, when variants are used (*note C++ Variants::), symbols must be constructed and destroyed properly. This option checks these constraints using runtime type information - (RTTI). Therefore the generated code cannot be compiled with + (RTTI). Therefore the generated code cannot be compiled with RTTI disabled (via compiler options such as ‘-fno-rtti’). • Accepted Values: Boolean @@ -6487,9 +6484,9 @@ qualifiers produce an error. Some of the accepted qualifiers are: • Purpose: This is the best place to write dependency code required for the value and location types (‘YYSTYPE’ and - ‘YYLTYPE’ in C). In other words, it’s the best place to define + ‘YYLTYPE’ in C). In other words, it's the best place to define types referenced in ‘%union’ directives. In C, if you use - ‘#define’ to override Bison’s default ‘YYSTYPE’ and ‘YYLTYPE’ + ‘#define’ to override Bison's default ‘YYSTYPE’ and ‘YYLTYPE’ definitions, then it is also the best place. However you should rather ‘%define’ ‘api.value.type’ and ‘api.location.type’. @@ -6571,7 +6568,7 @@ by PREFIX (i.e., PREFIX upper-cased) instead of ‘YY’. ‘yylval’, ‘yylloc’, ‘yychar’ and ‘yydebug’. If you use a push parser, ‘yypush_parse’, ‘yypull_parse’, ‘yypstate’, ‘yypstate_new’ and ‘yypstate_delete’ will also be renamed. The renamed macros include -‘YYSTYPE’, ‘YYLTYPE’, and ‘YYDEBUG’, which is treated specifically — +‘YYSTYPE’, ‘YYLTYPE’, and ‘YYDEBUG’, which is treated specifically -- more about this below. For example, if you use ‘%define api.prefix {c}’, the names become @@ -6609,7 +6606,7 @@ beginning of the parser implementation file, defining ‘yyparse’ as int yyparse (void); This effectively substitutes one name for the other in the entire -parser implementation file, thus the “original” names (‘yylex’, +parser implementation file, thus the "original" names (‘yylex’, ‘YYSTYPE’, ...) are also usable in the parser implementation file. However, in the parser header file, the symbols are defined renamed, @@ -6667,7 +6664,7 @@ grammar file, you are likely to run into trouble. which reads tokens. * Error Reporting:: Passing error messages to the user. * Action Features:: Special features for use in actions. -* Internationalization:: How to let the parser speak in the user’s +* Internationalization:: How to let the parser speak in the user's native language.  @@ -6714,7 +6711,7 @@ declaration ‘%parse-param’: declaring functions or prototypes. The last identifier in ARGUMENT-DECLARATION must be the argument name. - Here’s an example. Write this in the parser: + Here's an example. Write this in the parser: %parse-param {int *nastiness} {int *randomness} @@ -6903,7 +6900,7 @@ that there is nothing left afterwards. *Note Calling Convention::, for an example. Returning ‘YYUNDEF’ tells the parser that some lexical error was -found. It will emit an error message about an “invalid token”, and +found. It will emit an error message about an "invalid token", and enter error-recovery (*note Error Recovery::). Returning an unknown token kind results in the exact same behavior. @@ -6974,9 +6971,9 @@ if the type is ‘int’ (the default), you might write this in ‘yylex’: return INT; /* Return the kind of the token. */ ... - When you are using multiple data types, ‘yylval’’s type is a union + When you are using multiple data types, ‘yylval’'s type is a union made from the ‘%union’ declaration (*note Union Decl::). So when you -store a token’s value, you must use the proper member of the union. If +store a token's value, you must use the proper member of the union. If the ‘%union’ declaration looks like this: %union { @@ -7117,7 +7114,7 @@ incorrect information if LAC is not enabled (*note LAC::). The parser can detect one other kind of error: memory exhaustion. This can happen when the input contains constructions that are very -deeply nested. It isn’t likely you will encounter this, since the Bison +deeply nested. It isn't likely you will encounter this, since the Bison parser normally extends its stack automatically up to a very large limit. But if memory is exhausted, ‘yyparse’ calls ‘yyerror’ in the usual fashion, except that the argument string is ‘"memory exhausted"’. @@ -7175,9 +7172,9 @@ then the parser no longer passes syntax error messages to ‘yyerror’, rather it delegates that task to the user by calling the ‘yyreport_syntax_error’ function. - The following functions and types are “‘static’”: they are defined in + The following functions and types are "‘static’": they are defined in the implementation file (‘*.c’) and available only from there. They are -meant to be used from the grammar’s epilogue. +meant to be used from the grammar's epilogue. -- Function: static int yyreport_syntax_error (const yypcontext_t *CTX) Report a syntax error to the user. Return 0 on success, ‘YYENOMEM’ @@ -7211,7 +7208,7 @@ meant to be used from the grammar’s epilogue. -- Function: static yysymbol_kind_t yypcontext_token (const yypcontext_t *CTX) - The “unexpected” token: the symbol kind of the lookahead token that + The "unexpected" token: the symbol kind of the lookahead token that caused the syntax error. Returns ‘YYSYMBOL_YYEMPTY’ if there is no lookahead. @@ -7392,12 +7389,12 @@ File: bison.info, Node: Internationalization, Prev: Action Features, Up: Inte A Bison-generated parser can print diagnostics, including error and tracing messages. By default, they appear in English. However, Bison -also supports outputting diagnostics in the user’s native language. To +also supports outputting diagnostics in the user's native language. To make this work, the user should set the usual environment variables. -*Note The User’s View: (gettext)Users. For example, the shell command -‘export LC_ALL=fr_CA.UTF-8’ might set the user’s locale to French +*Note The User's View: (gettext)Users. For example, the shell command +‘export LC_ALL=fr_CA.UTF-8’ might set the user's locale to French Canadian using the UTF-8 encoding. The exact set of available locales -depends on the user’s installation. +depends on the user's installation. * Menu: @@ -7411,13 +7408,13 @@ File: bison.info, Node: Enabling I18n, Next: Token I18n, Up: Internationaliza ----------------------------------- The maintainer of a package that uses a Bison-generated parser enables -the internationalization of the parser’s output through the following +the internationalization of the parser's output through the following steps. Here we assume a package that uses GNU Autoconf and GNU Automake. 1. Into the directory containing the GNU Autoconf macros used by the - package —often called ‘m4’— copy the ‘bison-i18n.m4’ file installed - by Bison under ‘share/aclocal/bison-i18n.m4’ in Bison’s + package --often called ‘m4’-- copy the ‘bison-i18n.m4’ file + installed by Bison under ‘share/aclocal/bison-i18n.m4’ in Bison's installation directory. For example: cp /usr/local/share/aclocal/bison-i18n.m4 m4/bison-i18n.m4 @@ -7430,7 +7427,7 @@ Automake. to enable translations in the Bison-generated parser. 3. In the ‘main’ function of your program, designate the directory - containing Bison’s runtime message catalog, through a call to + containing Bison's runtime message catalog, through a call to ‘bindtextdomain’ with domain name ‘bison-runtime’. For example: bindtextdomain ("bison-runtime", BISON_LOCALEDIR); @@ -7478,17 +7475,17 @@ internationalization marker (‘_("function")’). parser will use both ‘N_’ and ‘_’, that must be defined (*note The Programmer’s View: (gettext)Programmers.). They are used only on string aliases marked for translation. In other words, even if your catalog -features a translation for “function”, then with +features a translation for "function", then with %token FUN "function" VAR _("variable") -“function” will appear untranslated in debug traces and error messages. +"function" will appear untranslated in debug traces and error messages. Unless defined by the user, the end-of-file token, ‘YYEOF’, is -provided “end of file” as an alias. It is also internationalized if the +provided "end of file" as an alias. It is also internationalized if the user internationalized tokens. To map it to another string, use: %token END 0 _("end of input") @@ -7512,11 +7509,11 @@ When the last N tokens and groupings shifted match the components of a grammar rule, they can be combined according to that rule. This is called “reduction”. Those tokens and groupings are replaced on the stack by a single grouping whose symbol is the result (left hand side) -of that rule. Running the rule’s action is part of the process of +of that rule. Running the rule's action is part of the process of reduction, because this is what computes the semantic value of the resulting grouping. - For example, if the infix calculator’s parser stack contains this: + For example, if the infix calculator's parser stack contains this: 1 + 5 * 3 @@ -7533,7 +7530,7 @@ At this point, another reduction can be made, resulting in the single value 16. Then the newline token can be shifted. The parser tries, by shifts and reductions, to reduce the entire -input down to a single grouping whose symbol is the grammar’s +input down to a single grouping whose symbol is the grammar's start-symbol (*note Language and Grammar::). This kind of parser is known in the literature as a bottom-up parser. @@ -7543,7 +7540,7 @@ start-symbol (*note Language and Grammar::). * Lookahead:: Parser looks one token ahead when deciding what to do. * Shift/Reduce:: Conflicts: when either shifting or reduction is valid. * Precedence:: Operator precedence works by resolving conflicts. -* Contextual Precedence:: When an operator’s precedence depends on context. +* Contextual Precedence:: When an operator's precedence depends on context. * Parser States:: The parser is a finite-state-machine with stack. * Reduce/Reduce:: When two rules are applicable in the same situation. * Mysterious Conflicts:: Conflicts that look unjustified. @@ -7560,7 +7557,7 @@ File: bison.info, Node: Lookahead, Next: Shift/Reduce, Up: Algorithm The Bison parser does _not_ always reduce immediately as soon as the last N tokens and groupings match a rule. This is because such a simple strategy is inadequate to handle most languages. Instead, when a -reduction is possible, the parser sometimes “looks ahead” at the next +reduction is possible, the parser sometimes "looks ahead" at the next token in order to decide what to do. When a token is read, it is not immediately shifted; first it becomes @@ -7630,7 +7627,7 @@ rule. This situation, where either a shift or a reduction would be valid, is called a “shift/reduce conflict”. Bison is designed to resolve these conflicts by choosing to shift, unless otherwise directed by operator -precedence declarations. To see the reason for this, let’s contrast it +precedence declarations. To see the reason for this, let's contrast it with the other alternative. Since the parser prefers to shift the ‘"else"’, the result is to @@ -7657,10 +7654,10 @@ Bison accomplishes by choosing to shift rather than reduce. (It would ideally be cleaner to write an unambiguous grammar, but that is very hard to do in this case.) This particular ambiguity was first encountered in the specifications of Algol 60 and is called the -“dangling ‘else’” ambiguity. +"dangling ‘else’" ambiguity. To assist the grammar author in understanding the nature of each -conflict, Bison can be asked to generate “counterexamples”. In the +conflict, Bison can be asked to generate "counterexamples". In the present case it actually even proves that the grammar is ambiguous by exhibiting a string with two different parses: @@ -7684,7 +7681,7 @@ exhibiting a string with two different parses: shift/reduce conflicts, you can use the ‘%expect N’ declaration. There will be no warning as long as the number of shift/reduce conflicts is exactly N, and Bison will report an error if there is a different -number. *Note Expect Decl::. However, we don’t recommend the use of +number. *Note Expect Decl::. However, we don't recommend the use of ‘%expect’ (except ‘%expect 0’!), as an equal number of conflicts does not mean that they are the _same_. When possible, you should rather use precedence directives to _fix_ the conflicts explicitly (*note Non @@ -7784,7 +7781,7 @@ list of tokens, which are operators whose precedence and associativity is being declared. The ‘%left’ declaration makes all those operators left-associative and the ‘%right’ declaration makes them right-associative. A third alternative is ‘%nonassoc’, which declares -that it is a syntax error to find the same operator twice “in a row”. +that it is a syntax error to find the same operator twice "in a row". The last alternative, ‘%precedence’, allows to define only precedence and no associativity at all. As a result, any associativity-related conflict that remains will be reported as an compile-time error. The @@ -7873,8 +7870,8 @@ Precedence::.) Finally, the resolution of conflicts works by comparing the precedence of the rule being considered with that of the lookahead -token. If the token’s precedence is higher, the choice is to shift. If -the rule’s precedence is higher, the choice is to reduce. If they have +token. If the token's precedence is higher, the choice is to shift. If +the rule's precedence is higher, the choice is to reduce. If they have equal precedence, the choice is made based on the associativity of that precedence level. The verbose output file made by ‘-v’ (*note Invocation::) says how each conflict was resolved. @@ -7890,7 +7887,7 @@ File: bison.info, Node: Non Operators, Prev: How Precedence, Up: Precedence Using properly precedence and associativity directives can help fixing shift/reduce conflicts that do not involve arithmetic-like operators. -For instance, the “dangling ‘else’” problem (*note Shift/Reduce::) can +For instance, the "dangling ‘else’" problem (*note Shift/Reduce::) can be solved elegantly in two different ways. In the present case, the conflict is between the token ‘"else"’ @@ -7910,12 +7907,12 @@ action, use right associativity: %right "then" "else" Neither solution is perfect however. Since Bison does not provide, -so far, “scoped” precedence, both force you to declare the precedence of +so far, "scoped" precedence, both force you to declare the precedence of these keywords with respect to the other operators your grammar. Therefore, instead of being warned about new conflicts you would be unaware of (e.g., a shift/reduce conflict due to ‘if test then 1 else 2 + 3’ being ambiguous: ‘if test then 1 else (2 + 3)’ or ‘(if test then 1 -else 2) + 3’?), the conflict will be already “fixed”. +else 2) + 3’?), the conflict will be already "fixed".  File: bison.info, Node: Contextual Precedence, Next: Parser States, Prev: Precedence, Up: Algorithm @@ -7936,8 +7933,8 @@ the ‘%prec’ modifier for rules. The ‘%prec’ modifier declares the precedence of a particular rule by specifying a terminal symbol whose precedence should be used for that -rule. It’s not necessary for that symbol to appear otherwise in the -rule. The modifier’s syntax is: +rule. It's not necessary for that symbol to appear otherwise in the +rule. The modifier's syntax is: %prec TERMINAL-SYMBOL @@ -7980,9 +7977,9 @@ do next. Each time a lookahead token is read, the current parser state together with the kind of lookahead token are looked up in a table. -This table entry can say, “Shift the lookahead token.” In this case, it +This table entry can say, "Shift the lookahead token." In this case, it also specifies the new parser state, which is pushed onto the top of the -parser stack. Or it can say, “Reduce using rule number N.” This means +parser stack. Or it can say, "Reduce using rule number N." This means that a certain number of tokens or groupings are taken off the top of the stack, and replaced by one grouping. In other words, that number of states are popped from the stack, and one new state is pushed. @@ -8030,8 +8027,8 @@ via ‘maybeword’ and then the second rule. You might think that this is a distinction without a difference, because it does not change whether any particular input is valid or not. But it does affect which actions are run. One parsing order runs the -second rule’s action; the other runs the first rule’s action and the -third rule’s action. In this example, the output of the program +second rule's action; the other runs the first rule's action and the +third rule's action. In this example, the output of the program changes. Bison resolves a reduce/reduce conflict by choosing to use the rule @@ -8147,7 +8144,7 @@ File: bison.info, Node: Mysterious Conflicts, Next: Tuning LR, Prev: Reduce/R 5.7 Mysterious Conflicts ======================== -Sometimes reduce/reduce conflicts can occur that don’t look warranted. +Sometimes reduce/reduce conflicts can occur that don't look warranted. Here is an example: %% @@ -8182,7 +8179,7 @@ default_, for historical reasons. In this grammar, two contexts, that after an ‘"id"’ at the beginning of a ‘param_spec’ and likewise at the beginning of a ‘return_spec’, are similar enough that Bison assumes they are the same. They appear similar because the same set of rules would -be active—the rule for reducing to a ‘name’ and that for reducing to a +be active--the rule for reducing to a ‘name’ and that for reducing to a ‘type’. Bison is unable to determine at that stage of processing that the rules would require different lookahead tokens in the two contexts, so it makes a single parser state for them both. Combining the two @@ -8197,7 +8194,7 @@ algorithm. Either IELR(1) or canonical LR(1) would suffice, but the former is more efficient and easier to debug during development. *Note LR Table Construction::, for details. - If you instead wish to work around LALR(1)’s limitations, you can + If you instead wish to work around LALR(1)'s limitations, you can often fix a mysterious conflict by identifying the two parser states that are being confused, and adding something to make them look distinct. In the above example, adding one rule to ‘return_spec’ as @@ -8243,11 +8240,11 @@ File: bison.info, Node: Tuning LR, Next: Generalized LR Parsing, Prev: Myster 5.8 Tuning LR ============= -The default behavior of Bison’s LR-based parsers is chosen mostly for +The default behavior of Bison's LR-based parsers is chosen mostly for historical reasons, but that behavior is often not robust. For example, in the previous section, we discussed the mysterious conflicts that can -be produced by LALR(1), Bison’s default parser table construction -algorithm. Another example is Bison’s ‘%define parse.error verbose’ +be produced by LALR(1), Bison's default parser table construction +algorithm. Another example is Bison's ‘%define parse.error verbose’ directive, which instructs the generated parser to produce verbose syntax error messages, which can sometimes contain incorrect information. @@ -8310,7 +8307,7 @@ use IELR will result in unnecessarily large parser tables. That is, IELR generates LALR tables when LALR (using a deterministic parsing algorithm) is sufficient to support the full language-recognition power of LR. Thus, by enabling IELR at the start of grammar development, you -can safely and completely eliminate the need to consider LALR’s +can safely and completely eliminate the need to consider LALR's shortcomings. While IELR is almost always preferable, there are circumstances where @@ -8335,7 +8332,7 @@ each parser table construction algorithm within Bison: to resolve conflicts statically, GLR behaves more like a deterministic parser in the syntactic contexts where those conflicts appear, and so either IELR or canonical LR can then - be helpful to avoid LALR’s mysterious behavior. + be helpful to avoid LALR's mysterious behavior. • Malformed grammars. @@ -8354,7 +8351,7 @@ each parser table construction algorithm within Bison: sentences. However, like LALR, IELR merges parser states during parser table construction so that the number of parser states is often an order of magnitude less than for canonical LR. More - importantly, because canonical LR’s extra parser states may contain + importantly, because canonical LR's extra parser states may contain duplicate conflicts in the case of non-LR grammars, the number of conflicts for IELR is often an order of magnitude less as well. This effect can significantly reduce the complexity of developing a @@ -8533,7 +8530,7 @@ enable default reductions in consistent states, canonical LR and IELR behave almost exactly the same for both syntactically acceptable and syntactically unacceptable input. While LALR still does not support the full language-recognition power of canonical LR and IELR, LAC at least -enables LALR’s syntax error handling to correctly reflect LALR’s +enables LALR's syntax error handling to correctly reflect LALR's language-recognition power. There are a few caveats to consider when using LAC: @@ -8564,7 +8561,7 @@ language-recognition power. reductions in consistent states and shift actions, the parser never has to initiate an exploratory parse. Moreover, the most time-consuming tasks in a parse are often the file I/O, the lexical - analysis performed by the scanner, and the user’s semantic actions, + analysis performed by the scanner, and the user's semantic actions, but none of these are performed during the exploratory parse. Finally, the base of the temporary stack used during an exploratory parse is a pointer into the normal parser state stack so that the @@ -8582,7 +8579,7 @@ File: bison.info, Node: Unreachable States, Prev: LAC, Up: Tuning LR 5.8.4 Unreachable States ------------------------ -If there exists no sequence of transitions from the parser’s start state +If there exists no sequence of transitions from the parser's start state to some state S, then Bison considers S to be an “unreachable state”. A state can become unreachable during conflict resolution if Bison disables a shift action leading to it from a predecessor state. @@ -8602,7 +8599,7 @@ understand the relationship between the parser and the grammar. Unreachable states may contain conflicts and may use rules not used in any other state. Thus, keeping unreachable states may induce - warnings that are irrelevant to your parser’s behavior, and it may + warnings that are irrelevant to your parser's behavior, and it may eliminate warnings that are relevant. Of course, the change in warnings may actually be relevant to a parser table analysis that wants to keep unreachable states, so this behavior will likely @@ -8635,7 +8632,7 @@ The same is true of languages that require more than one symbol of lookahead, since the parser lacks the information necessary to make a decision at the point it must be made in a shift/reduce parser. Finally, as previously mentioned (*note Mysterious Conflicts::), there -are languages where Bison’s default choice of how to summarize the input +are languages where Bison's default choice of how to summarize the input seen so far loses necessary information. When you use the ‘%glr-parser’ declaration in your grammar file, @@ -8685,7 +8682,7 @@ length of the input times the maximum number of stacks required for any prefix of the input. Thus, really ambiguous or nondeterministic grammars can require exponential time and space to process. Such badly behaving examples, however, are not generally of practical interest. -Usually, nondeterminism in a grammar is local—the parser is “in doubt” +Usually, nondeterminism in a grammar is local--the parser is "in doubt" only for a few tokens at a time. Therefore, the current data structure should generally be adequate. On LR(1) portions of a grammar, in particular, it is only slightly slower than with the deterministic LR(1) @@ -8837,14 +8834,14 @@ shifted will error messages resume. as any other rules can. You can make error messages resume immediately by using the macro -‘yyerrok’ in an action. If you do this in the error rule’s action, no +‘yyerrok’ in an action. If you do this in the error rule's action, no error messages will be suppressed. This macro requires no arguments; ‘yyerrok;’ is a valid C statement. The previous lookahead token is reanalyzed immediately after an error. If this is unacceptable, then the macro ‘yyclearin’ may be used to clear this token. Write the statement ‘yyclearin;’ in the error -rule’s action. *Note Action Features::. +rule's action. *Note Action Features::. For example, suppose that on a syntax error, an error handling routine is called that advances the input stream to some point where @@ -8875,7 +8872,7 @@ for such languages. * Tie-in Recovery:: Lexical tie-ins have implications for how error recovery rules must be written. - (Actually, “kludge” means any technique that gets its job done but is + (Actually, "kludge" means any technique that gets its job done but is neither clean nor robust.)  @@ -8904,7 +8901,7 @@ choice of token kind to recognize. ‘IDENTIFIER’ is accepted as an expression, but ‘TYPENAME’ is not. ‘TYPENAME’ can start a declaration, but ‘IDENTIFIER’ cannot. In contexts where the meaning of the identifier is _not_ significant, such as in declarations that can shadow -a typedef name, either ‘TYPENAME’ or ‘IDENTIFIER’ is accepted—there is +a typedef name, either ‘TYPENAME’ or ‘IDENTIFIER’ is accepted--there is one rule for each of the two token kinds. This technique is simple to use if the decision of which kinds of @@ -8922,13 +8919,13 @@ earlier: } Unfortunately, the name being declared is separated from the -declaration construct itself by a complicated syntactic structure—the -“declarator”. +declaration construct itself by a complicated syntactic structure--the +"declarator". As a result, part of the Bison parser for C needs to be duplicated, with all the nonterminal names changed: once for parsing a declaration in which a typedef name can be redefined, and once for parsing a -declaration in which that can’t be done. Here is a part of the +declaration in which that can't be done. Here is a part of the duplication, with actions omitted for brevity: initdcl: @@ -9050,7 +9047,7 @@ way you can write the action to determine whether a ‘hex’ construct is being aborted or not. So if you are using a lexical tie-in, you had better make sure your error recovery rules are not of this kind. Each rule must be such that you can be sure that it always will, or always -won’t, have to clear the flag. +won't, have to clear the flag.  File: bison.info, Node: Debugging, Next: Invocation, Prev: Context Dependency, Up: Top @@ -9058,7 +9055,7 @@ File: bison.info, Node: Debugging, Next: Invocation, Prev: Context Dependency 8 Debugging Your Parser *********************** -Developing a parser can be a challenge, especially if you don’t +Developing a parser can be a challenge, especially if you don't understand the algorithm (*note Algorithm::). This chapter explains how to understand and debug a parser. @@ -9118,7 +9115,7 @@ features one shift/reduce conflict: else.y: warning: 1 shift/reduce conflict [-Wconflicts-sr] else.y: note: rerun with option '-Wcounterexamples' to generate conflict counterexamples -Let’s rerun ‘bison’ with the option ‘-Wcex’/‘-Wcounterexamples’(the +Let's rerun ‘bison’ with the option ‘-Wcex’/‘-Wcounterexamples’(the following output is actually in color): else.y: warning: 1 shift/reduce conflict [-Wconflicts-sr] @@ -9205,7 +9202,7 @@ shows that the grammar accepts the empty input in two different ways. two ways. In these cases, counterexample generation will provide two examples that are the same up until the dot. Most notably, this will happen when your grammar requires a stronger parser (more lookahead, LR -instead of LALR). The following example isn’t LR(1): +instead of LALR). The following example isn't LR(1): %token ID %% @@ -9309,7 +9306,7 @@ might vary, but the interpretation is the same. The first section reports useless tokens, nonterminals and rules. Useless nonterminals and rules are removed in order to produce a smaller parser, but useless tokens are preserved, since they might be used by -the scanner (note the difference between “useless” and “unused” below): +the scanner (note the difference between "useless" and "unused" below): Nonterminals useless in grammar useless @@ -9373,14 +9370,14 @@ input cursor. exp go to state 2 - This reads as follows: “state 0 corresponds to being at the very + This reads as follows: "state 0 corresponds to being at the very beginning of the parsing, in the initial rule, right before the start symbol (here, ‘exp’). When the parser returns to this state right after having reduced a rule that produced an ‘exp’, the control flow jumps to state 2. If there is no such transition on a nonterminal symbol, and the lookahead is a ‘NUM’, then this token is shifted onto the parse stack, and the control flow jumps to state 1. Any other lookahead -triggers a syntax error.” +triggers a syntax error." Even though the only active rule in state 0 seems to be rule 0, the report lists ‘NUM’ as a lookahead token because ‘NUM’ can be at the @@ -9749,7 +9746,7 @@ distinguished by a red filling color on these nodes, just like how they are reported between square brackets in the verbose file. The reduction corresponding to the rule number 0 is the acceptation -state. It is shown as a blue diamond, labeled “Acc”. +state. It is shown as a blue diamond, labeled "Acc". Graphical Representation of Gotos --------------------------------- @@ -9802,7 +9799,7 @@ File: bison.info, Node: Tracing, Prev: Xml, Up: Debugging 8.5 Tracing Your Parser ======================= -When a Bison grammar compiles properly but parses “incorrectly”, the +When a Bison grammar compiles properly but parses "incorrectly", the ‘yydebug’ parser-trace feature helps figuring out why. * Menu: @@ -9890,7 +9887,7 @@ arrive at the place where something undesirable happens, and you will see which parts of the grammar are to blame. The parser implementation file is a C/C++/D/Java program and you can -use debuggers on it, but it’s not easy to interpret what it is doing. +use debuggers on it, but it's not easy to interpret what it is doing. The parser function is a finite-state machine interpreter, and aside from the actions it executes the same code over and over. Only the values of variables show where in the grammar it is working. @@ -9923,7 +9920,7 @@ its prologue: The ‘%define’ directive instructs Bison to generate run-time trace support. Then, activation of these traces is controlled at run-time by the ‘yydebug’ variable, which is disabled by default. Because these -traces will refer to the “states” of the parser, it is helpful to ask +traces will refer to the "states" of the parser, it is helpful to ask for the creation of a description of that parser; this is the purpose of (admittedly ill-named) ‘%verbose’ directive. @@ -10059,10 +10056,10 @@ The usual way to invoke Bison is as follows: $ bison FILE Here FILE is the grammar file name, which usually ends in ‘.y’. The -parser implementation file’s name is made by replacing the ‘.y’ with +parser implementation file's name is made by replacing the ‘.y’ with ‘.tab.c’ and removing any leading directory. Thus, the ‘bison foo.y’ file name yields ‘foo.tab.c’, and the ‘bison hack/foo.y’ file name -yields ‘foo.tab.c’. It’s also possible, in case you are writing C++ +yields ‘foo.tab.c’. It's also possible, in case you are writing C++ code instead of C in your grammar file, to name it ‘foo.ypp’ or ‘foo.y++’. Then, the output files will take an extension like the given one as input (respectively ‘foo.tab.cpp’ and ‘foo.tab.c++’). This @@ -10183,8 +10180,8 @@ Options controlling the global behavior of ‘bison’. Activate miscellaneous FEATUREs. FEATURE can be one of: ‘caret’ ‘diagnostics-show-caret’ - Show caret errors, in a manner similar to GCC’s - ‘-fdiagnostics-show-caret’, or Clang’s ‘-fcaret-diagnostics’. + Show caret errors, in a manner similar to GCC's + ‘-fdiagnostics-show-caret’, or Clang's ‘-fcaret-diagnostics’. The location provided with the message is used to quote the corresponding line of the source file, underlining the important part of it with carets (‘^’). Here is an example, @@ -10225,8 +10222,8 @@ Options controlling the global behavior of ‘bison’. ‘fixit’ ‘diagnostics-parseable-fixits’ - Show machine-readable fixes, in a manner similar to GCC’s and - Clang’s ‘-fdiagnostics-parseable-fixits’. + Show machine-readable fixes, in a manner similar to GCC's and + Clang's ‘-fdiagnostics-parseable-fixits’. Fix-its are generated for duplicate directives: @@ -10307,8 +10304,8 @@ Options controlling the diagnostics. %type cond "condition" - does not define “condition” as a string alias to - ‘cond’—nonterminal symbols do not have string aliases. It is + does not define "condition" as a string alias to + ‘cond’--nonterminal symbols do not have string aliases. It is rather equivalent to %nterm cond @@ -10450,7 +10447,7 @@ Options controlling the diagnostics. ‘-Wno-error=CATEGORY’ Deactivate the error treatment for this CATEGORY. However, the - warning itself won’t be disabled, or enabled, by this option. + warning itself won't be disabled, or enabled, by this option. ‘--color’ Equivalent to ‘--color=always’. @@ -10539,7 +10536,7 @@ Options changing the generated parsers. ‘-l’ ‘--no-lines’ - Don’t put any ‘#line’ preprocessor commands in the parser + Don't put any ‘#line’ preprocessor commands in the parser implementation file. Ordinarily Bison puts them in the parser implementation file so that the C compiler and debuggers will associate errors with your source file, the grammar file. This @@ -10574,11 +10571,11 @@ Options changing the generated parsers. void yyerror (const char *); As a Bison extension, additional arguments required by ‘%pure-parser’, ‘%locations’, ‘%lex-param’ and ‘%parse-param’ - are taken into account. You may disable ‘yyerror’’s prototype + are taken into account. You may disable ‘yyerror’'s prototype with ‘#define yyerror yyerror’ (as specified by POSIX), or with ‘#define YYERROR_IS_DECLARED’ (a Bison extension). Likewise for ‘yylex’. - • Imitate Yacc’s output file name conventions, so that the + • Imitate Yacc's output file name conventions, so that the parser implementation file is called ‘y.tab.c’, and the other outputs are called ‘y.output’ and ‘y.tab.h’. Do not use ‘--yacc’ just to change the output file names since it also @@ -10636,7 +10633,7 @@ Options controlling the output. ‘state’ Description of the grammar, conflicts (resolved and - unresolved), and parser’s automaton. + unresolved), and parser's automaton. ‘itemset’ Implies ‘state’ and augments the description of the automaton @@ -10645,7 +10642,7 @@ Options controlling the output. ‘lookahead’ Implies ‘state’ and augments the description of the automaton - with each rule’s lookahead set. + with each rule's lookahead set. ‘solved’ Implies ‘state’. Explain how conflicts were solved thanks to @@ -10682,7 +10679,7 @@ Options controlling the output. ‘-g [FILE]’ ‘--graph[=FILE]’ - Output a graphical representation of the parser’s automaton + Output a graphical representation of the parser's automaton computed by Bison, in Graphviz (https://www.graphviz.org/) DOT (https://www.graphviz.org/doc/info/lang.html) format. ‘FILE’ is optional. If omitted and the grammar file is ‘foo.y’, the output @@ -10690,7 +10687,7 @@ Options controlling the output. ‘-x [FILE]’ ‘--xml[=FILE]’ - Output an XML report of the parser’s automaton computed by Bison. + Output an XML report of the parser's automaton computed by Bison. ‘FILE’ is optional. If omitted and the grammar file is ‘foo.y’, the output file will be ‘foo.xml’. @@ -10749,18 +10746,18 @@ File: bison.info, Node: Yacc Library, Prev: Option Cross Key, Up: Invocation The Yacc library contains default implementations of the ‘yyerror’ and ‘main’ functions. These default implementations are normally not useful, but POSIX requires them. To use the Yacc library, link your -program with the ‘-ly’ option. Note that Bison’s implementation of the +program with the ‘-ly’ option. Note that Bison's implementation of the Yacc library is distributed under the terms of the GNU General Public License (*note Copying::). - If you use the Yacc library’s ‘yyerror’ function, you should declare + If you use the Yacc library's ‘yyerror’ function, you should declare ‘yyerror’ as follows: int yyerror (char const *); The ‘int’ value returned by this ‘yyerror’ is ignored. - The implementation of Yacc library’s ‘main’ function is: + The implementation of Yacc library's ‘main’ function is: int main (void) { @@ -10783,7 +10780,7 @@ File: bison.info, Node: Other Languages, Next: History, Prev: Invocation, Up In addition to C, Bison can generate parsers in C++, D and Java. This chapter is devoted to these languages. The reader is expected to understand how Bison works; read the introductory chapters first if you -don’t. +don't. * Menu: @@ -10832,7 +10829,7 @@ and that we generate C++. %require "3.2" %language "c++" - Let’s dive directly into the middle part: the grammar. Our input is + Let's dive directly into the middle part: the grammar. Our input is a simple list of strings, that we display once the parsing is done. %% @@ -10847,7 +10844,7 @@ a simple list of strings, that we display once the parsing is done. ; We used a vector of strings as a semantic value! To use genuine C++ -objects as semantic values—not just PODs—we cannot rely on the union +objects as semantic values--not just PODs--we cannot rely on the union that Bison uses by default to store them, we need _variants_ (*note C++ Variants::): @@ -11017,7 +11014,7 @@ argument for its constructor. A structure that contains (only) the ‘token_kind_type’ enumeration, which defines the tokens. To refer to the token ‘FOO’, use ‘yy::parser::token::FOO’. The scanner can use ‘typedef - yy::parser::token token;’ to “import” the token enumeration (*note + yy::parser::token token;’ to "import" the token enumeration (*note Calc++ Scanner::). -- Type of parser: token_kind_type @@ -11151,7 +11148,7 @@ section, and in particular, object types can be used without pointers. To enable variant-based semantic values, set the ‘%define’ variable ‘api.value.type’ to ‘variant’ (*note %define Summary::). Then ‘%union’ is ignored; instead of using the name of the fields of the ‘%union’ to -“type” the symbols, use genuine types. +"type" the symbols, use genuine types. For instance, instead of: @@ -11196,14 +11193,14 @@ Typed Midrule Actions::). from the variadic forwarding references U.... *Warning*: We do not use Boost.Variant, for two reasons. First, it -appeared unacceptable to require Boost on the user’s machine (i.e., the +appeared unacceptable to require Boost on the user's machine (i.e., the machine on which the generated parser will be compiled, not the machine on which ‘bison’ was run). Second, for each possible semantic value, Boost.Variant not only stores the value, but also a tag specifying its -type. But the parser already “knows” the type of the semantic value, so +type. But the parser already "knows" the type of the semantic value, so that would be duplicating the information. - We do not use C++17’s ‘std::variant’ either: we want to support all + We do not use C++17's ‘std::variant’ either: we want to support all the C++ standards, and of course ‘std::variant’ also stores a tag to record the current type. @@ -11363,13 +11360,13 @@ File: bison.info, Node: Exposing the Location Classes, Next: User Defined Loca ...................................... When both ‘%header’ and ‘%locations’ are enabled, Bison generates an -additional file: ‘location.hh’. If you don’t use locations outside of +additional file: ‘location.hh’. If you don't use locations outside of the parser, you may avoid its creation with ‘%define api.location.file none’. However this file is useful if, for instance, your parser builds an -abstract syntax tree decorated with locations: you may use Bison’s -‘location’ type independently of Bison’s parser. You may name the file +abstract syntax tree decorated with locations: you may use Bison's +‘location’ type independently of Bison's parser. You may name the file differently, e.g., ‘%define api.location.file "include/ast/location.hh"’: this name can have directory components, or even be absolute. The way the location file is included is controlled @@ -11489,7 +11486,7 @@ Function::), the user must define the following function. typedef symbol_kind::symbol_kind_t symbol_kind_type; -- Method on context: const symbol_type& lookahead () const - The “unexpected” token: the lookahead that caused the syntax error. + The "unexpected" token: the lookahead that caused the syntax error. -- Method on context: symbol_kind_type token () const The symbol kind of the lookahead token that caused the syntax @@ -11636,7 +11633,7 @@ expects ‘yylex’ to have the following prototype. yield additional arguments. -- Type of parser: symbol_type - A “complete symbol”, that binds together its kind, value and (when + A "complete symbol", that binds together its kind, value and (when applicable) location. -- Method on symbol_type: symbol_kind_type kind () const @@ -11763,8 +11760,8 @@ interface with.  File: bison.info, Node: Calc++ --- C++ Calculator, Next: Calc++ Parsing Driver, Up: A Complete C++ Example -10.1.8.1 Calc++ — C++ Calculator -................................ +10.1.8.1 Calc++ -- C++ Calculator +................................. Of course the grammar is dedicated to arithmetic, a single expression, possibly preceded by variable assignments. An environment containing @@ -11782,7 +11779,7 @@ File: bison.info, Node: Calc++ Parsing Driver, Next: Calc++ Parser, Prev: Cal .............................. To support a pure interface with the parser (and the scanner) the -technique of the “parsing context” is convenient: a structure containing +technique of the "parsing context" is convenient: a structure containing all the data to exchange. Since, in addition to simply launch the parsing, there are several auxiliary tasks to execute (open the file for scanning, instantiate the parser etc.), we recommend transforming the @@ -11894,7 +11891,7 @@ conversions. This example uses genuine C++ objects as semantic values, therefore, we require the variant-based storage of semantic values. To make sure we properly use it, we enable assertions. To fully benefit from -type-safety and more natural definition of “symbol”, we enable +type-safety and more natural definition of "symbol", we enable ‘api.token.constructor’. %define api.token.constructor @@ -11905,8 +11902,8 @@ Then come the declarations/inclusions needed by the semantic values. Because the parser uses the parsing driver and reciprocally, both would like to include the header of the other, which is, of course, insane. This mutual dependency will be broken using forward declarations. -Because the driver’s header needs detailed knowledge about the parser -class (in particular its inner types), it is the parser’s header which +Because the driver's header needs detailed knowledge about the parser +class (in particular its inner types), it is the parser's header which will use a forward declaration of the driver. *Note %code Summary::. %code requires { @@ -12008,8 +12005,8 @@ File: bison.info, Node: Calc++ Scanner, Next: Calc++ Top Level, Prev: Calc++ 10.1.8.4 Calc++ Scanner ....................... -In addition to standard headers, the Flex scanner includes the driver’s, -then the parser’s to get the set of defined tokens. +In addition to standard headers, the Flex scanner includes the driver's, +then the parser's to get the set of defined tokens. %{ /* -*- C++ -*- */ # include @@ -12021,8 +12018,8 @@ then the parser’s to get the set of defined tokens. # include "parser.hh" %} -Since our calculator has no ‘#include’-like feature, we don’t need -‘yywrap’. We don’t need the ‘unput’ and ‘input’ functions either, and +Since our calculator has no ‘#include’-like feature, we don't need +‘yywrap’. We don't need the ‘unput’ and ‘input’ functions either, and we parse an actual file, this is not an interactive session with the user. Finally, we enable scanner tracing. @@ -12098,8 +12095,8 @@ report errors. return yy::parser::make_NUMBER ((int) n, loc); } -Finally, because the scanner-related driver’s member-functions depend on -the scanner’s data, it is simpler to implement them in this file. +Finally, because the scanner-related driver's member-functions depend on +the scanner's data, it is simpler to implement them in this file. void driver::scan_begin () @@ -12209,7 +12206,7 @@ garbage collection. The parser will try to hold references to semantic values for as little time as needed. D parsers support ‘%printer’. An example for the output of type -‘int’, where ‘yyo’ is the parser’s debug output: +‘int’, where ‘yyo’ is the parser's debug output: %printer { yyo.write($$); } @@ -12518,7 +12515,7 @@ Summary::). returned if more input is required to finish parsing the input. If ‘api.push-pull’ is defined as ‘both’, then the generated parser -class will also implement the ‘parse’ method. This method’s body is a +class will also implement the ‘parse’ method. This method's body is a loop that repeatedly invokes the scanner and then passes the values obtained from the scanner to the ‘pushParse’ method. @@ -12581,7 +12578,7 @@ contains a single class for the parser. Contrary to C parsers, Java parsers do not use global variables; the state of the parser is always local to an instance of the parser class. -Therefore, all Java parsers are “pure”, and the ‘%define api.pure’ +Therefore, all Java parsers are "pure", and the ‘%define api.pure’ directive does nothing when used in Java. GLR parsers are currently unsupported in Java. Do not use the @@ -12598,7 +12595,7 @@ parser, so use ‘%define parse.trace’ explicitly if needed. Also, in the future the ‘%token-table’ directive might enable a public interface to access the token names and codes. - Getting a “code too large” error from the Java compiler means the + Getting a "code too large" error from the Java compiler means the code hit the 64KB bytecode per method limitation of the Java class file. Try reducing the amount of code in actions and static initializers; otherwise, report a bug so that the parser skeleton will be improved. @@ -12610,7 +12607,7 @@ File: bison.info, Node: Java Semantic Values, Next: Java Location Values, Pre --------------------------- There is no ‘%union’ directive in Java parsers. Instead, the semantic -values’ types (class names) should be specified in the ‘%nterm’ or +values' types (class names) should be specified in the ‘%nterm’ or ‘%token’ directive: %nterm expr assignment_expr term factor @@ -12776,7 +12773,7 @@ them automatically. must provide the parser with the following function: -- Static Method of YYParser: String i18n (string S) - Return the translation of S in the user’s language. As an example: + Return the translation of S in the user's language. As an example: %code { static ResourceBundle myResources @@ -13034,7 +13031,7 @@ following: 0 (success), 1 (abort), 2 (memory exhaustion), or input is required to finish parsing the grammar. If ‘api.push-pull’ is defined as ‘both’, then the generated parser -class will also implement the ‘parse’ method. This method’s body is a +class will also implement the ‘parse’ method. This method's body is a loop that repeatedly invokes the scanner and then passes the values obtained from the scanner to the ‘push_parse’ method. @@ -13265,7 +13262,7 @@ File: bison.info, Node: Yacc, Next: yacchack, Up: History 11.1 The ancestral Yacc ======================= -Bison originated as a workalike of a program called Yacc — Yet Another +Bison originated as a workalike of a program called Yacc -- Yet Another Compiler Compiler.(1) Yacc was written at Bell Labs as part of the very early development of Unix; one of its first uses was to develop the original Portable C Compiler, pcc. The same person, Steven C. Johnson, @@ -13289,13 +13286,13 @@ with less restrictive licenses and more features became available. Original Yacc became generally available when Caldera released the sources of old versions of Unix up to V7 and 32V in 2002. By that time -it had been long superseded in practical use by Bison even on Yacc’s +it had been long superseded in practical use by Bison even on Yacc's native Unix variants. ---------- Footnotes ---------- - (1) Because of the acronym, the name is sometimes given as “YACC”, -but Johnson used “Yacc” in the descriptive paper included in the Version + (1) Because of the acronym, the name is sometimes given as "YACC", +but Johnson used "Yacc" in the descriptive paper included in the Version 7 Unix Manual (https://s3.amazonaws.com/plan9-bell-labs/7thEdMan/v7vol2b.pdf). @@ -13309,7 +13306,7 @@ File: bison.info, Node: yacchack, Next: Byacc, Prev: Yacc, Up: History One of the deficiencies of original Yacc was its inability to produce reentrant parsers. This was first remedied by a set of drop-in -modifications called “yacchack”, published by Eric S. Raymond on USENET +modifications called "yacchack", published by Eric S. Raymond on USENET around 1983. This code was quickly forgotten when zoo and Berkeley Yacc became available a few years later. @@ -13320,14 +13317,14 @@ File: bison.info, Node: Byacc, Next: Bison, Prev: yacchack, Up: History ================== Berkeley Yacc was originated in 1985 by Robert Corbett (*note Corbett -1984::). It was originally named “zoo”, but by October 1989 it became +1984::). It was originally named "zoo", but by October 1989 it became known as Berkeley Yacc or byacc. Berkeley Yacc had three advantages over the ancestral Yacc: it generated faster parsers, it could generate reentrant parsers, and the source code was released to the public domain rather than being under an AT&T proprietary license. The better performance came from implementing -techniques from DeRemer and Penello’s seminal paper on LALR parsing +techniques from DeRemer and Penello's seminal paper on LALR parsing (*note DeRemer 1982::). Use of byacc spread rapidly due to its public domain license. @@ -13341,12 +13338,12 @@ File: bison.info, Node: Bison, Next: Other Ungulates, Prev: Byacc, Up: Histo ========== Robert Corbett actually wrote two (closely related) LALR parsers in -1985, both using the DeRemer/Penello techniques. One was “zoo”, the -other was “Byson”. In 1987 Richard Stallman began working on Byson; the +1985, both using the DeRemer/Penello techniques. One was "zoo", the +other was "Byson". In 1987 Richard Stallman began working on Byson; the name changed to Bison and the interface became Yacc-compatible. The main visible difference between Yacc and Byson/Bison at the time -of Byson’s first release is that Byson supported the ‘@N’ construct +of Byson's first release is that Byson supported the ‘@N’ construct (giving access to the starting and ending line number and character number associated with any of the symbols in the current rule). @@ -13391,8 +13388,8 @@ the early ports are extinct along with the languages that hosted them; others have been superseded by parser skeletons shipped with Bison. However, independent implementations persist. One of the best-known -still in use is David Beazley’s “PLY” (Python Lex-Yacc) for Python. -Another is goyacc, supporting the Go language. An “ocamlyacc” is +still in use is David Beazley's "PLY" (Python Lex-Yacc) for Python. +Another is goyacc, supporting the Go language. An "ocamlyacc" is shipped as part of the Ocaml compiler suite.  @@ -13574,7 +13571,7 @@ manipulate multiple input buffers. If your Flex-generated scanner uses start conditions (*note Start conditions: (flex)Start conditions.), you might also want to reset the -scanner’s state, i.e., go back to the initial start condition, through a +scanner's state, i.e., go back to the initial start condition, through a call to ‘BEGIN (0)’.  @@ -13587,7 +13584,7 @@ File: bison.info, Node: Strings are Destroyed, Next: Implementing Gotos/Loops, them. Instead of reporting ‘"foo", "bar"’, it reports ‘"bar", "bar"’, or even ‘"foo\nbar", "bar"’. - This error is probably the single most frequent “bug report” sent to + This error is probably the single most frequent "bug report" sent to Bison lists, but is only concerned with a misunderstanding of the role of the scanner. Consider the following Lex code: @@ -13639,9 +13636,9 @@ File: bison.info, Node: Implementing Gotos/Loops, Next: Multiple start-symbols functions, but how can I implement gotos, or loops? Although very pedagogical, the examples included in the document blur -the distinction to make between the parser—whose job is to recover the +the distinction to make between the parser--whose job is to recover the structure of a text and to transmit it to subsequent modules of the -program—and the processing (such as the execution) of this structure. +program--and the processing (such as the execution) of this structure. This works well with so called straight line programs, i.e., precisely those that have a straightforward execution model: execute simple instructions one after the others. @@ -13709,7 +13706,7 @@ File: bison.info, Node: Secure? Conform?, Next: Enabling Relocatability, Prev Is Bison secure? Does it conform to POSIX? - If you’re looking for a guarantee or certification, we don’t provide + If you're looking for a guarantee or certification, we don't provide it. However, Bison is intended to be a reliable program that conforms to the POSIX specification for Yacc. If you run into problems, please send us a bug report. @@ -13728,7 +13725,7 @@ through ‘configure; make; make install’ with all its dependencies, options, and hurdles. Most package management systems, that allow the user to install -pre-built binaries of the packages, solve the “ease of installation” +pre-built binaries of the packages, solve the "ease of installation" problem, but they hardwire path names, usually to ‘/usr’ or ‘/usr/local’. This means that users need root privileges to install a binary package, and prevents installing two different versions of the @@ -13760,7 +13757,7 @@ also do not recommend prefixes that might be behind an automounter (e.g. ‘$HOME/inst$$’) because of the performance impact of directory searching. - Here’s a sample installation run that takes into account all these + Here's a sample installation run that takes into account all these recommendations: ./configure --enable-relocatable --prefix=/nonexistent @@ -13779,29 +13776,29 @@ executes the real program).  File: bison.info, Node: I can't build Bison, Next: Where can I find help?, Prev: Enabling Relocatability, Up: FAQ -13.8 I can’t build Bison +13.8 I can't build Bison ======================== - I can’t build Bison because ‘make’ complains that ‘msgfmt’ is not + I can't build Bison because ‘make’ complains that ‘msgfmt’ is not found. What should I do? Like most GNU packages with internationalization support, that feature is turned on by default. If you have problems building in the -‘po’ subdirectory, it indicates that your system’s internationalization +‘po’ subdirectory, it indicates that your system's internationalization support is lacking. You can re-configure Bison with ‘--disable-nls’ to turn off this support, or you can install GNU gettext from and re-configure Bison. See the file ‘ABOUT-NLS’ for more information. - I can’t build Bison because my C compiler is too old. + I can't build Bison because my C compiler is too old. Except for GLR parsers (which require C99), the C code that Bison generates requires only C89 or later. However, Bison itself requires -common C99 features such as declarations after statements. Bison’s +common C99 features such as declarations after statements. Bison's ‘configure’ script attempts to enable C99 (or later) support on compilers that default to pre-C99. If your compiler lacks these C99 features entirely, GCC may well be a better choice; or you can try -upgrading to your compiler’s latest version. +upgrading to your compiler's latest version.  File: bison.info, Node: Where can I find help?, Next: Bug Reports, Prev: I can't build Bison, Up: FAQ @@ -13809,7 +13806,7 @@ File: bison.info, Node: Where can I find help?, Next: Bug Reports, Prev: I ca 13.9 Where can I find help? =========================== - I’m having trouble using Bison. Where can I find help? + I'm having trouble using Bison. Where can I find help? First, read this fine manual. Beyond that, you can send mail to . This mailing list is intended to be populated @@ -13842,7 +13839,7 @@ to edit or add anything). The smaller and simpler the grammar, the easier it will be to fix the bug. Include information about your compilation environment, including -your operating system’s name and version and your compiler’s name and +your operating system's name and version and your compiler's name and version. If you have trouble compiling, you should also include a transcript of the build session, starting with the invocation of ‘configure’. Depending on the nature of the bug, you may be asked to @@ -13862,7 +13859,7 @@ File: bison.info, Node: More Languages, Next: Beta Testing, Prev: Bug Reports Will Bison ever have C++ and Java support? How about INSERT YOUR FAVORITE LANGUAGE HERE? - C++, D and Java are supported. We’d love to add other languages; + C++, D and Java are supported. We'd love to add other languages; contributions are welcome.  @@ -13873,7 +13870,7 @@ File: bison.info, Node: Beta Testing, Next: Mailing Lists, Prev: More Languag What is involved in being a beta tester? - It’s not terribly involved. Basically, you would download a test + It's not terribly involved. Basically, you would download a test release, compile it, and use it to build and run a parser or two. After that, you would submit either a bug report or a message saying that everything is okay. It is important to report successes as well as @@ -13959,7 +13956,7 @@ Appendix A Bison Symbols Comments, as in C/C++. -- Delimiter: : - Separates a rule’s result from its components. *Note Rules::. + Separates a rule's result from its components. *Note Rules::. -- Delimiter: ; Terminates a rule. *Note Rules::. @@ -13998,7 +13995,7 @@ Appendix A Bison Symbols -- Directive: %define VARIABLE VALUE -- Directive: %define VARIABLE {VALUE} -- Directive: %define VARIABLE "VALUE" - Define a variable to adjust Bison’s behavior. *Note %define + Define a variable to adjust Bison's behavior. *Note %define Summary::. -- Directive: %defines @@ -14242,7 +14239,7 @@ Appendix A Bison Symbols External variable in which ‘yylex’ should place the line and column numbers associated with a token. (In a pure parser, it is a local variable within ‘yyparse’, and its address is passed to ‘yylex’.) - You can ignore this variable if you don’t use the ‘@’ feature in + You can ignore this variable if you don't use the ‘@’ feature in the grammar actions. *Note Token Locations::. In semantic actions, it stores the location of the lookahead token. *Note Actions and Locations::. @@ -14352,7 +14349,7 @@ Accepting state A state whose only action is the accept action. The accepting state is thus a consistent state. *Note Understanding::. -Backus-Naur Form (BNF; also called “Backus Normal Form”) +Backus-Naur Form (BNF; also called "Backus Normal Form") Formal method of specifying context-free grammars originally proposed by John Backus, and slightly improved by Peter Naur in his 1960-01-02 committee document contributing to what became the Algol @@ -14401,7 +14398,7 @@ Empty string character string of length zero. Finite-state stack machine - A “machine” that has discrete states in which it is said to exist + A "machine" that has discrete states in which it is said to exist at each instant in time. As input to the machine is processed, the machine moves from state to state as specified by the logic of the machine. In the case of the parser, the input is the language @@ -14411,14 +14408,14 @@ Finite-state stack machine Generalized LR (GLR) A parsing algorithm that can handle all context-free grammars, including those that are not LR(1). It resolves situations that - Bison’s deterministic parsing algorithm cannot by effectively + Bison's deterministic parsing algorithm cannot by effectively splitting off multiple parsers, trying all possible parsers, and discarding those that fail in the light of additional right context. *Note Generalized LR Parsing::. Grouping A language construct that is (in general) grammatically divisible; - for example, ‘expression’ or ‘declaration’ in C. *Note Language + for example, 'expression' or 'declaration' in C. *Note Language and Grammar::. IELR(1) (Inadequacy Elimination LR(1)) @@ -14427,7 +14424,7 @@ IELR(1) (Inadequacy Elimination LR(1)) with the full language-recognition power of canonical LR(1) but with nearly the same number of parser states as LALR(1). This reduction in parser states is often an order of magnitude. More - importantly, because canonical LR(1)’s extra parser states may + importantly, because canonical LR(1)'s extra parser states may contain duplicate conflicts in the case of non-LR(1) grammars, the number of conflicts for IELR(1) is often an order of magnitude less as well. This can significantly reduce the complexity of @@ -14441,25 +14438,25 @@ Input stream A continuous flow of data between devices or programs. Kind - “Token” and “symbol” are each overloaded to mean either a grammar + "Token" and "symbol" are each overloaded to mean either a grammar symbol (kind) or all parse info (kind, value, location) associated with occurrences of that grammar symbol from the input. To disambiguate, - • we use “token kind” and “symbol kind” to mean both grammar + • we use "token kind" and "symbol kind" to mean both grammar symbols and the values that represent them in a base programming language (C, C++, etc.). The names of the types of these values are typically ‘token_kind_t’, or ‘token_kind_type’, or ‘TokenKind’, depending on the programming language. - • we use “token” and “symbol” without the word “kind” to mean - parsed occurrences, and we append the word “type” to refer to + • we use "token" and "symbol" without the word "kind" to mean + parsed occurrences, and we append the word "type" to refer to the types that represent them in a base programming language. - In summary: When you see “kind”, interpret “symbol” or “token” to - mean a _grammar symbol_. When you don’t see “kind” (including when - you see “type”), interpret “symbol” or “token” to mean a _parsed + In summary: When you see "kind", interpret "symbol" or "token" to + mean a _grammar symbol_. When you don't see "kind" (including when + you see "type"), interpret "symbol" or "token" to mean a _parsed symbol_. LAC (Lookahead Correction) @@ -14594,7 +14591,7 @@ Token kind Unreachable state A parser state to which there does not exist a sequence of - transitions from the parser’s start state. A state can become + transitions from the parser's start state. A state can become unreachable during conflict resolution. *Note Unreachable States::. @@ -14622,7 +14619,7 @@ Appendix C GNU Free Documentation License author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others. - This License is a kind of “copyleft”, which means that derivative + This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software. @@ -14643,18 +14640,18 @@ Appendix C GNU Free Documentation License be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The - “Document”, below, refers to any such manual or work. Any member - of the public is a licensee, and is addressed as “you”. You accept + "Document", below, refers to any such manual or work. Any member + of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law. - A “Modified Version” of the Document means any work containing the + A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language. - A “Secondary Section” is a named appendix or a front-matter section + A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the - publishers or authors of the Document to the Document’s overall + publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not @@ -14663,7 +14660,7 @@ Appendix C GNU Free Documentation License of legal, commercial, philosophical, ethical or political position regarding them. - The “Invariant Sections” are certain Secondary Sections whose + The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it @@ -14671,13 +14668,13 @@ Appendix C GNU Free Documentation License contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none. - The “Cover Texts” are certain short passages of text that are + The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words. - A “Transparent” copy of the Document means a machine-readable copy, + A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed @@ -14689,7 +14686,7 @@ Appendix C GNU Free Documentation License been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not - “Transparent” is called “Opaque”. + "Transparent" is called "Opaque". Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, @@ -14702,23 +14699,23 @@ Appendix C GNU Free Documentation License the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only. - The “Title Page” means, for a printed book, the title page itself, + The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For - works in formats which do not have any title page as such, “Title - Page” means the text near the most prominent appearance of the - work’s title, preceding the beginning of the body of the text. + works in formats which do not have any title page as such, "Title + Page" means the text near the most prominent appearance of the + work's title, preceding the beginning of the body of the text. - The “publisher” means any person or entity that distributes copies + The "publisher" means any person or entity that distributes copies of the Document to the public. - A section “Entitled XYZ” means a named subunit of the Document + A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as - “Acknowledgements”, “Dedications”, “Endorsements”, or “History”.) - To “Preserve the Title” of such a section when you modify the - Document means that it remains a section “Entitled XYZ” according + "Acknowledgements", "Dedications", "Endorsements", or "History".) + To "Preserve the Title" of such a section when you modify the + Document means that it remains a section "Entitled XYZ" according to this definition. The Document may include Warranty Disclaimers next to the notice @@ -14748,7 +14745,7 @@ Appendix C GNU Free Documentation License If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and - the Document’s license notice requires Cover Texts, you must + the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly @@ -14820,15 +14817,15 @@ Appendix C GNU Free Documentation License the Addendum below. G. Preserve in that license notice the full lists of Invariant - Sections and required Cover Texts given in the Document’s + Sections and required Cover Texts given in the Document's license notice. H. Include an unaltered copy of this License. - I. Preserve the section Entitled “History”, Preserve its Title, + I. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the - Title Page. If there is no section Entitled “History” in the + Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the @@ -14838,12 +14835,12 @@ Appendix C GNU Free Documentation License for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the - “History” section. You may omit a network location for a work + "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission. - K. For any section Entitled “Acknowledgements” or “Dedications”, + K. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein. @@ -14852,11 +14849,11 @@ Appendix C GNU Free Documentation License in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles. - M. Delete any section Entitled “Endorsements”. Such a section + M. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified Version. N. Do not retitle any existing section to be Entitled - “Endorsements” or to conflict in title with any Invariant + "Endorsements" or to conflict in title with any Invariant Section. O. Preserve any Warranty Disclaimers. @@ -14865,15 +14862,15 @@ Appendix C GNU Free Documentation License appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their - titles to the list of Invariant Sections in the Modified Version’s + titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles. - You may add a section Entitled “Endorsements”, provided it contains + You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various - parties—for example, statements of peer review or that the text has - been approved by an organization as the authoritative definition of - a standard. + parties--for example, statements of peer review or that the text + has been approved by an organization as the authoritative + definition of a standard. You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of @@ -14911,10 +14908,10 @@ Appendix C GNU Free Documentation License combined work. In the combination, you must combine any sections Entitled - “History” in the various original documents, forming one section - Entitled “History”; likewise combine any sections Entitled - “Acknowledgements”, and any sections Entitled “Dedications”. You - must delete all sections Entitled “Endorsements.” + "History" in the various original documents, forming one section + Entitled "History"; likewise combine any sections Entitled + "Acknowledgements", and any sections Entitled "Dedications". You + must delete all sections Entitled "Endorsements." 6. COLLECTIONS OF DOCUMENTS @@ -14935,16 +14932,16 @@ Appendix C GNU Free Documentation License A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a - storage or distribution medium, is called an “aggregate” if the + storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the - legal rights of the compilation’s users beyond what the individual + legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document. If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half - of the entire aggregate, the Document’s Cover Texts may be placed + of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket @@ -14966,8 +14963,8 @@ Appendix C GNU Free Documentation License this License or a notice or disclaimer, the original version will prevail. - If a section in the Document is Entitled “Acknowledgements”, - “Dedications”, or “History”, the requirement (section 4) to + If a section in the Document is Entitled "Acknowledgements", + "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title. @@ -15008,7 +15005,7 @@ Appendix C GNU Free Documentation License Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered - version of this License “or any later version” applies to it, you + version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the @@ -15016,29 +15013,29 @@ Appendix C GNU Free Documentation License choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that - proxy’s public statement of acceptance of a version permanently + proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Document. 11. RELICENSING - “Massive Multiauthor Collaboration Site” (or “MMC Site”) means any + "Massive Multiauthor Collaboration Site" (or "MMC Site") means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. - A “Massive Multiauthor Collaboration” (or “MMC”) contained in the + A "Massive Multiauthor Collaboration" (or "MMC") contained in the site means any set of copyrightable works thus published on the MMC site. - “CC-BY-SA” means the Creative Commons Attribution-Share Alike 3.0 + "CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization. - “Incorporate” means to publish or republish a Document, in whole or + "Incorporate" means to publish or republish a Document, in whole or in part, as part of another Document. - An MMC is “eligible for relicensing” if it is licensed under this + An MMC is "eligible for relicensing" if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover @@ -15065,7 +15062,7 @@ notices just after the title page: Free Documentation License''. If you have Invariant Sections, Front-Cover Texts and Back-Cover -Texts, replace the “with...Texts.” line with this: +Texts, replace the "with...Texts." line with this: with the Invariant Sections being LIST THEIR TITLES, with the Front-Cover Texts being LIST, and with the Back-Cover Texts @@ -15088,7 +15085,7 @@ Bibliography [Corbett 1984] Robert Paul Corbett, Static Semantics in Compiler Error Recovery - Ph.D. Dissertation, Report No. UCB/CSD 85/251, Department of + Ph.D. Dissertation, Report No. UCB/CSD 85/251, Department of Electrical Engineering and Computer Science, Compute Science Division, University of California, Berkeley, California (June 1985). @@ -15097,7 +15094,7 @@ Bibliography Joel E. Denny and Brian A. Malloy, IELR(1): Practical LR(1) Parser Tables for Non-LR(1) Grammars with Conflict Resolution, in ‘Proceedings of the 2008 ACM Symposium on Applied Computing’ - (SAC’08), ACM, New York, NY, USA, pp. 240–245. + (SAC'08), ACM, New York, NY, USA, pp. 240-245. [Denny 2010 May] @@ -15110,32 +15107,32 @@ Bibliography Joel E. Denny and Brian A. Malloy, The IELR(1) Algorithm for Generating Minimal LR(1) Parser Tables for Non-LR(1) Grammars with Conflict Resolution, in ‘Science of Computer Programming’, Vol. 75, - Issue 11 (November 2010), pp. 943–979. + Issue 11 (November 2010), pp. 943-979. [DeRemer 1982] Frank DeRemer and Thomas Pennello, Efficient Computation of LALR(1) Look-Ahead Sets, in ‘ACM Transactions on Programming Languages and - Systems’, Vol. 4, No. 4 (October 1982), pp. 615–649. + Systems’, Vol. 4, No. 4 (October 1982), pp. 615-649. [Isradisaikul 2015] Chinawat Isradisaikul, Andrew Myers, Finding Counterexamples from Parsing Conflicts, in ‘Proceedings of the 36th ACM SIGPLAN Conference on Programming Language Design and Implementation’ (PLDI - ’15), ACM, pp. 555–564. + '15), ACM, pp. 555-564. [Johnson 1978] Steven C. Johnson, A portable compiler: theory and practice, in ‘Proceedings of the 5th ACM SIGACT-SIGPLAN symposium on Principles - of programming languages’ (POPL ’78), pp. 97–104. + of programming languages’ (POPL '78), pp. 97-104. . [Knuth 1965] Donald E. Knuth, On the Translation of Languages from Left to Right, in ‘Information and Control’, Vol. 8, Issue 6 (December - 1965), pp. 607–639. + 1965), pp. 607-639. [Scott 2000] @@ -15154,39 +15151,42 @@ Index of Terms [index] * Menu: -* $$: Actions. (line 6) -* $$ <1>: Java Action Features. - (line 20) -* $$ <2>: Action Features. (line 9) -* $$ <3>: D Action Features. (line 9) -* $$ <4>: Table of Symbols. (line 28) -* $$: Java Action Features. - (line 28) -* $$ <1>: Action Features. (line 17) -* $N: Java Action Features. - (line 16) -* $N <1>: Action Features. (line 21) -* $@N: Midrule Action Translation. +* ;: Table of Symbols. (line 65) +* :: Table of Symbols. (line 62) +* @[NAME]: Actions and Locations. (line 6) -* $@N <1>: Table of Symbols. (line 23) -* $accept: Table of Symbols. (line 84) -* $end: Table of Symbols. (line 122) -* $N: Actions. (line 6) -* $N <1>: Java Action Features. - (line 12) -* $N <2>: Action Features. (line 13) -* $N <3>: D Action Features. (line 13) -* $N <4>: Table of Symbols. (line 32) -* $NAME: Actions. (line 6) -* $NAME <1>: Table of Symbols. (line 36) -* $undefined: Table of Symbols. (line 253) -* $[NAME]: Actions. (line 6) -* $[NAME] <1>: Table of Symbols. (line 37) +* @[NAME] <1>: Table of Symbols. (line 19) +* @$: Actions and Locations. + (line 6) +* @$ <1>: Java Action Features. + (line 38) +* @$ <2>: Action Features. (line 99) +* @$ <3>: Table of Symbols. (line 6) +* @N: Midrule Action Translation. + (line 6) +* @N <1>: Actions and Locations. + (line 6) +* @N <2>: Java Action Features. + (line 34) +* @N <3>: Action Features. (line 104) +* @N <4>: Action Features. (line 105) +* @N <5>: Table of Symbols. (line 10) +* @N <6>: Table of Symbols. (line 11) +* @NAME: Actions and Locations. + (line 6) +* @NAME <1>: Table of Symbols. (line 18) +* /*: Table of Symbols. (line 58) +* /* ... */: Grammar Outline. (line 6) +* //: Table of Symbols. (line 59) +* // ...: Grammar Outline. (line 6) +* %?: Semantic Predicates. (line 6) +* %?{EXPRESSION}: Table of Symbols. (line 50) +* %{: Java Declarations Summary. + (line 51) +* %{CODE%}: Table of Symbols. (line 45) * %%: Java Declarations Summary. (line 47) * %% <1>: Table of Symbols. (line 41) -* %?: Semantic Predicates. (line 6) -* %?{EXPRESSION}: Table of Symbols. (line 50) * %code: Prologue Alternatives. (line 6) * %code <1>: Decl Summary. (line 52) @@ -15443,45 +15443,42 @@ Index of Terms * %union <3>: Table of Symbols. (line 258) * %verbose: Decl Summary. (line 241) * %yacc: Decl Summary. (line 246) -* %{: Java Declarations Summary. - (line 51) -* %{CODE%}: Table of Symbols. (line 45) -* /*: Table of Symbols. (line 58) -* /* ... */: Grammar Outline. (line 6) -* //: Table of Symbols. (line 59) -* // ...: Grammar Outline. (line 6) -* :: Table of Symbols. (line 62) -* ;: Table of Symbols. (line 65) * <*>: Destructor Decl. (line 6) * <*> <1>: Printer Decl. (line 6) * <*> <2>: Table of Symbols. (line 72) * <>: Destructor Decl. (line 6) * <> <1>: Printer Decl. (line 6) * <> <2>: Table of Symbols. (line 78) -* @$: Actions and Locations. - (line 6) -* @$ <1>: Java Action Features. - (line 38) -* @$ <2>: Action Features. (line 99) -* @$ <3>: Table of Symbols. (line 6) -* @N: Midrule Action Translation. - (line 6) -* @N <1>: Actions and Locations. - (line 6) -* @N <2>: Java Action Features. - (line 34) -* @N <3>: Action Features. (line 104) -* @N <4>: Action Features. (line 105) -* @N <5>: Table of Symbols. (line 10) -* @N <6>: Table of Symbols. (line 11) -* @NAME: Actions and Locations. - (line 6) -* @NAME <1>: Table of Symbols. (line 18) -* @[NAME]: Actions and Locations. - (line 6) -* @[NAME] <1>: Table of Symbols. (line 19) * |: Rules Syntax. (line 48) * | <1>: Table of Symbols. (line 68) +* $[NAME]: Actions. (line 6) +* $[NAME] <1>: Table of Symbols. (line 37) +* $@N: Midrule Action Translation. + (line 6) +* $@N <1>: Table of Symbols. (line 23) +* $$: Java Action Features. + (line 28) +* $$ <1>: Action Features. (line 17) +* $N: Java Action Features. + (line 16) +* $N <1>: Action Features. (line 21) +* $$: Actions. (line 6) +* $$ <1>: Java Action Features. + (line 20) +* $$ <2>: Action Features. (line 9) +* $$ <3>: D Action Features. (line 9) +* $$ <4>: Table of Symbols. (line 28) +* $accept: Table of Symbols. (line 84) +* $end: Table of Symbols. (line 122) +* $N: Actions. (line 6) +* $N <1>: Java Action Features. + (line 12) +* $N <2>: Action Features. (line 13) +* $N <3>: D Action Features. (line 13) +* $N <4>: Table of Symbols. (line 32) +* $NAME: Actions. (line 6) +* $NAME <1>: Table of Symbols. (line 36) +* $undefined: Table of Symbols. (line 253) * abstract syntax tree: Implementing Gotos/Loops. (line 17) * accepting state: Understanding. (line 185) @@ -15517,6 +15514,8 @@ Index of Terms * Bison parser algorithm: Algorithm. (line 6) * Bison symbols, table of: Table of Symbols. (line 6) * Bison utility: Bison Parser. (line 6) +* BISON_I18N: Enabling I18n. (line 18) +* BISON_LOCALEDIR: Enabling I18n. (line 18) * bison-i18n.m4: Enabling I18n. (line 11) * bison-po: Internationalization. (line 6) @@ -15526,8 +15525,6 @@ Index of Terms * bisonVersion of YYParser: D Parser Interface. (line 69) * bisonVersion of YYParser <1>: Java Parser Interface. (line 91) -* BISON_I18N: Enabling I18n. (line 18) -* BISON_LOCALEDIR: Enabling I18n. (line 18) * BNF: Language and Grammar. (line 16) * braced code: Rules Syntax. (line 29) @@ -15567,19 +15564,19 @@ Index of Terms (line 6) * controlling function: Rpcalc Main. (line 6) * core, item set: Understanding. (line 132) +* counter_type: C++ position. (line 11) * counterexample, nonunifying: Glossary. (line 31) * counterexample, unifying: Glossary. (line 31) * counterexamples: Counterexamples. (line 6) -* counter_type: C++ position. (line 11) * dangling else: Shift/Reduce. (line 6) * data type of locations: Location Type. (line 6) * data types in actions: Action Types. (line 6) * data types of semantic values: Value Type. (line 6) -* debugging: Tracing. (line 6) * debug_level on parser: C++ Parser Interface. (line 91) * debug_stream on parser: C++ Parser Interface. (line 86) +* debugging: Tracing. (line 6) * declaration summary: Decl Summary. (line 6) * declarations: Prologue. (line 6) * declarations section: Prologue. (line 6) @@ -15781,10 +15778,10 @@ Index of Terms (line 27) * location tracking calculator: Location Tracking Calc. (line 6) -* location, textual: Locations. (line 6) -* location, textual <1>: Tracking Locations. (line 6) * location_type: C++ Parser Interface. (line 49) +* location, textual: Locations. (line 6) +* location, textual <1>: Tracking Locations. (line 6) * lookahead correction: LAC. (line 6) * lookahead on context: C++ Parser Context. (line 43) * lookahead token: Lookahead. (line 6) @@ -15824,6 +15821,10 @@ Index of Terms * nonunifying counterexample: Glossary. (line 31) * operator precedence: Precedence. (line 6) * operator precedence, declaring: Precedence Decl. (line 6) +* operator- on location: C++ location. (line 30) +* operator- on position: C++ position. (line 45) +* operator-= on location: C++ location. (line 31) +* operator-= on position: C++ position. (line 44) * operator!= on location: C++ location. (line 43) * operator!= on position: C++ position. (line 49) * operator() on parser: C++ Parser Interface. @@ -15834,10 +15835,6 @@ Index of Terms * operator+= on location: C++ location. (line 29) * operator+= on location <1>: C++ location. (line 35) * operator+= on position: C++ position. (line 42) -* operator- on location: C++ location. (line 30) -* operator- on position: C++ position. (line 45) -* operator-= on location: C++ location. (line 31) -* operator-= on position: C++ position. (line 44) * operator<<: C++ position. (line 52) * operator<< <1>: C++ location. (line 47) * operator== on location: C++ location. (line 42) @@ -15875,14 +15872,14 @@ Index of Terms * pure parser: Pure Decl. (line 6) * push parser: Push Decl. (line 6) * push parser <1>: Push Decl. (line 6) -* pushParse on YYParser: D Push Parser Interface. - (line 18) * push_parse on YYParser: Java Push Parser Interface. (line 18) * push_parse on YYParser <1>: Java Push Parser Interface. (line 19) * push_parse on YYParser <2>: Java Push Parser Interface. (line 21) +* pushParse on YYParser: D Push Parser Interface. + (line 18) * questions: FAQ. (line 6) * recovering: Java Action Features. (line 54) @@ -15897,11 +15894,11 @@ Index of Terms * reduce/reduce conflicts <2>: Merging GLR Parses. (line 6) * reduction: Algorithm. (line 6) * reentrant parser: Pure Decl. (line 6) +* report_syntax_error on parser: C++ Parser Context. (line 9) * reportSyntaxError on Lexer: Java Scanner Interface. (line 59) * reportSyntaxError(YYParser.Context on Lexer: D Scanner Interface. (line 34) -* report_syntax_error on parser: C++ Parser Context. (line 9) * requiring a version of Bison: Require Decl. (line 6) * Reverse Polish Notation: RPN Calc. (line 6) * right recursion: Recursion. (line 17) @@ -15917,6 +15914,10 @@ Index of Terms * Semantic predicates in GLR parsers: Semantic Predicates. (line 6) * semantic value: Semantic Values. (line 6) * semantic value type: Value Type. (line 6) +* set_debug_level on parser: C++ Parser Interface. + (line 92) +* set_debug_stream on parser: C++ Parser Interface. + (line 87) * setDebugLevel on YYParser: Java Parser Interface. (line 87) * setDebugLevel(int on YYParser: D Parser Interface. (line 65) @@ -15926,10 +15927,6 @@ Index of Terms * setErrorVerbose on YYParser: Java Parser Interface. (line 65) * setErrorVerbose(boolean on YYParser: D Parser Interface. (line 44) -* set_debug_level on parser: C++ Parser Interface. - (line 92) -* set_debug_stream on parser: C++ Parser Interface. - (line 87) * shift/reduce conflicts: GLR Parsers. (line 6) * shift/reduce conflicts <1>: Simple GLR Parsers. (line 6) * shift/reduce conflicts <2>: Shift/Reduce. (line 6) @@ -15950,13 +15947,6 @@ Index of Terms * suppressing conflict warnings: Expect Decl. (line 6) * symbol: Symbols. (line 6) * symbol table example: Mfcalc Symbol Table. (line 6) -* SymbolKind: D Parser Context Interface. - (line 9) -* SymbolKind <1>: Java Parser Context Interface. - (line 9) -* symbols (abstract): Language and Grammar. - (line 46) -* symbols in Bison, table of: Table of Symbols. (line 6) * symbol_kind_type: C++ Parser Context. (line 19) * symbol_name on parser: C++ Parser Context. (line 68) * symbol_type: Complete Symbols. (line 17) @@ -15964,6 +15954,13 @@ Index of Terms * symbol_type on parser::symbol_type <1>: Complete Symbols. (line 34) * symbol_type on parser::symbol_type <2>: Complete Symbols. (line 36) * symbol_type on parser::symbol_type <3>: Complete Symbols. (line 38) +* SymbolKind: D Parser Context Interface. + (line 9) +* SymbolKind <1>: Java Parser Context Interface. + (line 9) +* symbols (abstract): Language and Grammar. + (line 46) +* symbols in Bison, table of: Table of Symbols. (line 6) * syntactic grouping: Language and Grammar. (line 46) * syntax error: Error Reporting Function. @@ -15978,8 +15975,8 @@ Index of Terms * terminal symbol: Symbols. (line 6) * textual location: Locations. (line 6) * textual location <1>: Tracking Locations. (line 6) -* this(Lexer on YYParser: D Parser Interface. (line 34) * this(LEX_PARAM, on YYParser: D Parser Interface. (line 29) +* this(Lexer on YYParser: D Parser Interface. (line 34) * this(Position on Location: D Location Values. (line 14) * this(Position on Location <1>: D Location Values. (line 18) * token: Language and Grammar. @@ -15989,9 +15986,9 @@ Index of Terms * token kind: Symbols. (line 6) * token kind names, declaring: Token Decl. (line 6) * token on context: C++ Parser Context. (line 46) -* token, useless: Understanding. (line 56) * token_kind_type: C++ Parser Interface. (line 21) +* token, useless: Understanding. (line 56) * toString on Location: Java Location Values. (line 30) * toString() on Location: D Location Values. (line 21) @@ -16011,9 +16008,9 @@ Index of Terms * value types, declaring <2>: Structured Value Type. (line 6) * value types, nonterminals, declaring: Type Decl. (line 6) -* value, semantic: Semantic Values. (line 6) * value_type: C++ Parser Interface. (line 46) +* value, semantic: Semantic Values. (line 6) * version: Versioning. (line 6) * version requirement: Require Decl. (line 6) * warnings, preventing: Expect Decl. (line 6) @@ -16181,270 +16178,269 @@ Index of Terms * YYUNDEF: Table of Symbols. (line 443) * zoo: Bison. (line 6) -  Tag Table: -Node: Top1066 -Node: Introduction18219 -Node: Conditions19794 -Node: Copying21717 -Node: Concepts59459 -Node: Language and Grammar60655 -Node: Grammar in Bison66769 -Node: Semantic Values68685 -Node: Semantic Actions70821 -Node: GLR Parsers71998 -Node: Simple GLR Parsers74773 -Node: Merging GLR Parses81253 -Ref: Merging GLR Parses-Footnote-186591 -Node: GLR Semantic Actions86732 -Node: Semantic Predicates89333 -Node: Locations91786 -Node: Bison Parser93264 -Node: Stages96464 -Node: Grammar Layout97689 -Node: Examples99051 -Node: RPN Calc100544 -Ref: RPN Calc-Footnote-1101596 -Node: Rpcalc Declarations101674 -Node: Rpcalc Rules103730 -Node: Rpcalc Input105629 -Node: Rpcalc Line107208 -Node: Rpcalc Exp108360 -Node: Rpcalc Lexer110373 -Node: Rpcalc Main113070 -Node: Rpcalc Error113481 -Node: Rpcalc Generate114509 -Node: Rpcalc Compile115757 -Node: Infix Calc116721 -Ref: Infix Calc-Footnote-1119567 -Node: Simple Error Recovery119720 -Node: Location Tracking Calc121658 -Node: Ltcalc Declarations122358 -Node: Ltcalc Rules123453 -Node: Ltcalc Lexer125295 -Node: Multi-function Calc127636 -Ref: Multi-function Calc-Footnote-1129413 -Node: Mfcalc Declarations129491 -Node: Mfcalc Rules131515 -Node: Mfcalc Symbol Table132793 -Node: Mfcalc Lexer136255 -Node: Mfcalc Main138828 -Node: Exercises139704 -Node: Grammar File140231 -Node: Grammar Outline141081 -Node: Prologue141939 -Node: Prologue Alternatives143740 -Ref: Prologue Alternatives-Footnote-1153440 -Node: Bison Declarations153545 -Node: Grammar Rules153955 -Node: Epilogue154411 -Node: Symbols155462 -Node: Rules162497 -Node: Rules Syntax162812 -Node: Empty Rules164877 -Node: Recursion165964 -Node: Semantics167622 -Node: Value Type168928 -Node: Multiple Types170216 -Node: Type Generation171666 -Node: Union Decl173596 -Node: Structured Value Type174989 -Node: Actions176015 -Node: Action Types179899 -Node: Midrule Actions181252 -Node: Using Midrule Actions181906 -Node: Typed Midrule Actions185445 -Node: Midrule Action Translation186995 -Node: Midrule Conflicts189488 -Node: Tracking Locations192097 -Node: Location Type192829 -Node: Actions and Locations194352 -Node: Printing Locations196734 -Node: Location Default Action197496 -Node: Named References201033 -Node: Declarations203630 -Node: Require Decl205319 -Node: Token Decl205833 -Node: Precedence Decl208750 -Node: Type Decl211026 -Node: Symbol Decls211977 -Node: Initial Action Decl212932 -Node: Destructor Decl213747 -Node: Printer Decl219393 -Node: Expect Decl221662 -Node: Start Decl225663 -Node: Pure Decl226057 -Node: Push Decl227805 -Node: Decl Summary232244 -Ref: %header234925 -Node: %define Summary243258 -Ref: api-filename-type245169 -Ref: api-token-prefix256117 -Node: %code Summary268123 -Node: Multiple Parsers272379 -Node: Interface276239 -Node: Parser Function277348 -Node: Push Parser Interface279841 -Ref: yypstate_new280226 -Ref: yypstate_delete280667 -Ref: yypush_parse281081 -Ref: yypull_parse282093 -Node: Lexical283096 -Node: Calling Convention284671 -Node: Special Tokens286200 -Node: Tokens from Literals287639 -Node: Token Values288720 -Node: Token Locations289888 -Node: Pure Calling290820 -Node: Error Reporting293417 -Node: Error Reporting Function293940 -Node: Syntax Error Reporting Function297312 -Node: Action Features301923 -Node: Internationalization306263 -Node: Enabling I18n307123 -Node: Token I18n309241 -Node: Algorithm310644 -Node: Lookahead313066 -Node: Shift/Reduce315280 -Node: Precedence319347 -Node: Why Precedence320119 -Node: Using Precedence322034 -Node: Precedence Only323534 -Node: Precedence Examples325336 -Node: How Precedence325860 -Node: Non Operators327005 -Node: Contextual Precedence328578 -Node: Parser States330324 -Node: Reduce/Reduce331579 -Node: Mysterious Conflicts336388 -Node: Tuning LR340015 -Node: LR Table Construction341221 -Node: Default Reductions346839 -Node: LAC351626 -Node: Unreachable States357132 -Node: Generalized LR Parsing359139 -Node: Memory Management363524 -Node: Error Recovery365908 -Node: Context Dependency371188 -Node: Semantic Tokens372045 -Node: Lexical Tie-ins375121 -Node: Tie-in Recovery376577 -Node: Debugging378709 -Node: Counterexamples380174 -Node: Understanding386180 -Ref: state-8392904 -Node: Graphviz398455 -Node: Xml402776 -Node: Tracing404514 -Node: Enabling Traces404891 -Node: Mfcalc Traces409019 -Node: Invocation414230 -Node: Bison Options416336 -Node: Operation Modes417183 -Node: Diagnostics422900 -Ref: Wconflicts-sr423208 -Ref: Wconflicts-rr423232 -Ref: Wcounterexamples423620 -Ref: Wdangling-alias423933 -Ref: Wdeprecated425263 -Ref: Wempty-rule425387 -Ref: Wmidrule-values425599 -Ref: Wprecedence426310 -Ref: Wyacc427444 -Ref: Wother427506 -Ref: Wall427810 -Ref: Wnone427930 -Ref: Werror428206 -Node: Tuning the Parser430013 -Ref: option-yacc433427 -Ref: Tuning the Parser-Footnote-1435280 -Node: Output Files435346 -Node: Option Cross Key438623 -Node: Yacc Library440761 -Node: Other Languages441834 -Node: C++ Parsers442459 -Node: A Simple C++ Example443188 -Ref: A Simple C++ Example-Footnote-1447342 -Node: C++ Bison Interface447425 -Node: C++ Parser Interface449015 -Node: C++ Semantic Values453602 -Node: C++ Unions454152 -Node: C++ Variants454945 -Node: C++ Location Values458718 -Node: C++ position459657 -Node: C++ location462026 -Node: Exposing the Location Classes464216 -Node: User Defined Location Type466115 -Node: C++ Parser Context467694 -Node: C++ Scanner Interface471661 -Node: Split Symbols472229 -Node: Complete Symbols473964 -Node: A Complete C++ Example478719 -Node: Calc++ --- C++ Calculator479662 -Node: Calc++ Parsing Driver480183 -Node: Calc++ Parser483150 -Node: Calc++ Scanner487273 -Node: Calc++ Top Level491228 -Node: D Parsers491927 -Node: D Bison Interface492631 -Node: D Semantic Values493744 -Node: D Location Values494577 -Node: D Parser Interface495448 -Node: D Parser Context Interface500364 -Node: D Scanner Interface501807 -Node: D Action Features504747 -Node: D Push Parser Interface505516 -Node: D Complete Symbols506992 -Node: Java Parsers507708 -Node: Java Bison Interface508524 -Node: Java Semantic Values510715 -Node: Java Location Values512412 -Node: Java Parser Interface514010 -Node: Java Parser Context Interface519267 -Node: Java Scanner Interface521352 -Node: Java Action Features525424 -Node: Java Push Parser Interface528175 -Node: Java Differences531170 -Ref: Java Differences-Footnote-1533833 -Node: Java Declarations Summary533987 -Node: History539020 -Node: Yacc539476 -Ref: Yacc-Footnote-1540972 -Ref: Yacc-Footnote-2541203 -Node: yacchack541273 -Node: Byacc541700 -Node: Bison542519 -Node: Other Ungulates544537 -Node: Versioning545127 -Node: FAQ548550 -Node: Memory Exhausted549577 -Node: How Can I Reset the Parser549879 -Node: Strings are Destroyed552473 -Node: Implementing Gotos/Loops554178 -Node: Multiple start-symbols555471 -Node: Secure? Conform?557051 -Node: Enabling Relocatability557505 -Node: I can't build Bison560429 -Node: Where can I find help?561701 -Node: Bug Reports562496 -Node: More Languages563975 -Node: Beta Testing564312 -Node: Mailing Lists565188 -Node: Table of Symbols565400 -Node: Glossary582432 -Node: GNU Free Documentation License592794 -Node: Bibliography618148 -Ref: Corbett 1984618288 -Ref: Denny 2008618638 -Ref: Denny 2010 May618964 -Ref: Denny 2010 November619239 -Ref: DeRemer 1982619577 -Ref: Isradisaikul 2015619849 -Ref: Johnson 1978620178 -Ref: Knuth 1965620447 -Ref: Scott 2000620683 -Node: Index of Terms621000 +Node: Top1040 +Node: Introduction18154 +Node: Conditions19727 +Node: Copying21636 +Node: Concepts59175 +Node: Language and Grammar60367 +Node: Grammar in Bison66345 +Node: Semantic Values68261 +Node: Semantic Actions70389 +Node: GLR Parsers71566 +Node: Simple GLR Parsers74339 +Node: Merging GLR Parses80810 +Ref: Merging GLR Parses-Footnote-186139 +Node: GLR Semantic Actions86280 +Node: Semantic Predicates88877 +Node: Locations91330 +Node: Bison Parser92808 +Node: Stages96001 +Node: Grammar Layout97226 +Node: Examples98588 +Node: RPN Calc100075 +Ref: RPN Calc-Footnote-1101127 +Node: Rpcalc Declarations101205 +Node: Rpcalc Rules103257 +Node: Rpcalc Input105148 +Node: Rpcalc Line106714 +Node: Rpcalc Exp107862 +Node: Rpcalc Lexer109871 +Node: Rpcalc Main112564 +Node: Rpcalc Error112975 +Node: Rpcalc Generate114003 +Node: Rpcalc Compile115247 +Node: Infix Calc116211 +Ref: Infix Calc-Footnote-1119054 +Node: Simple Error Recovery119207 +Node: Location Tracking Calc121142 +Node: Ltcalc Declarations121842 +Node: Ltcalc Rules122937 +Node: Ltcalc Lexer124777 +Node: Multi-function Calc127114 +Ref: Multi-function Calc-Footnote-1128891 +Node: Mfcalc Declarations128969 +Node: Mfcalc Rules130993 +Node: Mfcalc Symbol Table132271 +Node: Mfcalc Lexer135731 +Node: Mfcalc Main138304 +Node: Exercises139180 +Node: Grammar File139707 +Node: Grammar Outline140557 +Node: Prologue141415 +Node: Prologue Alternatives143214 +Ref: Prologue Alternatives-Footnote-1152898 +Node: Bison Declarations153003 +Node: Grammar Rules153413 +Node: Epilogue153869 +Node: Symbols154920 +Node: Rules161943 +Node: Rules Syntax162258 +Node: Empty Rules164323 +Node: Recursion165410 +Node: Semantics167068 +Node: Value Type168374 +Node: Multiple Types169658 +Node: Type Generation171108 +Node: Union Decl173038 +Node: Structured Value Type174431 +Node: Actions175457 +Node: Action Types179329 +Node: Midrule Actions180682 +Node: Using Midrule Actions181336 +Node: Typed Midrule Actions184873 +Node: Midrule Action Translation186421 +Node: Midrule Conflicts188913 +Node: Tracking Locations191522 +Node: Location Type192254 +Node: Actions and Locations193777 +Node: Printing Locations196159 +Node: Location Default Action196919 +Node: Named References200452 +Node: Declarations203048 +Node: Require Decl204735 +Node: Token Decl205249 +Node: Precedence Decl208162 +Node: Type Decl210438 +Node: Symbol Decls211389 +Node: Initial Action Decl212344 +Node: Destructor Decl213157 +Node: Printer Decl218801 +Node: Expect Decl221070 +Node: Start Decl225067 +Node: Pure Decl225461 +Node: Push Decl227209 +Node: Decl Summary231642 +Ref: %header234319 +Node: %define Summary242648 +Ref: api-filename-type244557 +Ref: api-token-prefix255495 +Node: %code Summary267498 +Node: Multiple Parsers271750 +Node: Interface275605 +Node: Parser Function276712 +Node: Push Parser Interface279203 +Ref: yypstate_new279588 +Ref: yypstate_delete280029 +Ref: yypush_parse280443 +Ref: yypull_parse281455 +Node: Lexical282458 +Node: Calling Convention284033 +Node: Special Tokens285562 +Node: Tokens from Literals286997 +Node: Token Values288078 +Node: Token Locations289242 +Node: Pure Calling290174 +Node: Error Reporting292771 +Node: Error Reporting Function293294 +Node: Syntax Error Reporting Function296664 +Node: Action Features301265 +Node: Internationalization305605 +Node: Enabling I18n306457 +Node: Token I18n308567 +Node: Algorithm309958 +Node: Lookahead312372 +Node: Shift/Reduce314582 +Node: Precedence318637 +Node: Why Precedence319409 +Node: Using Precedence321324 +Node: Precedence Only322820 +Node: Precedence Examples324622 +Node: How Precedence325146 +Node: Non Operators326287 +Node: Contextual Precedence327848 +Node: Parser States329590 +Node: Reduce/Reduce330839 +Node: Mysterious Conflicts335642 +Node: Tuning LR339264 +Node: LR Table Construction340464 +Node: Default Reductions346076 +Node: LAC350863 +Node: Unreachable States356363 +Node: Generalized LR Parsing358366 +Node: Memory Management362744 +Node: Error Recovery365128 +Node: Context Dependency370404 +Node: Semantic Tokens371257 +Node: Lexical Tie-ins374325 +Node: Tie-in Recovery375781 +Node: Debugging377911 +Node: Counterexamples379374 +Node: Understanding385376 +Ref: state-8392088 +Node: Graphviz397639 +Node: Xml401956 +Node: Tracing403694 +Node: Enabling Traces404067 +Node: Mfcalc Traces408193 +Node: Invocation413400 +Node: Bison Options415502 +Node: Operation Modes416349 +Node: Diagnostics422058 +Ref: Wconflicts-sr422366 +Ref: Wconflicts-rr422390 +Ref: Wcounterexamples422778 +Ref: Wdangling-alias423091 +Ref: Wdeprecated424416 +Ref: Wempty-rule424540 +Ref: Wmidrule-values424752 +Ref: Wprecedence425463 +Ref: Wyacc426597 +Ref: Wother426659 +Ref: Wall426963 +Ref: Wnone427083 +Ref: Werror427359 +Node: Tuning the Parser429164 +Ref: option-yacc432576 +Ref: Tuning the Parser-Footnote-1434425 +Node: Output Files434491 +Node: Option Cross Key437760 +Node: Yacc Library439898 +Node: Other Languages440965 +Node: C++ Parsers441588 +Node: A Simple C++ Example442317 +Ref: A Simple C++ Example-Footnote-1446467 +Node: C++ Bison Interface446550 +Node: C++ Parser Interface448140 +Node: C++ Semantic Values452723 +Node: C++ Unions453273 +Node: C++ Variants454066 +Node: C++ Location Values457827 +Node: C++ position458766 +Node: C++ location461135 +Node: Exposing the Location Classes463325 +Node: User Defined Location Type465218 +Node: C++ Parser Context466797 +Node: C++ Scanner Interface470760 +Node: Split Symbols471328 +Node: Complete Symbols473063 +Node: A Complete C++ Example477814 +Node: Calc++ --- C++ Calculator478757 +Node: Calc++ Parsing Driver479278 +Node: Calc++ Parser482241 +Node: Calc++ Scanner486356 +Node: Calc++ Top Level490299 +Node: D Parsers490998 +Node: D Bison Interface491702 +Node: D Semantic Values492815 +Node: D Location Values493646 +Node: D Parser Interface494517 +Node: D Parser Context Interface499433 +Node: D Scanner Interface500876 +Node: D Action Features503816 +Node: D Push Parser Interface504585 +Node: D Complete Symbols506059 +Node: Java Parsers506775 +Node: Java Bison Interface507591 +Node: Java Semantic Values509774 +Node: Java Location Values511469 +Node: Java Parser Interface513067 +Node: Java Parser Context Interface518322 +Node: Java Scanner Interface520407 +Node: Java Action Features524479 +Node: Java Push Parser Interface527230 +Node: Java Differences530223 +Ref: Java Differences-Footnote-1532886 +Node: Java Declarations Summary533040 +Node: History538073 +Node: Yacc538529 +Ref: Yacc-Footnote-1540022 +Ref: Yacc-Footnote-2540245 +Node: yacchack540315 +Node: Byacc540738 +Node: Bison541551 +Node: Other Ungulates543559 +Node: Versioning544139 +Node: FAQ547562 +Node: Memory Exhausted548589 +Node: How Can I Reset the Parser548891 +Node: Strings are Destroyed551483 +Node: Implementing Gotos/Loops553184 +Node: Multiple start-symbols554475 +Node: Secure? Conform?556055 +Node: Enabling Relocatability556505 +Node: I can't build Bison559423 +Node: Where can I find help?560683 +Node: Bug Reports561476 +Node: More Languages562951 +Node: Beta Testing563286 +Node: Mailing Lists564160 +Node: Table of Symbols564372 +Node: Glossary581398 +Node: GNU Free Documentation License591676 +Node: Bibliography616829 +Ref: Corbett 1984616969 +Ref: Denny 2008617320 +Ref: Denny 2010 May617642 +Ref: Denny 2010 November617917 +Ref: DeRemer 1982618253 +Ref: Isradisaikul 2015618523 +Ref: Johnson 1978618848 +Ref: Knuth 1965619113 +Ref: Scott 2000619347 +Node: Index of Terms619664  End Tag Table diff --git a/local/recipes/dev/bison/source/doc/stamp-vti b/local/recipes/dev/bison/source/doc/stamp-vti index f0d2ff89da..ea589ebddd 100644 --- a/local/recipes/dev/bison/source/doc/stamp-vti +++ b/local/recipes/dev/bison/source/doc/stamp-vti @@ -1,4 +1,4 @@ -@set UPDATED 12 September 2021 -@set UPDATED-MONTH September 2021 +@set UPDATED 15 May 2026 +@set UPDATED-MONTH May 2026 @set EDITION 3.8.2 @set VERSION 3.8.2 diff --git a/local/recipes/dev/bison/source/doc/version.texi b/local/recipes/dev/bison/source/doc/version.texi index f0d2ff89da..ea589ebddd 100644 --- a/local/recipes/dev/bison/source/doc/version.texi +++ b/local/recipes/dev/bison/source/doc/version.texi @@ -1,4 +1,4 @@ -@set UPDATED 12 September 2021 -@set UPDATED-MONTH September 2021 +@set UPDATED 15 May 2026 +@set UPDATED-MONTH May 2026 @set EDITION 3.8.2 @set VERSION 3.8.2 diff --git a/local/recipes/dev/bison/source/lib/config.in.h b/local/recipes/dev/bison/source/lib/config.in.h index c93fae45a5..2776c42a12 100644 --- a/local/recipes/dev/bison/source/lib/config.in.h +++ b/local/recipes/dev/bison/source/lib/config.in.h @@ -585,10 +585,10 @@ /* Define to 1 if you have the header file. */ #undef HAVE_BP_SYM_H -/* Define to 1 if you have the `canonicalize_file_name' function. */ +/* Define to 1 if you have the 'canonicalize_file_name' function. */ #undef HAVE_CANONICALIZE_FILE_NAME -/* Define to 1 if you have the `catgets' function. */ +/* Define to 1 if you have the 'catgets' function. */ #undef HAVE_CATGETS /* Define to 1 if you have the Mac OS X function CFLocaleCopyCurrent in the @@ -599,16 +599,16 @@ the CoreFoundation framework. */ #undef HAVE_CFPREFERENCESCOPYAPPVALUE -/* Define to 1 if you have the `clock_gettime' function. */ +/* Define to 1 if you have the 'clock_gettime' function. */ #undef HAVE_CLOCK_GETTIME -/* Define to 1 if you have the `clock_settime' function. */ +/* Define to 1 if you have the 'clock_settime' function. */ #undef HAVE_CLOCK_SETTIME -/* Define to 1 if you have the `closedir' function. */ +/* Define to 1 if you have the 'closedir' function. */ #undef HAVE_CLOSEDIR -/* Define to 1 if you have the `confstr' function. */ +/* Define to 1 if you have the 'confstr' function. */ #undef HAVE_CONFSTR /* Define if the copysignf function is declared in and available in @@ -623,7 +623,7 @@ libc. */ #undef HAVE_COPYSIGN_IN_LIBC -/* Define to 1 if you have the `copy_file_range' function. */ +/* Define to 1 if you have the 'copy_file_range' function. */ #undef HAVE_COPY_FILE_RANGE /* Define to 1 if you have the header file. */ @@ -633,127 +633,127 @@ */ #undef HAVE_DCGETTEXT -/* Define to 1 if you have the declaration of `alarm', and to 0 if you don't. +/* Define to 1 if you have the declaration of 'alarm', and to 0 if you don't. */ #undef HAVE_DECL_ALARM -/* Define to 1 if you have the declaration of `clearerr_unlocked', and to 0 if +/* Define to 1 if you have the declaration of 'clearerr_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_CLEARERR_UNLOCKED -/* Define to 1 if you have the declaration of `copysign', and to 0 if you +/* Define to 1 if you have the declaration of 'copysign', and to 0 if you don't. */ #undef HAVE_DECL_COPYSIGN -/* Define to 1 if you have the declaration of `copysignf', and to 0 if you +/* Define to 1 if you have the declaration of 'copysignf', and to 0 if you don't. */ #undef HAVE_DECL_COPYSIGNF -/* Define to 1 if you have the declaration of `copysignl', and to 0 if you +/* Define to 1 if you have the declaration of 'copysignl', and to 0 if you don't. */ #undef HAVE_DECL_COPYSIGNL -/* Define to 1 if you have the declaration of `dirfd', and to 0 if you don't. +/* Define to 1 if you have the declaration of 'dirfd', and to 0 if you don't. */ #undef HAVE_DECL_DIRFD -/* Define to 1 if you have the declaration of `ecvt', and to 0 if you don't. +/* Define to 1 if you have the declaration of 'ecvt', and to 0 if you don't. */ #undef HAVE_DECL_ECVT -/* Define to 1 if you have the declaration of `execvpe', and to 0 if you +/* Define to 1 if you have the declaration of 'execvpe', and to 0 if you don't. */ #undef HAVE_DECL_EXECVPE -/* Define to 1 if you have the declaration of `fchdir', and to 0 if you don't. +/* Define to 1 if you have the declaration of 'fchdir', and to 0 if you don't. */ #undef HAVE_DECL_FCHDIR -/* Define to 1 if you have the declaration of `fcloseall', and to 0 if you +/* Define to 1 if you have the declaration of 'fcloseall', and to 0 if you don't. */ #undef HAVE_DECL_FCLOSEALL -/* Define to 1 if you have the declaration of `fcvt', and to 0 if you don't. +/* Define to 1 if you have the declaration of 'fcvt', and to 0 if you don't. */ #undef HAVE_DECL_FCVT -/* Define to 1 if you have the declaration of `fdopendir', and to 0 if you +/* Define to 1 if you have the declaration of 'fdopendir', and to 0 if you don't. */ #undef HAVE_DECL_FDOPENDIR -/* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you +/* Define to 1 if you have the declaration of 'feof_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_FEOF_UNLOCKED -/* Define to 1 if you have the declaration of `ferror_unlocked', and to 0 if +/* Define to 1 if you have the declaration of 'ferror_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_FERROR_UNLOCKED -/* Define to 1 if you have the declaration of `fflush_unlocked', and to 0 if +/* Define to 1 if you have the declaration of 'fflush_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_FFLUSH_UNLOCKED -/* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if +/* Define to 1 if you have the declaration of 'fgets_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_FGETS_UNLOCKED -/* Define to 1 if you have the declaration of `fputc_unlocked', and to 0 if +/* Define to 1 if you have the declaration of 'fputc_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_FPUTC_UNLOCKED -/* Define to 1 if you have the declaration of `fputs_unlocked', and to 0 if +/* Define to 1 if you have the declaration of 'fputs_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_FPUTS_UNLOCKED -/* Define to 1 if you have the declaration of `fread_unlocked', and to 0 if +/* Define to 1 if you have the declaration of 'fread_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_FREAD_UNLOCKED -/* Define to 1 if you have the declaration of `fwrite_unlocked', and to 0 if +/* Define to 1 if you have the declaration of 'fwrite_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_FWRITE_UNLOCKED -/* Define to 1 if you have the declaration of `gcvt', and to 0 if you don't. +/* Define to 1 if you have the declaration of 'gcvt', and to 0 if you don't. */ #undef HAVE_DECL_GCVT -/* Define to 1 if you have the declaration of `getchar_unlocked', and to 0 if +/* Define to 1 if you have the declaration of 'getchar_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_GETCHAR_UNLOCKED -/* Define to 1 if you have the declaration of `getcwd', and to 0 if you don't. +/* Define to 1 if you have the declaration of 'getcwd', and to 0 if you don't. */ #undef HAVE_DECL_GETCWD -/* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you +/* Define to 1 if you have the declaration of 'getc_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_GETC_UNLOCKED -/* Define to 1 if you have the declaration of `getdelim', and to 0 if you +/* Define to 1 if you have the declaration of 'getdelim', and to 0 if you don't. */ #undef HAVE_DECL_GETDELIM -/* Define to 1 if you have the declaration of `getdtablesize', and to 0 if you +/* Define to 1 if you have the declaration of 'getdtablesize', and to 0 if you don't. */ #undef HAVE_DECL_GETDTABLESIZE -/* Define to 1 if you have the declaration of `gethrtime', and to 0 if you +/* Define to 1 if you have the declaration of 'gethrtime', and to 0 if you don't. */ #undef HAVE_DECL_GETHRTIME -/* Define to 1 if you have the declaration of `getline', and to 0 if you +/* Define to 1 if you have the declaration of 'getline', and to 0 if you don't. */ #undef HAVE_DECL_GETLINE -/* Define to 1 if you have the declaration of `iswblank', and to 0 if you +/* Define to 1 if you have the declaration of 'iswblank', and to 0 if you don't. */ #undef HAVE_DECL_ISWBLANK -/* Define to 1 if you have the declaration of `mbrtowc', and to 0 if you +/* Define to 1 if you have the declaration of 'mbrtowc', and to 0 if you don't. */ #undef HAVE_DECL_MBRTOWC -/* Define to 1 if you have the declaration of `mbsinit', and to 0 if you +/* Define to 1 if you have the declaration of 'mbsinit', and to 0 if you don't. */ #undef HAVE_DECL_MBSINIT @@ -761,122 +761,122 @@ otherwise. */ #undef HAVE_DECL_MBSWIDTH_IN_WCHAR_H -/* Define to 1 if you have the declaration of `memrchr', and to 0 if you +/* Define to 1 if you have the declaration of 'memrchr', and to 0 if you don't. */ #undef HAVE_DECL_MEMRCHR -/* Define to 1 if you have the declaration of `obstack_printf', and to 0 if +/* Define to 1 if you have the declaration of 'obstack_printf', and to 0 if you don't. */ #undef HAVE_DECL_OBSTACK_PRINTF -/* Define to 1 if you have the declaration of `posix_spawn', and to 0 if you +/* Define to 1 if you have the declaration of 'posix_spawn', and to 0 if you don't. */ #undef HAVE_DECL_POSIX_SPAWN -/* Define to 1 if you have the declaration of `program_invocation_name', and +/* Define to 1 if you have the declaration of 'program_invocation_name', and to 0 if you don't. */ #undef HAVE_DECL_PROGRAM_INVOCATION_NAME -/* Define to 1 if you have the declaration of `program_invocation_short_name', +/* Define to 1 if you have the declaration of 'program_invocation_short_name', and to 0 if you don't. */ #undef HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME -/* Define to 1 if you have the declaration of `putchar_unlocked', and to 0 if +/* Define to 1 if you have the declaration of 'putchar_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_PUTCHAR_UNLOCKED -/* Define to 1 if you have the declaration of `putc_unlocked', and to 0 if you +/* Define to 1 if you have the declaration of 'putc_unlocked', and to 0 if you don't. */ #undef HAVE_DECL_PUTC_UNLOCKED -/* Define to 1 if you have the declaration of `setenv', and to 0 if you don't. +/* Define to 1 if you have the declaration of 'setenv', and to 0 if you don't. */ #undef HAVE_DECL_SETENV -/* Define to 1 if you have the declaration of `snprintf', and to 0 if you +/* Define to 1 if you have the declaration of 'snprintf', and to 0 if you don't. */ #undef HAVE_DECL_SNPRINTF -/* Define to 1 if you have the declaration of `stpncpy', and to 0 if you +/* Define to 1 if you have the declaration of 'stpncpy', and to 0 if you don't. */ #undef HAVE_DECL_STPNCPY -/* Define to 1 if you have the declaration of `strdup', and to 0 if you don't. +/* Define to 1 if you have the declaration of 'strdup', and to 0 if you don't. */ #undef HAVE_DECL_STRDUP -/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you +/* Define to 1 if you have the declaration of 'strerror_r', and to 0 if you don't. */ #undef HAVE_DECL_STRERROR_R -/* Define to 1 if you have the declaration of `strndup', and to 0 if you +/* Define to 1 if you have the declaration of 'strndup', and to 0 if you don't. */ #undef HAVE_DECL_STRNDUP -/* Define to 1 if you have the declaration of `strnlen', and to 0 if you +/* Define to 1 if you have the declaration of 'strnlen', and to 0 if you don't. */ #undef HAVE_DECL_STRNLEN -/* Define to 1 if you have the declaration of `towlower', and to 0 if you +/* Define to 1 if you have the declaration of 'towlower', and to 0 if you don't. */ #undef HAVE_DECL_TOWLOWER -/* Define to 1 if you have the declaration of `unsetenv', and to 0 if you +/* Define to 1 if you have the declaration of 'unsetenv', and to 0 if you don't. */ #undef HAVE_DECL_UNSETENV -/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you +/* Define to 1 if you have the declaration of 'vsnprintf', and to 0 if you don't. */ #undef HAVE_DECL_VSNPRINTF -/* Define to 1 if you have the declaration of `wcsdup', and to 0 if you don't. +/* Define to 1 if you have the declaration of 'wcsdup', and to 0 if you don't. */ #undef HAVE_DECL_WCSDUP -/* Define to 1 if you have the declaration of `wcwidth', and to 0 if you +/* Define to 1 if you have the declaration of 'wcwidth', and to 0 if you don't. */ #undef HAVE_DECL_WCWIDTH -/* Define to 1 if you have the declaration of `_snprintf', and to 0 if you +/* Define to 1 if you have the declaration of '_snprintf', and to 0 if you don't. */ #undef HAVE_DECL__SNPRINTF -/* Define to 1 if you have the declaration of `__argv', and to 0 if you don't. +/* Define to 1 if you have the declaration of '__argv', and to 0 if you don't. */ #undef HAVE_DECL___ARGV -/* Define to 1 if you have the declaration of `__fpending', and to 0 if you +/* Define to 1 if you have the declaration of '__fpending', and to 0 if you don't. */ #undef HAVE_DECL___FPENDING /* Define to 1 if you have the header file. */ #undef HAVE_DIRENT_H -/* Define to 1 if you have the `dirfd' function. */ +/* Define to 1 if you have the 'dirfd' function. */ #undef HAVE_DIRFD /* Define if you have the declaration of environ. */ #undef HAVE_ENVIRON_DECL -/* Define to 1 if you have the `faccessat' function. */ +/* Define to 1 if you have the 'faccessat' function. */ #undef HAVE_FACCESSAT -/* Define to 1 if you have the `fchdir' function. */ +/* Define to 1 if you have the 'fchdir' function. */ #undef HAVE_FCHDIR -/* Define to 1 if you have the `fcntl' function. */ +/* Define to 1 if you have the 'fcntl' function. */ #undef HAVE_FCNTL -/* Define to 1 if you have the `fdopendir' function. */ +/* Define to 1 if you have the 'fdopendir' function. */ #undef HAVE_FDOPENDIR /* Define to 1 if you have the header file. */ #undef HAVE_FEATURES_H -/* Define to 1 if you have the `ffsl' function. */ +/* Define to 1 if you have the 'ffsl' function. */ #undef HAVE_FFSL -/* Define to 1 if you have the `flockfile' function. */ +/* Define to 1 if you have the 'flockfile' function. */ #undef HAVE_FLOCKFILE /* Define if the 'free' function is guaranteed to preserve errno. */ @@ -888,50 +888,50 @@ /* Define if the frexp function is available in libc. */ #undef HAVE_FREXP_IN_LIBC -/* Define to 1 if you have the `fstatat' function. */ +/* Define to 1 if you have the 'fstatat' function. */ #undef HAVE_FSTATAT -/* Define to 1 if you have the `fsync' function. */ +/* Define to 1 if you have the 'fsync' function. */ #undef HAVE_FSYNC -/* Define to 1 if you have the `funlockfile' function. */ +/* Define to 1 if you have the 'funlockfile' function. */ #undef HAVE_FUNLOCKFILE -/* Define to 1 if you have the `getcwd' function. */ +/* Define to 1 if you have the 'getcwd' function. */ #undef HAVE_GETCWD /* Define to 1 if getcwd works, but with shorter paths than is generally tested with the replacement. */ #undef HAVE_GETCWD_SHORTER -/* Define to 1 if you have the `getdelim' function. */ +/* Define to 1 if you have the 'getdelim' function. */ #undef HAVE_GETDELIM -/* Define to 1 if you have the `getdtablesize' function. */ +/* Define to 1 if you have the 'getdtablesize' function. */ #undef HAVE_GETDTABLESIZE -/* Define to 1 if you have the `getexecname' function. */ +/* Define to 1 if you have the 'getexecname' function. */ #undef HAVE_GETEXECNAME /* Define to 1 if you have the header file. */ #undef HAVE_GETOPT_H -/* Define to 1 if you have the `getopt_long_only' function. */ +/* Define to 1 if you have the 'getopt_long_only' function. */ #undef HAVE_GETOPT_LONG_ONLY /* Define to 1 if the system has the 'getpagesize' function. */ #undef HAVE_GETPAGESIZE -/* Define to 1 if you have the `getprogname' function. */ +/* Define to 1 if you have the 'getprogname' function. */ #undef HAVE_GETPROGNAME -/* Define to 1 if you have the `getrusage' function. */ +/* Define to 1 if you have the 'getrusage' function. */ #undef HAVE_GETRUSAGE /* Define if the GNU gettext() function is already present or preinstalled. */ #undef HAVE_GETTEXT -/* Define to 1 if you have the `gettimeofday' function. */ +/* Define to 1 if you have the 'gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Define if you have the iconv() function and it works. */ @@ -955,7 +955,7 @@ declares uintmax_t. */ #undef HAVE_INTTYPES_H_WITH_UINTMAX -/* Define to 1 if you have the `isascii' function. */ +/* Define to 1 if you have the 'isascii' function. */ #undef HAVE_ISASCII /* Define if the isnan(double) function is available in libc. */ @@ -967,10 +967,10 @@ /* Define if the isnan(long double) function is available in libc. */ #undef HAVE_ISNANL_IN_LIBC -/* Define to 1 if you have the `iswblank' function. */ +/* Define to 1 if you have the 'iswblank' function. */ #undef HAVE_ISWBLANK -/* Define to 1 if you have the `iswcntrl' function. */ +/* Define to 1 if you have the 'iswcntrl' function. */ #undef HAVE_ISWCNTRL /* Define if you have and nl_langinfo(CODESET). */ @@ -991,7 +991,7 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H -/* Define to 1 if you have the `link' function. */ +/* Define to 1 if you have the 'link' function. */ #undef HAVE_LINK /* Define to 1 if you have the header file. */ @@ -1000,7 +1000,7 @@ /* Define to 1 if the system has the type 'long long int'. */ #undef HAVE_LONG_LONG_INT -/* Define to 1 if you have the `lstat' function. */ +/* Define to 1 if you have the 'lstat' function. */ #undef HAVE_LSTAT /* Define to 1 if you have the header file. */ @@ -1016,22 +1016,22 @@ /* Define to 1 if you have the header file. */ #undef HAVE_MATH_H -/* Define to 1 if you have the `mbrtowc' function. */ +/* Define to 1 if you have the 'mbrtowc' function. */ #undef HAVE_MBRTOWC -/* Define to 1 if you have the `mbsinit' function. */ +/* Define to 1 if you have the 'mbsinit' function. */ #undef HAVE_MBSINIT /* Define to 1 if declares mbstate_t. */ #undef HAVE_MBSTATE_T -/* Define to 1 if you have the `mempcpy' function. */ +/* Define to 1 if you have the 'mempcpy' function. */ #undef HAVE_MEMPCPY -/* Define to 1 if you have the `memrchr' function. */ +/* Define to 1 if you have the 'memrchr' function. */ #undef HAVE_MEMRCHR -/* Define to 1 if you have the `microuptime' function. */ +/* Define to 1 if you have the 'microuptime' function. */ #undef HAVE_MICROUPTIME /* Define to 1 if getcwd minimally works, that is, its result can be trusted @@ -1047,29 +1047,29 @@ /* Define to 1 if defines the MIN and MAX macros. */ #undef HAVE_MINMAX_IN_SYS_PARAM_H -/* Define to 1 if you have the `mprotect' function. */ +/* Define to 1 if you have the 'mprotect' function. */ #undef HAVE_MPROTECT /* Define to 1 on MSVC platforms that have the "invalid parameter handler" concept. */ #undef HAVE_MSVC_INVALID_PARAMETER_HANDLER -/* Define to 1 if you have the `nanouptime' function. */ +/* Define to 1 if you have the 'nanouptime' function. */ #undef HAVE_NANOUPTIME -/* Define to 1 if you have the `nl_langinfo' function. */ +/* Define to 1 if you have the 'nl_langinfo' function. */ #undef HAVE_NL_LANGINFO /* Define to 1 if the system has obstacks that work with any size object. */ #undef HAVE_OBSTACK -/* Define to 1 if you have the `obstack_printf' function. */ +/* Define to 1 if you have the 'obstack_printf' function. */ #undef HAVE_OBSTACK_PRINTF -/* Define to 1 if you have the `openat' function. */ +/* Define to 1 if you have the 'openat' function. */ #undef HAVE_OPENAT -/* Define to 1 if you have the `opendir' function. */ +/* Define to 1 if you have the 'opendir' function. */ #undef HAVE_OPENDIR /* Define to 1 if getcwd works, except it sometimes fails when it shouldn't, @@ -1079,27 +1079,27 @@ /* Define to 1 if you have the header file. */ #undef HAVE_PATHS_H -/* Define to 1 if you have the `pipe' function. */ +/* Define to 1 if you have the 'pipe' function. */ #undef HAVE_PIPE -/* Define to 1 if you have the `pipe2' function. */ +/* Define to 1 if you have the 'pipe2' function. */ #undef HAVE_PIPE2 -/* Define to 1 if you have the `posix_spawn' function. */ +/* Define to 1 if you have the 'posix_spawn' function. */ #undef HAVE_POSIX_SPAWN -/* Define to 1 if the system has the type `posix_spawnattr_t'. */ +/* Define to 1 if the system has the type 'posix_spawnattr_t'. */ #undef HAVE_POSIX_SPAWNATTR_T -/* Define to 1 if you have the `posix_spawn_file_actions_addchdir' function. +/* Define to 1 if you have the 'posix_spawn_file_actions_addchdir' function. */ #undef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR -/* Define to 1 if you have the `posix_spawn_file_actions_addchdir_np' +/* Define to 1 if you have the 'posix_spawn_file_actions_addchdir_np' function. */ #undef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP -/* Define to 1 if the system has the type `posix_spawn_file_actions_t'. */ +/* Define to 1 if the system has the type 'posix_spawn_file_actions_t'. */ #undef HAVE_POSIX_SPAWN_FILE_ACTIONS_T /* Define if you have the header and the POSIX threads API. */ @@ -1115,13 +1115,13 @@ reader. */ #undef HAVE_PTHREAD_RWLOCK_RDLOCK_PREFER_WRITER -/* Define to 1 if you have the `raise' function. */ +/* Define to 1 if you have the 'raise' function. */ #undef HAVE_RAISE -/* Define to 1 if you have the `rawmemchr' function. */ +/* Define to 1 if you have the 'rawmemchr' function. */ #undef HAVE_RAWMEMCHR -/* Define to 1 if you have the `readdir' function. */ +/* Define to 1 if you have the 'readdir' function. */ #undef HAVE_READDIR /* Define if you have the readline library. */ @@ -1133,19 +1133,19 @@ /* Define to 1 if you have the header file. */ #undef HAVE_READLINE_READLINE_H -/* Define to 1 if you have the `readlink' function. */ +/* Define to 1 if you have the 'readlink' function. */ #undef HAVE_READLINK -/* Define to 1 if you have the `readlinkat' function. */ +/* Define to 1 if you have the 'readlinkat' function. */ #undef HAVE_READLINKAT -/* Define to 1 if you have the `reallocarray' function. */ +/* Define to 1 if you have the 'reallocarray' function. */ #undef HAVE_REALLOCARRAY -/* Define to 1 if you have the `realpath' function. */ +/* Define to 1 if you have the 'realpath' function. */ #undef HAVE_REALPATH -/* Define to 1 if you have the `rewinddir' function. */ +/* Define to 1 if you have the 'rewinddir' function. */ #undef HAVE_REWINDDIR /* Define to 1 if 'long double' and 'double' have the same representation. */ @@ -1154,10 +1154,10 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SCHED_H -/* Define to 1 if you have the `sched_setparam' function. */ +/* Define to 1 if you have the 'sched_setparam' function. */ #undef HAVE_SCHED_SETPARAM -/* Define to 1 if you have the `sched_setscheduler' function. */ +/* Define to 1 if you have the 'sched_setscheduler' function. */ #undef HAVE_SCHED_SETSCHEDULER /* Define to 1 if you have the header file. */ @@ -1166,31 +1166,31 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SEARCH_H -/* Define to 1 if you have the `setdtablesize' function. */ +/* Define to 1 if you have the 'setdtablesize' function. */ #undef HAVE_SETDTABLESIZE -/* Define to 1 if you have the `setegid' function. */ +/* Define to 1 if you have the 'setegid' function. */ #undef HAVE_SETEGID -/* Define to 1 if you have the `setenv' function. */ +/* Define to 1 if you have the 'setenv' function. */ #undef HAVE_SETENV -/* Define to 1 if you have the `seteuid' function. */ +/* Define to 1 if you have the 'seteuid' function. */ #undef HAVE_SETEUID -/* Define to 1 if you have the `setlocale' function. */ +/* Define to 1 if you have the 'setlocale' function. */ #undef HAVE_SETLOCALE -/* Define to 1 if you have the `sigaction' function. */ +/* Define to 1 if you have the 'sigaction' function. */ #undef HAVE_SIGACTION -/* Define to 1 if you have the `sigaltstack' function. */ +/* Define to 1 if you have the 'sigaltstack' function. */ #undef HAVE_SIGALTSTACK -/* Define to 1 if the system has the type `siginfo_t'. */ +/* Define to 1 if the system has the type 'siginfo_t'. */ #undef HAVE_SIGINFO_T -/* Define to 1 if you have the `siginterrupt' function. */ +/* Define to 1 if you have the 'siginterrupt' function. */ #undef HAVE_SIGINTERRUPT /* Define to 1 if 'sig_atomic_t' is a signed integer type. */ @@ -1202,13 +1202,13 @@ /* Define to 1 if 'wint_t' is a signed integer type. */ #undef HAVE_SIGNED_WINT_T -/* Define to 1 if the system has the type `sigset_t'. */ +/* Define to 1 if the system has the type 'sigset_t'. */ #undef HAVE_SIGSET_T -/* Define to 1 if the system has the type `sig_atomic_t'. */ +/* Define to 1 if the system has the type 'sig_atomic_t'. */ #undef HAVE_SIG_ATOMIC_T -/* Define to 1 if you have the `snprintf' function. */ +/* Define to 1 if you have the 'snprintf' function. */ #undef HAVE_SNPRINTF /* Define if the return value of the snprintf function is the number of of @@ -1239,16 +1239,16 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H -/* Define to 1 if you have the `stpcpy' function. */ +/* Define to 1 if you have the 'stpcpy' function. */ #undef HAVE_STPCPY /* Define if you have the stpncpy() function and it works. */ #undef HAVE_STPNCPY -/* Define to 1 if you have the `strchrnul' function. */ +/* Define to 1 if you have the 'strchrnul' function. */ #undef HAVE_STRCHRNUL -/* Define to 1 if you have the `strerror_r' function. */ +/* Define to 1 if you have the 'strerror_r' function. */ #undef HAVE_STRERROR_R /* Define to 1 if you have the header file. */ @@ -1257,43 +1257,43 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H -/* Define to 1 if you have the `strndup' function. */ +/* Define to 1 if you have the 'strndup' function. */ #undef HAVE_STRNDUP -/* Define to 1 if you have the `strnlen' function. */ +/* Define to 1 if you have the 'strnlen' function. */ #undef HAVE_STRNLEN -/* Define to 1 if `sa_sigaction' is a member of `struct sigaction'. */ +/* Define to 1 if 'sa_sigaction' is a member of 'struct sigaction'. */ #undef HAVE_STRUCT_SIGACTION_SA_SIGACTION -/* Define to 1 if `st_atimensec' is a member of `struct stat'. */ +/* Define to 1 if 'st_atimensec' is a member of 'struct stat'. */ #undef HAVE_STRUCT_STAT_ST_ATIMENSEC -/* Define to 1 if `st_atimespec.tv_nsec' is a member of `struct stat'. */ +/* Define to 1 if 'st_atimespec.tv_nsec' is a member of 'struct stat'. */ #undef HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC -/* Define to 1 if `st_atim.st__tim.tv_nsec' is a member of `struct stat'. */ +/* Define to 1 if 'st_atim.st__tim.tv_nsec' is a member of 'struct stat'. */ #undef HAVE_STRUCT_STAT_ST_ATIM_ST__TIM_TV_NSEC -/* Define to 1 if `st_atim.tv_nsec' is a member of `struct stat'. */ +/* Define to 1 if 'st_atim.tv_nsec' is a member of 'struct stat'. */ #undef HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC -/* Define to 1 if `st_birthtimensec' is a member of `struct stat'. */ +/* Define to 1 if 'st_birthtimensec' is a member of 'struct stat'. */ #undef HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC -/* Define to 1 if `st_birthtimespec.tv_nsec' is a member of `struct stat'. */ +/* Define to 1 if 'st_birthtimespec.tv_nsec' is a member of 'struct stat'. */ #undef HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC -/* Define to 1 if `st_birthtim.tv_nsec' is a member of `struct stat'. */ +/* Define to 1 if 'st_birthtim.tv_nsec' is a member of 'struct stat'. */ #undef HAVE_STRUCT_STAT_ST_BIRTHTIM_TV_NSEC -/* Define to 1 if the system has the type `struct tms'. */ +/* Define to 1 if the system has the type 'struct tms'. */ #undef HAVE_STRUCT_TMS -/* Define to 1 if you have the `strverscmp' function. */ +/* Define to 1 if you have the 'strverscmp' function. */ #undef HAVE_STRVERSCMP -/* Define to 1 if you have the `symlink' function. */ +/* Define to 1 if you have the 'symlink' function. */ #undef HAVE_SYMLINK /* Define to 1 if you have the header file. */ @@ -1338,28 +1338,28 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H -/* Define to 1 if you have the `tcdrain' function. */ +/* Define to 1 if you have the 'tcdrain' function. */ #undef HAVE_TCDRAIN /* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H -/* Define to 1 if you have the `thrd_create' function. */ +/* Define to 1 if you have the 'thrd_create' function. */ #undef HAVE_THRD_CREATE /* Define to 1 if you have the header file. */ #undef HAVE_THREADS_H -/* Define to 1 if you have the `towlower' function. */ +/* Define to 1 if you have the 'towlower' function. */ #undef HAVE_TOWLOWER -/* Define to 1 if you have the `tsearch' function. */ +/* Define to 1 if you have the 'tsearch' function. */ #undef HAVE_TSEARCH /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H -/* Define to 1 if you have the `unsetenv' function. */ +/* Define to 1 if you have the 'unsetenv' function. */ #undef HAVE_UNSETENV /* Define to 1 if the system has the type 'unsigned long long int'. */ @@ -1368,23 +1368,23 @@ /* Define if you have a global __progname variable */ #undef HAVE_VAR___PROGNAME -/* Define to 1 if you have the `vasnprintf' function. */ +/* Define to 1 if you have the 'vasnprintf' function. */ #undef HAVE_VASNPRINTF -/* Define to 1 if you have the `vasprintf' function. */ +/* Define to 1 if you have the 'vasprintf' function. */ #undef HAVE_VASPRINTF -/* Define to 1 if you have the `vfork' function. */ +/* Define to 1 if you have the 'vfork' function. */ #undef HAVE_VFORK /* Define to 1 or 0, depending whether the compiler supports simple visibility declarations. */ #undef HAVE_VISIBILITY -/* Define to 1 if you have the `vsnprintf' function. */ +/* Define to 1 if you have the 'vsnprintf' function. */ #undef HAVE_VSNPRINTF -/* Define to 1 if you have the `waitid' function. */ +/* Define to 1 if you have the 'waitid' function. */ #undef HAVE_WAITID /* Define to 1 if you have the header file. */ @@ -1393,19 +1393,19 @@ /* Define if you have the 'wchar_t' type. */ #undef HAVE_WCHAR_T -/* Define to 1 if you have the `wcrtomb' function. */ +/* Define to 1 if you have the 'wcrtomb' function. */ #undef HAVE_WCRTOMB -/* Define to 1 if you have the `wcslen' function. */ +/* Define to 1 if you have the 'wcslen' function. */ #undef HAVE_WCSLEN -/* Define to 1 if you have the `wcsnlen' function. */ +/* Define to 1 if you have the 'wcsnlen' function. */ #undef HAVE_WCSNLEN /* Define to 1 if you have the header file. */ #undef HAVE_WCTYPE_H -/* Define to 1 if you have the `wcwidth' function. */ +/* Define to 1 if you have the 'wcwidth' function. */ #undef HAVE_WCWIDTH /* Define to 1 if the compiler and linker support weak declarations of @@ -1431,13 +1431,13 @@ /* Define to 1 if you have the header file. */ #undef HAVE_XLOCALE_H -/* Define to 1 if the system has the type `_Bool'. */ +/* Define to 1 if the system has the type '_Bool'. */ #undef HAVE__BOOL -/* Define to 1 if you have the `_NSGetExecutablePath' function. */ +/* Define to 1 if you have the '_NSGetExecutablePath' function. */ #undef HAVE__NSGETEXECUTABLEPATH -/* Define to 1 if you have the `_set_invalid_parameter_handler' function. */ +/* Define to 1 if you have the '_set_invalid_parameter_handler' function. */ #undef HAVE__SET_INVALID_PARAMETER_HANDLER /* Define to 1 if the compiler supports __builtin_expect, @@ -1450,13 +1450,13 @@ #endif -/* Define to 1 if you have the `__fseterr' function. */ +/* Define to 1 if you have the '__fseterr' function. */ #undef HAVE___FSETERR /* Define to 1 if the compiler supports the keyword '__inline'. */ #undef HAVE___INLINE -/* Define to 1 if you have the `__xpg_strerror_r' function. */ +/* Define to 1 if you have the '__xpg_strerror_r' function. */ #undef HAVE___XPG_STRERROR_R /* Define as const if the declaration of iconv() needs const. */ @@ -1720,10 +1720,10 @@ STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION -/* Define to 1 if the `S_IS*' macros in do not work properly. */ +/* Define to 1 if the 'S_IS*' macros in do not work properly. */ #undef STAT_MACROS_BROKEN -/* Define to 1 if all of the C90 standard headers exist (not just the ones +/* Define to 1 if all of the C89 standard headers exist (not just the ones required in a freestanding environment). This macro is provided for backward compatibility; new code need not use it. */ #undef STDC_HEADERS @@ -1760,10 +1760,14 @@ weak. */ #undef USE_POSIX_THREADS_WEAK -/* Enable extensions on AIX 3, Interix. */ +/* Enable extensions on AIX, Interix, z/OS. */ #ifndef _ALL_SOURCE # undef _ALL_SOURCE #endif +/* Enable extensions on Cosmopolitan Libc. */ +#ifndef _COSMO_SOURCE +# undef _COSMO_SOURCE +#endif /* Enable general extensions on macOS. */ #ifndef _DARWIN_C_SOURCE # undef _DARWIN_C_SOURCE @@ -1821,11 +1825,15 @@ #ifndef __STDC_WANT_IEC_60559_DFP_EXT__ # undef __STDC_WANT_IEC_60559_DFP_EXT__ #endif +/* Enable extensions specified by C23 Annex F. */ +#ifndef __STDC_WANT_IEC_60559_EXT__ +# undef __STDC_WANT_IEC_60559_EXT__ +#endif /* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ #ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ # undef __STDC_WANT_IEC_60559_FUNCS_EXT__ #endif -/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ +/* Enable extensions specified by C23 Annex H and ISO/IEC TS 18661-3:2015. */ #ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ # undef __STDC_WANT_IEC_60559_TYPES_EXT__ #endif @@ -2455,10 +2463,10 @@ # define _GL_INLINE_HEADER_END #endif -/* Define to `int' if doesn't define. */ +/* Define as 'int' if doesn't define. */ #undef gid_t -/* Define to `__inline__' or `__inline' if that's what the C compiler +/* Define to '__inline__' or '__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline @@ -2496,7 +2504,7 @@ #define _GL_CMP(n1, n2) (((n1) > (n2)) - ((n1) < (n2))) -/* Define to `int' if does not define. */ +/* Define to 'int' if does not define. */ #undef mode_t /* Define to the type of st_nlink in struct stat, or a supertype. */ @@ -2528,13 +2536,13 @@ accessed atomically even in the presence of asynchronous signals. */ #undef sig_atomic_t -/* Define to `unsigned int' if does not define. */ +/* Define as 'unsigned int' if doesn't define. */ #undef size_t /* Define as a signed type of the same size as size_t. */ #undef ssize_t -/* Define to `int' if doesn't define. */ +/* Define as 'int' if doesn't define. */ #undef uid_t diff --git a/local/recipes/dev/flex/source/doc/flex.info b/local/recipes/dev/flex/source/doc/flex.info index a972bcd9d2..30c02398b3 100644 --- a/local/recipes/dev/flex/source/doc/flex.info +++ b/local/recipes/dev/flex/source/doc/flex.info @@ -1,12 +1,12 @@ -This is flex.info, produced by makeinfo version 6.1 from flex.texi. +This is flex.info, produced by makeinfo version 7.3 from flex.texi. The flex manual is placed under the same licensing conditions as the rest of flex: - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2012 The Flex + Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2012 The Flex Project. - Copyright (C) 1990, 1997 The Regents of the University of California. + Copyright © 1990, 1997 The Regents of the University of California. All rights reserved. This code is derived from software contributed to Berkeley by Vern @@ -42,240 +42,245 @@ END-INFO-DIR-ENTRY  Indirect: -flex.info-1: 1622 -flex.info-2: 318745 +flex.info-1: 1620 +flex.info-2: 324917  Tag Table: (Indirect) -Node: Top1622 -Node: Copyright9414 -Node: Reporting Bugs10933 -Node: Introduction11189 -Node: Simple Examples12018 -Node: Format15304 -Node: Definitions Section15759 -Ref: Definitions Section-Footnote-118017 -Node: Rules Section18085 -Node: User Code Section19243 -Node: Comments in the Input19681 -Node: Patterns21051 -Ref: case and character ranges27883 -Node: Matching31886 -Node: Actions35171 -Node: Generated Scanner44133 -Node: Start Conditions49136 -Node: Multiple Input Buffers59678 -Ref: Scanning Strings66221 -Node: EOF67850 -Node: Misc Macros69436 -Node: User Values72290 -Node: Yacc74615 -Node: Scanner Options75510 -Node: Options for Specifying Filenames78299 -Ref: option-header78525 -Ref: option-outfile79239 -Ref: option-stdout79564 -Node: Options Affecting Scanner Behavior80547 -Ref: option-case-insensitive80788 -Ref: option-lex-compat81221 -Ref: option-batch81753 -Ref: option-interactive82272 -Ref: option-7bit83626 -Ref: option-8bit84930 -Ref: option-default85342 -Ref: option-always-interactive85406 -Ref: option-posix86010 -Ref: option-stack87157 -Ref: option-stdinit87265 -Ref: option-yylineno87744 -Ref: option-yywrap88187 -Node: Code-Level And API Options88454 -Ref: option-ansi-definitions88681 -Ref: option-ansi-prototypes88756 -Ref: option-bison-bridge88829 -Ref: option-bison-locations89170 -Ref: option-noline89430 -Ref: option-reentrant89944 -Ref: option-c++90556 -Ref: option-array90682 -Ref: option-pointer90780 -Ref: option-prefix90907 -Ref: option-main92435 -Ref: option-nounistd92619 -Ref: option-yyclass93130 -Node: Options for Scanner Speed and Size93614 -Ref: option-align94164 -Ref: option-ecs94666 -Ref: option-meta-ecs95705 -Ref: option-read96193 -Ref: option-full98076 -Ref: option-fast98271 -Node: Debugging Options99195 -Ref: option-backup99382 -Ref: option-debug99927 -Ref: option-perf-report100649 -Ref: option-nodefault101275 -Ref: option-trace101593 -Ref: option-nowarn101884 -Ref: option-verbose101952 -Ref: option-warn102381 -Node: Miscellaneous Options102600 -Node: Performance103056 -Node: Cxx113303 -Node: Reentrant121395 -Node: Reentrant Uses122129 -Node: Reentrant Overview123691 -Node: Reentrant Example124491 -Node: Reentrant Detail125264 -Node: Specify Reentrant125768 -Node: Extra Reentrant Argument126418 -Node: Global Replacement127670 -Node: Init and Destroy Functions128905 -Node: Accessor Methods131426 -Node: Extra Data132773 -Node: About yyscan_t135040 -Node: Reentrant Functions135437 -Ref: bison-functions136921 -Node: Lex and Posix137660 -Node: Memory Management145007 -Ref: memory-management145153 -Node: The Default Memory Management145387 -Ref: The Default Memory Management-Footnote-1149207 -Node: Overriding The Default Memory Management149360 -Ref: Overriding The Default Memory Management-Footnote-1151774 -Node: A Note About yytext And Memory151938 -Node: Serialized Tables153178 -Ref: serialization153322 -Node: Creating Serialized Tables154102 -Node: Loading and Unloading Serialized Tables155717 -Node: Tables File Format157490 -Node: Diagnostics164515 -Node: Limitations167924 -Node: Bibliography169872 -Node: FAQ170542 -Node: When was flex born?175705 -Node: How do I expand backslash-escape sequences in C-style quoted strings?176082 -Node: Why do flex scanners call fileno if it is not ANSI compatible?177385 -Node: Does flex support recursive pattern definitions?178182 -Node: How do I skip huge chunks of input (tens of megabytes) while using flex?179029 -Node: Flex is not matching my patterns in the same order that I defined them.179496 -Node: My actions are executing out of order or sometimes not at all.181242 -Node: How can I have multiple input sources feed into the same scanner at the same time?182015 -Node: Can I build nested parsers that work with the same input file?184000 -Node: How can I match text only at the end of a file?185007 -Node: How can I make REJECT cascade across start condition boundaries?185811 -Node: Why cant I use fast or full tables with interactive mode?186825 -Node: How much faster is -F or -f than -C?188082 -Node: If I have a simple grammar cant I just parse it with flex?188394 -Node: Why doesn't yyrestart() set the start state back to INITIAL?188876 -Node: How can I match C-style comments?189503 -Node: The period isn't working the way I expected.190313 -Node: Can I get the flex manual in another format?191558 -Node: Does there exist a "faster" NDFA->DFA algorithm?192048 -Node: How does flex compile the DFA so quickly?192558 -Node: How can I use more than 8192 rules?193524 -Node: How do I abandon a file in the middle of a scan and switch to a new file?194934 -Node: How do I execute code only during initialization (only before the first scan)?195488 -Node: How do I execute code at termination?196265 -Node: Where else can I find help?196591 -Node: Can I include comments in the "rules" section of the file?196965 -Node: I get an error about undefined yywrap().197345 -Node: How can I change the matching pattern at run time?197821 -Node: How can I expand macros in the input?198183 -Node: How can I build a two-pass scanner?199215 -Node: How do I match any string not matched in the preceding rules?200133 -Node: I am trying to port code from AT&T lex that uses yysptr and yysbuf.201042 -Node: Is there a way to make flex treat NULL like a regular character?201837 -Node: Whenever flex can not match the input it says "flex scanner jammed".202357 -Node: Why doesn't flex have non-greedy operators like perl does?203000 -Node: Memory leak - 16386 bytes allocated by malloc.204353 -Ref: faq-memory-leak204651 -Node: How do I track the byte offset for lseek()?205622 -Node: How do I use my own I/O classes in a C++ scanner?207131 -Node: How do I skip as many chars as possible?207974 -Node: deleteme00209049 -Node: Are certain equivalent patterns faster than others?209489 -Node: Is backing up a big deal?212907 -Node: Can I fake multi-byte character support?214813 -Node: deleteme01216254 -Node: Can you discuss some flex internals?217363 -Node: unput() messes up yy_at_bol219607 -Node: The | operator is not doing what I want220709 -Node: Why can't flex understand this variable trailing context pattern?222255 -Node: The ^ operator isn't working223504 -Node: Trailing context is getting confused with trailing optional patterns224739 -Node: Is flex GNU or not?225982 -Node: ERASEME53227655 -Node: I need to scan if-then-else blocks and while loops228425 -Node: ERASEME55229624 -Node: ERASEME56230722 -Node: ERASEME57232080 -Node: Is there a repository for flex scanners?233078 -Node: How can I conditionally compile or preprocess my flex input file?233394 -Node: Where can I find grammars for lex and yacc?233867 -Node: I get an end-of-buffer message for each character scanned.234214 -Node: unnamed-faq-62234809 -Node: unnamed-faq-63235827 -Node: unnamed-faq-64237124 -Node: unnamed-faq-65238090 -Node: unnamed-faq-66238876 -Node: unnamed-faq-67239991 -Node: unnamed-faq-68240978 -Node: unnamed-faq-69242120 -Node: unnamed-faq-70242833 -Node: unnamed-faq-71243594 -Node: unnamed-faq-72244803 -Node: unnamed-faq-73245846 -Node: unnamed-faq-74246770 -Node: unnamed-faq-75247715 -Node: unnamed-faq-76248847 -Node: unnamed-faq-77249553 -Node: unnamed-faq-78250446 -Node: unnamed-faq-79251444 -Node: unnamed-faq-80253144 -Node: unnamed-faq-81254462 -Node: unnamed-faq-82257262 -Node: unnamed-faq-83258219 -Node: unnamed-faq-84259999 -Node: unnamed-faq-85261102 -Node: unnamed-faq-86262109 -Node: unnamed-faq-87263047 -Node: unnamed-faq-88263693 -Node: unnamed-faq-90264524 -Node: unnamed-faq-91265787 -Node: unnamed-faq-92268215 -Node: unnamed-faq-93268714 -Node: unnamed-faq-94269641 -Node: unnamed-faq-95271053 -Node: unnamed-faq-96272571 -Node: unnamed-faq-97273330 -Node: unnamed-faq-98273997 -Node: unnamed-faq-99274662 -Node: unnamed-faq-100275591 -Node: unnamed-faq-101276301 -Node: What is the difference between YYLEX_PARAM and YY_DECL?277114 -Node: Why do I get "conflicting types for yylex" error?277638 -Node: How do I access the values set in a Flex action from within a Bison action?278168 -Node: Appendices278597 -Node: Makefiles and Flex278862 -Ref: Makefiles and Flex-Footnote-1282064 -Ref: Makefiles and Flex-Footnote-2282181 -Ref: Makefiles and Flex-Footnote-3282368 -Node: Bison Bridge282419 -Ref: Bison Bridge-Footnote-1285086 -Node: M4 Dependency285278 -Ref: M4 Dependency-Footnote-1286692 -Node: Common Patterns286828 -Node: Numbers287151 -Node: Identifiers288127 -Node: Quoted Constructs288954 -Node: Addresses290008 -Node: Indices291320 -Node: Concept Index291612 -Node: Index of Functions and Macros318745 -Node: Index of Variables323714 -Node: Index of Data Types325380 -Node: Index of Hooks326268 -Node: Index of Scanner Options326836 +Node: Top1620 +Node: Copyright7694 +Node: Reporting Bugs9211 +Node: Introduction9471 +Node: Simple Examples10328 +Node: Format13771 +Node: Definitions Section14192 +Ref: Definitions Section-Footnote-116550 +Node: Rules Section16626 +Node: User Code Section17800 +Node: Comments in the Input18246 +Node: Patterns19651 +Ref: case and character ranges26973 +Node: Matching31202 +Node: Actions34639 +Node: Generated Scanner43962 +Node: Start Conditions49185 +Node: Multiple Input Buffers60101 +Ref: Scanning Strings66886 +Node: EOF68579 +Node: Misc Macros70215 +Node: User Values73173 +Node: Yacc75614 +Node: Scanner Options76575 +Node: Options for Specifying Filenames79407 +Ref: option-header79633 +Ref: option-outfile80379 +Ref: option-stdout80744 +Node: Options Affecting Scanner Behavior81763 +Ref: option-case-insensitive82004 +Ref: option-lex-compat82461 +Ref: option-batch83033 +Ref: option-interactive83588 +Ref: option-7bit84990 +Ref: option-8bit86358 +Ref: option-default86798 +Ref: option-always-interactive86870 +Ref: option-posix87498 +Ref: option-stack88711 +Ref: option-stdinit88827 +Ref: option-yylineno89350 +Ref: option-yywrap89829 +Node: Code-Level And API Options90120 +Ref: option-ansi-definitions90347 +Ref: option-ansi-prototypes90430 +Ref: option-bison-bridge90511 +Ref: option-bison-locations90876 +Ref: option-noline91164 +Ref: option-reentrant91714 +Ref: option-c++92346 +Ref: option-array92480 +Ref: option-pointer92586 +Ref: option-prefix92733 +Ref: option-main94325 +Ref: option-nounistd94529 +Ref: option-yyclass95068 +Node: Options for Scanner Speed and Size95596 +Ref: option-align96158 +Ref: option-ecs96668 +Ref: option-meta-ecs97751 +Ref: option-read98259 +Ref: option-full100222 +Ref: option-fast100437 +Node: Debugging Options101389 +Ref: option-backup101576 +Ref: option-debug102145 +Ref: option-perf-report102887 +Ref: option-nodefault103545 +Ref: option-trace103875 +Ref: option-nowarn104190 +Ref: option-verbose104266 +Ref: option-warn104723 +Node: Miscellaneous Options104950 +Node: Performance105434 +Node: Cxx115909 +Node: Reentrant124503 +Node: Reentrant Uses125197 +Node: Reentrant Overview126812 +Node: Reentrant Example127650 +Node: Reentrant Detail128458 +Node: Specify Reentrant128895 +Node: Extra Reentrant Argument129557 +Node: Global Replacement130869 +Node: Init and Destroy Functions132160 +Node: Accessor Methods134796 +Node: Extra Data136183 +Node: About yyscan_t138510 +Node: Reentrant Functions138919 +Ref: bison-functions140420 +Node: Lex and Posix141191 +Node: Memory Management149030 +Ref: memory-management149176 +Node: The Default Memory Management149404 +Ref: The Default Memory Management-Footnote-1153240 +Node: Overriding The Default Memory Management153393 +Ref: Overriding The Default Memory Management-Footnote-1155904 +Node: A Note About yytext And Memory156080 +Node: Serialized Tables157324 +Ref: serialization157468 +Node: Creating Serialized Tables158238 +Node: Loading and Unloading Serialized Tables159885 +Node: Tables File Format161694 +Node: Diagnostics169019 +Node: Limitations172584 +Node: Bibliography174608 +Node: FAQ175290 +Node: When was flex born?179534 +Node: How do I expand backslash-escape sequences in C-style quoted strings?179915 +Node: Why do flex scanners call fileno if it is not ANSI compatible?181230 +Node: Does flex support recursive pattern definitions?182071 +Node: How do I skip huge chunks of input (tens of megabytes) while using flex?182922 +Node: Flex is not matching my patterns in the same order that I defined them.183401 +Node: My actions are executing out of order or sometimes not at all.185187 +Node: How can I have multiple input sources feed into the same scanner at the same time?185982 +Node: Can I build nested parsers that work with the same input file?188033 +Node: How can I match text only at the end of a file?189060 +Node: How can I make REJECT cascade across start condition boundaries?189876 +Node: Why cant I use fast or full tables with interactive mode?190902 +Node: How much faster is -F or -f than -C?192159 +Node: If I have a simple grammar cant I just parse it with flex?192471 +Node: Why doesn't yyrestart() set the start state back to INITIAL?192953 +Node: How can I match C-style comments?193588 +Node: The period isn't working the way I expected.194398 +Node: Can I get the flex manual in another format?195735 +Node: Does there exist a "faster" NDFA->DFA algorithm?196233 +Node: How does flex compile the DFA so quickly?196743 +Node: How can I use more than 8192 rules?197713 +Node: How do I abandon a file in the middle of a scan and switch to a new file?199135 +Node: How do I execute code only during initialization (only before the first scan)?199701 +Node: How do I execute code at termination?200491 +Node: Where else can I find help?200821 +Node: Can I include comments in the "rules" section of the file?201195 +Node: I get an error about undefined yywrap().201575 +Node: How can I change the matching pattern at run time?202063 +Node: How can I expand macros in the input?202425 +Node: How can I build a two-pass scanner?203462 +Node: How do I match any string not matched in the preceding rules?204380 +Node: I am trying to port code from AT&T lex that uses yysptr and yysbuf.205301 +Node: Is there a way to make flex treat NULL like a regular character?206120 +Node: Whenever flex can not match the input it says "flex scanner jammed".206652 +Node: Why doesn't flex have non-greedy operators like perl does?207304 +Node: Memory leak - 16386 bytes allocated by malloc.208669 +Ref: faq-memory-leak208967 +Node: How do I track the byte offset for lseek()?209966 +Node: How do I use my own I/O classes in a C++ scanner?211523 +Node: How do I skip as many chars as possible?212386 +Node: deleteme00213461 +Node: Are certain equivalent patterns faster than others?213906 +Node: Is backing up a big deal?217394 +Node: Can I fake multi-byte character support?219365 +Node: deleteme01220841 +Node: Can you discuss some flex internals?221965 +Node: unput() messes up yy_at_bol224254 +Node: The | operator is not doing what I want225391 +Node: Why can't flex understand this variable trailing context pattern?226982 +Node: The ^ operator isn't working228246 +Node: Trailing context is getting confused with trailing optional patterns229516 +Node: Is flex GNU or not?230784 +Node: ERASEME53232497 +Node: I need to scan if-then-else blocks and while loops233292 +Node: ERASEME55234511 +Node: ERASEME56235624 +Node: ERASEME57237017 +Node: Is there a repository for flex scanners?238050 +Node: How can I conditionally compile or preprocess my flex input file?238366 +Node: Where can I find grammars for lex and yacc?238839 +Node: I get an end-of-buffer message for each character scanned.239186 +Node: unnamed-faq-62239781 +Node: unnamed-faq-63240829 +Node: unnamed-faq-64242141 +Node: unnamed-faq-65243142 +Node: unnamed-faq-66243943 +Node: unnamed-faq-67245073 +Node: unnamed-faq-68246075 +Node: unnamed-faq-69247232 +Node: unnamed-faq-70247965 +Node: unnamed-faq-71248741 +Node: unnamed-faq-72249970 +Node: unnamed-faq-73251038 +Node: unnamed-faq-74251982 +Node: unnamed-faq-75252952 +Node: unnamed-faq-76254124 +Node: unnamed-faq-77254845 +Node: unnamed-faq-78255753 +Node: unnamed-faq-79256766 +Node: unnamed-faq-80258501 +Node: unnamed-faq-81259844 +Node: unnamed-faq-82262684 +Node: unnamed-faq-83263666 +Node: unnamed-faq-84265471 +Node: unnamed-faq-85266589 +Node: unnamed-faq-86267636 +Node: unnamed-faq-87268609 +Node: unnamed-faq-88269270 +Node: unnamed-faq-90270126 +Node: unnamed-faq-91271424 +Node: unnamed-faq-92273907 +Node: unnamed-faq-93274421 +Node: unnamed-faq-94275363 +Node: unnamed-faq-95276805 +Node: unnamed-faq-96278338 +Node: unnamed-faq-97279122 +Node: unnamed-faq-98279804 +Node: unnamed-faq-99280494 +Node: unnamed-faq-100281453 +Node: unnamed-faq-101282178 +Node: What is the difference between YYLEX_PARAM and YY_DECL?283011 +Node: Why do I get "conflicting types for yylex" error?283535 +Node: How do I access the values set in a Flex action from within a Bison action?284065 +Node: Appendices284494 +Node: Makefiles and Flex284703 +Ref: Makefiles and Flex-Footnote-1288049 +Ref: Makefiles and Flex-Footnote-2288174 +Ref: Makefiles and Flex-Footnote-3288365 +Node: Bison Bridge288416 +Ref: Bison Bridge-Footnote-1291217 +Node: M4 Dependency291409 +Ref: M4 Dependency-Footnote-1292903 +Node: Common Patterns293039 +Node: Numbers293330 +Node: Identifiers294323 +Node: Quoted Constructs295154 +Node: Addresses296228 +Node: Indices297548 +Node: Concept Index297786 +Node: Index of Functions and Macros324917 +Node: Index of Variables329886 +Node: Index of Data Types331552 +Node: Index of Hooks332440 +Node: Index of Scanner Options333008  End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/local/recipes/dev/flex/source/doc/flex.info-1 b/local/recipes/dev/flex/source/doc/flex.info-1 index b79df5eda5..869bfa003e 100644 --- a/local/recipes/dev/flex/source/doc/flex.info-1 +++ b/local/recipes/dev/flex/source/doc/flex.info-1 @@ -1,12 +1,12 @@ -This is flex.info, produced by makeinfo version 6.1 from flex.texi. +This is flex.info, produced by makeinfo version 7.3 from flex.texi. The flex manual is placed under the same licensing conditions as the rest of flex: - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2012 The Flex + Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2012 The Flex Project. - Copyright (C) 1990, 1997 The Regents of the University of California. + Copyright © 1990, 1997 The Regents of the University of California. All rights reserved. This code is derived from software contributed to Berkeley by Vern @@ -46,215 +46,214 @@ File: flex.info, Node: Top, Next: Copyright, Prev: (dir), Up: (dir) flex **** -This manual describes 'flex', a tool for generating programs that +This manual describes ‘flex’, a tool for generating programs that perform pattern-matching on text. The manual includes both tutorial and reference sections. - This edition of 'The flex Manual' documents 'flex' version 2.6.4. It -was last updated on 6 May 2017. + This edition of ‘The flex Manual’ documents ‘flex’ version 2.6.4. It +was last updated on 15 May 2026. This manual was written by Vern Paxson, Will Estes and John Millaway. * Menu: -* Copyright:: -* Reporting Bugs:: -* Introduction:: -* Simple Examples:: -* Format:: -* Patterns:: -* Matching:: -* Actions:: -* Generated Scanner:: -* Start Conditions:: -* Multiple Input Buffers:: -* EOF:: -* Misc Macros:: -* User Values:: -* Yacc:: -* Scanner Options:: -* Performance:: -* Cxx:: -* Reentrant:: -* Lex and Posix:: -* Memory Management:: -* Serialized Tables:: -* Diagnostics:: -* Limitations:: -* Bibliography:: -* FAQ:: -* Appendices:: -* Indices:: +* Copyright:: +* Reporting Bugs:: +* Introduction:: +* Simple Examples:: +* Format:: +* Patterns:: +* Matching:: +* Actions:: +* Generated Scanner:: +* Start Conditions:: +* Multiple Input Buffers:: +* EOF:: +* Misc Macros:: +* User Values:: +* Yacc:: +* Scanner Options:: +* Performance:: +* Cxx:: +* Reentrant:: +* Lex and Posix:: +* Memory Management:: +* Serialized Tables:: +* Diagnostics:: +* Limitations:: +* Bibliography:: +* FAQ:: +* Appendices:: +* Indices:: -- The Detailed Node Listing -- Format of the Input File -* Definitions Section:: -* Rules Section:: -* User Code Section:: -* Comments in the Input:: +* Definitions Section:: +* Rules Section:: +* User Code Section:: +* Comments in the Input:: Scanner Options -* Options for Specifying Filenames:: -* Options Affecting Scanner Behavior:: -* Code-Level And API Options:: -* Options for Scanner Speed and Size:: -* Debugging Options:: -* Miscellaneous Options:: +* Options for Specifying Filenames:: +* Options Affecting Scanner Behavior:: +* Code-Level And API Options:: +* Options for Scanner Speed and Size:: +* Debugging Options:: +* Miscellaneous Options:: Reentrant C Scanners -* Reentrant Uses:: -* Reentrant Overview:: -* Reentrant Example:: -* Reentrant Detail:: -* Reentrant Functions:: +* Reentrant Uses:: +* Reentrant Overview:: +* Reentrant Example:: +* Reentrant Detail:: +* Reentrant Functions:: The Reentrant API in Detail -* Specify Reentrant:: -* Extra Reentrant Argument:: -* Global Replacement:: -* Init and Destroy Functions:: -* Accessor Methods:: -* Extra Data:: -* About yyscan_t:: +* Specify Reentrant:: +* Extra Reentrant Argument:: +* Global Replacement:: +* Init and Destroy Functions:: +* Accessor Methods:: +* Extra Data:: +* About yyscan_t:: Memory Management -* The Default Memory Management:: -* Overriding The Default Memory Management:: -* A Note About yytext And Memory:: +* The Default Memory Management:: +* Overriding The Default Memory Management:: +* A Note About yytext And Memory:: Serialized Tables -* Creating Serialized Tables:: -* Loading and Unloading Serialized Tables:: -* Tables File Format:: +* Creating Serialized Tables:: +* Loading and Unloading Serialized Tables:: +* Tables File Format:: FAQ -* When was flex born?:: -* How do I expand backslash-escape sequences in C-style quoted strings?:: -* Why do flex scanners call fileno if it is not ANSI compatible?:: -* Does flex support recursive pattern definitions?:: -* How do I skip huge chunks of input (tens of megabytes) while using flex?:: -* Flex is not matching my patterns in the same order that I defined them.:: -* My actions are executing out of order or sometimes not at all.:: -* How can I have multiple input sources feed into the same scanner at the same time?:: -* Can I build nested parsers that work with the same input file?:: -* How can I match text only at the end of a file?:: -* How can I make REJECT cascade across start condition boundaries?:: -* Why cant I use fast or full tables with interactive mode?:: -* How much faster is -F or -f than -C?:: -* If I have a simple grammar cant I just parse it with flex?:: -* Why doesn't yyrestart() set the start state back to INITIAL?:: -* How can I match C-style comments?:: -* The period isn't working the way I expected.:: -* Can I get the flex manual in another format?:: -* Does there exist a "faster" NDFA->DFA algorithm?:: -* How does flex compile the DFA so quickly?:: -* How can I use more than 8192 rules?:: -* How do I abandon a file in the middle of a scan and switch to a new file?:: -* How do I execute code only during initialization (only before the first scan)?:: -* How do I execute code at termination?:: -* Where else can I find help?:: -* Can I include comments in the "rules" section of the file?:: -* I get an error about undefined yywrap().:: -* How can I change the matching pattern at run time?:: -* How can I expand macros in the input?:: -* How can I build a two-pass scanner?:: -* How do I match any string not matched in the preceding rules?:: -* I am trying to port code from AT&T lex that uses yysptr and yysbuf.:: -* Is there a way to make flex treat NULL like a regular character?:: -* Whenever flex can not match the input it says "flex scanner jammed".:: -* Why doesn't flex have non-greedy operators like perl does?:: -* Memory leak - 16386 bytes allocated by malloc.:: -* How do I track the byte offset for lseek()?:: -* How do I use my own I/O classes in a C++ scanner?:: -* How do I skip as many chars as possible?:: -* deleteme00:: -* Are certain equivalent patterns faster than others?:: -* Is backing up a big deal?:: -* Can I fake multi-byte character support?:: -* deleteme01:: -* Can you discuss some flex internals?:: -* unput() messes up yy_at_bol:: -* The | operator is not doing what I want:: -* Why can't flex understand this variable trailing context pattern?:: -* The ^ operator isn't working:: -* Trailing context is getting confused with trailing optional patterns:: -* Is flex GNU or not?:: -* ERASEME53:: -* I need to scan if-then-else blocks and while loops:: -* ERASEME55:: -* ERASEME56:: -* ERASEME57:: -* Is there a repository for flex scanners?:: -* How can I conditionally compile or preprocess my flex input file?:: -* Where can I find grammars for lex and yacc?:: -* I get an end-of-buffer message for each character scanned.:: -* unnamed-faq-62:: -* unnamed-faq-63:: -* unnamed-faq-64:: -* unnamed-faq-65:: -* unnamed-faq-66:: -* unnamed-faq-67:: -* unnamed-faq-68:: -* unnamed-faq-69:: -* unnamed-faq-70:: -* unnamed-faq-71:: -* unnamed-faq-72:: -* unnamed-faq-73:: -* unnamed-faq-74:: -* unnamed-faq-75:: -* unnamed-faq-76:: -* unnamed-faq-77:: -* unnamed-faq-78:: -* unnamed-faq-79:: -* unnamed-faq-80:: -* unnamed-faq-81:: -* unnamed-faq-82:: -* unnamed-faq-83:: -* unnamed-faq-84:: -* unnamed-faq-85:: -* unnamed-faq-86:: -* unnamed-faq-87:: -* unnamed-faq-88:: -* unnamed-faq-90:: -* unnamed-faq-91:: -* unnamed-faq-92:: -* unnamed-faq-93:: -* unnamed-faq-94:: -* unnamed-faq-95:: -* unnamed-faq-96:: -* unnamed-faq-97:: -* unnamed-faq-98:: -* unnamed-faq-99:: -* unnamed-faq-100:: -* unnamed-faq-101:: +* When was flex born?:: +* How do I expand backslash-escape sequences in C-style quoted strings?:: +* Why do flex scanners call fileno if it is not ANSI compatible?:: +* Does flex support recursive pattern definitions?:: +* How do I skip huge chunks of input (tens of megabytes) while using flex?:: +* Flex is not matching my patterns in the same order that I defined them.:: +* My actions are executing out of order or sometimes not at all.:: +* How can I have multiple input sources feed into the same scanner at the same time?:: +* Can I build nested parsers that work with the same input file?:: +* How can I match text only at the end of a file?:: +* How can I make REJECT cascade across start condition boundaries?:: +* Why cant I use fast or full tables with interactive mode?:: +* How much faster is -F or -f than -C?:: +* If I have a simple grammar cant I just parse it with flex?:: +* Why doesn't yyrestart() set the start state back to INITIAL?:: +* How can I match C-style comments?:: +* The period isn't working the way I expected.:: +* Can I get the flex manual in another format?:: +* Does there exist a "faster" NDFA->DFA algorithm?:: +* How does flex compile the DFA so quickly?:: +* How can I use more than 8192 rules?:: +* How do I abandon a file in the middle of a scan and switch to a new file?:: +* How do I execute code only during initialization (only before the first scan)?:: +* How do I execute code at termination?:: +* Where else can I find help?:: +* Can I include comments in the "rules" section of the file?:: +* I get an error about undefined yywrap().:: +* How can I change the matching pattern at run time?:: +* How can I expand macros in the input?:: +* How can I build a two-pass scanner?:: +* How do I match any string not matched in the preceding rules?:: +* I am trying to port code from AT&T lex that uses yysptr and yysbuf.:: +* Is there a way to make flex treat NULL like a regular character?:: +* Whenever flex can not match the input it says "flex scanner jammed".:: +* Why doesn't flex have non-greedy operators like perl does?:: +* Memory leak - 16386 bytes allocated by malloc.:: +* How do I track the byte offset for lseek()?:: +* How do I use my own I/O classes in a C++ scanner?:: +* How do I skip as many chars as possible?:: +* deleteme00:: +* Are certain equivalent patterns faster than others?:: +* Is backing up a big deal?:: +* Can I fake multi-byte character support?:: +* deleteme01:: +* Can you discuss some flex internals?:: +* unput() messes up yy_at_bol:: +* The | operator is not doing what I want:: +* Why can't flex understand this variable trailing context pattern?:: +* The ^ operator isn't working:: +* Trailing context is getting confused with trailing optional patterns:: +* Is flex GNU or not?:: +* ERASEME53:: +* I need to scan if-then-else blocks and while loops:: +* ERASEME55:: +* ERASEME56:: +* ERASEME57:: +* Is there a repository for flex scanners?:: +* How can I conditionally compile or preprocess my flex input file?:: +* Where can I find grammars for lex and yacc?:: +* I get an end-of-buffer message for each character scanned.:: +* unnamed-faq-62:: +* unnamed-faq-63:: +* unnamed-faq-64:: +* unnamed-faq-65:: +* unnamed-faq-66:: +* unnamed-faq-67:: +* unnamed-faq-68:: +* unnamed-faq-69:: +* unnamed-faq-70:: +* unnamed-faq-71:: +* unnamed-faq-72:: +* unnamed-faq-73:: +* unnamed-faq-74:: +* unnamed-faq-75:: +* unnamed-faq-76:: +* unnamed-faq-77:: +* unnamed-faq-78:: +* unnamed-faq-79:: +* unnamed-faq-80:: +* unnamed-faq-81:: +* unnamed-faq-82:: +* unnamed-faq-83:: +* unnamed-faq-84:: +* unnamed-faq-85:: +* unnamed-faq-86:: +* unnamed-faq-87:: +* unnamed-faq-88:: +* unnamed-faq-90:: +* unnamed-faq-91:: +* unnamed-faq-92:: +* unnamed-faq-93:: +* unnamed-faq-94:: +* unnamed-faq-95:: +* unnamed-faq-96:: +* unnamed-faq-97:: +* unnamed-faq-98:: +* unnamed-faq-99:: +* unnamed-faq-100:: +* unnamed-faq-101:: * What is the difference between YYLEX_PARAM and YY_DECL?:: * Why do I get "conflicting types for yylex" error?:: * How do I access the values set in a Flex action from within a Bison action?:: Appendices -* Makefiles and Flex:: -* Bison Bridge:: -* M4 Dependency:: -* Common Patterns:: +* Makefiles and Flex:: +* Bison Bridge:: +* M4 Dependency:: +* Common Patterns:: Indices -* Concept Index:: -* Index of Functions and Macros:: -* Index of Variables:: -* Index of Data Types:: -* Index of Hooks:: -* Index of Scanner Options:: - +* Concept Index:: +* Index of Functions and Macros:: +* Index of Variables:: +* Index of Data Types:: +* Index of Hooks:: +* Index of Scanner Options::  File: flex.info, Node: Copyright, Next: Reporting Bugs, Prev: Top, Up: Top @@ -265,10 +264,10 @@ File: flex.info, Node: Copyright, Next: Reporting Bugs, Prev: Top, Up: Top The flex manual is placed under the same licensing conditions as the rest of flex: - Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2012 The Flex + Copyright © 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2012 The Flex Project. - Copyright (C) 1990, 1997 The Regents of the University of California. + Copyright © 1990, 1997 The Regents of the University of California. All rights reserved. This code is derived from software contributed to Berkeley by Vern @@ -304,7 +303,7 @@ File: flex.info, Node: Reporting Bugs, Next: Introduction, Prev: Copyright, 2 Reporting Bugs **************** -If you find a bug in 'flex', please report it using GitHub's issue +If you find a bug in ‘flex’, please report it using GitHub's issue tracking facility at  @@ -313,13 +312,13 @@ File: flex.info, Node: Introduction, Next: Simple Examples, Prev: Reporting B 3 Introduction ************** -'flex' is a tool for generating "scanners". A scanner is a program -which recognizes lexical patterns in text. The 'flex' program reads the +‘flex’ is a tool for generating “scanners”. A scanner is a program +which recognizes lexical patterns in text. The ‘flex’ program reads the given input files, or its standard input if no file names are given, for a description of a scanner to generate. The description is in the form -of pairs of regular expressions and C code, called "rules". 'flex' -generates as output a C source file, 'lex.yy.c' by default, which -defines a routine 'yylex()'. This file can be compiled and linked with +of pairs of regular expressions and C code, called “rules”. ‘flex’ +generates as output a C source file, ‘lex.yy.c’ by default, which +defines a routine ‘yylex()’. This file can be compiled and linked with the flex runtime library to produce an executable. When the executable is run, it analyzes its input for occurrences of the regular expressions. Whenever it finds one, it executes the corresponding C @@ -331,31 +330,31 @@ File: flex.info, Node: Simple Examples, Next: Format, Prev: Introduction, Up 4 Some Simple Examples ********************** -First some simple examples to get the flavor of how one uses 'flex'. +First some simple examples to get the flavor of how one uses ‘flex’. - The following 'flex' input specifies a scanner which, when it -encounters the string 'username' will replace it with the user's login + The following ‘flex’ input specifies a scanner which, when it +encounters the string ‘username’ will replace it with the user's login name: %% username printf( "%s", getlogin() ); - By default, any text not matched by a 'flex' scanner is copied to the + By default, any text not matched by a ‘flex’ scanner is copied to the output, so the net effect of this scanner is to copy its input file to -its output with each occurrence of 'username' expanded. In this input, -there is just one rule. 'username' is the "pattern" and the 'printf' is -the "action". The '%%' symbol marks the beginning of the rules. +its output with each occurrence of ‘username’ expanded. In this input, +there is just one rule. ‘username’ is the “pattern” and the ‘printf’ is +the “action”. The ‘%%’ symbol marks the beginning of the rules. Here's another simple example: int num_lines = 0, num_chars = 0; - + %% \n ++num_lines; ++num_chars; . ++num_chars; - + %% - + int main() { yylex(); @@ -366,52 +365,52 @@ the "action". The '%%' symbol marks the beginning of the rules. This scanner counts the number of characters and the number of lines in its input. It produces no output other than the final report on the character and line counts. The first line declares two globals, -'num_lines' and 'num_chars', which are accessible both inside 'yylex()' -and in the 'main()' routine declared after the second '%%'. There are -two rules, one which matches a newline ('\n') and increments both the +‘num_lines’ and ‘num_chars’, which are accessible both inside ‘yylex()’ +and in the ‘main()’ routine declared after the second ‘%%’. There are +two rules, one which matches a newline (‘\n’) and increments both the line count and the character count, and one which matches any character -other than a newline (indicated by the '.' regular expression). +other than a newline (indicated by the ‘.’ regular expression). A somewhat more complicated example: /* scanner for a toy Pascal-like language */ - + %{ /* need this for the call to atof() below */ #include %} - + DIGIT [0-9] ID [a-z][a-z0-9]* - + %% - + {DIGIT}+ { printf( "An integer: %s (%d)\n", yytext, atoi( yytext ) ); } - + {DIGIT}+"."{DIGIT}* { printf( "A float: %s (%g)\n", yytext, atof( yytext ) ); } - + if|then|begin|end|procedure|function { printf( "A keyword: %s\n", yytext ); } - + {ID} printf( "An identifier: %s\n", yytext ); - + "+"|"-"|"*"|"/" printf( "An operator: %s\n", yytext ); - + "{"[^{}\n]*"}" /* eat up one-line comments */ - + [ \t\n]+ /* eat up whitespace */ - + . printf( "Unrecognized character: %s\n", yytext ); - + %% - + int main( int argc, char **argv ) { ++argv, --argc; /* skip over program name */ @@ -419,12 +418,12 @@ other than a newline (indicated by the '.' regular expression). yyin = fopen( argv[0], "r" ); else yyin = stdin; - + yylex(); } This is the beginnings of a simple scanner for a language like -Pascal. It identifies different types of "tokens" and reports on what +Pascal. It identifies different types of “tokens” and reports on what it has seen. The details of this example will be explained in the following @@ -436,8 +435,8 @@ File: flex.info, Node: Format, Next: Patterns, Prev: Simple Examples, Up: To 5 Format of the Input File ************************** -The 'flex' input file consists of three sections, separated by a line -containing only '%%'. +The ‘flex’ input file consists of three sections, separated by a line +containing only ‘%%’. definitions %% @@ -447,10 +446,10 @@ containing only '%%'. * Menu: -* Definitions Section:: -* Rules Section:: -* User Code Section:: -* Comments in the Input:: +* Definitions Section:: +* Rules Section:: +* User Code Section:: +* Comments in the Input::  File: flex.info, Node: Definitions Section, Next: Rules Section, Prev: Format, Up: Format @@ -458,26 +457,26 @@ File: flex.info, Node: Definitions Section, Next: Rules Section, Prev: Format 5.1 Format of the Definitions Section ===================================== -The "definitions section" contains declarations of simple "name" +The “definitions section” contains declarations of simple “name” definitions to simplify the scanner specification, and declarations of -"start conditions", which are explained in a later section. +“start conditions”, which are explained in a later section. Name definitions have the form: name definition - The 'name' is a word beginning with a letter or an underscore ('_') -followed by zero or more letters, digits, '_', or '-' (dash). The + The ‘name’ is a word beginning with a letter or an underscore (‘_’) +followed by zero or more letters, digits, ‘_’, or ‘-’ (dash). The definition is taken to begin at the first non-whitespace character following the name and continuing to the end of the line. The -definition can subsequently be referred to using '{name}', which will -expand to '(definition)'. For example, +definition can subsequently be referred to using ‘{name}’, which will +expand to ‘(definition)’. For example, DIGIT [0-9] ID [a-z][a-z0-9]* - Defines 'DIGIT' to be a regular expression which matches a single -digit, and 'ID' to be a regular expression which matches a letter + Defines ‘DIGIT’ to be a regular expression which matches a single +digit, and ‘ID’ to be a regular expression which matches a letter followed by zero-or-more letters-or-digits. A subsequent reference to {DIGIT}+"."{DIGIT}* @@ -486,22 +485,22 @@ followed by zero-or-more letters-or-digits. A subsequent reference to ([0-9])+"."([0-9])* - and matches one-or-more digits followed by a '.' followed by + and matches one-or-more digits followed by a ‘.’ followed by zero-or-more digits. - An unindented comment (i.e., a line beginning with '/*') is copied -verbatim to the output up to the next '*/'. + An unindented comment (i.e., a line beginning with ‘/*’) is copied +verbatim to the output up to the next ‘*/’. - Any _indented_ text or text enclosed in '%{' and '%}' is also copied + Any _indented_ text or text enclosed in ‘%{’ and ‘%}’ is also copied verbatim to the output (with the %{ and %} symbols removed). The %{ and %} symbols must appear unindented on lines by themselves. - A '%top' block is similar to a '%{' ... '%}' block, except that the -code in a '%top' block is relocated to the _top_ of the generated file, -before any flex definitions (1). The '%top' block is useful when you + A ‘%top’ block is similar to a ‘%{’ ... ‘%}’ block, except that the +code in a ‘%top’ block is relocated to the _top_ of the generated file, +before any flex definitions (1). The ‘%top’ block is useful when you want certain preprocessor macros to be defined or certain files to be -included before the generated code. The single characters, '{' and '}' -are used to delimit the '%top' block, as show in the example below: +included before the generated code. The single characters, ‘{’ and ‘}’ +are used to delimit the ‘%top’ block, as show in the example below: %top{ /* This code goes at the "top" of the generated file. */ @@ -509,11 +508,11 @@ are used to delimit the '%top' block, as show in the example below: #include } - Multiple '%top' blocks are allowed, and their order is preserved. + Multiple ‘%top’ blocks are allowed, and their order is preserved. ---------- Footnotes ---------- - (1) Actually, 'yyIN_HEADER' is defined before the '%top' block. + (1) Actually, ‘yyIN_HEADER’ is defined before the ‘%top’ block.  File: flex.info, Node: Rules Section, Next: User Code Section, Prev: Definitions Section, Up: Format @@ -521,7 +520,7 @@ File: flex.info, Node: Rules Section, Next: User Code Section, Prev: Definiti 5.2 Format of the Rules Section =============================== -The "rules" section of the 'flex' input contains a series of rules of +The “rules” section of the ‘flex’ input contains a series of rules of the form: pattern action @@ -539,7 +538,7 @@ meaning is not well-defined and it may well cause compile-time errors (this feature is present for POSIX compliance. *Note Lex and Posix::, for other such features). - Any _indented_ text or text enclosed in '%{' and '%}' is copied + Any _indented_ text or text enclosed in ‘%{’ and ‘%}’ is copied verbatim to the output (with the %{ and %} symbols removed). The %{ and %} symbols must appear unindented on lines by themselves. @@ -549,10 +548,10 @@ File: flex.info, Node: User Code Section, Next: Comments in the Input, Prev: 5.3 Format of the User Code Section =================================== -The user code section is simply copied to 'lex.yy.c' verbatim. It is +The user code section is simply copied to ‘lex.yy.c’ verbatim. It is used for companion routines which call or are called by the scanner. The presence of this section is optional; if it is missing, the second -'%%' in the input file may be skipped, too. +‘%%’ in the input file may be skipped, too.  File: flex.info, Node: Comments in the Input, Prev: User Code Section, Up: Format @@ -560,31 +559,31 @@ File: flex.info, Node: Comments in the Input, Prev: User Code Section, Up: Fo 5.4 Comments in the Input ========================= -Flex supports C-style comments, that is, anything between '/*' and '*/' +Flex supports C-style comments, that is, anything between ‘/*’ and ‘*/’ is considered a comment. Whenever flex encounters a comment, it copies the entire comment verbatim to the generated source code. Comments may appear just about anywhere, but with the following exceptions: - * Comments may not appear in the Rules Section wherever flex is + • Comments may not appear in the Rules Section wherever flex is expecting a regular expression. This means comments may not appear at the beginning of a line, or immediately following a list of scanner states. - * Comments may not appear on an '%option' line in the Definitions + • Comments may not appear on an ‘%option’ line in the Definitions Section. If you want to follow a simple rule, then always begin a comment on a new line, with one or more whitespace characters before the initial -'/*'). This rule will work anywhere in the input file. +‘/*’). This rule will work anywhere in the input file. All the comments in the following example are valid: %{ /* code block */ %} - + /* Definitions Section */ %x STATE_X - + %% /* Rules Section */ ruleA /* after regex */ { /* code block */ } /* after code block */ @@ -598,7 +597,7 @@ new line, with one or more whitespace characters before the initial } %% /* User Code Section */ - +  File: flex.info, Node: Patterns, Next: Matching, Prev: Format, Up: Top @@ -609,84 +608,84 @@ File: flex.info, Node: Patterns, Next: Matching, Prev: Format, Up: Top The patterns in the input (see *note Rules Section::) are written using an extended set of regular expressions. These are: -'x' +‘x’ match the character 'x' -'.' +‘.’ any character (byte) except newline -'[xyz]' - a "character class"; in this case, the pattern matches either an +‘[xyz]’ + a “character class”; in this case, the pattern matches either an 'x', a 'y', or a 'z' -'[abj-oZ]' +‘[abj-oZ]’ a "character class" with a range in it; matches an 'a', a 'b', any letter from 'j' through 'o', or a 'Z' -'[^A-Z]' +‘[^A-Z]’ a "negated character class", i.e., any character but those in the class. In this case, any character EXCEPT an uppercase letter. -'[^A-Z\n]' +‘[^A-Z\n]’ any character EXCEPT an uppercase letter or a newline -'[a-z]{-}[aeiou]' +‘[a-z]{-}[aeiou]’ the lowercase consonants -'r*' +‘r*’ zero or more r's, where r is any regular expression -'r+' +‘r+’ one or more r's -'r?' +‘r?’ zero or one r's (that is, "an optional r") -'r{2,5}' +‘r{2,5}’ anywhere from two to five r's -'r{2,}' +‘r{2,}’ two or more r's -'r{4}' +‘r{4}’ exactly 4 r's -'{name}' - the expansion of the 'name' definition (*note Format::). +‘{name}’ + the expansion of the ‘name’ definition (*note Format::). -'"[xyz]\"foo"' - the literal string: '[xyz]"foo' +‘"[xyz]\"foo"’ + the literal string: ‘[xyz]"foo’ -'\X' - if X is 'a', 'b', 'f', 'n', 'r', 't', or 'v', then the ANSI-C - interpretation of '\x'. Otherwise, a literal 'X' (used to escape - operators such as '*') +‘\X’ + if X is ‘a’, ‘b’, ‘f’, ‘n’, ‘r’, ‘t’, or ‘v’, then the ANSI-C + interpretation of ‘\x’. Otherwise, a literal ‘X’ (used to escape + operators such as ‘*’) -'\0' +‘\0’ a NUL character (ASCII code 0) -'\123' +‘\123’ the character with octal value 123 -'\x2a' +‘\x2a’ the character with hexadecimal value 2a -'(r)' - match an 'r'; parentheses are used to override precedence (see +‘(r)’ + match an ‘r’; parentheses are used to override precedence (see below) -'(?r-s:pattern)' - apply option 'r' and omit option 's' while interpreting pattern. - Options may be zero or more of the characters 'i', 's', or 'x'. +‘(?r-s:pattern)’ + apply option ‘r’ and omit option ‘s’ while interpreting pattern. + Options may be zero or more of the characters ‘i’, ‘s’, or ‘x’. - 'i' means case-insensitive. '-i' means case-sensitive. + ‘i’ means case-insensitive. ‘-i’ means case-sensitive. - 's' alters the meaning of the '.' syntax to match any single byte - whatsoever. '-s' alters the meaning of '.' to match any byte - except '\n'. + ‘s’ alters the meaning of the ‘.’ syntax to match any single byte + whatsoever. ‘-s’ alters the meaning of ‘.’ to match any byte + except ‘\n’. - 'x' ignores comments and whitespace in patterns. Whitespace is - ignored unless it is backslash-escaped, contained within '""'s, or + ‘x’ ignores comments and whitespace in patterns. Whitespace is + ignored unless it is backslash-escaped, contained within ‘""’s, or appears inside a character class. The following are all valid: @@ -706,66 +705,66 @@ an extended set of regular expressions. These are: b c) same as (abc) -'(?# comment )' - omit everything within '()'. The first ')' character encountered +‘(?# comment )’ + omit everything within ‘()’. The first ‘)’ character encountered ends the pattern. It is not possible to for the comment to contain - a ')' character. The comment may span lines. + a ‘)’ character. The comment may span lines. -'rs' - the regular expression 'r' followed by the regular expression 's'; - called "concatenation" +‘rs’ + the regular expression ‘r’ followed by the regular expression ‘s’; + called “concatenation” -'r|s' - either an 'r' or an 's' +‘r|s’ + either an ‘r’ or an ‘s’ -'r/s' - an 'r' but only if it is followed by an 's'. The text matched by - 's' is included when determining whether this rule is the longest +‘r/s’ + an ‘r’ but only if it is followed by an ‘s’. The text matched by + ‘s’ is included when determining whether this rule is the longest match, but is then returned to the input before the action is - executed. So the action only sees the text matched by 'r'. This - type of pattern is called "trailing context". (There are some - combinations of 'r/s' that flex cannot match correctly. *Note + executed. So the action only sees the text matched by ‘r’. This + type of pattern is called “trailing context”. (There are some + combinations of ‘r/s’ that flex cannot match correctly. *Note Limitations::, regarding dangerous trailing context.) -'^r' - an 'r', but only at the beginning of a line (i.e., when just +‘^r’ + an ‘r’, but only at the beginning of a line (i.e., when just starting to scan, or right after a newline has been scanned). -'r$' - an 'r', but only at the end of a line (i.e., just before a - newline). Equivalent to 'r/\n'. +‘r$’ + an ‘r’, but only at the end of a line (i.e., just before a + newline). Equivalent to ‘r/\n’. - Note that 'flex''s notion of "newline" is exactly whatever the C - compiler used to compile 'flex' interprets '\n' as; in particular, - on some DOS systems you must either filter out '\r's in the input - yourself, or explicitly use 'r/\r\n' for 'r$'. + Note that ‘flex’'s notion of "newline" is exactly whatever the C + compiler used to compile ‘flex’ interprets ‘\n’ as; in particular, + on some DOS systems you must either filter out ‘\r’s in the input + yourself, or explicitly use ‘r/\r\n’ for ‘r$’. -'r' - an 'r', but only in start condition 's' (see *note Start +‘r’ + an ‘r’, but only in start condition ‘s’ (see *note Start Conditions:: for discussion of start conditions). -'r' - same, but in any of start conditions 's1', 's2', or 's3'. +‘r’ + same, but in any of start conditions ‘s1’, ‘s2’, or ‘s3’. -'<*>r' - an 'r' in any start condition, even an exclusive one. +‘<*>r’ + an ‘r’ in any start condition, even an exclusive one. -'<>' +‘<>’ an end-of-file. -'<>' - an end-of-file when in start condition 's1' or 's2' +‘<>’ + an end-of-file when in start condition ‘s1’ or ‘s2’ Note that inside of a character class, all regular expression -operators lose their special meaning except escape ('\') and the -character class operators, '-', ']]', and, at the beginning of the -class, '^'. +operators lose their special meaning except escape (‘\’) and the +character class operators, ‘-’, ‘]]’, and, at the beginning of the +class, ‘^’. The regular expressions listed above are grouped according to precedence, from highest precedence at the top to lowest at the bottom. Those grouped together have equal precedence (see special note on the -precedence of the repeat operator, '{}', under the documentation for the -'--posix' POSIX compliance option). For example, +precedence of the repeat operator, ‘{}’, under the documentation for the +‘--posix’ POSIX compliance option). For example, foo|bar* @@ -773,23 +772,23 @@ precedence of the repeat operator, '{}', under the documentation for the (foo)|(ba(r*)) - since the '*' operator has higher precedence than concatenation, and -concatenation higher than alternation ('|'). This pattern therefore -matches _either_ the string 'foo' _or_ the string 'ba' followed by -zero-or-more 'r''s. To match 'foo' or zero-or-more repetitions of the -string 'bar', use: + since the ‘*’ operator has higher precedence than concatenation, and +concatenation higher than alternation (‘|’). This pattern therefore +matches _either_ the string ‘foo’ _or_ the string ‘ba’ followed by +zero-or-more ‘r’'s. To match ‘foo’ or zero-or-more repetitions of the +string ‘bar’, use: foo|(bar)* - And to match a sequence of zero or more repetitions of 'foo' and -'bar': + And to match a sequence of zero or more repetitions of ‘foo’ and +‘bar’: (foo|bar)* In addition to characters and ranges of characters, character classes -can also contain "character class expressions". These are expressions -enclosed inside '[:' and ':]' delimiters (which themselves must appear -between the '[' and ']' of the character class. Other elements may +can also contain “character class expressions”. These are expressions +enclosed inside ‘[:’ and ‘:]’ delimiters (which themselves must appear +between the ‘[’ and ‘]’ of the character class. Other elements may occur inside the character class, too). The valid expressions are: [:alnum:] [:alpha:] [:blank:] @@ -798,10 +797,10 @@ occur inside the character class, too). The valid expressions are: [:space:] [:upper:] [:xdigit:] These expressions all designate a set of characters equivalent to the -corresponding standard C 'isXXX' function. For example, '[:alnum:]' -designates those characters for which 'isalnum()' returns true - i.e., +corresponding standard C ‘isXXX’ function. For example, ‘[:alnum:]’ +designates those characters for which ‘isalnum()’ returns true - i.e., any alphabetic or numeric character. Some systems don't provide -'isblank()', so flex defines '[:blank:]' as a blank or a tab. +‘isblank()’, so flex defines ‘[:blank:]’ as a blank or a tab. For example, the following character classes are all equivalent: @@ -811,100 +810,100 @@ any alphabetic or numeric character. Some systems don't provide [a-zA-Z0-9] A word of caution. Character classes are expanded immediately when -seen in the 'flex' input. This means the character classes are -sensitive to the locale in which 'flex' is executed, and the resulting +seen in the ‘flex’ input. This means the character classes are +sensitive to the locale in which ‘flex’ is executed, and the resulting scanner will not be sensitive to the runtime locale. This may or may not be desirable. - * If your scanner is case-insensitive (the '-i' flag), then - '[:upper:]' and '[:lower:]' are equivalent to '[:alpha:]'. + • If your scanner is case-insensitive (the ‘-i’ flag), then + ‘[:upper:]’ and ‘[:lower:]’ are equivalent to ‘[:alpha:]’. - * Character classes with ranges, such as '[a-Z]', should be used with + • Character classes with ranges, such as ‘[a-Z]’, should be used with caution in a case-insensitive scanner if the range spans upper or lowercase characters. Flex does not know if you want to fold all upper and lowercase characters together, or if you want the literal numeric range specified (with no case folding). When in doubt, flex will assume that you meant the literal numeric range, and will issue a warning. The exception to this rule is a character range - such as '[a-z]' or '[S-W]' where it is obvious that you want - case-folding to occur. Here are some examples with the '-i' flag + such as ‘[a-z]’ or ‘[S-W]’ where it is obvious that you want + case-folding to occur. Here are some examples with the ‘-i’ flag enabled: Range Result Literal Range Alternate Range - '[a-t]' ok '[a-tA-T]' - '[A-T]' ok '[a-tA-T]' - '[A-t]' ambiguous '[A-Z\[\\\]_`a-t]' '[a-tA-T]' - '[_-{]' ambiguous '[_`a-z{]' '[_`a-zA-Z{]' - '[@-C]' ambiguous '[@ABC]' '[@A-Z\[\\\]_`abc]' + ‘[a-t]’ ok ‘[a-tA-T]’ + ‘[A-T]’ ok ‘[a-tA-T]’ + ‘[A-t]’ ambiguous ‘[A-Z\[\\\]_`a-t]’ ‘[a-tA-T]’ + ‘[_-{]’ ambiguous ‘[_`a-z{]’ ‘[_`a-zA-Z{]’ + ‘[@-C]’ ambiguous ‘[@ABC]’ ‘[@A-Z\[\\\]_`abc]’ - * A negated character class such as the example '[^A-Z]' above _will_ - match a newline unless '\n' (or an equivalent escape sequence) is + • A negated character class such as the example ‘[^A-Z]’ above _will_ + match a newline unless ‘\n’ (or an equivalent escape sequence) is one of the characters explicitly present in the negated character - class (e.g., '[^A-Z\n]'). This is unlike how many other regular + class (e.g., ‘[^A-Z\n]’). This is unlike how many other regular expression tools treat negated character classes, but unfortunately the inconsistency is historically entrenched. Matching newlines - means that a pattern like '[^"]*' can match the entire input unless + means that a pattern like ‘[^"]*’ can match the entire input unless there's another quote in the input. Flex allows negation of character class expressions by prepending - '^' to the POSIX character class name. + ‘^’ to the POSIX character class name. [:^alnum:] [:^alpha:] [:^blank:] [:^cntrl:] [:^digit:] [:^graph:] [:^lower:] [:^print:] [:^punct:] [:^space:] [:^upper:] [:^xdigit:] - Flex will issue a warning if the expressions '[:^upper:]' and - '[:^lower:]' appear in a case-insensitive scanner, since their + Flex will issue a warning if the expressions ‘[:^upper:]’ and + ‘[:^lower:]’ appear in a case-insensitive scanner, since their meaning is unclear. The current behavior is to skip them entirely, but this may change without notice in future revisions of flex. - * - The '{-}' operator computes the difference of two character - classes. For example, '[a-c]{-}[b-z]' represents all the - characters in the class '[a-c]' that are not in the class '[b-z]' - (which in this case, is just the single character 'a'). The '{-}' - operator is left associative, so '[abc]{-}[b]{-}[c]' is the same as - '[a]'. Be careful not to accidentally create an empty set, which + • + The ‘{-}’ operator computes the difference of two character + classes. For example, ‘[a-c]{-}[b-z]’ represents all the + characters in the class ‘[a-c]’ that are not in the class ‘[b-z]’ + (which in this case, is just the single character ‘a’). The ‘{-}’ + operator is left associative, so ‘[abc]{-}[b]{-}[c]’ is the same as + ‘[a]’. Be careful not to accidentally create an empty set, which will never match. - * - The '{+}' operator computes the union of two character classes. - For example, '[a-z]{+}[0-9]' is the same as '[a-z0-9]'. This + • + The ‘{+}’ operator computes the union of two character classes. + For example, ‘[a-z]{+}[0-9]’ is the same as ‘[a-z0-9]’. This operator is useful when preceded by the result of a difference - operation, as in, '[[:alpha:]]{-}[[:lower:]]{+}[q]', which is - equivalent to '[A-Zq]' in the "C" locale. + operation, as in, ‘[[:alpha:]]{-}[[:lower:]]{+}[q]’, which is + equivalent to ‘[A-Zq]’ in the "C" locale. - * A rule can have at most one instance of trailing context (the '/' - operator or the '$' operator). The start condition, '^', and - '<>' patterns can only occur at the beginning of a pattern, - and, as well as with '/' and '$', cannot be grouped inside - parentheses. A '^' which does not occur at the beginning of a rule - or a '$' which does not occur at the end of a rule loses its + • A rule can have at most one instance of trailing context (the ‘/’ + operator or the ‘$’ operator). The start condition, ‘^’, and + ‘<>’ patterns can only occur at the beginning of a pattern, + and, as well as with ‘/’ and ‘$’, cannot be grouped inside + parentheses. A ‘^’ which does not occur at the beginning of a rule + or a ‘$’ which does not occur at the end of a rule loses its special properties and is treated as a normal character. - * The following are invalid: + • The following are invalid: foo/bar$ foobar - Note that the first of these can be written 'foo/bar\n'. + Note that the first of these can be written ‘foo/bar\n’. - * The following will result in '$' or '^' being treated as a normal + • The following will result in ‘$’ or ‘^’ being treated as a normal character: foo|(bar$) foo|^bar - If the desired meaning is a 'foo' or a 'bar'-followed-by-a-newline, - the following could be used (the special '|' action is explained + If the desired meaning is a ‘foo’ or a ‘bar’-followed-by-a-newline, + the following could be used (the special ‘|’ action is explained below, *note Actions::): foo | bar$ /* action goes here */ - A similar trick will work for matching a 'foo' or a - 'bar'-at-the-beginning-of-a-line. + A similar trick will work for matching a ‘foo’ or a + ‘bar’-at-the-beginning-of-a-line.  File: flex.info, Node: Matching, Next: Actions, Prev: Patterns, Up: Top @@ -917,61 +916,61 @@ strings which match any of its patterns. If it finds more than one match, it takes the one matching the most text (for trailing context rules, this includes the length of the trailing part, even though it will then be returned to the input). If it finds two or more matches of -the same length, the rule listed first in the 'flex' input file is +the same length, the rule listed first in the ‘flex’ input file is chosen. Once the match is determined, the text corresponding to the match -(called the "token") is made available in the global character pointer -'yytext', and its length in the global integer 'yyleng'. The "action" +(called the “token”) is made available in the global character pointer +‘yytext’, and its length in the global integer ‘yyleng’. The “action” corresponding to the matched pattern is then executed (*note Actions::), and then the remaining input is scanned for another match. - If no match is found, then the "default rule" is executed: the next + If no match is found, then the “default rule” is executed: the next character in the input is considered matched and copied to the standard -output. Thus, the simplest valid 'flex' input is: +output. Thus, the simplest valid ‘flex’ input is: %% which generates a scanner that simply copies its input (one character at a time) to its output. - Note that 'yytext' can be defined in two different ways: either as a + Note that ‘yytext’ can be defined in two different ways: either as a character _pointer_ or as a character _array_. You can control which -definition 'flex' uses by including one of the special directives -'%pointer' or '%array' in the first (definitions) section of your flex -input. The default is '%pointer', unless you use the '-l' lex -compatibility option, in which case 'yytext' will be an array. The -advantage of using '%pointer' is substantially faster scanning and no +definition ‘flex’ uses by including one of the special directives +‘%pointer’ or ‘%array’ in the first (definitions) section of your flex +input. The default is ‘%pointer’, unless you use the ‘-l’ lex +compatibility option, in which case ‘yytext’ will be an array. The +advantage of using ‘%pointer’ is substantially faster scanning and no buffer overflow when matching very large tokens (unless you run out of dynamic memory). The disadvantage is that you are restricted in how -your actions can modify 'yytext' (*note Actions::), and calls to the -'unput()' function destroys the present contents of 'yytext', which can -be a considerable porting headache when moving between different 'lex' +your actions can modify ‘yytext’ (*note Actions::), and calls to the +‘unput()’ function destroys the present contents of ‘yytext’, which can +be a considerable porting headache when moving between different ‘lex’ versions. - The advantage of '%array' is that you can then modify 'yytext' to -your heart's content, and calls to 'unput()' do not destroy 'yytext' -(*note Actions::). Furthermore, existing 'lex' programs sometimes -access 'yytext' externally using declarations of the form: + The advantage of ‘%array’ is that you can then modify ‘yytext’ to +your heart's content, and calls to ‘unput()’ do not destroy ‘yytext’ +(*note Actions::). Furthermore, existing ‘lex’ programs sometimes +access ‘yytext’ externally using declarations of the form: extern char yytext[]; - This definition is erroneous when used with '%pointer', but correct -for '%array'. + This definition is erroneous when used with ‘%pointer’, but correct +for ‘%array’. - The '%array' declaration defines 'yytext' to be an array of 'YYLMAX' + The ‘%array’ declaration defines ‘yytext’ to be an array of ‘YYLMAX’ characters, which defaults to a fairly large value. You can change the -size by simply #define'ing 'YYLMAX' to a different value in the first -section of your 'flex' input. As mentioned above, with '%pointer' +size by simply #define'ing ‘YYLMAX’ to a different value in the first +section of your ‘flex’ input. As mentioned above, with ‘%pointer’ yytext grows dynamically to accommodate large tokens. While this means -your '%pointer' scanner can accommodate very large tokens (such as +your ‘%pointer’ scanner can accommodate very large tokens (such as matching entire blocks of comments), bear in mind that each time the -scanner must resize 'yytext' it also must rescan the entire token from -the beginning, so matching such tokens can prove slow. 'yytext' -presently does _not_ dynamically grow if a call to 'unput()' results in +scanner must resize ‘yytext’ it also must rescan the entire token from +the beginning, so matching such tokens can prove slow. ‘yytext’ +presently does _not_ dynamically grow if a call to ‘unput()’ results in too much text being pushed back; instead, a run-time error results. - Also note that you cannot use '%array' with C++ scanner classes + Also note that you cannot use ‘%array’ with C++ scanner classes (*note Cxx::).  @@ -980,12 +979,12 @@ File: flex.info, Node: Actions, Next: Generated Scanner, Prev: Matching, Up: 8 Actions ********* -Each pattern in a rule has a corresponding "action", which can be any +Each pattern in a rule has a corresponding “action”, which can be any arbitrary C statement. The pattern ends at the first non-escaped whitespace character; the remainder of the line is its action. If the action is empty, then when the pattern is matched the input token is simply discarded. For example, here is the specification for a program -which deletes all occurrences of 'zap me' from its input: +which deletes all occurrences of ‘zap me’ from its input: %% "zap me" @@ -1000,62 +999,62 @@ single blank, and throws away whitespace found at the end of a line: [ \t]+ putchar( ' ' ); [ \t]+$ /* ignore this token */ - If the action contains a '{', then the action spans till the -balancing '}' is found, and the action may cross multiple lines. 'flex' + If the action contains a ‘{’, then the action spans till the +balancing ‘}’ is found, and the action may cross multiple lines. ‘flex’ knows about C strings and comments and won't be fooled by braces found -within them, but also allows actions to begin with '%{' and will -consider the action to be all the text up to the next '%}' (regardless +within them, but also allows actions to begin with ‘%{’ and will +consider the action to be all the text up to the next ‘%}’ (regardless of ordinary braces inside the action). - An action consisting solely of a vertical bar ('|') means "same as + An action consisting solely of a vertical bar (‘|’) means "same as the action for the next rule". See below for an illustration. - Actions can include arbitrary C code, including 'return' statements -to return a value to whatever routine called 'yylex()'. Each time -'yylex()' is called it continues processing tokens from where it last + Actions can include arbitrary C code, including ‘return’ statements +to return a value to whatever routine called ‘yylex()’. Each time +‘yylex()’ is called it continues processing tokens from where it last left off until it either reaches the end of the file or executes a return. - Actions are free to modify 'yytext' except for lengthening it (adding + Actions are free to modify ‘yytext’ except for lengthening it (adding characters to its end-these will overwrite later characters in the input -stream). This however does not apply when using '%array' (*note -Matching::). In that case, 'yytext' may be freely modified in any way. +stream). This however does not apply when using ‘%array’ (*note +Matching::). In that case, ‘yytext’ may be freely modified in any way. - Actions are free to modify 'yyleng' except they should not do so if -the action also includes use of 'yymore()' (see below). + Actions are free to modify ‘yyleng’ except they should not do so if +the action also includes use of ‘yymore()’ (see below). There are a number of special directives which can be included within an action: -'ECHO' +‘ECHO’ copies yytext to the scanner's output. -'BEGIN' +‘BEGIN’ followed by the name of a start condition places the scanner in the corresponding start condition (see below). -'REJECT' +‘REJECT’ directs the scanner to proceed on to the "second best" rule which matched the input (or a prefix of the input). The rule is chosen - as described above in *note Matching::, and 'yytext' and 'yyleng' + as described above in *note Matching::, and ‘yytext’ and ‘yyleng’ set up appropriately. It may either be one which matched as much - text as the originally chosen rule but came later in the 'flex' + text as the originally chosen rule but came later in the ‘flex’ input file, or one which matched less text. For example, the following will both count the words in the input and call the - routine 'special()' whenever 'frob' is seen: + routine ‘special()’ whenever ‘frob’ is seen: int word_count = 0; %% - + frob special(); REJECT; [^ \t\n]+ ++word_count; - Without the 'REJECT', any occurrences of 'frob' in the input would + Without the ‘REJECT’, any occurrences of ‘frob’ in the input would not be counted as words, since the scanner normally executes only - one action per token. Multiple uses of 'REJECT' are allowed, each + one action per token. Multiple uses of ‘REJECT’ are allowed, each one finding the next best choice to the currently active rule. For - example, when the following scanner scans the token 'abcd', it will - write 'abcdabcaba' to the output: + example, when the following scanner scans the token ‘abcd’, it will + write ‘abcdabcaba’ to the output: %% a | @@ -1065,59 +1064,59 @@ an action: .|\n /* eat up any unmatched character */ The first three rules share the fourth's action since they use the - special '|' action. + special ‘|’ action. - 'REJECT' is a particularly expensive feature in terms of scanner + ‘REJECT’ is a particularly expensive feature in terms of scanner performance; if it is used in _any_ of the scanner's actions it will slow down _all_ of the scanner's matching. Furthermore, - 'REJECT' cannot be used with the '-Cf' or '-CF' options (*note + ‘REJECT’ cannot be used with the ‘-Cf’ or ‘-CF’ options (*note Scanner Options::). - Note also that unlike the other special actions, 'REJECT' is a + Note also that unlike the other special actions, ‘REJECT’ is a _branch_. Code immediately following it in the action will _not_ be executed. -'yymore()' +‘yymore()’ tells the scanner that the next time it matches a rule, the corresponding token should be _appended_ onto the current value of - 'yytext' rather than replacing it. For example, given the input - 'mega-kludge' the following will write 'mega-mega-kludge' to the + ‘yytext’ rather than replacing it. For example, given the input + ‘mega-kludge’ the following will write ‘mega-mega-kludge’ to the output: %% mega- ECHO; yymore(); kludge ECHO; - First 'mega-' is matched and echoed to the output. Then 'kludge' - is matched, but the previous 'mega-' is still hanging around at the - beginning of 'yytext' so the 'ECHO' for the 'kludge' rule will - actually write 'mega-kludge'. + First ‘mega-’ is matched and echoed to the output. Then ‘kludge’ + is matched, but the previous ‘mega-’ is still hanging around at the + beginning of ‘yytext’ so the ‘ECHO’ for the ‘kludge’ rule will + actually write ‘mega-kludge’. - Two notes regarding use of 'yymore()'. First, 'yymore()' depends on -the value of 'yyleng' correctly reflecting the size of the current -token, so you must not modify 'yyleng' if you are using 'yymore()'. -Second, the presence of 'yymore()' in the scanner's action entails a + Two notes regarding use of ‘yymore()’. First, ‘yymore()’ depends on +the value of ‘yyleng’ correctly reflecting the size of the current +token, so you must not modify ‘yyleng’ if you are using ‘yymore()’. +Second, the presence of ‘yymore()’ in the scanner's action entails a minor performance penalty in the scanner's matching speed. - 'yyless(n)' returns all but the first 'n' characters of the current + ‘yyless(n)’ returns all but the first ‘n’ characters of the current token back to the input stream, where they will be rescanned when the -scanner looks for the next match. 'yytext' and 'yyleng' are adjusted -appropriately (e.g., 'yyleng' will now be equal to 'n'). For example, -on the input 'foobar' the following will write out 'foobarbar': +scanner looks for the next match. ‘yytext’ and ‘yyleng’ are adjusted +appropriately (e.g., ‘yyleng’ will now be equal to ‘n’). For example, +on the input ‘foobar’ the following will write out ‘foobarbar’: %% foobar ECHO; yyless(3); [a-z]+ ECHO; - An argument of 0 to 'yyless()' will cause the entire current input + An argument of 0 to ‘yyless()’ will cause the entire current input string to be scanned again. Unless you've changed how the scanner will -subsequently process its input (using 'BEGIN', for example), this will +subsequently process its input (using ‘BEGIN’, for example), this will result in an endless loop. - Note that 'yyless()' is a macro and can only be used in the flex + Note that ‘yyless()’ is a macro and can only be used in the flex input file, not from other source files. - 'unput(c)' puts the character 'c' back onto the input stream. It + ‘unput(c)’ puts the character ‘c’ back onto the input stream. It will be the next character scanned. The following action will take the current token and cause it to be rescanned enclosed in parentheses. @@ -1132,34 +1131,34 @@ current token and cause it to be rescanned enclosed in parentheses. free( yycopy ); } - Note that since each 'unput()' puts the given character back at the + Note that since each ‘unput()’ puts the given character back at the _beginning_ of the input stream, pushing back strings must be done back-to-front. - An important potential problem when using 'unput()' is that if you -are using '%pointer' (the default), a call to 'unput()' _destroys_ the -contents of 'yytext', starting with its rightmost character and + An important potential problem when using ‘unput()’ is that if you +are using ‘%pointer’ (the default), a call to ‘unput()’ _destroys_ the +contents of ‘yytext’, starting with its rightmost character and devouring one character to the left with each call. If you need the -value of 'yytext' preserved after a call to 'unput()' (as in the above +value of ‘yytext’ preserved after a call to ‘unput()’ (as in the above example), you must either first copy it elsewhere, or build your scanner -using '%array' instead (*note Matching::). +using ‘%array’ instead (*note Matching::). - Finally, note that you cannot put back 'EOF' to attempt to mark the + Finally, note that you cannot put back ‘EOF’ to attempt to mark the input stream with an end-of-file. - 'input()' reads the next character from the input stream. For + ‘input()’ reads the next character from the input stream. For example, the following is one way to eat up C comments: %% "/*" { int c; - + for ( ; ; ) { while ( (c = input()) != '*' && c != EOF ) ; /* eat up text of comment */ - + if ( c == '*' ) { while ( (c = input()) == '*' ) @@ -1167,7 +1166,7 @@ example, the following is one way to eat up C comments: if ( c == '/' ) break; /* found the end */ } - + if ( c == EOF ) { error( "EOF in comment" ); @@ -1176,19 +1175,19 @@ example, the following is one way to eat up C comments: } } - (Note that if the scanner is compiled using 'C++', then 'input()' is + (Note that if the scanner is compiled using ‘C++’, then ‘input()’ is instead referred to as yyinput(), in order to avoid a name clash with -the 'C++' stream by the name of 'input'.) +the ‘C++’ stream by the name of ‘input’.) - 'YY_FLUSH_BUFFER;' flushes the scanner's internal buffer so that the + ‘YY_FLUSH_BUFFER;’ flushes the scanner's internal buffer so that the next time the scanner attempts to match a token, it will first refill -the buffer using 'YY_INPUT()' (*note Generated Scanner::). This action -is a special case of the more general 'yy_flush_buffer;' function, +the buffer using ‘YY_INPUT()’ (*note Generated Scanner::). This action +is a special case of the more general ‘yy_flush_buffer;’ function, described below (*note Multiple Input Buffers::) - 'yyterminate()' can be used in lieu of a return statement in an + ‘yyterminate()’ can be used in lieu of a return statement in an action. It terminates the scanner and returns a 0 to the scanner's -caller, indicating "all done". By default, 'yyterminate()' is also +caller, indicating "all done". By default, ‘yyterminate()’ is also called when an end-of-file is encountered. It is a macro and may be redefined. @@ -1198,9 +1197,9 @@ File: flex.info, Node: Generated Scanner, Next: Start Conditions, Prev: Actio 9 The Generated Scanner *********************** -The output of 'flex' is the file 'lex.yy.c', which contains the scanning -routine 'yylex()', a number of tables used by it for matching tokens, -and a number of auxiliary routines and macros. By default, 'yylex()' is +The output of ‘flex’ is the file ‘lex.yy.c’, which contains the scanning +routine ‘yylex()’, a number of tables used by it for matching tokens, +and a number of auxiliary routines and macros. By default, ‘yylex()’ is declared as follows: int yylex() @@ -1209,61 +1208,61 @@ declared as follows: } (If your environment supports function prototypes, then it will be -'int yylex( void )'.) This definition may be changed by defining the -'YY_DECL' macro. For example, you could use: +‘int yylex( void )’.) This definition may be changed by defining the +‘YY_DECL’ macro. For example, you could use: #define YY_DECL float lexscan( a, b ) float a, b; - to give the scanning routine the name 'lexscan', returning a float, + to give the scanning routine the name ‘lexscan’, returning a float, and taking two floats as arguments. Note that if you give arguments to the scanning routine using a K&R-style/non-prototyped function declaration, you must terminate the definition with a semi-colon (;). - 'flex' generates 'C99' function definitions by default. Flex used to -have the ability to generate obsolete, er, 'traditional', function + ‘flex’ generates ‘C99’ function definitions by default. Flex used to +have the ability to generate obsolete, er, ‘traditional’, function definitions. This was to support bootstrapping gcc on old systems. Unfortunately, traditional definitions prevent us from using any standard data types smaller than int (such as short, char, or bool) as function arguments. Furthermore, traditional definitions support added extra complexity in the skeleton file. For this reason, current -versions of 'flex' generate standard C99 code only, leaving K&R-style +versions of ‘flex’ generate standard C99 code only, leaving K&R-style functions to the historians. - Whenever 'yylex()' is called, it scans tokens from the global input -file 'yyin' (which defaults to stdin). It continues until it either + Whenever ‘yylex()’ is called, it scans tokens from the global input +file ‘yyin’ (which defaults to stdin). It continues until it either reaches an end-of-file (at which point it returns the value 0) or one of -its actions executes a 'return' statement. +its actions executes a ‘return’ statement. If the scanner reaches an end-of-file, subsequent calls are undefined -unless either 'yyin' is pointed at a new input file (in which case -scanning continues from that file), or 'yyrestart()' is called. -'yyrestart()' takes one argument, a 'FILE *' pointer (which can be NULL, -if you've set up 'YY_INPUT' to scan from a source other than 'yyin'), -and initializes 'yyin' for scanning from that file. Essentially there -is no difference between just assigning 'yyin' to a new input file or -using 'yyrestart()' to do so; the latter is available for compatibility -with previous versions of 'flex', and because it can be used to switch +unless either ‘yyin’ is pointed at a new input file (in which case +scanning continues from that file), or ‘yyrestart()’ is called. +‘yyrestart()’ takes one argument, a ‘FILE *’ pointer (which can be NULL, +if you've set up ‘YY_INPUT’ to scan from a source other than ‘yyin’), +and initializes ‘yyin’ for scanning from that file. Essentially there +is no difference between just assigning ‘yyin’ to a new input file or +using ‘yyrestart()’ to do so; the latter is available for compatibility +with previous versions of ‘flex’, and because it can be used to switch input files in the middle of scanning. It can also be used to throw -away the current input buffer, by calling it with an argument of 'yyin'; -but it would be better to use 'YY_FLUSH_BUFFER' (*note Actions::). Note -that 'yyrestart()' does _not_ reset the start condition to 'INITIAL' +away the current input buffer, by calling it with an argument of ‘yyin’; +but it would be better to use ‘YY_FLUSH_BUFFER’ (*note Actions::). Note +that ‘yyrestart()’ does _not_ reset the start condition to ‘INITIAL’ (*note Start Conditions::). - If 'yylex()' stops scanning due to executing a 'return' statement in + If ‘yylex()’ stops scanning due to executing a ‘return’ statement in one of the actions, the scanner may then be called again and it will resume scanning where it left off. By default (and for purposes of efficiency), the scanner uses -block-reads rather than simple 'getc()' calls to read characters from -'yyin'. The nature of how it gets its input can be controlled by -defining the 'YY_INPUT' macro. The calling sequence for 'YY_INPUT()' is -'YY_INPUT(buf,result,max_size)'. Its action is to place up to -'max_size' characters in the character array 'buf' and return in the -integer variable 'result' either the number of characters read or the -constant 'YY_NULL' (0 on Unix systems) to indicate 'EOF'. The default -'YY_INPUT' reads from the global file-pointer 'yyin'. +block-reads rather than simple ‘getc()’ calls to read characters from +‘yyin’. The nature of how it gets its input can be controlled by +defining the ‘YY_INPUT’ macro. The calling sequence for ‘YY_INPUT()’ is +‘YY_INPUT(buf,result,max_size)’. Its action is to place up to +‘max_size’ characters in the character array ‘buf’ and return in the +integer variable ‘result’ either the number of characters read or the +constant ‘YY_NULL’ (0 on Unix systems) to indicate ‘EOF’. The default +‘YY_INPUT’ reads from the global file-pointer ‘yyin’. - Here is a sample definition of 'YY_INPUT' (in the definitions section + Here is a sample definition of ‘YY_INPUT’ (in the definitions section of the input file): %{ @@ -1278,24 +1277,24 @@ of the input file): character at a time. When the scanner receives an end-of-file indication from YY_INPUT, it -then checks the 'yywrap()' function. If 'yywrap()' returns false +then checks the ‘yywrap()’ function. If ‘yywrap()’ returns false (zero), then it is assumed that the function has gone ahead and set up -'yyin' to point to another input file, and scanning continues. If it +‘yyin’ to point to another input file, and scanning continues. If it returns true (non-zero), then the scanner terminates, returning 0 to its caller. Note that in either case, the start condition remains -unchanged; it does _not_ revert to 'INITIAL'. +unchanged; it does _not_ revert to ‘INITIAL’. - If you do not supply your own version of 'yywrap()', then you must -either use '%option noyywrap' (in which case the scanner behaves as -though 'yywrap()' returned 1), or you must link with '-lfl' to obtain + If you do not supply your own version of ‘yywrap()’, then you must +either use ‘%option noyywrap’ (in which case the scanner behaves as +though ‘yywrap()’ returned 1), or you must link with ‘-lfl’ to obtain the default version of the routine, which always returns 1. For scanning from in-memory buffers (e.g., scanning strings), see *note Scanning Strings::. *Note Multiple Input Buffers::. - The scanner writes its 'ECHO' output to the 'yyout' global (default, -'stdout'), which may be redefined by the user simply by assigning it to -some other 'FILE' pointer. + The scanner writes its ‘ECHO’ output to the ‘yyout’ global (default, +‘stdout’), which may be redefined by the user simply by assigning it to +some other ‘FILE’ pointer.  File: flex.info, Node: Start Conditions, Next: Multiple Input Buffers, Prev: Generated Scanner, Up: Top @@ -1303,15 +1302,15 @@ File: flex.info, Node: Start Conditions, Next: Multiple Input Buffers, Prev: 10 Start Conditions ******************* -'flex' provides a mechanism for conditionally activating rules. Any -rule whose pattern is prefixed with '' will only be active when the -scanner is in the "start condition" named 'sc'. For example, +‘flex’ provides a mechanism for conditionally activating rules. Any +rule whose pattern is prefixed with ‘’ will only be active when the +scanner is in the “start condition” named ‘sc’. For example, [^"]* { /* eat up the string body ... */ ... } - will be active only when the scanner is in the 'STRING' start + will be active only when the scanner is in the ‘STRING’ start condition, and \. { /* handle an escape ... */ @@ -1319,20 +1318,20 @@ condition, and } will be active only when the current start condition is either -'INITIAL', 'STRING', or 'QUOTE'. +‘INITIAL’, ‘STRING’, or ‘QUOTE’. Start conditions are declared in the definitions (first) section of -the input using unindented lines beginning with either '%s' or '%x' -followed by a list of names. The former declares "inclusive" start -conditions, the latter "exclusive" start conditions. A start condition -is activated using the 'BEGIN' action. Until the next 'BEGIN' action is +the input using unindented lines beginning with either ‘%s’ or ‘%x’ +followed by a list of names. The former declares “inclusive” start +conditions, the latter “exclusive” start conditions. A start condition +is activated using the ‘BEGIN’ action. Until the next ‘BEGIN’ action is executed, rules with the given start condition will be active and rules with other start conditions will be inactive. If the start condition is inclusive, then rules with no start conditions at all will also be active. If it is exclusive, then _only_ rules qualified with the start condition will be active. A set of rules contingent on the same exclusive start condition describe a scanner which is independent of any -of the other rules in the 'flex' input. Because of this, exclusive +of the other rules in the ‘flex’ input. Because of this, exclusive start conditions make it easy to specify "mini-scanners" which scan portions of the input that are syntactically different from the rest (e.g., comments). @@ -1343,80 +1342,80 @@ connection between the two. The set of rules: %s example %% - + foo do_something(); - + bar something_else(); is equivalent to %x example %% - + foo do_something(); - + bar something_else(); - Without the '' qualifier, the 'bar' pattern in the + Without the ‘’ qualifier, the ‘bar’ pattern in the second example wouldn't be active (i.e., couldn't match) when in start -condition 'example'. If we just used '' to qualify 'bar', -though, then it would only be active in 'example' and not in 'INITIAL', +condition ‘example’. If we just used ‘’ to qualify ‘bar’, +though, then it would only be active in ‘example’ and not in ‘INITIAL’, while in the first example it's active in both, because in the first -example the 'example' start condition is an inclusive '(%s)' start +example the ‘example’ start condition is an inclusive ‘(%s)’ start condition. - Also note that the special start-condition specifier '<*>' matches + Also note that the special start-condition specifier ‘<*>’ matches every start condition. Thus, the above example could also have been written: %x example %% - + foo do_something(); - + <*>bar something_else(); - The default rule (to 'ECHO' any unmatched character) remains active + The default rule (to ‘ECHO’ any unmatched character) remains active in start conditions. It is equivalent to: <*>.|\n ECHO; - 'BEGIN(0)' returns to the original state where only the rules with no + ‘BEGIN(0)’ returns to the original state where only the rules with no start conditions are active. This state can also be referred to as the -start-condition 'INITIAL', so 'BEGIN(INITIAL)' is equivalent to -'BEGIN(0)'. (The parentheses around the start condition name are not +start-condition ‘INITIAL’, so ‘BEGIN(INITIAL)’ is equivalent to +‘BEGIN(0)’. (The parentheses around the start condition name are not required but are considered good style.) - 'BEGIN' actions can also be given as indented code at the beginning + ‘BEGIN’ actions can also be given as indented code at the beginning of the rules section. For example, the following will cause the scanner -to enter the 'SPECIAL' start condition whenever 'yylex()' is called and -the global variable 'enter_special' is true: +to enter the ‘SPECIAL’ start condition whenever ‘yylex()’ is called and +the global variable ‘enter_special’ is true: int enter_special; - + %x SPECIAL %% if ( enter_special ) BEGIN(SPECIAL); - + blahblahblah ...more rules follow... To illustrate the uses of start conditions, here is a scanner which -provides two different interpretations of a string like '123.456'. By -default it will treat it as three tokens, the integer '123', a dot -('.'), and the integer '456'. But if the string is preceded earlier in -the line by the string 'expect-floats' it will treat it as a single -token, the floating-point number '123.456': +provides two different interpretations of a string like ‘123.456’. By +default it will treat it as three tokens, the integer ‘123’, a dot +(‘.’), and the integer ‘456’. But if the string is preceded earlier in +the line by the string ‘expect-floats’ it will treat it as a single +token, the floating-point number ‘123.456’: %{ #include %} %s expect - + %% expect-floats BEGIN(expect); - + [0-9]+.[0-9]+ { printf( "found a float, = %f\n", atof( yytext ) ); @@ -1429,12 +1428,12 @@ token, the floating-point number '123.456': */ BEGIN(INITIAL); } - + [0-9]+ { printf( "found an integer, = %d\n", atoi( yytext ) ); } - + "." printf( "found a dot\n" ); Here is a scanner which recognizes (and discards) C comments while @@ -1443,9 +1442,9 @@ maintaining a count of the current input line. %x comment %% int line_num = 1; - + "/*" BEGIN(comment); - + [^*\n]* /* eat anything that's not a '*' */ "*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ \n ++line_num; @@ -1464,32 +1463,32 @@ fashion: %% int line_num = 1; int comment_caller; - + "/*" { comment_caller = INITIAL; BEGIN(comment); } - + ... - + "/*" { comment_caller = foo; BEGIN(comment); } - + [^*\n]* /* eat anything that's not a '*' */ "*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ \n ++line_num; "*"+"/" BEGIN(comment_caller); Furthermore, you can access the current start condition using the -integer-valued 'YY_START' macro. For example, the above assignments to -'comment_caller' could instead be written +integer-valued ‘YY_START’ macro. For example, the above assignments to +‘comment_caller’ could instead be written comment_caller = YY_START; - Flex provides 'YYSTATE' as an alias for 'YY_START' (since that is -what's used by AT&T 'lex'). + Flex provides ‘YYSTATE’ as an alias for ‘YY_START’ (since that is +what's used by AT&T ‘lex’). For historical reasons, start conditions do not have their own name-space within the generated scanner. The start condition names are @@ -1501,14 +1500,14 @@ using exclusive start conditions, including expanded escape sequences (but not including checking for a string that's too long): %x str - + %% char string_buf[MAX_STR_CONST]; char *string_buf_ptr; - - + + \" string_buf_ptr = string_buf; BEGIN(str); - + \" { /* saw closing quote - all done */ BEGIN(INITIAL); *string_buf_ptr = '\0'; @@ -1516,41 +1515,41 @@ using exclusive start conditions, including expanded escape sequences * value to parser */ } - + \n { /* error - unterminated string constant */ /* generate error message */ } - + \\[0-7]{1,3} { /* octal escape sequence */ int result; - + (void) sscanf( yytext + 1, "%o", &result ); - + if ( result > 0xff ) /* error, constant is out-of-bounds */ - + *string_buf_ptr++ = result; } - + \\[0-9]+ { /* generate error - bad escape sequence; something * like '\48' or '\0777777' */ } - + \\n *string_buf_ptr++ = '\n'; \\t *string_buf_ptr++ = '\t'; \\r *string_buf_ptr++ = '\r'; \\b *string_buf_ptr++ = '\b'; \\f *string_buf_ptr++ = '\f'; - + \\(.|\n) *string_buf_ptr++ = yytext[1]; - + [^\\\n\"]+ { char *yptr = yytext; - + while ( *yptr ) *string_buf_ptr++ = *yptr++; } @@ -1558,13 +1557,13 @@ using exclusive start conditions, including expanded escape sequences Often, such as in some of the examples above, you wind up writing a whole bunch of rules all preceded by the same start condition(s). Flex makes this a little easier and cleaner by introducing a notion of start -condition "scope". A start condition scope is begun with: +condition “scope”. A start condition scope is begun with: { - where '' is a list of one or more start conditions. Inside the -start condition scope, every rule automatically has the prefix '' -applied to it, until a '}' which matches the initial '{'. So, for + where ‘’ is a list of one or more start conditions. Inside the +start condition scope, every rule automatically has the prefix ‘’ +applied to it, until a ‘}’ which matches the initial ‘{’. So, for example, { @@ -1586,14 +1585,14 @@ example, The following routines are available for manipulating stacks of start conditions: - -- Function: void yy_push_state ( int 'new_state' ) + -- Function: void yy_push_state ( int new_state ) pushes the current start condition onto the top of the start - condition stack and switches to 'new_state' as though you had used - 'BEGIN new_state' (recall that start condition names are also + condition stack and switches to ‘new_state’ as though you had used + ‘BEGIN new_state’ (recall that start condition names are also integers). -- Function: void yy_pop_state () - pops the top of the stack and switches to it via 'BEGIN'. + pops the top of the stack and switches to it via ‘BEGIN’. -- Function: int yy_top_state () returns the top of the stack without altering the stack's contents. @@ -1601,8 +1600,8 @@ conditions: The start condition stack grows dynamically and so has no built-in size limitation. If memory is exhausted, program execution aborts. - To use start condition stacks, your scanner must include a '%option -stack' directive (*note Scanner Options::). + To use start condition stacks, your scanner must include a ‘%option +stack’ directive (*note Scanner Options::).  File: flex.info, Node: Multiple Input Buffers, Next: EOF, Prev: Start Conditions, Up: Top @@ -1611,48 +1610,48 @@ File: flex.info, Node: Multiple Input Buffers, Next: EOF, Prev: Start Conditi ************************* Some scanners (such as those which support "include" files) require -reading from several input streams. As 'flex' scanners do a large +reading from several input streams. As ‘flex’ scanners do a large amount of buffering, one cannot control where the next input will be -read from by simply writing a 'YY_INPUT()' which is sensitive to the -scanning context. 'YY_INPUT()' is only called when the scanner reaches +read from by simply writing a ‘YY_INPUT()’ which is sensitive to the +scanning context. ‘YY_INPUT()’ is only called when the scanner reaches the end of its buffer, which may be a long time after scanning a -statement such as an 'include' statement which requires switching the +statement such as an ‘include’ statement which requires switching the input source. - To negotiate these sorts of problems, 'flex' provides a mechanism for + To negotiate these sorts of problems, ‘flex’ provides a mechanism for creating and switching between multiple input buffers. An input buffer is created by using: -- Function: YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ) - which takes a 'FILE' pointer and a size and creates a buffer -associated with the given file and large enough to hold 'size' -characters (when in doubt, use 'YY_BUF_SIZE' for the size). It returns -a 'YY_BUFFER_STATE' handle, which may then be passed to other routines -(see below). The 'YY_BUFFER_STATE' type is a pointer to an opaque -'struct yy_buffer_state' structure, so you may safely initialize -'YY_BUFFER_STATE' variables to '((YY_BUFFER_STATE) 0)' if you wish, and + which takes a ‘FILE’ pointer and a size and creates a buffer +associated with the given file and large enough to hold ‘size’ +characters (when in doubt, use ‘YY_BUF_SIZE’ for the size). It returns +a ‘YY_BUFFER_STATE’ handle, which may then be passed to other routines +(see below). The ‘YY_BUFFER_STATE’ type is a pointer to an opaque +‘struct yy_buffer_state’ structure, so you may safely initialize +‘YY_BUFFER_STATE’ variables to ‘((YY_BUFFER_STATE) 0)’ if you wish, and also refer to the opaque structure in order to correctly declare input buffers in source files other than that of your scanner. Note that the -'FILE' pointer in the call to 'yy_create_buffer' is only used as the -value of 'yyin' seen by 'YY_INPUT'. If you redefine 'YY_INPUT()' so it -no longer uses 'yyin', then you can safely pass a NULL 'FILE' pointer to -'yy_create_buffer'. You select a particular buffer to scan from using: +‘FILE’ pointer in the call to ‘yy_create_buffer’ is only used as the +value of ‘yyin’ seen by ‘YY_INPUT’. If you redefine ‘YY_INPUT()’ so it +no longer uses ‘yyin’, then you can safely pass a NULL ‘FILE’ pointer to +‘yy_create_buffer’. You select a particular buffer to scan from using: -- Function: void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ) The above function switches the scanner's input buffer so subsequent -tokens will come from 'new_buffer'. Note that 'yy_switch_to_buffer()' -may be used by 'yywrap()' to set things up for continued scanning, -instead of opening a new file and pointing 'yyin' at it. If you are +tokens will come from ‘new_buffer’. Note that ‘yy_switch_to_buffer()’ +may be used by ‘yywrap()’ to set things up for continued scanning, +instead of opening a new file and pointing ‘yyin’ at it. If you are looking for a stack of input buffers, then you want to use -'yypush_buffer_state()' instead of this function. Note also that -switching input sources via either 'yy_switch_to_buffer()' or 'yywrap()' +‘yypush_buffer_state()’ instead of this function. Note also that +switching input sources via either ‘yy_switch_to_buffer()’ or ‘yywrap()’ does _not_ change the start condition. -- Function: void yy_delete_buffer ( YY_BUFFER_STATE buffer ) - is used to reclaim the storage associated with a buffer. ('buffer' + is used to reclaim the storage associated with a buffer. (‘buffer’ can be NULL, in which case the routine does nothing.) You can also clear the current contents of a buffer using: @@ -1661,32 +1660,32 @@ clear the current contents of a buffer using: This function pushes the new buffer state onto an internal stack. The pushed state becomes the new current state. The stack is maintained by flex and will grow as required. This function is intended to be used -instead of 'yy_switch_to_buffer', when you want to change states, but +instead of ‘yy_switch_to_buffer’, when you want to change states, but preserve the current state for later use. -- Function: void yypop_buffer_state ( ) This function removes the current state from the top of the stack, -and deletes it by calling 'yy_delete_buffer'. The next state on the +and deletes it by calling ‘yy_delete_buffer’. The next state on the stack, if any, becomes the new current state. -- Function: void yy_flush_buffer ( YY_BUFFER_STATE buffer ) This function discards the buffer's contents, so the next time the scanner attempts to match a token from the buffer, it will first fill -the buffer anew using 'YY_INPUT()'. +the buffer anew using ‘YY_INPUT()’. -- Function: YY_BUFFER_STATE yy_new_buffer ( FILE *file, int size ) - is an alias for 'yy_create_buffer()', provided for compatibility with -the C++ use of 'new' and 'delete' for creating and destroying dynamic + is an alias for ‘yy_create_buffer()’, provided for compatibility with +the C++ use of ‘new’ and ‘delete’ for creating and destroying dynamic objects. - 'YY_CURRENT_BUFFER' macro returns a 'YY_BUFFER_STATE' handle to the + ‘YY_CURRENT_BUFFER’ macro returns a ‘YY_BUFFER_STATE’ handle to the current buffer. It should not be used as an lvalue. Here are two examples of using these features for writing a scanner -which expands include files (the '<>' feature is discussed below). +which expands include files (the ‘<>’ feature is discussed below). This first example uses yypush_buffer_state and yypop_buffer_state. Flex maintains the stack internally. @@ -1697,25 +1696,25 @@ Flex maintains the stack internally. %x incl %% include BEGIN(incl); - + [a-z]+ ECHO; [^a-z\n]*\n? ECHO; - + [ \t]* /* eat the whitespace */ [^ \t\n]+ { /* got the include file name */ yyin = fopen( yytext, "r" ); - + if ( ! yyin ) error( ... ); - + yypush_buffer_state(yy_create_buffer( yyin, YY_BUF_SIZE )); - + BEGIN(INITIAL); } - + <> { yypop_buffer_state(); - + if ( !YY_CURRENT_BUFFER ) { yyterminate(); @@ -1730,19 +1729,19 @@ letting flex do it). * of an include file */ %x incl - + %{ #define MAX_INCLUDE_DEPTH 10 YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH]; int include_stack_ptr = 0; %} - + %% include BEGIN(incl); - + [a-z]+ ECHO; [^a-z\n]*\n? ECHO; - + [ \t]* /* eat the whitespace */ [^ \t\n]+ { /* got the include file name */ if ( include_stack_ptr >= MAX_INCLUDE_DEPTH ) @@ -1750,27 +1749,27 @@ letting flex do it). fprintf( stderr, "Includes nested too deeply" ); exit( 1 ); } - + include_stack[include_stack_ptr++] = YY_CURRENT_BUFFER; - + yyin = fopen( yytext, "r" ); - + if ( ! yyin ) error( ... ); - + yy_switch_to_buffer( yy_create_buffer( yyin, YY_BUF_SIZE ) ); - + BEGIN(INITIAL); } - + <> { if ( --include_stack_ptr == 0 ) { yyterminate(); } - + else { yy_delete_buffer( YY_CURRENT_BUFFER ); @@ -1782,9 +1781,9 @@ letting flex do it). The following routines are available for setting up input buffers for scanning in-memory strings instead of files. All of them create a new input buffer for scanning the string, and return a corresponding -'YY_BUFFER_STATE' handle (which you should delete with -'yy_delete_buffer()' when done with it). They also switch to the new -buffer using 'yy_switch_to_buffer()', so the next call to 'yylex()' will +‘YY_BUFFER_STATE’ handle (which you should delete with +‘yy_delete_buffer()’ when done with it). They also switch to the new +buffer using ‘yy_switch_to_buffer()’, so the next call to ‘yylex()’ will start scanning the string. -- Function: YY_BUFFER_STATE yy_scan_string ( const char *str ) @@ -1792,24 +1791,24 @@ start scanning the string. -- Function: YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ) - scans 'len' bytes (including possibly 'NUL's) starting at location - 'bytes'. + scans ‘len’ bytes (including possibly ‘NUL’s) starting at location + ‘bytes’. Note that both of these functions create and scan a _copy_ of the -string or bytes. (This may be desirable, since 'yylex()' modifies the +string or bytes. (This may be desirable, since ‘yylex()’ modifies the contents of the buffer it is scanning.) You can avoid the copy by using: -- Function: YY_BUFFER_STATE yy_scan_buffer (char *base, yy_size_t size) - which scans in place the buffer starting at 'base', consisting of - 'size' bytes, the last two bytes of which _must_ be - 'YY_END_OF_BUFFER_CHAR' (ASCII NUL). These last two bytes are not - scanned; thus, scanning consists of 'base[0]' through - 'base[size-2]', inclusive. + which scans in place the buffer starting at ‘base’, consisting of + ‘size’ bytes, the last two bytes of which _must_ be + ‘YY_END_OF_BUFFER_CHAR’ (ASCII NUL). These last two bytes are not + scanned; thus, scanning consists of ‘base[0]’ through + ‘base[size-2]’, inclusive. - If you fail to set up 'base' in this manner (i.e., forget the final -two 'YY_END_OF_BUFFER_CHAR' bytes), then 'yy_scan_buffer()' returns a + If you fail to set up ‘base’ in this manner (i.e., forget the final +two ‘YY_END_OF_BUFFER_CHAR’ bytes), then ‘yy_scan_buffer()’ returns a NULL pointer instead of creating a new input buffer. -- Data type: yy_size_t @@ -1822,20 +1821,20 @@ File: flex.info, Node: EOF, Next: Misc Macros, Prev: Multiple Input Buffers, 12 End-of-File Rules ******************** -The special rule '<>' indicates actions which are to be taken when -an end-of-file is encountered and 'yywrap()' returns non-zero (i.e., +The special rule ‘<>’ indicates actions which are to be taken when +an end-of-file is encountered and ‘yywrap()’ returns non-zero (i.e., indicates no further files to process). The action must finish by doing one of the following things: - * assigning 'yyin' to a new input file (in previous versions of - 'flex', after doing the assignment you had to call the special - action 'YY_NEW_FILE'. This is no longer necessary.) + • assigning ‘yyin’ to a new input file (in previous versions of + ‘flex’, after doing the assignment you had to call the special + action ‘YY_NEW_FILE’. This is no longer necessary.) - * executing a 'return' statement; + • executing a ‘return’ statement; - * executing the special 'yyterminate()' action. + • executing the special ‘yyterminate()’ action. - * or, switching to a new buffer using 'yy_switch_to_buffer()' as + • or, switching to a new buffer using ‘yy_switch_to_buffer()’ as shown in the example above. <> rules may not be used with other patterns; they may only be @@ -1851,9 +1850,9 @@ An example: %x quote %% - + ...other rules for dealing with quotes... - + <> { error( "unterminated quote" ); yyterminate(); @@ -1871,57 +1870,57 @@ File: flex.info, Node: Misc Macros, Next: User Values, Prev: EOF, Up: Top 13 Miscellaneous Macros *********************** -The macro 'YY_USER_ACTION' can be defined to provide an action which is +The macro ‘YY_USER_ACTION’ can be defined to provide an action which is always executed prior to the matched rule's action. For example, it could be #define'd to call a routine to convert yytext to lower-case. -When 'YY_USER_ACTION' is invoked, the variable 'yy_act' gives the number +When ‘YY_USER_ACTION’ is invoked, the variable ‘yy_act’ gives the number of the matched rule (rules are numbered starting with 1). Suppose you want to profile how often each of your rules is matched. The following would do the trick: #define YY_USER_ACTION ++ctr[yy_act] - where 'ctr' is an array to hold the counts for the different rules. -Note that the macro 'YY_NUM_RULES' gives the total number of rules -(including the default rule), even if you use '-s)', so a correct -declaration for 'ctr' is: + where ‘ctr’ is an array to hold the counts for the different rules. +Note that the macro ‘YY_NUM_RULES’ gives the total number of rules +(including the default rule), even if you use ‘-s)’, so a correct +declaration for ‘ctr’ is: int ctr[YY_NUM_RULES]; - The macro 'YY_USER_INIT' may be defined to provide an action which is + The macro ‘YY_USER_INIT’ may be defined to provide an action which is always executed before the first scan (and before the scanner's internal initializations are done). For example, it could be used to call a routine to read in a data table or open a logging file. - The macro 'yy_set_interactive(is_interactive)' can be used to control -whether the current buffer is considered "interactive". An interactive + The macro ‘yy_set_interactive(is_interactive)’ can be used to control +whether the current buffer is considered “interactive”. An interactive buffer is processed more slowly, but must be used when the scanner's input source is indeed interactive to avoid problems due to waiting to -fill buffers (see the discussion of the '-I' flag in *note Scanner +fill buffers (see the discussion of the ‘-I’ flag in *note Scanner Options::). A non-zero value in the macro invocation marks the buffer as interactive, a zero value as non-interactive. Note that use of this -macro overrides '%option always-interactive' or '%option -never-interactive' (*note Scanner Options::). 'yy_set_interactive()' +macro overrides ‘%option always-interactive’ or ‘%option +never-interactive’ (*note Scanner Options::). ‘yy_set_interactive()’ must be invoked prior to beginning to scan the buffer that is (or is not) to be considered interactive. - The macro 'yy_set_bol(at_bol)' can be used to control whether the + The macro ‘yy_set_bol(at_bol)’ can be used to control whether the current buffer's scanning context for the next token match is done as though at the beginning of a line. A non-zero macro argument makes -rules anchored with '^' active, while a zero argument makes '^' rules +rules anchored with ‘^’ active, while a zero argument makes ‘^’ rules inactive. - The macro 'YY_AT_BOL()' returns true if the next token scanned from -the current buffer will have '^' rules active, false otherwise. + The macro ‘YY_AT_BOL()’ returns true if the next token scanned from +the current buffer will have ‘^’ rules active, false otherwise. In the generated scanner, the actions are all gathered in one large -switch statement and separated using 'YY_BREAK', which may be redefined. -By default, it is simply a 'break', to separate each rule's action from -the following rule's. Redefining 'YY_BREAK' allows, for example, C++ +switch statement and separated using ‘YY_BREAK’, which may be redefined. +By default, it is simply a ‘break’, to separate each rule's action from +the following rule's. Redefining ‘YY_BREAK’ allows, for example, C++ users to #define YY_BREAK to do nothing (while being very careful that -every rule ends with a 'break' or a 'return'!) to avoid suffering from +every rule ends with a ‘break’ or a ‘return’!) to avoid suffering from unreachable statement warnings where because a rule's action ends with -'return', the 'YY_BREAK' is inaccessible. +‘return’, the ‘YY_BREAK’ is inaccessible.  File: flex.info, Node: User Values, Next: Yacc, Prev: Misc Macros, Up: Top @@ -1932,52 +1931,52 @@ File: flex.info, Node: User Values, Next: Yacc, Prev: Misc Macros, Up: Top This chapter summarizes the various values available to the user in the rule actions. -'char *yytext' +‘char *yytext’ holds the text of the current token. It may be modified but not lengthened (you cannot append characters to the end). - If the special directive '%array' appears in the first section of - the scanner description, then 'yytext' is instead declared 'char - yytext[YYLMAX]', where 'YYLMAX' is a macro definition that you can + If the special directive ‘%array’ appears in the first section of + the scanner description, then ‘yytext’ is instead declared ‘char + yytext[YYLMAX]’, where ‘YYLMAX’ is a macro definition that you can redefine in the first section if you don't like the default value - (generally 8KB). Using '%array' results in somewhat slower - scanners, but the value of 'yytext' becomes immune to calls to - 'unput()', which potentially destroy its value when 'yytext' is a - character pointer. The opposite of '%array' is '%pointer', which + (generally 8KB). Using ‘%array’ results in somewhat slower + scanners, but the value of ‘yytext’ becomes immune to calls to + ‘unput()’, which potentially destroy its value when ‘yytext’ is a + character pointer. The opposite of ‘%array’ is ‘%pointer’, which is the default. - You cannot use '%array' when generating C++ scanner classes (the - '-+' flag). + You cannot use ‘%array’ when generating C++ scanner classes (the + ‘-+’ flag). -'int yyleng' +‘int yyleng’ holds the length of the current token. -'FILE *yyin' - is the file which by default 'flex' reads from. It may be +‘FILE *yyin’ + is the file which by default ‘flex’ reads from. It may be redefined but doing so only makes sense before scanning begins or after an EOF has been encountered. Changing it in the midst of - scanning will have unexpected results since 'flex' buffers its - input; use 'yyrestart()' instead. Once scanning terminates because - an end-of-file has been seen, you can assign 'yyin' at the new + scanning will have unexpected results since ‘flex’ buffers its + input; use ‘yyrestart()’ instead. Once scanning terminates because + an end-of-file has been seen, you can assign ‘yyin’ at the new input file and then call the scanner again to continue scanning. -'void yyrestart( FILE *new_file )' - may be called to point 'yyin' at the new input file. The +‘void yyrestart( FILE *new_file )’ + may be called to point ‘yyin’ at the new input file. The switch-over to the new file is immediate (any previously - buffered-up input is lost). Note that calling 'yyrestart()' with - 'yyin' as an argument thus throws away the current input buffer and + buffered-up input is lost). Note that calling ‘yyrestart()’ with + ‘yyin’ as an argument thus throws away the current input buffer and continues scanning the same input file. -'FILE *yyout' - is the file to which 'ECHO' actions are done. It can be reassigned +‘FILE *yyout’ + is the file to which ‘ECHO’ actions are done. It can be reassigned by the user. -'YY_CURRENT_BUFFER' - returns a 'YY_BUFFER_STATE' handle to the current buffer. +‘YY_CURRENT_BUFFER’ + returns a ‘YY_BUFFER_STATE’ handle to the current buffer. -'YY_START' +‘YY_START’ returns an integer value corresponding to the current start - condition. You can subsequently use this value with 'BEGIN' to + condition. You can subsequently use this value with ‘BEGIN’ to return to that start condition.  @@ -1986,23 +1985,23 @@ File: flex.info, Node: Yacc, Next: Scanner Options, Prev: User Values, Up: T 15 Interfacing with Yacc ************************ -One of the main uses of 'flex' is as a companion to the 'yacc' -parser-generator. 'yacc' parsers expect to call a routine named -'yylex()' to find the next input token. The routine is supposed to +One of the main uses of ‘flex’ is as a companion to the ‘yacc’ +parser-generator. ‘yacc’ parsers expect to call a routine named +‘yylex()’ to find the next input token. The routine is supposed to return the type of the next token as well as putting any associated -value in the global 'yylval'. To use 'flex' with 'yacc', one specifies -the '-d' option to 'yacc' to instruct it to generate the file 'y.tab.h' -containing definitions of all the '%tokens' appearing in the 'yacc' -input. This file is then included in the 'flex' scanner. For example, -if one of the tokens is 'TOK_NUMBER', part of the scanner might look +value in the global ‘yylval’. To use ‘flex’ with ‘yacc’, one specifies +the ‘-d’ option to ‘yacc’ to instruct it to generate the file ‘y.tab.h’ +containing definitions of all the ‘%tokens’ appearing in the ‘yacc’ +input. This file is then included in the ‘flex’ scanner. For example, +if one of the tokens is ‘TOK_NUMBER’, part of the scanner might look like: %{ #include "y.tab.h" %} - + %% - + [0-9]+ yylval = atoi( yytext ); return TOK_NUMBER;  @@ -2011,18 +2010,18 @@ File: flex.info, Node: Scanner Options, Next: Performance, Prev: Yacc, Up: T 16 Scanner Options ****************** -The various 'flex' options are categorized by function in the following +The various ‘flex’ options are categorized by function in the following menu. If you want to lookup a particular option by name, *Note Index of Scanner Options::. * Menu: -* Options for Specifying Filenames:: -* Options Affecting Scanner Behavior:: -* Code-Level And API Options:: -* Options for Scanner Speed and Size:: -* Debugging Options:: -* Miscellaneous Options:: +* Options for Specifying Filenames:: +* Options Affecting Scanner Behavior:: +* Code-Level And API Options:: +* Options for Scanner Speed and Size:: +* Debugging Options:: +* Miscellaneous Options:: Even though there are many scanner options, a typical scanner might only specify the following options: @@ -2038,41 +2037,41 @@ flex to track line numbers. The last line tells flex what to name the files. (The options can be specified in any order. We just divided them.) - 'flex' also provides a mechanism for controlling options within the + ‘flex’ also provides a mechanism for controlling options within the scanner specification itself, rather than from the flex command-line. -This is done by including '%option' directives in the first section of +This is done by including ‘%option’ directives in the first section of the scanner specification. You can specify multiple options with a -single '%option' directive, and multiple directives in the first section +single ‘%option’ directive, and multiple directives in the first section of your flex input file. Most options are given simply as names, optionally preceded by the -word 'no' (with no intervening whitespace) to negate their meaning. The +word ‘no’ (with no intervening whitespace) to negate their meaning. The names are the same as their long-option equivalents (but without the -leading '--' ). +leading ‘--’ ). - 'flex' scans your rule actions to determine whether you use the -'REJECT' or 'yymore()' features. The 'REJECT' and 'yymore' options are + ‘flex’ scans your rule actions to determine whether you use the +‘REJECT’ or ‘yymore()’ features. The ‘REJECT’ and ‘yymore’ options are available to override its decision as to whether you use the options, -either by setting them (e.g., '%option reject)' to indicate the feature +either by setting them (e.g., ‘%option reject)’ to indicate the feature is indeed used, or unsetting them to indicate it actually is not used -(e.g., '%option noyymore)'. +(e.g., ‘%option noyymore)’. A number of options are available for lint purists who want to suppress the appearance of unneeded routines in the generated scanner. -Each of the following, if unset (e.g., '%option nounput'), results in +Each of the following, if unset (e.g., ‘%option nounput’), results in the corresponding routine not appearing in the generated scanner: input, unput yy_push_state, yy_pop_state, yy_top_state yy_scan_buffer, yy_scan_bytes, yy_scan_string - + yyget_extra, yyset_extra, yyget_leng, yyget_text, yyget_lineno, yyset_lineno, yyget_in, yyset_in, yyget_out, yyset_out, yyget_lval, yyset_lval, yyget_lloc, yyset_lloc, yyget_debug, yyset_debug - (though 'yy_push_state()' and friends won't appear anyway unless you -use '%option stack)'. + (though ‘yy_push_state()’ and friends won't appear anyway unless you +use ‘%option stack)’.  File: flex.info, Node: Options for Specifying Filenames, Next: Options Affecting Scanner Behavior, Prev: Scanner Options, Up: Scanner Options @@ -2080,42 +2079,42 @@ File: flex.info, Node: Options for Specifying Filenames, Next: Options Affecti 16.1 Options for Specifying Filenames ===================================== -'--header-file=FILE, '%option header-file="FILE"'' - instructs flex to write a C header to 'FILE'. This file contains +‘--header-file=FILE, ‘%option header-file="FILE"’’ + instructs flex to write a C header to ‘FILE’. This file contains function prototypes, extern variables, and types used by the scanner. Only the external API is exported by the header file. Many macros that are usable from within scanner actions are not exported to the header file. This is due to namespace problems and the goal of a clean external API. - While in the header, the macro 'yyIN_HEADER' is defined, where 'yy' + While in the header, the macro ‘yyIN_HEADER’ is defined, where ‘yy’ is substituted with the appropriate prefix. - The '--header-file' option is not compatible with the '--c++' + The ‘--header-file’ option is not compatible with the ‘--c++’ option, since the C++ scanner provides its own header in - 'yyFlexLexer.h'. + ‘yyFlexLexer.h’. -'-oFILE, --outfile=FILE, '%option outfile="FILE"'' - directs flex to write the scanner to the file 'FILE' instead of - 'lex.yy.c'. If you combine '--outfile' with the '--stdout' option, - then the scanner is written to 'stdout' but its '#line' directives - (see the '-l' option above) refer to the file 'FILE'. +‘-oFILE, --outfile=FILE, ‘%option outfile="FILE"’’ + directs flex to write the scanner to the file ‘FILE’ instead of + ‘lex.yy.c’. If you combine ‘--outfile’ with the ‘--stdout’ option, + then the scanner is written to ‘stdout’ but its ‘#line’ directives + (see the ‘-l’ option above) refer to the file ‘FILE’. -'-t, --stdout, '%option stdout'' - instructs 'flex' to write the scanner it generates to standard - output instead of 'lex.yy.c'. +‘-t, --stdout, ‘%option stdout’’ + instructs ‘flex’ to write the scanner it generates to standard + output instead of ‘lex.yy.c’. -'-SFILE, --skel=FILE' - overrides the default skeleton file from which 'flex' constructs +‘-SFILE, --skel=FILE’ + overrides the default skeleton file from which ‘flex’ constructs its scanners. You'll never need this option unless you are doing - 'flex' maintenance or development. + ‘flex’ maintenance or development. -'--tables-file=FILE' +‘--tables-file=FILE’ Write serialized scanner dfa tables to FILE. The generated scanner will not contain the tables, and requires them to be loaded at runtime. *Note serialization::. -'--tables-verify' +‘--tables-verify’ This option is for flex development. We document it here in case you stumble upon it by accident or in case you suspect some inconsistency in the serialized tables. Flex will serialize the @@ -2130,34 +2129,34 @@ File: flex.info, Node: Options Affecting Scanner Behavior, Next: Code-Level An 16.2 Options Affecting Scanner Behavior ======================================= -'-i, --case-insensitive, '%option case-insensitive'' - instructs 'flex' to generate a "case-insensitive" scanner. The - case of letters given in the 'flex' input patterns will be ignored, +‘-i, --case-insensitive, ‘%option case-insensitive’’ + instructs ‘flex’ to generate a “case-insensitive” scanner. The + case of letters given in the ‘flex’ input patterns will be ignored, and tokens in the input will be matched regardless of case. The - matched text given in 'yytext' will have the preserved case (i.e., + matched text given in ‘yytext’ will have the preserved case (i.e., it will not be folded). For tricky behavior, see *note case and character ranges::. -'-l, --lex-compat, '%option lex-compat'' - turns on maximum compatibility with the original AT&T 'lex' +‘-l, --lex-compat, ‘%option lex-compat’’ + turns on maximum compatibility with the original AT&T ‘lex’ implementation. Note that this does not mean _full_ compatibility. Use of this option costs a considerable amount of performance, and - it cannot be used with the '--c++', '--full', '--fast', '-Cf', or - '-CF' options. For details on the compatibilities it provides, see + it cannot be used with the ‘--c++’, ‘--full’, ‘--fast’, ‘-Cf’, or + ‘-CF’ options. For details on the compatibilities it provides, see *note Lex and Posix::. This option also results in the name - 'YY_FLEX_LEX_COMPAT' being '#define''d in the generated scanner. + ‘YY_FLEX_LEX_COMPAT’ being ‘#define’'d in the generated scanner. -'-B, --batch, '%option batch'' - instructs 'flex' to generate a "batch" scanner, the opposite of - _interactive_ scanners generated by '--interactive' (see below). - In general, you use '-B' when you are _certain_ that your scanner +‘-B, --batch, ‘%option batch’’ + instructs ‘flex’ to generate a “batch” scanner, the opposite of + _interactive_ scanners generated by ‘--interactive’ (see below). + In general, you use ‘-B’ when you are _certain_ that your scanner will never be used interactively, and you want to squeeze a _little_ more performance out of it. If your goal is instead to - squeeze out a _lot_ more performance, you should be using the '-Cf' - or '-CF' options, which turn on '--batch' automatically anyway. + squeeze out a _lot_ more performance, you should be using the ‘-Cf’ + or ‘-CF’ options, which turn on ‘--batch’ automatically anyway. -'-I, --interactive, '%option interactive'' - instructs 'flex' to generate an interactive scanner. An +‘-I, --interactive, ‘%option interactive’’ + instructs ‘flex’ to generate an interactive scanner. An interactive scanner is one that only looks ahead to decide what token has been matched if it absolutely must. It turns out that always looking one extra character ahead, even if the scanner has @@ -2168,112 +2167,112 @@ File: flex.info, Node: Options Affecting Scanner Behavior, Next: Code-Level An newline token until they enter _another_ token, which often means typing in another whole line. - 'flex' scanners default to 'interactive' unless you use the '-Cf' - or '-CF' table-compression options (*note Performance::). That's + ‘flex’ scanners default to ‘interactive’ unless you use the ‘-Cf’ + or ‘-CF’ table-compression options (*note Performance::). That's because if you're looking for high-performance you should be using - one of these options, so if you didn't, 'flex' assumes you'd rather + one of these options, so if you didn't, ‘flex’ assumes you'd rather trade off a bit of run-time performance for intuitive interactive - behavior. Note also that you _cannot_ use '--interactive' in - conjunction with '-Cf' or '-CF'. Thus, this option is not really + behavior. Note also that you _cannot_ use ‘--interactive’ in + conjunction with ‘-Cf’ or ‘-CF’. Thus, this option is not really needed; it is on by default for all those cases in which it is allowed. - You can force a scanner to _not_ be interactive by using '--batch' + You can force a scanner to _not_ be interactive by using ‘--batch’ -'-7, --7bit, '%option 7bit'' - instructs 'flex' to generate a 7-bit scanner, i.e., one which can +‘-7, --7bit, ‘%option 7bit’’ + instructs ‘flex’ to generate a 7-bit scanner, i.e., one which can only recognize 7-bit characters in its input. The advantage of - using '--7bit' is that the scanner's tables can be up to half the - size of those generated using the '--8bit'. The disadvantage is + using ‘--7bit’ is that the scanner's tables can be up to half the + size of those generated using the ‘--8bit’. The disadvantage is that such scanners often hang or crash if their input contains an 8-bit character. Note, however, that unless you generate your scanner using the - '-Cf' or '-CF' table compression options, use of '--7bit' will save + ‘-Cf’ or ‘-CF’ table compression options, use of ‘--7bit’ will save only a small amount of table space, and make your scanner - considerably less portable. 'Flex''s default behavior is to - generate an 8-bit scanner unless you use the '-Cf' or '-CF', in - which case 'flex' defaults to generating 7-bit scanners unless your + considerably less portable. ‘Flex’'s default behavior is to + generate an 8-bit scanner unless you use the ‘-Cf’ or ‘-CF’, in + which case ‘flex’ defaults to generating 7-bit scanners unless your site was always configured to generate 8-bit scanners (as will often be the case with non-USA sites). You can tell whether flex generated a 7-bit or an 8-bit scanner by inspecting the flag - summary in the '--verbose' output as described above. + summary in the ‘--verbose’ output as described above. - Note that if you use '-Cfe' or '-CFe' 'flex' still defaults to + Note that if you use ‘-Cfe’ or ‘-CFe’ ‘flex’ still defaults to generating an 8-bit scanner, since usually with these compression options full 8-bit tables are not much more expensive than 7-bit tables. -'-8, --8bit, '%option 8bit'' - instructs 'flex' to generate an 8-bit scanner, i.e., one which can +‘-8, --8bit, ‘%option 8bit’’ + instructs ‘flex’ to generate an 8-bit scanner, i.e., one which can recognize 8-bit characters. This flag is only needed for scanners - generated using '-Cf' or '-CF', as otherwise flex defaults to + generated using ‘-Cf’ or ‘-CF’, as otherwise flex defaults to generating an 8-bit scanner anyway. - See the discussion of '--7bit' above for 'flex''s default behavior + See the discussion of ‘--7bit’ above for ‘flex’'s default behavior and the tradeoffs between 7-bit and 8-bit scanners. -'--default, '%option default'' +‘--default, ‘%option default’’ generate the default rule. -'--always-interactive, '%option always-interactive'' +‘--always-interactive, ‘%option always-interactive’’ instructs flex to generate a scanner which always considers its input _interactive_. Normally, on each new input file the scanner - calls 'isatty()' in an attempt to determine whether the scanner's + calls ‘isatty()’ in an attempt to determine whether the scanner's input source is interactive and thus should be read a character at a time. When this option is used, however, then no such call is made. -'--never-interactive, '--never-interactive'' +‘--never-interactive, ‘--never-interactive’’ instructs flex to generate a scanner which never considers its - input interactive. This is the opposite of 'always-interactive'. + input interactive. This is the opposite of ‘always-interactive’. -'-X, --posix, '%option posix'' +‘-X, --posix, ‘%option posix’’ turns on maximum compatibility with the POSIX 1003.2-1992 - definition of 'lex'. Since 'flex' was originally designed to - implement the POSIX definition of 'lex' this generally involves + definition of ‘lex’. Since ‘flex’ was originally designed to + implement the POSIX definition of ‘lex’ this generally involves very few changes in behavior. At the current writing the known - differences between 'flex' and the POSIX standard are: + differences between ‘flex’ and the POSIX standard are: - * In POSIX and AT&T 'lex', the repeat operator, '{}', has lower - precedence than concatenation (thus 'ab{3}' yields 'ababab'). + • In POSIX and AT&T ‘lex’, the repeat operator, ‘{}’, has lower + precedence than concatenation (thus ‘ab{3}’ yields ‘ababab’). Most POSIX utilities use an Extended Regular Expression (ERE) precedence that has the precedence of the repeat operator - higher than concatenation (which causes 'ab{3}' to yield - 'abbb'). By default, 'flex' places the precedence of the + higher than concatenation (which causes ‘ab{3}’ to yield + ‘abbb’). By default, ‘flex’ places the precedence of the repeat operator higher than concatenation which matches the ERE processing of other POSIX utilities. When either - '--posix' or '-l' are specified, 'flex' will use the + ‘--posix’ or ‘-l’ are specified, ‘flex’ will use the traditional AT&T and POSIX-compliant precedence for the repeat operator where concatenation has higher precedence than the repeat operator. -'--stack, '%option stack'' +‘--stack, ‘%option stack’’ enables the use of start condition stacks (*note Start Conditions::). -'--stdinit, '%option stdinit'' - if set (i.e., %option stdinit) initializes 'yyin' and 'yyout' to - 'stdin' and 'stdout', instead of the default of 'NULL'. Some - existing 'lex' programs depend on this behavior, even though it is - not compliant with ANSI C, which does not require 'stdin' and - 'stdout' to be compile-time constant. In a reentrant scanner, +‘--stdinit, ‘%option stdinit’’ + if set (i.e., %option stdinit) initializes ‘yyin’ and ‘yyout’ to + ‘stdin’ and ‘stdout’, instead of the default of ‘NULL’. Some + existing ‘lex’ programs depend on this behavior, even though it is + not compliant with ANSI C, which does not require ‘stdin’ and + ‘stdout’ to be compile-time constant. In a reentrant scanner, however, this is not a problem since initialization is performed in - 'yylex_init' at runtime. + ‘yylex_init’ at runtime. -'--yylineno, '%option yylineno'' - directs 'flex' to generate a scanner that maintains the number of +‘--yylineno, ‘%option yylineno’’ + directs ‘flex’ to generate a scanner that maintains the number of the current line read from its input in the global variable - 'yylineno'. This option is implied by '%option lex-compat'. In a - reentrant C scanner, the macro 'yylineno' is accessible regardless - of the value of '%option yylineno', however, its value is not - modified by 'flex' unless '%option yylineno' is enabled. + ‘yylineno’. This option is implied by ‘%option lex-compat’. In a + reentrant C scanner, the macro ‘yylineno’ is accessible regardless + of the value of ‘%option yylineno’, however, its value is not + modified by ‘flex’ unless ‘%option yylineno’ is enabled. -'--yywrap, '%option yywrap'' - if unset (i.e., '--noyywrap)', makes the scanner not call - 'yywrap()' upon an end-of-file, but simply assume that there are no - more files to scan (until the user points 'yyin' at a new file and - calls 'yylex()' again). +‘--yywrap, ‘%option yywrap’’ + if unset (i.e., ‘--noyywrap)’, makes the scanner not call + ‘yywrap()’ upon an end-of-file, but simply assume that there are no + more files to scan (until the user points ‘yyin’ at a new file and + calls ‘yylex()’ again).  File: flex.info, Node: Code-Level And API Options, Next: Options for Scanner Speed and Size, Prev: Options Affecting Scanner Behavior, Up: Scanner Options @@ -2281,62 +2280,62 @@ File: flex.info, Node: Code-Level And API Options, Next: Options for Scanner S 16.3 Code-Level And API Options =============================== -'--ansi-definitions, '%option ansi-definitions'' +‘--ansi-definitions, ‘%option ansi-definitions’’ Deprecated, ignored -'--ansi-prototypes, '%option ansi-prototypes'' +‘--ansi-prototypes, ‘%option ansi-prototypes’’ Deprecated, ignored -'--bison-bridge, '%option bison-bridge'' +‘--bison-bridge, ‘%option bison-bridge’’ instructs flex to generate a C scanner that is meant to be called - by a 'GNU bison' parser. The scanner has minor API changes for - 'bison' compatibility. In particular, the declaration of 'yylex' - is modified to take an additional parameter, 'yylval'. *Note Bison + by a ‘GNU bison’ parser. The scanner has minor API changes for + ‘bison’ compatibility. In particular, the declaration of ‘yylex’ + is modified to take an additional parameter, ‘yylval’. *Note Bison Bridge::. -'--bison-locations, '%option bison-locations'' - instruct flex that 'GNU bison' '%locations' are being used. This - means 'yylex' will be passed an additional parameter, 'yylloc'. - This option implies '%option bison-bridge'. *Note Bison Bridge::. +‘--bison-locations, ‘%option bison-locations’’ + instruct flex that ‘GNU bison’ ‘%locations’ are being used. This + means ‘yylex’ will be passed an additional parameter, ‘yylloc’. + This option implies ‘%option bison-bridge’. *Note Bison Bridge::. -'-L, --noline, '%option noline'' - instructs 'flex' not to generate '#line' directives. Without this - option, 'flex' peppers the generated scanner with '#line' +‘-L, --noline, ‘%option noline’’ + instructs ‘flex’ not to generate ‘#line’ directives. Without this + option, ‘flex’ peppers the generated scanner with ‘#line’ directives so error messages in the actions will be correctly - located with respect to either the original 'flex' input file (if - the errors are due to code in the input file), or 'lex.yy.c' (if - the errors are 'flex''s fault - you should report these sorts of + located with respect to either the original ‘flex’ input file (if + the errors are due to code in the input file), or ‘lex.yy.c’ (if + the errors are ‘flex’'s fault - you should report these sorts of errors to the email address given in *note Reporting Bugs::). -'-R, --reentrant, '%option reentrant'' +‘-R, --reentrant, ‘%option reentrant’’ instructs flex to generate a reentrant C scanner. The generated scanner may safely be used in a multi-threaded environment. The API for a reentrant scanner is different than for a non-reentrant scanner *note Reentrant::). Because of the API difference between - reentrant and non-reentrant 'flex' scanners, non-reentrant flex + reentrant and non-reentrant ‘flex’ scanners, non-reentrant flex code must be modified before it is suitable for use with this - option. This option is not compatible with the '--c++' option. + option. This option is not compatible with the ‘--c++’ option. - The option '--reentrant' does not affect the performance of the + The option ‘--reentrant’ does not affect the performance of the scanner. -'-+, --c++, '%option c++'' +‘-+, --c++, ‘%option c++’’ specifies that you want flex to generate a C++ scanner class. *Note Cxx::, for details. -'--array, '%option array'' +‘--array, ‘%option array’’ specifies that you want yytext to be an array instead of a char* -'--pointer, '%option pointer'' - specify that 'yytext' should be a 'char *', not an array. This - default is 'char *'. +‘--pointer, ‘%option pointer’’ + specify that ‘yytext’ should be a ‘char *’, not an array. This + default is ‘char *’. -'-PPREFIX, --prefix=PREFIX, '%option prefix="PREFIX"'' - changes the default 'yy' prefix used by 'flex' for all +‘-PPREFIX, --prefix=PREFIX, ‘%option prefix="PREFIX"’’ + changes the default ‘yy’ prefix used by ‘flex’ for all globally-visible variable and function names to instead be - 'PREFIX'. For example, '--prefix=foo' changes the name of 'yytext' - to 'footext'. It also changes the name of the default output file - from 'lex.yy.c' to 'lex.foo.c'. Here is a partial list of the + ‘PREFIX’. For example, ‘--prefix=foo’ changes the name of ‘yytext’ + to ‘footext’. It also changes the name of the default output file + from ‘lex.yy.c’ to ‘lex.foo.c’. Here is a partial list of the names affected: yy_create_buffer @@ -2358,39 +2357,39 @@ File: flex.info, Node: Code-Level And API Options, Next: Options for Scanner S yyrealloc yyfree - (If you are using a C++ scanner, then only 'yywrap' and - 'yyFlexLexer' are affected.) Within your scanner itself, you can + (If you are using a C++ scanner, then only ‘yywrap’ and + ‘yyFlexLexer’ are affected.) Within your scanner itself, you can still refer to the global variables and functions using either version of their name; but externally, they have the modified name. - This option lets you easily link together multiple 'flex' programs + This option lets you easily link together multiple ‘flex’ programs into the same executable. Note, though, that using this option - also renames 'yywrap()', so you now _must_ either provide your own + also renames ‘yywrap()’, so you now _must_ either provide your own (appropriately-named) version of the routine for your scanner, or - use '%option noyywrap', as linking with '-lfl' no longer provides + use ‘%option noyywrap’, as linking with ‘-lfl’ no longer provides one for you by default. -'--main, '%option main'' - directs flex to provide a default 'main()' program for the scanner, - which simply calls 'yylex()'. This option implies 'noyywrap' (see +‘--main, ‘%option main’’ + directs flex to provide a default ‘main()’ program for the scanner, + which simply calls ‘yylex()’. This option implies ‘noyywrap’ (see below). -'--nounistd, '%option nounistd'' - suppresses inclusion of the non-ANSI header file 'unistd.h'. This - option is meant to target environments in which 'unistd.h' does not +‘--nounistd, ‘%option nounistd’’ + suppresses inclusion of the non-ANSI header file ‘unistd.h’. This + option is meant to target environments in which ‘unistd.h’ does not exist. Be aware that certain options may cause flex to generate - code that relies on functions normally found in 'unistd.h', (e.g. - 'isatty()', 'read()'.) If you wish to use these functions, you + code that relies on functions normally found in ‘unistd.h’, (e.g. + ‘isatty()’, ‘read()’.) If you wish to use these functions, you will have to inform your compiler where to find them. *Note option-always-interactive::. *Note option-read::. -'--yyclass=NAME, '%option yyclass="NAME"'' - only applies when generating a C++ scanner (the '--c++' option). - It informs 'flex' that you have derived 'NAME' as a subclass of - 'yyFlexLexer', so 'flex' will place your actions in the member - function 'foo::yylex()' instead of 'yyFlexLexer::yylex()'. It also - generates a 'yyFlexLexer::yylex()' member function that emits a - run-time error (by invoking 'yyFlexLexer::LexerError())' if called. +‘--yyclass=NAME, ‘%option yyclass="NAME"’’ + only applies when generating a C++ scanner (the ‘--c++’ option). + It informs ‘flex’ that you have derived ‘NAME’ as a subclass of + ‘yyFlexLexer’, so ‘flex’ will place your actions in the member + function ‘foo::yylex()’ instead of ‘yyFlexLexer::yylex()’. It also + generates a ‘yyFlexLexer::yylex()’ member function that emits a + run-time error (by invoking ‘yyFlexLexer::LexerError())’ if called. *Note Cxx::.  @@ -2399,16 +2398,16 @@ File: flex.info, Node: Options for Scanner Speed and Size, Next: Debugging Opt 16.4 Options for Scanner Speed and Size ======================================= -'-C[aefFmr]' +‘-C[aefFmr]’ controls the degree of table compression and, more generally, trade-offs between small scanners and fast scanners. - '-C' - A lone '-C' specifies that the scanner tables should be + ‘-C’ + A lone ‘-C’ specifies that the scanner tables should be compressed but neither equivalence classes nor meta-equivalence classes should be used. - '-Ca, --align, '%option align'' + ‘-Ca, --align, ‘%option align’’ ("align") instructs flex to trade off larger tables in the generated scanner for faster performance because the elements of the tables are better aligned for memory access and @@ -2417,10 +2416,10 @@ File: flex.info, Node: Options for Scanner Speed and Size, Next: Debugging Opt smaller-sized units such as shortwords. This option can quadruple the size of the tables used by your scanner. - '-Ce, --ecs, '%option ecs'' - directs 'flex' to construct "equivalence classes", i.e., sets + ‘-Ce, --ecs, ‘%option ecs’’ + directs ‘flex’ to construct “equivalence classes”, i.e., sets of characters which have identical lexical properties (for - example, if the only appearance of digits in the 'flex' input + example, if the only appearance of digits in the ‘flex’ input is in the character class "[0-9]" then the digits '0', '1', ..., '9' will all be put in the same equivalence class). Equivalence classes usually give dramatic reductions in the @@ -2428,44 +2427,44 @@ File: flex.info, Node: Options for Scanner Speed and Size, Next: Debugging Opt are pretty cheap performance-wise (one array look-up per character scanned). - '-Cf' - specifies that the "full" scanner tables should be generated - - 'flex' should not compress the tables by taking advantages of + ‘-Cf’ + specifies that the “full” scanner tables should be generated - + ‘flex’ should not compress the tables by taking advantages of similar transition functions for different states. - '-CF' + ‘-CF’ specifies that the alternate fast scanner representation - (described above under the '--fast' flag) should be used. - This option cannot be used with '--c++'. + (described above under the ‘--fast’ flag) should be used. + This option cannot be used with ‘--c++’. - '-Cm, --meta-ecs, '%option meta-ecs'' - directs 'flex' to construct "meta-equivalence classes", which + ‘-Cm, --meta-ecs, ‘%option meta-ecs’’ + directs ‘flex’ to construct “meta-equivalence classes”, which are sets of equivalence classes (or characters, if equivalence classes are not being used) that are commonly used together. Meta-equivalence classes are often a big win when using compressed tables, but they have a moderate performance impact - (one or two 'if' tests and one array look-up per character + (one or two ‘if’ tests and one array look-up per character scanned). - '-Cr, --read, '%option read'' + ‘-Cr, --read, ‘%option read’’ causes the generated scanner to _bypass_ use of the standard - I/O library ('stdio') for input. Instead of calling 'fread()' - or 'getc()', the scanner will use the 'read()' system call, + I/O library (‘stdio’) for input. Instead of calling ‘fread()’ + or ‘getc()’, the scanner will use the ‘read()’ system call, resulting in a performance gain which varies from system to system, but in general is probably negligible unless you are - also using '-Cf' or '-CF'. Using '-Cr' can cause strange - behavior if, for example, you read from 'yyin' using 'stdio' + also using ‘-Cf’ or ‘-CF’. Using ‘-Cr’ can cause strange + behavior if, for example, you read from ‘yyin’ using ‘stdio’ prior to calling the scanner (because the scanner will miss - whatever text your previous reads left in the 'stdio' input - buffer). '-Cr' has no effect if you define 'YY_INPUT()' + whatever text your previous reads left in the ‘stdio’ input + buffer). ‘-Cr’ has no effect if you define ‘YY_INPUT()’ (*note Generated Scanner::). - The options '-Cf' or '-CF' and '-Cm' do not make sense together - + The options ‘-Cf’ or ‘-CF’ and ‘-Cm’ do not make sense together - there is no opportunity for meta-equivalence classes if the table is not being compressed. Otherwise the options may be freely mixed, and are cumulative. - The default setting is '-Cem', which specifies that 'flex' should + The default setting is ‘-Cem’, which specifies that ‘flex’ should generate equivalence classes and meta-equivalence classes. This setting provides the highest degree of table compression. You can trade off faster-executing scanners at the cost of larger tables @@ -2485,18 +2484,18 @@ File: flex.info, Node: Options for Scanner Speed and Size, Next: Debugging Opt and compiled the quickest, so during development you will usually want to use the default, maximal compression. - '-Cfe' is often a good compromise between speed and size for + ‘-Cfe’ is often a good compromise between speed and size for production scanners. -'-f, --full, '%option full'' - specifies "fast scanner". No table compression is done and 'stdio' +‘-f, --full, ‘%option full’’ + specifies “fast scanner”. No table compression is done and ‘stdio’ is bypassed. The result is large but fast. This option is - equivalent to '--Cfr' + equivalent to ‘--Cfr’ -'-F, --fast, '%option fast'' +‘-F, --fast, ‘%option fast’’ specifies that the _fast_ scanner table representation should be - used (and 'stdio' bypassed). This representation is about as fast - as the full table representation '--full', and for some sets of + used (and ‘stdio’ bypassed). This representation is about as fast + as the full table representation ‘--full’, and for some sets of patterns will be considerably smaller (and for others, larger). In general, if the pattern set contains both _keywords_ and a catch-all, _identifier_ rule, such as in the set: @@ -2510,10 +2509,10 @@ File: flex.info, Node: Options for Scanner Speed and Size, Next: Debugging Opt then you're better off using the full table representation. If only the _identifier_ rule is present and you then use a hash table or some such to detect the keywords, you're better off using - '--fast'. + ‘--fast’. - This option is equivalent to '-CFr'. It cannot be used with - '--c++'. + This option is equivalent to ‘-CFr’. It cannot be used with + ‘--c++’.  File: flex.info, Node: Debugging Options, Next: Miscellaneous Options, Prev: Options for Scanner Speed and Size, Up: Scanner Options @@ -2521,20 +2520,20 @@ File: flex.info, Node: Debugging Options, Next: Miscellaneous Options, Prev: 16.5 Debugging Options ====================== -'-b, --backup, '%option backup'' - Generate backing-up information to 'lex.backup'. This is a list of +‘-b, --backup, ‘%option backup’’ + Generate backing-up information to ‘lex.backup’. This is a list of scanner states which require backing up and the input characters on which they do so. By adding rules one can remove backing-up - states. If _all_ backing-up states are eliminated and '-Cf' or - '-CF' is used, the generated scanner will run faster (see the - '--perf-report' flag). Only users who wish to squeeze every last + states. If _all_ backing-up states are eliminated and ‘-Cf’ or + ‘-CF’ is used, the generated scanner will run faster (see the + ‘--perf-report’ flag). Only users who wish to squeeze every last cycle out of their scanners need worry about this option. (*note Performance::). -'-d, --debug, '%option debug'' - makes the generated scanner run in "debug" mode. Whenever a - pattern is recognized and the global variable 'yy_flex_debug' is - non-zero (which is the default), the scanner will write to 'stderr' +‘-d, --debug, ‘%option debug’’ + makes the generated scanner run in “debug” mode. Whenever a + pattern is recognized and the global variable ‘yy_flex_debug’ is + non-zero (which is the default), the scanner will write to ‘stderr’ a line of the form: -accepting rule at line 53 ("the matched text") @@ -2546,42 +2545,42 @@ File: flex.info, Node: Debugging Options, Next: Miscellaneous Options, Prev: NUL; at this point, the two look the same as far as the scanner's concerned), or reaches an end-of-file. -'-p, --perf-report, '%option perf-report'' - generates a performance report to 'stderr'. The report consists of - comments regarding features of the 'flex' input file which will +‘-p, --perf-report, ‘%option perf-report’’ + generates a performance report to ‘stderr’. The report consists of + comments regarding features of the ‘flex’ input file which will cause a serious loss of performance in the resulting scanner. If you give the flag twice, you will also get comments regarding features that lead to minor performance losses. - Note that the use of 'REJECT', and variable trailing context (*note + Note that the use of ‘REJECT’, and variable trailing context (*note Limitations::) entails a substantial performance penalty; use of - 'yymore()', the '^' operator, and the '--interactive' flag entail + ‘yymore()’, the ‘^’ operator, and the ‘--interactive’ flag entail minor performance penalties. -'-s, --nodefault, '%option nodefault'' +‘-s, --nodefault, ‘%option nodefault’’ causes the _default rule_ (that unmatched scanner input is echoed - to 'stdout)' to be suppressed. If the scanner encounters input + to ‘stdout)’ to be suppressed. If the scanner encounters input that does not match any of its rules, it aborts with an error. This option is useful for finding holes in a scanner's rule set. -'-T, --trace, '%option trace'' - makes 'flex' run in "trace" mode. It will generate a lot of - messages to 'stderr' concerning the form of the input and the +‘-T, --trace, ‘%option trace’’ + makes ‘flex’ run in “trace” mode. It will generate a lot of + messages to ‘stderr’ concerning the form of the input and the resultant non-deterministic and deterministic finite automata. - This option is mostly for use in maintaining 'flex'. + This option is mostly for use in maintaining ‘flex’. -'-w, --nowarn, '%option nowarn'' +‘-w, --nowarn, ‘%option nowarn’’ suppresses warning messages. -'-v, --verbose, '%option verbose'' - specifies that 'flex' should write to 'stderr' a summary of +‘-v, --verbose, ‘%option verbose’’ + specifies that ‘flex’ should write to ‘stderr’ a summary of statistics regarding the scanner it generates. Most of the - statistics are meaningless to the casual 'flex' user, but the first - line identifies the version of 'flex' (same as reported by - '--version'), and the next line the flags used when generating the + statistics are meaningless to the casual ‘flex’ user, but the first + line identifies the version of ‘flex’ (same as reported by + ‘--version’), and the next line the flags used when generating the scanner, including those that are on by default. -'--warn, '%option warn'' +‘--warn, ‘%option warn’’ warn about certain things. In particular, if the default rule can be matched but no default rule has been given, the flex will warn you. We recommend using this option always. @@ -2592,18 +2591,18 @@ File: flex.info, Node: Miscellaneous Options, Prev: Debugging Options, Up: Sc 16.6 Miscellaneous Options ========================== -'-c' +‘-c’ A do-nothing option included for POSIX compliance. -'-h, -?, --help' - generates a "help" summary of 'flex''s options to 'stdout' and then +‘-h, -?, --help’ + generates a "help" summary of ‘flex’'s options to ‘stdout’ and then exits. -'-n' +‘-n’ Another do-nothing option included for POSIX compliance. -'-V, --version' - prints the version number to 'stdout' and exits. +‘-V, --version’ + prints the version number to ‘stdout’ and exits.  File: flex.info, Node: Performance, Next: Cxx, Prev: Scanner Options, Up: Top @@ -2611,41 +2610,41 @@ File: flex.info, Node: Performance, Next: Cxx, Prev: Scanner Options, Up: To 17 Performance Considerations ***************************** -The main design goal of 'flex' is that it generate high-performance +The main design goal of ‘flex’ is that it generate high-performance scanners. It has been optimized for dealing well with large sets of rules. Aside from the effects on scanner speed of the table compression -'-C' options outlined above, there are a number of options/actions which +‘-C’ options outlined above, there are a number of options/actions which degrade performance. These are, from most expensive to least: REJECT arbitrary trailing context - + pattern sets that require backing up %option yylineno %array - + %option interactive %option always-interactive - + ^ beginning-of-line operator yymore() with the first two all being quite expensive and the last two being -quite cheap. Note also that 'unput()' is implemented as a routine call -that potentially does quite a bit of work, while 'yyless()' is a +quite cheap. Note also that ‘unput()’ is implemented as a routine call +that potentially does quite a bit of work, while ‘yyless()’ is a quite-cheap macro. So if you are just putting back some excess text you -scanned, use 'yyless()'. +scanned, use ‘yyless()’. - 'REJECT' should be avoided at all costs when performance is + ‘REJECT’ should be avoided at all costs when performance is important. It is a particularly expensive option. - There is one case when '%option yylineno' can be expensive. That is + There is one case when ‘%option yylineno’ can be expensive. That is when your patterns match long tokens that could _possibly_ contain a newline character. There is no performance penalty for rules that can not possibly match newlines, since flex does not need to check them for -newlines. In general, you should avoid rules such as '[^f]+', which +newlines. In general, you should avoid rules such as ‘[^f]+’, which match very long tokens, including newlines, and may possibly match your -entire file! A better approach is to separate '[^f]+' into two rules: +entire file! A better approach is to separate ‘[^f]+’ into two rules: %option yylineno %% @@ -2656,7 +2655,7 @@ entire file! A better approach is to separate '[^f]+' into two rules: Getting rid of backing up is messy and often may be an enormous amount of work for a complicated scanner. In principal, one begins by -using the '-b' flag to generate a 'lex.backup' file. For example, on +using the ‘-b’ flag to generate a ‘lex.backup’ file. For example, on the input: %% @@ -2670,19 +2669,19 @@ the input: 2 3 out-transitions: [ o ] jam-transitions: EOF [ \001-n p-\177 ] - + State #8 is non-accepting - associated rule line numbers: 3 out-transitions: [ a ] jam-transitions: EOF [ \001-` b-\177 ] - + State #9 is non-accepting - associated rule line numbers: 3 out-transitions: [ r ] jam-transitions: EOF [ \001-q s-\177 ] - + Compressed tables always back up. The first few lines tell us that there's a scanner state in which it @@ -2692,19 +2691,19 @@ state occurs when trying to match the rules found at lines 2 and 3 in the input file. If the scanner is in that state and then reads something other than an 'o', it will have to back up to find a rule which is matched. With a bit of headscratching one can see that this -must be the state it's in when it has seen 'fo'. When this has -happened, if anything other than another 'o' is seen, the scanner will -have to back up to simply match the 'f' (by the default rule). +must be the state it's in when it has seen ‘fo’. When this has +happened, if anything other than another ‘o’ is seen, the scanner will +have to back up to simply match the ‘f’ (by the default rule). The comment regarding State #8 indicates there's a problem when -'foob' has been scanned. Indeed, on any character other than an 'a', +‘foob’ has been scanned. Indeed, on any character other than an ‘a’, the scanner will have to back up to accept "foo". Similarly, the -comment for State #9 concerns when 'fooba' has been scanned and an 'r' +comment for State #9 concerns when ‘fooba’ has been scanned and an ‘r’ does not follow. The final comment reminds us that there's no point going to all the -trouble of removing backing up from the rules unless we're using '-Cf' -or '-CF', since there's no performance gain doing so with compressed +trouble of removing backing up from the rules unless we're using ‘-Cf’ +or ‘-CF’, since there's no performance gain doing so with compressed scanners. The way to remove the backing up is to add "error" rules: @@ -2712,7 +2711,7 @@ scanners. %% foo return TOK_KEYWORD; foobar return TOK_KEYWORD; - + fooba | foob | fo { @@ -2726,7 +2725,7 @@ using a "catch-all" rule: %% foo return TOK_KEYWORD; foobar return TOK_KEYWORD; - + [a-z]+ return TOK_ID; This is usually the best solution when appropriate. @@ -2735,7 +2734,7 @@ using a "catch-all" rule: it's not uncommon to get hundreds of messages. If one can decipher them, though, it often only takes a dozen or so rules to eliminate the backing up (though it's easy to make a mistake and have an error rule -accidentally match a valid token. A possible future 'flex' feature will +accidentally match a valid token. A possible future ‘flex’ feature will be to automatically add rules to eliminate backing up). It's important to keep in mind that you gain the benefits of @@ -2744,7 +2743,7 @@ up. Leaving just one means you gain nothing. _Variable_ trailing context (where both the leading and trailing parts do not have a fixed length) entails almost the same performance -loss as 'REJECT' (i.e., substantial). So when possible a rule like: +loss as ‘REJECT’ (i.e., substantial). So when possible a rule like: %% mouse|rat/(cat|dog) run(); @@ -2769,15 +2768,15 @@ one that's easier to implement) arises from the fact that the longer the tokens matched, the faster the scanner will run. This is because with long tokens the processing of most input characters takes place in the (short) inner scanning loop, and does not often have to go through the -additional work of setting up the scanning environment (e.g., 'yytext') +additional work of setting up the scanning environment (e.g., ‘yytext’) for the action. Recall the scanner for C comments: %x comment %% int line_num = 1; - + "/*" BEGIN(comment); - + [^*\n]* "*"+[^*/\n]* \n ++line_num; @@ -2788,9 +2787,9 @@ for the action. Recall the scanner for C comments: %x comment %% int line_num = 1; - + "/*" BEGIN(comment); - + [^*\n]* [^*\n]*\n ++line_num; "*"+[^*/\n]* @@ -2803,7 +2802,7 @@ keep the matched text as long as possible. Note that _adding_ rules does _not_ slow down the scanner! The speed of the scanner is independent of the number of rules or (modulo the considerations given at the beginning of this section) how complicated the rules are with -regard to operators such as '*' and '|'. +regard to operators such as ‘*’ and ‘|’. A final example in speeding up a scanner: suppose you want to scan through a file containing identifiers and keywords, one per line and @@ -2817,7 +2816,7 @@ natural first approach is: ... etc ... volatile | while /* it's a keyword */ - + .|\n /* it's not a keyword */ To eliminate the back-tracking, introduce a catch-all rule: @@ -2829,7 +2828,7 @@ natural first approach is: ... etc ... volatile | while /* it's a keyword */ - + [a-z]+ | .|\n /* it's not a keyword */ @@ -2844,18 +2843,18 @@ recognition of newlines with that of the other tokens: ... etc ... volatile\n | while\n /* it's a keyword */ - + [a-z]+\n | .|\n /* it's not a keyword */ One has to be careful here, as we have now reintroduced backing up into the scanner. In particular, while _we_ know that there will never be any characters in the input stream other than letters or newlines, -'flex' can't figure this out, and it will plan for possibly needing to -back up when it has scanned a token like 'auto' and then the next +‘flex’ can't figure this out, and it will plan for possibly needing to +back up when it has scanned a token like ‘auto’ and then the next character is something other than a newline or a letter. Previously it -would then just match the 'auto' rule and be done, but now it has no -'auto' rule, only a 'auto\n' rule. To eliminate the possibility of +would then just match the ‘auto’ rule and be done, but now it has no +‘auto’ rule, only a ‘auto\n’ rule. To eliminate the possibility of backing up, we could either duplicate all rules but without final newlines, or, since we never expect to encounter such an input and therefore don't how it's classified, we can introduce one more catch-all @@ -2868,21 +2867,21 @@ rule, this one which doesn't include a newline: ... etc ... volatile\n | while\n /* it's a keyword */ - + [a-z]+\n | [a-z]+ | .|\n /* it's not a keyword */ - Compiled with '-Cf', this is about as fast as one can get a 'flex' + Compiled with ‘-Cf’, this is about as fast as one can get a ‘flex’ scanner to go for this particular problem. - A final note: 'flex' is slow when matching 'NUL's, particularly when -a token contains multiple 'NUL's. It's best to write rules which match + A final note: ‘flex’ is slow when matching ‘NUL’s, particularly when +a token contains multiple ‘NUL’s. It's best to write rules which match _short_ amounts of text if it's anticipated that the text will often -include 'NUL's. +include ‘NUL’s. Another final note regarding performance: as mentioned in *note -Matching::, dynamically resizing 'yytext' to accommodate huge tokens is +Matching::, dynamically resizing ‘yytext’ to accommodate huge tokens is a slow process because it presently requires that the (huge) token be rescanned from the beginning. Thus if performance is vital, you should attempt to match "large" quantities of text but not "huge" quantities, @@ -2897,158 +2896,158 @@ File: flex.info, Node: Cxx, Next: Reentrant, Prev: Performance, Up: Top *IMPORTANT*: the present form of the scanning class is _experimental_ and may change considerably between major releases. - 'flex' provides two different ways to generate scanners for use with -C++. The first way is to simply compile a scanner generated by 'flex' + ‘flex’ provides two different ways to generate scanners for use with +C++. The first way is to simply compile a scanner generated by ‘flex’ using a C++ compiler instead of a C compiler. You should not encounter any compilation errors (*note Reporting Bugs::). You can then use C++ code in your rule actions instead of C code. Note that the default -input source for your scanner remains 'yyin', and default echoing is -still done to 'yyout'. Both of these remain 'FILE *' variables and not +input source for your scanner remains ‘yyin’, and default echoing is +still done to ‘yyout’. Both of these remain ‘FILE *’ variables and not C++ _streams_. - You can also use 'flex' to generate a C++ scanner class, using the -'-+' option (or, equivalently, '%option c++)', which is automatically -specified if the name of the 'flex' executable ends in a '+', such as -'flex++'. When using this option, 'flex' defaults to generating the -scanner to the file 'lex.yy.cc' instead of 'lex.yy.c'. The generated -scanner includes the header file 'FlexLexer.h', which defines the + You can also use ‘flex’ to generate a C++ scanner class, using the +‘-+’ option (or, equivalently, ‘%option c++)’, which is automatically +specified if the name of the ‘flex’ executable ends in a '+', such as +‘flex++’. When using this option, ‘flex’ defaults to generating the +scanner to the file ‘lex.yy.cc’ instead of ‘lex.yy.c’. The generated +scanner includes the header file ‘FlexLexer.h’, which defines the interface to two C++ classes. - The first class in 'FlexLexer.h', 'FlexLexer', provides an abstract + The first class in ‘FlexLexer.h’, ‘FlexLexer’, provides an abstract base class defining the general scanner class interface. It provides the following member functions: -'const char* YYText()' +‘const char* YYText()’ returns the text of the most recently matched token, the equivalent - of 'yytext'. + of ‘yytext’. -'int YYLeng()' +‘int YYLeng()’ returns the length of the most recently matched token, the - equivalent of 'yyleng'. + equivalent of ‘yyleng’. -'int lineno() const' - returns the current input line number (see '%option yylineno)', or - '1' if '%option yylineno' was not used. +‘int lineno() const’ + returns the current input line number (see ‘%option yylineno)’, or + ‘1’ if ‘%option yylineno’ was not used. -'void set_debug( int flag )' +‘void set_debug( int flag )’ sets the debugging flag for the scanner, equivalent to assigning to - 'yy_flex_debug' (*note Scanner Options::). Note that you must - build the scanner using '%option debug' to include debugging + ‘yy_flex_debug’ (*note Scanner Options::). Note that you must + build the scanner using ‘%option debug’ to include debugging information in it. -'int debug() const' +‘int debug() const’ returns the current setting of the debugging flag. Also provided are member functions equivalent to -'yy_switch_to_buffer()', 'yy_create_buffer()' (though the first argument -is an 'istream&' object reference and not a 'FILE*)', -'yy_flush_buffer()', 'yy_delete_buffer()', and 'yyrestart()' (again, the -first argument is a 'istream&' object reference). +‘yy_switch_to_buffer()’, ‘yy_create_buffer()’ (though the first argument +is an ‘istream&’ object reference and not a ‘FILE*)’, +‘yy_flush_buffer()’, ‘yy_delete_buffer()’, and ‘yyrestart()’ (again, the +first argument is a ‘istream&’ object reference). - The second class defined in 'FlexLexer.h' is 'yyFlexLexer', which is -derived from 'FlexLexer'. It defines the following additional member + The second class defined in ‘FlexLexer.h’ is ‘yyFlexLexer’, which is +derived from ‘FlexLexer’. It defines the following additional member functions: -'yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )' -'yyFlexLexer( istream& arg_yyin, ostream& arg_yyout )' - constructs a 'yyFlexLexer' object using the given streams for input - and output. If not specified, the streams default to 'cin' and - 'cout', respectively. 'yyFlexLexer' does not take ownership of its +‘yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )’ +‘yyFlexLexer( istream& arg_yyin, ostream& arg_yyout )’ + constructs a ‘yyFlexLexer’ object using the given streams for input + and output. If not specified, the streams default to ‘cin’ and + ‘cout’, respectively. ‘yyFlexLexer’ does not take ownership of its stream arguments. It's up to the user to ensure the streams - pointed to remain alive at least as long as the 'yyFlexLexer' + pointed to remain alive at least as long as the ‘yyFlexLexer’ instance. -'virtual int yylex()' - performs the same role is 'yylex()' does for ordinary 'flex' +‘virtual int yylex()’ + performs the same role is ‘yylex()’ does for ordinary ‘flex’ scanners: it scans the input stream, consuming tokens, until a - rule's action returns a value. If you derive a subclass 'S' from - 'yyFlexLexer' and want to access the member functions and variables - of 'S' inside 'yylex()', then you need to use '%option yyclass="S"' - to inform 'flex' that you will be using that subclass instead of - 'yyFlexLexer'. In this case, rather than generating - 'yyFlexLexer::yylex()', 'flex' generates 'S::yylex()' (and also - generates a dummy 'yyFlexLexer::yylex()' that calls - 'yyFlexLexer::LexerError()' if called). + rule's action returns a value. If you derive a subclass ‘S’ from + ‘yyFlexLexer’ and want to access the member functions and variables + of ‘S’ inside ‘yylex()’, then you need to use ‘%option yyclass="S"’ + to inform ‘flex’ that you will be using that subclass instead of + ‘yyFlexLexer’. In this case, rather than generating + ‘yyFlexLexer::yylex()’, ‘flex’ generates ‘S::yylex()’ (and also + generates a dummy ‘yyFlexLexer::yylex()’ that calls + ‘yyFlexLexer::LexerError()’ if called). -'virtual void switch_streams(istream* new_in = 0, ostream* new_out = 0)' -'virtual void switch_streams(istream& new_in, ostream& new_out)' - reassigns 'yyin' to 'new_in' (if non-null) and 'yyout' to 'new_out' - (if non-null), deleting the previous input buffer if 'yyin' is +‘virtual void switch_streams(istream* new_in = 0, ostream* new_out = 0)’ +‘virtual void switch_streams(istream& new_in, ostream& new_out)’ + reassigns ‘yyin’ to ‘new_in’ (if non-null) and ‘yyout’ to ‘new_out’ + (if non-null), deleting the previous input buffer if ‘yyin’ is reassigned. -'int yylex( istream* new_in, ostream* new_out = 0 )' -'int yylex( istream& new_in, ostream& new_out )' - first switches the input streams via 'switch_streams( new_in, - new_out )' and then returns the value of 'yylex()'. +‘int yylex( istream* new_in, ostream* new_out = 0 )’ +‘int yylex( istream& new_in, ostream& new_out )’ + first switches the input streams via ‘switch_streams( new_in, + new_out )’ and then returns the value of ‘yylex()’. - In addition, 'yyFlexLexer' defines the following protected virtual + In addition, ‘yyFlexLexer’ defines the following protected virtual functions which you can redefine in derived classes to tailor the scanner: -'virtual int LexerInput( char* buf, int max_size )' - reads up to 'max_size' characters into 'buf' and returns the number +‘virtual int LexerInput( char* buf, int max_size )’ + reads up to ‘max_size’ characters into ‘buf’ and returns the number of characters read. To indicate end-of-input, return 0 characters. - Note that 'interactive' scanners (see the '-B' and '-I' flags in - *note Scanner Options::) define the macro 'YY_INTERACTIVE'. If you - redefine 'LexerInput()' and need to take different actions + Note that ‘interactive’ scanners (see the ‘-B’ and ‘-I’ flags in + *note Scanner Options::) define the macro ‘YY_INTERACTIVE’. If you + redefine ‘LexerInput()’ and need to take different actions depending on whether or not the scanner might be scanning an interactive input source, you can test for the presence of this - name via '#ifdef' statements. + name via ‘#ifdef’ statements. -'virtual void LexerOutput( const char* buf, int size )' - writes out 'size' characters from the buffer 'buf', which, while - 'NUL'-terminated, may also contain internal 'NUL's if the scanner's - rules can match text with 'NUL's in them. +‘virtual void LexerOutput( const char* buf, int size )’ + writes out ‘size’ characters from the buffer ‘buf’, which, while + ‘NUL’-terminated, may also contain internal ‘NUL’s if the scanner's + rules can match text with ‘NUL’s in them. -'virtual void LexerError( const char* msg )' +‘virtual void LexerError( const char* msg )’ reports a fatal error message. The default version of this - function writes the message to the stream 'cerr' and exits. + function writes the message to the stream ‘cerr’ and exits. - Note that a 'yyFlexLexer' object contains its _entire_ scanning + Note that a ‘yyFlexLexer’ object contains its _entire_ scanning state. Thus you can use such objects to create reentrant scanners, but see also *note Reentrant::. You can instantiate multiple instances of -the same 'yyFlexLexer' class, and you can also combine multiple C++ -scanner classes together in the same program using the '-P' option +the same ‘yyFlexLexer’ class, and you can also combine multiple C++ +scanner classes together in the same program using the ‘-P’ option discussed above. - Finally, note that the '%array' feature is not available to C++ -scanner classes; you must use '%pointer' (the default). + Finally, note that the ‘%array’ feature is not available to C++ +scanner classes; you must use ‘%pointer’ (the default). Here is an example of a simple C++ scanner: // An example of using the flex C++ scanner class. - + %{ #include using namespace std; int mylineno = 0; %} - + %option noyywrap c++ - + string \"[^\n"]+\" - + ws [ \t]+ - + alpha [A-Za-z] dig [0-9] name ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])* num1 [-+]?{dig}+\.?([eE][-+]?{dig}+)? num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)? number {num1}|{num2} - + %% - + {ws} /* skip blanks and tabs */ - + "/*" { int c; - + while((c = yyinput()) != 0) { if(c == '\n') ++mylineno; - + else if(c == '*') { if((c = yyinput()) == '/') @@ -3058,20 +3057,20 @@ scanner classes; you must use '%pointer' (the default). } } } - + {number} cout << "number " << YYText() << '\n'; - + \n mylineno++; - + {name} cout << "name " << YYText() << '\n'; - + {string} cout << "string " << YYText() << '\n'; - + %% - + // This include is required if main() is an another source file. //#include - + int main( int /* argc */, char** /* argv */ ) { FlexLexer* lexer = new yyFlexLexer; @@ -3081,20 +3080,20 @@ scanner classes; you must use '%pointer' (the default). } If you want to create multiple (different) lexer classes, you use the -'-P' flag (or the 'prefix=' option) to rename each 'yyFlexLexer' to some -other 'xxFlexLexer'. You then can include '' in your other -sources once per lexer class, first renaming 'yyFlexLexer' as follows: +‘-P’ flag (or the ‘prefix=’ option) to rename each ‘yyFlexLexer’ to some +other ‘xxFlexLexer’. You then can include ‘’ in your other +sources once per lexer class, first renaming ‘yyFlexLexer’ as follows: #undef yyFlexLexer #define yyFlexLexer xxFlexLexer #include - + #undef yyFlexLexer #define yyFlexLexer zzFlexLexer #include - if, for example, you used '%option prefix="xx"' for one of your -scanners and '%option prefix="zz"' for the other. + if, for example, you used ‘%option prefix="xx"’ for one of your +scanners and ‘%option prefix="zz"’ for the other.  File: flex.info, Node: Reentrant, Next: Lex and Posix, Prev: Cxx, Up: Top @@ -3102,21 +3101,21 @@ File: flex.info, Node: Reentrant, Next: Lex and Posix, Prev: Cxx, Up: Top 19 Reentrant C Scanners *********************** -'flex' has the ability to generate a reentrant C scanner. This is -accomplished by specifying '%option reentrant' ('-R') The generated +‘flex’ has the ability to generate a reentrant C scanner. This is +accomplished by specifying ‘%option reentrant’ (‘-R’) The generated scanner is both portable, and safe to use in one or more separate threads of control. The most common use for reentrant scanners is from within multi-threaded applications. Any thread may create and execute a -reentrant 'flex' scanner without the need for synchronization with other +reentrant ‘flex’ scanner without the need for synchronization with other threads. * Menu: -* Reentrant Uses:: -* Reentrant Overview:: -* Reentrant Example:: -* Reentrant Detail:: -* Reentrant Functions:: +* Reentrant Uses:: +* Reentrant Overview:: +* Reentrant Example:: +* Reentrant Detail:: +* Reentrant Functions::  File: flex.info, Node: Reentrant Uses, Next: Reentrant Overview, Prev: Reentrant, Up: Reentrant @@ -3125,44 +3124,44 @@ File: flex.info, Node: Reentrant Uses, Next: Reentrant Overview, Prev: Reentr ================================ However, there are other uses for a reentrant scanner. For example, you -could scan two or more files simultaneously to implement a 'diff' at the +could scan two or more files simultaneously to implement a ‘diff’ at the token level (i.e., instead of at the character level): /* Example of maintaining more than one active scanner. */ - + do { int tok1, tok2; - + tok1 = yylex( scanner_1 ); tok2 = yylex( scanner_2 ); - + if( tok1 != tok2 ) printf("Files are different."); - + } while ( tok1 && tok2 ); Another use for a reentrant scanner is recursion. (Note that a recursive scanner can also be created using a non-reentrant scanner and buffer states. *Note Multiple Input Buffers::.) - The following crude scanner supports the 'eval' command by invoking + The following crude scanner supports the ‘eval’ command by invoking another instance of itself. /* Example of recursive invocation. */ - + %option reentrant - + %% "eval(".+")" { yyscan_t scanner; YY_BUFFER_STATE buf; - + yylex_init( &scanner ); yytext[yyleng-1] = ' '; - + buf = yy_scan_string( yytext + 5, scanner ); yylex( scanner ); - + yy_delete_buffer(buf,scanner); yylex_destroy( scanner ); } @@ -3178,20 +3177,20 @@ File: flex.info, Node: Reentrant Overview, Next: Reentrant Example, Prev: Ree The API for reentrant scanners is different than for non-reentrant scanners. Here is a quick overview of the API: - '%option reentrant' must be specified. + ‘%option reentrant’ must be specified. - * All functions take one additional argument: 'yyscanner' + • All functions take one additional argument: ‘yyscanner’ - * All global variables are replaced by their macro equivalents. (We + • All global variables are replaced by their macro equivalents. (We tell you this because it may be important to you during debugging.) - * 'yylex_init' and 'yylex_destroy' must be called before and after - 'yylex', respectively. + • ‘yylex_init’ and ‘yylex_destroy’ must be called before and after + ‘yylex’, respectively. - * Accessor methods (get/set functions) provide access to common - 'flex' variables. + • Accessor methods (get/set functions) provide access to common + ‘flex’ variables. - * User-specific data can be stored in 'yyextra'. + • User-specific data can be stored in ‘yyextra’.  File: flex.info, Node: Reentrant Example, Next: Reentrant Detail, Prev: Reentrant Overview, Up: Reentrant @@ -3201,24 +3200,24 @@ File: flex.info, Node: Reentrant Example, Next: Reentrant Detail, Prev: Reent First, an example of a reentrant scanner: /* This scanner prints "//" comments. */ - + %option reentrant stack noyywrap %x COMMENT - + %% - + "//" yy_push_state( COMMENT, yyscanner); .|\n - + \n yy_pop_state( yyscanner ); [^\n]+ fprintf( yyout, "%s\n", yytext); - + %% - + int main ( int argc, char * argv[] ) { yyscan_t scanner; - + yylex_init ( &scanner ); yylex ( scanner ); yylex_destroy ( scanner ); @@ -3232,17 +3231,17 @@ File: flex.info, Node: Reentrant Detail, Next: Reentrant Functions, Prev: Ree ================================ Here are the things you need to do or know to use the reentrant C API of -'flex'. +‘flex’. * Menu: -* Specify Reentrant:: -* Extra Reentrant Argument:: -* Global Replacement:: -* Init and Destroy Functions:: -* Accessor Methods:: -* Extra Data:: -* About yyscan_t:: +* Specify Reentrant:: +* Extra Reentrant Argument:: +* Global Replacement:: +* Init and Destroy Functions:: +* Accessor Methods:: +* Extra Data:: +* About yyscan_t::  File: flex.info, Node: Specify Reentrant, Next: Extra Reentrant Argument, Prev: Reentrant Detail, Up: Reentrant Detail @@ -3252,10 +3251,10 @@ File: flex.info, Node: Specify Reentrant, Next: Extra Reentrant Argument, Pre %option reentrant (-reentrant) must be specified. - Notice that '%option reentrant' is specified in the above example -(*note Reentrant Example::. Had this option not been specified, 'flex' + Notice that ‘%option reentrant’ is specified in the above example +(*note Reentrant Example::. Had this option not been specified, ‘flex’ would have happily generated a non-reentrant scanner without -complaining. You may explicitly specify '%option noreentrant', if you +complaining. You may explicitly specify ‘%option noreentrant’, if you do _not_ want a reentrant scanner, although it is not necessary. The default is to generate a non-reentrant scanner. @@ -3265,25 +3264,25 @@ File: flex.info, Node: Extra Reentrant Argument, Next: Global Replacement, Pr 19.4.2 The Extra Argument ------------------------- -All functions take one additional argument: 'yyscanner'. +All functions take one additional argument: ‘yyscanner’. - Notice that the calls to 'yy_push_state' and 'yy_pop_state' both have -an argument, 'yyscanner' , that is not present in a non-reentrant -scanner. Here are the declarations of 'yy_push_state' and -'yy_pop_state' in the reentrant scanner: + Notice that the calls to ‘yy_push_state’ and ‘yy_pop_state’ both have +an argument, ‘yyscanner’ , that is not present in a non-reentrant +scanner. Here are the declarations of ‘yy_push_state’ and +‘yy_pop_state’ in the reentrant scanner: static void yy_push_state ( int new_state , yyscan_t yyscanner ) ; static void yy_pop_state ( yyscan_t yyscanner ) ; - Notice that the argument 'yyscanner' appears in the declaration of -both functions. In fact, all 'flex' functions in a reentrant scanner + Notice that the argument ‘yyscanner’ appears in the declaration of +both functions. In fact, all ‘flex’ functions in a reentrant scanner have this additional argument. It is always the last argument in the -argument list, it is always of type 'yyscan_t' (which is typedef'd to -'void *') and it is always named 'yyscanner'. As you may have guessed, -'yyscanner' is a pointer to an opaque data structure encapsulating the +argument list, it is always of type ‘yyscan_t’ (which is typedef'd to +‘void *’) and it is always named ‘yyscanner’. As you may have guessed, +‘yyscanner’ is a pointer to an opaque data structure encapsulating the current state of the scanner. For a list of function declarations, see *note Reentrant Functions::. Note that preprocessor macros, such as -'BEGIN', 'ECHO', and 'REJECT', do not take this additional argument. +‘BEGIN’, ‘ECHO’, and ‘REJECT’, do not take this additional argument.  File: flex.info, Node: Global Replacement, Next: Init and Destroy Functions, Prev: Extra Reentrant Argument, Up: Reentrant Detail @@ -3294,11 +3293,11 @@ File: flex.info, Node: Global Replacement, Next: Init and Destroy Functions, All global variables in traditional flex have been replaced by macro equivalents. - Note that in the above example, 'yyout' and 'yytext' are not plain + Note that in the above example, ‘yyout’ and ‘yytext’ are not plain variables. These are macros that will expand to their equivalent -lvalue. All of the familiar 'flex' globals have been replaced by their -macro equivalents. In particular, 'yytext', 'yyleng', 'yylineno', -'yyin', 'yyout', 'yyextra', 'yylval', and 'yylloc' are macros. You may +lvalue. All of the familiar ‘flex’ globals have been replaced by their +macro equivalents. In particular, ‘yytext’, ‘yyleng’, ‘yylineno’, +‘yyin’, ‘yyout’, ‘yyextra’, ‘yylval’, and ‘yylloc’ are macros. You may safely use these macros in actions as if they were plain variables. We only tell you this so you don't expect to link to these variables externally. Currently, each macro expands to a member of an internal @@ -3306,10 +3305,10 @@ struct, e.g., #define yytext (((struct yyguts_t*)yyscanner)->yytext_r) - One important thing to remember about 'yytext' and friends is that -'yytext' is not a global variable in a reentrant scanner, you can not + One important thing to remember about ‘yytext’ and friends is that +‘yytext’ is not a global variable in a reentrant scanner, you can not access it directly from outside an action or from other functions. You -must use an accessor method, e.g., 'yyget_text', to accomplish this. +must use an accessor method, e.g., ‘yyget_text’, to accomplish this. (See below).  @@ -3318,44 +3317,44 @@ File: flex.info, Node: Init and Destroy Functions, Next: Accessor Methods, Pr 19.4.4 Init and Destroy Functions --------------------------------- -'yylex_init' and 'yylex_destroy' must be called before and after -'yylex', respectively. +‘yylex_init’ and ‘yylex_destroy’ must be called before and after +‘yylex’, respectively. int yylex_init ( yyscan_t * ptr_yy_globals ) ; int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t * ptr_yy_globals ) ; int yylex ( yyscan_t yyscanner ) ; int yylex_destroy ( yyscan_t yyscanner ) ; - The function 'yylex_init' must be called before calling any other -function. The argument to 'yylex_init' is the address of an -uninitialized pointer to be filled in by 'yylex_init', overwriting any -previous contents. The function 'yylex_init_extra' may be used instead, -taking as its first argument a variable of type 'YY_EXTRA_TYPE'. See + The function ‘yylex_init’ must be called before calling any other +function. The argument to ‘yylex_init’ is the address of an +uninitialized pointer to be filled in by ‘yylex_init’, overwriting any +previous contents. The function ‘yylex_init_extra’ may be used instead, +taking as its first argument a variable of type ‘YY_EXTRA_TYPE’. See the section on yyextra, below, for more details. - The value stored in 'ptr_yy_globals' should thereafter be passed to -'yylex' and 'yylex_destroy'. Flex does not save the argument passed to -'yylex_init', so it is safe to pass the address of a local pointer to -'yylex_init' so long as it remains in scope for the duration of all -calls to the scanner, up to and including the call to 'yylex_destroy'. + The value stored in ‘ptr_yy_globals’ should thereafter be passed to +‘yylex’ and ‘yylex_destroy’. Flex does not save the argument passed to +‘yylex_init’, so it is safe to pass the address of a local pointer to +‘yylex_init’ so long as it remains in scope for the duration of all +calls to the scanner, up to and including the call to ‘yylex_destroy’. - The function 'yylex' should be familiar to you by now. The reentrant + The function ‘yylex’ should be familiar to you by now. The reentrant version takes one argument, which is the value returned (via an -argument) by 'yylex_init'. Otherwise, it behaves the same as the -non-reentrant version of 'yylex'. +argument) by ‘yylex_init’. Otherwise, it behaves the same as the +non-reentrant version of ‘yylex’. - Both 'yylex_init' and 'yylex_init_extra' returns 0 (zero) on success, + Both ‘yylex_init’ and ‘yylex_init_extra’ returns 0 (zero) on success, or non-zero on failure, in which case errno is set to one of the following values: - * ENOMEM Memory allocation error. *Note memory-management::. - * EINVAL Invalid argument. + • ENOMEM Memory allocation error. *Note memory-management::. + • EINVAL Invalid argument. - The function 'yylex_destroy' should be called to free resources used -by the scanner. After 'yylex_destroy' is called, the contents of -'yyscanner' should not be used. Of course, there is no need to destroy -a scanner if you plan to reuse it. A 'flex' scanner (both reentrant and -non-reentrant) may be restarted by calling 'yyrestart'. + The function ‘yylex_destroy’ should be called to free resources used +by the scanner. After ‘yylex_destroy’ is called, the contents of +‘yyscanner’ should not be used. Of course, there is no need to destroy +a scanner if you plan to reuse it. A ‘flex’ scanner (both reentrant and +non-reentrant) may be restarted by calling ‘yyrestart’. Below is an example of a program that creates a scanner, uses it, then destroys it when done: @@ -3364,12 +3363,12 @@ then destroys it when done: { yyscan_t scanner; int tok; - + yylex_init(&scanner); - + while ((tok=yylex(scanner)) > 0) printf("tok=%d yytext=%s\n", tok, yyget_text(scanner)); - + yylex_destroy(scanner); return 0; } @@ -3380,17 +3379,17 @@ File: flex.info, Node: Accessor Methods, Next: Extra Data, Prev: Init and Des 19.4.5 Accessing Variables with Reentrant Scanners -------------------------------------------------- -Accessor methods (get/set functions) provide access to common 'flex' +Accessor methods (get/set functions) provide access to common ‘flex’ variables. Many scanners that you build will be part of a larger project. -Portions of your project will need access to 'flex' values, such as -'yytext'. In a non-reentrant scanner, these values are global, so there +Portions of your project will need access to ‘flex’ values, such as +‘yytext’. In a non-reentrant scanner, these values are global, so there is no problem accessing them. However, in a reentrant scanner, there -are no global 'flex' values. You can not access them directly. -Instead, you must access 'flex' values using accessor methods (get/set -functions). Each accessor method is named 'yyget_NAME' or 'yyset_NAME', -where 'NAME' is the name of the 'flex' variable you want. For example: +are no global ‘flex’ values. You can not access them directly. +Instead, you must access ‘flex’ values using accessor methods (get/set +functions). Each accessor method is named ‘yyget_NAME’ or ‘yyset_NAME’, +where ‘NAME’ is the name of the ‘flex’ variable you want. For example: /* Set the last character of yytext to NULL. */ void chop ( yyscan_t scanner ) @@ -3404,7 +3403,7 @@ where 'NAME' is the name of the 'flex' variable you want. For example: %% .+\n { chop( yyscanner );} - You may find that '%option header-file' is particularly useful for + You may find that ‘%option header-file’ is particularly useful for generating prototypes of all the accessor functions. *Note option-header::. @@ -3414,7 +3413,7 @@ File: flex.info, Node: Extra Data, Next: About yyscan_t, Prev: Accessor Metho 19.4.6 Extra Data ----------------- -User-specific data can be stored in 'yyextra'. +User-specific data can be stored in ‘yyextra’. In a reentrant scanner, it is unwise to use global variables to communicate with or maintain state between different pieces of your @@ -3422,23 +3421,23 @@ program. However, you may need access to external data or invoke external functions from within the scanner actions. Likewise, you may need to pass information to your scanner (e.g., open file descriptors, or database connections). In a non-reentrant scanner, the only way to -do this would be through the use of global variables. 'Flex' allows you +do this would be through the use of global variables. ‘Flex’ allows you to store arbitrary, "extra" data in a scanner. This data is accessible -through the accessor methods 'yyget_extra' and 'yyset_extra' from -outside the scanner, and through the shortcut macro 'yyextra' from +through the accessor methods ‘yyget_extra’ and ‘yyset_extra’ from +outside the scanner, and through the shortcut macro ‘yyextra’ from within the scanner itself. They are defined as follows: #define YY_EXTRA_TYPE void* YY_EXTRA_TYPE yyget_extra ( yyscan_t scanner ); void yyset_extra ( YY_EXTRA_TYPE arbitrary_data , yyscan_t scanner); - In addition, an extra form of 'yylex_init' is provided, -'yylex_init_extra'. This function is provided so that the yyextra value + In addition, an extra form of ‘yylex_init’ is provided, +‘yylex_init_extra’. This function is provided so that the yyextra value can be accessed from within the very first yyalloc, used to allocate the scanner itself. - By default, 'YY_EXTRA_TYPE' is defined as type 'void *'. You may -redefine this type using '%option extra-type="your_type"' in the + By default, ‘YY_EXTRA_TYPE’ is defined as type ‘void *’. You may +redefine this type using ‘%option extra-type="your_type"’ in the scanner: /* An example of overriding YY_EXTRA_TYPE. */ @@ -3449,7 +3448,7 @@ scanner: %option reentrant %option extra-type="struct stat *" %% - + __filesize__ printf( "%ld", yyextra->st_size ); __lastmod__ printf( "%ld", yyextra->st_mtime ); %% @@ -3458,15 +3457,15 @@ scanner: yyscan_t scanner; struct stat buf; FILE *in; - + in = fopen( filename, "r" ); stat( filename, &buf ); - + yylex_init_extra( buf, &scanner ); yyset_in( in, scanner ); yylex( scanner ); yylex_destroy( scanner ); - + fclose( in ); } @@ -3476,13 +3475,13 @@ File: flex.info, Node: About yyscan_t, Prev: Extra Data, Up: Reentrant Detail 19.4.7 About yyscan_t --------------------- -'yyscan_t' is defined as: +‘yyscan_t’ is defined as: typedef void* yyscan_t; - It is initialized by 'yylex_init()' to point to an internal + It is initialized by ‘yylex_init()’ to point to an internal structure. You should never access this value directly. In particular, -you should never attempt to free it (use 'yylex_destroy()' instead.) +you should never attempt to free it (use ‘yylex_destroy()’ instead.)  File: flex.info, Node: Reentrant Functions, Prev: Reentrant Detail, Up: Reentrant @@ -3499,7 +3498,7 @@ The following Functions are available in a reentrant scanner: int yyget_lineno ( yyscan_t scanner ); YY_EXTRA_TYPE yyget_extra ( yyscan_t scanner ); int yyget_debug ( yyscan_t scanner ); - + void yyset_debug ( int flag, yyscan_t scanner ); void yyset_in ( FILE * in_str , yyscan_t scanner ); void yyset_out ( FILE * out_str , yyscan_t scanner ); @@ -3522,27 +3521,27 @@ scanner: In a reentrant C scanner, support for yylineno is always present (i.e., you may access yylineno), but the value is never modified by -'flex' unless '%option yylineno' is enabled. This is to allow the user -to maintain the line count independently of 'flex'. +‘flex’ unless ‘%option yylineno’ is enabled. This is to allow the user +to maintain the line count independently of ‘flex’. - The following functions and macros are made available when '%option -bison-bridge' ('--bison-bridge') is specified: + The following functions and macros are made available when ‘%option +bison-bridge’ (‘--bison-bridge’) is specified: YYSTYPE * yyget_lval ( yyscan_t scanner ); void yyset_lval ( YYSTYPE * yylvalp , yyscan_t scanner ); yylval - The following functions and macros are made available when '%option -bison-locations' ('--bison-locations') is specified: + The following functions and macros are made available when ‘%option +bison-locations’ (‘--bison-locations’) is specified: YYLTYPE *yyget_lloc ( yyscan_t scanner ); void yyset_lloc ( YYLTYPE * yyllocp , yyscan_t scanner ); yylloc - Support for yylval assumes that 'YYSTYPE' is a valid type. Support -for yylloc assumes that 'YYSLYPE' is a valid type. Typically, these -types are generated by 'bison', and are included in section 1 of the -'flex' input. + Support for yylval assumes that ‘YYSTYPE’ is a valid type. Support +for yylloc assumes that ‘YYSLYPE’ is a valid type. Typically, these +types are generated by ‘bison’, and are included in section 1 of the +‘flex’ input.  File: flex.info, Node: Lex and Posix, Next: Memory Management, Prev: Reentrant, Up: Top @@ -3550,46 +3549,46 @@ File: flex.info, Node: Lex and Posix, Next: Memory Management, Prev: Reentran 20 Incompatibilities with Lex and Posix *************************************** -'flex' is a rewrite of the AT&T Unix _lex_ tool (the two implementations +‘flex’ is a rewrite of the AT&T Unix _lex_ tool (the two implementations do not share any code, though), with some extensions and incompatibilities, both of which are of concern to those who wish to -write scanners acceptable to both implementations. 'flex' is fully -compliant with the POSIX 'lex' specification, except that when using -'%pointer' (the default), a call to 'unput()' destroys the contents of -'yytext', which is counter to the POSIX specification. In this section -we discuss all of the known areas of incompatibility between 'flex', -AT&T 'lex', and the POSIX specification. 'flex''s '-l' option turns on -maximum compatibility with the original AT&T 'lex' implementation, at +write scanners acceptable to both implementations. ‘flex’ is fully +compliant with the POSIX ‘lex’ specification, except that when using +‘%pointer’ (the default), a call to ‘unput()’ destroys the contents of +‘yytext’, which is counter to the POSIX specification. In this section +we discuss all of the known areas of incompatibility between ‘flex’, +AT&T ‘lex’, and the POSIX specification. ‘flex’'s ‘-l’ option turns on +maximum compatibility with the original AT&T ‘lex’ implementation, at the cost of a major loss in the generated scanner's performance. We -note below which incompatibilities can be overcome using the '-l' -option. 'flex' is fully compatible with 'lex' with the following +note below which incompatibilities can be overcome using the ‘-l’ +option. ‘flex’ is fully compatible with ‘lex’ with the following exceptions: - * The undocumented 'lex' scanner internal variable 'yylineno' is not - supported unless '-l' or '%option yylineno' is used. + • The undocumented ‘lex’ scanner internal variable ‘yylineno’ is not + supported unless ‘-l’ or ‘%option yylineno’ is used. - * 'yylineno' should be maintained on a per-buffer basis, rather than + • ‘yylineno’ should be maintained on a per-buffer basis, rather than a per-scanner (single global variable) basis. - * 'yylineno' is not part of the POSIX specification. + • ‘yylineno’ is not part of the POSIX specification. - * The 'input()' routine is not redefinable, though it may be called + • The ‘input()’ routine is not redefinable, though it may be called to read characters following whatever has been matched by a rule. - If 'input()' encounters an end-of-file the normal 'yywrap()' - processing is done. A "real" end-of-file is returned by 'input()' - as 'EOF'. + If ‘input()’ encounters an end-of-file the normal ‘yywrap()’ + processing is done. A "real" end-of-file is returned by ‘input()’ + as ‘EOF’. - * Input is instead controlled by defining the 'YY_INPUT()' macro. + • Input is instead controlled by defining the ‘YY_INPUT()’ macro. - * The 'flex' restriction that 'input()' cannot be redefined is in + • The ‘flex’ restriction that ‘input()’ cannot be redefined is in accordance with the POSIX specification, which simply does not specify any way of controlling the scanner's input other than by - making an initial assignment to 'yyin'. + making an initial assignment to ‘yyin’. - * The 'unput()' routine is not redefinable. This restriction is in + • The ‘unput()’ routine is not redefinable. This restriction is in accordance with POSIX. - * 'flex' scanners are not as reentrant as 'lex' scanners. In + • ‘flex’ scanners are not as reentrant as ‘lex’ scanners. In particular, if you have an interactive scanner and an interrupt handler which long-jumps out of the scanner, and the scanner is subsequently called again, you may get the following message: @@ -3602,117 +3601,117 @@ exceptions: Note that this call will throw away any buffered input; usually this isn't a problem with an interactive scanner. *Note - Reentrant::, for 'flex''s reentrant API. + Reentrant::, for ‘flex’'s reentrant API. - * Also note that 'flex' C++ scanner classes _are_ reentrant, so if + • Also note that ‘flex’ C++ scanner classes _are_ reentrant, so if using C++ is an option for you, you should use them instead. *Note Cxx::, and *note Reentrant:: for details. - * 'output()' is not supported. Output from the ECHO macro is done to - the file-pointer 'yyout' (default 'stdout)'. + • ‘output()’ is not supported. Output from the ECHO macro is done to + the file-pointer ‘yyout’ (default ‘stdout)’. - * 'output()' is not part of the POSIX specification. + • ‘output()’ is not part of the POSIX specification. - * 'lex' does not support exclusive start conditions (%x), though they + • ‘lex’ does not support exclusive start conditions (%x), though they are in the POSIX specification. - * When definitions are expanded, 'flex' encloses them in parentheses. - With 'lex', the following: + • When definitions are expanded, ‘flex’ encloses them in parentheses. + With ‘lex’, the following: NAME [A-Z][A-Z0-9]* %% foo{NAME}? printf( "Found it\n" ); %% - will not match the string 'foo' because when the macro is expanded - the rule is equivalent to 'foo[A-Z][A-Z0-9]*?' and the precedence - is such that the '?' is associated with '[A-Z0-9]*'. With 'flex', - the rule will be expanded to 'foo([A-Z][A-Z0-9]*)?' and so the - string 'foo' will match. + will not match the string ‘foo’ because when the macro is expanded + the rule is equivalent to ‘foo[A-Z][A-Z0-9]*?’ and the precedence + is such that the ‘?’ is associated with ‘[A-Z0-9]*’. With ‘flex’, + the rule will be expanded to ‘foo([A-Z][A-Z0-9]*)?’ and so the + string ‘foo’ will match. - * Note that if the definition begins with '^' or ends with '$' then + • Note that if the definition begins with ‘^’ or ends with ‘$’ then it is _not_ expanded with parentheses, to allow these operators to appear in definitions without losing their special meanings. But - the '', '/', and '<>' operators cannot be used in a 'flex' + the ‘’, ‘/’, and ‘<>’ operators cannot be used in a ‘flex’ definition. - * Using '-l' results in the 'lex' behavior of no parentheses around + • Using ‘-l’ results in the ‘lex’ behavior of no parentheses around the definition. - * The POSIX specification is that the definition be enclosed in + • The POSIX specification is that the definition be enclosed in parentheses. - * Some implementations of 'lex' allow a rule's action to begin on a + • Some implementations of ‘lex’ allow a rule's action to begin on a separate line, if the rule's pattern has trailing whitespace: %% foo|bar { foobar_action();} - 'flex' does not support this feature. + ‘flex’ does not support this feature. - * The 'lex' '%r' (generate a Ratfor scanner) option is not supported. + • The ‘lex’ ‘%r’ (generate a Ratfor scanner) option is not supported. It is not part of the POSIX specification. - * After a call to 'unput()', _yytext_ is undefined until the next - token is matched, unless the scanner was built using '%array'. - This is not the case with 'lex' or the POSIX specification. The - '-l' option does away with this incompatibility. + • After a call to ‘unput()’, _yytext_ is undefined until the next + token is matched, unless the scanner was built using ‘%array’. + This is not the case with ‘lex’ or the POSIX specification. The + ‘-l’ option does away with this incompatibility. - * The precedence of the '{,}' (numeric range) operator is different. - The AT&T and POSIX specifications of 'lex' interpret 'abc{1,3}' as - match one, two, or three occurrences of 'abc'", whereas 'flex' - interprets it as "match 'ab' followed by one, two, or three - occurrences of 'c'". The '-l' and '--posix' options do away with + • The precedence of the ‘{,}’ (numeric range) operator is different. + The AT&T and POSIX specifications of ‘lex’ interpret ‘abc{1,3}’ as + match one, two, or three occurrences of ‘abc’", whereas ‘flex’ + interprets it as "match ‘ab’ followed by one, two, or three + occurrences of ‘c’". The ‘-l’ and ‘--posix’ options do away with this incompatibility. - * The precedence of the '^' operator is different. 'lex' interprets - '^foo|bar' as "match either 'foo' at the beginning of a line, or - 'bar' anywhere", whereas 'flex' interprets it as "match either - 'foo' or 'bar' if they come at the beginning of a line". The + • The precedence of the ‘^’ operator is different. ‘lex’ interprets + ‘^foo|bar’ as "match either 'foo' at the beginning of a line, or + 'bar' anywhere", whereas ‘flex’ interprets it as "match either + ‘foo’ or ‘bar’ if they come at the beginning of a line". The latter is in agreement with the POSIX specification. - * The special table-size declarations such as '%a' supported by 'lex' - are not required by 'flex' scanners.. 'flex' ignores them. - * The name 'FLEX_SCANNER' is '#define''d so scanners may be written - for use with either 'flex' or 'lex'. Scanners also include - 'YY_FLEX_MAJOR_VERSION', 'YY_FLEX_MINOR_VERSION' and - 'YY_FLEX_SUBMINOR_VERSION' indicating which version of 'flex' + • The special table-size declarations such as ‘%a’ supported by ‘lex’ + are not required by ‘flex’ scanners.. ‘flex’ ignores them. + • The name ‘FLEX_SCANNER’ is ‘#define’'d so scanners may be written + for use with either ‘flex’ or ‘lex’. Scanners also include + ‘YY_FLEX_MAJOR_VERSION’, ‘YY_FLEX_MINOR_VERSION’ and + ‘YY_FLEX_SUBMINOR_VERSION’ indicating which version of ‘flex’ generated the scanner. For example, for the 2.5.22 release, these defines would be 2, 5 and 22 respectively. If the version of - 'flex' being used is a beta version, then the symbol 'FLEX_BETA' is + ‘flex’ being used is a beta version, then the symbol ‘FLEX_BETA’ is defined. - * The symbols '[[' and ']]' in the code sections of the input may + • The symbols ‘[[’ and ‘]]’ in the code sections of the input may conflict with the m4 delimiters. *Note M4 Dependency::. - The following 'flex' features are not included in 'lex' or the POSIX + The following ‘flex’ features are not included in ‘lex’ or the POSIX specification: - * C++ scanners - * %option - * start condition scopes - * start condition stacks - * interactive/non-interactive scanners - * yy_scan_string() and friends - * yyterminate() - * yy_set_interactive() - * yy_set_bol() - * YY_AT_BOL() <> - * <*> - * YY_DECL - * YY_START - * YY_USER_ACTION - * YY_USER_INIT - * #line directives - * %{}'s around actions - * reentrant C API - * multiple actions on a line - * almost all of the 'flex' command-line options + • C++ scanners + • %option + • start condition scopes + • start condition stacks + • interactive/non-interactive scanners + • yy_scan_string() and friends + • yyterminate() + • yy_set_interactive() + • yy_set_bol() + • YY_AT_BOL() <> + • <*> + • YY_DECL + • YY_START + • YY_USER_ACTION + • YY_USER_INIT + • #line directives + • %{}'s around actions + • reentrant C API + • multiple actions on a line + • almost all of the ‘flex’ command-line options The feature "multiple actions on a line" refers to the fact that with -'flex' you can put multiple actions on the same line, separated with -semi-colons, while with 'lex', the following: +‘flex’ you can put multiple actions on the same line, separated with +semi-colons, while with ‘lex’, the following: foo handle_foo(); ++num_foos_seen; @@ -3720,7 +3719,7 @@ semi-colons, while with 'lex', the following: foo handle_foo(); - 'flex' does not truncate the action. Actions that are not enclosed + ‘flex’ does not truncate the action. Actions that are not enclosed in braces are simply terminated at the end of the line.  @@ -3734,9 +3733,9 @@ override the default behavior. * Menu: -* The Default Memory Management:: -* Overriding The Default Memory Management:: -* A Note About yytext And Memory:: +* The Default Memory Management:: +* Overriding The Default Memory Management:: +* A Note About yytext And Memory::  File: flex.info, Node: The Default Memory Management, Next: Overriding The Default Memory Management, Prev: Memory Management, Up: Memory Management @@ -3748,7 +3747,7 @@ Flex allocates dynamic memory during initialization, and once in a while from within a call to yylex(). Initialization takes place during the first call to yylex(). Thereafter, flex may reallocate more memory if it needs to enlarge a buffer. As of version 2.5.9 Flex will clean up -all memory when you call 'yylex_destroy' *Note faq-memory-leak::. +all memory when you call ‘yylex_destroy’ *Note faq-memory-leak::. Flex allocates dynamic memory for four purposes, listed below (1) @@ -3763,7 +3762,7 @@ all memory when you call 'yylex_destroy' *Note faq-memory-leak::. for this buffer is the length of the longest token expected, in bytes, plus a little more. Flex will allocate a few extra bytes for housekeeping. Currently, to override the size of the input - buffer you must '#define YY_BUF_SIZE' to whatever number of bytes + buffer you must ‘#define YY_BUF_SIZE’ to whatever number of bytes you want. We don't plan to change this in the near future, but we reserve the right to do so if we ever add a more robust memory management API. @@ -3771,7 +3770,7 @@ all memory when you call 'yylex_destroy' *Note faq-memory-leak::. 64kb for the REJECT state. This will only be allocated if you use REJECT. The size is large enough to hold the same number of states as characters in the input buffer. If you override the size of the - input buffer (via 'YY_BUF_SIZE'), then you automatically override + input buffer (via ‘YY_BUF_SIZE’), then you automatically override the size of this buffer as well. 100 bytes for the start condition stack. @@ -3779,7 +3778,7 @@ all memory when you call 'yylex_destroy' *Note faq-memory-leak::. stack used for pushing start states, i.e., with yy_push_state(). It will grow if necessary. Since the states are simply integers, this stack doesn't consume much memory. This stack is not present - if '%option stack' is not specified. You will rarely need to tune + if ‘%option stack’ is not specified. You will rarely need to tune this buffer. The ideal size for this stack is the maximum depth expected. The memory for this stack is automatically destroyed when you call yylex_destroy(). *Note option-stack::. @@ -3818,10 +3817,10 @@ File: flex.info, Node: Overriding The Default Memory Management, Next: A Note 21.2 Overriding The Default Memory Management ============================================= -Flex calls the functions 'yyalloc', 'yyrealloc', and 'yyfree' when it +Flex calls the functions ‘yyalloc’, ‘yyrealloc’, and ‘yyfree’ when it needs to allocate or free memory. By default, these functions are -wrappers around the standard C functions, 'malloc', 'realloc', and -'free', respectively. You can override the default implementations by +wrappers around the standard C functions, ‘malloc’, ‘realloc’, and +‘free’, respectively. You can override the default implementations by telling flex that you will provide your own implementations. To override the default implementations, you must do two things: @@ -3829,9 +3828,9 @@ telling flex that you will provide your own implementations. 1. Suppress the default implementations by specifying one or more of the following options: - * '%option noyyalloc' - * '%option noyyrealloc' - * '%option noyyfree'. + • ‘%option noyyalloc’ + • ‘%option noyyrealloc’ + • ‘%option noyyfree’. 2. Provide your own implementation of the following functions: (1) @@ -3839,7 +3838,7 @@ telling flex that you will provide your own implementations. void * yyalloc (size_t bytes); void * yyrealloc (void * ptr, size_t bytes); void yyfree (void * ptr); - + // For a reentrant scanner void * yyalloc (size_t bytes, void * yyscanner); void * yyrealloc (void * ptr, size_t bytes, void * yyscanner); @@ -3848,45 +3847,45 @@ telling flex that you will provide your own implementations. In the following example, we will override all three memory routines. We assume that there is a custom allocator with garbage collection. In order to make this example interesting, we will use a reentrant scanner, -passing a pointer to the custom allocator through 'yyextra'. +passing a pointer to the custom allocator through ‘yyextra’. %{ #include "some_allocator.h" %} - + /* Suppress the default implementations. */ %option noyyalloc noyyrealloc noyyfree %option reentrant - + /* Initialize the allocator. */ %{ #define YY_EXTRA_TYPE struct allocator* #define YY_USER_INIT yyextra = allocator_create(); %} - + %% .|\n ; %% - + /* Provide our own implementations. */ void * yyalloc (size_t bytes, void* yyscanner) { return allocator_alloc (yyextra, bytes); } - + void * yyrealloc (void * ptr, size_t bytes, void* yyscanner) { return allocator_realloc (yyextra, bytes); } - - void yyfree (void * ptr, void * yyscanner) { + + void yyfree (void * ptr, void * yyscanner) { /* Do nothing -- we leave it to the garbage collector. */ } - + ---------- Footnotes ---------- (1) It is not necessary to override all (or any) of the memory -management routines. You may, for example, override 'yyrealloc', but -not 'yyfree' or 'yyalloc'. +management routines. You may, for example, override ‘yyrealloc’, but +not ‘yyfree’ or ‘yyalloc’.  File: flex.info, Node: A Note About yytext And Memory, Prev: Overriding The Default Memory Management, Up: Memory Management @@ -3894,7 +3893,7 @@ File: flex.info, Node: A Note About yytext And Memory, Prev: Overriding The De 21.3 A Note About yytext And Memory =================================== -When flex finds a match, 'yytext' points to the first character of the +When flex finds a match, ‘yytext’ points to the first character of the match in the input buffer. The string itself is part of the input buffer, and is _NOT_ allocated separately. The value of yytext will be overwritten the next time yylex() is called. In short, the value of @@ -3919,7 +3918,7 @@ File: flex.info, Node: Serialized Tables, Next: Diagnostics, Prev: Memory Man 22 Serialized Tables ******************** -A 'flex' scanner has the ability to save the DFA tables to a file, and +A ‘flex’ scanner has the ability to save the DFA tables to a file, and load them at runtime when needed. The motivation for this feature is to reduce the runtime memory footprint. Traditionally, these tables have been compiled into the scanner as C arrays, and are sometimes quite @@ -3934,9 +3933,9 @@ finished. * Menu: -* Creating Serialized Tables:: -* Loading and Unloading Serialized Tables:: -* Tables File Format:: +* Creating Serialized Tables:: +* Loading and Unloading Serialized Tables:: +* Tables File Format::  File: flex.info, Node: Creating Serialized Tables, Next: Loading and Unloading Serialized Tables, Prev: Serialized Tables, Up: Serialized Tables @@ -3956,8 +3955,8 @@ will not function on its own. The scanner will be dependent upon the serialized tables. You must load the tables from this file at runtime before you can scan anything. - If you do not specify a filename to '--tables-file', the tables will -be saved to 'lex.yy.tables', where 'yy' is the appropriate prefix. + If you do not specify a filename to ‘--tables-file’, the tables will +be saved to ‘lex.yy.tables’, where ‘yy’ is the appropriate prefix. If your project uses several different scanners, you can concatenate the serialized tables into one file, and flex will find the correct set @@ -3968,10 +3967,10 @@ example follows: $ flex --tables-file --prefix=c c.l $ cat lex.cpp.tables lex.c.tables > all.tables - The above example created two scanners, 'cpp', and 'c'. Since we did -not specify a filename, the tables were serialized to 'lex.c.tables' and -'lex.cpp.tables', respectively. Then, we concatenated the two files -together into 'all.tables', which we will distribute with our project. + The above example created two scanners, ‘cpp’, and ‘c’. Since we did +not specify a filename, the tables were serialized to ‘lex.c.tables’ and +‘lex.cpp.tables’, respectively. Then, we concatenated the two files +together into ‘all.tables’, which we will distribute with our project. At runtime, we will open the file and tell flex to load the tables from it. Flex will find the correct tables automatically. (See next section). @@ -3982,19 +3981,19 @@ File: flex.info, Node: Loading and Unloading Serialized Tables, Next: Tables F 22.2 Loading and Unloading Serialized Tables ============================================ -If you've built your scanner with '%option tables-file', then you must +If you've built your scanner with ‘%option tables-file’, then you must load the scanner tables at runtime. This can be accomplished with the following function: -- Function: int yytables_fload (FILE* FP [, yyscan_t SCANNER]) Locates scanner tables in the stream pointed to by FP and loads - them. Memory for the tables is allocated via 'yyalloc'. You must - call this function before the first call to 'yylex'. The argument + them. Memory for the tables is allocated via ‘yyalloc’. You must + call this function before the first call to ‘yylex’. The argument SCANNER only appears in the reentrant scanner. This function - returns '0' (zero) on success, or non-zero on error. + returns ‘0’ (zero) on success, or non-zero on error. The loaded tables are *not* automatically destroyed (unloaded) when -you call 'yylex_destroy'. The reason is that you may create several +you call ‘yylex_destroy’. The reason is that you may create several scanners of the same type (in a reentrant scanner), each of which needs access to these tables. To avoid a nasty memory leak, you must call the following function: @@ -4002,13 +4001,13 @@ following function: -- Function: int yytables_destroy ([yyscan_t SCANNER]) Unloads the scanner tables. The tables must be loaded again before you can scan any more data. The argument SCANNER only appears in - the reentrant scanner. This function returns '0' (zero) on + the reentrant scanner. This function returns ‘0’ (zero) on success, or non-zero on error. - *The functions 'yytables_fload' and 'yytables_destroy' are not + *The functions ‘yytables_fload’ and ‘yytables_destroy’ are not thread-safe.* You must ensure that these functions are called exactly once (for each scanner type) in a threaded program, before any thread -calls 'yylex'. After the tables are loaded, they are never written to, +calls ‘yylex’. After the tables are loaded, they are never written to, and no thread protection is required thereafter - until you destroy them. @@ -4018,7 +4017,7 @@ File: flex.info, Node: Tables File Format, Prev: Loading and Unloading Seriali 22.3 Tables File Format ======================= -This section defines the file format of serialized 'flex' tables. +This section defines the file format of serialized ‘flex’ tables. The tables format allows for one or more sets of tables to be specified, where each set corresponds to a given scanner. Scanners are @@ -4068,118 +4067,118 @@ possible. Remember, _all integer values are in network byte order_. Fields of a table header: -'th_magic' +‘th_magic’ Magic number, always 0xF13C57B1. -'th_hsize' +‘th_hsize’ Size of this entire header, in bytes, including all fields plus any padding. -'th_ssize' +‘th_ssize’ Size of this entire set, in bytes, including the header, all tables, plus any padding. -'th_flags' +‘th_flags’ Bit flags for this table set. Currently unused. -'th_version[]' - Flex version in NULL-terminated string format. e.g., '2.5.13a'. +‘th_version[]’ + Flex version in NULL-terminated string format. e.g., ‘2.5.13a’. This is the version of flex that was used to create the serialized tables. -'th_name[]' - Contains the name of this table set. The default is 'yytables', - and is prefixed accordingly, e.g., 'footables'. Must be +‘th_name[]’ + Contains the name of this table set. The default is ‘yytables’, + and is prefixed accordingly, e.g., ‘footables’. Must be NULL-terminated. -'th_pad64[]' +‘th_pad64[]’ Zero or more NULL bytes, padding the entire header to the next 64-bit boundary as calculated from the beginning of the header. Fields of a table: -'td_id' +‘td_id’ Specifies the table identifier. Possible values are: - 'YYTD_ID_ACCEPT (0x01)' - 'yy_accept' - 'YYTD_ID_BASE (0x02)' - 'yy_base' - 'YYTD_ID_CHK (0x03)' - 'yy_chk' - 'YYTD_ID_DEF (0x04)' - 'yy_def' - 'YYTD_ID_EC (0x05)' - 'yy_ec ' - 'YYTD_ID_META (0x06)' - 'yy_meta' - 'YYTD_ID_NUL_TRANS (0x07)' - 'yy_NUL_trans' - 'YYTD_ID_NXT (0x08)' - 'yy_nxt'. This array may be two dimensional. See the - 'td_hilen' field below. - 'YYTD_ID_RULE_CAN_MATCH_EOL (0x09)' - 'yy_rule_can_match_eol' - 'YYTD_ID_START_STATE_LIST (0x0A)' - 'yy_start_state_list'. This array is handled specially + ‘YYTD_ID_ACCEPT (0x01)’ + ‘yy_accept’ + ‘YYTD_ID_BASE (0x02)’ + ‘yy_base’ + ‘YYTD_ID_CHK (0x03)’ + ‘yy_chk’ + ‘YYTD_ID_DEF (0x04)’ + ‘yy_def’ + ‘YYTD_ID_EC (0x05)’ + ‘yy_ec ’ + ‘YYTD_ID_META (0x06)’ + ‘yy_meta’ + ‘YYTD_ID_NUL_TRANS (0x07)’ + ‘yy_NUL_trans’ + ‘YYTD_ID_NXT (0x08)’ + ‘yy_nxt’. This array may be two dimensional. See the + ‘td_hilen’ field below. + ‘YYTD_ID_RULE_CAN_MATCH_EOL (0x09)’ + ‘yy_rule_can_match_eol’ + ‘YYTD_ID_START_STATE_LIST (0x0A)’ + ‘yy_start_state_list’. This array is handled specially because it is an array of pointers to structs. See the - 'td_flags' field below. - 'YYTD_ID_TRANSITION (0x0B)' - 'yy_transition'. This array is handled specially because it - is an array of structs. See the 'td_lolen' field below. - 'YYTD_ID_ACCLIST (0x0C)' - 'yy_acclist' + ‘td_flags’ field below. + ‘YYTD_ID_TRANSITION (0x0B)’ + ‘yy_transition’. This array is handled specially because it + is an array of structs. See the ‘td_lolen’ field below. + ‘YYTD_ID_ACCLIST (0x0C)’ + ‘yy_acclist’ -'td_flags' - Bit flags describing how to interpret the data in 'td_data'. The +‘td_flags’ + Bit flags describing how to interpret the data in ‘td_data’. The data arrays are one-dimensional by default, but may be two - dimensional as specified in the 'td_hilen' field. + dimensional as specified in the ‘td_hilen’ field. - 'YYTD_DATA8 (0x01)' + ‘YYTD_DATA8 (0x01)’ The data is serialized as an array of type int8. - 'YYTD_DATA16 (0x02)' + ‘YYTD_DATA16 (0x02)’ The data is serialized as an array of type int16. - 'YYTD_DATA32 (0x04)' + ‘YYTD_DATA32 (0x04)’ The data is serialized as an array of type int32. - 'YYTD_PTRANS (0x08)' + ‘YYTD_PTRANS (0x08)’ The data is a list of indexes of entries in the expanded - 'yy_transition' array. Each index should be expanded to a - pointer to the corresponding entry in the 'yy_transition' - array. We count on the fact that the 'yy_transition' array + ‘yy_transition’ array. Each index should be expanded to a + pointer to the corresponding entry in the ‘yy_transition’ + array. We count on the fact that the ‘yy_transition’ array has already been seen. - 'YYTD_STRUCT (0x10)' + ‘YYTD_STRUCT (0x10)’ The data is a list of yy_trans_info structs, each of which consists of two integers. There is no padding between struct elements or between structs. The type of each member is - determined by the 'YYTD_DATA*' bits. + determined by the ‘YYTD_DATA*’ bits. -'td_hilen' - If 'td_hilen' is non-zero, then the data is a two-dimensional - array. Otherwise, the data is a one-dimensional array. 'td_hilen' +‘td_hilen’ + If ‘td_hilen’ is non-zero, then the data is a two-dimensional + array. Otherwise, the data is a one-dimensional array. ‘td_hilen’ contains the number of elements in the higher dimensional array, - and 'td_lolen' contains the number of elements in the lowest + and ‘td_lolen’ contains the number of elements in the lowest dimension. - Conceptually, 'td_data' is either 'sometype td_data[td_lolen]', or - 'sometype td_data[td_hilen][td_lolen]', where 'sometype' is - specified by the 'td_flags' field. It is possible for both - 'td_lolen' and 'td_hilen' to be zero, in which case 'td_data' is a + Conceptually, ‘td_data’ is either ‘sometype td_data[td_lolen]’, or + ‘sometype td_data[td_hilen][td_lolen]’, where ‘sometype’ is + specified by the ‘td_flags’ field. It is possible for both + ‘td_lolen’ and ‘td_hilen’ to be zero, in which case ‘td_data’ is a zero length array, and no data is loaded, i.e., this table is simply skipped. Flex does not currently generate tables of zero length. -'td_lolen' +‘td_lolen’ Specifies the number of elements in the lowest dimension array. If this is a one-dimensional array, then it is simply the number of elements in this array. The element size is determined by the - 'td_flags' field. + ‘td_flags’ field. -'td_data[]' +‘td_data[]’ The table data. This array may be a one- or two-dimensional array, - of type 'int8', 'int16', 'int32', 'struct yy_trans_info', or - 'struct yy_trans_info*', depending upon the values in the - 'td_flags', 'td_hilen', and 'td_lolen' fields. + of type ‘int8’, ‘int16’, ‘int32’, ‘struct yy_trans_info’, or + ‘struct yy_trans_info*’, depending upon the values in the + ‘td_flags’, ‘td_hilen’, and ‘td_lolen’ fields. -'td_pad64[]' +‘td_pad64[]’ Zero or more NULL bytes, padding the entire table to the next 64-bit boundary as calculated from the beginning of this table. @@ -4189,70 +4188,70 @@ File: flex.info, Node: Diagnostics, Next: Limitations, Prev: Serialized Table 23 Diagnostics ************** -The following is a list of 'flex' diagnostic messages: +The following is a list of ‘flex’ diagnostic messages: - * 'warning, rule cannot be matched' indicates that the given rule + • ‘warning, rule cannot be matched’ indicates that the given rule cannot be matched because it follows other rules that will always - match the same text as it. For example, in the following 'foo' + match the same text as it. For example, in the following ‘foo’ cannot be matched because it comes after an identifier "catch-all" rule: [a-z]+ got_identifier(); foo got_foo(); - Using 'REJECT' in a scanner suppresses this warning. + Using ‘REJECT’ in a scanner suppresses this warning. - * 'warning, -s option given but default rule can be matched' means + • ‘warning, -s option given but default rule can be matched’ means that it is possible (perhaps only in a particular start condition) that the default rule (match any single character) is the only one - that will match a particular input. Since '-s' was given, + that will match a particular input. Since ‘-s’ was given, presumably this is not intended. - * 'reject_used_but_not_detected undefined' or - 'yymore_used_but_not_detected undefined'. These errors can occur - at compile time. They indicate that the scanner uses 'REJECT' or - 'yymore()' but that 'flex' failed to notice the fact, meaning that - 'flex' scanned the first two sections looking for occurrences of + • ‘reject_used_but_not_detected undefined’ or + ‘yymore_used_but_not_detected undefined’. These errors can occur + at compile time. They indicate that the scanner uses ‘REJECT’ or + ‘yymore()’ but that ‘flex’ failed to notice the fact, meaning that + ‘flex’ scanned the first two sections looking for occurrences of these actions and failed to find any, but somehow you snuck some in - (via a #include file, for example). Use '%option reject' or - '%option yymore' to indicate to 'flex' that you really do use these + (via a #include file, for example). Use ‘%option reject’ or + ‘%option yymore’ to indicate to ‘flex’ that you really do use these features. - * 'flex scanner jammed'. a scanner compiled with '-s' has + • ‘flex scanner jammed’. a scanner compiled with ‘-s’ has encountered an input string which wasn't matched by any of its rules. This error can also occur due to internal problems. - * 'token too large, exceeds YYLMAX'. your scanner uses '%array' and - one of its rules matched a string longer than the 'YYLMAX' constant + • ‘token too large, exceeds YYLMAX’. your scanner uses ‘%array’ and + one of its rules matched a string longer than the ‘YYLMAX’ constant (8K bytes by default). You can increase the value by #define'ing - 'YYLMAX' in the definitions section of your 'flex' input. + ‘YYLMAX’ in the definitions section of your ‘flex’ input. - * 'scanner requires -8 flag to use the character 'x''. Your scanner - specification includes recognizing the 8-bit character ''x'' and + • ‘scanner requires -8 flag to use the character 'x'’. Your scanner + specification includes recognizing the 8-bit character ‘'x'’ and you did not specify the -8 flag, and your scanner defaulted to - 7-bit because you used the '-Cf' or '-CF' table compression - options. See the discussion of the '-7' flag, *note Scanner + 7-bit because you used the ‘-Cf’ or ‘-CF’ table compression + options. See the discussion of the ‘-7’ flag, *note Scanner Options::, for details. - * 'flex scanner push-back overflow'. you used 'unput()' to push back + • ‘flex scanner push-back overflow’. you used ‘unput()’ to push back so much text that the scanner's buffer could not hold both the - pushed-back text and the current token in 'yytext'. Ideally the + pushed-back text and the current token in ‘yytext’. Ideally the scanner should dynamically resize the buffer in this case, but at present it does not. - * 'input buffer overflow, can't enlarge buffer because scanner uses - REJECT'. the scanner was working on matching an extremely large + • ‘input buffer overflow, can't enlarge buffer because scanner uses + REJECT’. the scanner was working on matching an extremely large token and needed to expand the input buffer. This doesn't work - with scanners that use 'REJECT'. + with scanners that use ‘REJECT’. - * 'fatal flex scanner internal error--end of buffer missed'. This + • ‘fatal flex scanner internal error--end of buffer missed’. This can occur in a scanner which is reentered after a long-jump has jumped out (or over) the scanner's activation frame. Before reentering the scanner, use: yyrestart( yyin ); or, as noted above, switch to using the C++ scanner class. - * 'too many start conditions in <> construct!' you listed more start + • ‘too many start conditions in <> construct!’ you listed more start conditions in a <> construct than exist (so you must have listed at least one of them twice). @@ -4263,16 +4262,16 @@ File: flex.info, Node: Limitations, Next: Bibliography, Prev: Diagnostics, U ************** Some trailing context patterns cannot be properly matched and generate -warning messages ('dangerous trailing context'). These are patterns +warning messages (‘dangerous trailing context’). These are patterns where the ending of the first part of the rule matches the beginning of -the second part, such as 'zx*/xy*', where the 'x*' matches the 'x' at +the second part, such as ‘zx*/xy*’, where the 'x*' matches the 'x' at the beginning of the trailing context. (Note that the POSIX draft states that the text matched by such patterns is undefined.) For some trailing context rules, parts which are actually fixed-length are not recognized as such, leading to the abovementioned performance loss. In -particular, parts using '|' or '{n}' (such as 'foo{3}') are always +particular, parts using ‘|’ or ‘{n}’ (such as ‘foo{3}’) are always considered variable-length. Combining trailing context with the special -'|' action can result in _fixed_ trailing context being turned into the +‘|’ action can result in _fixed_ trailing context being turned into the more expensive _variable_ trailing context. For example, in the following: @@ -4280,21 +4279,21 @@ following: abc | xyz/def - Use of 'unput()' invalidates yytext and yyleng, unless the '%array' -directive or the '-l' option has been used. Pattern-matching of 'NUL's + Use of ‘unput()’ invalidates yytext and yyleng, unless the ‘%array’ +directive or the ‘-l’ option has been used. Pattern-matching of ‘NUL’s is substantially slower than matching other characters. Dynamic resizing of the input buffer is slow, as it entails rescanning all the text matched so far by the current (generally huge) token. Due to both buffering of input and read-ahead, you cannot intermix calls to -'' routines, such as, getchar(), with 'flex' rules and expect -it to work. Call 'input()' instead. The total table entries listed by -the '-v' flag excludes the number of table entries needed to determine +‘’ routines, such as, getchar(), with ‘flex’ rules and expect +it to work. Call ‘input()’ instead. The total table entries listed by +the ‘-v’ flag excludes the number of table entries needed to determine what rule has been matched. The number of entries is equal to the -number of DFA states if the scanner does not use 'REJECT', and somewhat -greater than the number of states if it does. 'REJECT' cannot be used -with the '-f' or '-F' options. +number of DFA states if the scanner does not use ‘REJECT’, and somewhat +greater than the number of states if it does. ‘REJECT’ cannot be used +with the ‘-f’ or ‘-F’ options. - The 'flex' internal algorithms need documentation. + The ‘flex’ internal algorithms need documentation.  File: flex.info, Node: Bibliography, Next: FAQ, Prev: Limitations, Up: Top @@ -4303,10 +4302,10 @@ File: flex.info, Node: Bibliography, Next: FAQ, Prev: Limitations, Up: Top ********************* You may wish to read more about the following programs: - * lex - * yacc - * sed - * awk + • lex + • yacc + • sed + • awk The following books may contain material of interest: @@ -4317,7 +4316,7 @@ Associates. Be sure to get the 2nd edition. Alfred Aho, Ravi Sethi and Jeffrey Ullman, _Compilers: Principles, Techniques and Tools_, Addison-Wesley (1986). Describes the -pattern-matching techniques used by 'flex' (deterministic finite +pattern-matching techniques used by ‘flex’ (deterministic finite automata).  @@ -4326,111 +4325,111 @@ File: flex.info, Node: FAQ, Next: Appendices, Prev: Bibliography, Up: Top FAQ *** -From time to time, the 'flex' maintainer receives certain questions. +From time to time, the ‘flex’ maintainer receives certain questions. Rather than repeat answers to well-understood problems, we publish them here. * Menu: -* When was flex born?:: -* How do I expand backslash-escape sequences in C-style quoted strings?:: -* Why do flex scanners call fileno if it is not ANSI compatible?:: -* Does flex support recursive pattern definitions?:: -* How do I skip huge chunks of input (tens of megabytes) while using flex?:: -* Flex is not matching my patterns in the same order that I defined them.:: -* My actions are executing out of order or sometimes not at all.:: -* How can I have multiple input sources feed into the same scanner at the same time?:: -* Can I build nested parsers that work with the same input file?:: -* How can I match text only at the end of a file?:: -* How can I make REJECT cascade across start condition boundaries?:: -* Why cant I use fast or full tables with interactive mode?:: -* How much faster is -F or -f than -C?:: -* If I have a simple grammar cant I just parse it with flex?:: -* Why doesn't yyrestart() set the start state back to INITIAL?:: -* How can I match C-style comments?:: -* The period isn't working the way I expected.:: -* Can I get the flex manual in another format?:: -* Does there exist a "faster" NDFA->DFA algorithm?:: -* How does flex compile the DFA so quickly?:: -* How can I use more than 8192 rules?:: -* How do I abandon a file in the middle of a scan and switch to a new file?:: -* How do I execute code only during initialization (only before the first scan)?:: -* How do I execute code at termination?:: -* Where else can I find help?:: -* Can I include comments in the "rules" section of the file?:: -* I get an error about undefined yywrap().:: -* How can I change the matching pattern at run time?:: -* How can I expand macros in the input?:: -* How can I build a two-pass scanner?:: -* How do I match any string not matched in the preceding rules?:: -* I am trying to port code from AT&T lex that uses yysptr and yysbuf.:: -* Is there a way to make flex treat NULL like a regular character?:: -* Whenever flex can not match the input it says "flex scanner jammed".:: -* Why doesn't flex have non-greedy operators like perl does?:: -* Memory leak - 16386 bytes allocated by malloc.:: -* How do I track the byte offset for lseek()?:: -* How do I use my own I/O classes in a C++ scanner?:: -* How do I skip as many chars as possible?:: -* deleteme00:: -* Are certain equivalent patterns faster than others?:: -* Is backing up a big deal?:: -* Can I fake multi-byte character support?:: -* deleteme01:: -* Can you discuss some flex internals?:: -* unput() messes up yy_at_bol:: -* The | operator is not doing what I want:: -* Why can't flex understand this variable trailing context pattern?:: -* The ^ operator isn't working:: -* Trailing context is getting confused with trailing optional patterns:: -* Is flex GNU or not?:: -* ERASEME53:: -* I need to scan if-then-else blocks and while loops:: -* ERASEME55:: -* ERASEME56:: -* ERASEME57:: -* Is there a repository for flex scanners?:: -* How can I conditionally compile or preprocess my flex input file?:: -* Where can I find grammars for lex and yacc?:: -* I get an end-of-buffer message for each character scanned.:: -* unnamed-faq-62:: -* unnamed-faq-63:: -* unnamed-faq-64:: -* unnamed-faq-65:: -* unnamed-faq-66:: -* unnamed-faq-67:: -* unnamed-faq-68:: -* unnamed-faq-69:: -* unnamed-faq-70:: -* unnamed-faq-71:: -* unnamed-faq-72:: -* unnamed-faq-73:: -* unnamed-faq-74:: -* unnamed-faq-75:: -* unnamed-faq-76:: -* unnamed-faq-77:: -* unnamed-faq-78:: -* unnamed-faq-79:: -* unnamed-faq-80:: -* unnamed-faq-81:: -* unnamed-faq-82:: -* unnamed-faq-83:: -* unnamed-faq-84:: -* unnamed-faq-85:: -* unnamed-faq-86:: -* unnamed-faq-87:: -* unnamed-faq-88:: -* unnamed-faq-90:: -* unnamed-faq-91:: -* unnamed-faq-92:: -* unnamed-faq-93:: -* unnamed-faq-94:: -* unnamed-faq-95:: -* unnamed-faq-96:: -* unnamed-faq-97:: -* unnamed-faq-98:: -* unnamed-faq-99:: -* unnamed-faq-100:: -* unnamed-faq-101:: +* When was flex born?:: +* How do I expand backslash-escape sequences in C-style quoted strings?:: +* Why do flex scanners call fileno if it is not ANSI compatible?:: +* Does flex support recursive pattern definitions?:: +* How do I skip huge chunks of input (tens of megabytes) while using flex?:: +* Flex is not matching my patterns in the same order that I defined them.:: +* My actions are executing out of order or sometimes not at all.:: +* How can I have multiple input sources feed into the same scanner at the same time?:: +* Can I build nested parsers that work with the same input file?:: +* How can I match text only at the end of a file?:: +* How can I make REJECT cascade across start condition boundaries?:: +* Why cant I use fast or full tables with interactive mode?:: +* How much faster is -F or -f than -C?:: +* If I have a simple grammar cant I just parse it with flex?:: +* Why doesn't yyrestart() set the start state back to INITIAL?:: +* How can I match C-style comments?:: +* The period isn't working the way I expected.:: +* Can I get the flex manual in another format?:: +* Does there exist a "faster" NDFA->DFA algorithm?:: +* How does flex compile the DFA so quickly?:: +* How can I use more than 8192 rules?:: +* How do I abandon a file in the middle of a scan and switch to a new file?:: +* How do I execute code only during initialization (only before the first scan)?:: +* How do I execute code at termination?:: +* Where else can I find help?:: +* Can I include comments in the "rules" section of the file?:: +* I get an error about undefined yywrap().:: +* How can I change the matching pattern at run time?:: +* How can I expand macros in the input?:: +* How can I build a two-pass scanner?:: +* How do I match any string not matched in the preceding rules?:: +* I am trying to port code from AT&T lex that uses yysptr and yysbuf.:: +* Is there a way to make flex treat NULL like a regular character?:: +* Whenever flex can not match the input it says "flex scanner jammed".:: +* Why doesn't flex have non-greedy operators like perl does?:: +* Memory leak - 16386 bytes allocated by malloc.:: +* How do I track the byte offset for lseek()?:: +* How do I use my own I/O classes in a C++ scanner?:: +* How do I skip as many chars as possible?:: +* deleteme00:: +* Are certain equivalent patterns faster than others?:: +* Is backing up a big deal?:: +* Can I fake multi-byte character support?:: +* deleteme01:: +* Can you discuss some flex internals?:: +* unput() messes up yy_at_bol:: +* The | operator is not doing what I want:: +* Why can't flex understand this variable trailing context pattern?:: +* The ^ operator isn't working:: +* Trailing context is getting confused with trailing optional patterns:: +* Is flex GNU or not?:: +* ERASEME53:: +* I need to scan if-then-else blocks and while loops:: +* ERASEME55:: +* ERASEME56:: +* ERASEME57:: +* Is there a repository for flex scanners?:: +* How can I conditionally compile or preprocess my flex input file?:: +* Where can I find grammars for lex and yacc?:: +* I get an end-of-buffer message for each character scanned.:: +* unnamed-faq-62:: +* unnamed-faq-63:: +* unnamed-faq-64:: +* unnamed-faq-65:: +* unnamed-faq-66:: +* unnamed-faq-67:: +* unnamed-faq-68:: +* unnamed-faq-69:: +* unnamed-faq-70:: +* unnamed-faq-71:: +* unnamed-faq-72:: +* unnamed-faq-73:: +* unnamed-faq-74:: +* unnamed-faq-75:: +* unnamed-faq-76:: +* unnamed-faq-77:: +* unnamed-faq-78:: +* unnamed-faq-79:: +* unnamed-faq-80:: +* unnamed-faq-81:: +* unnamed-faq-82:: +* unnamed-faq-83:: +* unnamed-faq-84:: +* unnamed-faq-85:: +* unnamed-faq-86:: +* unnamed-faq-87:: +* unnamed-faq-88:: +* unnamed-faq-90:: +* unnamed-faq-91:: +* unnamed-faq-92:: +* unnamed-faq-93:: +* unnamed-faq-94:: +* unnamed-faq-95:: +* unnamed-faq-96:: +* unnamed-faq-97:: +* unnamed-faq-98:: +* unnamed-faq-99:: +* unnamed-faq-100:: +* unnamed-faq-101:: * What is the difference between YYLEX_PARAM and YY_DECL?:: * Why do I get "conflicting types for yylex" error?:: * How do I access the values set in a Flex action from within a Bison action?:: @@ -4441,7 +4440,7 @@ File: flex.info, Node: When was flex born?, Next: How do I expand backslash-es When was flex born? =================== -Vern Paxson took over the 'Software Tools' lex project from Jef +Vern Paxson took over the ‘Software Tools’ lex project from Jef Poskanzer in 1982. At that point it was written in Ratfor. Around 1987 or so, Paxson translated it into C, and a legend was born :-). @@ -4462,10 +4461,10 @@ one for matching non-escaped text, one for matching a single escape, one for matching an embedded newline, and one for recognizing the end of the string. Each of these rules is then faced with the question of where to put its intermediary results. The best solution is for the rules to -append their local value of 'yytext' to the end of a "string literal" +append their local value of ‘yytext’ to the end of a "string literal" buffer. A rule like the escape-matcher will append to the buffer the -meaning of the escape sequence rather than the literal text in 'yytext'. -In this way, 'yytext' does not need to be modified at all. +meaning of the escape sequence rather than the literal text in ‘yytext’. +In this way, ‘yytext’ does not need to be modified at all.  File: flex.info, Node: Why do flex scanners call fileno if it is not ANSI compatible?, Next: Does flex support recursive pattern definitions?, Prev: How do I expand backslash-escape sequences in C-style quoted strings?, Up: FAQ @@ -4473,13 +4472,13 @@ File: flex.info, Node: Why do flex scanners call fileno if it is not ANSI compa Why do flex scanners call fileno if it is not ANSI compatible? ============================================================== -Flex scanners call 'fileno()' in order to get the file descriptor -corresponding to 'yyin'. The file descriptor may be passed to -'isatty()' or 'read()', depending upon which '%options' you specified. -If your system does not have 'fileno()' support, to get rid of the -'read()' call, do not specify '%option read'. To get rid of the -'isatty()' call, you must specify one of '%option always-interactive' or -'%option never-interactive'. +Flex scanners call ‘fileno()’ in order to get the file descriptor +corresponding to ‘yyin’. The file descriptor may be passed to +‘isatty()’ or ‘read()’, depending upon which ‘%options’ you specified. +If your system does not have ‘fileno()’ support, to get rid of the +‘read()’ call, do not specify ‘%option read’. To get rid of the +‘isatty()’ call, you must specify one of ‘%option always-interactive’ or +‘%option never-interactive’.  File: flex.info, Node: Does flex support recursive pattern definitions?, Next: How do I skip huge chunks of input (tens of megabytes) while using flex?, Prev: Why do flex scanners call fileno if it is not ANSI compatible?, Up: FAQ @@ -4498,7 +4497,7 @@ too) is limited. In particular, regular expressions cannot "balance" parentheses to an arbitrary degree. For example, it's impossible to write a regular expression that matches all strings containing the same number of '{'s as '}'s. For more powerful pattern matching, you need a -parser, such as 'GNU bison'. +parser, such as ‘GNU bison’.  File: flex.info, Node: How do I skip huge chunks of input (tens of megabytes) while using flex?, Next: Flex is not matching my patterns in the same order that I defined them., Prev: Does flex support recursive pattern definitions?, Up: FAQ @@ -4506,7 +4505,7 @@ File: flex.info, Node: How do I skip huge chunks of input (tens of megabytes) w How do I skip huge chunks of input (tens of megabytes) while using flex? ======================================================================== -Use 'fseek()' (or 'lseek()') to position yyin, then call 'yyrestart()'. +Use ‘fseek()’ (or ‘lseek()’) to position yyin, then call ‘yyrestart()’.  File: flex.info, Node: Flex is not matching my patterns in the same order that I defined them., Next: My actions are executing out of order or sometimes not at all., Prev: How do I skip huge chunks of input (tens of megabytes) while using flex?, Up: FAQ @@ -4514,32 +4513,32 @@ File: flex.info, Node: Flex is not matching my patterns in the same order that Flex is not matching my patterns in the same order that I defined them. ======================================================================= -'flex' picks the rule that matches the most text (i.e., the longest -possible input string). This is because 'flex' uses an entirely +‘flex’ picks the rule that matches the most text (i.e., the longest +possible input string). This is because ‘flex’ uses an entirely different matching technique ("deterministic finite automata") that actually does all of the matching simultaneously, in parallel. (Seems impossible, but it's actually a fairly simple technique once you understand the principles.) A side-effect of this parallel matching is that when the input -matches more than one rule, 'flex' scanners pick the rule that matched +matches more than one rule, ‘flex’ scanners pick the rule that matched the _most_ text. This is explained further in the manual, in the section *Note Matching::. - If you want 'flex' to choose a shorter match, then you can work + If you want ‘flex’ to choose a shorter match, then you can work around this behavior by expanding your short rule to match more text, then put back the extra: data_.* yyless( 5 ); BEGIN BLOCKIDSTATE; Another fix would be to make the second rule active only during the -'' start condition, and make that start condition -exclusive by declaring it with '%x' instead of '%s'. +‘’ start condition, and make that start condition +exclusive by declaring it with ‘%x’ instead of ‘%s’. A final fix is to change the input language so that the ambiguity for -'data_' is removed, by adding characters to it that don't match the -identifier rule, or by removing characters (such as '_') from the -identifier rule so it no longer matches 'data_'. (Of course, you might +‘data_’ is removed, by adding characters to it that don't match the +identifier rule, or by removing characters (such as ‘_’) from the +identifier rule so it no longer matches ‘data_’. (Of course, you might also not have the option of changing the input language.)  @@ -4548,20 +4547,20 @@ File: flex.info, Node: My actions are executing out of order or sometimes not a My actions are executing out of order or sometimes not at all. ============================================================== -Most likely, you have (in error) placed the opening '{' of the action +Most likely, you have (in error) placed the opening ‘{’ of the action block on a different line than the rule, e.g., ^(foo|bar) { <<<--- WRONG! - + } - 'flex' requires that the opening '{' of an action associated with a + ‘flex’ requires that the opening ‘{’ of an action associated with a rule begin on the same line as does the rule. You need instead to write your rules as follows: ^(foo|bar) { // CORRECT! - + }  @@ -4571,34 +4570,34 @@ How can I have multiple input sources feed into the same scanner at the same tim ================================================================================== If ... - * your scanner is free of backtracking (verified using 'flex''s '-b' + • your scanner is free of backtracking (verified using ‘flex’'s ‘-b’ flag), - * AND you run your scanner interactively ('-I' option; default unless + • AND you run your scanner interactively (‘-I’ option; default unless using special table compression options), - * AND you feed it one character at a time by redefining 'YY_INPUT' to + • AND you feed it one character at a time by redefining ‘YY_INPUT’ to do so, then every time it matches a token, it will have exhausted its input buffer (because the scanner is free of backtracking). This means you -can safely use 'select()' at the point and only call 'yylex()' for -another token if 'select()' indicates there's data available. +can safely use ‘select()’ at the point and only call ‘yylex()’ for +another token if ‘select()’ indicates there's data available. - That is, move the 'select()' out from the input function to a point -where it determines whether 'yylex()' gets called for the next token. + That is, move the ‘select()’ out from the input function to a point +where it determines whether ‘yylex()’ gets called for the next token. With this approach, you will still have problems if your input can -arrive piecemeal; 'select()' could inform you that the beginning of a -token is available, you call 'yylex()' to get it, but it winds up +arrive piecemeal; ‘select()’ could inform you that the beginning of a +token is available, you call ‘yylex()’ to get it, but it winds up blocking waiting for the later characters in the token. Here's another way: Move your input multiplexing inside of -'YY_INPUT'. That is, whenever 'YY_INPUT' is called, it 'select()''s to +‘YY_INPUT’. That is, whenever ‘YY_INPUT’ is called, it ‘select()’'s to see where input is available. If input is available for the scanner, it reads and returns the next byte. If input is available from another source, it calls whatever function is responsible for reading from that source. (If no input is available, it blocks until some input is available.) I've used this technique in an interpreter I wrote that -both reads keyboard input using a 'flex' scanner and IPC traffic from +both reads keyboard input using a ‘flex’ scanner and IPC traffic from sockets, and it works fine.  @@ -4608,11 +4607,11 @@ Can I build nested parsers that work with the same input file? ============================================================== This is not going to work without some additional effort. The reason is -that 'flex' block-buffers the input it reads from 'yyin'. This means -that the "outermost" 'yylex()', when called, will automatically slurp up +that ‘flex’ block-buffers the input it reads from ‘yyin’. This means +that the "outermost" ‘yylex()’, when called, will automatically slurp up the first 8K of input available on yyin, and subsequent calls to other -'yylex()''s won't see that input. You might be tempted to work around -this problem by redefining 'YY_INPUT' to only return a small amount of +‘yylex()’'s won't see that input. You might be tempted to work around +this problem by redefining ‘YY_INPUT’ to only return a small amount of text, but it turns out that that approach is quite difficult. Instead, the best solution is to combine all of your scanners into one large scanner, using a different exclusive start condition for each. @@ -4626,9 +4625,9 @@ How can I match text only at the end of a file? There is no way to write a rule which is "match this text, but only if it comes at the end of the file". You can fake it, though, if you happen to have a character lying around that you don't allow in your -input. Then you redefine 'YY_INPUT' to call your own routine which, if -it sees an 'EOF', returns the magic character first (and remembers to -return a real 'EOF' next time it's called). Then you could write: +input. Then you redefine ‘YY_INPUT’ to call your own routine which, if +it sees an ‘EOF’, returns the magic character first (and remembers to +return a real ‘EOF’ next time it's called). Then you could write: (.|\n)*{EOF_CHAR} /* saw comment at EOF */ @@ -4638,9 +4637,9 @@ File: flex.info, Node: How can I make REJECT cascade across start condition bou How can I make REJECT cascade across start condition boundaries? ================================================================ -You can do this as follows. Suppose you have a start condition 'A', and -after exhausting all of the possible matches in '', you want to try -matches in ''. Then you could use the following: +You can do this as follows. Suppose you have a start condition ‘A’, and +after exhausting all of the possible matches in ‘’, you want to try +matches in ‘’. Then you could use the following: %x A %% @@ -4707,7 +4706,7 @@ Why doesn't yyrestart() set the start state back to INITIAL? There are two reasons. The first is that there might be programs that rely on the start state not changing across file changes. The second is -that beginning with 'flex' version 2.4, use of 'yyrestart()' is no +that beginning with ‘flex’ version 2.4, use of ‘yyrestart()’ is no longer required, so fixing the problem there doesn't solve the more general problem. @@ -4747,26 +4746,26 @@ File: flex.info, Node: The period isn't working the way I expected., Next: Can The '.' isn't working the way I expected. ========================================= -Here are some tips for using '.': +Here are some tips for using ‘.’: - * A common mistake is to place the grouping parenthesis AFTER an + • A common mistake is to place the grouping parenthesis AFTER an operator, when you really meant to place the parenthesis BEFORE the - operator, e.g., you probably want this '(foo|bar)+' and NOT this - '(foo|bar+)'. + operator, e.g., you probably want this ‘(foo|bar)+’ and NOT this + ‘(foo|bar+)’. - The first pattern matches the words 'foo' or 'bar' any number of - times, e.g., it matches the text 'barfoofoobarfoo'. The second - pattern matches a single instance of 'foo' or a single instance of - 'bar' followed by one or more 'r's, e.g., it matches the text - 'barrrr' . - * A '.' inside '[]''s just means a literal'.' (period), and NOT "any + The first pattern matches the words ‘foo’ or ‘bar’ any number of + times, e.g., it matches the text ‘barfoofoobarfoo’. The second + pattern matches a single instance of ‘foo’ or a single instance of + ‘bar’ followed by one or more ‘r’s, e.g., it matches the text + ‘barrrr’ . + • A ‘.’ inside ‘[]’'s just means a literal‘.’ (period), and NOT "any character except newline". - * Remember that '.' matches any character EXCEPT '\n' (and 'EOF'). + • Remember that ‘.’ matches any character EXCEPT ‘\n’ (and ‘EOF’). If you really want to match ANY character, including newlines, then - use '(.|\n)' Beware that the regex '(.|\n)+' will match your entire + use ‘(.|\n)’ Beware that the regex ‘(.|\n)+’ will match your entire input! - * Finally, if you want to match a literal '.' (a period), then use - '[.]' or '"."' + • Finally, if you want to match a literal ‘.’ (a period), then use + ‘[.]’ or ‘"."’  File: flex.info, Node: Can I get the flex manual in another format?, Next: Does there exist a "faster" NDFA->DFA algorithm?, Prev: The period isn't working the way I expected., Up: FAQ @@ -4774,8 +4773,8 @@ File: flex.info, Node: Can I get the flex manual in another format?, Next: Doe Can I get the flex manual in another format? ============================================ -The 'flex' source distribution includes a texinfo manual. You are free -to convert that texinfo into whatever format you desire. The 'texinfo' +The ‘flex’ source distribution includes a texinfo manual. You are free +to convert that texinfo into whatever format you desire. The ‘texinfo’ package includes tools for conversion to a number of formats.  @@ -4795,7 +4794,7 @@ File: flex.info, Node: How does flex compile the DFA so quickly?, Next: How ca How does flex compile the DFA so quickly? ========================================= -There are two big speed wins that 'flex' uses: +There are two big speed wins that ‘flex’ uses: 1. It analyzes the input rules to construct equivalence classes for those characters that always make the same transitions. It then @@ -4814,9 +4813,9 @@ File: flex.info, Node: How can I use more than 8192 rules?, Next: How do I aba How can I use more than 8192 rules? =================================== -'Flex' is compiled with an upper limit of 8192 rules per scanner. If +‘Flex’ is compiled with an upper limit of 8192 rules per scanner. If you need more than 8192 rules in your scanner, you'll have to recompile -'flex' with the following changes in 'flexdef.h': +‘flex’ with the following changes in ‘flexdef.h’: < #define YY_TRAILING_MASK 0x2000 < #define YY_TRAILING_HEAD_MASK 0x4000 @@ -4849,9 +4848,9 @@ File: flex.info, Node: How do I abandon a file in the middle of a scan and swit How do I abandon a file in the middle of a scan and switch to a new file? ========================================================================= -Just call 'yyrestart(newfile)'. Be sure to reset the start state if you -want a "fresh start, since 'yyrestart' does NOT reset the start state -back to 'INITIAL'. +Just call ‘yyrestart(newfile)’. Be sure to reset the start state if you +want a "fresh start, since ‘yyrestart’ does NOT reset the start state +back to ‘INITIAL’.  File: flex.info, Node: How do I execute code only during initialization (only before the first scan)?, Next: How do I execute code at termination?, Prev: How do I abandon a file in the middle of a scan and switch to a new file?, Up: FAQ @@ -4859,14 +4858,14 @@ File: flex.info, Node: How do I execute code only during initialization (only b How do I execute code only during initialization (only before the first scan)? ============================================================================== -You can specify an initial action by defining the macro 'YY_USER_INIT' -(though note that 'yyout' may not be available at the time this macro is +You can specify an initial action by defining the macro ‘YY_USER_INIT’ +(though note that ‘yyout’ may not be available at the time this macro is executed). Or you can add to the beginning of your rules section: %% /* Must be indented! */ static int did_init = 0; - + if ( ! did_init ){ do_my_init(); did_init = 1; @@ -4878,7 +4877,7 @@ File: flex.info, Node: How do I execute code at termination?, Next: Where else How do I execute code at termination? ===================================== -You can specify an action for the '<>' rule. +You can specify an action for the ‘<>’ rule.  File: flex.info, Node: Where else can I find help?, Next: Can I include comments in the "rules" section of the file?, Prev: How do I execute code at termination?, Up: FAQ @@ -4905,12 +4904,12 @@ File: flex.info, Node: I get an error about undefined yywrap()., Next: How can I get an error about undefined yywrap(). ======================================== -You must supply a 'yywrap()' function of your own, or link to 'libfl.a' +You must supply a ‘yywrap()’ function of your own, or link to ‘libfl.a’ (which provides one), or use %option noyywrap - in your source to say you don't want a 'yywrap()' function. + in your source to say you don't want a ‘yywrap()’ function.  File: flex.info, Node: How can I change the matching pattern at run time?, Next: How can I expand macros in the input?, Prev: I get an error about undefined yywrap()., Up: FAQ @@ -4939,7 +4938,7 @@ parser. expansion_buffer = yy_scan_string(expand(yytext)); yy_switch_to_buffer(expansion_buffer); } - + <> { if ( expansion_buffer ) { @@ -4982,16 +4981,16 @@ How do I match any string not matched in the preceding rules? One way to assign precedence, is to place the more specific rules first. If two rules would match the same input (same sequence of characters) -then the first rule listed in the 'flex' input wins, e.g., +then the first rule listed in the ‘flex’ input wins, e.g., %% foo[a-zA-Z_]+ return FOO_ID; bar[a-zA-Z_]+ return BAR_ID; [a-zA-Z_]+ return GENERIC_ID; - Note that the rule '[a-zA-Z_]+' must come *after* the others. It + Note that the rule ‘[a-zA-Z_]+’ must come *after* the others. It will match the same amount of text as the more specific rules, and in -that case the 'flex' scanner will pick the first rule listed in your +that case the ‘flex’ scanner will pick the first rule listed in your scanner as the one to match.  @@ -5002,10 +5001,10 @@ I am trying to port code from AT&T lex that uses yysptr and yysbuf. Those are internal variables pointing into the AT&T scanner's input buffer. I imagine they're being manipulated in user versions of the -'input()' and 'unput()' functions. If so, what you need to do is +‘input()’ and ‘unput()’ functions. If so, what you need to do is analyze those functions to figure out what they're doing, and then -replace 'input()' with an appropriate definition of 'YY_INPUT'. You -shouldn't need to (and must not) replace 'flex''s 'unput()' function. +replace ‘input()’ with an appropriate definition of ‘YY_INPUT’. You +shouldn't need to (and must not) replace ‘flex’'s ‘unput()’ function.  File: flex.info, Node: Is there a way to make flex treat NULL like a regular character?, Next: Whenever flex can not match the input it says "flex scanner jammed"., Prev: I am trying to port code from AT&T lex that uses yysptr and yysbuf., Up: FAQ @@ -5013,8 +5012,8 @@ File: flex.info, Node: Is there a way to make flex treat NULL like a regular ch Is there a way to make flex treat NULL like a regular character? ================================================================ -Yes, '\0' and '\x00' should both do the trick. Perhaps you have an -ancient version of 'flex'. The latest release is version 2.6.4. +Yes, ‘\0’ and ‘\x00’ should both do the trick. Perhaps you have an +ancient version of ‘flex’. The latest release is version 2.6.4.  File: flex.info, Node: Whenever flex can not match the input it says "flex scanner jammed"., Next: Why doesn't flex have non-greedy operators like perl does?, Prev: Is there a way to make flex treat NULL like a regular character?, Up: FAQ @@ -5027,10 +5026,10 @@ You need to add a rule that matches the otherwise-unmatched text, e.g., %option yylineno %% [[a bunch of rules here]] - + . printf("bad input character '%s' at line %d\n", yytext, yylineno); - See '%option default' for more information. + See ‘%option default’ for more information.  File: flex.info, Node: Why doesn't flex have non-greedy operators like perl does?, Next: Memory leak - 16386 bytes allocated by malloc., Prev: Whenever flex can not match the input it says "flex scanner jammed"., Up: FAQ @@ -5051,9 +5050,9 @@ decent job. Better is to either introduce a separate parser, or to split the scanner into multiple scanners using (exclusive) start conditions. - You might have a separate start state once you've seen the 'BEGIN'. -In that state, you might then have a regex that will match 'END' (to -kick you out of the state), and perhaps '(.|\n)' to get a single + You might have a separate start state once you've seen the ‘BEGIN’. +In that state, you might then have a regex that will match ‘END’ (to +kick you out of the state), and perhaps ‘(.|\n)’ to get a single character within the chunk ... This approach also has much better error-reporting properties. @@ -5064,18 +5063,18 @@ File: flex.info, Node: Memory leak - 16386 bytes allocated by malloc., Next: H Memory leak - 16386 bytes allocated by malloc. ============================================== -UPDATED 2002-07-10: As of 'flex' version 2.5.9, this leak means that you -did not call 'yylex_destroy()'. If you are using an earlier version of -'flex', then read on. +UPDATED 2002-07-10: As of ‘flex’ version 2.5.9, this leak means that you +did not call ‘yylex_destroy()’. If you are using an earlier version of +‘flex’, then read on. The leak is about 16426 bytes. That is, (8192 * 2 + 2) for the -read-buffer, and about 40 for 'struct yy_buffer_state' (depending upon +read-buffer, and about 40 for ‘struct yy_buffer_state’ (depending upon alignment). The leak is in the non-reentrant C scanner only (NOT in the -reentrant scanner, NOT in the C++ scanner). Since 'flex' doesn't know +reentrant scanner, NOT in the C++ scanner). Since ‘flex’ doesn't know when you are done, the buffer is never freed. However, the leak won't multiply since the buffer is reused no matter -how many times you call 'yylex()'. +how many times you call ‘yylex()’. If you want to reclaim the memory when you are completely done scanning, then you might try this: @@ -5084,7 +5083,7 @@ scanning, then you might try this: yy_delete_buffer(YY_CURRENT_BUFFER); yy_init = 1; - Note: 'yy_init' is an "internal variable", and hasn't been tested in + Note: ‘yy_init’ is an "internal variable", and hasn't been tested in this situation. It is possible that some other globals may need resetting as well. @@ -5100,24 +5099,24 @@ How do I track the byte offset for lseek()? > seek_position = (no_buffers)*YY_READ_BUF_SIZE + yy_c_buf_p - YY_CURRENT_BUFFER->yy_ch_buf While this is the right idea, it has two problems. The first is that -it's possible that 'flex' will request less than 'YY_READ_BUF_SIZE' -during an invocation of 'YY_INPUT' (or that your input source will -return less even though 'YY_READ_BUF_SIZE' bytes were requested). The -second problem is that when refilling its internal buffer, 'flex' keeps +it's possible that ‘flex’ will request less than ‘YY_READ_BUF_SIZE’ +during an invocation of ‘YY_INPUT’ (or that your input source will +return less even though ‘YY_READ_BUF_SIZE’ bytes were requested). The +second problem is that when refilling its internal buffer, ‘flex’ keeps some characters from the previous buffer (because usually it's in the -middle of a match, and needs those characters to construct 'yytext' for -the match once it's done). Because of this, 'yy_c_buf_p - -YY_CURRENT_BUFFER->yy_ch_buf' won't be exactly the number of characters +middle of a match, and needs those characters to construct ‘yytext’ for +the match once it's done). Because of this, ‘yy_c_buf_p - +YY_CURRENT_BUFFER->yy_ch_buf’ won't be exactly the number of characters already read from the current buffer. An alternative solution is to count the number of characters you've matched since starting to scan. This can be done by using -'YY_USER_ACTION'. For example, +‘YY_USER_ACTION’. For example, #define YY_USER_ACTION num_chars += yyleng; (You need to be careful to update your bookkeeping if you use -'yymore('), 'yyless()', 'unput()', or 'input()'.) +‘yymore(’), ‘yyless()’, ‘unput()’, or ‘input()’.)  File: flex.info, Node: How do I use my own I/O classes in a C++ scanner?, Next: How do I skip as many chars as possible?, Prev: How do I track the byte offset for lseek()?, Up: FAQ @@ -5129,11 +5128,11 @@ When the flex C++ scanning class rewrite finally happens, then this sort of thing should become much easier. You can do this by passing the various functions (such as -'LexerInput()' and 'LexerOutput()') NULL 'iostream*''s, and then dealing +‘LexerInput()’ and ‘LexerOutput()’) NULL ‘iostream*’'s, and then dealing with your own I/O classes surreptitiously (i.e., stashing them in special member variables). This works because the only assumption about the lexer regarding what's done with the iostream's is that they're -ultimately passed to 'LexerInput()' and 'LexerOutput', which then do +ultimately passed to ‘LexerInput()’ and ‘LexerOutput’, which then do whatever is necessary with them.  @@ -5178,7 +5177,7 @@ deleteme00 QUESTION: When was flex born? - + Vern Paxson took over the Software Tools lex project from Jef Poskanzer in 1982. At that point it was written in Ratfor. Around 1987 or so, Paxson translated it into C, and @@ -5195,29 +5194,29 @@ Are certain equivalent patterns faster than others? In-reply-to: Your message of Wed, 18 Sep 96 11:12:17 EDT. Date: Wed, 18 Sep 96 10:51:02 PDT From: Vern Paxson - + [Note, the most recent flex release is 2.5.4, which you can get from ftp.ee.lbl.gov. It has bug fixes over 2.5.2 and 2.5.3.] - + > 1. Using the pattern > ([Ff](oot)?)?[Nn](ote)?(\.)? > instead of > (((F|f)oot(N|n)ote)|((N|n)ote)|((N|n)\.)|((F|f)(N|n)(\.))) > (in a very complicated flex program) caused the program to slow from > 300K+/min to 100K/min (no other changes were done). - + These two are not equivalent. For example, the first can match "footnote." but the second can only match "footnote". This is almost certainly the cause in the discrepancy - the slower scanner run is matching more tokens, and/or having to do more backing up. - + > 2. Which of these two are better: [Ff]oot or (F|f)oot ? - + From a performance point of view, they're equivalent (modulo presumably minor effects such as memory cache hit rates; and the presence of trailing context, see below). From a space point of view, the first is slightly preferable. - + > 3. I have a pattern that look like this: > pats {p1}|{p2}|{p3}|...|{p50} (50 patterns ORd) > @@ -5225,22 +5224,22 @@ Are certain equivalent patterns faster than others? > {and}/{no4}{bb}{pats} > > gets me to "too complicated - over 32,000 states"... - + I can't tell from this example whether the trailing context is variable-length or fixed-length (it could be the latter if {and} is fixed-length). If it's variable length, which flex -p will tell you, then this reflects a basic performance problem, and if you can eliminate it by restructuring your scanner, you will see significant improvement. - + > so I divided {pats} to {pats1}, {pats2},..., {pats5} each consists of about > 10 patterns and changed the rule to be 5 rules. > This did compile, but what is the rule of thumb here ? - + The rule is to avoid trailing context other than fixed-length, in which for a/b, either the 'a' pattern or the 'b' pattern have a fixed length. Use of the '|' operator automatically makes the pattern variable length, so in this case '[Ff]oot' is preferred to '(F|f)oot'. - + > 4. I changed a rule that looked like this: > {and}{bb}/{ROMAN}[^A-Za-z] { BEGIN... > @@ -5249,16 +5248,16 @@ Are certain equivalent patterns faster than others? > {and}{bb}/{ROMAN} { BEGIN... > > Again, I understand the using [^...] will cause a great performance loss - + Actually, it doesn't cause any sort of performance loss. It's a surprising fact about regular expressions that they always match in linear time regardless of how complex they are. - + > but are there any specific rules about it ? - + See the "Performance Considerations" section of the man page, and also the example in MISC/fastwc/. - + Vern  @@ -5272,45 +5271,45 @@ Is backing up a big deal? In-reply-to: Your message of Thu, 19 Sep 96 10:16:04 EDT. Date: Thu, 19 Sep 96 09:58:00 PDT From: Vern Paxson - + > a lot about the backing up problem. > I believe that there lies my biggest problem, and I'll try to improve > it. - + Since you have variable trailing context, this is a bigger performance problem. Fixing it is usually easier than fixing backing up, which in a complicated scanner (yours seems to fit the bill) can be extremely difficult to do correctly. - + You also don't mention what flags you are using for your scanner. -f makes a large speed difference, and -Cfe buys you nearly as much speed but the resulting scanner is considerably smaller. - + > I have an | operator in {and} and in {pats} so both of them are variable > length. - + -p should have reported this. - + > Is changing one of them to fixed-length is enough ? - + Yes. - + > Is it possible to change the 32,000 states limit ? - + Yes. I've appended instructions on how. Before you make this change, though, you should think about whether there are ways to fundamentally simplify your scanner - those are certainly preferable! - + Vern - + To increase the 32K limit (on a machine with 32 bit integers), you increase the magnitude of the following in flexdef.h: - + #define JAMSTATE -32766 /* marks a reference to the state that always jams */ #define MAXIMUM_MNS 31999 #define BAD_SUBSCRIPT -32767 #define MAX_SHORT 32700 - + Adding a 0 or two after each should do the trick.  @@ -5324,31 +5323,31 @@ Can I fake multi-byte character support? In-reply-to: Your message of Thu, 03 Oct 1996 17:24:04 PDT. Date: Fri, 04 Oct 1996 11:42:18 PDT From: Vern Paxson - + > I assume as long as my *.l file defines the > range of expected character code values (in octal format), flex will > scan the file and read multi-byte characters correctly. But I have no > confidence in this assumption. - + Your lack of confidence is justified - this won't work. - + Flex has in it a widespread assumption that the input is processed one byte at a time. Fixing this is on the to-do list, but is involved, so it won't happen any time soon. In the interim, the best I can suggest (unless you want to try fixing it yourself) is to write your rules in terms of pairs of bytes, using definitions in the first section: - + X \xfe\xc2 ... %% foo{X}bar found_foo_fe_c2_bar(); - + etc. Definitely a pain - sorry about that. - + By the way, the email address you used for me is ancient, indicating you have a very old version of flex. You can get the most recent, 2.5.4, from ftp.ee.lbl.gov. - + Vern  @@ -5362,7 +5361,7 @@ deleteme01 In-reply-to: Your message of Tue, 22 Oct 1996 10:15:42 PDT. Date: Tue, 22 Oct 1996 11:06:13 PDT From: Vern Paxson - + Unfortunately flex at the moment has a widespread assumption within it that characters are processed 8 bits at a time. I don't see any easy fix for this (other than writing your rules in terms of double characters - @@ -5370,11 +5369,11 @@ deleteme01 the Plan 9 stuff because I know it's a Unicode system, and also the PCCT toolkit (try searching say Alta Vista for "Purdue Compiler Construction Toolkit"). - + Fixing flex to handle wider characters is on the long-term to-do list. But since flex is a strictly spare-time project these days, this probably won't happen for quite a while, unless someone else does it first. - + Vern  @@ -5388,30 +5387,30 @@ Can you discuss some flex internals? In-reply-to: Your message of Sun, 10 Nov 1996 09:16:36 PST. Date: Mon, 11 Nov 1996 10:33:50 PST From: Vern Paxson - + > I'm working for the Swedish team translating GNU program, and I'm currently > working with flex. I have a few questions about some of the messages which > I hope you can answer. - + All of the things you're wondering about, by the way, concerning flex internals - probably the only person who understands what they mean in English is me! So I wouldn't worry too much about getting them right. That said ... - + > #: main.c:545 > msgid " %d protos created\n" > > Does proto mean prototype? - + Yes - prototypes of state compression tables. - + > #: main.c:539 > msgid " %d/%d (peak %d) template nxt-chk entries created\n" > > Here I'm mainly puzzled by 'nxt-chk'. I guess it means 'next-check'. (?) > However, 'template next-check entries' doesn't make much sense to me. To be > able to find a good translation I need to know a little bit more about it. - + There is a scheme in the Aho/Sethi/Ullman compiler book for compressing scanner tables. It involves creating two pairs of tables. The first has "base" and "default" entries, the second has "next" and "check" entries. @@ -5422,14 +5421,14 @@ Can you discuss some flex internals? correct for the current state. Flex creates templates of series of next/check entries and then encodes differences from these templates as a way to compress the tables. - + > #: main.c:533 > msgid " %d/%d base-def entries created\n" > > The same problem here for 'base-def'. - + See above. - + Vern  @@ -5443,23 +5442,23 @@ unput() messes up yy_at_bol In-reply-to: Your message of Wed, 13 Nov 1996 17:28:38 PST. Date: Wed, 13 Nov 1996 19:51:54 PST From: Vern Paxson - + > "unput()" them to input flow, question occurs. If I do this after I scan > a carriage, the variable "YY_CURRENT_BUFFER->yy_at_bol" is changed. That > means the carriage flag has gone. - + You can control this by calling yy_set_bol(). It's described in the manual. - + > And if in pre-reading it goes to the end of file, is anything done > to control the end of curren buffer and end of file? - + No, there's no way to put back an end-of-file. - + > By the way I am using flex 2.5.2 and using the "-l". - + The latest release is 2.5.4, by the way. It fixes some bugs in 2.5.2 and 2.5.3. You can get it from ftp.ee.lbl.gov. - + Vern  @@ -5473,33 +5472,33 @@ The | operator is not doing what I want In-reply-to: Your message of Mon, 18 Nov 1996 09:45:02 PST. Date: Mon, 18 Nov 1996 10:41:34 PST From: Vern Paxson - + > I am not able to use the start condition scope and to use the | (OR) with > rules having start conditions. - + The problem is that if you use '|' as a regular expression operator, for example "a|b" meaning "match either 'a' or 'b'", then it must *not* have any blanks around it. If you instead want the special '|' *action* (which from your scanner appears to be the case), which is a way of giving two different rules the same action: - + foo | bar matched_foo_or_bar(); - + then '|' *must* be separated from the first rule by whitespace and *must* be followed by a new line. You *cannot* write it as: - + foo | bar matched_foo_or_bar(); - + even though you might think you could because yacc supports this syntax. The reason for this unfortunately incompatibility is historical, but it's unlikely to be changed. - + Your problems with start condition scope are simply due to syntax errors from your use of '|' later confusing flex. - + Let me know if you still have problems. - + Vern  @@ -5513,10 +5512,10 @@ Why can't flex understand this variable trailing context pattern? In-reply-to: Your message of Sat, 23 Nov 1996 16:50:09 PST. Date: Sat, 23 Nov 1996 17:07:32 PST From: Vern Paxson - + > Enclosed is a lex file that "real" lex will process, but I cannot get > flex to process it. Could you try it and maybe point me in the right direction? - + Your problem is that some of the definitions in the scanner use the '/' trailing context operator, and have it enclosed in ()'s. Flex does not allow this operator to be enclosed in ()'s because doing so allows undefined @@ -5524,7 +5523,7 @@ Why can't flex understand this variable trailing context pattern? parentheses. Note that you must also be building the scanner with the -l option for AT&T lex compatibility. Without this option, flex automatically encloses the definitions in parentheses. - + Vern  @@ -5538,29 +5537,29 @@ The ^ operator isn't working In-reply-to: Your message of Tue, 26 Nov 1996 14:35:01 PST. Date: Tue, 26 Nov 1996 11:15:05 PST From: Vern Paxson - + > In my lexer code, i have the line : > ^\*.* { } > > Thus all lines starting with an astrix (*) are comment lines. > This does not work ! - + I can't get this problem to reproduce - it works fine for me. Note though that if what you have is slightly different: - + COMMENT ^\*.* %% {COMMENT} { } - + then it won't work, because flex pushes back macro definitions enclosed in ()'s, so the rule becomes - + (^\*.*) { } - + and now that the '^' operator is not at the immediate beginning of the line, it's interpreted as just a regular character. You can avoid this behavior by using the "-l" lex-compatibility flag, or "%option lex-compat". - + Vern  @@ -5574,23 +5573,23 @@ Trailing context is getting confused with trailing optional patterns In-reply-to: Your message of Tue, 26 Nov 1996 16:10:41 PST. Date: Wed, 27 Nov 1996 10:56:25 PST From: Vern Paxson - + > Organization(s)?/[a-z] > > This matched "Organizations" (looking in debug mode, the trailing s > was matched with trailing context instead of the optional (s) in the > end of the word. - + That should only happen with lex. Flex can properly match this pattern. (That might be what you're saying, I'm just not sure.) - + > Is there a way to avoid this dangerous trailing context problem ? - + Unfortunately, there's no easy way. On the other hand, I don't see why it should be a problem. Lex's matching is clearly wrong, and I'd hope that usually the intent remains the same as expressed with the pattern, so flex's matching will be correct. - + Vern  @@ -5604,33 +5603,33 @@ Is flex GNU or not? In-reply-to: Your message of Mon, 02 Dec 1996 00:07:08 PST. Date: Sun, 01 Dec 1996 22:29:39 PST From: Vern Paxson - + > I'm not sure how or where to submit bug reports (documentation or > otherwise) for the GNU project stuff ... - + Well, strictly speaking flex isn't part of the GNU project. They just distribute it because no one's written a decent GPL'd lex replacement. So you should send bugs directly to me. Those sent to the GNU folks sometimes find there way to me, but some may drop between the cracks. - + > In GNU Info, under the section 'Start Conditions', and also in the man > page (mine's dated April '95) is a nice little snippet showing how to > parse C quoted strings into a buffer, defined to be MAX_STR_CONST in > size. Unfortunately, no overflow checking is ever done ... - + This is already mentioned in the manual: - + Finally, here's an example of how to match C-style quoted strings using exclusive start conditions, including expanded escape sequences (but not including checking for a string that's too long): - + The reason for not doing the overflow checking is that it will needlessly clutter up an example whose main purpose is just to demonstrate how to use flex. - + The latest release is 2.5.4, by the way, available from ftp.ee.lbl.gov. - + Vern  @@ -5644,18 +5643,18 @@ ERASEME53 In-reply-to: Your message of Thu, 06 Mar 1997 23:50:16 PST. Date: Thu, 06 Mar 1997 15:54:19 PST From: Vern Paxson - + > [:alpha:] ([:alnum:] | \\_)* - + If your rule really has embedded blanks as shown above, then it won't work, as the first blank delimits the rule from the action. (It wouldn't even compile ...) You need instead: - + [:alpha:]([:alnum:]|\\_)* - + and that should work fine - there's no restriction on what can go inside of ()'s except for the trailing context operator, '/'. - + Vern  @@ -5669,21 +5668,21 @@ I need to scan if-then-else blocks and while loops In-reply-to: Your message of Fri, 30 May 1997 13:33:27 PDT. Date: Fri, 30 May 1997 10:46:35 PDT From: Vern Paxson - + > We'd like to add "if-then-else", "while", and "for" statements to our > language ... > We've investigated many possible solutions. The one solution that seems > the most reasonable involves knowing the position of a TOKEN in yyin. - + I strongly advise you to instead build a parse tree (abstract syntax tree) and loop over that instead. You'll find this has major benefits in keeping your interpreter simple and extensible. - + That said, the functionality you mention for get_position and set_position have been on the to-do list for a while. As flex is a purely spare-time project for me, no guarantees when this will be added (in particular, it for sure won't be for many months to come). - + Vern  @@ -5697,7 +5696,7 @@ ERASEME55 In-reply-to: Your message of 09 Aug 1997 17:11:41 PDT. Date: Fri, 15 Aug 1997 10:48:19 PDT From: Vern Paxson - + > #define YY_DECL int yylex (YYSTYPE *lvalp, struct parser_control > *parm) > @@ -5708,11 +5707,11 @@ ERASEME55 > Is this supposed to be possible, or is it being worked on (I DID > notice the comment that scanner classes are still experimental, so I'm > not too hopeful)? - + What you need to do is derive a subclass from yyFlexLexer that provides the above yylex() method, squirrels away lvalp and parm into member variables, and then invokes yyFlexLexer::yylex() to do the regular scanning. - + Vern  @@ -5726,29 +5725,29 @@ ERASEME56 In-reply-to: Your message of Fri, 05 Sep 1997 16:07:24 PDT. Date: Fri, 05 Sep 1997 10:01:54 PDT From: Vern Paxson - + > In that example you show how to count comment lines when using > C style /* ... */ comments. My question is, shouldn't you take into > account a scenario where end of a comment marker occurs inside > character or string literals? - + The scanner certainly needs to also scan character and string literals. However it does that (there's an example in the man page for strings), the lexer will recognize the beginning of the literal before it runs across the embedded "/*". Consequently, it will finish scanning the literal before it even considers the possibility of matching "/*". - + Example: - + '([^']*|{ESCAPE_SEQUENCE})' - + will match all the text between the ''s (inclusive). So the lexer considers this as a token beginning at the first ', and doesn't even attempt to match other tokens inside it. - + I thinnk this subtlety is not worth putting in the manual, as I suspect it would confuse more people than it would enlighten. - + Vern  @@ -5762,25 +5761,25 @@ ERASEME57 In-reply-to: Your message of Sat, 06 Sep 1997 11:27:21 PDT. Date: Mon, 08 Sep 1997 11:38:08 PDT From: Vern Paxson - + > %% > [a-zA-Z]+ /* skip a line */ > { printf("got %s\n", yytext); } > %% - + What version of flex are you using? If I feed this to 2.5.4, it complains: - + "bug.l", line 5: EOF encountered inside an action "bug.l", line 5: unrecognized rule "bug.l", line 5: fatal parse error - + Not the world's greatest error message, but it manages to flag the problem. - + (With the introduction of start condition scopes, flex can't accommodate an action on a separate line, since it's ambiguous with an indented rule.) - + You can get 2.5.4 from ftp.ee.lbl.gov. - + Vern  @@ -5833,26 +5832,26 @@ unnamed-faq-62 In-reply-to: Your message of Mon, 17 Nov 1997 17:16:06 PST. Date: Mon, 17 Nov 1997 17:16:15 PST From: Vern Paxson - + > I took a quick look into the flex-sources and altered some #defines in > flexdefs.h: > > #define INITIAL_MNS 64000 > #define MNS_INCREMENT 1024000 > #define MAXIMUM_MNS 64000 - + The things to fix are to add a couple of zeroes to: - + #define JAMSTATE -32766 /* marks a reference to the state that always jams */ #define MAXIMUM_MNS 31999 #define BAD_SUBSCRIPT -32767 #define MAX_SHORT 32700 - + and, if you get complaints about too many rules, make the following change too: - + #define YY_TRAILING_MASK 0x200000 #define YY_TRAILING_HEAD_MASK 0x400000 - + - Vern  @@ -5866,7 +5865,7 @@ unnamed-faq-63 In-reply-to: Your message of Mon, 08 Dec 1997 15:54:15 PST. Date: Mon, 15 Dec 1997 13:21:35 PST From: Vern Paxson - + > stdin_handle = YY_CURRENT_BUFFER; > ifstream fin( "aFile" ); > yy_switch_to_buffer( yy_create_buffer( fin, YY_BUF_SIZE ) ); @@ -5880,11 +5879,11 @@ unnamed-faq-63 > first argument (as stated in the man page). However, fin is a ifstream > object. Any ideas on what I might be doing wrong? Any help would be > appreciated. Thanks!! - + You need to pass &fin, to turn it into an ifstream* instead of an ifstream. Then its type will be compatible with the expected istream*, because ifstream is derived from istream. - + Vern  @@ -5898,22 +5897,22 @@ unnamed-faq-64 In-reply-to: Your message of Tue, 16 Dec 1997 15:17:34 PST. Date: Tue, 16 Dec 1997 14:17:09 PST From: Vern Paxson - + > Can you explain to me what is ment by a long-jump in relation to flex? - + Using the longjmp() function while inside yylex() or a routine called by it. - + > what is the flex activation frame. - + Just yylex()'s stack frame. - + > As far as I can see yyrestart will bring me back to the sart of the input > file and using flex++ isnot really an option! - + No, yyrestart() doesn't imply a rewind, even though its name might sound like it does. It tells the scanner to flush its internal buffers and start reading from the given file at its present location. - + Vern  @@ -5927,7 +5926,7 @@ unnamed-faq-65 In-reply-to: Your message of Sat, 20 Dec 1997 19:38:19 PST. Date: Sun, 21 Dec 1997 21:30:46 PST From: Vern Paxson - + > /usr/lib/yaccpar: In function `int yyparse()': > /usr/lib/yaccpar:184: warning: implicit declaration of function `int yylex(...)' > @@ -5935,11 +5934,11 @@ unnamed-faq-65 > _yylex > _yyparse > _yyin - + This is a known problem with Solaris C++ (and/or Solaris yacc). I believe the fix is to explicitly insert some 'extern "C"' statements for the corresponding routines/symbols. - + Vern  @@ -5954,7 +5953,7 @@ unnamed-faq-66 In-reply-to: Your message of Fri, 12 Dec 1997 17:57:29 PST. Date: Sun, 21 Dec 1997 22:33:37 PST From: Vern Paxson - + > This is my definition for float and integer types: > . . . > NZD [1-9] @@ -5962,14 +5961,14 @@ unnamed-faq-66 > I've tested my program on other lex version (on UNIX Sun Solaris an HP > UNIX) and it work well, so I think that my definitions are correct. > There are any differences between Lex and Flex? - + There are indeed differences, as discussed in the man page. The one you are probably running into is that when flex expands a name definition, it puts parentheses around the expansion, while lex does not. There's an example in the man page of how this can lead to different matching. Flex's behavior complies with the POSIX standard (or at least with the last POSIX draft I saw). - + Vern  @@ -5983,18 +5982,18 @@ unnamed-faq-67 In-reply-to: Your message of Mon, 22 Dec 1997 16:06:35 PST. Date: Mon, 22 Dec 1997 14:35:05 PST From: Vern Paxson - + > Thank you very much for your help. I compile and link well with C++ while > declaring 'yylex ...' extern, But a little problem remains. I get a > segmentation default when executing ( I linked with lfl library) while it > works well when using LEX instead of flex. Do you have some ideas about the > reason for this ? - + The one possible reason for this that comes to mind is if you've defined yytext as "extern char yytext[]" (which is what lex uses) instead of "extern char *yytext" (which is what flex uses). If it's not that, then I'm afraid I don't know what the problem might be. - + Vern  @@ -6008,10 +6007,10 @@ unnamed-faq-68 In-reply-to: Your message of Tue, 06 Jan 1998 10:34:21 PST. Date: Tue, 06 Jan 1998 19:19:30 PST From: Vern Paxson - + > The problem is that when I do this (using %option c++) start > conditions seem to not apply. - + The BEGIN macro modifies the yy_start variable. For C scanners, this is a static with scope visible through the whole file. For C++ scanners, it's a member variable, so it only has visible scope within a member @@ -6021,7 +6020,7 @@ unnamed-faq-68 a declaration of yy_start in order to get your scanner to compile when using C++; instead, the correct fix is to make lexbegin() a member function (by deriving from yyFlexLexer). - + Vern  @@ -6035,15 +6034,15 @@ unnamed-faq-69 In-reply-to: Your message of Mon, 12 Jan 1998 18:58:23 PST. Date: Mon, 12 Jan 1998 12:03:15 PST From: Vern Paxson - + > The problem is how to determine the current position in flex active > buffer when a rule is matched.... - + You will need to keep track of this explicitly, such as by redefining YY_USER_ACTION to count the number of characters matched. - + The latest flex release, by the way, is 2.5.4, available from ftp.ee.lbl.gov. - + Vern  @@ -6057,16 +6056,16 @@ unnamed-faq-70 In-reply-to: Your message of Mon, 26 Jan 1998 13:05:35 PST. Date: Tue, 27 Jan 1998 22:41:52 PST From: Vern Paxson - + > That requirement involves knowing > the character position at which a particular token was matched > in the lexer. - + The way you have to do this is by explicitly keeping track of where you are in the file, by counting the number of characters scanned for each token (available in yyleng). It may prove convenient to do this by redefining YY_USER_ACTION, as described in the manual. - + Vern  @@ -6080,22 +6079,22 @@ unnamed-faq-71 In-reply-to: Your message of Mon, 26 Jan 1998 05:50:16 PST. Date: Tue, 27 Jan 1998 22:45:37 PST From: Vern Paxson - + > It seems useful for the parser to be able to tell the lexer about such > context dependencies, because then they don't have to be limited to > local or sequential context. - + One way to do this is to have the parser call a stub routine that's included in the scanner's .l file, and consequently that has access ot BEGIN. The only ugliness is that the parser can't pass in the state it wants, because those aren't visible - but if you don't have many such states, then using a different set of names doesn't seem like to much of a burden. - + While generating a .h file like you suggests is certainly cleaner, flex development has come to a virtual stand-still :-(, so a workaround like the above is much more pragmatic than waiting for a new feature. - + Vern  @@ -6109,16 +6108,16 @@ unnamed-faq-72 In-reply-to: Your message of Fri, 30 Jan 1998 12:00:43 PST. Date: Fri, 30 Jan 1998 12:42:32 PST From: Vern Paxson - + > lex.yy.c:1996: parse error before `=' - + This is the key, identifying this error. (It may help to pinpoint it by using flex -L, so it doesn't generate #line directives in its output.) I will bet you heavy money that you have a start condition name that is also a variable name, or something like that; flex spits out #define's for each start condition name, mapping them to a number, so you can wind up with: - + %x foo %% ... @@ -6127,10 +6126,10 @@ unnamed-faq-72 { int foo = 3; } - + and the penultimate will turn into "int 1 = 3" after C preprocessing, since flex will put "#define foo 1" in the generated scanner. - + Vern  @@ -6144,19 +6143,19 @@ unnamed-faq-73 In-reply-to: Your message of Mon, 02 Feb 1998 14:10:01 PST. Date: Mon, 02 Feb 1998 11:15:12 PST From: Vern Paxson - + > I am curious as to > whether there is a simple way to backtrack from the generated source to > reproduce the lost list of tokens we are searching on. - + In theory, it's straight-forward to go from the DFA representation back to a regular-expression representation - the two are isomorphic. In practice, a huge headache, because you have to unpack all the tables back into a single DFA representation, and then write a program to munch on that and translate it into an RE. - + Sorry for the less-than-happy news ... - + Vern  @@ -6170,21 +6169,21 @@ unnamed-faq-74 In-reply-to: Your message of Thu, 19 Feb 1998 11:01:17 PST. Date: Thu, 19 Feb 1998 08:48:51 PST From: Vern Paxson - + > What I have found, is that the smaller the data chunk, the faster the > program executes. This is the opposite of what I expected. Should this be > happening this way? - + This is exactly what will happen if your input file has embedded NULs. From the man page: - + A final note: flex is slow when matching NUL's, particularly when a token contains multiple NUL's. It's best to write rules which match short amounts of text if it's anticipated that the text will often include NUL's. - + So that's the first thing to look for. - + Vern  @@ -6198,31 +6197,31 @@ unnamed-faq-75 In-reply-to: Your message of Thu, 19 Feb 1998 11:01:17 PST. Date: Thu, 19 Feb 1998 15:42:25 PST From: Vern Paxson - + So there are several problems. - + First, to go fast, you want to match as much text as possible, which your scanners don't in the case that what they're scanning is *not* a tag. So you want a rule like: - + [^<]+ - + Second, C++ scanners are particularly slow if they're interactive, which they are by default. Using -B speeds it up by a factor of 3-4 on my workstation. - + Third, C++ scanners that use the istream interface are slow, because of how poorly implemented istream's are. I built two versions of the following scanner: - + %% .*\n .* %% - + and the C version inhales a 2.5MB file on my workstation in 0.8 seconds. The C++ istream version, using -B, takes 3.8 seconds. - + Vern  @@ -6236,14 +6235,14 @@ unnamed-faq-76 In-reply-to: Your message of Wed, 03 Jun 1998 11:26:22 PDT. Date: Wed, 03 Jun 1998 10:22:26 PDT From: Vern Paxson - + > I am researching the Y2K problem with General Electric R&D > and need to know if there are any known issues concerning > the above mentioned software and Y2K regardless of version. - + There shouldn't be, all it ever does with the date is ask the system for it and then print it out. - + Vern  @@ -6257,16 +6256,16 @@ unnamed-faq-77 In-reply-to: Your message of Wed, 15 Jul 1998 21:30:13 PDT. Date: Tue, 21 Jul 1998 14:23:34 PDT From: Vern Paxson - + > To overcome this, I gets() the stdin into a string and lex the string. The > string is lexed OK except that the end of string isn't lexed properly > (yy_scan_string()), that is the lexer dosn't recognise the end of string. - + Flex doesn't contain mechanisms for recognizing buffer endpoints. But if you use fgets instead (which you should anyway, to protect against buffer overflows), then the final \n will be preserved in the string, and you can scan that in order to find the end of the string. - + Vern  @@ -6280,7 +6279,7 @@ unnamed-faq-78 In-reply-to: Your message of Mon, 27 Jul 1998 02:10:04 PDT. Date: Tue, 28 Jul 1998 01:10:34 PDT From: Vern Paxson - + > %{ > int mylineno = 0; > %} @@ -6296,9 +6295,9 @@ unnamed-faq-78 > > How will this work if I want to run a multi-threaded application with each > thread creating a FlexLexer instance? - + Derive your own subclass and make mylineno a member variable of it. - + Vern  @@ -6312,7 +6311,7 @@ unnamed-faq-79 In-reply-to: Your message of Tue, 04 Aug 1998 16:55:39 PDT. Date: Tue, 04 Aug 1998 22:28:45 PDT From: Vern Paxson - + > Vern Paxson, > > I followed your advice, posted on Usenet bu you, and emailed to me @@ -6327,25 +6326,25 @@ unnamed-faq-79 > > and compiled. > All looked fine, including check and bigcheck, so I installed. - + Hmmm, you shouldn't increase MAX_SHORT, though looking through my email archives I see that I did indeed recommend doing so. Try setting it back to 32700; that should suffice that you no longer need -Ca. If it still hangs, then the interesting question is - where? - + > Compiling the same hanged program with a out-of-the-box (RedHat 4.2 > distribution of Linux) > flex 2.5.4 binary works. - + Since Linux comes with source code, you should diff it against what you have to see what problems they missed. - + > Should I always compile with the -Ca option now ? even short and simple > filters ? - + No, definitely not. It's meant to be for those situations where you absolutely must squeeze every last cycle out of your scanner. - + Vern  @@ -6359,10 +6358,10 @@ unnamed-faq-80 In-reply-to: Your message of Tue, 11 Aug 1998 11:55:30 PDT. Date: Mon, 17 Aug 1998 23:57:42 PDT From: Vern Paxson - + > I would like to use flex under the hood to generate a binary file > containing the data structures that control the parse. - + This has been on the wish-list for a long time. In principle it's straight-forward - you redirect mkdata() et al's I/O to another file, and modify the skeleton to have a start-up function that slurps these @@ -6371,12 +6370,12 @@ unnamed-faq-80 going down this path :-( ; and (2) being careful about buffering so that when the tables change you make sure the scanner starts in the correct state and reading at the right point in the input file. - + > I was wondering if you know of anyone who has used flex in this way. - + I don't - but it seems like a reasonable project to undertake (unlike numerous other flex tweaks :-). - + Vern  @@ -6404,30 +6403,30 @@ unnamed-faq-81 MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit - + Hi Vern, - + Yesterday, I encountered a strange problem: I use the macro processor m4 to include some lengthy lists into a .l file. Following is a flex macro definition that causes some serious pain in my neck: - + AUTHOR ("A. Boucard / L. Boucard"|"A. Dastarac / M. Levent"|"A.Boucaud / L.Boucaud"|"Abderrahim Lamchichi"|"Achmat Dangor"|"Adeline Toullier"|"Adewale Maja-Pearce"|"Ahmed Ziri"|"Akram Ellyas"|"Alain Bihr"|"Alain Gresh"|"Alain Guillemoles"|"Alain Joxe"|"Alain Morice"|"Alain Renon"|"Alain Zecchini"|"Albert Memmi"|"Alberto Manguel"|"Alex De Waal"|"Alfonso Artico"| [...]) - + The complete list contains about 10kB. When I try to "flex" this file (on a Solaris 2.6 machine, using a modified flex 2.5.4 (I only increased some of the predefined values in flexdefs.h) I get the error: - + myflex/flex -8 sentag.tmp.l flex scanner push-back overflow - + When I remove the slashes in the macro definition everything works fine. As I understand it, the double quotes escape the slash-character so it really means "/" and not "trailing context". Furthermore, I tried to escape the slashes with backslashes, but with no use, the same error message appeared when flexing the code. - + Do you have an idea what's going on here? - + Greetings from Germany, Georg -- @@ -6445,21 +6444,21 @@ unnamed-faq-82 In-reply-to: Your message of Thu, 20 Aug 1998 09:47:54 PDT. Date: Thu, 20 Aug 1998 07:05:35 PDT From: Vern Paxson - + > myflex/flex -8 sentag.tmp.l > flex scanner push-back overflow - + Flex itself uses a flex scanner. That scanner is running out of buffer space when it tries to unput() the humongous macro you've defined. When you remove the '/'s, you make it small enough so that it fits in the buffer; removing spaces would do the same thing. - + The fix is to either rethink how come you're using such a big macro and perhaps there's another/better way to do it; or to rebuild flex's own scan.c with a larger value for - + #define YY_BUF_SIZE 16384 - + - Vern  @@ -6473,7 +6472,7 @@ unnamed-faq-83 In-reply-to: Your message of Fri, 04 Sep 1998 12:18:43 +0200. Date: Sat, 05 Sep 1998 00:59:49 PDT From: Vern Paxson - + > %% > > "TEST1\n" { fprintf(stderr, "TEST1\n"); yyless(5); } @@ -6488,7 +6487,7 @@ unnamed-faq-83 > TEST1 > empty line > ------------------------------------------------ - + IMHO, it's not clear whether or not this is in fact a bug. It depends on whether you view yyless() as backing up in the input stream, or as pushing new characters onto the beginning of the input stream. Flex @@ -6496,16 +6495,16 @@ unnamed-faq-83 and so considers the newline as in fact matching at the beginning of a line, as after all the last token scanned an entire line and so the scanner is now at the beginning of a new line. - + I agree that this is counter-intuitive for yyless(), given its functional description (it's less so for unput(), depending on whether you're unput()'ing new text or scanned text). But I don't plan to change it any time soon, as it's a pain to do so. Consequently, you do indeed need to use yy_set_bol() and YY_AT_BOL() to tweak your scanner into the behavior you desire. - + Sorry for the less-than-completely-satisfactory answer. - + Vern  @@ -6519,19 +6518,19 @@ unnamed-faq-84 In-reply-to: Your message of Thu, 24 Sep 1998 10:14:07 PDT. Date: Thu, 24 Sep 1998 23:28:43 PDT From: Vern Paxson - + > I am using flex-2.5.2 and bison 1.25 for Solaris and I am desperately > trying to make my scanner restart with a new file after my parser stops > with a parse error. When my compiler restarts, the parser always > receives the token after the token (in the old file!) that caused the > parser error. - + I suspect the problem is that your parser has read ahead in order to attempt to resolve an ambiguity, and when it's restarted it picks up with that token rather than reading a fresh one. If you're using yacc, then the special "error" production can sometimes be used to consume tokens in an attempt to get the parser into a consistent state. - + Vern  @@ -6545,26 +6544,26 @@ unnamed-faq-85 In-reply-to: Your message of Tue, 27 Oct 1998 16:41:42 PST. Date: Tue, 27 Oct 1998 16:50:14 PST From: Vern Paxson - + > This brings up a feature request: How about a command line > option to specify the filename when reading from stdin? That way one > doesn't need to create a temporary file in order to get the "#line" > directives to make sense. - + Use -o combined with -t (per the man page description of -o). - + > P.S., Is there any simple way to use non-blocking IO to parse multiple > streams? - + Simple, no. - + One approach might be to return a magic character on EWOULDBLOCK and have a rule - + .* // put back .*, eat magic character - + This is off the top of my head, not sure it'll work. - + Vern  @@ -6578,25 +6577,25 @@ unnamed-faq-86 In-reply-to: Your message of Wed, 13 Jan 1999 10:52:47 PST. Date: Thu, 14 Jan 1999 00:25:30 PST From: Vern Paxson - + > It appears that maybe it cannot find the lfl library. - + The Makefile in the distribution builds it, so you should have it. It's exceedingly trivial, just a main() that calls yylex() and a yyrap() that always returns 1. - + > %% > \n ++num_lines; ++num_chars; > . ++num_chars; - + You can't indent your rules like this - that's where the errors are coming from. Flex copies indented text to the output file, it's how you do things like - + int num_lines_seen = 0; - + to declare local variables. - + Vern  @@ -6610,13 +6609,13 @@ unnamed-faq-87 In-reply-to: Your message of Tue, 09 Feb 1999 13:53:46 PST. Date: Tue, 09 Feb 1999 21:03:37 PST From: Vern Paxson - + > In the flex.skl file the size of the default input buffers is set. Can you > explain why this size is set and why it is such a high number. - + It's large to optimize performance when scanning large files. You can safely make it a lot lower if needed. - + Vern  @@ -6630,20 +6629,20 @@ unnamed-faq-88 In-reply-to: Your message of Wed, 24 Feb 1999 15:31:46 PST. Date: Thu, 25 Feb 1999 00:11:31 PST From: Vern Paxson - + > I'm extending a larger scanner written in Flex and I keep running into > problems. More specifically, I get the error message: > "flex: input rules are too complicated (>= 32000 NFA states)" - + Increase the definitions in flexdef.h for: - + #define JAMSTATE -32766 /* marks a reference to the state that always j ams */ #define MAXIMUM_MNS 31999 #define BAD_SUBSCRIPT -32767 - + recompile everything, and it should all work. - + Vern  @@ -6657,28 +6656,28 @@ unnamed-faq-90 In-reply-to: Your message of Mon, 31 May 1999 18:44:49 PDT. Date: Tue, 01 Jun 1999 00:15:07 PDT From: Vern Paxson - + > I have a trouble with FLEX. Why rule "/*".*"*/" work properly,=20 > but rule "/*"(.|\n)*"*/" don't work ? - + The second of these will have to scan the entire input stream (because "(.|\n)*" matches an arbitrary amount of any text) in order to see if it ends with "*/", terminating the comment. That potentially will overflow the input buffer. - + > More complex rule "/*"([^*]|(\*/[^/]))*"*/ give an error > 'unrecognized rule'. - + You can't use the '/' operator inside parentheses. It's not clear what "(a/b)*" actually means. - + > I now use workaround with state , but single-rule is > better, i think. - + Single-rule is nice but will always have the problem of either setting restrictions on comments (like not allowing multi-line comments) and/or running the risk of consuming the entire input stream, as noted above. - + Vern  @@ -6705,47 +6704,47 @@ unnamed-faq-91 Organization: My Deja Email (http://www.my-deja.com:80) Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit - + Dear Dr. Paxon, - + I have been using flex for years. It works very well on many projects. Most case, I used it to generate a scanner on C language. However, one project I needed to generate a scanner on C++ lanuage. Thanks to your enhancement, flex did the job. - + Currently, I'm working on enhancing my previous project. I need to deal with multiple input streams (recursive inclusion) in this scanner (C++). I did similar thing for another scanner (C) as you explained in your documentation. - + The generated scanner (C++) has necessary methods: - switch_to_buffer(struct yy_buffer_state *b) - yy_create_buffer(istream *is, int sz) - yy_delete_buffer(struct yy_buffer_state *b) - + However, I couldn't figure out how to access current buffer (yy_current_buffer). - + yy_current_buffer is a protected member of yyFlexLexer. I can't access it directly. Then, I thought yy_create_buffer() with is = 0 might return current stream buffer. But it seems not as far as I checked the source. (flex 2.5.4) - + I went through the Web in addition to Flex documentation. However, it hasn't been successful, so far. - + It is not my intention to bother you, but, can you comment about how to obtain the current stream buffer? - + Your response would be highly appreciated. - + Best regards, Aki Niimura - + --== Sent via Deja.com http://www.deja.com/ ==-- Share what you know. Learn what you don't. @@ -6760,12 +6759,12 @@ unnamed-faq-92 In-reply-to: Your message of Tue, 15 Jun 1999 08:55:43 PDT. Date: Tue, 15 Jun 1999 09:04:24 PDT From: Vern Paxson - + > However, I couldn't figure out how to access current > buffer (yy_current_buffer). - + Derive your own subclass from yyFlexLexer. - + Vern  @@ -6779,17 +6778,17 @@ unnamed-faq-93 In-reply-to: Your message of Wed, 23 Jun 1999 11:10:29 PDT. Date: Wed, 23 Jun 1999 09:01:40 PDT From: Vern Paxson - + > I hope you can help me. I am using Flex and Bison to produce an interpreted > language. However all goes well until I try to implement an IF statement or > a WHILE. I cannot get this to work as the parser parses all the conditions > eg. the TRUE and FALSE conditons to check for a rule match. So I cannot > make a decision!! - + You need to use the parser to build a parse tree (= abstract syntax trwee), and when that's all done you recursively evaluate the tree, binding variables to values at that time. - + Vern  @@ -6803,29 +6802,29 @@ unnamed-faq-94 In-reply-to: Your message of Mon, 28 Jun 1999 19:21:41 PDT. Date: Fri, 02 Jul 1999 16:52:13 PDT From: Vern Paxson - + > file, it takes an enormous amount of time. It is funny, because the > source code has only 12 rules!!! I think it looks like an exponencial > growth. - + Right, that's the problem - some patterns (those with a lot of ambiguity, where yours has because at any given time the scanner can be in the middle of all sorts of combinations of the different rules) blow up exponentially. - + For your rules, there is an easy fix. Change the ".*" that comes fater the directory name to "[^ ]*". With that in place, the rules are no longer nearly so ambiguous, because then once one of the directories has been matched, no other can be matched (since they all require a leading blank). - + If that's not an acceptable solution, then you can enter a start state to pick up the .*\n after each directory is matched. - + Also note that for speed, you'll want to add a ".*" rule at the end, otherwise rules that don't match any of the patterns will be matched very slowly, a character at a time. - + Vern  @@ -6839,7 +6838,7 @@ unnamed-faq-95 In-reply-to: Your message of Thu, 08 Jul 1999 13:20:37 PDT. Date: Thu, 08 Jul 1999 08:20:39 PDT From: Vern Paxson - + > I was hoping you could help me with my problem. > > I tried compiling (gnu)flex on a Solaris 2.4 machine @@ -6861,12 +6860,12 @@ unnamed-faq-95 > using flex or lex? > > Thanks so much for your time. - + You managed to step on the bootstrap sequence, which first copies initscan.c to scan.c in order to build flex. Try fetching a fresh distribution from ftp.ee.lbl.gov. (Or you can first try removing ".bootstrap" and doing a make again.) - + Vern  @@ -6880,20 +6879,20 @@ unnamed-faq-96 In-reply-to: Your message of Fri, 09 Jul 1999 09:16:14 PDT. Date: Fri, 09 Jul 1999 00:27:20 PDT From: Vern Paxson - + > First I removed .bootstrap (and ran make) - no luck. I downloaded the > software but I still have the same problem. Is there anything else I > could try. - + Try: - + cp initscan.c scan.c touch scan.c make scan.o - + If this last tries to first build scan.c from scan.l using ./flex, then your "make" is broken, in which case compile scan.c to scan.o by hand. - + Vern  @@ -6907,13 +6906,13 @@ unnamed-faq-97 In-reply-to: Your message of Mon, 19 Jul 1999 23:08:41 PDT. Date: Tue, 20 Jul 1999 00:18:26 PDT From: Vern Paxson - + > I am getting a compilation error. The error is given as "unknown symbol- yylex". - + The parser relies on calling yylex(), but you're instead using the C++ scanning class, so you need to supply a yylex() "glue" function that calls an instance scanner of the scanner (e.g., "scanner->yylex()"). - + Vern  @@ -6927,16 +6926,16 @@ unnamed-faq-98 In-reply-to: Your message of Mon, 22 Nov 1999 11:19:04 PST. Date: Tue, 23 Nov 1999 15:54:30 PST From: Vern Paxson - + Well, your problem is the - + switch (yybgin-yysvec-1) { /* witchcraft */ - + at the beginning of lex rules. "witchcraft" == "non-portable". It's assuming knowledge of the AT&T lex's internal variables. - + For flex, you can probably do the equivalent using a switch on YYSTATE. - + Vern  @@ -6950,21 +6949,21 @@ unnamed-faq-99 In-reply-to: Your message of Sun, 19 Dec 1999 17:50:24 +0530. Date: Wed, 22 Dec 1999 01:56:24 PST From: Vern Paxson - + > When we provide the customer with an object code distribution, is it > necessary for us to provide source > for the generated C files from flex and bison since they are generated by > flex and bison ? - + For flex, no. I don't know what the current state of this is for bison. - + > Also, is there any requrirement for us to neccessarily provide source for > the grammar files which are fed into flex and bison ? - + Again, for flex, no. - + See the file "COPYING" in the flex distribution for the legalese. - + Vern  @@ -6978,15 +6977,15 @@ unnamed-faq-100 In-reply-to: Your message of Sun, 20 Feb 2000 01:01:21 PST. Date: Sat, 19 Feb 2000 18:33:16 PST From: Vern Paxson - + > However, I do not use unput anywhere. I do use self-referencing > rules like this: > > UnaryExpr ({UnionExpr})|("-"{UnaryExpr}) - + You can't do this - flex is *not* a parser like yacc (which does indeed allow recursion), it is a scanner that's confined to regular expressions. - + Vern  @@ -7000,9 +6999,9 @@ unnamed-faq-101 In-reply-to: Your message of Thu, 02 Mar 2000 12:29:04 PST. Date: Thu, 02 Mar 2000 23:00:46 PST From: Vern Paxson - + If this is exactly your program: - + > digit [0-9] > digits {digit}+ > whitespace [ \t\n]+ @@ -7014,9 +7013,9 @@ unnamed-faq-101 > "*" { printf("multop\n");} > {digits} { printf("NUMBER = %s\n", yytext);} > whitespace ; - + then the problem is that the last rule needs to be "{whitespace}" ! - + Vern  @@ -7060,10 +7059,10 @@ Appendix A Appendices * Menu: -* Makefiles and Flex:: -* Bison Bridge:: -* M4 Dependency:: -* Common Patterns:: +* Makefiles and Flex:: +* Bison Bridge:: +* M4 Dependency:: +* Common Patterns::  File: flex.info, Node: Makefiles and Flex, Next: Bison Bridge, Prev: Appendices, Up: Appendices @@ -7074,17 +7073,17 @@ A.1 Makefiles and Flex In this appendix, we provide tips for writing Makefiles to build your scanners. - In a traditional build environment, we say that the '.c' files are -the sources, and the '.o' files are the intermediate files. When using -'flex', however, the '.l' files are the sources, and the generated '.c' -files (along with the '.o' files) are the intermediate files. This + In a traditional build environment, we say that the ‘.c’ files are +the sources, and the ‘.o’ files are the intermediate files. When using +‘flex’, however, the ‘.l’ files are the sources, and the generated ‘.c’ +files (along with the ‘.o’ files) are the intermediate files. This requires you to carefully plan your Makefile. - Modern 'make' programs understand that 'foo.l' is intended to -generate 'lex.yy.c' or 'foo.c', and will behave accordingly(1)(2). The -following Makefile does not explicitly instruct 'make' how to build -'foo.c' from 'foo.l'. Instead, it relies on the implicit rules of the -'make' program to build the intermediate file, 'scan.c': + Modern ‘make’ programs understand that ‘foo.l’ is intended to +generate ‘lex.yy.c’ or ‘foo.c’, and will behave accordingly(1)(2). The +following Makefile does not explicitly instruct ‘make’ how to build +‘foo.c’ from ‘foo.l’. Instead, it relies on the implicit rules of the +‘make’ program to build the intermediate file, ‘scan.c’: # Basic Makefile -- relies on implicit rules # Creates "myprogram" from "scan.l" and "myprogram.c" @@ -7092,10 +7091,10 @@ following Makefile does not explicitly instruct 'make' how to build LEX=flex myprogram: scan.o myprogram.o scan.o: scan.l - + For simple cases, the above may be sufficient. For other cases, you -may have to explicitly instruct 'make' how to build your scanner. The +may have to explicitly instruct ‘make’ how to build your scanner. The following is an example of a Makefile containing explicit rules: # Basic Makefile -- provides explicit rules @@ -7104,28 +7103,28 @@ following is an example of a Makefile containing explicit rules: LEX=flex myprogram: scan.o myprogram.o $(CC) -o $@ $(LDFLAGS) $^ - + myprogram.o: myprogram.c $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $^ - + scan.o: scan.c $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $^ - + scan.c: scan.l $(LEX) $(LFLAGS) -o $@ $^ - + clean: $(RM) *.o scan.c + - - Notice in the above example that 'scan.c' is in the 'clean' target. -This is because we consider the file 'scan.c' to be an intermediate + Notice in the above example that ‘scan.c’ is in the ‘clean’ target. +This is because we consider the file ‘scan.c’ to be an intermediate file. - Finally, we provide a realistic example of a 'flex' scanner used with -a 'bison' parser(3). There is a tricky problem we have to deal with. -Since a 'flex' scanner will typically include a header file (e.g., -'y.tab.h') generated by the parser, we need to be sure that the header + Finally, we provide a realistic example of a ‘flex’ scanner used with +a ‘bison’ parser(3). There is a tricky problem we have to deal with. +Since a ‘flex’ scanner will typically include a header file (e.g., +‘y.tab.h’) generated by the parser, we need to be sure that the header file is generated BEFORE the scanner is compiled. We handle this case in the following example: @@ -7136,31 +7135,31 @@ in the following example: YACC = bison -y YFLAGS = -d objects = scan.o parse.o myprogram.o - + myprogram: $(objects) scan.o: scan.l parse.c parse.o: parse.y myprogram.o: myprogram.c - + In the above example, notice the line, scan.o: scan.l parse.c - , which lists the file 'parse.c' (the generated parser) as a -dependency of 'scan.o'. We want to ensure that the parser is created + , which lists the file ‘parse.c’ (the generated parser) as a +dependency of ‘scan.o’. We want to ensure that the parser is created before the scanner is compiled, and the above line seems to do the trick. Feel free to experiment with your specific implementation of -'make'. +‘make’. For more details on writing Makefiles, see *note (make)Top::. ---------- Footnotes ---------- - (1) GNU 'make' and GNU 'automake' are two such programs that provide + (1) GNU ‘make’ and GNU ‘automake’ are two such programs that provide implicit rules for flex-generated scanners. - (2) GNU 'automake' may generate code to execute flex in + (2) GNU ‘automake’ may generate code to execute flex in lex-compatible mode, or to stdout. If this is not what you want, then you should provide an explicit rule in your Makefile.am @@ -7172,52 +7171,52 @@ File: flex.info, Node: Bison Bridge, Next: M4 Dependency, Prev: Makefiles and A.2 C Scanners with Bison Parsers ================================= -This section describes the 'flex' features useful when integrating -'flex' with 'GNU bison'(1). Skip this section if you are not using -'bison' with your scanner. Here we discuss only the 'flex' half of the -'flex' and 'bison' pair. We do not discuss 'bison' in any detail. For -more information about generating 'bison' parsers, see *note +This section describes the ‘flex’ features useful when integrating +‘flex’ with ‘GNU bison’(1). Skip this section if you are not using +‘bison’ with your scanner. Here we discuss only the ‘flex’ half of the +‘flex’ and ‘bison’ pair. We do not discuss ‘bison’ in any detail. For +more information about generating ‘bison’ parsers, see *note (bison)Top::. - A compatible 'bison' scanner is generated by declaring '%option -bison-bridge' or by supplying '--bison-bridge' when invoking 'flex' from -the command line. This instructs 'flex' that the macro 'yylval' may be -used. The data type for 'yylval', 'YYSTYPE', is typically defined in a -header file, included in section 1 of the 'flex' input file. For a list + A compatible ‘bison’ scanner is generated by declaring ‘%option +bison-bridge’ or by supplying ‘--bison-bridge’ when invoking ‘flex’ from +the command line. This instructs ‘flex’ that the macro ‘yylval’ may be +used. The data type for ‘yylval’, ‘YYSTYPE’, is typically defined in a +header file, included in section 1 of the ‘flex’ input file. For a list of functions and macros available, *Note bison-functions::. The declaration of yylex becomes, int yylex ( YYSTYPE * lvalp, yyscan_t scanner ); - If '%option bison-locations' is specified, then the declaration + If ‘%option bison-locations’ is specified, then the declaration becomes, int yylex ( YYSTYPE * lvalp, YYLTYPE * llocp, yyscan_t scanner ); - Note that the macros 'yylval' and 'yylloc' evaluate to pointers. -Support for 'yylloc' is optional in 'bison', so it is optional in 'flex' -as well. The following is an example of a 'flex' scanner that is -compatible with 'bison'. + Note that the macros ‘yylval’ and ‘yylloc’ evaluate to pointers. +Support for ‘yylloc’ is optional in ‘bison’, so it is optional in ‘flex’ +as well. The following is an example of a ‘flex’ scanner that is +compatible with ‘bison’. /* Scanner for "C" assignment statements... sort of. */ %{ #include "y.tab.h" /* Generated by bison. */ %} - + %option bison-bridge bison-locations % - + [[:digit:]]+ { yylval->num = atoi(yytext); return NUMBER;} [[:alnum:]]+ { yylval->str = strdup(yytext); return STRING;} "="|";" { return yytext[0];} . {} % - As you can see, there really is no magic here. We just use 'yylval' -as we would any other variable. The data type of 'yylval' is generated -by 'bison', and included in the file 'y.tab.h'. Here is the -corresponding 'bison' parser: + As you can see, there really is no magic here. We just use ‘yylval’ +as we would any other variable. The data type of ‘yylval’ is generated +by ‘bison’, and included in the file ‘y.tab.h’. Here is the +corresponding ‘bison’ parser: /* Parser to convert "C" assignments to lisp. */ %{ @@ -7252,28 +7251,28 @@ File: flex.info, Node: M4 Dependency, Next: Common Patterns, Prev: Bison Brid A.3 M4 Dependency ================= -The macro processor 'm4'(1) must be installed wherever flex is -installed. 'flex' invokes 'm4', found by searching the directories in -the 'PATH' environment variable. Any code you place in section 1 or in +The macro processor ‘m4’(1) must be installed wherever flex is +installed. ‘flex’ invokes ‘m4’, found by searching the directories in +the ‘PATH’ environment variable. Any code you place in section 1 or in the actions will be sent through m4. Please follow these rules to -protect your code from unwanted 'm4' processing. +protect your code from unwanted ‘m4’ processing. - * Do not use symbols that begin with, 'm4_', such as, 'm4_define', or - 'm4_include', since those are reserved for 'm4' macro names. If + • Do not use symbols that begin with, ‘m4_’, such as, ‘m4_define’, or + ‘m4_include’, since those are reserved for ‘m4’ macro names. If for some reason you need m4_ as a prefix, use a preprocessor #define to get your symbol past m4 unmangled. - * Do not use the strings '[[' or ']]' anywhere in your code. The + • Do not use the strings ‘[[’ or ‘]]’ anywhere in your code. The former is not valid in C, except within comments and strings, but - the latter is valid in code such as 'x[y[z]]'. The solution is - simple. To get the literal string '"]]"', use '"]""]"'. To get - the array notation 'x[y[z]]', use 'x[y[z] ]'. Flex will attempt to + the latter is valid in code such as ‘x[y[z]]’. The solution is + simple. To get the literal string ‘"]]"’, use ‘"]""]"’. To get + the array notation ‘x[y[z]]’, use ‘x[y[z] ]’. Flex will attempt to detect these sequences in user code, and escape them. However, it's best to avoid this complexity where possible, by removing such sequences from your code. - 'm4' is only required at the time you run 'flex'. The generated -scanner is ordinary C or C++, and does _not_ require 'm4'. + ‘m4’ is only required at the time you run ‘flex’. The generated +scanner is ordinary C or C++, and does _not_ require ‘m4’. ---------- Footnotes ---------- @@ -7291,10 +7290,10 @@ use in your scanner. * Menu: -* Numbers:: -* Identifiers:: -* Quoted Constructs:: -* Addresses:: +* Numbers:: +* Identifiers:: +* Quoted Constructs:: +* Addresses::  File: flex.info, Node: Numbers, Next: Identifiers, Up: Common Patterns @@ -7303,13 +7302,13 @@ A.4.1 Numbers ------------- C99 decimal constant - '([[:digit:]]{-}[0])[[:digit:]]*' + ‘([[:digit:]]{-}[0])[[:digit:]]*’ C99 hexadecimal constant - '0[xX][[:xdigit:]]+' + ‘0[xX][[:xdigit:]]+’ C99 octal constant - '0[01234567]*' + ‘0[01234567]*’ C99 floating point constant {dseq} ([[:digit:]]+) @@ -7326,7 +7325,7 @@ C99 floating point constant {bexp} ([pP][+-]?{dseq}) {dfc} (({frac}{exp_opt}{fsuff_opt})|({dseq}{exp}{fsuff_opt})) {hfc} (({hpref}{hfrac}{bexp}{fsuff_opt})|({hpref}{hdseq}{bexp}{fsuff_opt})) - + {c99_floating_point_constant} ({dfc}|{hfc}) See C99 section 6.4.4.2 for the gory details. @@ -7345,7 +7344,7 @@ C99 Identifier Technically, the above pattern does not encompass all possible C99 identifiers, since C99 allows for "implementation-defined" characters. In practice, C compilers follow the above pattern, - with the addition of the '$' character. + with the addition of the ‘$’ character. UTF-8 Encoded Unicode Code Point [\x09\x0A\x0D\x20-\x7E]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF]([\x80-\xBF]{2})|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF]([\x80-\xBF]{2})|[\xF1-\xF3]([\x80-\xBF]{3})|\xF4[\x80-\x8F]([\x80-\xBF]{2}) @@ -7357,16 +7356,16 @@ A.4.3 Quoted Constructs ----------------------- C99 String Literal - 'L?\"([^\"\\\n]|(\\['\"?\\abfnrtv])|(\\([0123456]{1,3}))|(\\x[[:xdigit:]]+)|(\\u([[:xdigit:]]{4}))|(\\U([[:xdigit:]]{8})))*\"' + ‘L?\"([^\"\\\n]|(\\['\"?\\abfnrtv])|(\\([0123456]{1,3}))|(\\x[[:xdigit:]]+)|(\\u([[:xdigit:]]{4}))|(\\U([[:xdigit:]]{8})))*\"’ C99 Comment - '("/*"([^*]|"*"[^/])*"*/")|("/"(\\\n)*"/"[^\n]*)' + ‘("/*"([^*]|"*"[^/])*"*/")|("/"(\\\n)*"/"[^\n]*)’ - Note that in C99, a '//'-style comment may be split across lines, - and, contrary to popular belief, does not include the trailing '\n' + Note that in C99, a ‘//’-style comment may be split across lines, + and, contrary to popular belief, does not include the trailing ‘\n’ character. - A better way to scan '/* */' comments is by line, rather than + A better way to scan ‘/* */’ comments is by line, rather than matching possibly huge comments all at once. This will allow you to scan comments of unlimited length, as long as line breaks appear at sane intervals. This is also more efficient when used with @@ -7406,11 +7405,11 @@ IPv6 Address (({h16}:){0,6}{h16})?:: See RFC 2373 (http://www.ietf.org/rfc/rfc2373.txt) for details. - Note that you have to fold the definition of 'IPv6address' into one + Note that you have to fold the definition of ‘IPv6address’ into one line and that it also matches the "unspecified address" "::". URI - '(([^:/?#]+):)?("//"([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?' + ‘(([^:/?#]+):)?("//"([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?’ This pattern is nearly useless, since it allows just about any character to appear in a URI, including spaces and control @@ -7425,12 +7424,12 @@ Indices * Menu: -* Concept Index:: -* Index of Functions and Macros:: -* Index of Variables:: -* Index of Data Types:: -* Index of Hooks:: -* Index of Scanner Options:: +* Concept Index:: +* Index of Functions and Macros:: +* Index of Variables:: +* Index of Data Types:: +* Index of Hooks:: +* Index of Scanner Options::  File: flex.info, Node: Concept Index, Next: Index of Functions and Macros, Prev: Indices, Up: Indices @@ -7441,7 +7440,9 @@ Concept Index [index] * Menu: -* $ as normal character in patterns: Patterns. (line 275) +* [] in patterns: Patterns. (line 15) +* %{ and %}, in Definitions Section: Definitions Section. (line 40) +* %{ and %}, in Rules Section: Actions. (line 26) * %array, advantages of: Matching. (line 43) * %array, use of: Matching. (line 29) * %array, with C++: Matching. (line 65) @@ -7449,13 +7450,11 @@ Concept Index * %pointer, and unput(): Actions. (line 162) * %pointer, use of: Matching. (line 29) * %top: Definitions Section. (line 44) -* %{ and %}, in Definitions Section: Definitions Section. (line 40) -* %{ and %}, in Rules Section: Actions. (line 26) -* <>, use of: EOF. (line 33) -* [] in patterns: Patterns. (line 15) * ^ as non-special character in patterns: Patterns. (line 275) +* <>, use of: EOF. (line 33) * |, in actions: Actions. (line 33) * |, use of: Actions. (line 83) +* $ as normal character in patterns: Patterns. (line 275) * accessor functions, use of: Accessor Methods. (line 18) * actions: Actions. (line 6) * actions, embedded C strings: Actions. (line 26) @@ -7480,6 +7479,7 @@ Concept Index * braces in patterns: Patterns. (line 42) * bugs, reporting: Reporting Bugs. (line 6) * C code in flex input: Definitions Section. (line 40) +* C-strings, in actions: Actions. (line 26) * C++: Cxx. (line 9) * C++ and %array: User Values. (line 23) * C++ I/O, customizing: How do I use my own I/O classes in a C++ scanner?. @@ -7488,7 +7488,6 @@ Concept Index * C++ scanners, use of: Cxx. (line 128) * c++, experimental form of scanner class: Cxx. (line 6) * C++, multiple different scanners: Cxx. (line 192) -* C-strings, in actions: Actions. (line 26) * case-insensitive, effect on character classes: Patterns. (line 216) * character classes in patterns: Patterns. (line 186) * character classes in patterns, syntax of: Patterns. (line 15) @@ -7565,10 +7564,10 @@ Concept Index * input file, Definitions section: Definitions Section. (line 6) * input file, Rules Section: Rules Section. (line 6) * input file, user code Section: User Code Section. (line 6) -* input(): Actions. (line 173) -* input(), and C++: Actions. (line 202) * input, format of: Format. (line 6) * input, matching: Matching. (line 6) +* input(): Actions. (line 173) +* input(), and C++: Actions. (line 202) * keywords, for performance: Performance. (line 200) * lex (traditional) and POSIX: Lex and Posix. (line 6) * LexerInput, overriding: How do I use my own I/O classes in a C++ scanner?. @@ -7746,6 +7745,15 @@ Concept Index * whitespace, compressing: Actions. (line 22) * yacc interface: Yacc. (line 17) * yacc, interface: Yacc. (line 6) +* YY_CURRENT_BUFFER, and multiple buffers Finally, the macro: Multiple Input Buffers. + (line 78) +* YY_EXTRA_TYPE, defining your own type: Extra Data. (line 33) +* YY_FLUSH_BUFFER: Actions. (line 206) +* YY_INPUT: Generated Scanner. (line 61) +* YY_INPUT, overriding: Generated Scanner. (line 71) +* YY_START, example: Start Conditions. (line 185) +* YY_USER_ACTION to track each time a rule is matched: Misc Macros. + (line 14) * yyalloc, overriding: Overriding The Default Memory Management. (line 6) * yyfree, overriding: Overriding The Default Memory Management. @@ -7756,16 +7764,16 @@ Concept Index * yyleng, modification of: Actions. (line 47) * yyless(): Actions. (line 125) * yyless(), pushing back characters: Actions. (line 131) +* yylex, overriding the prototype of: Generated Scanner. (line 20) * yylex(), in generated scanner: Generated Scanner. (line 6) * yylex(), overriding: Generated Scanner. (line 16) -* yylex, overriding the prototype of: Generated Scanner. (line 20) * yylineno, in a reentrant scanner: Reentrant Functions. (line 36) * yylineno, performance costs: Performance. (line 12) +* yymore, and yyleng: Actions. (line 47) +* yymore, performance penalty of: Actions. (line 119) * yymore(): Actions. (line 104) * yymore() to append token to previous token: Actions. (line 110) * yymore(), mega-kludge: Actions. (line 110) -* yymore, and yyleng: Actions. (line 47) -* yymore, performance penalty of: Actions. (line 119) * yyout: Generated Scanner. (line 101) * yyrealloc, overriding: Overriding The Default Memory Management. (line 6) @@ -7777,15 +7785,6 @@ Concept Index (line 6) * yytext, modification of: Actions. (line 42) * yytext, two types of: Matching. (line 29) -* yywrap(): Generated Scanner. (line 85) * yywrap, default for: Generated Scanner. (line 93) -* YY_CURRENT_BUFFER, and multiple buffers Finally, the macro: Multiple Input Buffers. - (line 78) -* YY_EXTRA_TYPE, defining your own type: Extra Data. (line 33) -* YY_FLUSH_BUFFER: Actions. (line 206) -* YY_INPUT: Generated Scanner. (line 61) -* YY_INPUT, overriding: Generated Scanner. (line 71) -* YY_START, example: Start Conditions. (line 185) -* YY_USER_ACTION to track each time a rule is matched: Misc Macros. - (line 14) +* yywrap(): Generated Scanner. (line 85) diff --git a/local/recipes/dev/flex/source/doc/flex.info-2 b/local/recipes/dev/flex/source/doc/flex.info-2 index 32356d6fc0..4908ef22eb 100644 Binary files a/local/recipes/dev/flex/source/doc/flex.info-2 and b/local/recipes/dev/flex/source/doc/flex.info-2 differ diff --git a/local/recipes/dev/flex/source/doc/stamp-vti b/local/recipes/dev/flex/source/doc/stamp-vti index fa020ed7ac..19f7b019d8 100644 --- a/local/recipes/dev/flex/source/doc/stamp-vti +++ b/local/recipes/dev/flex/source/doc/stamp-vti @@ -1,4 +1,4 @@ -@set UPDATED 6 May 2017 -@set UPDATED-MONTH May 2017 +@set UPDATED 15 May 2026 +@set UPDATED-MONTH May 2026 @set EDITION 2.6.4 @set VERSION 2.6.4 diff --git a/local/recipes/dev/flex/source/doc/version.texi b/local/recipes/dev/flex/source/doc/version.texi index fa020ed7ac..19f7b019d8 100644 --- a/local/recipes/dev/flex/source/doc/version.texi +++ b/local/recipes/dev/flex/source/doc/version.texi @@ -1,4 +1,4 @@ -@set UPDATED 6 May 2017 -@set UPDATED-MONTH May 2017 +@set UPDATED 15 May 2026 +@set UPDATED-MONTH May 2026 @set EDITION 2.6.4 @set VERSION 2.6.4 diff --git a/local/recipes/dev/flex/source/src/config.h.in b/local/recipes/dev/flex/source/src/config.h.in index 475650558e..03154f5c29 100644 --- a/local/recipes/dev/flex/source/src/config.h.in +++ b/local/recipes/dev/flex/source/src/config.h.in @@ -1,30 +1,18 @@ /* src/config.h.in. Generated from configure.ac by autoheader. */ -/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP - systems. This function is required for `alloca.c' support on those systems. - */ -#undef CRAY_STACKSEG_END - -/* Define to 1 if using `alloca.c'. */ +/* Define to 1 if using 'alloca.c'. */ #undef C_ALLOCA /* Define to 1 if translation of program messages to the user's native language is requested. */ #undef ENABLE_NLS -/* Define to 1 if you have `alloca', as a function or macro. */ +/* Define to 1 if you have 'alloca', as a function or macro. */ #undef HAVE_ALLOCA -/* Define to 1 if you have and it should be used (not on Ultrix). - */ +/* Define to 1 if works. */ #undef HAVE_ALLOCA_H -/* Define to 1 if you have the `available.' function. */ -#undef HAVE_AVAILABLE_ - -/* Define to 1 if you have the `by' function. */ -#undef HAVE_BY - /* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the CoreFoundation framework. */ #undef HAVE_CFLOCALECOPYCURRENT @@ -40,43 +28,25 @@ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H -/* Define to 1 if you have the `dnl' function. */ -#undef HAVE_DNL - -/* Define to 1 if you have the `dup2' function. */ +/* Define to 1 if you have the 'dup2' function. */ #undef HAVE_DUP2 -/* Define to 1 if you have the `enabled' function. */ -#undef HAVE_ENABLED - -/* Define to 1 if you have the `fork' function. */ +/* Define to 1 if you have the 'fork' function. */ #undef HAVE_FORK -/* Define to 1 if you have the `function.' function. */ -#undef HAVE_FUNCTION_ - /* Define if the GNU gettext() function is already present or preinstalled. */ #undef HAVE_GETTEXT -/* Define to 1 if you have the `have' function. */ -#undef HAVE_HAVE - /* Define if you have the iconv() function and it works. */ #undef HAVE_ICONV -/* Define to 1 if you have the `if' function. */ -#undef HAVE_IF - /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H -/* Define to 1 if you have the `is' function. */ -#undef HAVE_IS - /* Define to 1 if you have the header file. */ #undef HAVE_LIBINTL_H -/* Define to 1 if you have the `m' library (-lm). */ +/* Define to 1 if you have the 'm' library (-lm). */ #undef HAVE_LIBM /* Define to 1 if you have the header file. */ @@ -85,60 +55,39 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H -/* Define to 1 if your system has a GNU libc compatible `malloc' function, and +/* Define to 1 if your system has a GNU libc compatible 'malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the `memset' function. */ +/* Define to 1 if you have the 'memset' function. */ #undef HAVE_MEMSET -/* Define to 1 if you have the `Needed' function. */ -#undef HAVE_NEEDED - /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H -/* Define to 1 if you have the `NLS' function. */ -#undef HAVE_NLS - -/* Define to 1 if you have the `not' function. */ -#undef HAVE_NOT - -/* Define to 1 if you have the `only' function. */ -#undef HAVE_ONLY - -/* Define to 1 if you have the `OpenBSD' function. */ -#undef HAVE_OPENBSD - -/* Define to 1 if you have the `pow' function. */ +/* Define to 1 if you have the 'pow' function. */ #undef HAVE_POW /* Define to 1 if you have the header file. */ #undef HAVE_PTHREAD_H -/* Define to 1 if your system has a GNU libc compatible `realloc' function, +/* Define to 1 if your system has a GNU libc compatible 'realloc' function, and to 0 otherwise. */ #undef HAVE_REALLOC -/* Define to 1 if you have the `reallocarray' function. */ +/* Define to 1 if you have the 'reallocarray' function. */ #undef HAVE_REALLOCARRAY -/* Define to 1 if you have the `regcomp' function. */ +/* Define to 1 if you have the 'regcomp' function. */ #undef HAVE_REGCOMP /* Define to 1 if you have the header file. */ #undef HAVE_REGEX_H -/* Define to 1 if you have the `replacement' function. */ -#undef HAVE_REPLACEMENT - -/* Define to 1 if you have the `setlocale' function. */ +/* Define to 1 if you have the 'setlocale' function. */ #undef HAVE_SETLOCALE /* Define to 1 if stdbool.h conforms to C99. */ @@ -147,16 +96,19 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H +/* Define to 1 if you have the header file. */ +#undef HAVE_STDIO_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H -/* Define to 1 if you have the `strcasecmp' function. */ +/* Define to 1 if you have the 'strcasecmp' function. */ #undef HAVE_STRCASECMP -/* Define to 1 if you have the `strchr' function. */ +/* Define to 1 if you have the 'strchr' function. */ #undef HAVE_STRCHR -/* Define to 1 if you have the `strdup' function. */ +/* Define to 1 if you have the 'strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the header file. */ @@ -165,7 +117,7 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H -/* Define to 1 if you have the `strtol' function. */ +/* Define to 1 if you have the 'strtol' function. */ #undef HAVE_STRTOL /* Define to 1 if you have the header file. */ @@ -180,25 +132,19 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H -/* Define to 1 if you have the `Used' function. */ -#undef HAVE_USED - -/* Define to 1 if you have the `vfork' function. */ +/* Define to 1 if you have the 'vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H -/* Define to 1 if you have the `We' function. */ -#undef HAVE_WE - -/* Define to 1 if `fork' works. */ +/* Define to 1 if 'fork' works. */ #undef HAVE_WORKING_FORK -/* Define to 1 if `vfork' works. */ +/* Define to 1 if 'vfork' works. */ #undef HAVE_WORKING_VFORK -/* Define to 1 if the system has the type `_Bool'. */ +/* Define to 1 if the system has the type '_Bool'. */ #undef HAVE__BOOL /* Define to the sub-directory where libtool stores uninstalled libraries. */ @@ -236,30 +182,32 @@ STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION -/* Define to 1 if you have the ANSI C header files. */ +/* Define to 1 if all of the C89 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION -/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a - `char[]'. */ +/* Define to 1 if 'lex' declares 'yytext' as a 'char *' by default, not a + 'char[]'. */ #undef YYTEXT_POINTER -/* Define to empty if `const' does not conform to ANSI C. */ +/* Define to empty if 'const' does not conform to ANSI C. */ #undef const /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc -/* Define to `int' if does not define. */ +/* Define as a signed integer type capable of holding a process identifier. */ #undef pid_t /* Define to rpl_realloc if the replacement function should be used. */ #undef realloc -/* Define to `unsigned int' if does not define. */ +/* Define as 'unsigned int' if doesn't define. */ #undef size_t -/* Define as `fork' if `vfork' does not work. */ +/* Define as 'fork' if 'vfork' does not work. */ #undef vfork diff --git a/local/recipes/dev/m4/recipe.toml b/local/recipes/dev/m4/recipe.toml index 0e77e26e48..147b5d5901 100644 --- a/local/recipes/dev/m4/recipe.toml +++ b/local/recipes/dev/m4/recipe.toml @@ -6,16 +6,121 @@ patches = ["redox.patch"] template = "custom" script = """ DYNAMIC_INIT + +# Add relibc system headers to the include path. +# The cookbook sets CPPFLAGS="-I${COOKBOOK_SYSROOT}/include" but the recipe +# sysroot is empty for packages with no header-providing deps. The relibc +# headers are at prefix/${TARGET}/relibc-install/${TARGET}/include/ — not in +# the compiler's default search path. Without this, gnulib's #include_next +# can't find the system headers and every wrapper fails. +RELIBC_INCLUDE="${COOKBOOK_ROOT}/prefix/${TARGET}/relibc-install/${TARGET}/include" +export CPPFLAGS="${CPPFLAGS} -isystem ${RELIBC_INCLUDE}" + +# relibc's float.h is missing LDBL_DIG (and possibly other LDBL_* macros). +# For x86_64 80-bit extended precision: LDBL_DIG = floor(63 * log10(2)) = 18 +export CPPFLAGS="${CPPFLAGS} -DLDBL_DIG=18" + +# The redoxer toolchain has a stale libc without __fseterr/__freadahead. +# Add the relibc library path so the linker finds the updated library. +RELIBC_LIB="${COOKBOOK_ROOT}/prefix/${TARGET}/relibc-install/${TARGET}/lib" +export LDFLAGS="${LDFLAGS} -L${RELIBC_LIB}" + +# Gnulib cross-compilation: relibc provides standard POSIX headers and types +# but gnulib's configure can't run test programs during cross-compilation. +export ac_cv_header_stdio_h=yes +export ac_cv_header_stdlib_h=yes +export ac_cv_header_string_h=yes +export ac_cv_header_strings_h=yes +export ac_cv_header_inttypes_h=yes +export ac_cv_header_stdint_h=yes +export ac_cv_header_unistd_h=yes +export ac_cv_header_sys_types_h=yes +export ac_cv_header_sys_stat_h=yes +export ac_cv_header_time_h=yes +export ac_cv_header_sys_time_h=yes +export ac_cv_header_sys_select_h=yes +export ac_cv_header_wchar_h=yes +export ac_cv_header_wctype_h=yes +export ac_cv_header_signal_h=yes +export ac_cv_header_dirent_h=yes +export ac_cv_header_fcntl_h=yes +export ac_cv_header_locale_h=yes +export ac_cv_header_errno_h=yes +export ac_cv_header_ctype_h=yes +export ac_cv_header_limits_h=yes +export ac_cv_header_stdarg_h=yes +export ac_cv_header_stddef_h=yes +export ac_cv_header_spawn_h=yes + +# Standard types +export ac_cv_type_intmax_t=yes +export ac_cv_type_uintmax_t=yes +export ac_cv_type_gid_t=yes +export ac_cv_type_uid_t=yes +export ac_cv_type_pid_t=yes +export ac_cv_type_mode_t=yes +export ac_cv_type_off_t=yes +export ac_cv_type_size_t=yes +export ac_cv_type_ssize_t=yes +export ac_cv_type_ptrdiff_t=yes +export ac_cv_type_nlink_t=yes +export ac_cv_type_mbstate_t=yes +export ac_cv_type_sigset_t=yes +export ac_cv_type_posix_spawnattr_t=yes +export ac_cv_type_posix_spawn_file_actions_t=yes +export gl_cv_type_intmax_t=yes +export gl_cv_type_ptrdiff_t_signed=yes +export gl_cv_header_inttypes_h=yes +export gl_cv_header_stdint_h=yes +export gl_cv_header_inttypes_h_with_uintmax=yes +export ac_cv_have_inttypes_h_with_uintmax=yes + +# m4-specific gnulib function checks +export ac_cv_func___freadahead=yes +export ac_cv_have_decl___freadahead=yes +export gl_cv_header_wchar_h_correct_inline=yes +export gl_cv_func_btowc_nul=yes +export gl_cv_func_btowc_consistent=yes +export gl_cv_onwards_func___freadahead=yes +export gl_cv_socklen_t_equiv=socklen_t +export ac_cv_func_getpagesize=yes +export ac_cv_func_memcmp_working=yes + +# Tell gnulib these wide-char functions exist and work +export ac_cv_func_btowc=yes +export ac_cv_func_mbrtowc=yes +export ac_cv_func_mbsinit=yes +export ac_cv_func_wcrtomb=yes +export ac_cv_func_wctob=yes +export ac_cv_func_mbsrtowcs=yes +export ac_cv_func_wcswidth=yes +export ac_cv_func_wcwidth=yes +export gl_cv_func_btowc=yes +export gl_cv_func_mbrtowc=yes +export gl_cv_func_mbsinit=yes +export gl_cv_func_wcrtomb=yes +export gl_cv_func_wctob=yes +export gl_cv_func_wcwidth=yes +export gl_cv_func_wcswidth=yes + +# Functions that relibc provides but gnulib can't detect during cross-compilation +export ac_cv_func___fseterr=yes +export ac_cv_func_getlocalename_l=yes + COOKBOOK_CONFIGURE_FLAGS+=( --disable-nls - ac_cv_func___freadahead=yes - ac_cv_have_decl___freadahead=yes - gl_cv_header_wchar_h_correct_inline=yes - gl_cv_func_btowc_nul=yes - gl_cv_func_btowc_consistent=yes - gl_cv_onwards_func___freadahead=yes ) -cookbook_configure + +"${COOKBOOK_CONFIGURE}" "${COOKBOOK_CONFIGURE_FLAGS[@]}" + +# Fix gnulib cross-compilation misdetections in config.h +"${COOKBOOK_ROOT}/local/scripts/gnulib-cross-fix.sh" "${COOKBOOK_BUILD}/lib/config.h" + +# Prevent man page regeneration (help2man not available in cross-env) +touch "${COOKBOOK_SOURCE}/doc/m4.1" + +"${COOKBOOK_MAKE}" -j "${COOKBOOK_MAKE_JOBS}" HELP2MAN=true +"${COOKBOOK_MAKE}" install DESTDIR="${COOKBOOK_STAGE}" HELP2MAN=true """ [package] diff --git a/local/recipes/dev/m4/redox.patch b/local/recipes/dev/m4/redox.patch index 646b442b25..630a5dc398 100644 --- a/local/recipes/dev/m4/redox.patch +++ b/local/recipes/dev/m4/redox.patch @@ -4,7 +4,7 @@ }; const char *name = ((struct __locale_t *) locale)->mb_cur_max == 4 ? "C.UTF-8" : "C"; return (struct string_with_storage) { name, STORAGE_INDEFINITE }; -+#elif defined __redox__ && HAVE_GETLOCALENAME_L ++#elif defined __RELIBC__ && HAVE_GETLOCALENAME_L + const char *name = getlocalename_l (category, locale); + return (struct string_with_storage) { name != NULL ? name : "", STORAGE_OBJECT }; #else diff --git a/local/recipes/dev/m4/source/aclocal.m4 b/local/recipes/dev/m4/source/aclocal.m4 index c05dd7f0f6..e4ac6f4138 100644 --- a/local/recipes/dev/m4/source/aclocal.m4 +++ b/local/recipes/dev/m4/source/aclocal.m4 @@ -14,8 +14,8 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.72.90],, -[m4_warning([this file was generated for autoconf 2.72.90. +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.73],, +[m4_warning([this file was generated for autoconf 2.73. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) diff --git a/local/recipes/dev/m4/source/configure b/local/recipes/dev/m4/source/configure index 3f4df68ebb..6061184b56 100755 --- a/local/recipes/dev/m4/source/configure +++ b/local/recipes/dev/m4/source/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.72.90 for GNU M4 1.4.21. +# Generated by GNU Autoconf 2.73 for GNU M4 1.4.21. # # Report bugs to . # @@ -634,7 +634,7 @@ gl_getopt_required=POSIX gl_trunc_required=plain gl_truncl_required=plain gt_needs= -enable_year2038=no +: ${enable_year2038:=no} ac_subst_vars='M4tests_libm4_LIBOBJDEPS M4tests_libm4_LTLIBOBJS M4tests_libm4_LIBOBJS @@ -3969,7 +3969,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF GNU M4 configure 1.4.21 -generated by GNU Autoconf 2.72.90 +generated by GNU Autoconf 2.73 Copyright (C) 2026 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation @@ -4692,7 +4692,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by GNU M4 $as_me 1.4.21, which was -generated by GNU Autoconf 2.72.90. Invocation command line was +generated by GNU Autoconf 2.73. Invocation command line was $ $0$ac_configure_args_raw @@ -61929,14 +61929,14 @@ int main (void) { #if defined _AIX && !defined _AIX51 - #error "AIX pre 5.1 is buggy" - #endif - #ifdef __ANDROID__ - #include - #if __ANDROID_API__ < 22 - #error "Android API < 22 is buggy" - #endif - #endif + #error "AIX pre 5.1 is buggy" + #endif + #ifdef __ANDROID__ + #include + #if __ANDROID_API__ < 22 + #error "Android API < 22 is buggy" + #endif + #endif ; return 0; @@ -61955,27 +61955,27 @@ else case e in #( /* end confdefs.h. */ $ac_includes_default /* Use pstrnlen to test; 'volatile' prevents the compiler - from optimizing the strnlen calls away. */ - size_t (*volatile pstrnlen) (char const *, size_t) = strnlen; - char const s[] = "foobar"; - int s_len = sizeof s - 1; + from optimizing the strnlen calls away. */ + size_t (*volatile pstrnlen) (char const *, size_t) = strnlen; + char const s[] = "foobar"; + int s_len = sizeof s - 1; int main (void) { - /* AIX 4.3 is buggy: strnlen (S, 1) == 3. */ - int i; - for (i = 0; i < s_len + 1; ++i) - { - int expected = i <= s_len ? i : s_len; - if (pstrnlen (s, i) != expected) - return 1; - } + /* AIX 4.3 is buggy: strnlen (S, 1) == 3. */ + int i; + for (i = 0; i < s_len + 1; ++i) + { + int expected = i <= s_len ? i : s_len; + if (pstrnlen (s, i) != expected) + return 1; + } - /* Android 5.0 (API 21) strnlen ("", SIZE_MAX) incorrectly crashes. */ - if (pstrnlen ("", -1) != 0) - return 1; + /* Android 5.0 (API 21) strnlen ("", SIZE_MAX) incorrectly crashes. */ + if (pstrnlen ("", -1) != 0) + return 1; ; return 0; } @@ -75126,7 +75126,7 @@ cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1 # values after options handling. ac_log=" This file was extended by GNU M4 $as_me 1.4.21, which was -generated by GNU Autoconf 2.72.90. Invocation command line was +generated by GNU Autoconf 2.73. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -75200,7 +75200,7 @@ cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ GNU M4 config.status 1.4.21 -configured by $0, generated by GNU Autoconf 2.72.90, +configured by $0, generated by GNU Autoconf 2.73, with options \\"\$ac_cs_config\\" Copyright (C) 2026 Free Software Foundation, Inc. diff --git a/local/recipes/dev/m4/source/doc/m4.info b/local/recipes/dev/m4/source/doc/m4.info index 419e183330..2c4a13ed59 100644 --- a/local/recipes/dev/m4/source/doc/m4.info +++ b/local/recipes/dev/m4/source/doc/m4.info @@ -1,6 +1,6 @@ -This is m4.info, produced by makeinfo version 7.2 from m4.texi. +This is m4.info, produced by makeinfo version 7.3 from m4.texi. -This manual (6 February 2026) is for GNU M4 (version 1.4.21), a package +This manual (15 May 2026) is for GNU M4 (version 1.4.21), a package containing an implementation of the m4 macro language. Copyright © 1989-1994, 2004-2014, 2016-2017, 2020-2026 Free Software @@ -19,117 +19,117 @@ END-INFO-DIR-ENTRY  Indirect: -m4.info-1: 832 -m4.info-2: 317307 +m4.info-1: 828 +m4.info-2: 317295  Tag Table: (Indirect) -Node: Top832 -Node: Preliminaries9778 -Node: Intro10484 -Node: History12175 -Node: Bugs16228 -Node: Manual17491 -Node: Invoking m420994 -Node: Operation modes23198 -Node: Preprocessor features26297 -Node: Limits control29467 -Node: Frozen state33478 -Node: Debugging options34317 -Node: Command line files36369 -Node: Syntax38020 -Node: Names39175 -Node: Quoted strings39657 -Node: Comments40324 -Node: Other tokens41227 -Node: Input processing41821 -Ref: Input processing-Footnote-150258 -Node: Macros50455 -Node: Invocation50949 -Node: Inhibiting Invocation51750 -Node: Macro Arguments55992 -Node: Quoting Arguments59112 -Node: Macro expansion61248 -Node: Definitions61966 -Node: Define62751 -Node: Arguments65269 -Node: Pseudo Arguments69035 -Node: Undefine72664 -Node: Defn73823 -Node: Pushdef78886 -Node: Indir81626 -Node: Builtin83793 -Node: Conditionals86068 -Node: Ifdef87014 -Node: Ifelse87896 -Node: Shift91282 -Node: Forloop102102 -Node: Foreach104783 -Node: Stacks110405 -Node: Composition113540 -Node: Debugging121217 -Node: Dumpdef121810 -Node: Trace123228 -Node: Debug Levels126880 -Node: Debug Output131750 -Node: Input Control133063 -Node: Dnl133604 -Node: Changequote135546 -Node: Changecom145278 -Node: Changeword149164 -Node: M4wrap154769 -Node: File Inclusion158854 -Node: Include159175 -Node: Search Path161992 -Node: Diversions162941 -Node: Divert164648 -Node: Undivert167214 -Node: Divnum170599 -Node: Cleardivert171072 -Node: Text handling172293 -Node: Len173020 -Node: Index macro173414 -Node: Regexp174307 -Node: Substr177468 -Node: Translit178526 -Node: Patsubst181317 -Node: Format185958 -Node: Arithmetic189366 -Node: Incr189819 -Node: Eval191494 -Node: Shell commands200238 -Node: Platform macros201176 -Node: Syscmd203378 -Node: Esyscmd205753 -Node: Sysval207336 -Node: Mkstemp209303 -Node: Miscellaneous213360 -Node: Errprint213797 -Node: Location215049 -Node: M4exit217926 -Node: Frozen files220052 -Node: Using frozen files220850 -Node: Frozen file format224231 -Node: Compatibility227381 -Node: Extensions228463 -Node: Incompatibilities232517 -Node: Other Incompatibilities241821 -Node: Answers244551 -Node: Improved exch245365 -Node: Improved forloop245918 -Node: Improved foreach251374 -Node: Improved copy264752 -Node: Improved m4wrap268809 -Node: Improved cleardivert271305 -Node: Improved capitalize272303 -Node: Improved fatal_error277339 -Node: Copying This Package278436 -Node: GNU General Public License278915 -Node: Copying This Manual317307 -Node: GNU Free Documentation License317831 -Node: Indices342955 -Node: Macro index343239 -Node: Concept index349849 +Node: Top828 +Node: Preliminaries9770 +Node: Intro10476 +Node: History12167 +Node: Bugs16220 +Node: Manual17483 +Node: Invoking m420986 +Node: Operation modes23190 +Node: Preprocessor features26289 +Node: Limits control29459 +Node: Frozen state33470 +Node: Debugging options34309 +Node: Command line files36361 +Node: Syntax38012 +Node: Names39167 +Node: Quoted strings39649 +Node: Comments40316 +Node: Other tokens41219 +Node: Input processing41813 +Ref: Input processing-Footnote-150250 +Node: Macros50447 +Node: Invocation50941 +Node: Inhibiting Invocation51742 +Node: Macro Arguments55984 +Node: Quoting Arguments59104 +Node: Macro expansion61240 +Node: Definitions61958 +Node: Define62743 +Node: Arguments65261 +Node: Pseudo Arguments69027 +Node: Undefine72656 +Node: Defn73815 +Node: Pushdef78878 +Node: Indir81618 +Node: Builtin83785 +Node: Conditionals86060 +Node: Ifdef87006 +Node: Ifelse87888 +Node: Shift91274 +Node: Forloop102094 +Node: Foreach104775 +Node: Stacks110397 +Node: Composition113532 +Node: Debugging121209 +Node: Dumpdef121802 +Node: Trace123220 +Node: Debug Levels126872 +Node: Debug Output131742 +Node: Input Control133055 +Node: Dnl133596 +Node: Changequote135538 +Node: Changecom145270 +Node: Changeword149156 +Node: M4wrap154761 +Node: File Inclusion158846 +Node: Include159167 +Node: Search Path161984 +Node: Diversions162933 +Node: Divert164640 +Node: Undivert167206 +Node: Divnum170591 +Node: Cleardivert171064 +Node: Text handling172285 +Node: Len173012 +Node: Index macro173406 +Node: Regexp174299 +Node: Substr177460 +Node: Translit178518 +Node: Patsubst181309 +Node: Format185950 +Node: Arithmetic189358 +Node: Incr189811 +Node: Eval191486 +Node: Shell commands200230 +Node: Platform macros201168 +Node: Syscmd203370 +Node: Esyscmd205745 +Node: Sysval207328 +Node: Mkstemp209295 +Node: Miscellaneous213352 +Node: Errprint213789 +Node: Location215041 +Node: M4exit217918 +Node: Frozen files220044 +Node: Using frozen files220842 +Node: Frozen file format224223 +Node: Compatibility227373 +Node: Extensions228455 +Node: Incompatibilities232509 +Node: Other Incompatibilities241813 +Node: Answers244543 +Node: Improved exch245357 +Node: Improved forloop245910 +Node: Improved foreach251366 +Node: Improved copy264744 +Node: Improved m4wrap268801 +Node: Improved cleardivert271297 +Node: Improved capitalize272295 +Node: Improved fatal_error277331 +Node: Copying This Package278428 +Node: GNU General Public License278907 +Node: Copying This Manual317295 +Node: GNU Free Documentation License317819 +Node: Indices342943 +Node: Macro index343227 +Node: Concept index349837  End Tag Table diff --git a/local/recipes/dev/m4/source/doc/m4.info-1 b/local/recipes/dev/m4/source/doc/m4.info-1 index 9863b94282..788022e5c0 100644 --- a/local/recipes/dev/m4/source/doc/m4.info-1 +++ b/local/recipes/dev/m4/source/doc/m4.info-1 @@ -1,6 +1,6 @@ -This is m4.info, produced by makeinfo version 7.2 from m4.texi. +This is m4.info, produced by makeinfo version 7.3 from m4.texi. -This manual (6 February 2026) is for GNU M4 (version 1.4.21), a package +This manual (15 May 2026) is for GNU M4 (version 1.4.21), a package containing an implementation of the m4 macro language. Copyright © 1989-1994, 2004-2014, 2016-2017, 2020-2026 Free Software @@ -23,7 +23,7 @@ File: m4.info, Node: Top, Next: Preliminaries, Up: (dir) GNU M4 ****** -This manual (6 February 2026) is for GNU M4 (version 1.4.21), a package +This manual (15 May 2026) is for GNU M4 (version 1.4.21), a package containing an implementation of the m4 macro language. Copyright © 1989-1994, 2004-2014, 2016-2017, 2020-2026 Free Software diff --git a/local/recipes/dev/m4/source/doc/m4.info-2 b/local/recipes/dev/m4/source/doc/m4.info-2 index f83d3e8f70..aa9403bb0f 100644 --- a/local/recipes/dev/m4/source/doc/m4.info-2 +++ b/local/recipes/dev/m4/source/doc/m4.info-2 @@ -1,6 +1,6 @@ -This is m4.info, produced by makeinfo version 7.2 from m4.texi. +This is m4.info, produced by makeinfo version 7.3 from m4.texi. -This manual (6 February 2026) is for GNU M4 (version 1.4.21), a package +This manual (15 May 2026) is for GNU M4 (version 1.4.21), a package containing an implementation of the m4 macro language. Copyright © 1989-1994, 2004-2014, 2016-2017, 2020-2026 Free Software diff --git a/local/recipes/dev/m4/source/doc/stamp-vti b/local/recipes/dev/m4/source/doc/stamp-vti index 745a8bdb1c..174211ab7d 100644 --- a/local/recipes/dev/m4/source/doc/stamp-vti +++ b/local/recipes/dev/m4/source/doc/stamp-vti @@ -1,4 +1,4 @@ -@set UPDATED 6 February 2026 -@set UPDATED-MONTH February 2026 +@set UPDATED 15 May 2026 +@set UPDATED-MONTH May 2026 @set EDITION 1.4.21 @set VERSION 1.4.21 diff --git a/local/recipes/dev/m4/source/doc/version.texi b/local/recipes/dev/m4/source/doc/version.texi index 745a8bdb1c..174211ab7d 100644 --- a/local/recipes/dev/m4/source/doc/version.texi +++ b/local/recipes/dev/m4/source/doc/version.texi @@ -1,4 +1,4 @@ -@set UPDATED 6 February 2026 -@set UPDATED-MONTH February 2026 +@set UPDATED 15 May 2026 +@set UPDATED-MONTH May 2026 @set EDITION 1.4.21 @set VERSION 1.4.21 diff --git a/local/recipes/dev/ninja-build/recipe.toml b/local/recipes/dev/ninja-build/recipe.toml index 425ee7e608..743eec1e31 100644 --- a/local/recipes/dev/ninja-build/recipe.toml +++ b/local/recipes/dev/ninja-build/recipe.toml @@ -1,9 +1,31 @@ [source] git = "https://github.com/ninja-build/ninja" rev = "v1.13.1" +patches = ["redox.patch"] [build] -template = "cmake" +template = "custom" +script = """ +DYNAMIC_INIT + +# Add relibc include/lib paths (same as m4/flex gnulib packages) +RELIBC_INCLUDE="${COOKBOOK_ROOT}/prefix/${TARGET}/relibc-install/${TARGET}/include" +RELIBC_LIB="${COOKBOOK_ROOT}/prefix/${TARGET}/relibc-install/${TARGET}/lib" +export CPPFLAGS="${CPPFLAGS} -isystem ${RELIBC_INCLUDE}" +export LDFLAGS="${LDFLAGS} -L${RELIBC_LIB}" + +# Copy updated relibc headers into sysroot so they take precedence over +# the stale toolchain headers at ~/.redoxer/. The C++ wrapper +# explicitly includes the toolchain's stdlib.h which lacks newer functions +# like getloadavg. The -I path (sysroot/include) takes priority over all +# other include paths, so this ensures our headers win. +mkdir -p "${COOKBOOK_SYSROOT}/include" +cp -a "${RELIBC_INCLUDE}/"* "${COOKBOOK_SYSROOT}/include/" + +# Disable tests — build_test.cc includes host headers that conflict with +# relibc's headers during cross-compilation. +cookbook_cmake -DBUILD_TESTING=OFF +""" [package] description = "Ninja build system" diff --git a/local/recipes/dev/ninja-build/redox.patch b/local/recipes/dev/ninja-build/redox.patch index 04218d3218..ae61b549c1 100644 --- a/local/recipes/dev/ninja-build/redox.patch +++ b/local/recipes/dev/ninja-build/redox.patch @@ -1,67 +1,14 @@ ---- a/src/subprocess-posix.cc -+++ b/src/subprocess-posix.cc -@@ -72,6 +72,45 @@ bool Subprocess::Start(SubprocessSet* set, const string& command) { - SetCloseOnExec(fd_); - } - -+#if defined(__redox__) -+ pid_ = fork(); -+ if (pid_ < 0) -+ Fatal("fork: %s", strerror(errno)); -+ if (pid_ == 0) { -+ if (sigprocmask(SIG_SETMASK, &set->old_mask_, 0) < 0) { -+ perror("ninja: sigprocmask"); -+ _exit(1); -+ } -+ if (!use_console_) { -+ if (setpgid(0, 0) < 0) { -+ perror("ninja: setpgid"); -+ _exit(1); -+ } -+ int devnull = open("/dev/null", O_RDONLY); -+ if (devnull < 0) { -+ perror("ninja: open /dev/null"); -+ _exit(1); -+ } -+ if (dup2(devnull, 0) < 0 || dup2(subproc_stdout_fd, 1) < 0 || -+ dup2(subproc_stdout_fd, 2) < 0) { -+ perror("ninja: dup2"); -+ _exit(1); -+ } -+ close(devnull); -+ close(fd_); -+ close(subproc_stdout_fd); -+ } -+ -+ const char* spawned_args[] = { "/bin/sh", "-c", command.c_str(), NULL }; -+ execve("/bin/sh", const_cast(spawned_args), environ); -+ perror("ninja: execve /bin/sh"); -+ _exit(127); -+ } -+ -+ if (!use_console_) -+ close(subproc_stdout_fd); -+ return true; -+#else - posix_spawn_file_actions_t action; - int err = posix_spawn_file_actions_init(&action); - if (err != 0) -@@ -145,6 +184,7 @@ bool Subprocess::Start(SubprocessSet* set, const string& command) { - if (!use_console_) - close(subproc_stdout_fd); - return true; -+#endif - } - - void Subprocess::OnPipeReady() { --- a/src/util.cc +++ b/src/util.cc -@@ -973,7 +973,7 @@ double GetLoadAverage() { - return -0.0f; - return 1.0 / (1 << SI_LOAD_SHIFT) * si.loads[0]; - } --#elif defined(__HAIKU__) -+#elif defined(__HAIKU__) || defined(__redox__) - double GetLoadAverage() { - return -0.0f; - } +@@ -30,6 +30,11 @@ + #include + #include + #include ++// Redox: the C++ wrapper pulls in a stale toolchain stdlib.h that ++// lacks getloadavg. Re-declare it here since relibc provides the implementation. ++#if defined(__redox__) ++extern "C" int getloadavg(double loadavg[], int nelem); ++#endif + #include + #include + #include diff --git a/recipes/core/base/audiod/Cargo.toml b/recipes/core/base/audiod/Cargo.toml deleted file mode 100644 index 762a080b9a..0000000000 --- a/recipes/core/base/audiod/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "audiod" -description = "Sound daemon" -version = "0.1.0" -authors = ["Jeremy Soller "] -edition = "2021" - -[dependencies] -daemon = { path = "../daemon" } -redox_syscall = { workspace = true, features = ["std"] } -libc.workspace = true -libredox = { workspace = true, features = ["mkns"] } -redox-scheme.workspace = true -scheme-utils = { path = "../scheme-utils" } -anyhow.workspace = true -ioslice = "0.6.0" - -[lints] -workspace = true diff --git a/recipes/core/base/audiod/src/main.rs b/recipes/core/base/audiod/src/main.rs deleted file mode 100644 index 51b103afa6..0000000000 --- a/recipes/core/base/audiod/src/main.rs +++ /dev/null @@ -1,94 +0,0 @@ -//! The audio daemon for RedoxOS. -use std::mem::MaybeUninit; -use std::ptr::addr_of_mut; -use std::sync::{Arc, Mutex}; -use std::{mem, process, slice, thread}; - -use anyhow::Context; -use ioslice::IoSlice; -use libredox::flag; -use libredox::{error::Result, Fd}; - -use redox_scheme::Socket; -use scheme_utils::ReadinessBased; - -use daemon::SchemeDaemon; - -use self::scheme::AudioScheme; - -mod scheme; - -extern "C" fn sigusr_handler(_sig: usize) {} - -fn thread(scheme: Arc>, pid: usize, hw_file: Fd) -> Result<()> { - loop { - let buffer = scheme.lock().unwrap().buffer(); - let buffer_u8 = unsafe { - slice::from_raw_parts(buffer.as_ptr() as *const u8, mem::size_of_val(&buffer)) - }; - - // Wake up the scheme thread - libredox::call::kill(pid, libredox::flag::SIGUSR1 as u32)?; - - hw_file.write(&buffer_u8)?; - } -} - -fn daemon(daemon: SchemeDaemon) -> anyhow::Result<()> { - // Handle signals from the hw thread - - let new_sigaction = unsafe { - let mut sigaction = MaybeUninit::::uninit(); - addr_of_mut!((*sigaction.as_mut_ptr()).sa_flags).write(0); - libc::sigemptyset(addr_of_mut!((*sigaction.as_mut_ptr()).sa_mask)); - addr_of_mut!((*sigaction.as_mut_ptr()).sa_sigaction).write(sigusr_handler as usize); - sigaction.assume_init() - }; - libredox::call::sigaction(flag::SIGUSR1, Some(&new_sigaction), None)?; - - let pid = libredox::call::getpid()?; - - let hw_file = Fd::open("/scheme/audiohw", flag::O_WRONLY | flag::O_CLOEXEC, 0)?; - - let socket = Socket::create().context("failed to create scheme")?; - - let scheme = Arc::new(Mutex::new(AudioScheme::new())); - - let _ = daemon.ready_sync_scheme(&socket, &mut *scheme.lock().unwrap()); - - // Enter a constrained namespace - let ns = libredox::call::mkns(&[ - IoSlice::new(b"memory"), - IoSlice::new(b"rand"), // for HashMap - ]) - .context("failed to make namespace")?; - libredox::call::setns(ns).context("failed to set namespace")?; - - // Spawn a thread to mix and send audio data - let scheme_thread = scheme.clone(); - let _thread = thread::spawn(move || thread(scheme_thread, pid, hw_file)); - - let mut readiness = ReadinessBased::new(&socket, 16); - - loop { - readiness.read_and_process_requests(&mut *scheme.lock().unwrap())?; - readiness.poll_all_requests(&mut *scheme.lock().unwrap())?; - readiness.write_responses()?; - } -} - -fn main() { - SchemeDaemon::new(inner); -} - -fn inner(x: SchemeDaemon) -> ! { - match daemon(x) { - Ok(()) => { - process::exit(0); - } - Err(err) => { - eprintln!("audiod: {}", err); - process::exit(1); - } - } -} diff --git a/recipes/core/base/audiod/src/scheme.rs b/recipes/core/base/audiod/src/scheme.rs deleted file mode 100644 index 62d9b9ede2..0000000000 --- a/recipes/core/base/audiod/src/scheme.rs +++ /dev/null @@ -1,177 +0,0 @@ -use redox_scheme::{CallerCtx, OpenResult}; -use scheme_utils::HandleMap; -use std::collections::VecDeque; -use std::str; -use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, ENOENT, EWOULDBLOCK}; - -use redox_scheme::scheme::SchemeSync; -use syscall::schemev2::NewFdFlags; - -// The strict buffer size of the audiohw: driver -const HW_BUFFER_SIZE: usize = 512; -// The desired buffer size of each handle -const HANDLE_BUFFER_SIZE: usize = 4096; - -enum Handle { - Audio { buffer: VecDeque<(i16, i16)> }, - // TODO: move volume to audiohw:? - // TODO: Use SYS_CALL to handle this better? - Volume, - SchemeRoot, -} - -pub struct AudioScheme { - handles: HandleMap, - volume: i32, -} - -impl AudioScheme { - pub fn new() -> Self { - AudioScheme { - handles: HandleMap::new(), - volume: 50, - } - } - - pub fn buffer(&mut self) -> [(i16, i16); HW_BUFFER_SIZE] { - let mut mix_buffer = [(0i16, 0i16); HW_BUFFER_SIZE]; - - // Multiply each sample by the cube of volume divided by 100 - // This mimics natural perception of loudness - let volume_factor = ((self.volume as f32) / 100.0).powi(3); - for (_id, handle) in self.handles.iter_mut() { - match handle { - Handle::Audio { ref mut buffer } => { - let mut i = 0; - while i < mix_buffer.len() { - if let Some(sample) = buffer.pop_front() { - let left = (sample.0 as f32 * volume_factor) as i16; - let right = (sample.1 as f32 * volume_factor) as i16; - mix_buffer[i].0 = mix_buffer[i].0.saturating_add(left); - mix_buffer[i].1 = mix_buffer[i].1.saturating_add(right); - } else { - break; - } - i += 1; - } - } - _ => (), - } - } - - mix_buffer - } -} - -impl SchemeSync for AudioScheme { - fn scheme_root(&mut self) -> Result { - Ok(self.handles.insert(Handle::SchemeRoot)) - } - fn openat( - &mut self, - dirfd: usize, - path: &str, - _flags: usize, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - if !matches!(self.handles.get(dirfd)?, Handle::SchemeRoot) { - return Err(Error::new(EACCES)); - } - - let (handle, flags) = match path.trim_matches('/') { - "" => ( - Handle::Audio { - buffer: VecDeque::new(), - }, - NewFdFlags::empty(), - ), - "volume" => (Handle::Volume, NewFdFlags::POSITIONED), - _ => return Err(Error::new(ENOENT)), - }; - - let id = self.handles.insert(handle); - - Ok(OpenResult::ThisScheme { number: id, flags }) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - off: u64, - _flags: u32, - _ctx: &CallerCtx, - ) -> Result { - //TODO: check flags for readable - match self.handles.get_mut(id)? { - Handle::Audio { buffer: _ } => { - //TODO: audio input? - Err(Error::new(EBADF)) - } - Handle::Volume => { - let Ok(off) = usize::try_from(off) else { - return Ok(0); - }; - //TODO: should we allocate every time? - let bytes = format!("{}", self.volume).into_bytes(); - let src = bytes.get(off..).unwrap_or(&[]); - let len = src.len().min(buf.len()); - buf[..len].copy_from_slice(&src[..len]); - - Ok(len) - } - Handle::SchemeRoot => Err(Error::new(EBADF)), - } - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - offset: u64, - _flags: u32, - _ctx: &CallerCtx, - ) -> Result { - //TODO: check flags for writable - match self.handles.get_mut(id)? { - Handle::Audio { ref mut buffer } => { - if buffer.len() >= HANDLE_BUFFER_SIZE { - Err(Error::new(EWOULDBLOCK)) - } else { - let mut i = 0; - while i + 4 <= buf.len() { - buffer.push_back(( - (buf[i] as i16) | ((buf[i + 1] as i16) << 8), - (buf[i + 2] as i16) | ((buf[i + 3] as i16) << 8), - )); - - i += 4; - } - - Ok(i) - } - } - Handle::Volume => { - //TODO: support other offsets? - if offset == 0 { - let value = str::from_utf8(buf) - .map_err(|_| Error::new(EINVAL))? - .trim() - .parse::() - .map_err(|_| Error::new(EINVAL))?; - if value >= 0 && value <= 100 { - self.volume = value; - Ok(buf.len()) - } else { - Err(Error::new(EINVAL)) - } - } else { - // EOF - Ok(0) - } - } - Handle::SchemeRoot => Err(Error::new(EBADF)), - } - } -} diff --git a/recipes/core/base/bootstrap/.cargo/config.toml b/recipes/core/base/bootstrap/.cargo/config.toml deleted file mode 100644 index b69619dd83..0000000000 --- a/recipes/core/base/bootstrap/.cargo/config.toml +++ /dev/null @@ -1,3 +0,0 @@ -[unstable] -build-std = ["core", "alloc", "compiler_builtins"] -build-std-features = ["compiler-builtins-mem"] diff --git a/recipes/core/base/bootstrap/Cargo.toml b/recipes/core/base/bootstrap/Cargo.toml deleted file mode 100644 index 82120c213d..0000000000 --- a/recipes/core/base/bootstrap/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -name = "bootstrap" -description = "Userspace bootstrapper" -version = "0.0.0" -authors = ["4lDO2 <4lDO2@protonmail.com>"] -edition = "2024" -license = "MIT" - -[dependencies] -hashbrown = { version = "0.15", default-features = false, features = [ - "inline-more", - "default-hasher", -] } -linked_list_allocator = "0.10" -libredox = { version = "0.1.16", default-features = false, features = ["protocol"] } -log = { version = "0.4", default-features = false } -plain = "0.2" -redox-initfs = { path = "../initfs", default-features = false } -redox_syscall = "0.7.4" -redox-scheme = { version = "0.11.0", default-features = false } -redox-path = "0.3.1" -slab = { version = "0.4.9", default-features = false } -arrayvec = { version = "0.7.6", default-features = false } - -[target.'cfg(target_os = "redox")'.dependencies] -redox-rt = { git = "https://gitlab.redox-os.org/redox-os/relibc.git", default-features = false } - -[profile.release] -panic = "abort" -lto = "fat" -opt-level = "s" - -[profile.dev] -panic = "abort" -opt-level = "s" diff --git a/recipes/core/base/bootstrap/build.rs b/recipes/core/base/bootstrap/build.rs deleted file mode 100644 index dae28f09ff..0000000000 --- a/recipes/core/base/bootstrap/build.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::env; - -fn main() { - let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); - let mut arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap(); - if arch == "x86" { - arch = "i586".to_owned(); - } - - println!("cargo::rustc-link-arg=-z"); - println!("cargo::rustc-link-arg=max-page-size=4096"); - println!("cargo::rustc-link-arg=-T"); - println!("cargo::rustc-link-arg={manifest_dir}/src/{arch}.ld"); -} diff --git a/recipes/core/base/bootstrap/src/aarch64.ld b/recipes/core/base/bootstrap/src/aarch64.ld deleted file mode 100644 index 4a0804b8c2..0000000000 --- a/recipes/core/base/bootstrap/src/aarch64.ld +++ /dev/null @@ -1,55 +0,0 @@ -ENTRY(_start) -OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64") - -SECTIONS { - . = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */ - __initfs_header = . - 4096; - . += SIZEOF_HEADERS; - . = ALIGN(4096); - - .text : { - __text_start = .; - *(.text*) - . = ALIGN(4096); - __text_end = .; - } - .rodata : { - __rodata_start = .; - *(.rodata*) - } - .data.rel.ro : { - *(.data.rel.ro*) - } - .got : { - *(.got) - } - .got.plt : { - *(.got.plt) - . = ALIGN(4096); - __rodata_end = .; - } - .data : { - __data_start = .; - *(.data*) - . = ALIGN(4096); - __data_end = .; - - *(.tbss*) - . = ALIGN(4096); - *(.tdata*) - . = ALIGN(4096); - - __bss_start = .; - *(.bss*) - . = ALIGN(4096); - __bss_end = .; - } - - /DISCARD/ : { - *(.comment*) - *(.eh_frame*) - *(.gcc_except_table*) - *(.note*) - *(.rel.eh_frame*) - } -} diff --git a/recipes/core/base/bootstrap/src/aarch64.rs b/recipes/core/base/bootstrap/src/aarch64.rs deleted file mode 100644 index ee39725f86..0000000000 --- a/recipes/core/base/bootstrap/src/aarch64.rs +++ /dev/null @@ -1,53 +0,0 @@ -use core::mem; -use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP}; - -pub const USERMODE_END: usize = 0x0000_8000_0000_0000; -pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE; - -const STACK_SIZE: usize = 64 * 1024; // 64 KiB -static MAP: Map = Map { - offset: 0, - size: STACK_SIZE, - flags: MapFlags::PROT_READ - .union(MapFlags::PROT_WRITE) - .union(MapFlags::MAP_PRIVATE) - .union(MapFlags::MAP_FIXED_NOREPLACE), - address: STACK_START, // highest possible user address -}; - -core::arch::global_asm!( - " - .globl _start - _start: - // Setup a stack. - ldr x8, ={number} - ldr x0, ={fd} - ldr x1, ={map} // pointer to Map struct - ldr x2, ={map_size} // size of Map struct - svc 0 - - // Failure if return value is zero - cbz x0, 1f - - // Failure if return value is negative - tbnz x0, 63, 1f - - // Set up stack frame - mov sp, x0 - add sp, sp, #{stack_size} - mov fp, sp - - // Stack has the same alignment as `size`. - bl start - // `start` must never return. - - // failure, emit undefined instruction - 1: - udf #0 - ", - fd = const usize::MAX, // dummy fd indicates anonymous map - map = sym MAP, - map_size = const mem::size_of::(), - number = const SYS_FMAP, - stack_size = const STACK_SIZE, -); diff --git a/recipes/core/base/bootstrap/src/exec.rs b/recipes/core/base/bootstrap/src/exec.rs deleted file mode 100644 index 8425e3b5e1..0000000000 --- a/recipes/core/base/bootstrap/src/exec.rs +++ /dev/null @@ -1,354 +0,0 @@ -use alloc::string::ToString; -use alloc::sync::Arc; -use alloc::vec::Vec; -use core::ffi::CStr; -use core::str::FromStr; -use hashbrown::HashMap; -use redox_scheme::Socket; - -use syscall::CallFlags; -use syscall::data::{GlobalSchemes, KernelSchemeInfo}; -use syscall::flag::{O_CLOEXEC, O_RDONLY, O_STAT}; -use syscall::{EINTR, Error}; - -use redox_rt::proc::*; - -use crate::KernelSchemeMap; - -struct Logger; - -impl log::Log for Logger { - fn enabled(&self, metadata: &log::Metadata) -> bool { - metadata.level() <= log::max_level() - } - fn log(&self, record: &log::Record) { - let file = record.file().unwrap_or(""); - let line = record.line().unwrap_or(0); - let level = record.level(); - let msg = record.args(); - let _ = syscall::write( - 1, - alloc::format!("[{file}:{line} {level}] {msg}\n").as_bytes(), - ); - } - fn flush(&self) {} -} - -const KERNEL_METADATA_BASE: usize = crate::arch::USERMODE_END - syscall::KERNEL_METADATA_SIZE; - -pub fn main() -> ! { - let mut cursor = KERNEL_METADATA_BASE; - let kernel_scheme_infos = unsafe { - let base_ptr = cursor as *const u8; - let infos_len = *(base_ptr as *const usize); - let infos_ptr = base_ptr.add(core::mem::size_of::()) as *const KernelSchemeInfo; - let slice = core::slice::from_raw_parts(infos_ptr, infos_len); - cursor += core::mem::size_of::() // kernel scheme number size - + infos_len // kernel scheme number - * core::mem::size_of::(); - slice - }; - let scheme_creation_cap = unsafe { - let base_ptr = cursor as *const u8; - FdGuard::new(*(base_ptr as *const usize)) - }; - - let mut kernel_schemes = KernelSchemeMap::new(kernel_scheme_infos); - - let auth = kernel_schemes - .0 - .remove(&GlobalSchemes::Proc) - .expect("failed to get proc fd"); - - let this_thr_fd = auth - .dup(b"cur-context") - .expect("failed to open open_via_dup") - .to_upper() - .unwrap(); - let this_thr_fd = unsafe { redox_rt::initialize_freestanding(this_thr_fd) }; - - let mut env_bytes = [0_u8; 4096]; - let mut envs = { - let fd = FdGuard::new( - syscall::openat( - kernel_schemes - .get(GlobalSchemes::Sys) - .expect("failed to get sys fd") - .as_raw_fd(), - "env", - O_RDONLY | O_CLOEXEC, - 0, - ) - .expect("bootstrap: failed to open env"), - ); - let bytes_read = fd - .read(&mut env_bytes) - .expect("bootstrap: failed to read env"); - - if bytes_read >= env_bytes.len() { - // TODO: Handle this, we can allocate as much as we want in theory. - panic!("env is too large"); - } - let env_bytes = &mut env_bytes[..bytes_read]; - - env_bytes - .split(|&c| c == b'\n') - .filter(|var| !var.is_empty()) - .filter(|var| !var.starts_with(b"INITFS_")) - .collect::>() - }; - envs.push(b"RUST_BACKTRACE=1"); - //envs.push(b"LD_DEBUG=all"); - envs.push(b"LD_LIBRARY_PATH=/scheme/initfs/lib"); - - log::set_max_level(log::LevelFilter::Warn); - - if let Some(log_env) = envs - .iter() - .find_map(|var| var.strip_prefix(b"BOOTSTRAP_LOG_LEVEL=")) - { - if let Ok(Ok(log_level)) = str::from_utf8(&log_env).map(|s| log::LevelFilter::from_str(s)) { - log::set_max_level(log_level); - } - } - - let _ = log::set_logger(&Logger); - - unsafe extern "C" { - // The linker script will define this as the location of the initfs header. - static __initfs_header: u8; - - // The linker script will define this as the end of the executable (excluding initfs). - static __bss_end: u8; - } - - let initfs_start = core::ptr::addr_of!(__initfs_header); - let initfs_length = unsafe { - (*(core::ptr::addr_of!(__initfs_header) as *const redox_initfs::types::Header)) - .initfs_size - .get() as usize - }; - - let (scheme_creation_cap, auth, kernel_schemes, initfs_fd) = spawn( - "initfs daemon", - auth, - &this_thr_fd, - scheme_creation_cap, - kernel_schemes, - false, - |write_fd, socket, _, _| unsafe { - crate::initfs::run( - core::slice::from_raw_parts(initfs_start, initfs_length), - write_fd, - socket, - ); - }, - ); - - // Unmap initfs data as only the initfs scheme implementation needs it. - unsafe { - let executable_end = core::ptr::addr_of!(__bss_end) - .add(core::ptr::addr_of!(__bss_end).align_offset(syscall::PAGE_SIZE)); - syscall::funmap( - executable_end as usize, - initfs_length.next_multiple_of(syscall::PAGE_SIZE) - - (executable_end.offset_from(initfs_start) as usize), - ) - .unwrap(); - } - - let (scheme_creation_cap, auth, kernel_schemes, proc_fd) = spawn( - "process manager", - auth, - &this_thr_fd, - scheme_creation_cap, - kernel_schemes, - true, - |write_fd, socket, auth, mut kernel_schemes| { - let event = kernel_schemes - .0 - .remove(&GlobalSchemes::Event) - .expect("failed to get event fd"); - drop(kernel_schemes); - crate::procmgr::run(write_fd, socket, auth, event) - }, - ); - - let scheme_creation_cap_dup = scheme_creation_cap - .dup(b"") - .expect("failed to dup scheme creation cap"); - let (_, _, _, initns_fd) = spawn( - "init namespace manager", - auth, - &this_thr_fd, - scheme_creation_cap, - kernel_schemes, - false, - |write_fd, socket, _, kernel_schemes| { - let mut schemes = HashMap::default(); - for (scheme, fd) in kernel_schemes.0.into_iter() { - schemes.insert(scheme.as_str().to_string(), Arc::new(fd)); - } - schemes.insert( - "proc".to_string(), - // A bit dirty, but necessary as the parent process still needs access to it. Rust - // doesn't know that the fd got cloned by fork. - Arc::new(FdGuard::new(proc_fd.as_raw_fd())), - ); - schemes.insert("initfs".to_string(), Arc::new(initfs_fd)); - - crate::initnsmgr::run(write_fd, socket, schemes, scheme_creation_cap_dup) - }, - ); - - let (init_proc_fd, init_thr_fd) = unsafe { make_init(proc_fd.take()) }; - // from this point, this_thr_fd is no longer valid - - const CWD: &[u8] = b"/scheme/initfs"; - let cwd_fd = FdGuard::new( - syscall::openat(initns_fd.as_raw_fd(), "/scheme/initfs", O_STAT, 0) - .expect("failed to open cwd fd"), - ) - .to_upper() - .unwrap(); - let extrainfo = ExtraInfo { - cwd: Some(CWD), - sigprocmask: 0, - sigignmask: 0, - umask: redox_rt::sys::get_umask(), - thr_fd: init_thr_fd.as_raw_fd(), - proc_fd: init_proc_fd.as_raw_fd(), - ns_fd: Some(initns_fd.take()), - cwd_fd: Some(cwd_fd.as_raw_fd()), - }; - - let exe_path = "/scheme/initfs/bin/init"; - - let image_file = FdGuard::new( - syscall::openat(extrainfo.ns_fd.unwrap(), exe_path, O_RDONLY | O_CLOEXEC, 0) - .expect("failed to open init"), - ) - .to_upper() - .unwrap(); - - let FexecResult::Interp { - path: interp_path, - interp_override, - } = fexec_impl( - image_file, - init_thr_fd, - init_proc_fd, - exe_path.as_bytes(), - &[exe_path.as_bytes()], - &envs, - &extrainfo, - None, - ) - .expect("failed to execute init"); - - // According to elf(5), PT_INTERP requires that the interpreter path be - // null-terminated. Violating this should therefore give the "format error" ENOEXEC. - let interp_cstr = CStr::from_bytes_with_nul(&interp_path).expect("interpreter not valid C str"); - let interp_file = FdGuard::new( - syscall::openat( - extrainfo.ns_fd.unwrap(), // initns, not initfs! - interp_cstr.to_str().expect("interpreter not UTF-8"), - O_RDONLY | O_CLOEXEC, - 0, - ) - .expect("failed to open dynamic linker"), - ) - .to_upper() - .unwrap(); - - fexec_impl( - interp_file, - init_thr_fd, - init_proc_fd, - exe_path.as_bytes(), - &[exe_path.as_bytes()], - &envs, - &extrainfo, - Some(interp_override), - ) - .expect("failed to execute init"); - - unreachable!() -} - -pub(crate) fn spawn( - name: &str, - auth: FdGuard, - this_thr_fd: &FdGuardUpper, - scheme_creation_cap: FdGuard, - kernel_schemes: KernelSchemeMap, - nonblock: bool, - inner: impl FnOnce(FdGuard, Socket, FdGuard, KernelSchemeMap) -> !, -) -> (FdGuard, FdGuard, KernelSchemeMap, FdGuard) { - let read = FdGuard::new( - syscall::openat( - kernel_schemes - .get(GlobalSchemes::Pipe) - .expect("failed to get pipe fd") - .as_raw_fd(), - "", - O_CLOEXEC, - 0, - ) - .expect("failed to open sync read pipe"), - ); - - // The write pipe will not inherit O_CLOEXEC, but is closed by the daemon later. - let write = FdGuard::new( - syscall::dup(read.as_raw_fd(), b"write").expect("failed to open sync write pipe"), - ); - - match fork_impl(&ForkArgs::Init { - this_thr_fd, - auth: &auth, - }) { - Err(err) => { - panic!("Failed to fork in order to start {name}: {err}"); - } - // Continue serving the scheme as the child. - Ok(0) => { - drop(read); - - let socket = Socket::create_inner(scheme_creation_cap.as_raw_fd(), nonblock) - .expect("failed to open proc scheme socket"); - drop(scheme_creation_cap); - - inner(write, socket, auth, kernel_schemes) - } - // Return in order to execute init, as the parent. - Ok(_) => { - drop(write); - - let mut new_fd = usize::MAX; - let fd_bytes = unsafe { - core::slice::from_raw_parts_mut( - core::slice::from_mut(&mut new_fd).as_mut_ptr() as *mut u8, - core::mem::size_of::(), - ) - }; - loop { - match syscall::call_ro( - read.as_raw_fd(), - fd_bytes, - CallFlags::FD | CallFlags::FD_UPPER, - &[], - ) { - Err(Error { errno: EINTR }) => continue, - _ => break, - } - } - - ( - scheme_creation_cap, - auth, - kernel_schemes, - FdGuard::new(new_fd), - ) - } - } -} diff --git a/recipes/core/base/bootstrap/src/i586.ld b/recipes/core/base/bootstrap/src/i586.ld deleted file mode 100644 index f53877f039..0000000000 --- a/recipes/core/base/bootstrap/src/i586.ld +++ /dev/null @@ -1,55 +0,0 @@ -ENTRY(_start) -OUTPUT_FORMAT(elf32-i386) - -SECTIONS { - . = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */ - __initfs_header = . - 4096; - . += SIZEOF_HEADERS; - . = ALIGN(4096); - - .text : { - __text_start = .; - *(.text*) - . = ALIGN(4096); - __text_end = .; - } - .rodata : { - __rodata_start = .; - *(.rodata*) - } - .data.rel.ro : { - *(.data.rel.ro*) - } - .got : { - *(.got) - } - .got.plt : { - *(.got.plt) - . = ALIGN(4096); - __rodata_end = .; - } - .data : { - __data_start = .; - *(.data*) - . = ALIGN(4096); - __data_end = .; - - *(.tbss*) - . = ALIGN(4096); - *(.tdata*) - . = ALIGN(4096); - - __bss_start = .; - *(.bss*) - . = ALIGN(4096); - __bss_end = .; - } - - /DISCARD/ : { - *(.comment*) - *(.eh_frame*) - *(.gcc_except_table*) - *(.note*) - *(.rel.eh_frame*) - } -} diff --git a/recipes/core/base/bootstrap/src/i686.ld b/recipes/core/base/bootstrap/src/i686.ld deleted file mode 100644 index f53877f039..0000000000 --- a/recipes/core/base/bootstrap/src/i686.ld +++ /dev/null @@ -1,55 +0,0 @@ -ENTRY(_start) -OUTPUT_FORMAT(elf32-i386) - -SECTIONS { - . = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */ - __initfs_header = . - 4096; - . += SIZEOF_HEADERS; - . = ALIGN(4096); - - .text : { - __text_start = .; - *(.text*) - . = ALIGN(4096); - __text_end = .; - } - .rodata : { - __rodata_start = .; - *(.rodata*) - } - .data.rel.ro : { - *(.data.rel.ro*) - } - .got : { - *(.got) - } - .got.plt : { - *(.got.plt) - . = ALIGN(4096); - __rodata_end = .; - } - .data : { - __data_start = .; - *(.data*) - . = ALIGN(4096); - __data_end = .; - - *(.tbss*) - . = ALIGN(4096); - *(.tdata*) - . = ALIGN(4096); - - __bss_start = .; - *(.bss*) - . = ALIGN(4096); - __bss_end = .; - } - - /DISCARD/ : { - *(.comment*) - *(.eh_frame*) - *(.gcc_except_table*) - *(.note*) - *(.rel.eh_frame*) - } -} diff --git a/recipes/core/base/bootstrap/src/i686.rs b/recipes/core/base/bootstrap/src/i686.rs deleted file mode 100644 index 5fbbf47908..0000000000 --- a/recipes/core/base/bootstrap/src/i686.rs +++ /dev/null @@ -1,49 +0,0 @@ -use core::mem; -use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP}; - -const STACK_SIZE: usize = 64 * 1024; // 64 KiB -pub const USERMODE_END: usize = 0x8000_0000; -pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE; - -static MAP: Map = Map { - offset: 0, - size: STACK_SIZE, - flags: MapFlags::PROT_READ - .union(MapFlags::PROT_WRITE) - .union(MapFlags::MAP_PRIVATE) - .union(MapFlags::MAP_FIXED_NOREPLACE), - address: STACK_START, // highest possible user address -}; - -core::arch::global_asm!( - " - .globl _start - _start: - # Setup a stack. - mov eax, {number} - mov ebx, {fd} - mov ecx, offset {map} # pointer to Map struct - mov edx, {map_size} # size of Map struct - int 0x80 - - # Test for success (nonzero value). - cmp eax, 0 - jg 1f - # (failure) - ud2 - 1: - # Subtract 16 since all instructions seem to hate non-canonical ESP values :) - lea esp, [eax+{stack_size}-16] - mov ebp, esp - - # Stack has the same alignment as `size`. - call start - # `start` must never return. - ud2 - ", - fd = const usize::MAX, // dummy fd indicates anonymous map - map = sym MAP, - map_size = const mem::size_of::(), - number = const SYS_FMAP, - stack_size = const STACK_SIZE, -); diff --git a/recipes/core/base/bootstrap/src/initfs.rs b/recipes/core/base/bootstrap/src/initfs.rs deleted file mode 100644 index 04d3cfe033..0000000000 --- a/recipes/core/base/bootstrap/src/initfs.rs +++ /dev/null @@ -1,485 +0,0 @@ -use core::convert::TryFrom; -#[allow(deprecated)] -use core::hash::{BuildHasherDefault, SipHasher}; -use core::str; - -use alloc::string::String; - -use hashbrown::HashMap; -use redox_initfs::{InitFs, Inode, InodeDir, InodeKind, InodeStruct}; - -use redox_rt::proc::FdGuard; -use redox_scheme::{ - CallerCtx, OpenResult, RequestKind, - scheme::{SchemeState, SchemeSync}, -}; - -use redox_scheme::{SignalBehavior, Socket}; -use syscall::PAGE_SIZE; -use syscall::data::Stat; -use syscall::dirent::DirEntry; -use syscall::dirent::DirentBuf; -use syscall::dirent::DirentKind; -use syscall::error::*; -use syscall::flag::*; -use syscall::schemev2::NewFdFlags; - -enum Handle { - Node(Node), - SchemeRoot, -} -impl Handle { - fn as_node(&self) -> Result<&Node> { - match self { - Handle::Node(n) => Ok(n), - _ => Err(Error::new(EBADF)), - } - } - fn as_node_mut(&mut self) -> Result<&mut Node> { - match self { - Handle::Node(n) => Ok(n), - _ => Err(Error::new(EBADF)), - } - } -} - -struct Node { - inode: Inode, - // TODO: Any better way to implement fpath? Or maybe work around it, e.g. by giving paths such - // as `initfs:__inodes__/`? - filename: String, -} -pub struct InitFsScheme { - #[allow(deprecated)] - handles: HashMap>, - next_id: usize, - fs: InitFs<'static>, -} -impl InitFsScheme { - pub fn new(bytes: &'static [u8]) -> Self { - Self { - handles: HashMap::default(), - next_id: 0, - fs: InitFs::new(bytes, Some(PAGE_SIZE.try_into().unwrap())) - .expect("failed to parse initfs"), - } - } - - fn get_inode(fs: &InitFs<'static>, inode: Inode) -> Result> { - fs.get_inode(inode).ok_or_else(|| Error::new(EIO)) - } - fn next_id(&mut self) -> usize { - assert_ne!(self.next_id, usize::MAX, "usize overflow in initfs scheme"); - self.next_id += 1; - self.next_id - } -} - -struct Iter { - dir: InodeDir<'static>, - idx: u32, -} -impl Iterator for Iter { - type Item = Result>; - - fn next(&mut self) -> Option { - let entry = self.dir.get_entry(self.idx).map_err(|_| Error::new(EIO)); - self.idx += 1; - entry.transpose() - } - fn size_hint(&self) -> (usize, Option) { - match self.dir.entry_count().ok() { - Some(size) => { - let size = - usize::try_from(size).expect("expected u32 to be convertible into usize"); - (size, Some(size)) - } - None => (0, None), - } - } -} - -fn inode_len(inode: InodeStruct<'static>) -> Result { - Ok(match inode.kind() { - InodeKind::File(file) => file.data().map_err(|_| Error::new(EIO))?.len(), - InodeKind::Dir(dir) => (Iter { dir, idx: 0 }).fold(0, |len, entry| { - len + entry - .and_then(|entry| entry.name().map_err(|_| Error::new(EIO))) - .map_or(0, |name| name.len() + 1) - }), - InodeKind::Link(link) => link.data().map_err(|_| Error::new(EIO))?.len(), - InodeKind::Unknown => return Err(Error::new(EIO)), - }) -} - -impl SchemeSync for InitFsScheme { - fn openat( - &mut self, - dirfd: usize, - path: &str, - flags: usize, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - if !matches!( - self.handles.get(&dirfd).ok_or(Error::new(EBADF))?, - Handle::SchemeRoot - ) { - return Err(Error::new(EACCES)); - } - let mut components = path - // trim leading and trailing slash - .trim_matches('/') - // divide into components - .split('/') - // filter out double slashes (e.g. /usr//bin/...) - .filter(|c| !c.is_empty()); - - let mut current_inode = self.fs.root_inode(); - - while let Some(component) = components.next() { - match component { - "." => continue, - ".." => { - let _ = components.next_back(); - continue; - } - - _ => (), - } - - let current_inode_struct = Self::get_inode(&self.fs, current_inode)?; - - let dir = match current_inode_struct.kind() { - InodeKind::Dir(dir) => dir, - - // TODO: Support symlinks in other position than xopen target - InodeKind::Link(_) => { - return Err(Error::new(EOPNOTSUPP)); - } - - // If we still have more components in the path, and the file tree for that - // particular branch is not all directories except the last, then that file cannot - // exist. - InodeKind::File(_) | InodeKind::Unknown => return Err(Error::new(ENOENT)), - }; - - let mut entries = Iter { dir, idx: 0 }; - - current_inode = loop { - let entry_res = match entries.next() { - Some(e) => e, - None => return Err(Error::new(ENOENT)), - }; - let entry = entry_res?; - let name = entry.name().map_err(|_| Error::new(EIO))?; - if name == component.as_bytes() { - break entry.inode(); - } - }; - } - - // xopen target is link -- return EXDEV so that the file is opened as a link. - // TODO: Maybe follow initfs-local symlinks here? Would be faster - let is_link = matches!( - Self::get_inode(&self.fs, current_inode)?.kind(), - InodeKind::Link(_) - ); - let o_stat_nofollow = flags & O_STAT != 0 && flags & O_NOFOLLOW != 0; - let o_symlink = flags & O_SYMLINK != 0; - if is_link && !o_stat_nofollow && !o_symlink { - return Err(Error::new(EXDEV)); - } - - let id = self.next_id(); - let old = self.handles.insert( - id, - Handle::Node(Node { - inode: current_inode, - filename: path.into(), - }), - ); - assert!(old.is_none()); - - Ok(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - }) - } - - fn read( - &mut self, - id: usize, - buffer: &mut [u8], - offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - let Ok(offset) = usize::try_from(offset) else { - return Ok(0); - }; - - let handle = self - .handles - .get_mut(&id) - .ok_or(Error::new(EBADF))? - .as_node_mut()?; - - match Self::get_inode(&self.fs, handle.inode)?.kind() { - InodeKind::File(file) => { - let data = file.data().map_err(|_| Error::new(EIO))?; - let src_buf = &data[core::cmp::min(offset, data.len())..]; - - let to_copy = core::cmp::min(src_buf.len(), buffer.len()); - buffer[..to_copy].copy_from_slice(&src_buf[..to_copy]); - - Ok(to_copy) - } - InodeKind::Dir(_) => Err(Error::new(EISDIR)), - InodeKind::Link(link) => { - let link_data = link.data().map_err(|_| Error::new(EIO))?; - let src_buf = &link_data[core::cmp::min(offset, link_data.len())..]; - - let to_copy = core::cmp::min(src_buf.len(), buffer.len()); - buffer[..to_copy].copy_from_slice(&src_buf[..to_copy]); - - Ok(to_copy) - } - InodeKind::Unknown => Err(Error::new(EIO)), - } - } - fn getdents<'buf>( - &mut self, - id: usize, - mut buf: DirentBuf<&'buf mut [u8]>, - opaque_offset: u64, - ) -> Result> { - let Ok(offset) = u32::try_from(opaque_offset) else { - return Ok(buf); - }; - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?; - let InodeKind::Dir(dir) = Self::get_inode(&self.fs, handle.inode)?.kind() else { - return Err(Error::new(ENOTDIR)); - }; - let iter = Iter { dir, idx: offset }; - for (index, entry) in iter.enumerate() { - let entry = entry?; - buf.entry(DirEntry { - // TODO: Add getter - //inode: entry.inode(), - inode: 0, - - name: entry - .name() - .ok() - .and_then(|utf8| core::str::from_utf8(utf8).ok()) - .ok_or(Error::new(EIO))?, - next_opaque_id: index as u64 + 1, - kind: DirentKind::Unspecified, - })?; - } - Ok(buf) - } - - fn fsize(&mut self, id: usize, _ctx: &CallerCtx) -> Result { - let handle = self - .handles - .get_mut(&id) - .ok_or(Error::new(EBADF))? - .as_node_mut()?; - - Ok(inode_len(Self::get_inode(&self.fs, handle.inode)?)? as u64) - } - - fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?; - - Ok(0) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?; - - // TODO: Copy scheme part in kernel - let scheme_path = b"/scheme/initfs"; - let scheme_bytes = core::cmp::min(scheme_path.len(), buf.len()); - buf[..scheme_bytes].copy_from_slice(&scheme_path[..scheme_bytes]); - - let source = handle.filename.as_bytes(); - let path_bytes = core::cmp::min(buf.len() - scheme_bytes, source.len()); - buf[scheme_bytes..scheme_bytes + path_bytes].copy_from_slice(&source[..path_bytes]); - - Ok(scheme_bytes + path_bytes) - } - - fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?; - - let inode = Self::get_inode(&self.fs, handle.inode)?; - - stat.st_ino = inode.id(); - stat.st_mode = inode.mode() - | match inode.kind() { - InodeKind::Dir(_) => MODE_DIR, - InodeKind::File(_) => MODE_FILE, - InodeKind::Link(_) => MODE_SYMLINK, - _ => 0, - }; - stat.st_uid = 0; - stat.st_gid = 0; - stat.st_size = u64::try_from(inode_len(inode)?).unwrap_or(u64::MAX); - - stat.st_ctime = 0; - stat.st_ctime_nsec = 0; - stat.st_mtime = 0; - stat.st_mtime_nsec = 0; - - Ok(()) - } - - fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> { - if !self.handles.contains_key(&id) { - return Err(Error::new(EBADF)); - } - - Ok(()) - } - - fn mmap_prep( - &mut self, - id: usize, - offset: u64, - size: usize, - flags: MapFlags, - _ctx: &CallerCtx, - ) -> syscall::Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - let Handle::Node(node) = handle else { - return Err(Error::new(EBADF)); - }; - let data = match Self::get_inode(&self.fs, node.inode)?.kind() { - InodeKind::File(file) => file.data().map_err(|_| Error::new(EIO))?, - InodeKind::Dir(_) => return Err(Error::new(EISDIR)), - InodeKind::Link(_) => return Err(Error::new(ELOOP)), - InodeKind::Unknown => return Err(Error::new(EIO)), - }; - - if flags.contains(MapFlags::PROT_WRITE) { - return Err(Error::new(EPERM)); - } - - let Some(last_addr) = offset.checked_add(size as u64) else { - return Err(Error::new(EINVAL)); - }; - - if last_addr > data.len().next_multiple_of(PAGE_SIZE) as u64 { - return Err(Error::new(EINVAL)); - } - - Ok(data.as_ptr() as usize) - } -} - -pub fn run(bytes: &'static [u8], sync_pipe: FdGuard, socket: Socket) -> ! { - log::info!("bootstrap: starting initfs scheme"); - let mut state = SchemeState::new(); - let mut scheme = InitFsScheme::new(bytes); - - // send open-capability to bootstrap - let new_id = scheme.next_id(); - scheme.handles.insert(new_id, Handle::SchemeRoot); - let cap_fd = socket - .create_this_scheme_fd(0, new_id, 0, 0) - .expect("failed to issue initfs root fd"); - let _ = syscall::call_rw( - sync_pipe.as_raw_fd(), - &mut cap_fd.to_ne_bytes(), - CallFlags::FD, - &[], - ); - drop(sync_pipe); - - loop { - let Some(req) = socket - .next_request(SignalBehavior::Restart) - .expect("bootstrap: failed to read scheme request from kernel") - else { - break; - }; - match req.kind() { - RequestKind::Call(req) => { - let resp = req.handle_sync(&mut scheme, &mut state); - - if !socket - .write_response(resp, SignalBehavior::Restart) - .expect("bootstrap: failed to write scheme response to kernel") - { - break; - } - } - RequestKind::OnClose { id } => { - scheme.handles.remove(&id); - } - _ => (), - } - } - - unreachable!() -} - -// TODO: Restructure bootstrap so it calls into relibc, or a split-off derivative without the C -// parts, such as "redox-rt". - -#[unsafe(no_mangle)] -pub unsafe extern "C" fn redox_read_v1(fd: usize, ptr: *mut u8, len: usize) -> isize { - Error::mux(syscall::read(fd, unsafe { - core::slice::from_raw_parts_mut(ptr, len) - })) as isize -} - -#[unsafe(no_mangle)] -pub unsafe extern "C" fn redox_write_v1(fd: usize, ptr: *const u8, len: usize) -> isize { - Error::mux(syscall::write(fd, unsafe { - core::slice::from_raw_parts(ptr, len) - })) as isize -} - -#[unsafe(no_mangle)] -pub unsafe fn redox_dup_v1(fd: usize, buf: *const u8, len: usize) -> isize { - Error::mux(syscall::dup(fd, unsafe { - core::slice::from_raw_parts(buf, len) - })) as isize -} - -#[unsafe(no_mangle)] -pub extern "C" fn redox_close_v1(fd: usize) -> isize { - Error::mux(syscall::close(fd)) as isize -} - -#[unsafe(no_mangle)] -pub unsafe extern "C" fn redox_sys_call_v0( - fd: usize, - payload: *mut u8, - payload_len: usize, - flags: usize, - metadata: *const u64, - metadata_len: usize, -) -> isize { - let flags = CallFlags::from_bits_retain(flags); - - let metadata = unsafe { core::slice::from_raw_parts(metadata, metadata_len) }; - - let result = if flags.contains(CallFlags::READ) { - let payload = unsafe { core::slice::from_raw_parts_mut(payload, payload_len) }; - if flags.contains(CallFlags::WRITE) { - syscall::call_rw(fd, payload, flags, metadata) - } else { - syscall::call_ro(fd, payload, flags, metadata) - } - } else { - let payload = unsafe { core::slice::from_raw_parts(payload, payload_len) }; - syscall::call_wo(fd, payload, flags, metadata) - }; - - Error::mux(result) as isize -} diff --git a/recipes/core/base/bootstrap/src/initnsmgr.rs b/recipes/core/base/bootstrap/src/initnsmgr.rs deleted file mode 100644 index fa8b728a10..0000000000 --- a/recipes/core/base/bootstrap/src/initnsmgr.rs +++ /dev/null @@ -1,560 +0,0 @@ -use alloc::rc::Rc; -use alloc::string::{String, ToString}; -use alloc::sync::Arc; -use alloc::vec::Vec; -use core::cell::RefCell; -use core::fmt::Debug; -use core::mem; -use hashbrown::HashMap; -use libredox::protocol::{NsDup, NsPermissions}; -use log::{error, warn}; -use redox_path::RedoxPath; -use redox_path::RedoxScheme; -use redox_rt::proc::FdGuard; -use redox_scheme::{ - CallerCtx, OpenResult, RequestKind, Response, SendFdRequest, SignalBehavior, Socket, - scheme::{SchemeState, SchemeSync}, -}; -use syscall::Stat; -use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; -use syscall::{CallFlags, FobtainFdFlags, error::*, schemev2::NewFdFlags}; - -#[derive(Debug, Clone)] -struct Namespace { - schemes: HashMap>, -} - -impl Namespace { - fn fork(&self, buf: &[u8]) -> Result { - let mut schemes = HashMap::new(); - let mut cursor = 0; - while cursor < buf.len() { - let len = read_num::(&buf[cursor..])?; - cursor += mem::size_of::(); - let name = String::from_utf8(Vec::from(&buf[cursor..cursor + len])) - .map_err(|_| Error::new(EINVAL))?; - cursor += len; - if name.ends_with('*') { - let prefix = &name[..name.len() - 1]; - for (registered_name, fd) in &self.schemes { - if registered_name.starts_with(prefix) { - schemes.insert(registered_name.clone(), fd.clone()); - } - } - } else { - let Some(fd) = self.schemes.get(&name) else { - warn!("Scheme {} not found in namespace", name); - continue; - }; - schemes.insert(name, fd.clone()); - } - } - Ok(Self { schemes }) - } - fn get_scheme_fd(&self, scheme: &str) -> Option<&Arc> { - self.schemes.get(scheme) - } - fn remove_scheme(&mut self, scheme: &str) -> Option<()> { - self.schemes.remove(scheme).map(|_| ()) - } -} - -#[derive(Debug, Clone)] -struct NamespaceAccess { - namespace: Rc>, - permission: NsPermissions, -} - -impl NamespaceAccess { - fn has_permission(&self, permission: NsPermissions) -> bool { - self.permission.contains(permission) - } -} - -#[derive(Debug, Clone)] -struct SchemeRegister { - target_namespace: Rc>, - scheme_name: String, -} - -impl SchemeRegister { - fn register(&self, fd: FdGuard) -> Result<()> { - let mut ns = self.target_namespace.borrow_mut(); - if ns.schemes.contains_key(&self.scheme_name) { - return Err(Error::new(EEXIST)); - } - ns.schemes.insert(self.scheme_name.clone(), Arc::new(fd)); - Ok(()) - } -} - -#[derive(Debug, Clone)] -enum Handle { - Access(NamespaceAccess), - Register(SchemeRegister), - List(NamespaceAccess), -} - -pub struct NamespaceScheme<'sock> { - socket: &'sock Socket, - handles: HashMap, - root_namespace: Namespace, - next_id: usize, - scheme_creation_cap: FdGuard, -} - -const HIGH_PERMISSIONS: NsPermissions = NsPermissions::SCHEME_CREATE; - -impl<'sock> NamespaceScheme<'sock> { - pub fn new( - socket: &'sock Socket, - schemes: HashMap>, - scheme_creation_cap: FdGuard, - ) -> Self { - Self { - socket, - handles: HashMap::new(), - root_namespace: Namespace { schemes }, - next_id: 0, - scheme_creation_cap, - } - } - - fn add_namespace(&mut self, id: usize, schemes: Namespace, permission: NsPermissions) { - let handle = Handle::Access(NamespaceAccess { - namespace: Rc::new(RefCell::new(schemes)), - permission, - }); - self.handles.insert(id, handle); - } - - fn get_ns_access(&self, id: usize) -> Option<&NamespaceAccess> { - let handle = self.handles.get(&id); - match handle { - Some(Handle::Access(access)) => Some(access), - _ => None, - } - } - - fn open_namespace_resource( - &self, - ns_access: &NamespaceAccess, - reference: &str, - _flags: usize, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - match reference { - "scheme-creation-cap" => { - if !ns_access.has_permission(NsPermissions::SCHEME_CREATE) { - error!("Permission denied to get scheme creation capability"); - return Err(Error::new(EACCES)); - } - Ok(syscall::dup(self.scheme_creation_cap.as_raw_fd(), &[])?) - } - _ => { - error!("Unknown special reference: {}", reference); - return Err(Error::new(EINVAL)); - } - } - } - - fn open_scheme_resource( - &self, - ns: &Namespace, - scheme: &str, - reference: &str, - flags: usize, - fcntl_flags: u32, - ctx: &CallerCtx, - ) -> Result { - let Some(cap_fd) = ns.get_scheme_fd(scheme) else { - log::info!("Scheme {:?} not found in namespace", scheme); - return Err(Error::new(ENODEV)); - }; - - let scheme_fd = syscall::openat_with_filter( - cap_fd.as_raw_fd(), - reference, - flags, - fcntl_flags as usize, - ctx.uid, - ctx.gid, - )?; - - Ok(scheme_fd) - } - - fn fork_namespace(&mut self, namespace: Rc>, names: &[u8]) -> Result { - let new_id = self.next_id; - let new_namespace = namespace.borrow().fork(names).map_err(|e| { - error!("Failed to fork namespace {}: {}", new_id, e); - e - })?; - self.add_namespace( - new_id, - new_namespace, - NsPermissions::all().difference(HIGH_PERMISSIONS), - ); - self.next_id += 1; - Ok(new_id) - } - - fn shrink_permissions( - &mut self, - mut ns: NamespaceAccess, - permission: NsPermissions, - ) -> Result { - ns.permission = ns.permission.intersection(permission); - let next_id = self.next_id; - self.handles.insert(next_id, Handle::Access(ns)); - self.next_id += 1; - Ok(next_id) - } -} - -impl<'sock> SchemeSync for NamespaceScheme<'sock> { - fn openat( - &mut self, - fd: usize, - path: &str, - flags: usize, - fcntl_flags: u32, - ctx: &CallerCtx, - ) -> Result { - let ns_access = { - let handle = self.handles.get(&fd); - match handle { - Some(Handle::Access(access)) => Some(access), - _ => None, - } - } - .ok_or_else(|| { - error!("Namespace with ID {} not found", fd); - Error::new(ENOENT) - })?; - let redox_path = RedoxPath::from_absolute(path).ok_or(Error::new(EINVAL))?; - let (scheme, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?; - - let res_fd = match scheme.as_ref() { - "namespace" => self.open_namespace_resource( - ns_access, - reference.as_ref(), - flags, - fcntl_flags, - ctx, - )?, - "" => { - if !ns_access.has_permission(NsPermissions::LIST) { - error!("Permission denied to list schemes in namespace {}", fd); - return Err(Error::new(EACCES)); - } - - let new_id = self.next_id; - self.next_id += 1; - - self.handles.insert(new_id, Handle::List(ns_access.clone())); - - return Ok(OpenResult::ThisScheme { - number: new_id, - flags: NewFdFlags::empty(), - }); - } - _ => self.open_scheme_resource( - &ns_access.namespace.borrow(), - scheme.as_ref(), - reference.as_ref(), - flags, - fcntl_flags, - ctx, - )?, - }; - - Ok(OpenResult::OtherScheme { fd: res_fd }) - } - - fn dup(&mut self, id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result { - let ns_access = self.get_ns_access(id).ok_or_else(|| { - error!("Namespace with ID {} not found", id); - Error::new(ENOENT) - })?; - - let raw_kind = read_num::(buf)?; - let Some(kind) = NsDup::try_from_raw(raw_kind) else { - error!("Unknown dup kind: {}", raw_kind); - return Err(Error::new(EINVAL)); - }; - let payload = &buf[mem::size_of::()..]; - let new_id = match kind { - NsDup::ForkNs => { - let ns = ns_access.namespace.clone(); - let _ = ns_access; - self.fork_namespace(ns, payload)? - } - NsDup::ShrinkPermissions => self.shrink_permissions( - ns_access.clone(), - NsPermissions::from_bits_truncate(read_num::(payload)?), - )?, - NsDup::IssueRegister => { - let name = core::str::from_utf8(payload).map_err(|_| Error::new(EINVAL))?; - let scheme_name = RedoxScheme::new(name).ok_or_else(|| { - error!("Invalid scheme name: {}", name); - Error::new(EINVAL) - })?; - - if !ns_access.has_permission(NsPermissions::INSERT) { - error!( - "Permission denied to issue register capability for namespace {}", - id - ); - return Err(Error::new(EACCES)); - } - let new_id = self.next_id; - let register_cap = Handle::Register(SchemeRegister { - target_namespace: ns_access.namespace.clone(), - scheme_name: scheme_name.as_ref().to_string(), - }); - self.handles.insert(new_id, register_cap); - self.next_id += 1; - new_id - } - }; - - Ok(OpenResult::ThisScheme { - number: new_id, - flags: NewFdFlags::empty(), - }) - } - - fn unlinkat(&mut self, fd: usize, path: &str, flags: usize, ctx: &CallerCtx) -> Result<()> { - let ns_access = self.get_ns_access(fd).ok_or_else(|| { - error!("Namespace with ID {} not found", fd); - Error::new(ENOENT) - })?; - let mut ns = ns_access.namespace.borrow_mut(); - - let redox_path = RedoxPath::from_absolute(path).ok_or(Error::new(EINVAL))?; - let (scheme, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?; - if reference.as_ref().is_empty() { - if !ns_access.has_permission(NsPermissions::DELETE) { - error!("Permission denied to remove scheme for namespace {}", fd); - return Err(Error::new(EACCES)); - } - match ns.remove_scheme(scheme.as_ref()) { - Some(_) => return Ok(()), - None => { - error!("Scheme {} not found in namespace", scheme); - return Err(Error::new(ENODEV)); - } - } - } - let Some(cap_fd) = ns.get_scheme_fd(scheme.as_ref()) else { - error!("Scheme {} not found in namespace", scheme); - return Err(Error::new(ENODEV)); - }; - - syscall::unlinkat_with_filter(cap_fd.as_raw_fd(), reference, flags, ctx.uid, ctx.gid)?; - - Ok(()) - } - - fn on_close(&mut self, id: usize) { - self.handles.remove(&id); - } - - fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result { - let namespace_id = sendfd_request.id(); - let num_fds = sendfd_request.num_fds(); - - let handle = self.handles.get(&namespace_id).ok_or_else(|| { - error!("Namespace with ID {} not found", namespace_id); - Error::new(ENOENT) - })?; - let Handle::Register(register_cap) = handle else { - error!( - "Handle with ID {} is not a register capability", - namespace_id - ); - return Err(Error::new(EACCES)); - }; - - if num_fds == 0 { - return Ok(0); - } - if num_fds > 1 { - error!("Can only send one fd at a time"); - return Err(Error::new(EINVAL)); - } - let mut new_fd = usize::MAX; - if let Err(e) = sendfd_request.obtain_fd( - &self.socket, - FobtainFdFlags::UPPER_TBL, - core::slice::from_mut(&mut new_fd), - ) { - error!("on_sendfd: obtain_fd failed with error: {:?}", e); - return Err(e); - } - register_cap.register(FdGuard::new(new_fd))?; - - Ok(num_fds) - } - - fn getdents<'buf>( - &mut self, - id: usize, - mut buf: DirentBuf<&'buf mut [u8]>, - opaque_offset: u64, - ) -> Result> { - let Handle::List(ns_access) = self.handles.get(&id).ok_or(Error::new(EBADF))? else { - return Err(Error::new(ENOTDIR)); - }; - - if !ns_access.has_permission(NsPermissions::LIST) { - return Err(Error::new(EACCES)); - } - - let ns = ns_access.namespace.borrow(); - - let opaque_offset = opaque_offset as usize; - for (i, (name, _)) in ns.schemes.iter().enumerate().skip(opaque_offset) { - if name.is_empty() { - continue; - } - if let Err(err) = buf.entry(DirEntry { - kind: DirentKind::Unspecified, - name: &name.clone(), - inode: 0, - next_opaque_id: i as u64 + 1, - }) { - if err.errno == EINVAL && i > opaque_offset { - // POSIX allows partial result of getdents - break; - } else { - return Err(err); - } - } - } - - Ok(buf) - } - - fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { - let resource_stat = match self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => Stat { - st_mode: 0o444 | syscall::MODE_DIR, - st_uid: 0, - st_gid: 0, - st_size: 0, - ..Default::default() - }, - Handle::Access(_) | Handle::Register(_) => Stat { - st_mode: 0o666 | syscall::MODE_FILE, - st_uid: 0, - st_gid: 0, - st_size: 0, - ..Default::default() - }, - }; - *stat = resource_stat; - Ok(()) - } -} - -trait NumFromBytes: Sized + Debug { - fn from_le_bytes_slice(buffer: &[u8]) -> Result; -} - -macro_rules! num_from_bytes_impl { - ($($t:ty),*) => { - $( - impl NumFromBytes for $t { - fn from_le_bytes_slice(buffer: &[u8]) -> Result { - let size = mem::size_of::(); - let buffer_slice = buffer.get(..size).and_then(|s| s.try_into().ok()); - - if let Some(slice) = buffer_slice { - Ok(Self::from_le_bytes(slice)) - } else { - error!( - "read_num: buffer is too short to read num of size {} (buffer len: {})", - size, buffer.len() - ); - Err(Error::new(EINVAL)) - } - } - } - )* - }; -} - -num_from_bytes_impl!(usize); - -fn read_num(buffer: &[u8]) -> Result -where - T: NumFromBytes, -{ - T::from_le_bytes_slice(buffer) -} - -pub fn run( - sync_pipe: FdGuard, - socket: Socket, - schemes: HashMap>, - scheme_creation_cap: FdGuard, -) -> ! { - let mut state = SchemeState::new(); - let mut scheme = NamespaceScheme::new(&socket, schemes, scheme_creation_cap); - - // send namespace fd to bootstrap - let new_id = scheme.next_id; - scheme.add_namespace(new_id, scheme.root_namespace.clone(), NsPermissions::all()); - scheme.next_id += 1; - let cap_fd = scheme - .socket - .create_this_scheme_fd(0, new_id, 0, 0) - .expect("nsmgr: failed to create namespace fd"); - let _ = syscall::call_wo( - sync_pipe.as_raw_fd(), - &cap_fd.to_ne_bytes(), - CallFlags::FD, - &[], - ); - drop(sync_pipe); - - log::info!("bootstrap: namespace scheme start!"); - loop { - let Some(req) = socket - .next_request(SignalBehavior::Restart) - .expect("bootstrap: failed to read scheme request from kernel") - else { - break; - }; - match req.kind() { - RequestKind::Call(req) => { - let resp = req.handle_sync(&mut scheme, &mut state); - - if !socket - .write_response(resp, SignalBehavior::Restart) - .expect("bootstrap: failed to write scheme response to kernel") - { - break; - } - } - RequestKind::OnClose { id } => scheme.on_close(id), - RequestKind::SendFd(sendfd_request) => { - let result = scheme.on_sendfd(&sendfd_request); - let resp = Response::new(result, sendfd_request); - if !socket - .write_response(resp, SignalBehavior::Restart) - .expect("bootstrap: failed to write scheme response to kernel") - { - break; - } - } - - _ => (), - } - } - - unreachable!() -} diff --git a/recipes/core/base/bootstrap/src/main.rs b/recipes/core/base/bootstrap/src/main.rs deleted file mode 100644 index f7dcd537cc..0000000000 --- a/recipes/core/base/bootstrap/src/main.rs +++ /dev/null @@ -1,154 +0,0 @@ -#![no_std] -#![no_main] -#![allow(internal_features)] -#![feature(core_intrinsics, str_from_raw_parts, never_type)] - -#[cfg(target_arch = "aarch64")] -#[path = "aarch64.rs"] -pub mod arch; - -#[cfg(target_arch = "x86")] -#[path = "i686.rs"] -pub mod arch; - -#[cfg(target_arch = "x86_64")] -#[path = "x86_64.rs"] -pub mod arch; - -#[cfg(target_arch = "riscv64")] -#[path = "riscv64.rs"] -pub mod arch; - -pub mod exec; -pub mod initfs; -pub mod initnsmgr; -pub mod procmgr; -pub mod start; - -extern crate alloc; - -use core::cell::UnsafeCell; - -use alloc::collections::btree_map::BTreeMap; -use redox_rt::proc::FdGuard; -use syscall::data::Map; -use syscall::data::{GlobalSchemes, KernelSchemeInfo}; -use syscall::flag::MapFlags; - -#[panic_handler] -fn panic_handler(info: &core::panic::PanicInfo) -> ! { - use core::fmt::Write; - - struct Writer; - - impl Write for Writer { - fn write_str(&mut self, s: &str) -> core::fmt::Result { - syscall::write(1, s.as_bytes()) - .map_err(|_| core::fmt::Error) - .map(|_| ()) - } - } - - let _ = writeln!(&mut Writer, "{}", info); - core::intrinsics::abort(); -} - -const HEAP_OFF: usize = arch::USERMODE_END / 2; - -struct Allocator; -#[global_allocator] -static ALLOCATOR: Allocator = Allocator; - -struct AllocStateInner { - heap: Option, - heap_top: usize, -} -struct AllocState(UnsafeCell); -unsafe impl Send for AllocState {} -unsafe impl Sync for AllocState {} -static ALLOC_STATE: AllocState = AllocState(UnsafeCell::new(AllocStateInner { - heap: None, - heap_top: HEAP_OFF + SIZE, -})); - -const SIZE: usize = 1024 * 1024; -const HEAP_INCREASE_BY: usize = SIZE; - -unsafe impl alloc::alloc::GlobalAlloc for Allocator { - unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { - let state = unsafe { &mut (*ALLOC_STATE.0.get()) }; - let heap = state.heap.get_or_insert_with(|| { - state.heap_top = HEAP_OFF + SIZE; - let _ = unsafe { - syscall::fmap( - !0, - &Map { - offset: 0, - size: SIZE, - address: HEAP_OFF, - flags: MapFlags::PROT_WRITE - | MapFlags::PROT_READ - | MapFlags::MAP_PRIVATE - | MapFlags::MAP_FIXED_NOREPLACE, - }, - ) - } - .expect("failed to map initial heap"); - unsafe { linked_list_allocator::Heap::new(HEAP_OFF as *mut u8, SIZE) } - }); - - match heap.allocate_first_fit(layout) { - Ok(p) => p.as_ptr(), - Err(_) => { - if layout.size() > HEAP_INCREASE_BY || layout.align() > 4096 { - return core::ptr::null_mut(); - } - - let _ = unsafe { - syscall::fmap( - !0, - &Map { - offset: 0, - size: HEAP_INCREASE_BY, - address: state.heap_top, - flags: MapFlags::PROT_WRITE - | MapFlags::PROT_READ - | MapFlags::MAP_PRIVATE - | MapFlags::MAP_FIXED_NOREPLACE, - }, - ) - } - .expect("failed to extend heap"); - unsafe { heap.extend(HEAP_INCREASE_BY) }; - state.heap_top += HEAP_INCREASE_BY; - - return unsafe { self.alloc(layout) }; - } - } - } - unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { - unsafe { - (&mut *ALLOC_STATE.0.get()) - .heap - .as_mut() - .unwrap() - .deallocate(core::ptr::NonNull::new(ptr).unwrap(), layout) - } - } -} - -pub struct KernelSchemeMap(BTreeMap); -impl KernelSchemeMap { - fn new(kernel_scheme_infos: &[KernelSchemeInfo]) -> Self { - let mut map = BTreeMap::new(); - for info in kernel_scheme_infos { - if let Some(scheme_id) = GlobalSchemes::try_from_raw(info.scheme_id) { - map.insert(scheme_id, FdGuard::new(info.fd)); - } - } - Self(map) - } - fn get(&self, scheme: GlobalSchemes) -> Option<&FdGuard> { - self.0.get(&scheme) - } -} diff --git a/recipes/core/base/bootstrap/src/procmgr.rs b/recipes/core/base/bootstrap/src/procmgr.rs deleted file mode 100644 index b1268e0362..0000000000 --- a/recipes/core/base/bootstrap/src/procmgr.rs +++ /dev/null @@ -1,2640 +0,0 @@ -use core::cell::RefCell; -use core::cmp; -use core::mem::size_of; -use core::num::{NonZeroU8, NonZeroUsize}; -use core::ops::Deref; -use core::ptr::NonNull; -use core::str::FromStr; -use core::sync::atomic::Ordering; -use core::task::Poll::{self, *}; - -use alloc::collections::VecDeque; -use alloc::collections::btree_map::BTreeMap; -use alloc::rc::{Rc, Weak}; -use alloc::vec; -use alloc::vec::Vec; - -use arrayvec::ArrayString; -use hashbrown::hash_map::{Entry, OccupiedEntry, VacantEntry}; -use hashbrown::{DefaultHashBuilder, HashMap, HashSet}; - -use libredox::protocol::{ - ProcCall, ProcKillTarget, ProcMeta, RtSigInfo, SIGCHLD, SIGCONT, SIGHUP, SIGKILL, SIGSTOP, - SIGTSTP, SIGTTIN, SIGTTOU, ThreadCall, WaitFlags, -}; -use redox_rt::proc::FdGuard; -use redox_scheme::scheme::{IntoTag, Op, OpCall}; -use redox_scheme::{ - CallerCtx, Id, OpenResult, Request, RequestKind, Response, SendFdRequest, SignalBehavior, - Socket, Tag, -}; -use slab::Slab; -use syscall::schemev2::NewFdFlags; -use syscall::{ - CallFlags, ContextStatus, ContextVerb, CtxtStsBuf, EACCES, EAGAIN, EBADF, EBADFD, ECANCELED, - ECHILD, EEXIST, EINTR, EINVAL, ENOENT, ENOSYS, EOPNOTSUPP, EOWNERDEAD, EPERM, ERESTART, ESRCH, - EWOULDBLOCK, Error, Event, EventFlags, FobtainFdFlags, MapFlags, O_ACCMODE, O_CREAT, O_RDONLY, - PAGE_SIZE, ProcSchemeAttrs, Result, SenderInfo, SetSighandlerData, SigProcControl, Sigcontrol, - sig_bit, -}; - -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -enum VirtualId { - KernelId(Id), - // TODO: slab or something for better ID reuse - InternalId(u64), -} - -pub fn run(write_fd: FdGuard, socket: Socket, auth: FdGuard, event: FdGuard) -> ! { - // TODO? - let socket_ident = socket.inner().raw(); - - let queue = RawEventQueue::new(event.as_raw_fd()).expect("failed to create event queue"); - drop(event); - - queue - .subscribe(socket.inner().raw(), socket_ident, EventFlags::EVENT_READ) - .expect("failed to listen to scheme socket events"); - - let mut scheme = ProcScheme::new(auth, &queue); - - // send open-capability to bootstrap - let new_id = scheme.handles.insert(Handle::SchemeRoot); - let cap_fd = socket - .create_this_scheme_fd(0, new_id, 0, 0) - .expect("failed to issue procmgr root fd"); - - log::debug!("process manager started"); - let _ = syscall::call_wo( - write_fd.as_raw_fd(), - &cap_fd.to_ne_bytes(), - CallFlags::FD, - &[], - ); - drop(write_fd); - - let mut states = HashMap::::new(); - let mut awoken = VecDeque::::new(); - let mut new_awoken = VecDeque::new(); - - 'outer: loop { - log::trace!("AWOKEN {awoken:#?}"); - while !awoken.is_empty() || !new_awoken.is_empty() { - awoken.append(&mut new_awoken); - for awoken in awoken.drain(..) { - //log::trace!("ALL STATES {states:#?}, AWOKEN {awoken:#?}"); - let Entry::Occupied(state) = states.entry(awoken) else { - continue; - }; - match scheme.work_on(state, &mut new_awoken) { - Ready(resp) => loop { - match socket.write_response(resp, SignalBehavior::Interrupt) { - Ok(false) => break 'outer, - Ok(_) => break, - Err(err) if err.errno == EINTR => continue, - Err(err) => { - panic!( - "bootstrap: failed to write scheme response to kernel: {err}" - ) - } - } - }, - Pending => continue, - } - } - } - // TODO: multiple events? - let event = queue.next_event().expect("failed to get next event"); - - if event.data == socket_ident { - 'reqs: loop { - let req = loop { - match socket.next_request(SignalBehavior::Interrupt) { - Ok(None) => break 'outer, - Ok(Some(req)) => break req, - Err(e) if e.errno == EINTR => continue, - // spurious event - Err(e) if e.errno == EWOULDBLOCK || e.errno == EAGAIN => break 'reqs, - Err(other) => { - panic!("bootstrap: failed to read scheme request from kernel: {other}") - } - } - }; - log::trace!("REQ{req:#?}"); - let Ready(resp) = - handle_scheme(req, &socket, &mut scheme, &mut states, &mut awoken) - else { - continue 'reqs; - }; - loop { - match socket.write_response(resp, SignalBehavior::Interrupt) { - Ok(false) => break 'outer, - Ok(_) => break, - Err(err) if err.errno == EINTR => continue, - Err(err) => { - panic!("bootstrap: failed to write scheme response to kernel: {err}") - } - } - } - } - } else if let Some(thread) = scheme.thread_lookup.get(&event.data) { - let Some(thread_rc) = thread.upgrade() else { - log::trace!("DEAD THREAD EVENT FROM {}", event.data,); - continue; - }; - let thread = thread_rc.borrow(); - let pid = thread.pid; - let Some(proc_rc) = scheme.processes.get(&pid) else { - // TODO(err)? - continue; - }; - let mut proc = proc_rc.borrow_mut(); - log::trace!("THREAD EVENT FROM {}, {}", event.data, thread.pid.0); - let mut sts_buf = CtxtStsBuf::default(); - thread.status_hndl.read(&mut sts_buf).unwrap(); - - let status = if sts_buf.status == ContextStatus::Dead as usize { - // dont-care, already called explicit exit() - 0 - } else if sts_buf.status == ContextStatus::ForceKilled as usize { - (SIGKILL << 8) as u16 - } else if sts_buf.status == ContextStatus::UnhandledExcp as usize { - // TODO: translate arch-specific exception kind - // TODO: generate coredump (or let some other process do that) - // into signal (SIGSEGV, SIGBUS, SIGILL, SIGFPE) - 1 - } else { - // spurious event - continue; - }; - - log::trace!("--THREAD DIED {}, {}", event.data, thread.pid.0); - - if let Err(err) = scheme.queue.unsubscribe(event.data, event.data) { - log::error!("failed to unsubscribe from fd {}: {err}", event.data); - } - scheme.thread_lookup.remove(&event.data); - proc.threads.retain(|rc| !Rc::ptr_eq(rc, &thread_rc)); - - if matches!(proc.status, ProcessStatus::Exiting { .. }) { - log::trace!("WAKING UP {}", proc.awaiting_threads_term.len(),); - awoken.extend(proc.awaiting_threads_term.drain(..)); // TODO(opt) - } else if proc.threads.is_empty() { - let internal_id = scheme.next_internal_id; - scheme.next_internal_id += 1; - let Entry::Vacant(entry) = states.entry(VirtualId::InternalId(internal_id)) else { - log::error!("internal ID reuse!"); - continue; - }; - drop(thread); - drop(proc); - let Pending = scheme.on_exit_start(pid, status, entry, &mut awoken, None) else { - unreachable!("not possible with tag=None"); - }; - } - } else { - log::warn!("TODO: UNKNOWN EVENT {event:?}"); - } - } - - unreachable!() -} -fn handle_scheme<'a>( - req: Request, - socket: &'a Socket, - scheme: &mut ProcScheme<'a>, - states: &mut HashMap, - awoken: &mut VecDeque, -) -> Poll { - match req.kind() { - RequestKind::Call(req) => { - let caller = req.caller(); - let req_id = VirtualId::KernelId(req.request_id()); - let op = match req.op() { - Ok(op) => op, - Err(req) => return Response::ready_err(ENOSYS, req), - }; - match op { - Op::OpenAt(op) => Ready(Response::open_dup_like( - scheme.on_openat(op.fd, op.path(), *op.flags(), op.fcntl_flags, &caller), - op, - )), - Op::Dup(op) => Ready(Response::open_dup_like(scheme.on_dup(op.fd, op.buf()), op)), - Op::Read(mut op) => Ready(Response::new( - scheme.on_read(op.fd, op.offset, op.buf()), - op, - )), - Op::Call(op) => scheme.on_call( - { - // TODO: cleanup - states.remove(&req_id); - if let Entry::Vacant(entry) = states.entry(req_id) { - entry - } else { - unreachable!() - } - }, - op, - awoken, - ), - Op::Fpath(mut op) => { - //TODO: fill in useful path? - let buf = op.buf(); - let scheme_path = b"/scheme/proc/"; - let scheme_bytes = core::cmp::min(scheme_path.len(), buf.len()); - buf[..scheme_bytes].copy_from_slice(&scheme_path[..scheme_bytes]); - Response::ready_ok(scheme_bytes, op) - } - Op::Fsize { req, fd } => { - if let Handle::Ps(b) = &scheme.handles[fd] { - Response::ready_ok(b.len(), req) - } else { - Response::ready_err(EOPNOTSUPP, req) - } - } - Op::Fstat(mut op) => { - if let Handle::Ps(b) = &scheme.handles[op.fd] { - op.buf().st_size = b.len() as _; - op.buf().st_mode = syscall::MODE_FILE | 0o444; - Response::ready_ok(0, op) - } else { - Response::ready_err(EOPNOTSUPP, op) - } - } - _ => { - log::trace!("UNKNOWN: {op:?}"); - Response::ready_err(ENOSYS, op) - } - } - } - RequestKind::Cancellation(req) => { - if let Entry::Occupied(state) = states.entry(VirtualId::KernelId(req.id)) { - match state.remove() { - PendingState::AwaitingStatusChange { op, .. } => { - Response::ready_err(ECANCELED, op) - } - // TODO: Test this by calling exit() on behalf of another process using the IPC - // call Exit, then cancel. Keep in mind this won't cancel the underlying exit, just - // detach the waiter from it. - PendingState::AwaitingThreadsTermination(pid, tag) => { - let resp = if let Some(tag) = tag { - Ready(Response::err(ECANCELED, tag)) - } else { - Pending - }; - - let vid = VirtualId::InternalId(scheme.next_internal_id); - scheme.next_internal_id += 1; - states.insert(vid, PendingState::AwaitingThreadsTermination(pid, None)); - awoken.push_back(vid); - - resp - } - PendingState::Placeholder => { - log::warn!("State {:?} was placeholder!", req.id); - Pending - } - } - } else { - log::warn!("Cancellation for unknown id {:?}", req.id); - Pending - } - } - RequestKind::OnClose { id } => { - scheme.on_close(id); - // no response associated - Pending - } - RequestKind::SendFd(req) => Ready(scheme.on_sendfd(socket, req)), - - // ignore - _ => Pending, - } -} -#[derive(Debug)] -enum PendingState { - AwaitingStatusChange { - waiter: ProcessId, - target: WaitpidTarget, - flags: WaitFlags, - op: OpCall, - }, - AwaitingThreadsTermination(ProcessId, Option), - Placeholder, -} -/*impl IntoTag for PendingState { - fn into_tag(self) -> Tag { - match self { - Self::AwaitingThreadsTermination(_, tag) => tag, - Self::AwaitingStatusChange { op, .. } => op.into_tag(), - Self::Placeholder => unreachable!(), - } - } -}*/ - -#[derive(Debug)] -pub struct Page { - ptr: NonNull, - off: u16, -} -impl Page { - pub fn map(fd: &FdGuard, req_offset: usize, displacement: u16) -> Result { - Ok(Self { - off: displacement, - ptr: NonNull::new(unsafe { - syscall::fmap( - fd.as_raw_fd(), - &syscall::Map { - offset: req_offset, - size: PAGE_SIZE, - flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_SHARED, - address: 0, - }, - )? as *mut T - }) - .unwrap(), - }) - } -} -impl Deref for Page { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.ptr.as_ptr().byte_add(self.off.into()) } - } -} -impl Drop for Page { - fn drop(&mut self) { - unsafe { - let _ = syscall::funmap(self.ptr.as_ptr() as usize, PAGE_SIZE); - } - } -} - -const NAME_CAPAC: usize = 32; - -#[derive(Debug)] -struct Process { - threads: Vec>>, - pid: ProcessId, - ppid: ProcessId, - pgid: ProcessId, - sid: ProcessId, - name: ArrayString, - prio: u32, - - ruid: u32, - euid: u32, - suid: u32, - rgid: u32, - egid: u32, - sgid: u32, - - status: ProcessStatus, - disabled_setpgid: bool, - - awaiting_threads_term: Vec, - - waitpid: BTreeMap, - waitpid_waiting: VecDeque, - - sig_pctl: Option>, - rtqs: Vec>, -} -#[derive(Copy, Clone, Debug)] -struct WaitpidKey { - pid: Option, - pgid: Option, -} - -// TODO: Is this valid? (transitive?) -impl Ord for WaitpidKey { - fn cmp(&self, other: &WaitpidKey) -> cmp::Ordering { - // If both have pid set, compare that - if let Some(s_pid) = self.pid { - if let Some(o_pid) = other.pid { - return s_pid.cmp(&o_pid); - } - } - - // If both have pgid set, compare that - if let Some(s_pgid) = self.pgid { - if let Some(o_pgid) = other.pgid { - return s_pgid.cmp(&o_pgid); - } - } - - // If either has pid set, it is greater - if self.pid.is_some() { - return cmp::Ordering::Greater; - } - - if other.pid.is_some() { - return cmp::Ordering::Less; - } - - // If either has pgid set, it is greater - if self.pgid.is_some() { - return cmp::Ordering::Greater; - } - - if other.pgid.is_some() { - return cmp::Ordering::Less; - } - - // If all pid and pgid are None, they are equal - cmp::Ordering::Equal - } -} - -impl PartialOrd for WaitpidKey { - fn partial_cmp(&self, other: &WaitpidKey) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for WaitpidKey { - fn eq(&self, other: &WaitpidKey) -> bool { - self.cmp(other) == cmp::Ordering::Equal - } -} - -impl Eq for WaitpidKey {} -#[derive(Debug, Clone, Copy)] -enum ProcessStatus { - PossiblyRunnable, - Stopped(usize), - Exiting { - signal: Option, - status: u8, - }, - Exited { - signal: Option, - status: u8, - }, -} -#[derive(Debug)] -struct Thread { - fd: FdGuard, - status_hndl: FdGuard, - pid: ProcessId, - sig_ctrl: Option>, -} -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -struct ProcessId(usize); - -const INIT_PID: ProcessId = ProcessId(1); - -struct ProcScheme<'a> { - processes: HashMap>, DefaultHashBuilder>, - groups: HashMap>>, - sessions: HashSet, - handles: Slab, - - thread_lookup: HashMap>>, - - next_internal_id: u64, - - init_claimed: bool, - next_id: ProcessId, - - queue: &'a RawEventQueue, - auth: FdGuard, -} -#[derive(Debug, Default)] -struct Pgrp { - processes: Vec>>, -} -#[derive(Clone, Copy, Debug)] -enum WaitpidStatus { - Continued, - Stopped { - signal: NonZeroU8, - }, - Terminated { - signal: Option, - status: u8, - }, -} - -#[derive(Debug)] -enum Handle { - Init, - Proc(ProcessId), - - // Needs to be weak so the thread is owned only by the process. Otherwise there would be a - // cyclic reference since the underlying context's file table almost certainly contains the - // thread fd itself, linked to this handle. - Thread(Weak>), - - // TODO: stateless API, perhaps using intermediate daemon for providing a file-like API - Ps(Vec), - - // A handle that grants the holder the capability to obtain process credentials. - ProcCredsCapability, - - // A handle that grants the holder the capability to open process scheme resource. - SchemeRoot, -} - -#[derive(Clone, Copy, Debug)] -enum WaitpidTarget { - SingleProc(ProcessId), - ProcGroup(ProcessId), - AnyChild, - AnyGroupMember, -} -// TODO(feat): Add 'syscall' backend for redox-event so it can act both as library-ABI frontend and -// backend -struct RawEventQueue(FdGuard); -impl RawEventQueue { - pub fn new(cap_fd: usize) -> Result { - syscall::openat(cap_fd, "", O_CREAT, 0) - .map(FdGuard::new) - .map(Self) - } - pub fn subscribe(&self, fd: usize, ident: usize, flags: EventFlags) -> Result<()> { - self.0.write(&Event { - id: fd, - data: ident, - flags, - })?; - Ok(()) - } - pub fn unsubscribe(&self, fd: usize, ident: usize) -> Result<()> { - self.subscribe(fd, ident, EventFlags::empty()) - } - pub fn next_event(&self) -> Result { - let mut event = Event::default(); - let read = self.0.read(&mut event)?; - assert_eq!( - read, - size_of::(), - "event queue EOF currently undefined" - ); - Ok(event) - } -} - -impl<'a> ProcScheme<'a> { - pub fn new(auth: FdGuard, queue: &'a RawEventQueue) -> ProcScheme<'a> { - ProcScheme { - processes: HashMap::new(), - groups: HashMap::new(), - sessions: HashSet::new(), - thread_lookup: HashMap::new(), - handles: Slab::new(), - init_claimed: false, - next_id: ProcessId(2), - next_internal_id: 1, - queue, - auth, - } - } - fn new_id(&mut self) -> ProcessId { - let id = self.next_id; - self.next_id.0 += 1; - id - } - fn on_sendfd(&mut self, socket: &Socket, req: SendFdRequest) -> Response { - match self.handles[req.id()] { - ref mut st @ Handle::Init => { - let mut fd_out = usize::MAX; - if let Err(e) = req.obtain_fd( - socket, - FobtainFdFlags::empty(), - core::slice::from_mut(&mut fd_out), - ) { - return Response::new(Err(e), req); - }; - let fd = FdGuard::new(fd_out); - - // TODO: Use global thread id etc. rather than reusing fd for identifier? - self.queue - .subscribe(fd_out, fd_out, EventFlags::EVENT_READ) - .expect("TODO"); - let status_hndl = fd - .dup(alloc::format!("auth-{}-status", self.auth.as_raw_fd()).as_bytes()) - .expect("TODO"); - - let thread = Rc::new(RefCell::new(Thread { - fd, - status_hndl, - pid: INIT_PID, - sig_ctrl: None, - })); - let thread_weak = Rc::downgrade(&thread); - let process = Rc::new(RefCell::new(Process { - threads: vec![thread], - pid: INIT_PID, - ppid: INIT_PID, - sid: INIT_PID, - pgid: INIT_PID, - ruid: 0, - euid: 0, - suid: 0, - rgid: 0, - egid: 0, - sgid: 0, - name: ArrayString::<32>::from_str("[init]").unwrap(), - prio: 20, - - status: ProcessStatus::PossiblyRunnable, - disabled_setpgid: false, - awaiting_threads_term: Vec::new(), - waitpid: BTreeMap::new(), - waitpid_waiting: VecDeque::new(), - - sig_pctl: None, - rtqs: Vec::new(), - })); - self.groups.insert( - INIT_PID, - Rc::new(RefCell::new(Pgrp { - processes: vec![Rc::downgrade(&process)], - })), - ); - self.processes.insert(INIT_PID, process); - self.sessions.insert(INIT_PID); - - self.thread_lookup.insert(fd_out, thread_weak); - - *st = Handle::Proc(INIT_PID); - Response::ok(0, req) - } - _ => Response::err(EBADF, req), - } - } - fn fork(&mut self, parent_pid: ProcessId) -> Result { - let child_pid = self.new_id(); - - let proc_guard = self.processes.get(&parent_pid).ok_or(Error::new(EBADFD))?; - - let Process { - pgid, - sid, - ruid, - euid, - suid, - rgid, - egid, - sgid, - name, - prio, - .. - } = *proc_guard.borrow(); - - let new_ctxt_fd = self.auth.dup(b"new-context")?; - let status_fd = - new_ctxt_fd.dup(alloc::format!("auth-{}-status", self.auth.as_raw_fd()).as_bytes())?; - - let thread_ident = new_ctxt_fd.as_raw_fd(); - self.queue - .subscribe(thread_ident, thread_ident, EventFlags::EVENT_READ) - .expect("TODO"); - - let thread = Rc::new(RefCell::new(Thread { - fd: new_ctxt_fd, - status_hndl: status_fd, - pid: child_pid, - sig_ctrl: None, // TODO - })); - let thread_weak = Rc::downgrade(&thread); - let new_process = Rc::new(RefCell::new(Process { - threads: vec![thread], - ppid: parent_pid, - pid: child_pid, - pgid, - sid, - ruid, - euid, - suid, - rgid, - egid, - sgid, - name, - prio, - - status: ProcessStatus::PossiblyRunnable, - disabled_setpgid: false, - awaiting_threads_term: Vec::new(), - - waitpid: BTreeMap::new(), - waitpid_waiting: VecDeque::new(), - - sig_pctl: None, // TODO - rtqs: Vec::new(), - })); - if let Err(err) = new_process - .borrow_mut() - .sync_kernel_attrs(&self.auth) - { - log::warn!("Failed to set kernel attrs when forking: {err}"); - } - - if let Some(group) = self.groups.get(&pgid) { - group - .borrow_mut() - .processes - .push(Rc::downgrade(&new_process)); - } - - self.processes.insert(child_pid, new_process); - self.thread_lookup.insert(thread_ident, thread_weak); - Ok(child_pid) - } - fn new_thread(&mut self, pid: ProcessId) -> Result>> { - // TODO: deduplicate code with fork - let proc_rc = self.processes.get_mut(&pid).ok_or(Error::new(EBADFD))?; - let mut proc = proc_rc.borrow_mut(); - - let ctxt_fd = self.auth.dup(b"new-context")?; - - // TODO: sync_kernel_attrs? - let attr_fd = - ctxt_fd.dup(alloc::format!("auth-{}-attrs", self.auth.as_raw_fd()).as_bytes())?; - attr_fd.write(&ProcSchemeAttrs { - pid: pid.0 as u32, - euid: proc.euid, - egid: proc.egid, - prio: proc.prio, - debug_name: arraystring_to_bytes(proc.name), - })?; - - let status_hndl = - ctxt_fd.dup(alloc::format!("auth-{}-status", self.auth.as_raw_fd()).as_bytes())?; - - let ident = ctxt_fd.as_raw_fd(); - self.queue - .subscribe(ident, ident, EventFlags::EVENT_READ) - .expect("TODO"); - - let thread = Rc::new(RefCell::new(Thread { - fd: ctxt_fd, - status_hndl, - pid, - sig_ctrl: None, - })); - let thread_weak = Rc::downgrade(&thread); - proc.threads.push(Rc::clone(&thread)); - self.thread_lookup.insert(ident, thread_weak); - Ok(thread) - } - fn on_openat( - &mut self, - fd: usize, - path: &str, - flags: usize, - _fcntl_flags: u32, - ctx: &CallerCtx, - ) -> Result { - match self.handles[fd] { - Handle::SchemeRoot => {} - _ => return Err(Error::new(EACCES)), - }; - let path = path.trim_start_matches('/'); - Ok(match path { - "init" => { - if core::mem::replace(&mut self.init_claimed, true) { - return Err(Error::new(EEXIST)); - } - OpenResult::ThisScheme { - number: self.handles.insert(Handle::Init), - flags: NewFdFlags::empty(), - } - } - "ps" => { - let data = self.ps_data(ctx)?; - OpenResult::ThisScheme { - number: self.handles.insert(Handle::Ps(data)), - flags: NewFdFlags::POSITIONED, - } - } - "proc-creds-capability" => { - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - if flags & O_ACCMODE != O_RDONLY { - return Err(Error::new(EINVAL)); - } - OpenResult::ThisScheme { - number: self.handles.insert(Handle::ProcCredsCapability), - flags: NewFdFlags::empty(), - } - } - - _ => return Err(Error::new(ENOENT)), - }) - } - fn read_process_metadata(&self, pid: ProcessId, buf: &mut [u8]) -> Result { - let proc_rc = self.processes.get(&pid).ok_or(Error::new(ESRCH))?; - let process = proc_rc.borrow(); - let metadata = ProcMeta { - pid: pid.0 as u32, - pgid: process.pgid.0 as u32, - ppid: process.ppid.0 as u32, - ruid: process.ruid, - euid: process.euid, - suid: process.suid, - rgid: process.rgid, - egid: process.egid, - sgid: process.sgid, - ens: 1, - rns: 1, - }; - *buf.get_mut(..size_of::()) - .and_then(|b| plain::from_mut_bytes(b).ok()) - .ok_or(Error::new(EBADF))? = metadata; - Ok(size_of::()) - } - fn on_read(&mut self, id: usize, offset: u64, buf: &mut [u8]) -> Result { - match self.handles[id] { - Handle::Proc(pid) => self.read_process_metadata(pid, buf), - Handle::Ps(ref src_buf) => { - let src_buf = usize::try_from(offset) - .ok() - .and_then(|o| src_buf.get(o..)) - .unwrap_or(&[]); - let len = src_buf.len().min(buf.len()); - buf[..len].copy_from_slice(&src_buf[..len]); - Ok(len) - } - Handle::Init | Handle::Thread(_) | Handle::ProcCredsCapability | Handle::SchemeRoot => { - return Err(Error::new(EBADF)); - } - } - } - fn on_dup(&mut self, old_id: usize, buf: &[u8]) -> Result { - log::trace!("Dup request"); - match self.handles[old_id] { - Handle::Proc(pid) => match buf { - b"fork" => { - log::trace!("Forking {pid:?}"); - let child_pid = self.fork(pid)?; - Ok(OpenResult::ThisScheme { - number: self.handles.insert(Handle::Proc(child_pid)), - flags: NewFdFlags::empty(), - }) - } - b"new-thread" => { - let thread = self.new_thread(pid)?; - Ok(OpenResult::ThisScheme { - number: self.handles.insert(Handle::Thread(Rc::downgrade(&thread))), - flags: NewFdFlags::empty(), - }) - } - w if w.starts_with(b"thread-") => { - let idx = core::str::from_utf8(&w["thread-".len()..]) - .ok() - .and_then(|s| s.parse::().ok()) - .ok_or(Error::new(EINVAL))?; - let process = self.processes.get(&pid).ok_or(Error::new(EBADFD))?.borrow(); - let thread = Rc::downgrade(process.threads.get(idx).ok_or(Error::new(ENOENT))?); - - return Ok(OpenResult::ThisScheme { - number: self.handles.insert(Handle::Thread(thread)), - flags: NewFdFlags::empty(), - }); - } - _ => return Err(Error::new(EINVAL)), - }, - Handle::Thread(ref thread_weak) => { - let thread_rc = thread_weak.upgrade().ok_or(Error::new(EOWNERDEAD))?; - let thread = thread_rc.borrow(); - - // By forwarding all dup calls to the kernel, this fd is now effectively the same - // as the underlying fd since that fd can't do anything itself. - Ok(OpenResult::OtherScheme { - fd: thread.fd.dup(buf)?.take(), - }) - } - Handle::Init | Handle::Ps(_) | Handle::ProcCredsCapability | Handle::SchemeRoot => { - Err(Error::new(EBADF)) - } - } - } - fn on_call( - &mut self, - state: VacantEntry, - mut op: OpCall, - awoken: &mut VecDeque, - ) -> Poll { - let id = op.fd; - let (payload, metadata) = op.payload_and_metadata(); - match self.handles[id] { - Handle::Init => Response::ready_err(EBADF, op), - Handle::Thread(ref thr_weak) => { - let Some(thr) = thr_weak.upgrade() else { - return Response::ready_err(EOWNERDEAD, op); - }; - let Some(verb) = ThreadCall::try_from_raw(metadata[0] as usize) else { - return Response::ready_err(EINVAL, op); - }; - match verb { - ThreadCall::SyncSigTctl => Ready(Response::new( - Self::on_sync_sigtctl(&mut *thr.borrow_mut()).map(|()| 0), - op, - )), - ThreadCall::SignalThread => Ready(Response::new( - self.on_kill_thread(&thr, metadata[1] as u8, awoken) - .map(|()| 0), - op, - )), - } - } - Handle::Proc(fd_pid) => { - let Some(verb) = ProcCall::try_from_raw(metadata[0] as usize) else { - log::trace!("Invalid proc call: {metadata:?}"); - return Response::ready_err(EINVAL, op); - }; - match verb { - ProcCall::Exit => self.on_exit_start( - fd_pid, - metadata[1] as u16, - state, - awoken, - Some(op.into_tag()), - ), - ProcCall::Waitpid | ProcCall::Waitpgid => { - let req_pid = ProcessId(metadata[1] as usize); - let target = match (verb, metadata[1] == 0) { - (ProcCall::Waitpid, true) => WaitpidTarget::AnyChild, - (ProcCall::Waitpid, false) => WaitpidTarget::SingleProc(req_pid), - (ProcCall::Waitpgid, true) => WaitpidTarget::AnyGroupMember, - (ProcCall::Waitpgid, false) => WaitpidTarget::ProcGroup(req_pid), - _ => unreachable!(), - }; - let flags = match WaitFlags::from_bits(metadata[2] as usize) { - Some(fl) => fl, - None => { - return Response::ready_err(EINVAL, op); - } - }; - let state = state.insert_entry(PendingState::AwaitingStatusChange { - waiter: fd_pid, - target, - flags, - op, - }); - self.work_on(state, awoken) - } - ProcCall::Setpgid => { - let target_pid = NonZeroUsize::new(metadata[1] as usize) - .map_or(fd_pid, |n| ProcessId(n.get())); - - let new_pgid = NonZeroUsize::new(metadata[2] as usize) - .map_or(target_pid, |n| ProcessId(n.get())); - if new_pgid.0 == usize::wrapping_neg(1) { - Ready(Response::new( - self.on_getpgid(fd_pid, target_pid).map(|ProcessId(p)| p), - op, - )) - } else { - Ready(Response::new( - self.on_setpgid(fd_pid, target_pid, new_pgid, awoken) - .map(|()| 0), - op, - )) - } - } - ProcCall::Getsid => { - let req_pid = NonZeroUsize::new(metadata[1] as usize) - .map_or(fd_pid, |n| ProcessId(n.get())); - Ready(Response::new( - self.on_getsid(fd_pid, req_pid).map(|ProcessId(s)| s), - op, - )) - } - ProcCall::Getppid => Ready(Response::new( - self.on_getppid(fd_pid).map(|ProcessId(p)| p), - op, - )), - ProcCall::Setsid => Ready(Response::new( - self.on_setsid(fd_pid, awoken).map(|()| 0), - op, - )), - ProcCall::SetResugid => Ready(Response::new( - self.on_setresugid(fd_pid, payload).map(|()| 0), - op, - )), - ProcCall::Kill | ProcCall::Sigq => { - let (payload, metadata) = op.payload_and_metadata(); - let target = ProcKillTarget::from_raw(metadata[1] as usize); - let Some(signal) = u8::try_from(metadata[2]).ok().filter(|s| *s <= 64) - else { - return Response::ready_err(EINVAL, op); - }; - let mode = match verb { - ProcCall::Kill => KillMode::Idempotent, - ProcCall::Sigq => KillMode::Queued({ - let mut buf = [0_u8; size_of::()]; - if payload.len() != size_of::() { - return Response::ready_err(EINVAL, op); - } - buf.copy_from_slice(payload); - *plain::from_bytes(&buf).unwrap() - }), - _ => unreachable!(), - }; - - Ready(Response::new( - self.on_kill(fd_pid, target, signal, mode, awoken) - .map(|()| 0), - op, - )) - } - ProcCall::SyncSigPctl => { - Ready(Response::new(self.on_sync_sigpctl(fd_pid).map(|()| 0), op)) - } - ProcCall::Sigdeq => Ready(Response::new( - self.on_sigdeq(fd_pid, payload).map(|()| 0), - op, - )), - ProcCall::Rename => Ready(Response::new( - self.on_proc_rename(fd_pid, payload).map(|()| 0), - op, - )), - ProcCall::DisableSetpgid => { - if let Some(proc) = self.processes.get(&fd_pid) { - proc.borrow_mut().disabled_setpgid = true; - Response::ready_ok(0, op) - } else { - Response::ready_err(ESRCH, op) - } - } - ProcCall::GetProcCredentials => Response::ready_err(EACCES, op), - - // setrens is no longer implemented as procmgr call - // FIXME remove this ProcCall variant - ProcCall::Setrens => Response::ready_err(EINVAL, op), - ProcCall::SetProcPriority => { - let target_pid = NonZeroUsize::new(metadata[1] as usize).map_or(fd_pid, |n| ProcessId(n.get())); - - let new_prio = metadata[2] as u32; - - Ready(Response::new( - self.on_setprocprio(fd_pid, target_pid, new_prio).map(|()| 0), - op - )) - }, - ProcCall::GetProcPriority => { - let target_pid = NonZeroUsize::new(metadata[1] as usize) - .map_or(fd_pid, |n| ProcessId(n.get())); - - Ready(Response::new( - self.on_getprocprio(fd_pid, target_pid).map(|prio| prio as usize), - op, - )) - }, - - } - } - Handle::Ps(_) => Response::ready_err(EOPNOTSUPP, op), - Handle::ProcCredsCapability => { - let Some(verb) = ProcCall::try_from_raw(metadata[0] as usize) else { - log::trace!("Invalid proc call: {metadata:?}"); - return Response::ready_err(EINVAL, op); - }; - match verb { - ProcCall::GetProcCredentials => Ready(Response::new( - self.read_process_metadata(ProcessId(metadata[1] as usize), payload), - op, - )), - _ => Response::ready_err(EINVAL, op), - } - } - Handle::SchemeRoot => Response::ready_err(EBADF, op), - } - } - fn on_getpgid(&mut self, caller_pid: ProcessId, target_pid: ProcessId) -> Result { - log::trace!("GETPGID from {caller_pid:?} target {target_pid:?}"); - let caller_proc = self - .processes - .get(&caller_pid) - .ok_or(Error::new(ESRCH))? - .borrow(); - let target_proc = self - .processes - .get(&target_pid) - .ok_or(Error::new(ESRCH))? - .borrow(); - - // Although not required, POSIX allows the impl to forbid getting the pgid of processes - // outside of the caller's session. - if caller_proc.sid != target_proc.sid && caller_proc.euid != 0 { - return Err(Error::new(EPERM)); - } - - Ok(target_proc.pgid) - } - fn on_setsid(&mut self, caller_pid: ProcessId, awoken: &mut VecDeque) -> Result<()> { - // TODO: more efficient? - // POSIX: any other process's pgid matches the caller pid - if self - .processes - .iter() - .any(|(pid, rc)| *pid != caller_pid && rc.borrow().pgid == caller_pid) - { - return Err(Error::new(EPERM)); - } - - let caller_proc_rc = self.processes.get(&caller_pid).ok_or(Error::new(ESRCH))?; - let mut caller_proc = caller_proc_rc.borrow_mut(); - let mut parent = (caller_proc.ppid != caller_pid) - .then(|| { - self.processes - .get(&caller_proc.ppid) - .map(|p| p.borrow_mut()) - }) - .ok_or(Error::new(ESRCH))?; - - // POSIX: already a process group leader - if caller_proc.pgid == caller_pid { - return Err(Error::new(EPERM)); - } - - Self::set_pgid( - caller_proc_rc, - &mut *caller_proc, - parent.as_deref_mut(), - &mut self.groups, - caller_pid, - awoken, - )?; - caller_proc.sid = caller_pid; - - // TODO: Remove controlling terminal - Ok(()) - } - fn on_getppid(&mut self, caller_pid: ProcessId) -> Result { - log::trace!("GETPPID {caller_pid:?}"); - let ppid = self - .processes - .get(&caller_pid) - .ok_or(Error::new(ESRCH))? - .borrow() - .ppid; - log::trace!("GETPPID {caller_pid:?} -> {ppid:?}"); - Ok(ppid) - } - fn on_getsid(&mut self, caller_pid: ProcessId, req_pid: ProcessId) -> Result { - let caller_proc = self - .processes - .get(&caller_pid) - .ok_or(Error::new(ESRCH))? - .borrow(); - let requested_proc = self - .processes - .get(&req_pid) - .ok_or(Error::new(ESRCH))? - .borrow(); - - // POSIX allows, but does not require, the implementation to forbid getting the session ID of processes outside - // the current session. - if caller_proc.sid != requested_proc.sid && caller_proc.euid != 0 { - return Err(Error::new(EPERM)); - } - - Ok(requested_proc.sid) - } - fn on_setpgid( - &mut self, - caller_pid: ProcessId, - target_pid: ProcessId, - new_pgid: ProcessId, - awoken: &mut VecDeque, - ) -> Result<()> { - let caller_proc = self.processes.get(&caller_pid).ok_or(Error::new(ESRCH))?; - let caller_sid = caller_proc.borrow().sid; - - let proc_rc = self.processes.get(&target_pid).ok_or(Error::new(ESRCH))?; - let mut proc = proc_rc.borrow_mut(); - - if proc.ppid != caller_pid && target_pid != caller_pid { - return Err(Error::new(ESRCH)); - } - - let mut parent = if proc.ppid == target_pid { - None // init - } else { - Some( - self.processes - .get(&proc.ppid) - .ok_or(Error::new(ESRCH))? - .borrow_mut(), - ) - }; - - // Session leaders cannot have their pgid changed. - if proc.sid == target_pid { - return Err(Error::new(EPERM)); - } - - // Cannot change the pgid of a process in a different session. - if caller_sid != proc.sid { - return Err(Error::new(EPERM)); - } - - // New pgid must either already exit, or be the same as the target pid. - if new_pgid != target_pid && !self.groups.contains_key(&new_pgid) { - return Err(Error::new(EPERM)); - } - - // After execv(), i.e. ProcCall::DisableSetpgid, setpgid where target_pid is a child - // process of the calling process, shall return EACCESS. - if proc.ppid == caller_pid && proc.disabled_setpgid { - return Err(Error::new(EACCES)); - } - - if proc.pgid == new_pgid { - return Ok(()); - } - - Self::set_pgid( - proc_rc, - &mut *proc, - parent.as_deref_mut(), - &mut self.groups, - new_pgid, - awoken, - )?; - - Ok(()) - } - fn set_pgid( - proc_rc: &Rc>, - proc: &mut Process, - parent: Option<&mut Process>, - groups: &mut HashMap>>, - new_pgid: ProcessId, - awoken: &mut VecDeque, - ) -> Result<()> { - let old_pgid = proc.pgid; - assert_ne!(old_pgid, new_pgid); - - if let Some(parent) = parent { - // Some waitpid waiters may end up waiting for no children, if a child sets its pgid - // and the parent was waiting with a pgid filter. Ensure the waiter is awoken and - // possibly returns ECHILD. - awoken.extend(parent.waitpid_waiting.drain(..)); - } - - let proc_weak = Rc::downgrade(proc_rc); - let shall_remove = { - let mut old_group = groups.get(&old_pgid).ok_or(Error::new(ESRCH))?.borrow_mut(); - old_group.processes.retain(|w| !Weak::ptr_eq(w, &proc_weak)); - old_group.processes.is_empty() - }; - if shall_remove { - groups.remove(&old_pgid); - } - groups - .entry(new_pgid) - .or_default() - .borrow_mut() - .processes - .push(proc_weak); - proc.pgid = new_pgid; - Ok(()) - } - fn on_exit_start( - &mut self, - pid: ProcessId, - status: u16, - state: VacantEntry, - awoken: &mut VecDeque, - tag: Option, - ) -> Poll { - log::trace!("ON_EXIT_START {pid:?} status {status:#x}"); - let Some(proc_rc) = self.processes.get(&pid) else { - return if let Some(tag) = tag { - Response::ready_err(EBADFD, tag) - } else { - Pending - }; - }; - let mut process_guard = proc_rc.borrow_mut(); - let process = &mut *process_guard; - - match process.status { - ProcessStatus::Stopped(_) | ProcessStatus::PossiblyRunnable => (), - //ProcessStatus::Exiting => return Pending, - ProcessStatus::Exiting { .. } => { - return if let Some(tag) = tag { - Response::ready_err(EAGAIN, tag) - } else { - Pending - }; - } - ProcessStatus::Exited { .. } => { - return if let Some(tag) = tag { - Response::ready_err(ESRCH, tag) - } else { - Pending - }; - } - } - - // Forbid the caller from giving statuses corresponding to e.g. WIFCONTINUED which exit() - // obviously can never be. - - log::trace!("Killed with raw status {status:?}"); - - // TODO: Are WIFEXITED and WIFSIGNALED mutually exclusive? - let (status, signal) = if status & 0xff == status { - (status as u8, None) - } else { - // TODO: Only allow valid and catchable signal numbers. - let sig = (status >> 8) as u8; - if !matches!(sig, 1..=64) { - return if let Some(tag) = tag { - Response::ready_err(EINVAL, tag) - } else { - Pending - }; - } - (0, NonZeroU8::new(sig)) - }; - - process.status = ProcessStatus::Exiting { status, signal }; - if !process.threads.is_empty() { - // terminate all threads (possibly including the caller, resulting in EINTR and a - // to-be-ignored cancellation request to this scheme). - for thread in &process.threads { - let thread = thread.borrow_mut(); - // TODO: cancel all threads anyway on error? - if let Err(err) = thread.status_hndl.write(&usize::MAX.to_ne_bytes()) { - if let Some(tag) = tag { - return Response::ready_err(err.errno, tag); - } - } - } - - log::trace!("EXIT PENDING"); - //self.debug(); - // TODO: check? - process.awaiting_threads_term.push(*state.key()); - } - drop(process_guard); - self.work_on( - state.insert_entry(PendingState::AwaitingThreadsTermination(pid, tag)), - awoken, - ) - } - fn on_waitpid( - &mut self, - this_pid: ProcessId, - target: WaitpidTarget, - flags: WaitFlags, - req_id: VirtualId, - ) -> Poll> { - if matches!( - target, - WaitpidTarget::AnyChild | WaitpidTarget::AnyGroupMember - ) { - // Check for existence of child. - // TODO(opt): inefficient, keep refcount? - if !self.processes.values().any(|p| p.borrow().ppid == this_pid) { - return Ready(Err(Error::new(ECHILD))); - } - } - - let proc_rc = self.processes.get(&this_pid).ok_or(Error::new(EBADFD))?; - - log::trace!("PROCS {:#?}", self.processes); - - let mut proc_guard = proc_rc.borrow_mut(); - let proc = &mut *proc_guard; - - let recv_nonblock = |waitpid: &mut BTreeMap, - key: &WaitpidKey| - -> Option<(ProcessId, WaitpidStatus)> { - if let Some((pid, sts)) = waitpid.get(key).map(|(k, v)| (*k, *v)) { - waitpid.remove(key); - /*while let Some((_, new_sts)) = waitpid.remove(&WaitpidKey { pid: Some(pid), pgid: None }) { - sts = new_sts; - }*/ - Some((pid, sts)) - } else { - None - } - }; - let grim_reaper = - |w_pid: ProcessId, status: WaitpidStatus, scheme: &mut ProcScheme| match status { - WaitpidStatus::Continued => { - if flags.contains(WaitFlags::WCONTINUED) { - Ready((w_pid.0, 0xffff)) - } else { - Pending - } - } - WaitpidStatus::Stopped { signal } => { - if flags.contains(WaitFlags::WUNTRACED) { - Ready((w_pid.0, 0x7f | (i32::from(signal.get()) << 8))) - } else { - Pending - } - } - WaitpidStatus::Terminated { signal, status } => { - scheme.reap(w_pid); - Ready(( - w_pid.0, - i32::from(signal.map_or(0, NonZeroU8::get)) | (i32::from(status) << 8), - )) - } - }; - - match target { - WaitpidTarget::AnyChild | WaitpidTarget::AnyGroupMember => { - let kv = (if matches!(target, WaitpidTarget::AnyChild) { - proc.waitpid.first_key_value() - } else { - proc.waitpid.get_key_value(&WaitpidKey { - pid: None, - pgid: Some(proc.pgid), - }) - }) - .map(|(k, v)| (*k, *v)); - if let Some((wid, (w_pid, status))) = kv { - let _ = proc.waitpid.remove(&wid); - drop(proc_guard); - grim_reaper(w_pid, status, self).map(Ok) - } else if flags.contains(WaitFlags::WNOHANG) { - Ready(Ok((0, 0))) - } else { - proc.waitpid_waiting.push_back(req_id); - Pending - } - } - WaitpidTarget::SingleProc(pid) => { - if this_pid == pid { - return Ready(Err(Error::new(EINVAL))); - } - let target_proc_rc = self.processes.get(&pid).ok_or(Error::new(ECHILD))?; - let target_proc = target_proc_rc.borrow_mut(); - - if target_proc.ppid != this_pid { - return Ready(Err(Error::new(ECHILD))); - } - let key = WaitpidKey { - pid: Some(pid), - pgid: None, - }; - if let ProcessStatus::Exited { status, signal } = target_proc.status { - let _ = recv_nonblock(&mut proc.waitpid, &key); - drop(proc_guard); - drop(target_proc); - grim_reaper(pid, WaitpidStatus::Terminated { signal, status }, self).map(Ok) - } else { - let res = recv_nonblock(&mut proc.waitpid, &key); - if let Some((w_pid, status)) = res { - drop(proc_guard); - drop(target_proc); - grim_reaper(w_pid, status, self).map(Ok) - } else if flags.contains(WaitFlags::WNOHANG) { - Ready(Ok((0, 0))) - } else { - proc.waitpid_waiting.push_back(req_id); - Pending - } - } - } - WaitpidTarget::ProcGroup(pgid) => { - if let Some(group_rc) = self.groups.get(&pgid) { - let group = group_rc.borrow(); - if !group - .processes - .iter() - .filter_map(Weak::upgrade) - .filter(|r| !Rc::ptr_eq(r, proc_rc)) - .any(|p| p.borrow().ppid == this_pid) - { - return Ready(Err(Error::new(ECHILD))); - } - } else { - return Ready(Err(Error::new(ECHILD))); - } - - let key = WaitpidKey { - pid: None, - pgid: Some(pgid), - }; - if let Some(&(w_pid, status)) = proc.waitpid.get(&key) { - let _ = proc.waitpid.remove(&key); - drop(proc_guard); - grim_reaper(w_pid, status, self).map(Ok) - } else if flags.contains(WaitFlags::WNOHANG) { - Ready(Ok((0, 0))) - } else { - proc.waitpid_waiting.push_back(req_id); - Pending - } - } - } - } - fn reap(&mut self, pid: ProcessId) { - let Entry::Occupied(entry) = self.processes.entry(pid) else { - return; - }; - let pgid = { - let proc = entry.get().borrow(); - if !proc.threads.is_empty() { - log::error!( - "reaping process (pid {pid:?} with remaining threads: {:#?}", - proc.threads - ); - return; - } - proc.pgid - }; - let proc_rc = entry.remove(); - let proc_weak = Rc::downgrade(&proc_rc); - - let Entry::Occupied(group) = self.groups.entry(pgid) else { - log::error!("Process missing from its group"); - return; - }; - group - .get() - .borrow_mut() - .processes - .retain(|p| !Weak::ptr_eq(&proc_weak, p)); - if group.get().borrow_mut().processes.is_empty() { - group.remove(); - } - // TODO: notify parent's other waiters if ECHILD would now occur? - } - fn on_setresugid(&mut self, pid: ProcessId, raw_buf: &[u8]) -> Result<()> { - let [new_ruid, new_euid, new_suid, new_rgid, new_egid, new_sgid] = { - let raw_ids: [u32; 6] = plain::slice_from_bytes::(raw_buf) - .unwrap() - .try_into() - .map_err(|_| Error::new(EINVAL))?; - raw_ids.map(|i| if i == u32::MAX { None } else { Some(i) }) - }; - let mut proc = self - .processes - .get(&pid) - .ok_or(Error::new(ESRCH))? - .borrow_mut(); - - if proc.euid != 0 { - if ![new_ruid, new_euid, new_suid] - .iter() - .filter_map(|x| *x) - .all(|new_id| [proc.ruid, proc.euid, proc.suid].contains(&new_id)) - { - return Err(Error::new(EPERM)); - } - if ![new_rgid, new_egid, new_sgid] - .iter() - .filter_map(|x| *x) - .all(|new_id| [proc.rgid, proc.egid, proc.sgid].contains(&new_id)) - { - return Err(Error::new(EPERM)); - } - } - - if let Some(new_ruid) = new_ruid { - proc.ruid = new_ruid; - } - if let Some(new_euid) = new_euid { - proc.euid = new_euid; - } - if let Some(new_suid) = new_suid { - proc.suid = new_suid; - } - if let Some(new_rgid) = new_rgid { - proc.rgid = new_rgid; - } - if let Some(new_egid) = new_egid { - proc.egid = new_egid; - } - if let Some(new_sgid) = new_sgid { - proc.sgid = new_sgid; - } - if let Err(err) = proc.sync_kernel_attrs(&self.auth) { - log::warn!("Failed to sync proc attrs in setresugid: {err}"); - } - Ok(()) - } - fn ancestors(&self, pid: ProcessId) -> impl Iterator + '_ { - struct Iter<'a> { - cur: Option, - procs: &'a HashMap>, DefaultHashBuilder>, - } - impl Iterator for Iter<'_> { - type Item = ProcessId; - - fn next(&mut self) -> Option { - let proc = self.procs.get(&self.cur?)?; - let ppid = proc.borrow().ppid; - self.cur = Some(ppid); - Some(ppid) - } - } - Iter { - cur: Some(pid), - procs: &self.processes, - } - } - fn work_on( - &mut self, - mut state_entry: OccupiedEntry, - awoken: &mut VecDeque, - ) -> Poll { - let req_id = *state_entry.key(); - let state = state_entry.get_mut(); - let this_state = core::mem::replace(state, PendingState::Placeholder); - match this_state { - PendingState::Placeholder => return Pending, // unreachable!(), - PendingState::AwaitingThreadsTermination(current_pid, tag) => { - let Some(proc_rc) = self.processes.get(¤t_pid) else { - return if let Some(tag) = tag { - Response::ready_err(ESRCH, tag) - } else { - state_entry.remove(); - Pending - }; - }; - let mut proc_guard = proc_rc.borrow_mut(); - let proc = &mut *proc_guard; - - if proc.threads.is_empty() { - log::trace!("WORKING ON AWAIT TERM"); - let (signal, status) = match proc.status { - ProcessStatus::Exiting { signal, status } => (signal, status), - ProcessStatus::Exited { .. } => { - return if let Some(tag) = tag { - Response::ready_ok(0, tag) - } else { - state_entry.remove(); - Pending - }; - } - _ => { - return if let Some(tag) = tag { - Response::ready_err(ESRCH, tag) // TODO? - } else { - state_entry.remove(); - Pending - }; - } - }; - // TODO: Properly remove state - state_entry.remove(); - - proc.status = ProcessStatus::Exited { signal, status }; - - let (ppid, pgid) = (proc.ppid, proc.pgid); - drop(proc_guard); - - if let Some(parent_rc) = self.processes.get(&ppid) { - // When a process exits, the parent is sent SIGCHLD. The process has no threads - // at this point. - if let Err(err) = self.on_send_sig( - current_pid, - KillTarget::Proc(ppid), - SIGCHLD as u8, - &mut false, - KillMode::Idempotent, - false, // stop_or_continue - awoken, - ) { - // EPERM on SIGCHLD to PID 1 is a known kernel limitation. - // The procmgr continues correctly after this; downgrade to debug. - log::debug!("failed to send SIGCHLD to parent PID {ppid:?}: {err}"); - } - - if let Some(init_rc) = self.processes.get(&INIT_PID) { - awoken.extend(init_rc.borrow_mut().waitpid_waiting.drain(..)); - - // TODO(opt): Store list of children in each process? - let children_iter = || { - self.processes - .values() - .filter(|p| !Rc::ptr_eq(p, init_rc)) - .filter(|p| p.borrow().ppid == current_pid) - }; - - // TODO(opt): Avoid allocation? - let affected_pgids = children_iter() - .map(|child_rc| { - let child_pgid = child_rc.borrow().pgid; - (child_pgid, self.pgrp_is_orphaned(child_pgid)) - }) - .chain(Some((pgid, self.pgrp_is_orphaned(pgid)))) - .collect::>>(); - - // Transfer children to init - for child_rc in children_iter() { - let mut child = child_rc.borrow_mut(); - log::trace!( - "Reparenting {:?} (ppid {:?}) => {:?}", - child.pid, - child.ppid, - INIT_PID - ); - child.ppid = INIT_PID; - init_rc.borrow_mut().waitpid.append(&mut child.waitpid); - drop(child); - } - // Check if any process group ID would become orphaned as a result of - // this exit. - for (affected_pgid, was_orphaned) in affected_pgids { - let is_orphaned = self.pgrp_is_orphaned(affected_pgid); - - if !was_orphaned.unwrap_or(false) - && is_orphaned.unwrap_or(false) - && let Some(group) = - self.groups.get(&affected_pgid).map(|r| r.borrow()) - { - for process_rc in - group.processes.iter().filter_map(|w| Weak::upgrade(&w)) - { - if !matches!( - process_rc.borrow().status, - ProcessStatus::Stopped(_) - ) { - continue; - } - let sighup_pid = process_rc.borrow().pid; - log::trace!("SENDING SIGCONT TO {sighup_pid:?}"); - if let Err(err) = self.on_send_sig( - INIT_PID, - KillTarget::Proc(sighup_pid), - SIGCONT as u8, - &mut false, - KillMode::Idempotent, - false, - awoken, - ) { - log::warn!( - "Failed to send newly-orphaned-pgid SIGHUP to PID {sighup_pid:?}: {err}" - ); - } - log::trace!("SENDING SIGHUP TO {sighup_pid:?}"); - if let Err(err) = self.on_send_sig( - INIT_PID, - KillTarget::Proc(sighup_pid), - SIGHUP as u8, - &mut false, - KillMode::Idempotent, - false, - awoken, - ) { - log::warn!( - "Failed to send newly-orphaned-pgid SIGHUP to PID {sighup_pid:?}: {err}" - ); - } - } - } - } - } - - let mut parent = parent_rc.borrow_mut(); - - parent.waitpid.insert( - WaitpidKey { - pid: Some(current_pid), - pgid: Some(pgid), - }, - (current_pid, WaitpidStatus::Terminated { signal, status }), - ); - log::trace!("AWAKING WAITPID {:?}", parent.waitpid_waiting); - // TODO(opt): inefficient - awoken.extend(parent.waitpid_waiting.drain(..)); - } - if let Some(tag) = tag { - Ready(Response::new(Ok(0), tag)) - } else { - // state was removed earlier - Pending - } - } else { - log::trace!("WAITING AGAIN"); - proc.awaiting_threads_term.push(req_id); - *state = PendingState::AwaitingThreadsTermination(current_pid, tag); - Pending - } - } - PendingState::AwaitingStatusChange { - waiter, - target, - flags, - mut op, - } => { - log::trace!("WAITPID {req_id:?}, {waiter:?}: {target:?} flags {flags:?}"); - let res = self.on_waitpid(waiter, target, flags, req_id); - log::trace!( - "WAITPID {req_id:?}, {waiter:?}: {target:?} flags {flags:?} -> {res:?}" - ); - - match res { - Ready(Ok((pid, status))) => { - if let Ok(status_out) = plain::from_mut_bytes::(op.payload()) { - *status_out = status; - } - Response::ready_ok(pid, op) - } - Ready(Err(e)) => Response::ready_err(e.errno, op), - Pending => { - *state = PendingState::AwaitingStatusChange { - waiter, - target, - flags, - op, - }; - Pending - } - } - } - } - } - fn debug(&self) { - log::trace!("PROCESSES\n{:#?}", self.processes); - log::trace!("HANDLES\n{:#?}", self.handles); - } - fn on_kill_thread( - &mut self, - thread: &Rc>, - signal: u8, - awoken: &mut VecDeque, - ) -> Result<()> { - let mut killed_self = false; - - let stop_or_continue = false; - - let caller_pid = thread.borrow().pid; // TODO(feat): allow this to be specified? - - self.on_send_sig( - caller_pid, - KillTarget::Thread(Rc::clone(thread)), - signal, - &mut killed_self, - KillMode::Idempotent, - stop_or_continue, - awoken, - )?; - - if killed_self { - // TODO: is this the most accurate error code? - Err(Error::new(ERESTART)) - } else { - Ok(()) - } - } - fn on_kill( - &mut self, - caller_pid: ProcessId, - target: ProcKillTarget, - signal: u8, - mode: KillMode, - awoken: &mut VecDeque, - ) -> Result<()> { - log::trace!("KILL(from {caller_pid:?}) TARGET {target:?} {signal} {mode:?}"); - - // if this is set and we would otherwise have succeeded, return EINTR so it can check its - // own mask - let mut killed_self = false; - - // SIGCHLD to parent are not generated by on_kill, but by on_send_sig itself - let stop_or_continue = false; - - let match_grp = match target { - ProcKillTarget::SingleProc(pid) => { - self.on_send_sig( - caller_pid, - KillTarget::Proc(ProcessId(pid)), - signal, - &mut killed_self, - mode, - stop_or_continue, - awoken, - )?; - return if killed_self { - Err(Error::new(ERESTART)) - } else { - Ok(()) - }; - } - ProcKillTarget::All => None, - ProcKillTarget::ProcGroup(grp) => Some(ProcessId(grp)), - ProcKillTarget::ThisGroup => Some( - self.processes - .get(&caller_pid) - .ok_or(Error::new(ESRCH))? - .borrow() - .pgid, - ), - }; - log::trace!("match group {match_grp:?}"); - - let mut err_opt = None; - // Number of processes successfully signaled. - let mut num_succeeded = 0; - - for (pid, proc_rc) in self.processes.iter() { - if match_grp.map_or(false, |g| proc_rc.borrow().pgid != g) { - continue; - } - let res = self.on_send_sig( - caller_pid, - KillTarget::Proc(*pid), - signal, - &mut killed_self, - mode, - stop_or_continue, - awoken, - ); - match res { - Ok(()) => num_succeeded += 1, - Err(err) => err_opt = Some(err), - } - } - - // > POSIX Issue 8: The `kill()` function is successful if the process has - // > permission to send `sig` to *any* of the processes specified by - // > `pid`. - // - // Thus, if *at least one* process was successfully signaled, `kill()` - // returns success. - if num_succeeded == 0 { - if let Some(err) = err_opt { - Err(err) - } else { - // No process or process group could be found corrsponding to - // that specified by `target`. - Err(Error::new(ESRCH)) - } - } else if killed_self { - Err(Error::new(ERESTART)) - } else { - Ok(()) - } - } - fn on_send_sig( - &self, - caller_pid: ProcessId, - target: KillTarget, - signal: u8, - killed_self: &mut bool, - mode: KillMode, - stop_or_continue: bool, - awoken: &mut VecDeque, - ) -> Result<()> { - log::trace!("SEND_SIG(from {caller_pid:?}) TARGET {target:?} {signal} {mode:?}"); - let sig = usize::from(signal); - - if sig > 64 { - return Err(Error::new(EINVAL)); - } - - let sig_group = (sig - 1) / 32; - let sig_idx = (sig - 1) % 32; - - let target_pid = match target { - KillTarget::Proc(pid) => pid, - KillTarget::Thread(ref thread) => thread.borrow().pid, - }; - let target_proc_rc = self.processes.get(&target_pid).ok_or(Error::new(ESRCH))?; - - let sender = SenderInfo { - pid: caller_pid.0 as u32, - ruid: self - .processes - .get(&caller_pid) - .ok_or(Error::new(ESRCH))? - .borrow() - .ruid, - }; - - enum SendResult { - LacksPermission, - Succeeded, - SucceededSigchld { - orig_signal: NonZeroU8, - ppid: ProcessId, - pgid: ProcessId, - }, - SucceededSigcont { - ppid: ProcessId, - pgid: ProcessId, - }, - FullQ, - Invalid, - } - let (caller_euid, caller_ruid) = { - let caller = self - .processes - .get(&caller_pid) - .ok_or(Error::new(ESRCH))? - .borrow(); - (caller.euid, caller.ruid) - }; - - let result = (|| { - // XXX: It's not currently possible for procmgr to know what thread called, so the - // EINTR will be coarser. That shouldn't affect program logic though, since the - // trampoline always checks the masks anyway. - // TODO(feat): allow regular kill (alongside thread-kill) to operate on *thread fds*? - let is_self = target_pid == caller_pid; - - let mut target_proc_guard = target_proc_rc.borrow_mut(); - let mut target_proc = &mut *target_proc_guard; - - if caller_euid != 0 - && caller_euid != target_proc.ruid - && caller_ruid != target_proc.ruid - { - return SendResult::LacksPermission; - } - - // If sig = 0, test that process exists and can be signalled, but don't send any - // signal. - let Some(nz_signal) = NonZeroU8::new(signal) else { - return SendResult::Succeeded; - }; - - // Similarly, don't send anything for already exiting or exited processes. It would be - // bad if e.g. SIGCONT could cause these to become PossiblyRunnable again. - if matches!( - target_proc.status, - ProcessStatus::Exited { .. } | ProcessStatus::Exiting { .. } - ) { - return SendResult::Succeeded; - } - - let Some(mut sig_pctl) = target_proc.sig_pctl.as_ref() else { - log::trace!("No pctl {caller_pid:?} => {target_pid:?}"); - return SendResult::Invalid; - }; - log::trace!("PCTL {:#x?}", &**sig_pctl); - log::trace!( - "STS {:?} NTHRD {}", - target_proc.status, - target_proc.threads.len() - ); - - if sig == SIGCONT - && let ProcessStatus::Stopped(_sig) = target_proc.status - { - // Convert stopped processes to blocked if sending SIGCONT, regardless of whether - // SIGCONT is blocked or ignored. It can however be controlled whether the process - // will additionally ignore, defer, or handle that signal. - target_proc.status = ProcessStatus::PossiblyRunnable; - - if !sig_pctl.signal_will_ign(SIGCONT, false) { - sig_pctl - .pending - .fetch_or(sig_bit(SIGCONT), Ordering::Relaxed); - } - - // TODO: which threads should become Runnable? - for thread_rc in target_proc.threads.iter() { - let thread = thread_rc.borrow_mut(); - if let Some(ref tctl) = thread.sig_ctrl { - tctl.word[0].fetch_and( - !(sig_bit(SIGSTOP) - | sig_bit(SIGTTIN) - | sig_bit(SIGTTOU) - | sig_bit(SIGTSTP)), - Ordering::Relaxed, - ); - } - thread - .status_hndl - .write(&(ContextVerb::Unstop as usize).to_ne_bytes()) - .expect("TODO"); - } - // POSIX XSI allows but does not reqiure SIGCHLD to be sent when SIGCONT occurs. - return SendResult::SucceededSigcont { - ppid: target_proc.ppid, - pgid: target_proc.pgid, - }; - } - let is_conditional_stop = matches!(sig, SIGTTIN | SIGTTOU | SIGTSTP); - if sig == SIGSTOP - || (is_conditional_stop - && target_proc - .sig_pctl - .as_ref() - .map_or(false, |proc| proc.signal_will_stop(sig))) - { - if is_conditional_stop { - let pgid = target_proc.pgid; - drop(target_proc_guard); - - if self.pgrp_is_orphaned(pgid).unwrap_or(true) { - // POSIX requires that processes in orphaned process groups never be stopped in - // due to SIGTTIN/SIGTTOU/SIGTSTP. - return SendResult::Succeeded; - } - - target_proc_guard = target_proc_rc.borrow_mut(); - target_proc = &mut *target_proc_guard; - sig_pctl = target_proc.sig_pctl.as_mut().expect("already checked"); - } - - target_proc.status = ProcessStatus::Stopped(sig); - - for thread in &target_proc.threads { - let thread = thread.borrow(); - match thread - .status_hndl - .write(&(ContextVerb::Stop as usize).to_ne_bytes()) - { - Ok(_) => (), - // TODO: Write a test that this actually results in the thread eventually - // being removed from `threads`. A "dead thread" event should already have - // been triggered, but it is possible that happens during this code, or - // just before that event. - // - // Thread has state Dead, so ignore. - Err(Error { errno: EOWNERDEAD }) => continue, - Err(other) => { - log::error!( - "Unexpected error when stopping context: {other}, pid {target_pid:?} thread fd {}", - thread.status_hndl.as_raw_fd() - ); - continue; - } - } - if let Some(ref tctl) = thread.sig_ctrl { - tctl.word[0].fetch_and(!sig_bit(SIGCONT), Ordering::Relaxed); - } - } - - // TODO: Actually wait for, or IPI the context first, then clear bit. Not atomically safe otherwise? - sig_pctl - .pending - .fetch_and(!sig_bit(SIGCONT), Ordering::Relaxed); - - log::trace!("SUCCEEDED SIGCHILD MY_PID {target_pid:?}"); - return SendResult::SucceededSigchld { - orig_signal: nz_signal, - ppid: target_proc.ppid, - pgid: target_proc.pgid, - }; - } - if sig == SIGKILL { - for thread in &target_proc.threads { - let thread = thread.borrow(); - thread - .status_hndl - .write(&(ContextVerb::ForceKill as usize).to_ne_bytes()) - .expect("TODO"); - } - - *killed_self |= is_self; - - // exit() will signal the parent, rather than immediately in kill() - return SendResult::Succeeded; - } - if !sig_pctl.signal_will_ign(sig, stop_or_continue) { - match target { - KillTarget::Thread(ref thread_rc) => { - let thread = thread_rc.borrow(); - let Some(ref tctl) = thread.sig_ctrl else { - log::trace!("No tctl"); - return SendResult::Invalid; - }; - - tctl.sender_infos[sig_idx].store(sender.raw(), Ordering::Relaxed); - let bit = 1 << sig_idx; - - let _was_new = tctl.word[sig_group].fetch_or(bit, Ordering::Release); - if (tctl.word[sig_group].load(Ordering::Relaxed) >> 32) & bit != 0 { - *killed_self |= is_self; - thread - .status_hndl - .write(&(ContextVerb::Interrupt as usize).to_ne_bytes()) - .expect("TODO"); - } - } - KillTarget::Proc(proc) => { - match mode { - KillMode::Queued(arg) => { - if sig_group != 1 { - log::trace!("Out of range"); - return SendResult::Invalid; - } - let rtidx = sig_idx; - //log::trace!("QUEUEING {arg:?} RTIDX {rtidx}"); - if rtidx >= target_proc.rtqs.len() { - target_proc.rtqs.resize_with(rtidx + 1, VecDeque::new); - } - let rtq = target_proc.rtqs.get_mut(rtidx).unwrap(); - - // TODO(feat): configurable limit? - if rtq.len() >= 32 { - return SendResult::FullQ; - } - - rtq.push_back(arg); - } - KillMode::Idempotent => { - if sig_pctl.pending.load(Ordering::Acquire) & sig_bit(sig) != 0 { - // If already pending, do not send this signal. While possible that - // another thread is concurrently clearing pending, and that other - // spuriously awoken threads would benefit from actually receiving - // this signal, there is no requirement by POSIX for such signals - // not to be mergeable. So unless the signal handler is observed to - // happen-before this syscall, it can be ignored. The pending bits - // would certainly have been cleared, thus contradicting this - // already reached statement. - return SendResult::Succeeded; - } - - if sig_group != 0 { - log::trace!("Invalid sig group"); - return SendResult::Invalid; - } - sig_pctl.sender_infos[sig_idx] - .store(sender.raw(), Ordering::Relaxed); - } - } - - sig_pctl.pending.fetch_or(sig_bit(sig), Ordering::Release); - - for thread in target_proc.threads.iter() { - let thread = thread.borrow(); - let Some(ref tctl) = thread.sig_ctrl else { - continue; - }; - log::trace!("TCTL {:#x?}", &**tctl); - if (tctl.word[sig_group].load(Ordering::Relaxed) >> 32) & (1 << sig_idx) - != 0 - { - thread - .status_hndl - .write(&(ContextVerb::Interrupt as usize).to_ne_bytes()) - .expect("TODO"); - *killed_self |= is_self; - break; - } - } - } - } - SendResult::Succeeded - } else { - // Discard signals if sighandler is unset. This includes both special contexts such - // as bootstrap, and child processes or threads that have not yet been started. - // This is semantically equivalent to having all signals except SIGSTOP and SIGKILL - // blocked/ignored (SIGCONT can be ignored and masked, but will always continue - // stopped processes first). - SendResult::Succeeded - } - })(); - - match result { - // TODO: succeed even if *some* (when group/all procs is specified) fail? - SendResult::LacksPermission => return Err(Error::new(EPERM)), - - SendResult::Succeeded => (), - SendResult::FullQ => return Err(Error::new(EAGAIN)), - SendResult::Invalid => { - log::trace!("Invalid signal configuration for {target_pid:?}"); - return Err(Error::new(ESRCH)); - } - SendResult::SucceededSigchld { - ppid, - pgid, - orig_signal, - } => { - { - let mut parent = self - .processes - .get(&ppid) - .ok_or(Error::new(ESRCH))? - .borrow_mut(); - parent.waitpid.insert( - WaitpidKey { - pid: Some(target_pid), - pgid: Some(pgid), - }, - ( - target_pid, - WaitpidStatus::Stopped { - signal: orig_signal, - }, - ), - ); - awoken.extend(parent.waitpid_waiting.drain(..)); - } - // TODO(err): Just ignore EINVAL (missing signal config), otherwise handle error? - if ppid != INIT_PID { - log::trace!("SIGCHLDing {ppid:?}"); - if let Err(err) = self.on_send_sig( - INIT_PID, // caller, TODO? - KillTarget::Proc(ppid), - SIGCHLD as u8, - killed_self, - KillMode::Idempotent, - true, // stop_or_continue - awoken, - ) { - log::trace!("failed to SIGCHLD parent (SIGSTOP): {err}"); - } - } - } - SendResult::SucceededSigcont { ppid, pgid } => { - { - let mut parent = self - .processes - .get(&ppid) - .ok_or(Error::new(ESRCH))? - .borrow_mut(); - parent.waitpid.insert( - WaitpidKey { - pid: Some(target_pid), - pgid: Some(pgid), - }, - (target_pid, WaitpidStatus::Continued), - ); - awoken.extend(parent.waitpid_waiting.drain(..)); - } - // POSIX XSI allows but does not require SIGCONT to send signals to the parent. - // TODO(err): Just ignore EINVAL (missing signal config), otherwise handle error? - if ppid != INIT_PID { - if let Err(err) = self.on_send_sig( - INIT_PID, // caller, TODO? - KillTarget::Proc(ppid), - SIGCHLD as u8, - killed_self, - KillMode::Idempotent, - true, // stop_or_continue - awoken, - ) { - log::trace!("failed to SIGCHLD parent (SIGCONT): {err}"); - } - } - } - } - - Ok(()) - } - fn real_tctl_pctl_intra_page_offsets(fd: &FdGuard) -> Result<[u16; 2]> { - let mut buf = SetSighandlerData::default(); - fd.read(&mut buf)?; - Ok([ - (buf.thread_control_addr % PAGE_SIZE) as u16, - (buf.proc_control_addr % PAGE_SIZE) as u16, - ]) - } - fn on_proc_rename(&mut self, pid: ProcessId, new_name_raw: &[u8]) -> Result<()> { - let name_len = new_name_raw - .iter() - .position(|c| *c == 0) - .unwrap_or(new_name_raw.len()); - - let new_name = - core::str::from_utf8(&new_name_raw[..name_len]).map_err(|_| Error::new(EINVAL))?; - let mut proc = self - .processes - .get(&pid) - .ok_or(Error::new(ESRCH))? - .borrow_mut(); - - proc.name = ArrayString::from_str(&new_name[..new_name.len().min(NAME_CAPAC)]).unwrap(); - if let Err(err) = proc.sync_kernel_attrs(&self.auth) { - log::warn!("Failed to set kernel attrs when renaming proc: {err}"); - } - Ok(()) - } - fn on_sync_sigtctl(thread: &mut Thread) -> Result<()> { - log::trace!("Sync tctl {:?}", thread.pid); - let sigcontrol_fd = thread.fd.dup(b"sighandler")?; - let [tctl_off, _] = Self::real_tctl_pctl_intra_page_offsets(&sigcontrol_fd)?; - log::trace!("read intra offsets"); - thread - .sig_ctrl - .replace(Page::map(&sigcontrol_fd, 0, tctl_off)?); - Ok(()) - } - fn on_sync_sigpctl(&mut self, pid: ProcessId) -> Result<()> { - log::trace!("Sync pctl {pid:?}"); - let mut proc = self - .processes - .get(&pid) - .ok_or(Error::new(ESRCH))? - .borrow_mut(); - let any_thread = proc.threads.first().ok_or(Error::new(EINVAL))?; - let sigcontrol_fd = any_thread.borrow().fd.dup(b"sighandler")?; - let [_, pctl_off] = Self::real_tctl_pctl_intra_page_offsets(&sigcontrol_fd)?; - proc.sig_pctl - .replace(Page::map(&sigcontrol_fd, PAGE_SIZE, pctl_off)?); - Ok(()) - } - fn on_sigdeq(&mut self, pid: ProcessId, payload: &mut [u8]) -> Result<()> { - let sig_idx = { - let bytes = <[u8; 4]>::try_from(payload.get(..4).ok_or(Error::new(EINVAL))?).unwrap(); - u32::from_ne_bytes(bytes) - }; - log::trace!("SIGDEQ {pid:?} idx {sig_idx}"); - let dst = payload - .get_mut(..size_of::()) - .ok_or(Error::new(EINVAL))?; - if sig_idx >= 32 { - return Err(Error::new(EINVAL)); - } - let mut proc = self - .processes - .get_mut(&pid) - .ok_or(Error::new(ESRCH))? - .borrow_mut(); - let proc = &mut *proc; - - let pctl = proc.sig_pctl.as_ref().ok_or(Error::new(EBADF))?; - - let q = proc - .rtqs - .get_mut(sig_idx as usize) - .ok_or(Error::new(EAGAIN))?; - let Some(front) = q.pop_front() else { - return Err(Error::new(EAGAIN)); - }; - - if q.is_empty() { - pctl.pending - .fetch_and(!(1 << (32 + sig_idx as usize)), Ordering::Relaxed); - } - dst.copy_from_slice(unsafe { plain::as_bytes(&front) }); - Ok(()) - } - fn on_close(&mut self, id: usize) { - if self.handles.try_remove(id).is_none() { - log::error!("on_close for nonexistent handle, id={id}"); - } - } - fn pgrp_is_orphaned(&self, grp: ProcessId) -> Option { - let group = self.groups.get(&grp)?.borrow(); - - let mut still_true = true; - - for process_rc in group.processes.iter().filter_map(Weak::upgrade) { - let process = process_rc.borrow(); - let Some(parent_rc) = self.processes.get(&process_rc.borrow().ppid) else { - // TODO(err): what to do here? - continue; - }; - let parent = parent_rc.borrow(); - - // POSIX defines orphaned process groups as those where - // - // forall process in group, parent = process.parent, - // parent's pgid == process's pgid - // OR - // parent's session id != process's session id - let cond = parent.pgid == process.pgid || parent.sid != process.sid; - if !cond { - log::trace!( - "COUNTEREXAMPLE: process {:#?} parent {:#?}", - process, - parent - ); - } - still_true &= cond; - } - Some(still_true) - } - fn ps_data(&mut self, _ctx: &CallerCtx) -> Result> { - // TODO: enforce uid == 0? - - let mut string = alloc::format!( - "{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{:<16}\n", - "PID", - "PGID", - "PPID", - "SID", - "RUID", - "RGID", - "EUID", - "EGID", - "NTHRD", - "STATUS", - "NAME", - ); - for (pid, process_rc) in self.processes.iter() { - let process = process_rc.borrow(); - let status = match process.status { - ProcessStatus::PossiblyRunnable => "R", - ProcessStatus::Stopped(_) => "S", - ProcessStatus::Exiting { .. } => "E", - ProcessStatus::Exited { .. } => "X", - }; - use core::fmt::Write; - writeln!( - string, - "{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<6}{:<8}{:<16}", - pid.0, - process.pgid.0, - process.ppid.0, - process.sid.0, - process.ruid, - process.rgid, - process.euid, - process.egid, - process.threads.len(), - status, - process.name, - ) - .unwrap(); - } - - // Useful for debugging memory leaks. - log::trace!("NEXT FD: {}", { - let nextfd = syscall::dup(0, &[]).unwrap(); - let _ = syscall::close(nextfd); - nextfd - }); - log::trace!("{} processes", self.processes.len()); - log::trace!("{} groups", self.groups.len()); - log::trace!("{} sessions", self.sessions.len()); - log::trace!("{} handles", self.handles.len()); - log::trace!("{} thread_lookup", self.thread_lookup.len()); - log::trace!("{} next_id", self.next_internal_id); - - Ok(string.into_bytes()) - } - - fn on_setprocprio( - &mut self, - caller_pid: ProcessId, - target_pid: ProcessId, - new_prio: u32, - ) -> Result<()> { - if new_prio >= 40 { - return Err(Error::new(EINVAL)); - } - - let caller_euid = self.processes.get(&caller_pid).ok_or(Error::new(ESRCH))?.borrow().euid; - - let target_rc = self.processes.get(&target_pid).ok_or(Error::new(ESRCH))?; - let mut target = target_rc.borrow_mut(); - - if caller_euid != 0 && caller_euid != target.euid { - return Err(Error::new(EPERM)); - } - - target.prio = new_prio; - - if let Err(err) = target.sync_kernel_attrs(&self.auth) { - log::warn!("Failed to sync proc attrs in setprocprio: {err}"); - } - Ok(()) - } - - fn on_getprocprio( - &self, - caller_pid: ProcessId, - target_pid: ProcessId, - ) -> Result { - let target_rc = self.processes.get(&target_pid).ok_or(Error::new(ESRCH))?; - Ok(target_rc.borrow().prio) - } -} - -#[derive(Clone, Copy, Debug)] -enum KillMode { - Idempotent, - Queued(RtSigInfo), -} -#[derive(Debug)] -enum KillTarget { - Proc(ProcessId), - Thread(Rc>), -} -fn arraystring_to_bytes(s: ArrayString) -> [u8; C] { - let mut buf = [0_u8; C]; - let min = buf.len().min(s.len()); - buf[..min].copy_from_slice(&s.as_bytes()[..min]); - buf -} - -impl Process { - fn sync_kernel_attrs(&mut self, auth: &FdGuard) -> Result<()> { - // TODO: continue with other threads if one fails? - for thread_rc in &self.threads { - let mut thread = thread_rc.borrow_mut(); - thread.sync_kernel_attrs(self, auth)?; - } - Ok(()) - } -} - -impl Thread { - fn sync_kernel_attrs(&mut self, process: &Process, auth: &FdGuard) -> Result<()> { - let attr_fd = self - .fd - .dup(alloc::format!("auth-{}-attrs", auth.as_raw_fd()).as_bytes())?; - attr_fd.write(&ProcSchemeAttrs { - pid: process.pid.0 as u32, - euid: process.euid, - egid: process.egid, - prio: process.prio, - debug_name: arraystring_to_bytes(process.name), - })?; - Ok(()) - } -} diff --git a/recipes/core/base/bootstrap/src/riscv64.ld b/recipes/core/base/bootstrap/src/riscv64.ld deleted file mode 100644 index c37274b9f3..0000000000 --- a/recipes/core/base/bootstrap/src/riscv64.ld +++ /dev/null @@ -1,52 +0,0 @@ -ENTRY(_start) -OUTPUT_FORMAT(elf64-littleriscv) - -SECTIONS { - . = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */ - __initfs_header = . - 4096; - . += SIZEOF_HEADERS; - . = ALIGN(4096); - - .text : { - __text_start = .; - *(.text*) - . = ALIGN(4096); - __text_end = .; - } - .rodata : { - __rodata_start = .; - *(.rodata*) - } - .data.rel.ro : { - *(.data.rel.ro*) - } - .got : { - *(.got) - } - .got.plt : { - *(.got.plt) - . = ALIGN(4096); - __rodata_end = .; - } - .data : { - __data_start = .; - *(.data*) - *(.sdata*) - . = ALIGN(4096); - __data_end = .; - - __bss_start = .; - *(.bss*) - *(.sbss*) - . = ALIGN(4096); - __bss_end = .; - } - - /DISCARD/ : { - *(.comment*) - *(.eh_frame*) - *(.gcc_except_table*) - *(.note*) - *(.rel.eh_frame*) - } -} diff --git a/recipes/core/base/bootstrap/src/riscv64.rs b/recipes/core/base/bootstrap/src/riscv64.rs deleted file mode 100644 index 6bec4c2ec6..0000000000 --- a/recipes/core/base/bootstrap/src/riscv64.rs +++ /dev/null @@ -1,47 +0,0 @@ -use core::mem; -use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP}; - -const STACK_SIZE: usize = 64 * 1024; // 64 KiB -pub const USERMODE_END: usize = 1 << 38; // Assuming Sv39 -pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE; - -static MAP: Map = Map { - offset: 0, - size: STACK_SIZE, - flags: MapFlags::PROT_READ - .union(MapFlags::PROT_WRITE) - .union(MapFlags::MAP_PRIVATE) - .union(MapFlags::MAP_FIXED_NOREPLACE), - address: STACK_START, // highest possible user address -}; - -core::arch::global_asm!( - " - .globl _start -_start: - # Setup a stack. - li a7, {number} - li a0, {fd} - la a1, {map} # pointer to Map struct - li a2, {map_size} # size of Map struct - ecall - - # Test for success (nonzero value). - bne a0, x0, 2f - # (failure) - unimp -2: - li sp, {stack_size} - add sp, sp, a0 - mv fp, x0 - - jal start - # `start` must never return. - unimp - ", - fd = const usize::MAX, // dummy fd indicates anonymous map - map = sym MAP, - map_size = const mem::size_of::(), - number = const SYS_FMAP, - stack_size = const STACK_SIZE, -); diff --git a/recipes/core/base/bootstrap/src/start.rs b/recipes/core/base/bootstrap/src/start.rs deleted file mode 100644 index 14a97ac2ad..0000000000 --- a/recipes/core/base/bootstrap/src/start.rs +++ /dev/null @@ -1,86 +0,0 @@ -use syscall::flag::MapFlags; - -mod offsets { - unsafe extern "C" { - // text (R-X) - static __text_start: u8; - static __text_end: u8; - // rodata (R--) - static __rodata_start: u8; - static __rodata_end: u8; - // data+bss (RW-) - static __data_start: u8; - static __bss_end: u8; - } - pub fn text() -> (usize, usize) { - unsafe { - ( - &__text_start as *const u8 as usize, - &__text_end as *const u8 as usize, - ) - } - } - pub fn rodata() -> (usize, usize) { - unsafe { - ( - &__rodata_start as *const u8 as usize, - &__rodata_end as *const u8 as usize, - ) - } - } - pub fn data_and_bss() -> (usize, usize) { - unsafe { - ( - &__data_start as *const u8 as usize, - &__bss_end as *const u8 as usize, - ) - } - } -} - -#[unsafe(no_mangle)] -pub unsafe extern "C" fn start() -> ! { - // Remap self, from the previous RWX - - let (text_start, text_end) = offsets::text(); - let (rodata_start, rodata_end) = offsets::rodata(); - let (data_start, data_end) = offsets::data_and_bss(); - - // NOTE: Assuming the debug scheme root fd is always placed at this position - let debug_fd = syscall::UPPER_FDTBL_TAG + syscall::data::GlobalSchemes::Debug as usize; - let _ = syscall::openat(debug_fd, "", syscall::O_RDONLY, 0); // stdin - let _ = syscall::openat(debug_fd, "", syscall::O_WRONLY, 0); // stdout - let _ = syscall::openat(debug_fd, "", syscall::O_WRONLY, 0); // stderr - - unsafe { - let _ = syscall::mprotect(4096, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE) - .expect("mprotect failed for initfs header page"); - - let _ = syscall::mprotect( - text_start, - text_end - text_start, - MapFlags::PROT_READ | MapFlags::PROT_EXEC | MapFlags::MAP_PRIVATE, - ) - .expect("mprotect failed for .text"); - let _ = syscall::mprotect( - rodata_start, - rodata_end - rodata_start, - MapFlags::PROT_READ | MapFlags::MAP_PRIVATE, - ) - .expect("mprotect failed for .rodata"); - let _ = syscall::mprotect( - data_start, - data_end - data_start, - MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE, - ) - .expect("mprotect failed for .data/.bss"); - let _ = syscall::mprotect( - data_end, - crate::arch::STACK_START - data_end, - MapFlags::PROT_READ | MapFlags::MAP_PRIVATE, - ) - .expect("mprotect failed for rest of memory"); - } - - crate::exec::main(); -} diff --git a/recipes/core/base/bootstrap/src/x86_64.ld b/recipes/core/base/bootstrap/src/x86_64.ld deleted file mode 100644 index 375f4acb0d..0000000000 --- a/recipes/core/base/bootstrap/src/x86_64.ld +++ /dev/null @@ -1,55 +0,0 @@ -ENTRY(_start) -OUTPUT_FORMAT(elf64-x86-64) - -SECTIONS { - . = 4096 + 4096; /* Reserved for the null page and the initfs header prepended by redox-initfs-ar */ - __initfs_header = . - 4096; - . += SIZEOF_HEADERS; - . = ALIGN(4096); - - .text : { - __text_start = .; - *(.text*) - . = ALIGN(4096); - __text_end = .; - } - .rodata : { - __rodata_start = .; - *(.rodata*) - } - .data.rel.ro : { - *(.data.rel.ro*) - } - .got : { - *(.got) - } - .got.plt : { - *(.got.plt) - . = ALIGN(4096); - __rodata_end = .; - } - .data : { - __data_start = .; - *(.data*) - . = ALIGN(4096); - __data_end = .; - - *(.tbss*) - . = ALIGN(4096); - *(.tdata*) - . = ALIGN(4096); - - __bss_start = .; - *(.bss*) - . = ALIGN(4096); - __bss_end = .; - } - - /DISCARD/ : { - *(.comment*) - *(.eh_frame*) - *(.gcc_except_table*) - *(.note*) - *(.rel.eh_frame*) - } -} diff --git a/recipes/core/base/bootstrap/src/x86_64.rs b/recipes/core/base/bootstrap/src/x86_64.rs deleted file mode 100644 index 23d52cf4dc..0000000000 --- a/recipes/core/base/bootstrap/src/x86_64.rs +++ /dev/null @@ -1,49 +0,0 @@ -use core::mem; -use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP}; - -const STACK_SIZE: usize = 64 * 1024; // 64 KiB -pub const USERMODE_END: usize = 0x0000_8000_0000_0000; -pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE; - -static MAP: Map = Map { - offset: 0, - size: STACK_SIZE, - flags: MapFlags::PROT_READ - .union(MapFlags::PROT_WRITE) - .union(MapFlags::MAP_PRIVATE) - .union(MapFlags::MAP_FIXED_NOREPLACE), - address: STACK_START, // highest possible user address -}; - -core::arch::global_asm!( - " - .globl _start - _start: - # Setup a stack. - mov rax, {number} - mov rdi, {fd} - mov rsi, offset {map} # pointer to Map struct - mov rdx, {map_size} # size of Map struct - syscall - - # Test for success (nonzero value). - cmp rax, 0 - jg 1f - # (failure) - ud2 - 1: - # Subtract 16 since all instructions seem to hate non-canonical RSP values :) - lea rsp, [rax+{stack_size}-16] - mov rbp, rsp - - # Stack has the same alignment as `size`. - call start - # `start` must never return. - ud2 - ", - fd = const usize::MAX, // dummy fd indicates anonymous map - map = sym MAP, - map_size = const mem::size_of::(), - number = const SYS_FMAP, - stack_size = const STACK_SIZE, -); diff --git a/recipes/core/base/config/Cargo.toml b/recipes/core/base/config/Cargo.toml deleted file mode 100644 index c7fb85c442..0000000000 --- a/recipes/core/base/config/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "config" -description = "Configuration override library" -version = "0.0.0" -edition = "2024" - -[dependencies] - -[lints] -workspace = true diff --git a/recipes/core/base/config/src/lib.rs b/recipes/core/base/config/src/lib.rs deleted file mode 100644 index e7ba434d23..0000000000 --- a/recipes/core/base/config/src/lib.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::collections::BTreeMap; -use std::path::{Path, PathBuf}; -use std::{fs, io}; - -pub fn config(name: &str) -> Result, io::Error> { - config_for_dirs(&[ - &Path::new("/usr/lib").join(format!("{name}.d")), - &Path::new("/etc").join(format!("{name}.d")), - ]) -} - -pub fn config_for_initfs(name: &str) -> Result, io::Error> { - config_for_dirs(&[ - &Path::new("/scheme/initfs/lib").join(format!("{name}.d")), - &Path::new("/scheme/initfs/etc").join(format!("{name}.d")), - ]) -} - -pub fn config_for_dirs(dirs: &[impl AsRef]) -> Result, io::Error> { - // This must be a BTreeMap to iterate in sorted order. - let mut entries = BTreeMap::new(); - - for dir in dirs { - let dir = dir.as_ref(); - if !dir.exists() { - // Skip non-existent dirs - continue; - } - - for entry_res in fs::read_dir(&dir)? { - // This intentionally overwrites older entries with - // the same filename to allow overriding entries in - // one search dir with those in a later search dir. - let entry = entry_res?; - entries.insert(entry.file_name(), entry.path()); - } - } - - Ok(entries.into_values().collect()) -} diff --git a/recipes/core/base/daemon/Cargo.toml b/recipes/core/base/daemon/Cargo.toml deleted file mode 100644 index a390eaf044..0000000000 --- a/recipes/core/base/daemon/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "daemon" -description = "Redox daemon library" -version = "0.0.0" -edition = "2024" - -[dependencies] -libc.workspace = true -libredox.workspace = true -redox-scheme.workspace = true -redox_syscall.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/daemon/src/lib.rs b/recipes/core/base/daemon/src/lib.rs deleted file mode 100644 index a16d34dc31..0000000000 --- a/recipes/core/base/daemon/src/lib.rs +++ /dev/null @@ -1,153 +0,0 @@ -//! A library for creating and managing daemons for RedoxOS. -#![feature(never_type)] - -use std::io::{self, PipeWriter, Read, Write}; -use std::os::fd::{AsRawFd, FromRawFd, OwnedFd, RawFd}; -use std::os::unix::process::CommandExt; -use std::process::Command; - -use libredox::Fd; -use redox_scheme::scheme::{SchemeAsync, SchemeSync}; -use redox_scheme::Socket; - -unsafe fn get_fd(var: &str) -> Option { - let value = match std::env::var(var) { - Ok(value) => value, - Err(_) => { - let exe = std::env::args() - .next() - .unwrap_or_else(|| "daemon".to_string()); - eprintln!("daemon: {var} not set for {exe}; readiness notification disabled"); - return None; - } - }; - let fd: RawFd = match value.parse() { - Ok(fd) => fd, - Err(err) => { - let exe = std::env::args() - .next() - .unwrap_or_else(|| "daemon".to_string()); - eprintln!("daemon: invalid {var} value {value:?} for {exe}: {err}; readiness notification disabled"); - return None; - } - }; - if unsafe { libc::fcntl(fd, libc::F_SETFD, libc::FD_CLOEXEC) } == -1 { - eprintln!( - "daemon: failed to set CLOEXEC flag for {var} fd: {}", - io::Error::last_os_error() - ); - return None; - } - Some(fd) -} - -unsafe fn pass_fd(cmd: &mut Command, env: &str, fd: OwnedFd) { - cmd.env(env, format!("{}", fd.as_raw_fd())); - unsafe { - cmd.pre_exec(move || { - // Pass notify pipe to child - if libc::fcntl(fd.as_raw_fd(), libc::F_SETFD, 0) == -1 { - Err(io::Error::last_os_error()) - } else { - Ok(()) - } - }); - } -} - -/// A long running background process that handles requests. -#[must_use = "Daemon::ready must be called"] -pub struct Daemon { - write_pipe: Option, -} - -impl Daemon { - /// Create a new daemon. - pub fn new(f: impl FnOnce(Daemon) -> !) -> ! { - let write_pipe = unsafe { get_fd("INIT_NOTIFY").map(io::PipeWriter::from_raw_fd) }; - - f(Daemon { write_pipe }) - } - - /// Notify the process that the daemon is ready to accept requests. - pub fn ready(mut self) { - if let Some(write_pipe) = self.write_pipe.as_mut() { - write_pipe.write_all(&[0]).unwrap(); - } - } - - /// Executes `Command` as a child process. - // FIXME remove once the service spawning of hwd and pcid-spawner is moved to init - #[deprecated] - pub fn spawn(mut cmd: Command) { - let (mut read_pipe, write_pipe) = io::pipe().unwrap(); - - unsafe { pass_fd(&mut cmd, "INIT_NOTIFY", write_pipe.into()) }; - - if let Err(err) = cmd.spawn() { - eprintln!("daemon: failed to execute {cmd:?}: {err}"); - return; - } - - let mut data = [0]; - match read_pipe.read_exact(&mut data) { - Ok(()) => {} - Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => { - eprintln!("daemon: {cmd:?} exited without notifying readiness"); - } - Err(err) => { - eprintln!("daemon: failed to wait for {cmd:?}: {err}"); - } - } - } -} - -/// A long running background process that handles requests using schemes. -#[must_use = "SchemeDaemon::ready must be called"] -pub struct SchemeDaemon { - write_pipe: Option, -} - -impl SchemeDaemon { - /// Create a new daemon for use with schemes. - pub fn new(f: impl FnOnce(SchemeDaemon) -> !) -> ! { - let write_pipe = unsafe { get_fd("INIT_NOTIFY").map(io::PipeWriter::from_raw_fd) }; - - f(SchemeDaemon { write_pipe }) - } - - /// Notify the process that the scheme daemon is ready to accept requests. - pub fn ready_with_fd(self, cap_fd: Fd) -> syscall::Result<()> { - if let Some(write_pipe) = self.write_pipe { - syscall::call_wo( - write_pipe.as_raw_fd() as usize, - &cap_fd.into_raw().to_ne_bytes(), - syscall::CallFlags::FD, - &[], - )?; - } - Ok(()) - } - - /// Notify the process that the synchronous scheme daemon is ready to accept requests. - pub fn ready_sync_scheme( - self, - socket: &Socket, - scheme: &mut S, - ) -> syscall::Result<()> { - let cap_id = scheme.scheme_root()?; - let cap_fd = socket.create_this_scheme_fd(0, cap_id, 0, 0)?; - self.ready_with_fd(Fd::new(cap_fd)) - } - - /// Notify the process that the asynchronous scheme daemon is ready to accept requests. - pub fn ready_async_scheme( - self, - socket: &Socket, - scheme: &mut S, - ) -> syscall::Result<()> { - let cap_id = scheme.scheme_root()?; - let cap_fd = socket.create_this_scheme_fd(0, cap_id, 0, 0)?; - self.ready_with_fd(Fd::new(cap_fd)) - } -} diff --git a/recipes/core/base/dhcpd/src/dhcp/mod.rs b/recipes/core/base/dhcpd/src/dhcp/mod.rs deleted file mode 100644 index d57f380778..0000000000 --- a/recipes/core/base/dhcpd/src/dhcp/mod.rs +++ /dev/null @@ -1,19 +0,0 @@ -#[repr(C, packed)] -pub struct Dhcp { - pub op: u8, - pub htype: u8, - pub hlen: u8, - pub hops: u8, - pub tid: u32, - pub secs: u16, - pub flags: u16, - pub ciaddr: [u8; 4], - pub yiaddr: [u8; 4], - pub siaddr: [u8; 4], - pub giaddr: [u8; 4], - pub chaddr: [u8; 16], - pub sname: [u8; 64], - pub file: [u8; 128], - pub magic: u32, - pub options: [u8; 308], -} diff --git a/recipes/core/base/dhcpd/src/main.rs b/recipes/core/base/dhcpd/src/main.rs deleted file mode 100644 index a95b703eea..0000000000 --- a/recipes/core/base/dhcpd/src/main.rs +++ /dev/null @@ -1,497 +0,0 @@ -use std::fs::{File, OpenOptions}; -use std::io::{Read, Write}; -use std::net::{SocketAddr, UdpSocket}; -use std::time::Duration; -use std::{env, process, time}; - -use dhcp::Dhcp; - -mod dhcp; - -macro_rules! try_fmt { - ($e:expr, $m:expr) => { - match $e { - Ok(ok) => ok, - Err(err) => return Err(format!("{}: {}", $m, err)), - } - }; -} - -fn get_cfg_value(path: &str) -> Result { - let path = format!("/scheme/netcfg/{path}"); - let mut file = File::open(&path).map_err(|_| format!("Can't open {path}"))?; - let mut result = String::new(); - file.read_to_string(&mut result) - .map_err(|_| format!("Can't read {path}"))?; - Ok(result) -} - -fn get_iface_cfg_value(iface: &str, cfg: &str) -> Result { - let path = format!("ifaces/{iface}/{cfg}"); - get_cfg_value(&path) -} - -fn set_cfg_value(path: &str, value: &str) -> Result<(), String> { - let path = format!("/scheme/netcfg/{path}"); - let mut file = OpenOptions::new() - .read(false) - .write(true) - .create(false) - .open(&path) - .map_err(|_| format!("Can't open {path}"))?; - file.write(value.as_bytes()) - .map(|_| ()) - .map_err(|_| format!("Can't write {value} to {path}"))?; - file.sync_data() - .map_err(|_| format!("Can't commit {value} to {path}")) -} - -fn set_iface_cfg_value(iface: &str, cfg: &str, value: &str) -> Result<(), String> { - let path = format!("ifaces/{iface}/{cfg}"); - set_cfg_value(&path, value) -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Default)] -struct MacAddr { - bytes: [u8; 6], -} - -impl MacAddr { - fn from_str(string: &str) -> Self { - MacAddr::try_parse_with_delimeter(string, ':') - .or_else(|| MacAddr::try_parse_with_delimeter(string, '-')) - .unwrap_or_default() - } - - fn try_parse_with_delimeter(string: &str, delimeter: char) -> Option { - let mut addr = MacAddr::default(); - let mut segments = 0; - - for part in string.split(delimeter) { - if segments >= addr.bytes.len() { - return None; - } - addr.bytes[segments] = match u8::from_str_radix(part, 16) { - Ok(b) => b, - _ => return None, - }; - segments += 1; - } - - if segments == addr.bytes.len() { - Some(addr) - } else { - None - } - } - - fn to_string(&self) -> String { - format!( - "{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}", - self.bytes[0], - self.bytes[1], - self.bytes[2], - self.bytes[3], - self.bytes[4], - self.bytes[5] - ) - } -} - -fn dhcp(iface: &str, verbose: bool) -> Result<(), String> { - let current_mac = MacAddr::from_str(get_iface_cfg_value(iface, "mac")?.trim()); - - let current_ip = get_iface_cfg_value(iface, "addr/list")? - .lines() - .next() - .map(|l| l.to_owned()) - .unwrap_or("0.0.0.0".to_string()); - - if verbose { - println!( - "DHCP: MAC: {} Current IP: {}", - current_mac.to_string(), - current_ip.trim() - ); - } - - let tid = try_fmt!( - time::SystemTime::now().duration_since(time::UNIX_EPOCH), - "failed to get time" - ) - .subsec_nanos(); - - let socket = try_fmt!(UdpSocket::bind(("0.0.0.0", 68)), "failed to bind udp"); - try_fmt!( - socket.connect(SocketAddr::from(([255, 255, 255, 255], 67))), - "failed to connect udp" - ); - try_fmt!( - socket.set_read_timeout(Some(Duration::new(30, 0))), - "failed to set read timeout" - ); - try_fmt!( - socket.set_write_timeout(Some(Duration::new(30, 0))), - "failed to set write timeout" - ); - - { - let mut discover = Dhcp { - op: 1, - htype: 1, - hlen: 6, - hops: 0, - tid, - secs: 0, - flags: 0x8000u16.to_be(), - ciaddr: [0, 0, 0, 0], - yiaddr: [0, 0, 0, 0], - siaddr: [0, 0, 0, 0], - giaddr: [0, 0, 0, 0], - chaddr: [ - current_mac.bytes[0], - current_mac.bytes[1], - current_mac.bytes[2], - current_mac.bytes[3], - current_mac.bytes[4], - current_mac.bytes[5], - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - ], - sname: [0; 64], - file: [0; 128], - magic: 0x63825363u32.to_be(), - options: [0; 308], - }; - - for (s, d) in [ - // DHCP Message Type (Discover) - 53, 1, 1, // End - 255, - ] - .iter() - .zip(discover.options.iter_mut()) - { - *d = *s; - } - - let discover_data = unsafe { - std::slice::from_raw_parts( - (&discover as *const Dhcp) as *const u8, - std::mem::size_of::(), - ) - }; - - let _sent = try_fmt!(socket.send(discover_data), "failed to send discover"); - - if verbose { - println!("DHCP: Sent Discover"); - } - } - - let mut offer_data = [0; 65536]; - try_fmt!(socket.recv(&mut offer_data), "failed to receive offer"); - let offer = unsafe { &*(offer_data.as_ptr() as *const Dhcp) }; - if verbose { - println!( - "DHCP: Offer IP: {:?}, Server IP: {:?}", - offer.yiaddr, offer.siaddr - ); - } - - let mut subnet_option = None; - let mut router_option = None; - let mut dns_option = None; - let mut server_id_option = None; - { - let mut options = offer.options.iter(); - while let Some(option) = options.next() { - match *option { - 0 => (), - 255 => break, - _ => { - if let Some(len) = options.next() { - if *len as usize <= options.as_slice().len() { - let data = &options.as_slice()[..*len as usize]; - for _data_i in 0..*len { - options.next(); - } - match *option { - 1 => { - if verbose { - println!("DHCP: Subnet Mask: {data:?}"); - } - if data.len() == 4 && subnet_option.is_none() { - subnet_option = Some(Vec::from(data)); - } - } - 3 => { - if verbose { - println!("DHCP: Router: {data:?}"); - } - if data.len() == 4 && router_option.is_none() { - router_option = Some(Vec::from(data)); - } - } - 6 => { - if verbose { - println!("DHCP: Domain Name Server: {data:?}"); - } - if data.len() == 4 && dns_option.is_none() { - dns_option = Some(Vec::from(data)); - } - } - 51 => { - if verbose { - println!("DHCP: Lease Time: {data:?}"); - } - } - 53 => { - if verbose { - println!("DHCP: Message Type: {data:?}"); - } - } - 54 => { - if verbose { - println!("DHCP: Server ID: {data:?}"); - } - if data.len() == 4 { - // Store the server ID - server_id_option = - Some([data[0], data[1], data[2], data[3]]); - } - } - _ => { - if verbose { - println!("DHCP: {option}: {data:?}"); - } - } - } - } - } - } - } - } - - let mask_len = if let Some(subnet) = subnet_option { - let mut subnet: u32 = (subnet[0] as u32) << 24 - | (subnet[1] as u32) << 16 - | (subnet[2] as u32) << 8 - | subnet[3] as u32; - subnet = !subnet; - subnet.leading_zeros() - } else { - 0 - }; - - let new_ips = format!( - "{}.{}.{}.{}/{}\n", - offer.yiaddr[0], offer.yiaddr[1], offer.yiaddr[2], offer.yiaddr[3], mask_len - ); - try_fmt!( - set_iface_cfg_value(iface, "addr/set", &new_ips), - "failed to set ip" - ); - - if verbose { - let new_ip = try_fmt!(get_iface_cfg_value(iface, "addr/list"), "failed to get ip"); - println!("DHCP: New IP: {}", new_ip.trim()); - } - - if let Some(router) = router_option { - let default_route = format!( - "default via {}.{}.{}.{}", - router[0], router[1], router[2], router[3] - ); - - try_fmt!( - set_cfg_value("route/add", &default_route), - "failed to set default route" - ); - - if verbose { - let new_router = try_fmt!(get_cfg_value("route/list"), "failed to get ip router"); - println!("DHCP: New Router: {}", new_router.trim()); - } - } - - if let Some(mut dns) = dns_option { - if dns[0] == 127 { - let quad9 = [9, 9, 9, 9].to_vec(); - if verbose { - println!( - "DHCP: Received sarcastic DNS suggestion {}.{}.{}.{}, using {}.{}.{}.{} instead", - dns[0], dns[1], dns[2], dns[3], quad9[0], quad9[1], quad9[2], quad9[3] - ); - } - dns = quad9; - } - - let nameserver = format!("{}.{}.{}.{}", dns[0], dns[1], dns[2], dns[3]); - - try_fmt!( - set_cfg_value("resolv/nameserver", &nameserver), - "failed to set name server" - ); - - if verbose { - let new_dns = try_fmt!(get_cfg_value("resolv/nameserver"), "failed to get dns"); - println!("DHCP: New DNS: {}", new_dns.trim()); - } - } - } - - { - let mut request = Dhcp { - op: 1, - htype: 1, - hlen: 6, - hops: 0, - tid, - secs: 0, - flags: 0, - ciaddr: [0; 4], - yiaddr: [0; 4], - siaddr: [0; 4], - giaddr: [0; 4], - chaddr: [ - current_mac.bytes[0], - current_mac.bytes[1], - current_mac.bytes[2], - current_mac.bytes[3], - current_mac.bytes[4], - current_mac.bytes[5], - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - ], - sname: [0; 64], - file: [0; 128], - magic: 0x63825363u32.to_be(), - options: [0; 308], - }; - - // If the server_id_option was None, use "0.0.0.0" - let server_id = server_id_option.unwrap_or([0, 0, 0, 0]); - - for (s, d) in [ - // DHCP Message Type (Request) - 53, - 1, - 3, - // Requested IP Address - 50, - 4, - offer.yiaddr[0], - offer.yiaddr[1], - offer.yiaddr[2], - offer.yiaddr[3], - // Server Identifier - use Option 54 from the Offer - 54, - 4, - server_id[0], - server_id[1], - server_id[2], - server_id[3], - // End - 255, - ] - .iter() - .zip(request.options.iter_mut()) - { - *d = *s; - } - - let request_data = unsafe { - std::slice::from_raw_parts( - (&request as *const Dhcp) as *const u8, - std::mem::size_of::(), - ) - }; - - let _sent = try_fmt!(socket.send(request_data), "failed to send request"); - - if verbose { - println!("DHCP: Sent Request"); - } - } - - { - let mut ack_data = [0; 65536]; - try_fmt!(socket.recv(&mut ack_data), "failed to receive ack"); - let ack = unsafe { &*(ack_data.as_ptr() as *const Dhcp) }; - if verbose { - println!( - "DHCP: Ack IP: {:?}, Server IP: {:?}", - ack.yiaddr, ack.siaddr - ); - } - } - - Ok(()) -} - -fn main() { - let mut verbose = false; - let iface = "eth0"; - - //TODO: parse iface from the args - for arg in env::args().skip(1) { - match arg.as_ref() { - "-v" => verbose = true, - _ => (), - } - } - - if let Err(err) = dhcp(iface, verbose) { - eprintln!("dhcpd: {err}"); - process::exit(1); - } -} - -#[cfg(test)] -mod test { - use super::MacAddr; - - #[test] - fn from_str_test() { - let mac = MacAddr { - bytes: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab], - }; - let empty_mac = MacAddr::default(); - - assert_eq!(mac, MacAddr::from_str("01:23:45:67:89:ab")); - assert_eq!(mac, MacAddr::from_str("1:23:45:67:89:ab")); - assert_eq!(mac, MacAddr::from_str("01:23:45:67:89:AB")); - assert_eq!(mac, MacAddr::from_str("01-23-45-67-89-ab")); - assert_eq!(empty_mac, MacAddr::from_str("")); - assert_eq!(empty_mac, MacAddr::from_str("01:23:45:67:89")); - assert_eq!(empty_mac, MacAddr::from_str("01:23:45:67:89:ab:cd")); - assert_eq!(empty_mac, MacAddr::from_str("x1:23:45:67:89:ab")); - assert_eq!(empty_mac, MacAddr::from_str("01:23-45-67-89-ab")); - assert_eq!(empty_mac, MacAddr::from_str("01-23-45-67-89-ag")); - assert_eq!(empty_mac, MacAddr::from_str("01.23.45.67.89.ab")); - assert_eq!(empty_mac, MacAddr::from_str("01234-23-45-67-89-ab")); - assert_eq!(empty_mac, MacAddr::from_str("01--23-45-67-89-ab")); - assert_eq!(empty_mac, MacAddr::from_str("12")); - assert_eq!(empty_mac, MacAddr::from_str("0:0:0:0:0:0")); - - assert_eq!(mac, MacAddr::from_str(&mac.to_string())); - assert_eq!(empty_mac, MacAddr::from_str(&empty_mac.to_string())); - } -} diff --git a/recipes/core/base/drivers/COMMUNITY-HW.md b/recipes/core/base/drivers/COMMUNITY-HW.md deleted file mode 100644 index bf91a7a4dc..0000000000 --- a/recipes/core/base/drivers/COMMUNITY-HW.md +++ /dev/null @@ -1,63 +0,0 @@ -# Community Hardware - -This document tracks the devices from developers or community that need a driver. - -This document was created because unfortunately we can't know the most sold device models of the world to measure our device porting priority, thus we will use our community data to measure our device priorities, if you find a "device model users" survey (similar to [Debian Popularity Contest](https://popcon.debian.org/) and [Steam Hardware/Software Survey](https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam)), please comment. - -If you want to contribute to this table, install [pciutils](https://mj.ucw.cz/sw/pciutils/) on your Linux or Unix-like distribution (it may have a package on your distribution), run the `lspci -v` command to see your hardware devices, their kernel drivers and give the results of these items on each device: - -- The first field (each device has an unique name for this item) -- Kernel driver -- Kernel module - -If you are unsure of what to do, you can talk with us on the [chat](https://doc.redox-os.org/book/chat.html). - -## Template - -You will use this template to insert your devices on the table. - -``` -| | | | No | -``` - -- Remove the `#` characters in the port numbers to avoid GitLab issues to be wrongly mentioned - -## Devices - -| **Device model** | **Kernel driver?** | **Kernel module?** | **There's a Redox driver?** | -|------------------|--------------------|--------------------|-----------------------------| -| Realtek RTL8821CE 802.11ac (Wi-Fi) | rtw_8821ce | rtw88_8821ce | No | -| Intel Ice Lake-LP SPI Controller | intel-spi | spi_intel_pci | No | -| Intel Ice Lake-LP SMBus Controller | i801_smbus | i2c_i801 | No | -| Intel Ice Lake-LP Smart Sound Technology Audio Controller | snd_hda_intel | snd_hda_intel, snd_sof_pci_intel_icl | No | -| Intel Ice Lake-LP Serial IO SPI Controller | intel-lpss | No | No | -| Intel Ice Lake-LP Serial IO UART Controller | intel-lpss | No | No | -| Intel Ice Lake-LP Serial IO I2C Controller | intel-lpss | No | No | -| Ice Lake-LP USB 3.1 xHCI Host Controller | xhci_hcd | No | No | -| Intel Processor Power and Thermal Controller | proc_thermal | processor_thermal_device_pci_legacy | No | -| Intel Device 8a02 | icl_uncore | No | No | -| Iris Plus Graphics G1 (Ice Lake) | i915 | i915 | No | -| Intel Corporation Raptor Lake-P 6p+8e cores Host Bridge/DRAM Controller | No | No | No | -| Intel Corporation Raptor Lake PCI Express 5.0 Graphics Port (PEG010) (prog-if 00 [Normal decode]) | pcieport | No | No | -| Intel Corporation Raptor Lake-P [UHD Graphics] (rev 04) (prog-if 00 [VGA controller]) | i915 | i915 | No | -| Intel Corporation Raptor Lake Dynamic Platform and Thermal Framework Processor Participant | proc_thermal_pci | processor_thermal_device_pci | No | -| Intel Corporation Raptor Lake PCIe 4.0 Graphics Port (prog-if 00 [Normal decode]) | pcieport | No | No | -| Intel Corporation Raptor Lake-P Thunderbolt 4 PCI Express Root Port 0 (prog-if 00 [Normal decode]) | pcieport | No | No | -| Intel Corporation GNA Scoring Accelerator module | No | No | No | -| Intel Corporation Raptor Lake-P Thunderbolt 4 USB Controller (prog-if 30 [XHCI]) | xhci_hcd | xhci_pci | No | -| Intel Corporation Raptor Lake-P Thunderbolt 4 NHI 0 (prog-if 40 [USB4 Host Interface]) | thunderbolt | thunderbolt | No | -| Intel Corporation Raptor Lake-P Thunderbolt 4 NHI 1 (prog-if 40 [USB4 Host Interface]) | thunderbolt | thunderbolt | No | -| Intel Corporation Alder Lake PCH USB 3.2 xHCI Host Controller (rev 01) (prog-if 30 [XHCI]) | xhci_hcd | xhci_pci | No | -| Intel Corporation Alder Lake PCH Shared SRAM (rev 01) | No | No | No | -| Intel Corporation Raptor Lake PCH CNVi WiFi (rev 01) | iwlwifi | iwlwifi | No | -| Intel Corporation Alder Lake PCH Serial IO I2C Controller #0 (rev 01) | intel-lpss | intel_lpss_pci | No | -| Intel Corporation Alder Lake PCH HECI Controller (rev 01) | mei_me | mei_me | No | -| Intel Corporation Device 51b8 (rev 01) (prog-if 00 [Normal decode]) | pcieport | No | No | -| Intel Corporation Alder Lake-P PCH PCIe Root Port 6 (rev 01) (prog-if 00 [Normal decode]) | pcieport | No | No | -| Intel Corporation Raptor Lake LPC/eSPI Controller (rev 01) | No | No | No | -| Intel Corporation Raptor Lake-P/U/H cAVS (rev 01) (prog-if 80) | sof-audio-pci-intel-tgl | snd_hda_intel, snd_sof_pci_intel_tgl | No | -| Intel Corporation Alder Lake PCH-P SMBus Host Controller | i801_smbus | i2c_i801 | No | -| Intel Corporation Alder Lake-P PCH SPI Controller (rev 01) | intel-spi | spi_intel_pci | No | -| NVIDIA Corporation GA107GLM [RTX A1000 6GB Laptop GPU] (rev a1) | nvidia | nouveau, nvidia_drm, nvidia | No | -| SK hynix Platinum P41/PC801 NVMe Solid State Drive (prog-if 02 [NVM Express]) | nvme | nvme | No | -| Realtek Semiconductor Co., Ltd. RTS5261 PCI Express Card Reader (rev 01) | rtsx_pci | rtsx_pci | No | diff --git a/recipes/core/base/drivers/README.md b/recipes/core/base/drivers/README.md deleted file mode 100644 index 5f33f2c70a..0000000000 --- a/recipes/core/base/drivers/README.md +++ /dev/null @@ -1,160 +0,0 @@ -# Drivers - -- [Libraries](#libraries) -- [Services](#services) -- [Hardware Interfaces](#hardware-interfaces) -- [Devices](#devices) - - [CPU](#cpu) - - [Controllers](#controllers) - - [Storage](#storage) - - [Graphics](#graphics) - - [Input](#input) - - [Sound](#sound) - - [Networking](#networking) - - [Virtualization](#virtualization) -- [System Interfaces](#system-interfaces) -- [System Calls](#system-calls) -- [Schemes](#schemes) -- [Contribution Details](#contribution-details) - -## Libraries - -- amlserde - Library to provide serialization/deserialization of the AML symbol table from ACPI -- common - Library with shared driver code -- executor - Library to run Rust futures and integrate the executor in an interrupt+queue model without a separated reactor thread -- [graphics/console-draw](graphics/console-draw/) - Library with shared terminal drawing code -- [graphics/driver-graphics](graphics/driver-graphics/) - Library with shared graphics code -- [graphics/graphics-ipc](graphics/graphics-ipc/) - Library with graphics IPC shared code -- [net/driver-network](net/driver-network/) - Library with shared networking code -- [storage/partitionlib](storage/partitionlib/) - Library with MBR and GPT code -- [storage/driver-block](storage/driver-block/) - Library with shared storage code -- virtio-core - VirtIO driver library - -## Services - -- [graphics/fbbootlogd](graphics/fbbootlogd/) - Daemon for boot log drawing -- [graphics/fbcond](graphics/fbcond/) - Terminal daemon -- hwd - Daemon that handle the ACPI and DeviceTree booting -- inputd - Multiplexes input from multiple input drivers and provides that to Orbital -- pcid-spawner - Daemon for PCI-based device driver spawn -- [storage/lived](storage/lived/) - Daemon for live disk -- redoxerd - Daemon that send/receive terminal text between the host system and QEMU - -## Hardware Interfaces - -- acpid - ACPI interface driver -- pcid - PCI and PCI Express driver - -## Devices - -### CPU - -- rtcd - x86 Real Time Clock driver - -### Controllers - -- [usb/xhcid](usb/xhcid/) - xHCI USB controller driver - -### Storage - -- [storage/ahcid](storage/ahcid/) - AHCI (SATA) driver -- [storage/bcm2835-sdhcid](storage/bcm2835-sdhcid/) - BCM2835 storage driver -- [storage/ided](storage/ided/) - PATA (IDE) driver -- [storage/nvmed](storage/nvmed/) - NVMe driver -- [storage/virtio-blkd](storage/virtio-blkd/) - VirtIO block device driver -- [storage/usbscsid](storage/usbscsid/) - USB SCSI driver - -### Graphics - -- [graphics/ihdgd](graphics/ihdgd/) - Intel graphics driver -- [graphics/vesad](graphics/vesad/) - VESA video driver -- [graphics/virtio-gpud](graphics/virtio-gpud/) - VirtIO-GPU device driver - -### Input - -- [input/ps2d](input/ps2d/) - PS/2 interface driver -- [input/usbhidd](input/usbhidd/) - USB HID driver -- [usb/usbhubd](usb/usbhubd/) - USB Hub driver -- [usb/usbctl](usb/usbctl/) - TODO - -### Sound - -- [audio/ac97d](audio/ac97d/) - AC'97 codec driver -- [audio/ihdad](audio/ihdad/) - Intel HD Audio chipset driver -- [audio/sb16d](audio/sb16d/) - Sound Blaster sound card driver - -### Networking - -- [net/e1000d](net/e1000d/) - Intel Gigabit ethernet driver -- [net/ixgbed](net/ixgbed/) - Intel 10 Gigabit ethernet driver -- [net/rtl8139d](net/rtl8139d/), [net/rtl8168d](net/rtl8168d/) - Realtek ethernet drivers -- [net/virtio-netd](net/virtio-netd/) - VirtIO network device driver - -### Virtualization - -- vboxd - VirtualBox driver - -Some drivers are work-in-progress and incomplete, read [this](https://gitlab.redox-os.org/redox-os/base/-/issues/56) tracking issue to verify. - -## System Interfaces - -This section explain the system interfaces used by drivers. - -### System Calls - -- `iopl` : system call that sets the I/O privilege level. x86 has four privilege rings (0/1/2/3), of which the kernel runs in ring 0 and userspace in ring 3. IOPL can only be changed by the kernel, for obvious security reasons, and therefore the Redox kernel needs root to set it. It is unique for each process. Processes with IOPL=3 can access I/O ports, and the kernel can access them as well. - -### Schemes - -- `/scheme/memory/physical` : Allows mapping physical memory frames to driver-accessible virtual memory pages, with various available memory types: - - `/scheme/memory/physical` : Default memory type (currently writeback) - - `/scheme/memory/physical@wb` Writeback cached memory - - `/scheme/memory/physical@uc` : Uncacheable memory - - `/scheme/memory/physical@wc` : Write-combining memory -- `/scheme/irq` : Allows getting events from interrupts. It is used primarily by listening for its file descriptors using the `/scheme/event` scheme. - -## Contribution Details - -### Driver Design - -A device driver on Redox is an user-space daemon that use system calls and schemes to work, while operating systems with monolithic kernels drivers use internal kernel APIs instead of common program APIs. - -If you want to port a driver from a monolithic operating system to Redox you will need to rewrite the driver with reverse enginnering of the code logic, because the logic is adapted to internal kernel APIs (it's a hard task if the device is complex, datasheets are much more easy). - -### Write a Driver - -Datasheets are preferable (much more easy depending on device complexity), when they are freely available. Be aware that datasheets are often provided under a [Non-Disclosure Agreement](https://en.wikipedia.org/wiki/Non-disclosure_agreement) from hardware vendors, which can affect the ability to create an MIT-licensed driver. - -If datasheets aren't available you need to do reverse-engineering of BSD or Linux drivers (if you want use a Linux driver as reference for your Redox driver please ask in the [Chat](https://doc.redox-os.org/book/chat.html) before the implementation to know/satisfy the license requirements and not waste your time, also if you use a BSD driver not licensed as BSD as reference). - -### Libraries - -You should use the [redox-scheme](https://crates.io/crates/redox-scheme) and [redox_event](https://crates.io/crates/redox_event) libraries to create your drivers, you can also read the [example driver](https://gitlab.redox-os.org/redox-os/exampled) or read the code of other drivers with the same type of your device. - -Before testing your changes be aware of [this](https://doc.redox-os.org/book/coding-and-building.html#how-to-update-initfs). - -### References - -If you want to reverse enginner the existing drivers, you can access the BSD code using these links: - -- [FreeBSD drivers](https://github.com/freebsd/freebsd-src/tree/main/sys/dev) -- [NetBSD drivers](https://github.com/NetBSD/src/tree/trunk/sys/dev) -- [OpenBSD drivers](https://github.com/openbsd/src/tree/master/sys/dev) - -## How To Contribute - -To learn how to contribute to this system component you need to read the following document: - -- [CONTRIBUTING.md](https://gitlab.redox-os.org/redox-os/redox/-/blob/master/CONTRIBUTING.md) - -## Development - -To learn how to do development with this system component inside the Redox build system you need to read the [Build System](https://doc.redox-os.org/book/build-system-reference.html) and [Coding and Building](https://doc.redox-os.org/book/coding-and-building.html) pages. - -### How To Build - -To build this system component you need to download the Redox build system, you can learn how to do it on the [Building Redox](https://doc.redox-os.org/book/podman-build.html) page. - -This is necessary because they only work with cross-compilation to a Redox virtual machine or real hardware, but you can do some testing from Linux. - -[Back to top](#drivers) diff --git a/recipes/core/base/drivers/acpi-resource/Cargo.toml b/recipes/core/base/drivers/acpi-resource/Cargo.toml deleted file mode 100644 index f30c6d023c..0000000000 --- a/recipes/core/base/drivers/acpi-resource/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "acpi-resource" -description = "Shared ACPI resource template decoder" -version = "0.0.1" -authors = ["Red Bear OS"] -repository = "https://gitlab.redox-os.org/redox-os/drivers" -categories = ["hardware-support"] -license = "MIT/Apache-2.0" -edition = "2021" - -[dependencies] -serde.workspace = true -thiserror.workspace = true diff --git a/recipes/core/base/drivers/acpi-resource/src/lib.rs b/recipes/core/base/drivers/acpi-resource/src/lib.rs deleted file mode 100644 index 57ae4b4b86..0000000000 --- a/recipes/core/base/drivers/acpi-resource/src/lib.rs +++ /dev/null @@ -1,688 +0,0 @@ -use serde::{Deserialize, Serialize}; -use thiserror::Error; - -const SMALL_IRQ: u8 = 0x20; -const SMALL_END_TAG: u8 = 0x78; - -const LARGE_MEMORY32: u8 = 0x85; -const LARGE_FIXED_MEMORY32: u8 = 0x86; -const LARGE_ADDRESS32: u8 = 0x87; -const LARGE_EXTENDED_IRQ: u8 = 0x89; -const LARGE_ADDRESS64: u8 = 0x8A; -const LARGE_GPIO: u8 = 0x8C; -const LARGE_SERIAL_BUS: u8 = 0x8E; - -const SERIAL_BUS_I2C: u8 = 1; -const I2C_TYPE_DATA_LEN: usize = 6; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum InterruptTrigger { - Edge, - Level, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum InterruptPolarity { - ActiveHigh, - ActiveLow, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum AddressResourceType { - MemoryRange, - IoRange, - BusNumberRange, - Unknown(u8), -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct ResourceSource { - pub index: u8, - pub source: String, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct IrqDescriptor { - pub interrupts: Vec, - pub triggering: InterruptTrigger, - pub polarity: InterruptPolarity, - pub shareable: bool, - pub wake_capable: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct ExtendedIrqDescriptor { - pub producer_consumer: bool, - pub interrupts: Vec, - pub triggering: InterruptTrigger, - pub polarity: InterruptPolarity, - pub shareable: bool, - pub wake_capable: bool, - pub resource_source: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct GpioDescriptor { - pub revision_id: u8, - pub producer_consumer: bool, - pub pin_config: u8, - pub shareable: bool, - pub wake_capable: bool, - pub io_restriction: u8, - pub triggering: InterruptTrigger, - pub polarity: InterruptPolarity, - pub drive_strength: u16, - pub debounce_timeout: u16, - pub pins: Vec, - pub resource_source: Option, - pub vendor_data: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct I2cSerialBusDescriptor { - pub revision_id: u8, - pub producer_consumer: bool, - pub slave_mode: bool, - pub connection_sharing: bool, - pub type_revision_id: u8, - pub access_mode_10bit: bool, - pub slave_address: u16, - pub connection_speed: u32, - pub resource_source: Option, - pub vendor_data: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Memory32RangeDescriptor { - pub write_protect: bool, - pub minimum: u32, - pub maximum: u32, - pub alignment: u32, - pub address_length: u32, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct FixedMemory32Descriptor { - pub write_protect: bool, - pub address: u32, - pub address_length: u32, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Address32Descriptor { - pub resource_type: AddressResourceType, - pub producer_consumer: bool, - pub decode: bool, - pub min_address_fixed: bool, - pub max_address_fixed: bool, - pub specific_flags: u8, - pub granularity: u32, - pub minimum: u32, - pub maximum: u32, - pub translation_offset: u32, - pub address_length: u32, - pub resource_source: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Address64Descriptor { - pub resource_type: AddressResourceType, - pub producer_consumer: bool, - pub decode: bool, - pub min_address_fixed: bool, - pub max_address_fixed: bool, - pub specific_flags: u8, - pub granularity: u64, - pub minimum: u64, - pub maximum: u64, - pub translation_offset: u64, - pub address_length: u64, - pub resource_source: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum ResourceDescriptor { - Irq(IrqDescriptor), - ExtendedIrq(ExtendedIrqDescriptor), - GpioInt(GpioDescriptor), - GpioIo(GpioDescriptor), - I2cSerialBus(I2cSerialBusDescriptor), - Memory32Range(Memory32RangeDescriptor), - FixedMemory32(FixedMemory32Descriptor), - Address32(Address32Descriptor), - Address64(Address64Descriptor), -} - -#[derive(Debug, Error, PartialEq, Eq)] -pub enum ResourceDecodeError { - #[error("descriptor at offset {offset} overruns the resource template")] - TruncatedDescriptor { offset: usize }, - - #[error("unsupported small descriptor length {length} for tag {tag:#04x} at offset {offset}")] - InvalidSmallLength { - offset: usize, - tag: u8, - length: usize, - }, - - #[error("descriptor {descriptor} at offset {offset} is shorter than {minimum} bytes")] - InvalidLargeLength { - offset: usize, - descriptor: &'static str, - minimum: usize, - }, - - #[error("descriptor {descriptor} at offset {offset} has an invalid internal offset")] - InvalidInternalOffset { - offset: usize, - descriptor: &'static str, - }, -} - -pub fn decode_resource_template( - bytes: &[u8], -) -> Result, ResourceDecodeError> { - let mut resources = Vec::new(); - let mut offset = 0usize; - - while offset < bytes.len() { - let descriptor = *bytes - .get(offset) - .ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?; - - if descriptor & 0x80 == 0 { - let length = usize::from(descriptor & 0x07); - let end = offset + 1 + length; - let desc = bytes - .get(offset..end) - .ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?; - let body = &desc[1..]; - - match descriptor & 0x78 { - SMALL_IRQ => resources.push(ResourceDescriptor::Irq(parse_irq(body, offset)?)), - SMALL_END_TAG => break, - _ => {} - } - - offset = end; - continue; - } - - let length = usize::from(read_u16(bytes, offset + 1)?); - let end = offset + 3 + length; - let desc = bytes - .get(offset..end) - .ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?; - let body = &desc[3..]; - - match descriptor { - LARGE_MEMORY32 => resources.push(ResourceDescriptor::Memory32Range(parse_memory32( - body, offset, - )?)), - LARGE_FIXED_MEMORY32 => resources.push(ResourceDescriptor::FixedMemory32( - parse_fixed_memory32(body, offset)?, - )), - LARGE_ADDRESS32 => { - resources.push(ResourceDescriptor::Address32(parse_address32( - desc, body, offset, - )?)); - } - LARGE_ADDRESS64 => { - resources.push(ResourceDescriptor::Address64(parse_address64( - desc, body, offset, - )?)); - } - LARGE_EXTENDED_IRQ => resources.push(ResourceDescriptor::ExtendedIrq( - parse_extended_irq(desc, body, offset)?, - )), - LARGE_GPIO => { - let (is_interrupt, descriptor) = parse_gpio(desc, body, offset)?; - resources.push(if is_interrupt { - ResourceDescriptor::GpioInt(descriptor) - } else { - ResourceDescriptor::GpioIo(descriptor) - }); - } - LARGE_SERIAL_BUS => { - if let Some(descriptor) = parse_i2c_serial_bus(desc, body, offset)? { - resources.push(ResourceDescriptor::I2cSerialBus(descriptor)); - } - } - _ => {} - } - - offset = end; - } - - Ok(resources) -} - -fn parse_irq(body: &[u8], offset: usize) -> Result { - if body.len() != 2 && body.len() != 3 { - return Err(ResourceDecodeError::InvalidSmallLength { - offset, - tag: SMALL_IRQ, - length: body.len(), - }); - } - - let mask = u16::from_le_bytes([body[0], body[1]]); - let flags = body.get(2).copied().unwrap_or(0); - let interrupts = (0..16) - .filter(|irq| mask & (1 << irq) != 0) - .map(|irq| irq as u8) - .collect(); - - Ok(IrqDescriptor { - interrupts, - triggering: if flags & 0x01 != 0 { - InterruptTrigger::Level - } else { - InterruptTrigger::Edge - }, - polarity: if flags & 0x08 != 0 { - InterruptPolarity::ActiveLow - } else { - InterruptPolarity::ActiveHigh - }, - shareable: flags & 0x10 != 0, - wake_capable: flags & 0x20 != 0, - }) -} - -fn parse_extended_irq( - desc: &[u8], - body: &[u8], - offset: usize, -) -> Result { - ensure_length(body, 2, offset, "ExtendedIrq")?; - - let flags = body[0]; - let count = usize::from(body[1]); - let ints_len = count * 4; - ensure_length(body, 2 + ints_len, offset, "ExtendedIrq")?; - - let interrupts = (0..count) - .map(|index| read_u32(body, 2 + index * 4)) - .collect::, _>>()?; - let resource_source = if body.len() > 2 + ints_len { - Some(parse_source_inline(&body[2 + ints_len..])) - } else { - None - }; - - let _ = desc; - - Ok(ExtendedIrqDescriptor { - producer_consumer: flags & 0x01 != 0, - triggering: if flags & 0x02 != 0 { - InterruptTrigger::Level - } else { - InterruptTrigger::Edge - }, - polarity: if flags & 0x04 != 0 { - InterruptPolarity::ActiveLow - } else { - InterruptPolarity::ActiveHigh - }, - shareable: flags & 0x08 != 0, - wake_capable: flags & 0x10 != 0, - interrupts, - resource_source, - }) -} - -fn parse_gpio( - desc: &[u8], - body: &[u8], - offset: usize, -) -> Result<(bool, GpioDescriptor), ResourceDecodeError> { - ensure_length(body, 20, offset, "Gpio")?; - - let connection_type = body[1]; - let flags = read_u16(body, 2)?; - let int_flags = read_u16(body, 4)?; - let pin_table_offset = usize::from(read_u16(body, 11)?); - let resource_source_index = body[13]; - let resource_source_offset = usize::from(read_u16(body, 14)?); - let vendor_offset = usize::from(read_u16(body, 16)?); - let vendor_length = usize::from(read_u16(body, 18)?); - - let pins_end = min_nonzero([resource_source_offset, vendor_offset, desc.len()]); - let pins = parse_u16_list(desc, pin_table_offset, pins_end, offset, "Gpio")?; - let resource_source = parse_source_absolute( - desc, - resource_source_offset, - min_nonzero([vendor_offset, desc.len()]), - resource_source_index, - offset, - "Gpio", - )?; - let vendor_data = parse_blob_absolute(desc, vendor_offset, vendor_length, offset, "Gpio")?; - - Ok(( - connection_type == 0, - GpioDescriptor { - revision_id: body[0], - producer_consumer: flags & 0x0001 != 0, - pin_config: body[6], - shareable: int_flags & 0x0008 != 0, - wake_capable: int_flags & 0x0010 != 0, - io_restriction: (int_flags & 0x0003) as u8, - triggering: if int_flags & 0x0001 != 0 { - InterruptTrigger::Level - } else { - InterruptTrigger::Edge - }, - polarity: if int_flags & 0x0002 != 0 { - InterruptPolarity::ActiveLow - } else { - InterruptPolarity::ActiveHigh - }, - drive_strength: read_u16(body, 7)?, - debounce_timeout: read_u16(body, 9)?, - pins, - resource_source, - vendor_data, - }, - )) -} - -fn parse_i2c_serial_bus( - desc: &[u8], - body: &[u8], - offset: usize, -) -> Result, ResourceDecodeError> { - ensure_length(body, 15, offset, "SerialBus")?; - if body[2] != SERIAL_BUS_I2C { - return Ok(None); - } - - let type_data_length = usize::from(read_u16(body, 7)?); - if type_data_length < I2C_TYPE_DATA_LEN { - return Err(ResourceDecodeError::InvalidLargeLength { - offset, - descriptor: "I2cSerialBus", - minimum: 15, - }); - } - - let vendor_length = type_data_length - I2C_TYPE_DATA_LEN; - let vendor_data = parse_blob_absolute(desc, 18, vendor_length, offset, "I2cSerialBus")?; - let resource_source = parse_source_absolute( - desc, - 12 + type_data_length, - desc.len(), - body[1], - offset, - "I2cSerialBus", - )?; - - Ok(Some(I2cSerialBusDescriptor { - revision_id: body[0], - producer_consumer: body[3] & 0x02 != 0, - slave_mode: body[3] & 0x01 != 0, - connection_sharing: body[3] & 0x04 != 0, - type_revision_id: body[6], - access_mode_10bit: read_u16(body, 4)? & 0x0001 != 0, - connection_speed: read_u32(body, 9)?, - slave_address: read_u16(body, 13)?, - resource_source, - vendor_data, - })) -} - -fn parse_memory32( - body: &[u8], - offset: usize, -) -> Result { - ensure_length(body, 17, offset, "Memory32Range")?; - Ok(Memory32RangeDescriptor { - write_protect: body[0] & 0x01 != 0, - minimum: read_u32(body, 1)?, - maximum: read_u32(body, 5)?, - alignment: read_u32(body, 9)?, - address_length: read_u32(body, 13)?, - }) -} - -fn parse_fixed_memory32( - body: &[u8], - offset: usize, -) -> Result { - ensure_length(body, 9, offset, "FixedMemory32")?; - Ok(FixedMemory32Descriptor { - write_protect: body[0] & 0x01 != 0, - address: read_u32(body, 1)?, - address_length: read_u32(body, 5)?, - }) -} - -fn parse_address32( - desc: &[u8], - body: &[u8], - offset: usize, -) -> Result { - ensure_length(body, 23, offset, "Address32")?; - Ok(Address32Descriptor { - resource_type: parse_address_type(body[0]), - producer_consumer: body[1] & 0x01 != 0, - decode: body[1] & 0x02 != 0, - min_address_fixed: body[1] & 0x04 != 0, - max_address_fixed: body[1] & 0x08 != 0, - specific_flags: body[2], - granularity: read_u32(body, 3)?, - minimum: read_u32(body, 7)?, - maximum: read_u32(body, 11)?, - translation_offset: read_u32(body, 15)?, - address_length: read_u32(body, 19)?, - resource_source: if desc.len() > 26 { - parse_source_absolute(desc, 26, desc.len(), desc[26], offset, "Address32")? - } else { - None - }, - }) -} - -fn parse_address64( - desc: &[u8], - body: &[u8], - offset: usize, -) -> Result { - ensure_length(body, 43, offset, "Address64")?; - Ok(Address64Descriptor { - resource_type: parse_address_type(body[0]), - producer_consumer: body[1] & 0x01 != 0, - decode: body[1] & 0x02 != 0, - min_address_fixed: body[1] & 0x04 != 0, - max_address_fixed: body[1] & 0x08 != 0, - specific_flags: body[2], - granularity: read_u64(body, 3)?, - minimum: read_u64(body, 11)?, - maximum: read_u64(body, 19)?, - translation_offset: read_u64(body, 27)?, - address_length: read_u64(body, 35)?, - resource_source: if desc.len() > 46 { - parse_source_absolute(desc, 46, desc.len(), desc[46], offset, "Address64")? - } else { - None - }, - }) -} - -fn ensure_length( - body: &[u8], - minimum: usize, - offset: usize, - descriptor: &'static str, -) -> Result<(), ResourceDecodeError> { - if body.len() < minimum { - return Err(ResourceDecodeError::InvalidLargeLength { - offset, - descriptor, - minimum, - }); - } - Ok(()) -} - -fn parse_source_inline(bytes: &[u8]) -> ResourceSource { - let index = bytes.first().copied().unwrap_or(0); - let source = bytes.get(1..).map(parse_nul_string).unwrap_or_default(); - ResourceSource { index, source } -} - -fn parse_source_absolute( - desc: &[u8], - start: usize, - end: usize, - index: u8, - offset: usize, - descriptor: &'static str, -) -> Result, ResourceDecodeError> { - if start == 0 || start >= end || start > desc.len() { - return Ok(None); - } - let slice = desc - .get(start..end) - .ok_or(ResourceDecodeError::InvalidInternalOffset { offset, descriptor })?; - Ok(Some(ResourceSource { - index, - source: parse_nul_string(slice), - })) -} - -fn parse_blob_absolute( - desc: &[u8], - start: usize, - length: usize, - offset: usize, - descriptor: &'static str, -) -> Result, ResourceDecodeError> { - if start == 0 || length == 0 { - return Ok(Vec::new()); - } - let end = start + length; - Ok(desc - .get(start..end) - .ok_or(ResourceDecodeError::InvalidInternalOffset { offset, descriptor })? - .to_vec()) -} - -fn parse_u16_list( - desc: &[u8], - start: usize, - end: usize, - offset: usize, - descriptor: &'static str, -) -> Result, ResourceDecodeError> { - if start == 0 || start >= end || start > desc.len() { - return Ok(Vec::new()); - } - let slice = desc - .get(start..end) - .ok_or(ResourceDecodeError::InvalidInternalOffset { offset, descriptor })?; - if slice.len() % 2 != 0 { - return Err(ResourceDecodeError::InvalidInternalOffset { offset, descriptor }); - } - slice - .chunks_exact(2) - .map(|chunk| Ok(u16::from_le_bytes([chunk[0], chunk[1]]))) - .collect() -} - -fn parse_nul_string(bytes: &[u8]) -> String { - let end = bytes - .iter() - .position(|byte| *byte == 0) - .unwrap_or(bytes.len()); - String::from_utf8_lossy(&bytes[..end]).to_string() -} - -fn parse_address_type(value: u8) -> AddressResourceType { - match value { - 0 => AddressResourceType::MemoryRange, - 1 => AddressResourceType::IoRange, - 2 => AddressResourceType::BusNumberRange, - other => AddressResourceType::Unknown(other), - } -} - -fn read_u16(bytes: &[u8], offset: usize) -> Result { - let slice = bytes - .get(offset..offset + 2) - .ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?; - Ok(u16::from_le_bytes([slice[0], slice[1]])) -} - -fn read_u32(bytes: &[u8], offset: usize) -> Result { - let slice = bytes - .get(offset..offset + 4) - .ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?; - Ok(u32::from_le_bytes([slice[0], slice[1], slice[2], slice[3]])) -} - -fn read_u64(bytes: &[u8], offset: usize) -> Result { - let slice = bytes - .get(offset..offset + 8) - .ok_or(ResourceDecodeError::TruncatedDescriptor { offset })?; - Ok(u64::from_le_bytes([ - slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7], - ])) -} - -fn min_nonzero(values: [usize; N]) -> usize { - values - .into_iter() - .filter(|value| *value != 0) - .min() - .unwrap_or(0) -} - -#[cfg(test)] -mod tests { - use super::{decode_resource_template, ResourceDescriptor}; - - #[test] - fn decodes_small_irq_descriptor() { - let resources = decode_resource_template(&[0x23, 0x0A, 0x00, 0x19, 0x79, 0x00]).unwrap(); - - assert!(matches!( - &resources[0], - ResourceDescriptor::Irq(descriptor) - if descriptor.interrupts == vec![1, 3] - && descriptor.shareable - && descriptor.wake_capable == false - )); - } - - #[test] - fn decodes_i2c_serial_bus_descriptor() { - let template = [ - 0x8E, 0x14, 0x00, 0x01, 0x02, 0x01, 0x02, 0x00, 0x00, 0x01, 0x06, 0x00, 0x80, 0x1A, - 0x06, 0x00, 0x15, 0x00, b'I', b'2', b'C', b'0', 0x00, 0x79, 0x00, - ]; - let resources = decode_resource_template(&template).unwrap(); - - assert!(matches!( - &resources[0], - ResourceDescriptor::I2cSerialBus(descriptor) - if descriptor.connection_speed == 400_000 - && descriptor.slave_address == 0x15 - && descriptor.resource_source.as_ref().map(|source| source.source.as_str()) - == Some("I2C0") - )); - } - - #[test] - fn decodes_gpio_interrupt_descriptor() { - let template = [ - 0x8C, 0x1B, 0x00, 0x01, 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, - 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x12, b'\\', b'_', b'S', b'B', - 0x00, 0x79, 0x00, - ]; - let resources = decode_resource_template(&template).unwrap(); - - assert!(matches!(&resources[0], ResourceDescriptor::GpioInt(_))); - } -} diff --git a/recipes/core/base/drivers/acpid/Cargo.toml b/recipes/core/base/drivers/acpid/Cargo.toml deleted file mode 100644 index 737fe34c68..0000000000 --- a/recipes/core/base/drivers/acpid/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "acpid" -description = "ACPI daemon" -version = "0.1.0" -authors = ["4lDO2 <4lDO2@protonmail.com>"] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -acpi.workspace = true -arrayvec = "0.7.6" -log.workspace = true -num-derive = "0.3" -num-traits = "0.2" -parking_lot.workspace = true -plain.workspace = true -redox_syscall.workspace = true -redox_event.workspace = true -rustc-hash = "1.1.0" -thiserror.workspace = true -ron.workspace = true -serde.workspace = true - -amlserde = { path = "../amlserde" } -common = { path = "../common" } -daemon = { path = "../../daemon" } -libredox.workspace = true -redox-scheme.workspace = true -scheme-utils = { path = "../../scheme-utils" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/acpid/src/acpi.rs b/recipes/core/base/drivers/acpid/src/acpi.rs deleted file mode 100644 index 3521bfc7b3..0000000000 --- a/recipes/core/base/drivers/acpid/src/acpi.rs +++ /dev/null @@ -1,874 +0,0 @@ -use acpi::aml::object::{Object, WrappedObject}; -use acpi::aml::op_region::{RegionHandler, RegionSpace}; -use rustc_hash::FxHashMap; -use std::convert::{TryFrom, TryInto}; -use std::error::Error; -use std::ops::Deref; -use std::str::FromStr; -use std::sync::{Arc, Mutex}; -use std::{fmt, mem}; -use syscall::PAGE_SIZE; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use common::io::{Io, Pio}; - -use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; -use thiserror::Error; - -use acpi::{ - aml::{namespace::AmlName, AmlError, Interpreter}, - platform::AcpiPlatform, - AcpiTables, -}; -use amlserde::aml_serde_name::aml_to_symbol; -use amlserde::{AmlSerde, AmlSerdeValue}; - -#[cfg(target_arch = "x86_64")] -pub mod dmar; -use crate::aml_physmem::{AmlPageCache, AmlPhysMemHandler}; - -/// The raw SDT header struct, as defined by the ACPI specification. -#[derive(Copy, Clone, Debug)] -#[repr(C, packed)] -pub struct SdtHeader { - pub signature: [u8; 4], - pub length: u32, - pub revision: u8, - pub checksum: u8, - pub oem_id: [u8; 6], - pub oem_table_id: [u8; 8], - pub oem_revision: u32, - pub creator_id: u32, - pub creator_revision: u32, -} -unsafe impl plain::Plain for SdtHeader {} - -impl SdtHeader { - pub fn signature(&self) -> SdtSignature { - SdtSignature { - signature: self.signature, - oem_id: self.oem_id, - oem_table_id: self.oem_table_id, - } - } - pub fn length(&self) -> usize { - self.length - .try_into() - .expect("expected usize to be at least 32 bits") - } -} - -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct SdtSignature { - pub signature: [u8; 4], - pub oem_id: [u8; 6], - pub oem_table_id: [u8; 8], -} - -impl fmt::Display for SdtSignature { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}-{}-{}", - String::from_utf8_lossy(&self.signature), - String::from_utf8_lossy(&self.oem_id), - String::from_utf8_lossy(&self.oem_table_id) - ) - } -} - -#[derive(Debug, Error)] -pub enum TablePhysLoadError { - // TODO: Make syscall::Error implement std::error::Error, when enabling a Cargo feature. - #[error("i/o error: {0}")] - Io(#[from] std::io::Error), - - #[error("invalid SDT: {0}")] - Validity(#[from] InvalidSdtError), -} -#[derive(Debug, Error)] -pub enum InvalidSdtError { - #[error("invalid size")] - InvalidSize, - - #[error("invalid checksum")] - BadChecksum, -} - -struct PhysmapGuard { - virt: *const u8, - size: usize, -} -impl PhysmapGuard { - fn map(page: usize, page_count: usize) -> std::io::Result { - let size = page_count * PAGE_SIZE; - let virt = unsafe { - common::physmap(page, size, common::Prot::RO, common::MemoryType::default()) - .map_err(|error| std::io::Error::from_raw_os_error(error.errno()))? - }; - - Ok(Self { - virt: virt as *const u8, - size, - }) - } -} -impl Deref for PhysmapGuard { - type Target = [u8]; - - fn deref(&self) -> &Self::Target { - unsafe { std::slice::from_raw_parts(self.virt as *const u8, self.size) } - } -} -impl Drop for PhysmapGuard { - fn drop(&mut self) { - unsafe { - let _ = libredox::call::munmap(self.virt as *mut (), self.size); - } - } -} - -#[derive(Clone)] -pub struct Sdt(Arc<[u8]>); - -impl Sdt { - pub fn new(slice: Arc<[u8]>) -> Result { - let header = match plain::from_bytes::(&slice) { - Ok(header) => header, - Err(plain::Error::TooShort) => return Err(InvalidSdtError::InvalidSize), - Err(plain::Error::BadAlignment) => { - log::error!("acpid: plain::from_bytes failed due to alignment, but SdtHeader is #[repr(packed)] - internal inconsistency"); - return Err(InvalidSdtError::InvalidSize); - } - }; - - if header.length() != slice.len() { - return Err(InvalidSdtError::InvalidSize); - } - - let checksum = slice - .iter() - .copied() - .fold(0_u8, |current_sum, item| current_sum.wrapping_add(item)); - - if checksum != 0 { - return Err(InvalidSdtError::BadChecksum); - } - - Ok(Self(slice)) - } - pub fn load_from_physical(physaddr: usize) -> Result { - let physaddr_start_page = physaddr / PAGE_SIZE * PAGE_SIZE; - let physaddr_page_offset = physaddr % PAGE_SIZE; - - // Begin by reading and validating the header first. The SDT header is always 36 bytes - // long, and can thus span either one or two page table frames. - let needs_extra_page = (PAGE_SIZE - physaddr_page_offset) - .checked_sub(mem::size_of::()) - .is_none(); - let page_table_count = 1 + if needs_extra_page { 1 } else { 0 }; - - let pages = PhysmapGuard::map(physaddr_start_page, page_table_count)?; - assert!(pages.len() >= mem::size_of::()); - let sdt_mem = &pages[physaddr_page_offset..]; - - let sdt = plain::from_bytes::(&sdt_mem[..mem::size_of::()]) - .expect("either alignment is wrong, or the length is too short, both of which are already checked for"); - - let total_length = sdt.length(); - let base_length = std::cmp::min(total_length, sdt_mem.len()); - let extended_length = total_length - base_length; - - let mut loaded = sdt_mem[..base_length].to_owned(); - loaded.reserve(extended_length); - - const SIMULTANEOUS_PAGE_COUNT: usize = 4; - - let mut left = extended_length; - let mut offset = physaddr_start_page + page_table_count * PAGE_SIZE; - - let length_per_iteration = PAGE_SIZE * SIMULTANEOUS_PAGE_COUNT; - - while left > 0 { - let to_copy = std::cmp::min(left, length_per_iteration); - let additional_pages = PhysmapGuard::map(offset, to_copy.div_ceil(PAGE_SIZE))?; - - loaded.extend(&additional_pages[..to_copy]); - - left -= to_copy; - offset += to_copy; - } - assert_eq!(left, 0); - - Self::new(loaded.into()).map_err(Into::into) - } - pub fn as_slice(&self) -> &[u8] { - &self.0 - } -} - -impl Deref for Sdt { - type Target = SdtHeader; - - fn deref(&self) -> &Self::Target { - plain::from_bytes::(&self.0) - .expect("expected already validated Sdt to be able to get its header") - } -} - -impl Sdt { - pub fn data(&self) -> &[u8] { - &self.0[mem::size_of::()..] - } -} - -impl fmt::Debug for Sdt { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Sdt") - .field("header", &*self as &SdtHeader) - .field("extra_len", &self.data().len()) - .finish() - } -} - -pub struct Dsdt(Sdt); -pub struct Ssdt(Sdt); - -// Current AML implementation builds the aml_context.namespace at startup, -// but the cache for symbols is lazy-loaded when someone -// reads from the acpi:/symbols scheme. -// If you dynamically add an SDT, you can add to the namespace, but you -// must empty the cache so it is rebuilt. -// If you modify an SDT, you must discard the aml_context and rebuild it. -pub struct AmlSymbols { - aml_context: Option>, - // k = name, v = description - symbol_cache: FxHashMap, - page_cache: Arc>, - aml_region_handlers: Vec<(RegionSpace, Box)>, -} - -impl AmlSymbols { - pub fn new(aml_region_handlers: Vec<(RegionSpace, Box)>) -> Self { - Self { - aml_context: None, - symbol_cache: FxHashMap::default(), - page_cache: Arc::new(Mutex::new(AmlPageCache::default())), - aml_region_handlers, - } - } - - pub fn init(&mut self, pci_fd: Option<&libredox::Fd>) -> Result<(), Box> { - if self.aml_context.is_some() { - return Err("AML interpreter already initialized".into()); - } - let format_err = |err| format!("{:?}", err); - let handler = AmlPhysMemHandler::new(pci_fd, Arc::clone(&self.page_cache)); - //TODO: use these parsed tables for the rest of acpid - let rsdp_address = usize::from_str_radix(&std::env::var("RSDP_ADDR")?, 16)?; - let tables = - unsafe { AcpiTables::from_rsdp(handler.clone(), rsdp_address).map_err(format_err)? }; - let platform = AcpiPlatform::new(tables, handler).map_err(format_err)?; - let interpreter = Interpreter::new_from_platform(&platform).map_err(format_err)?; - for (region, handler) in self.aml_region_handlers.drain(..) { - interpreter.install_region_handler(region, handler); - } - self.aml_context = Some(interpreter); - Ok(()) - } - - pub fn aml_context_mut( - &mut self, - pci_fd: Option<&libredox::Fd>, - ) -> Result<&mut Interpreter, AmlEvalError> { - if self.aml_context.is_none() { - match self.init(pci_fd) { - Ok(()) => (), - Err(err) => { - log::error!("failed to initialize AML context: {}", err); - } - } - } - self.aml_context - .as_mut() - .ok_or(AmlEvalError::NotInitialized) - } - - pub fn symbols_cache(&self) -> &FxHashMap { - &self.symbol_cache - } - - pub fn lookup(&self, symbol: &str) -> Option { - if let Some(description) = self.symbol_cache.get(symbol) { - log::trace!("Found symbol in cache, {}, {}", symbol, description); - return Some(description.to_owned()); - } - None - } - - pub fn build_cache(&mut self, pci_fd: Option<&libredox::Fd>) { - let Ok(aml_context) = self.aml_context_mut(pci_fd) else { - return; - }; - - let mut symbol_list: Vec<(AmlName, String)> = Vec::with_capacity(5000); - - if aml_context - .namespace - .lock() - .traverse(|level_aml_name, level| { - for (child_seg, handle) in level.values.iter() { - if let Ok(aml_name) = - AmlName::from_name_seg(child_seg.to_owned()).resolve(level_aml_name) - { - let name = aml_to_symbol(&aml_name); - symbol_list.push((aml_name, name)); - } else { - log::error!( - "AmlName resolve failed, {:?}:{:?}", - level_aml_name, - child_seg - ); - } - } - Ok(true) - }) - .is_err() - { - log::error!("Namespace traverse failed"); - return; - } - - let mut symbol_cache: FxHashMap = FxHashMap::default(); - - for (aml_name, name) in &symbol_list { - // create an empty entry, in case something goes wrong with serialization - symbol_cache.insert(name.to_owned(), "".to_owned()); - if let Some(ser_value) = AmlSerde::from_aml(aml_context, aml_name) { - if let Ok(ser_string) = ron::ser::to_string_pretty(&ser_value, Default::default()) { - // replace the empty entry - symbol_cache.insert(name.to_owned(), ser_string); - } - } - } - - // Cache the new list - log::trace!("Updating symbols list"); - - self.symbol_cache = symbol_cache; - } -} - -#[derive(Debug, Error)] -pub enum AmlEvalError { - #[error("AML error")] - AmlError(AmlError), - #[error("Failed to serialize argument")] - SerializationError, - #[error("Failed to deserialize")] - DeserializationError, - #[error("AML not initialized")] - NotInitialized, -} -impl From for AmlEvalError { - fn from(value: AmlError) -> Self { - AmlEvalError::AmlError(value) - } -} - -pub struct AcpiContext { - tables: Vec, - dsdt: Option, - fadt: Option, - - aml_symbols: RwLock, - - // TODO: The kernel ACPI code seemed to use load_table quite ubiquitously, however ACPI 5.1 - // states that DDBHandles can only be obtained when loading XSDT-pointed tables. So, we'll - // generate an index only for those. - sdt_order: RwLock>>, - - pub next_ctx: RwLock, -} - -impl AcpiContext { - pub fn aml_eval( - &self, - symbol: AmlName, - args: Vec, - ) -> Result { - let mut symbols = self.aml_symbols.write(); - let interpreter = symbols.aml_context_mut(None)?; - interpreter.acquire_global_lock(16)?; - - let args = args - .into_iter() - .map(|aml_serde_value| { - aml_serde_value - .to_aml_object() - .map(Object::wrap) - .ok_or(AmlEvalError::DeserializationError) - }) - .collect::, AmlEvalError>>()?; - - let result = interpreter.evaluate(symbol, args); - interpreter - .release_global_lock() - .expect("Failed to release GIL!"); //TODO: check if this should panic - - result - .map_err(AmlEvalError::from) - .map(|object| { - AmlSerdeValue::from_aml_value(object.deref()) - .ok_or(AmlEvalError::SerializationError) - }) - .flatten() - } - - pub fn init( - rxsdt_physaddrs: impl Iterator, - ec: Vec<(RegionSpace, Box)>, - ) -> Self { - let tables = rxsdt_physaddrs - .map(|physaddr| { - let physaddr: usize = physaddr - .try_into() - .expect("expected ACPI addresses to be compatible with the current word size"); - - log::trace!("TABLE AT {:#>08X}", physaddr); - - Sdt::load_from_physical(physaddr).expect("failed to load physical SDT") - }) - .collect::>(); - - let mut this = Self { - tables, - dsdt: None, - fadt: None, - - // Temporary values - aml_symbols: RwLock::new(AmlSymbols::new(ec)), - - next_ctx: RwLock::new(0), - - sdt_order: RwLock::new(Vec::new()), - }; - - for table in &this.tables { - this.new_index(&table.signature()); - } - - Fadt::init(&mut this); - //TODO (hangs on real hardware): Dmar::init(&this); - - this - } - - pub fn dsdt(&self) -> Option<&Dsdt> { - self.dsdt.as_ref() - } - pub fn ssdts(&self) -> impl Iterator + '_ { - self.find_multiple_sdts(*b"SSDT") - .map(|sdt| Ssdt(sdt.clone())) - } - fn find_single_sdt_pos(&self, signature: [u8; 4]) -> Option { - let count = self - .tables - .iter() - .filter(|sdt| sdt.signature == signature) - .count(); - - if count > 1 { - log::warn!( - "Expected only a single SDT of signature `{}` ({:?}), but there were {}", - String::from_utf8_lossy(&signature), - signature, - count - ); - } - - self.tables - .iter() - .position(|sdt| sdt.signature == signature) - } - pub fn find_multiple_sdts<'a>(&'a self, signature: [u8; 4]) -> impl Iterator { - self.tables - .iter() - .filter(move |sdt| sdt.signature == signature) - } - pub fn take_single_sdt(&self, signature: [u8; 4]) -> Option { - self.find_single_sdt_pos(signature) - .map(|pos| self.tables[pos].clone()) - } - pub fn fadt(&self) -> Option<&Fadt> { - self.fadt.as_ref() - } - pub fn sdt_from_signature(&self, signature: &SdtSignature) -> Option<&Sdt> { - self.tables.iter().find(|sdt| { - sdt.signature == signature.signature - && sdt.oem_id == signature.oem_id - && sdt.oem_table_id == signature.oem_table_id - }) - } - pub fn get_signature_from_index(&self, index: usize) -> Option { - self.sdt_order.read().get(index).copied().flatten() - } - pub fn get_index_from_signature(&self, signature: &SdtSignature) -> Option { - self.sdt_order - .read() - .iter() - .rposition(|sig| sig.map_or(false, |sig| &sig == signature)) - } - pub fn tables(&self) -> &[Sdt] { - &self.tables - } - pub fn new_index(&self, signature: &SdtSignature) { - self.sdt_order.write().push(Some(*signature)); - } - - pub fn aml_lookup(&self, symbol: &str) -> Option { - if let Ok(aml_symbols) = self.aml_symbols(None) { - aml_symbols.lookup(symbol) - } else { - None - } - } - - pub fn aml_symbols( - &self, - pci_fd: Option<&libredox::Fd>, - ) -> Result, AmlError> { - // return the cached value if it exists - let symbols = self.aml_symbols.read(); - if !symbols.symbols_cache().is_empty() { - return Ok(symbols); - } - // free the read lock - drop(symbols); - - // List has not been initialized, we have to build it - log::trace!("Creating symbols list"); - - let mut aml_symbols = self.aml_symbols.write(); - - aml_symbols.build_cache(pci_fd); - - // return the cached value - Ok(RwLockWriteGuard::downgrade(aml_symbols)) - } - - /// Discard any cached symbols list. To be called if the AML namespace changes. - pub fn aml_symbols_reset(&self) { - let mut aml_symbols = self.aml_symbols.write(); - aml_symbols.symbol_cache = FxHashMap::default(); - } - - /// Set Power State - /// See https://uefi.org/sites/default/files/resources/ACPI_6_1.pdf - /// - search for PM1a - /// See https://forum.osdev.org/viewtopic.php?t=16990 for practical details - pub fn set_global_s_state(&self, state: u8) { - if state != 5 { - return; - } - let fadt = match self.fadt() { - Some(fadt) => fadt, - None => { - log::error!("Cannot set global S-state due to missing FADT."); - return; - } - }; - - let port = fadt.pm1a_control_block as u16; - let mut val = 1 << 13; - - let aml_symbols = self.aml_symbols.read(); - - let s5_aml_name = match acpi::aml::namespace::AmlName::from_str("\\_S5") { - Ok(aml_name) => aml_name, - Err(error) => { - log::error!("Could not build AmlName for \\_S5, {:?}", error); - return; - } - }; - - let s5 = match &aml_symbols.aml_context { - Some(aml_context) => match aml_context.namespace.lock().get(s5_aml_name) { - Ok(s5) => s5, - Err(error) => { - log::error!("Cannot set S-state, missing \\_S5, {:?}", error); - return; - } - }, - None => { - log::error!("Cannot set S-state, AML context not initialized"); - return; - } - }; - - let package = match s5.deref() { - acpi::aml::object::Object::Package(package) => package, - _ => { - log::error!("Cannot set S-state, \\_S5 is not a package"); - return; - } - }; - - let slp_typa = match package[0].deref() { - acpi::aml::object::Object::Integer(i) => i.to_owned(), - _ => { - log::error!("typa is not an Integer"); - return; - } - }; - let slp_typb = match package[1].deref() { - acpi::aml::object::Object::Integer(i) => i.to_owned(), - _ => { - log::error!("typb is not an Integer"); - return; - } - }; - - log::trace!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); - val |= slp_typa as u16; - - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - log::warn!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); - Pio::::new(port).write(val); - } - - // TODO: Handle SLP_TYPb - - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - { - log::error!( - "Cannot shutdown with ACPI outw(0x{:X}, 0x{:X}) on this architecture", - port, - val - ); - } - - loop { - core::hint::spin_loop(); - } - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct FadtStruct { - pub header: SdtHeader, - pub firmware_ctrl: u32, - pub dsdt: u32, - - // field used in ACPI 1.0; no longer in use, for compatibility only - reserved: u8, - - pub preferred_power_managament: u8, - pub sci_interrupt: u16, - pub smi_command_port: u32, - pub acpi_enable: u8, - pub acpi_disable: u8, - pub s4_bios_req: u8, - pub pstate_control: u8, - pub pm1a_event_block: u32, - pub pm1b_event_block: u32, - pub pm1a_control_block: u32, - pub pm1b_control_block: u32, - pub pm2_control_block: u32, - pub pm_timer_block: u32, - pub gpe0_block: u32, - pub gpe1_block: u32, - pub pm1_event_length: u8, - pub pm1_control_length: u8, - pub pm2_control_length: u8, - pub pm_timer_length: u8, - pub gpe0_ength: u8, - pub gpe1_length: u8, - pub gpe1_base: u8, - pub c_state_control: u8, - pub worst_c2_latency: u16, - pub worst_c3_latency: u16, - pub flush_size: u16, - pub flush_stride: u16, - pub duty_offset: u8, - pub duty_width: u8, - pub day_alarm: u8, - pub month_alarm: u8, - pub century: u8, - - // reserved in ACPI 1.0; used since ACPI 2.0+ - pub boot_architecture_flags: u16, - - reserved2: u8, - pub flags: u32, -} -unsafe impl plain::Plain for FadtStruct {} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct GenericAddressStructure { - address_space: u8, - bit_width: u8, - bit_offset: u8, - access_size: u8, - address: u64, -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct FadtAcpi2Struct { - // 12 byte structure; see below for details - pub reset_reg: GenericAddressStructure, - - pub reset_value: u8, - reserved3: [u8; 3], - - // 64bit pointers - Available on ACPI 2.0+ - pub x_firmware_control: u64, - pub x_dsdt: u64, - - pub x_pm1a_event_block: GenericAddressStructure, - pub x_pm1b_event_block: GenericAddressStructure, - pub x_pm1a_control_block: GenericAddressStructure, - pub x_pm1b_control_block: GenericAddressStructure, - pub x_pm2_control_block: GenericAddressStructure, - pub x_pm_timer_block: GenericAddressStructure, - pub x_gpe0_block: GenericAddressStructure, - pub x_gpe1_block: GenericAddressStructure, -} -unsafe impl plain::Plain for FadtAcpi2Struct {} - -#[derive(Clone)] -pub struct Fadt(Sdt); - -impl Fadt { - pub fn acpi_2_struct(&self) -> Option<&FadtAcpi2Struct> { - let bytes = &self.0 .0[mem::size_of::()..]; - - match plain::from_bytes::(bytes) { - Ok(fadt2) => Some(fadt2), - Err(plain::Error::TooShort) => None, - Err(plain::Error::BadAlignment) => unreachable!( - "plain::from_bytes reported bad alignment, but FadtAcpi2Struct is #[repr(packed)]" - ), - } - } -} - -impl Deref for Fadt { - type Target = FadtStruct; - - fn deref(&self) -> &Self::Target { - plain::from_bytes::(&self.0 .0) - .expect("expected FADT struct to already be validated in Deref impl") - } -} - -impl Fadt { - pub fn new(sdt: Sdt) -> Option { - if sdt.signature != *b"FACP" || sdt.length() < mem::size_of::() { - return None; - } - Some(Fadt(sdt)) - } - - pub fn init(context: &mut AcpiContext) { - let fadt_sdt = context - .take_single_sdt(*b"FACP") - .expect("expected ACPI to always have a FADT"); - - let fadt = match Fadt::new(fadt_sdt) { - Some(fadt) => fadt, - None => { - log::error!("Failed to find FADT"); - return; - } - }; - - let dsdt_ptr = match fadt.acpi_2_struct() { - Some(fadt2) => usize::try_from(fadt2.x_dsdt).unwrap_or_else(|_| { - usize::try_from(fadt.dsdt).expect("expected any given u32 to fit within usize") - }), - None => usize::try_from(fadt.dsdt).expect("expected any given u32 to fit within usize"), - }; - - log::debug!("FACP at {:X}", { dsdt_ptr }); - - let dsdt_sdt = match Sdt::load_from_physical(fadt.dsdt as usize) { - Ok(dsdt) => dsdt, - Err(error) => { - log::error!("Failed to load DSDT: {}", error); - return; - } - }; - - context.fadt = Some(fadt.clone()); - context.dsdt = Some(Dsdt(dsdt_sdt.clone())); - - context.tables.push(dsdt_sdt); - } -} - -pub enum PossibleAmlTables { - Dsdt(Dsdt), - Ssdt(Ssdt), -} -impl PossibleAmlTables { - pub fn try_new(inner: Sdt) -> Option { - match &inner.signature { - b"DSDT" => Some(Self::Dsdt(Dsdt(inner))), - b"SSDT" => Some(Self::Ssdt(Ssdt(inner))), - _ => None, - } - } -} -impl AmlContainingTable for PossibleAmlTables { - fn aml(&self) -> &[u8] { - match self { - Self::Dsdt(dsdt) => dsdt.aml(), - Self::Ssdt(ssdt) => ssdt.aml(), - } - } - fn header(&self) -> &SdtHeader { - match self { - Self::Dsdt(dsdt) => dsdt.header(), - Self::Ssdt(ssdt) => ssdt.header(), - } - } -} - -pub trait AmlContainingTable { - fn aml(&self) -> &[u8]; - fn header(&self) -> &SdtHeader; -} - -impl AmlContainingTable for &T -where - T: AmlContainingTable, -{ - fn aml(&self) -> &[u8] { - T::aml(*self) - } - fn header(&self) -> &SdtHeader { - T::header(*self) - } -} - -impl AmlContainingTable for Dsdt { - fn aml(&self) -> &[u8] { - self.0.data() - } - fn header(&self) -> &SdtHeader { - &*self.0 - } -} -impl AmlContainingTable for Ssdt { - fn aml(&self) -> &[u8] { - self.0.data() - } - fn header(&self) -> &SdtHeader { - &*self.0 - } -} diff --git a/recipes/core/base/drivers/acpid/src/acpi/dmar/drhd.rs b/recipes/core/base/drivers/acpid/src/acpi/dmar/drhd.rs deleted file mode 100644 index f33f3bf6e2..0000000000 --- a/recipes/core/base/drivers/acpid/src/acpi/dmar/drhd.rs +++ /dev/null @@ -1,128 +0,0 @@ -use std::ops::{Deref, DerefMut}; - -use common::io::Mmio; - -// TODO: Only wrap with Mmio where there are hardware-registers. (Some of these structs seem to be -// ring buffer entries, which are not to be treated the same way). - -pub struct DrhdPage { - virt: *mut Drhd, -} -impl DrhdPage { - pub fn map(base_phys: usize) -> syscall::Result { - assert_eq!( - base_phys % crate::acpi::PAGE_SIZE, - 0, - "DRHD registers must be page-aligned" - ); - - // TODO: Uncachable? Can reads have side-effects? - let virt = unsafe { - common::physmap( - base_phys, - crate::acpi::PAGE_SIZE, - common::Prot::RO, - common::MemoryType::default(), - )? - } as *mut Drhd; - - Ok(Self { virt }) - } -} -impl Deref for DrhdPage { - type Target = Drhd; - - fn deref(&self) -> &Self::Target { - unsafe { &*self.virt } - } -} -impl DerefMut for DrhdPage { - fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { &mut *self.virt } - } -} -impl Drop for DrhdPage { - fn drop(&mut self) { - unsafe { - let _ = libredox::call::munmap(self.virt.cast(), crate::acpi::PAGE_SIZE); - } - } -} - -#[repr(C, packed)] -pub struct DrhdFault { - pub sts: Mmio, - pub ctrl: Mmio, - pub data: Mmio, - pub addr: [Mmio; 2], - _rsv: [Mmio; 2], - pub log: Mmio, -} - -#[repr(C, packed)] -pub struct DrhdProtectedMemory { - pub en: Mmio, - pub low_base: Mmio, - pub low_limit: Mmio, - pub high_base: Mmio, - pub high_limit: Mmio, -} - -#[repr(C, packed)] -pub struct DrhdInvalidation { - pub queue_head: Mmio, - pub queue_tail: Mmio, - pub queue_addr: Mmio, - _rsv: Mmio, - pub cmpl_sts: Mmio, - pub cmpl_ctrl: Mmio, - pub cmpl_data: Mmio, - pub cmpl_addr: [Mmio; 2], -} - -#[repr(C, packed)] -pub struct DrhdPageRequest { - pub queue_head: Mmio, - pub queue_tail: Mmio, - pub queue_addr: Mmio, - _rsv: Mmio, - pub sts: Mmio, - pub ctrl: Mmio, - pub data: Mmio, - pub addr: [Mmio; 2], -} - -#[repr(C, packed)] -pub struct DrhdMtrrVariable { - pub base: Mmio, - pub mask: Mmio, -} - -#[repr(C, packed)] -pub struct DrhdMtrr { - pub cap: Mmio, - pub def_type: Mmio, - pub fixed: [Mmio; 11], - pub variable: [DrhdMtrrVariable; 10], -} - -#[repr(C, packed)] -pub struct Drhd { - pub version: Mmio, - _rsv: Mmio, - pub cap: Mmio, - pub ext_cap: Mmio, - pub gl_cmd: Mmio, - pub gl_sts: Mmio, - pub root_table: Mmio, - pub ctx_cmd: Mmio, - _rsv1: Mmio, - pub fault: DrhdFault, - _rsv2: Mmio, - pub pm: DrhdProtectedMemory, - pub invl: DrhdInvalidation, - _rsv3: Mmio, - pub intr_table: Mmio, - pub page_req: DrhdPageRequest, - pub mtrr: DrhdMtrr, -} diff --git a/recipes/core/base/drivers/acpid/src/acpi/dmar/mod.rs b/recipes/core/base/drivers/acpid/src/acpi/dmar/mod.rs deleted file mode 100644 index c42b379a10..0000000000 --- a/recipes/core/base/drivers/acpid/src/acpi/dmar/mod.rs +++ /dev/null @@ -1,528 +0,0 @@ -//! DMA Remapping Table -- `DMAR`. This is Intel's implementation of IOMMU functionality, known as -//! VT-d. -//! -//! Too understand what all of these structs mean, refer to the "Intel(R) Virtualization -//! Technology for Directed I/O" specification. - -// TODO: Move this code to a separate driver as well? - -use std::convert::TryFrom; -use std::ops::Deref; -use std::{fmt, mem}; - -use common::io::Io as _; - -use num_derive::FromPrimitive; -use num_traits::FromPrimitive; - -use self::drhd::DrhdPage; -use crate::acpi::{AcpiContext, Sdt, SdtHeader}; - -pub mod drhd; - -#[repr(C, packed)] -pub struct DmarStruct { - pub sdt_header: SdtHeader, - pub host_addr_width: u8, - pub flags: u8, - pub _rsvd: [u8; 10], - // This header is followed by N remapping structures. -} -unsafe impl plain::Plain for DmarStruct {} - -/// The DMA Remapping Table -#[derive(Debug)] -pub struct Dmar(Sdt); - -impl Dmar { - fn remmapping_structs_area(&self) -> &[u8] { - &self.0.as_slice()[mem::size_of::()..] - } -} - -impl Deref for Dmar { - type Target = DmarStruct; - - fn deref(&self) -> &Self::Target { - plain::from_bytes(self.0.as_slice()) - .expect("expected Dmar struct to already have checked the length, and alignment issues should be impossible due to #[repr(packed)]") - } -} - -impl Dmar { - // TODO: Again, perhaps put this code into a different driver, and read the table the regular - // way via the acpi scheme? - pub fn init(acpi_ctx: &AcpiContext) { - let dmar_sdt = match acpi_ctx.take_single_sdt(*b"DMAR") { - Some(dmar_sdt) => dmar_sdt, - None => { - log::warn!("Unable to find `DMAR` ACPI table."); - return; - } - }; - let dmar = match Dmar::new(dmar_sdt) { - Some(dmar) => dmar, - None => { - log::error!("Failed to parse DMAR table, possibly malformed."); - return; - } - }; - - log::info!("Found DMAR: {}: {}", dmar.host_addr_width, dmar.flags); - log::debug!("DMAR: {:?}", dmar); - - for dmar_entry in dmar.iter() { - log::debug!("DMAR entry: {:?}", dmar_entry); - match dmar_entry { - DmarEntry::Drhd(dmar_drhd) => { - let drhd = dmar_drhd.map(); - - log::debug!("VER: {:X}", drhd.version.read()); - log::debug!("CAP: {:X}", drhd.cap.read()); - log::debug!("EXT_CAP: {:X}", drhd.ext_cap.read()); - log::debug!("GCMD: {:X}", drhd.gl_cmd.read()); - log::debug!("GSTS: {:X}", drhd.gl_sts.read()); - log::debug!("RT: {:X}", drhd.root_table.read()); - } - _ => (), - } - } - } - - fn new(sdt: Sdt) -> Option { - assert_eq!( - sdt.signature, *b"DMAR", - "signature already checked against `DMAR`" - ); - if sdt.length() < mem::size_of::() { - log::error!( - "The DMAR table was too small ({} B < {} B).", - sdt.length(), - mem::size_of::() - ); - return None; - } - // No need to check alignment for #[repr(packed)] structs. - - Some(Dmar(sdt)) - } - - pub fn iter(&self) -> DmarIter<'_> { - DmarIter(DmarRawIter { - bytes: self.remmapping_structs_area(), - }) - } -} - -/// DMAR DMA Remapping Hardware Unit Definition -#[derive(Clone, Copy, Debug)] -#[repr(C, packed)] -pub struct DmarDrhdHeader { - pub kind: u16, - pub length: u16, - - pub flags: u8, - pub _rsv: u8, - pub segment: u16, - pub base: u64, -} -unsafe impl plain::Plain for DmarDrhdHeader {} - -#[derive(Clone, Copy, Debug)] -#[repr(C, packed)] -pub struct DeviceScopeHeader { - pub ty: u8, - pub len: u8, - pub _rsvd: u16, - pub enumeration_id: u8, - pub start_bus_num: u8, - // The variable-sized path comes after. -} -unsafe impl plain::Plain for DeviceScopeHeader {} - -pub struct DeviceScope(Box<[u8]>); - -impl DeviceScope { - pub fn try_new(raw: &[u8]) -> Option { - // TODO: Check ty. - - let header_bytes = match raw.get(..mem::size_of::()) { - Some(bytes) => bytes, - None => return None, - }; - let header = plain::from_bytes::(header_bytes) - .expect("length already checked, and alignment 1 (#[repr(packed)] should suffice"); - - let len = usize::from(header.len); - - if len > raw.len() { - log::warn!("Device scope smaller than len field."); - return None; - } - - Some(Self(raw.into())) - } -} - -impl fmt::Debug for DeviceScope { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DeviceScope") - .field("header", &*self as &DeviceScopeHeader) - .field("path", &self.path()) - .finish() - } -} - -impl Deref for DeviceScope { - type Target = DeviceScopeHeader; - - fn deref(&self) -> &Self::Target { - plain::from_bytes(&self.0) - .expect("expected length to be sufficient, and alignment (due to #[repr(packed)]") - } -} -impl DeviceScope { - pub fn path(&self) -> &[u8] { - &self.0[mem::size_of::()..] - } -} - -pub struct DmarDrhd(Box<[u8]>); - -impl DmarDrhd { - pub fn try_new(raw: &[u8]) -> Option { - if raw.len() < mem::size_of::() { - return None; - } - - Some(Self(raw.into())) - } - pub fn device_scope_area(&self) -> &[u8] { - &self.0[mem::size_of::()..] - } - pub fn map(&self) -> DrhdPage { - let base = usize::try_from(self.base).expect("expected u64 to fit within usize"); - - DrhdPage::map(base).expect("failed to map DRHD registers") - } -} -impl Deref for DmarDrhd { - type Target = DmarDrhdHeader; - - fn deref(&self) -> &Self::Target { - plain::from_bytes::(&self.0[..mem::size_of::()]) - .expect("length is already checked, and alignment 1 (#[repr(packed)] should suffice") - } -} -impl fmt::Debug for DmarDrhd { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DmarDrhd") - .field("header", &*self as &DmarDrhd) - // TODO: print out device scopes - .finish() - } -} - -/// DMAR Reserved Memory Region Reporting -#[derive(Clone, Copy, Debug)] -#[repr(C, packed)] -pub struct DmarRmrrHeader { - pub kind: u16, - pub length: u16, - pub _rsv: u16, - pub segment: u16, - pub base: u64, - pub limit: u64, - // The device scopes come after. -} -unsafe impl plain::Plain for DmarRmrrHeader {} - -pub struct DmarRmrr(Box<[u8]>); - -impl DmarRmrr { - pub fn try_new(raw: &[u8]) -> Option { - if raw.len() < mem::size_of::() { - return None; - } - - Some(Self(raw.into())) - } -} -impl Deref for DmarRmrr { - type Target = DmarRmrrHeader; - - fn deref(&self) -> &Self::Target { - plain::from_bytes(&self.0[..mem::size_of::()]) - .expect("length already checked, and with #[repr(packed)] alignment should be okay") - } -} -impl fmt::Debug for DmarRmrr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DmarRmrr") - .field("header", &*self as &DmarRmrrHeader) - // TODO: print out device scopes - .finish() - } -} - -/// DMAR Root Port ATS Capability Reporting -#[derive(Clone, Copy, Debug)] -#[repr(C, packed)] -pub struct DmarAtsrHeader { - kind: u16, - length: u16, - flags: u8, - _rsv: u8, - segment: u16, - // The device scopes come after. -} -unsafe impl plain::Plain for DmarAtsrHeader {} - -pub struct DmarAtsr(Box<[u8]>); - -impl DmarAtsr { - pub fn try_new(raw: &[u8]) -> Option { - if raw.len() < mem::size_of::() { - return None; - } - - Some(Self(raw.into())) - } -} -impl Deref for DmarAtsr { - type Target = DmarAtsrHeader; - - fn deref(&self) -> &Self::Target { - plain::from_bytes(&self.0[..mem::size_of::()]) - .expect("length already checked, and with #[repr(packed)] alignment should be okay") - } -} -impl fmt::Debug for DmarAtsr { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DmarAtsr") - .field("header", &*self as &DmarAtsrHeader) - // TODO: print out device scopes - .finish() - } -} - -/// DMAR Remapping Hardware Static Affinity -#[derive(Clone, Copy, Debug)] -#[repr(C, packed)] -pub struct DmarRhsa { - pub kind: u16, - pub length: u16, - - pub _rsv: u32, - pub base: u64, - pub domain: u32, -} -unsafe impl plain::Plain for DmarRhsa {} -impl DmarRhsa { - pub fn try_new(raw: &[u8]) -> Option { - let bytes = raw.get(..mem::size_of::())?; - - let this = plain::from_bytes(bytes) - .expect("length is already checked, and alignment 1 should suffice (#[repr(packed)])"); - - Some(*this) - } -} - -/// DMAR ACPI Name-space Device Declaration -#[derive(Clone, Copy, Debug)] -#[repr(C, packed)] -pub struct DmarAnddHeader { - pub kind: u16, - pub length: u16, - - pub _rsv: [u8; 3], - pub acpi_dev: u8, - // The device scopes come after. -} -unsafe impl plain::Plain for DmarAnddHeader {} - -pub struct DmarAndd(Box<[u8]>); - -impl DmarAndd { - pub fn try_new(raw: &[u8]) -> Option { - if raw.len() < mem::size_of::() { - return None; - } - - Some(Self(raw.into())) - } -} -impl Deref for DmarAndd { - type Target = DmarAnddHeader; - - fn deref(&self) -> &Self::Target { - plain::from_bytes(&self.0[..mem::size_of::()]) - .expect("length already checked, and with #[repr(packed)] alignment should be okay") - } -} -impl fmt::Debug for DmarAndd { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DmarAndd") - .field("header", &*self as &DmarAnddHeader) - // TODO: print out device scopes - .finish() - } -} - -/// DMAR ACPI Name-space Device Declaration -#[derive(Clone, Copy, Debug)] -#[repr(C, packed)] -pub struct DmarSatcHeader { - pub kind: u16, - pub length: u16, - - pub flags: u8, - pub _rsvd: u8, - pub seg_num: u16, - // The device scopes come after. -} -unsafe impl plain::Plain for DmarSatcHeader {} - -pub struct DmarSatc(Box<[u8]>); - -impl DmarSatc { - pub fn try_new(raw: &[u8]) -> Option { - if raw.len() < mem::size_of::() { - return None; - } - - Some(Self(raw.into())) - } -} - -impl Deref for DmarSatc { - type Target = DmarSatcHeader; - - fn deref(&self) -> &Self::Target { - plain::from_bytes(&self.0[..mem::size_of::()]) - .expect("length already checked, and with #[repr(packed)] alignment should be okay") - } -} -impl fmt::Debug for DmarSatc { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("DmarSatc") - .field("header", &*self as &DmarSatcHeader) - // TODO: print out device scopes - .finish() - } -} - -/// The list of different "Remapping Structure Types". -/// -/// Refer to section 8.2 in the VTIO spec (as of revision 3.2). -#[derive(Clone, Copy, Debug, FromPrimitive)] -#[repr(u16)] -pub enum EntryType { - Drhd = 0, - Rmrr = 1, - Atsr = 2, - Rhsa = 3, - Andd = 4, - Satc = 5, -} - -/// DMAR Entries -#[derive(Debug)] -pub enum DmarEntry { - Drhd(DmarDrhd), - Rmrr(DmarRmrr), - Atsr(DmarAtsr), - Rhsa(DmarRhsa), - Andd(DmarAndd), - - // TODO: "SoC Integrated Address Translation Cache Reporting Structure". - Satc(DmarSatc), - - TooShort(EntryType), - Unknown(u16), -} - -struct DmarRawIter<'sdt> { - bytes: &'sdt [u8], -} - -impl<'sdt> Iterator for DmarRawIter<'sdt> { - type Item = (u16, &'sdt [u8]); - - fn next(&mut self) -> Option { - let type_bytes = match self.bytes.get(..2) { - Some(bytes) => bytes, - None => { - if !self.bytes.is_empty() { - log::warn!("DMAR table ended between two entries."); - } - return None; - } - }; - let len_bytes = match self.bytes.get(2..4) { - Some(bytes) => bytes, - None => { - log::warn!("DMAR table ended between two entries."); - return None; - } - }; - let remainder = &self.bytes[4..]; - - let type_bytes = <[u8; 2]>::try_from(type_bytes) - .expect("expected a 2-byte slice to be convertible to [u8; 2]"); - let len_bytes = <[u8; 2]>::try_from(type_bytes) - .expect("expected a 2-byte slice to be convertible to [u8; 2]"); - - let ty = u16::from_ne_bytes(type_bytes); - let len = u16::from_ne_bytes(len_bytes); - - let len = usize::try_from(len).expect("expected u16 to fit within usize"); - - if len > remainder.len() { - log::warn!("DMAR remapping structure length was smaller than the remaining length of the table."); - return None; - } - - let (current, residue) = self.bytes.split_at(len); - self.bytes = residue; - - Some((ty, current)) - } -} - -pub struct DmarIter<'sdt>(DmarRawIter<'sdt>); - -impl Iterator for DmarIter<'_> { - type Item = DmarEntry; - fn next(&mut self) -> Option { - let (raw_type, raw) = self.0.next()?; - - // NOTE: If any of these entries look incorrect, we should simply continue the iterator, - // and instead print a warning. - - let entry_type = match EntryType::from_u16(raw_type) { - Some(ty) => ty, - None => { - log::warn!( - "Encountered invalid entry type {} (length {})", - raw_type, - raw.len() - ); - return Some(DmarEntry::Unknown(raw_type)); - } - }; - - let item_opt = match entry_type { - EntryType::Drhd => DmarDrhd::try_new(raw).map(DmarEntry::Drhd), - EntryType::Rmrr => DmarRmrr::try_new(raw).map(DmarEntry::Rmrr), - EntryType::Atsr => DmarAtsr::try_new(raw).map(DmarEntry::Atsr), - EntryType::Rhsa => DmarRhsa::try_new(raw).map(DmarEntry::Rhsa), - EntryType::Andd => DmarAndd::try_new(raw).map(DmarEntry::Andd), - EntryType::Satc => DmarSatc::try_new(raw).map(DmarEntry::Satc), - }; - let item = item_opt.unwrap_or(DmarEntry::TooShort(entry_type)); - - Some(item) - } -} diff --git a/recipes/core/base/drivers/acpid/src/aml_physmem.rs b/recipes/core/base/drivers/acpid/src/aml_physmem.rs deleted file mode 100644 index 2bdd667ba2..0000000000 --- a/recipes/core/base/drivers/acpid/src/aml_physmem.rs +++ /dev/null @@ -1,430 +0,0 @@ -use acpi::{aml::AmlError, Handle, PciAddress, PhysicalMapping}; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use common::io::{Io, Pio}; -use num_traits::PrimInt; -use rustc_hash::FxHashMap; -use std::fmt::LowerHex; -use std::mem::size_of; -use std::ptr::NonNull; -use std::sync::{Arc, Mutex}; -use syscall::PAGE_SIZE; - -const PAGE_MASK: usize = !(PAGE_SIZE - 1); -const OFFSET_MASK: usize = PAGE_SIZE - 1; - -struct MappedPage { - phys_page: usize, - virt_page: usize, -} - -impl MappedPage { - fn new(phys_page: usize) -> std::io::Result { - let virt_page = unsafe { - common::physmap( - phys_page, - PAGE_SIZE, - common::Prot::RW, - common::MemoryType::default(), - ) - .map_err(|error| std::io::Error::from_raw_os_error(error.errno()))? - } as usize; - Ok(Self { - phys_page, - virt_page, - }) - } -} - -impl Drop for MappedPage { - fn drop(&mut self) { - log::trace!("Drop page {:#x}", self.phys_page); - if let Err(e) = unsafe { libredox::call::munmap(self.virt_page as *mut (), PAGE_SIZE) } { - log::error!("funmap (phys): {:?}", e); - } - } -} - -#[derive(Default)] -pub struct AmlPageCache { - page_cache: FxHashMap, -} - -impl AmlPageCache { - /// get a virtual address for the given physical page - fn get_page(&mut self, phys_target: usize) -> std::io::Result<&MappedPage> { - let phys_page = phys_target & PAGE_MASK; - if self.page_cache.contains_key(&phys_page) { - log::trace!("re-using cached page {:#x}", phys_page); - - Ok(self - .page_cache - .get(&phys_page) - .expect("could not get page after contains=true")) - } else { - let mapped_page = MappedPage::new(phys_page)?; - log::trace!("adding page {:#x} to cache", mapped_page.phys_page); - self.page_cache.insert(phys_page, mapped_page); - Ok(self - .page_cache - .get(&phys_page) - .expect("can't find page that was just inserted")) - } - } - - /// The offset into the virtual slice of T that matches the physical target - fn sized_index(phys_target: usize) -> usize { - assert_eq!( - phys_target & !(size_of::() - 1), - phys_target, - "address {} is not aligned", - phys_target - ); - (phys_target & OFFSET_MASK) / size_of::() - } - /// Read from the given physical address - fn read_from_phys(&mut self, phys_target: usize) -> std::io::Result { - let mapped_page = self.get_page(phys_target)?; - let page_as_slice = unsafe { - std::slice::from_raw_parts( - mapped_page.virt_page as *const T, - PAGE_SIZE / size_of::(), - ) - }; - // for debugging only - let _virt_ptr = page_as_slice[Self::sized_index::(phys_target)..].as_ptr() as usize; - - let val = page_as_slice[Self::sized_index::(phys_target)]; - - log::trace!( - "read {:#x}, virt {:#x}, val {:#x}", - phys_target, - _virt_ptr, - val - ); - Ok(val) - } - - /// Write to the given physical address - fn write_to_phys( - &mut self, - phys_target: usize, - val: T, - ) -> std::io::Result<()> { - let mapped_page = self.get_page(phys_target)?; - let page_as_slice = unsafe { - std::slice::from_raw_parts_mut( - mapped_page.virt_page as *mut T, - PAGE_SIZE / size_of::(), - ) - }; - // for debugging only - let _virt_ptr = page_as_slice[Self::sized_index::(phys_target)..].as_ptr() as usize; - - page_as_slice[Self::sized_index::(phys_target)] = val; - - log::trace!( - "write {:#x}, virt {:#x}, val {:#x}", - phys_target, - _virt_ptr, - val - ); - Ok(()) - } - - pub fn clear(&mut self) { - log::trace!("Clear page cache"); - self.page_cache.clear(); - } -} - -#[derive(Clone)] -pub struct AmlPhysMemHandler { - page_cache: Arc>, - pci_fd: Arc>, -} - -/// Read from a physical address. -/// Generic parameter must be u8, u16, u32 or u64. -impl AmlPhysMemHandler { - pub fn new(pci_fd_opt: Option<&libredox::Fd>, page_cache: Arc>) -> Self { - let pci_fd = if let Some(pci_fd) = pci_fd_opt { - Some(libredox::Fd::new(pci_fd.raw())) - } else { - log::error!("pci_fd is not registered"); - None - }; - Self { - page_cache, - pci_fd: Arc::new(pci_fd), - } - } - - fn pci_call_metadata(kind: u8, addr: PciAddress, off: u16) -> [u64; 2] { - // Segment: u16, at 28 bits - // Bus: u8, 8 bits, 256 total, at 20 bits - // Device: u8, 5 bits, 32 total, at 15 bits - // Function: u8, 3 bits, 8 total, at 12 bits - // Offset: u16, 12 bits, 4096 total, at 0 bits - [ - kind.into(), - (u64::from(addr.segment()) << 28) - | (u64::from(addr.bus()) << 20) - | (u64::from(addr.device()) << 15) - | (u64::from(addr.function()) << 12) - | u64::from(off), - ] - } - - fn read_pci(&self, addr: PciAddress, off: u16, value: &mut [u8]) { - let metadata = Self::pci_call_metadata(1, addr, off); - match &*self.pci_fd { - Some(pci_fd) => match pci_fd.call_ro(value, syscall::CallFlags::empty(), &metadata) { - Ok(_) => {} - Err(err) => { - log::error!("read pci {addr}@{off:04X}:{:02X}: {}", value.len(), err); - } - }, - None => { - log::error!( - "read pci {addr}@{off:04X}:{:02X}: pci access not available", - value.len() - ); - } - } - } - - fn write_pci(&self, addr: PciAddress, off: u16, value: &[u8]) { - let metadata = Self::pci_call_metadata(2, addr, off); - match &*self.pci_fd { - Some(pci_fd) => match pci_fd.call_wo(value, syscall::CallFlags::empty(), &metadata) { - Ok(_) => {} - Err(err) => { - log::error!("write pci {addr}@{off:04X}={value:02X?}: {}", err); - } - }, - None => { - log::error!("write pci {addr}@{off:04X}={value:02X?}: pci access not available"); - } - } - } -} - -impl acpi::Handler for AmlPhysMemHandler { - unsafe fn map_physical_region(&self, phys: usize, size: usize) -> PhysicalMapping { - let phys_page = phys & PAGE_MASK; - let offset = phys & OFFSET_MASK; - let pages = (offset + size + PAGE_SIZE - 1) / PAGE_SIZE; - let map_size = pages * PAGE_SIZE; - let virt_page = common::physmap( - phys_page, - map_size, - common::Prot::RW, - common::MemoryType::default(), - ) - .expect("failed to map physical region") as usize; - PhysicalMapping { - physical_start: phys, - virtual_start: NonNull::new((virt_page + offset) as *mut T).unwrap(), - region_length: size, - mapped_length: map_size, - handler: self.clone(), - } - } - fn unmap_physical_region(region: &PhysicalMapping) { - let virt_page = region.virtual_start.addr().get() & PAGE_MASK; - unsafe { - libredox::call::munmap(virt_page as *mut (), region.mapped_length) - .expect("failed to unmap physical region") - } - } - - fn read_u8(&self, address: usize) -> u8 { - log::trace!("read u8 {:X}", address); - if let Ok(mut page_cache) = self.page_cache.lock() { - if let Ok(value) = page_cache.read_from_phys::(address) { - return value; - } - } - log::error!("failed to read u8 {:#x}", address); - 0 - } - fn read_u16(&self, address: usize) -> u16 { - log::trace!("read u16 {:X}", address); - if let Ok(mut page_cache) = self.page_cache.lock() { - if let Ok(value) = page_cache.read_from_phys::(address) { - return value; - } - } - log::error!("failed to read u16 {:#x}", address); - 0 - } - fn read_u32(&self, address: usize) -> u32 { - log::trace!("read u32 {:X}", address); - if let Ok(mut page_cache) = self.page_cache.lock() { - if let Ok(value) = page_cache.read_from_phys::(address) { - return value; - } - } - log::error!("failed to read u32 {:#x}", address); - 0 - } - fn read_u64(&self, address: usize) -> u64 { - log::trace!("read u64 {:X}", address); - if let Ok(mut page_cache) = self.page_cache.lock() { - if let Ok(value) = page_cache.read_from_phys::(address) { - return value; - } - } - log::error!("failed to read u64 {:#x}", address); - 0 - } - - fn write_u8(&self, address: usize, value: u8) { - log::trace!("write u8 {:X} = {:X}", address, value); - if let Ok(mut page_cache) = self.page_cache.lock() { - if page_cache.write_to_phys::(address, value).is_ok() { - return; - } - } - log::error!("failed to write u8 {:#x}", address); - } - fn write_u16(&self, address: usize, value: u16) { - log::trace!("write u16 {:X} = {:X}", address, value); - if let Ok(mut page_cache) = self.page_cache.lock() { - if page_cache.write_to_phys::(address, value).is_ok() { - return; - } - } - log::error!("failed to write u16 {:#x}", address); - } - fn write_u32(&self, address: usize, value: u32) { - log::trace!("write u32 {:X} = {:X}", address, value); - if let Ok(mut page_cache) = self.page_cache.lock() { - if page_cache.write_to_phys::(address, value).is_ok() { - return; - } - } - log::error!("failed to write u32 {:#x}", address); - } - fn write_u64(&self, address: usize, value: u64) { - log::trace!("write u64 {:X} = {:X}", address, value); - if let Ok(mut page_cache) = self.page_cache.lock() { - if page_cache.write_to_phys::(address, value).is_ok() { - return; - } - } - log::error!("failed to write u64 {:#x}", address); - } - - // Pio must be enabled via syscall::iopl - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - fn read_io_u8(&self, port: u16) -> u8 { - Pio::::new(port).read() - } - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - fn read_io_u16(&self, port: u16) -> u16 { - Pio::::new(port).read() - } - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - fn read_io_u32(&self, port: u16) -> u32 { - Pio::::new(port).read() - } - - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - fn write_io_u8(&self, port: u16, value: u8) { - Pio::::new(port).write(value) - } - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - fn write_io_u16(&self, port: u16, value: u16) { - Pio::::new(port).write(value) - } - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - fn write_io_u32(&self, port: u16, value: u32) { - Pio::::new(port).write(value) - } - - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - fn read_io_u8(&self, port: u16) -> u8 { - log::error!("cannot read u8 from port 0x{port:04X}"); - 0 - } - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - fn read_io_u16(&self, port: u16) -> u16 { - log::error!("cannot read u16 from port 0x{port:04X}"); - 0 - } - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - fn read_io_u32(&self, port: u16) -> u32 { - log::error!("cannot read u32 from port 0x{port:04X}"); - 0 - } - - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - fn write_io_u8(&self, port: u16, value: u8) { - log::error!("cannot write 0x{value:02X} to port 0x{port:04X}"); - } - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - fn write_io_u16(&self, port: u16, value: u16) { - log::error!("cannot write 0x{value:04X} to port 0x{port:04X}"); - } - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - fn write_io_u32(&self, port: u16, value: u32) { - log::error!("cannot write 0x{value:08X} to port 0x{port:04X}"); - } - - fn read_pci_u8(&self, addr: PciAddress, off: u16) -> u8 { - let mut value = [0u8]; - self.read_pci(addr, off, &mut value); - value[0] - } - fn read_pci_u16(&self, addr: PciAddress, off: u16) -> u16 { - let mut value = [0u8; 2]; - self.read_pci(addr, off, &mut value); - u16::from_le_bytes(value) - } - fn read_pci_u32(&self, addr: PciAddress, off: u16) -> u32 { - let mut value = [0u8; 4]; - self.read_pci(addr, off, &mut value); - u32::from_le_bytes(value) - } - fn write_pci_u8(&self, addr: PciAddress, off: u16, value: u8) { - self.write_pci(addr, off, &[value]); - } - fn write_pci_u16(&self, addr: PciAddress, off: u16, value: u16) { - self.write_pci(addr, off, &value.to_le_bytes()); - } - fn write_pci_u32(&self, addr: PciAddress, off: u16, value: u32) { - self.write_pci(addr, off, &value.to_le_bytes()); - } - - fn nanos_since_boot(&self) -> u64 { - let ts = libredox::call::clock_gettime(libredox::flag::CLOCK_MONOTONIC) - .expect("failed to get time"); - (ts.tv_sec as u64) * 1_000_000_000 + (ts.tv_nsec as u64) - } - - fn stall(&self, microseconds: u64) { - let start = std::time::Instant::now(); - while start.elapsed().as_micros() < microseconds.into() { - std::hint::spin_loop(); - } - } - - fn sleep(&self, milliseconds: u64) { - std::thread::sleep(std::time::Duration::from_millis(milliseconds)); - } - - fn create_mutex(&self) -> Handle { - log::debug!("TODO: Handler::create_mutex"); - Handle(0) - } - - fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), AmlError> { - log::debug!("TODO: Handler::acquire"); - Ok(()) - } - - fn release(&self, mutex: Handle) { - log::debug!("TODO: Handler::release"); - } -} diff --git a/recipes/core/base/drivers/acpid/src/ec.rs b/recipes/core/base/drivers/acpid/src/ec.rs deleted file mode 100644 index c322790af6..0000000000 --- a/recipes/core/base/drivers/acpid/src/ec.rs +++ /dev/null @@ -1,256 +0,0 @@ -use std::time::Duration; - -use acpi::aml::{ - op_region::{OpRegion, RegionHandler, RegionSpace}, - AmlError, -}; -use common::{ - io::{Io, Pio}, - timeout::Timeout, -}; -use log::*; - -const EC_DATA: u16 = 0x62; -const EC_SC: u16 = 0x66; - -const OBF: u8 = 1 << 0; // output full / data ready for host <> empty -const IBF: u8 = 1 << 1; // input full / data ready for ec <> empty -const CMD: u8 = 1 << 3; // byte in data reg is command <> data -const BURST: u8 = 1 << 4; // burst mode <> normal mode -const SCI_EVT: u8 = 1 << 5; // sci event pending <> not -const SMI_EVT: u8 = 1 << 6; // smi event pending <> not - -const RD_EC: u8 = 0x80; -const WR_EC: u8 = 0x81; -const BE_EC: u8 = 0x82; -const BD_EC: u8 = 0x83; -const QR_EC: u8 = 0x84; - -const BURST_ACK: u8 = 0x90; - -pub const DEFAULT_EC_TIMEOUT: Duration = Duration::from_millis(10); - -#[repr(transparent)] -pub struct ScBits(u8); -#[allow(dead_code)] -impl ScBits { - const fn obf(&self) -> bool { - (self.0 & OBF) != 0 - } - const fn ibf(&self) -> bool { - (self.0 & IBF) != 0 - } - const fn cmd(&self) -> bool { - (self.0 & CMD) != 0 - } - const fn burst(&self) -> bool { - (self.0 & BURST) != 0 - } - const fn sci_evt(&self) -> bool { - (self.0 & SCI_EVT) != 0 - } - const fn smi_evt(&self) -> bool { - (self.0 & SMI_EVT) != 0 - } -} - -#[derive(Debug, Clone, Copy)] -pub struct Ec { - sc: u16, - data: u16, - - timeout: Duration, -} -impl Ec { - pub fn new() -> Self { - Self { - sc: EC_SC, - data: EC_DATA, - timeout: DEFAULT_EC_TIMEOUT, - } - } - #[allow(dead_code)] - pub fn with_address(sc: u16, data: u16, timeout: Duration) -> Self { - Self { sc, data, timeout } - } - #[inline] - fn read_reg_sc(&self) -> ScBits { - ScBits(Pio::::new(self.sc).read()) - } - #[inline] - fn read_reg_data(&self) -> u8 { - Pio::::new(self.data).read() - } - #[inline] - fn write_reg_sc(&self, value: u8) { - Pio::::new(self.sc).write(value); - } - #[inline] - fn write_reg_data(&self, value: u8) { - Pio::::new(self.data).write(value); - } - #[inline] - fn wait_for_write_ready(&self) -> Option<()> { - let timeout = Timeout::new(self.timeout); - loop { - if !self.read_reg_sc().ibf() { - return Some(()); - } - timeout.run().ok()?; - } - } - #[inline] - fn wait_for_read_ready(&self) -> Option<()> { - let timeout = Timeout::new(self.timeout); - loop { - if self.read_reg_sc().obf() { - return Some(()); - } - timeout.run().ok()?; - } - } - - //https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/12_ACPI_Embedded_Controller_Interface_Specification/embedded-controller-command-set.html - pub fn read(&self, address: u8) -> Option { - trace!("ec read addr: {:x}", address); - self.wait_for_write_ready()?; - - self.write_reg_sc(RD_EC); - - self.wait_for_write_ready()?; - - self.write_reg_data(address); - - self.wait_for_read_ready()?; - - let val = self.read_reg_data(); - trace!("got: {:x}", val); - Some(val) - } - pub fn write(&self, address: u8, value: u8) -> Option<()> { - trace!("ec write addr: {:x}, with: {:x}", address, value); - self.wait_for_write_ready()?; - - self.write_reg_sc(WR_EC); - - self.wait_for_write_ready()?; - - self.write_reg_data(address); - - self.wait_for_write_ready()?; - - self.write_reg_data(value); - trace!("done"); - Some(()) - } - // disabled if not met - // First Access - 400 microseconds - // Subsequent Accesses - 50 microseconds each - // Total Burst Time - 1 millisecond - //Accesses should be responded to within 50 microseconds. - #[allow(dead_code)] - fn enable_burst(&self) -> bool { - trace!("ec burst enable"); - self.wait_for_write_ready(); - - self.write_reg_sc(BE_EC); - - self.wait_for_read_ready(); - - let res = self.read_reg_data() == BURST_ACK; - trace!("success: {}", res); - res - } - #[allow(dead_code)] - fn disable_burst(&self) { - trace!("ec burst disable"); - self.wait_for_write_ready(); - self.write_reg_sc(BD_EC); - trace!("done"); - } - //OSPM driver sends this command when the SCI_EVT flag in the EC_SC register is set. - #[allow(dead_code)] - fn queue_query(&mut self) -> u8 { - trace!("ec query"); - self.wait_for_write_ready(); - - self.write_reg_sc(QR_EC); - - self.wait_for_read_ready(); - - let val = self.read_reg_data(); - trace!("got: {}", val); - val - } -} -impl RegionHandler for Ec { - fn read_u8( - &self, - region: &acpi::aml::op_region::OpRegion, - offset: usize, - ) -> Result { - assert_eq!(region.space, RegionSpace::EmbeddedControl); - self.read(offset as u8).ok_or(AmlError::MutexAcquireTimeout) // TODO proper error type - } - fn write_u8( - &self, - region: &OpRegion, - offset: usize, - value: u8, - ) -> Result<(), acpi::aml::AmlError> { - assert_eq!(region.space, RegionSpace::EmbeddedControl); - self.write(offset as u8, value) - .ok_or(AmlError::MutexAcquireTimeout) // TODO proper error type - } - fn read_u16(&self, _region: &OpRegion, _offset: usize) -> Result { - warn!("Got u16 EC read from AML!"); - Err(acpi::aml::AmlError::NoHandlerForRegionAccess( - RegionSpace::EmbeddedControl, - )) // TODO proper error type - } - fn read_u32(&self, _region: &OpRegion, _offset: usize) -> Result { - warn!("Got u32 EC read from AML!"); - Err(acpi::aml::AmlError::NoHandlerForRegionAccess( - RegionSpace::EmbeddedControl, - )) // TODO proper error type - } - fn read_u64(&self, _region: &OpRegion, _offset: usize) -> Result { - warn!("Got u64 EC read from AML!"); - Err(acpi::aml::AmlError::NoHandlerForRegionAccess( - RegionSpace::EmbeddedControl, - )) // TODO proper error type - } - fn write_u16( - &self, - _region: &OpRegion, - _offset: usize, - _value: u16, - ) -> Result<(), acpi::aml::AmlError> { - warn!("Got u16 EC write from AML!"); - Err(acpi::aml::AmlError::NoHandlerForRegionAccess( - RegionSpace::EmbeddedControl, - )) // TODO proper error type - } - fn write_u32( - &self, - _region: &OpRegion, - _offset: usize, - _value: u32, - ) -> Result<(), acpi::aml::AmlError> { - warn!("Got u32 EC write from AML!"); - Err(acpi::aml::AmlError::NoHandlerForRegionAccess( - RegionSpace::EmbeddedControl, - )) // TODO proper error type - } - fn write_u64( - &self, - _region: &OpRegion, - _offset: usize, - _value: u64, - ) -> Result<(), acpi::aml::AmlError> { - warn!("Got u64 EC write from AML!"); - Err(acpi::aml::AmlError::NoHandlerForRegionAccess( - RegionSpace::EmbeddedControl, - )) // TODO proper error type - } -} diff --git a/recipes/core/base/drivers/acpid/src/main.rs b/recipes/core/base/drivers/acpid/src/main.rs deleted file mode 100644 index 8f99f2ea9f..0000000000 --- a/recipes/core/base/drivers/acpid/src/main.rs +++ /dev/null @@ -1,191 +0,0 @@ -use std::convert::TryFrom; -use std::fs::File; -use std::mem; -use std::ops::ControlFlow; -use std::os::unix::io::AsRawFd; -use std::sync::Arc; - -use ::acpi::aml::op_region::{RegionHandler, RegionSpace}; -use event::{EventFlags, RawEventQueue}; -use redox_scheme::{scheme::register_sync_scheme, Socket}; -use scheme_utils::Blocking; - -mod acpi; -mod aml_physmem; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod ec; - -mod scheme; - -fn daemon(daemon: daemon::Daemon) -> ! { - common::setup_logging( - "misc", - "acpi", - "acpid", - common::output_level(), - common::file_level(), - ); - - log::info!("acpid start"); - - let rxsdt_raw_data: Arc<[u8]> = match std::fs::read("/scheme/kernel.acpi/rxsdt") { - Ok(data) => data.into(), - Err(err) => { - log::error!("acpid: failed to read `/scheme/kernel.acpi/rxsdt`: {}", err); - std::process::exit(1); - } - }; - - if rxsdt_raw_data.is_empty() { - log::info!("System doesn't use ACPI"); - daemon.ready(); - std::process::exit(0); - } - - let sdt = match self::acpi::Sdt::new(rxsdt_raw_data) { - Ok(sdt) => sdt, - Err(err) => { - log::error!("acpid: failed to parse [RX]SDT: {:?}", err); - std::process::exit(1); - } - }; - - let mut thirty_two_bit; - let mut sixty_four_bit; - - let physaddrs_iter = match &sdt.signature { - b"RSDT" => { - thirty_two_bit = sdt - .data() - .chunks(mem::size_of::()) - // TODO: With const generics, the compiler has some way of doing this for static sizes. - .map(|chunk| <[u8; mem::size_of::()]>::try_from(chunk).unwrap()) - .map(|chunk| u32::from_le_bytes(chunk)) - .map(u64::from); - - &mut thirty_two_bit as &mut dyn Iterator - } - b"XSDT" => { - sixty_four_bit = sdt - .data() - .chunks(mem::size_of::()) - .map(|chunk| <[u8; mem::size_of::()]>::try_from(chunk).unwrap()) - .map(|chunk| u64::from_le_bytes(chunk)); - - &mut sixty_four_bit as &mut dyn Iterator - } - _ => { - log::error!("acpid: expected [RX]SDT from kernel to be RSDT or XSDT"); - std::process::exit(1); - } - }; - - let region_handlers: Vec<(RegionSpace, Box)> = vec![ - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - (RegionSpace::EmbeddedControl, Box::new(ec::Ec::new())), - ]; - let acpi_context = self::acpi::AcpiContext::init(physaddrs_iter, region_handlers); - - // TODO: I/O permission bitmap? - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - if let Err(err) = common::acquire_port_io_rights() { - log::error!("acpid: failed to set I/O privilege level to Ring 3: {:?}", err); - std::process::exit(1); - } - - let shutdown_pipe = match File::open("/scheme/kernel.acpi/kstop") { - Ok(f) => f, - Err(err) => { - log::error!("acpid: failed to open `/scheme/kernel.acpi/kstop`: {}", err); - std::process::exit(1); - } - }; - - let mut event_queue = match RawEventQueue::new() { - Ok(q) => q, - Err(err) => { - log::error!("acpid: failed to create event queue: {:?}", err); - std::process::exit(1); - } - }; - let socket = match Socket::nonblock() { - Ok(s) => s, - Err(err) => { - log::error!("acpid: failed to create scheme socket: {:?}", err); - std::process::exit(1); - } - }; - - let mut scheme = self::scheme::AcpiScheme::new(&acpi_context, &socket); - let mut handler = Blocking::new(&socket, 16); - - if let Err(err) = event_queue - .subscribe(shutdown_pipe.as_raw_fd() as usize, 0, EventFlags::READ) - { - log::error!("acpid: failed to register shutdown pipe for event queue: {:?}", err); - std::process::exit(1); - } - if let Err(err) = event_queue - .subscribe(socket.inner().raw(), 1, EventFlags::READ) - { - log::error!("acpid: failed to register scheme socket for event queue: {:?}", err); - std::process::exit(1); - } - - if let Err(err) = register_sync_scheme(&socket, "acpi", &mut scheme) { - log::error!("acpid: failed to register acpi scheme to namespace: {:?}", err); - std::process::exit(1); - } - - daemon.ready(); - - if let Err(err) = libredox::call::setrens(0, 0) { - log::error!("acpid: failed to enter null namespace: {}", err); - std::process::exit(1); - } - - let mut mounted = true; - while mounted { - let event = match event_queue.next().transpose() { - Ok(Some(ev)) => ev, - Ok(None) => break, - Err(err) => { - log::error!("acpid: failed to read event file: {:?}", err); - break; - } - }; - - if event.fd == socket.inner().raw() { - loop { - match handler.process_requests_nonblocking(&mut scheme) { - Ok(flow) => match flow { - ControlFlow::Continue(()) => {} - ControlFlow::Break(()) => break, - }, - Err(err) => { - log::error!("acpid: failed to process requests: {:?}", err); - break; - } - } - } - } else if event.fd == shutdown_pipe.as_raw_fd() as usize { - log::info!("Received shutdown request from kernel."); - mounted = false; - } else { - log::debug!("Received request to unknown fd: {}", event.fd); - continue; - } - } - - drop(shutdown_pipe); - drop(event_queue); - - acpi_context.set_global_s_state(5); - - unreachable!("System should have shut down before this is entered"); -} - -fn main() { - common::init(); - daemon::Daemon::new(daemon); -} diff --git a/recipes/core/base/drivers/acpid/src/scheme.rs b/recipes/core/base/drivers/acpid/src/scheme.rs deleted file mode 100644 index 5a5040c385..0000000000 --- a/recipes/core/base/drivers/acpid/src/scheme.rs +++ /dev/null @@ -1,485 +0,0 @@ -use acpi::aml::namespace::AmlName; -use amlserde::aml_serde_name::to_aml_format; -use amlserde::AmlSerdeValue; -use core::str; -use libredox::Fd; -use parking_lot::RwLockReadGuard; -use redox_scheme::scheme::SchemeSync; -use redox_scheme::{CallerCtx, OpenResult, SendFdRequest, Socket}; -use ron::de::SpannedError; -use scheme_utils::HandleMap; -use std::convert::{TryFrom, TryInto}; -use std::str::FromStr; -use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; -use syscall::schemev2::NewFdFlags; -use syscall::FobtainFdFlags; - -use syscall::data::Stat; -use syscall::error::{Error, Result}; -use syscall::error::{EACCES, EBADF, EBADFD, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR}; -use syscall::flag::{MODE_DIR, MODE_FILE}; -use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDONLY, O_STAT, O_SYMLINK}; -use syscall::{EOVERFLOW, EPERM}; - -use crate::acpi::{AcpiContext, AmlSymbols, SdtSignature}; - -pub struct AcpiScheme<'acpi, 'sock> { - ctx: &'acpi AcpiContext, - handles: HandleMap>, - pci_fd: Option, - socket: &'sock Socket, -} - -struct Handle<'a> { - kind: HandleKind<'a>, - stat: bool, - allowed_to_eval: bool, -} -enum HandleKind<'a> { - TopLevel, - Tables, - Table(SdtSignature), - Symbols(RwLockReadGuard<'a, AmlSymbols>), - Symbol { name: String, description: String }, - SchemeRoot, - RegisterPci, -} - -impl HandleKind<'_> { - fn is_dir(&self) -> bool { - match self { - Self::TopLevel => true, - Self::Tables => true, - Self::Table(_) => false, - Self::Symbols(_) => true, - Self::Symbol { .. } => false, - Self::SchemeRoot => false, - Self::RegisterPci => false, - } - } - fn len(&self, acpi_ctx: &AcpiContext) -> Result { - Ok(match self { - // Files - Self::Table(signature) => acpi_ctx - .sdt_from_signature(signature) - .ok_or(Error::new(EBADFD))? - .length(), - Self::Symbol { description, .. } => description.len(), - // Directories - Self::TopLevel | Self::Symbols(_) | Self::Tables => 0, - Self::SchemeRoot | Self::RegisterPci => return Err(Error::new(EBADF)), - }) - } -} - -impl<'acpi, 'sock> AcpiScheme<'acpi, 'sock> { - pub fn new(ctx: &'acpi AcpiContext, socket: &'sock Socket) -> Self { - Self { - ctx, - handles: HandleMap::new(), - pci_fd: None, - socket, - } - } -} - -fn parse_hex_digit(hex: u8) -> Option { - let hex = hex.to_ascii_lowercase(); - - if hex >= b'a' && hex <= b'f' { - Some(hex - b'a' + 10) - } else if hex >= b'0' && hex <= b'9' { - Some(hex - b'0') - } else { - None - } -} - -fn parse_hex_2digit(hex: &[u8]) -> Option { - parse_hex_digit(hex[0]) - .and_then(|most_significant| Some((most_significant << 4) | parse_hex_digit(hex[1])?)) -} - -fn parse_oem_id(hex: [u8; 12]) -> Option<[u8; 6]> { - Some([ - parse_hex_2digit(&hex[0..2])?, - parse_hex_2digit(&hex[2..4])?, - parse_hex_2digit(&hex[4..6])?, - parse_hex_2digit(&hex[6..8])?, - parse_hex_2digit(&hex[8..10])?, - parse_hex_2digit(&hex[10..12])?, - ]) -} -fn parse_oem_table_id(hex: [u8; 16]) -> Option<[u8; 8]> { - Some([ - parse_hex_2digit(&hex[0..2])?, - parse_hex_2digit(&hex[2..4])?, - parse_hex_2digit(&hex[4..6])?, - parse_hex_2digit(&hex[6..8])?, - parse_hex_2digit(&hex[8..10])?, - parse_hex_2digit(&hex[10..12])?, - parse_hex_2digit(&hex[12..14])?, - parse_hex_2digit(&hex[14..16])?, - ]) -} - -fn parse_table(table: &[u8]) -> Option { - let signature_part = table.get(..4)?; - let first_hyphen = table.get(4)?; - let oem_id_part = table.get(5..17)?; - let second_hyphen = table.get(17)?; - let oem_table_part = table.get(18..34)?; - - if *first_hyphen != b'-' { - return None; - } - if *second_hyphen != b'-' { - return None; - } - - if table.len() > 34 { - return None; - } - - Some(SdtSignature { - signature: <[u8; 4]>::try_from(signature_part) - .expect("expected 4-byte slice to be convertible into [u8; 4]"), - oem_id: { - let hex = <[u8; 12]>::try_from(oem_id_part) - .expect("expected 12-byte slice to be convertible into [u8; 12]"); - parse_oem_id(hex)? - }, - oem_table_id: { - let hex = <[u8; 16]>::try_from(oem_table_part) - .expect("expected 16-byte slice to be convertible into [u8; 16]"); - parse_oem_table_id(hex)? - }, - }) -} - -impl SchemeSync for AcpiScheme<'_, '_> { - fn scheme_root(&mut self) -> Result { - Ok(self.handles.insert(Handle { - stat: false, - kind: HandleKind::SchemeRoot, - allowed_to_eval: false, - })) - } - fn openat( - &mut self, - dirfd: usize, - path: &str, - flags: usize, - _fcntl_flags: u32, - ctx: &CallerCtx, - ) -> Result { - let handle = self.handles.get(dirfd)?; - - let path = path.trim_start_matches('/'); - - let flag_stat = flags & O_STAT == O_STAT; - let flag_dir = flags & O_DIRECTORY == O_DIRECTORY; - - let kind = match handle.kind { - HandleKind::SchemeRoot => { - // TODO: arrayvec - let components = { - let mut v = arrayvec::ArrayVec::<&str, 3>::new(); - let it = path.split('/'); - for component in it.take(3) { - v.push(component); - } - - v - }; - - match &*components { - [""] => HandleKind::TopLevel, - ["register_pci"] => HandleKind::RegisterPci, - ["tables"] => HandleKind::Tables, - - ["tables", table] => { - let signature = parse_table(table.as_bytes()).ok_or(Error::new(ENOENT))?; - HandleKind::Table(signature) - } - - ["symbols"] => { - if let Ok(aml_symbols) = self.ctx.aml_symbols(self.pci_fd.as_ref()) { - HandleKind::Symbols(aml_symbols) - } else { - return Err(Error::new(EIO)); - } - } - - ["symbols", symbol] => { - if let Some(description) = self.ctx.aml_lookup(symbol) { - HandleKind::Symbol { - name: (*symbol).to_owned(), - description, - } - } else { - return Err(Error::new(ENOENT)); - } - } - - _ => return Err(Error::new(ENOENT)), - } - } - HandleKind::Symbols(ref aml_symbols) => { - if let Some(description) = aml_symbols.lookup(path) { - HandleKind::Symbol { - name: (*path).to_owned(), - description, - } - } else { - return Err(Error::new(ENOENT)); - } - } - _ => return Err(Error::new(EACCES)), - }; - - if kind.is_dir() && !flag_dir && !flag_stat { - return Err(Error::new(EISDIR)); - } else if !kind.is_dir() && flag_dir && !flag_stat { - return Err(Error::new(ENOTDIR)); - } - - let allowed_to_eval = if flags & O_ACCMODE == O_RDONLY || flag_stat { - false - } else if ctx.uid == 0 { - true - } else { - return Err(Error::new(EINVAL)); - }; - - if flags & O_SYMLINK == O_SYMLINK && !flag_stat { - return Err(Error::new(EINVAL)); - } - - let fd = self.handles.insert(Handle { - stat: flag_stat, - kind, - allowed_to_eval, - }); - - Ok(OpenResult::ThisScheme { - number: fd, - flags: NewFdFlags::POSITIONED, - }) - } - - fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { - let handle = self.handles.get(id)?; - - stat.st_size = handle - .kind - .len(self.ctx)? - .try_into() - .unwrap_or(u64::max_value()); - - if handle.kind.is_dir() { - stat.st_mode = MODE_DIR; - } else { - stat.st_mode = MODE_FILE; - } - - Ok(()) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _fcntl: u32, - _ctx: &CallerCtx, - ) -> Result { - let offset: usize = offset.try_into().map_err(|_| Error::new(EINVAL))?; - - let handle = self.handles.get_mut(id)?; - - if handle.stat { - return Err(Error::new(EBADF)); - } - - let src_buf = match &handle.kind { - HandleKind::Table(ref signature) => self - .ctx - .sdt_from_signature(signature) - .ok_or(Error::new(EBADFD))? - .as_slice(), - HandleKind::Symbol { description, .. } => description.as_bytes(), - _ => return Err(Error::new(EINVAL)), - }; - - let offset = std::cmp::min(src_buf.len(), offset); - let src_buf = &src_buf[offset..]; - - let to_copy = std::cmp::min(src_buf.len(), buf.len()); - - buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); - - Ok(to_copy) - } - - fn getdents<'buf>( - &mut self, - id: usize, - mut buf: DirentBuf<&'buf mut [u8]>, - opaque_offset: u64, - ) -> Result> { - let handle = self.handles.get_mut(id)?; - - match &handle.kind { - HandleKind::TopLevel => { - const TOPLEVEL_ENTRIES: &[&str] = &["tables", "symbols"]; - - for (idx, name) in TOPLEVEL_ENTRIES - .iter() - .enumerate() - .skip(opaque_offset as usize) - { - buf.entry(DirEntry { - inode: 0, - next_opaque_id: idx as u64 + 1, - name, - kind: DirentKind::Directory, - })?; - } - } - HandleKind::Symbols(aml_symbols) => { - for (idx, (symbol_name, _value)) in aml_symbols - .symbols_cache() - .iter() - .enumerate() - .skip(opaque_offset as usize) - { - buf.entry(DirEntry { - inode: 0, - next_opaque_id: idx as u64 + 1, - name: symbol_name.as_str(), - kind: DirentKind::Regular, - })?; - } - } - HandleKind::Tables => { - for (idx, table) in self - .ctx - .tables() - .iter() - .enumerate() - .skip(opaque_offset as usize) - { - let utf8_or_eio = |bytes| str::from_utf8(bytes).map_err(|_| Error::new(EIO)); - - let mut name = String::new(); - name.push_str(utf8_or_eio(&table.signature[..])?); - name.push('-'); - for byte in table.oem_id.iter() { - std::fmt::write(&mut name, format_args!("{:>02X}", byte)).unwrap(); - } - name.push('-'); - for byte in table.oem_table_id.iter() { - std::fmt::write(&mut name, format_args!("{:>02X}", byte)).unwrap(); - } - - buf.entry(DirEntry { - inode: 0, - next_opaque_id: idx as u64 + 1, - name: &name, - kind: DirentKind::Regular, - })?; - } - } - _ => return Err(Error::new(EIO)), - } - - Ok(buf) - } - - fn call( - &mut self, - id: usize, - payload: &mut [u8], - _metadata: &[u64], - _ctx: &CallerCtx, - ) -> Result { - let handle = self.handles.get_mut(id)?; - if !handle.allowed_to_eval { - return Err(Error::new(EPERM)); - } - - let Ok(args): Result, SpannedError> = ron::de::from_bytes(payload) - else { - return Err(Error::new(EINVAL)); - }; - - let HandleKind::Symbol { name, .. } = &handle.kind else { - return Err(Error::new(EBADF)); - }; - - let Ok(aml_name) = AmlName::from_str(&to_aml_format(name)) else { - log::error!("Failed to convert symbol name: \"{name}\" to aml name!"); - return Err(Error::new(EBADF)); - }; - - let Ok(result) = self.ctx.aml_eval(aml_name, args) else { - return Err(Error::new(EINVAL)); - }; - - let Ok(serialized_result) = ron::ser::to_string(&result) else { - log::error!("Failed to serialize aml result!"); - return Err(Error::new(EINVAL)); - }; - - let byte_result = serialized_result.as_bytes(); - let result_len = byte_result.len(); - - if result_len > payload.len() { - return Err(Error::new(EOVERFLOW)); - } - - payload[..result_len].copy_from_slice(byte_result); - - Ok(result_len) - } - - fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result { - let id = sendfd_request.id(); - let num_fds = sendfd_request.num_fds(); - - let handle = self.handles.get(id)?; - if !matches!(handle.kind, HandleKind::RegisterPci) { - return Err(Error::new(EACCES)); - } - - if num_fds == 0 { - return Ok(0); - } - - if num_fds > 1 { - return Err(Error::new(EINVAL)); - } - let mut new_fd = usize::MAX; - if let Err(e) = sendfd_request.obtain_fd( - &self.socket, - FobtainFdFlags::UPPER_TBL, - std::slice::from_mut(&mut new_fd), - ) { - return Err(e); - } - let new_fd = libredox::Fd::new(new_fd); - - if self.pci_fd.is_some() { - return Err(Error::new(EINVAL)); - } else { - self.pci_fd = Some(new_fd); - } - - Ok(num_fds) - } - - fn on_close(&mut self, id: usize) { - self.handles.remove(id); - } -} diff --git a/recipes/core/base/drivers/amlserde/Cargo.toml b/recipes/core/base/drivers/amlserde/Cargo.toml deleted file mode 100644 index 3a47c9588e..0000000000 --- a/recipes/core/base/drivers/amlserde/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "amlserde" -description = "Library for serializing AML symbols" -version = "0.0.1" -authors = ["Ron Williams"] -repository = "https://gitlab.redox-os.org/redox-os/drivers" -categories = ["hardware-support"] -license = "MIT/Apache-2.0" -edition = "2021" - -[dependencies] -acpi.workspace = true -serde.workspace = true -toml.workspace = true diff --git a/recipes/core/base/drivers/amlserde/src/lib.rs b/recipes/core/base/drivers/amlserde/src/lib.rs deleted file mode 100644 index 918b8ee599..0000000000 --- a/recipes/core/base/drivers/amlserde/src/lib.rs +++ /dev/null @@ -1,484 +0,0 @@ -use acpi::{ - aml::{ - namespace::AmlName, - object::{ - FieldAccessType, FieldFlags, FieldUnit, FieldUnitKind, FieldUpdateRule, MethodFlags, - Object, ReferenceKind, WrappedObject, - }, - op_region::{OpRegion, RegionSpace}, - Interpreter, - }, - Handle, Handler, -}; -use serde::{Deserialize, Serialize}; -use std::{ - ops::{Deref, Shl}, - str::FromStr, - sync::{ - atomic::{AtomicU64, Ordering}, - Arc, - }, -}; - -#[derive(Debug, Serialize, Deserialize)] -pub struct AmlSerde { - pub name: String, - pub value: AmlSerdeValue, -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum AmlSerdeValue { - Uninitialized, - Integer(u64), - String(String), - OpRegion { - region: AmlSerdeRegionSpace, - offset: u64, - length: u64, - parent_device: String, - }, - Field { - kind: AmlSerdeFieldKind, - flags: AmlSerdeFieldFlags, - offset: u64, - length: u64, - }, - Device, - Event(u64), - Method { - arg_count: usize, - serialize: bool, - sync_level: u8, - }, - Buffer(Vec), - BufferField { - offset: u64, - length: u64, - data: Box, - }, - Processor { - id: u8, - pblk_address: u32, - pblk_len: u8, - }, - Mutex { - mutex: u32, - sync_level: u8, - }, - Reference { - kind: AmlSerdeReferenceKind, - inner: Box, - }, - Package { - contents: Vec, - }, - PowerResource { - system_level: u8, - resource_order: u16, - }, - RawDataBuffer, - ThermalZone, - Debug, -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum AmlSerdeRegionSpace { - SystemMemory, - SystemIo, - PciConfig, - EmbeddedControl, - SMBus, - SystemCmos, - PciBarTarget, - IPMI, - GeneralPurposeIo, - GenericSerialBus, - Pcc, - OemDefined(u8), -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum AmlSerdeFieldKind { - Normal { - region: Box, - }, - Bank { - region: Box, - bank: Box, - bank_value: u64, - }, - Index { - index: Box, - data: Box, - }, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct AmlSerdeFieldFlags { - pub access_type: AmlSerdeFieldAccessType, - pub lock_rule: bool, // bit 4 - pub update_rule: AmlSerdeFieldUpdateRule, -} -impl Into for AmlSerdeFieldFlags { - fn into(self) -> u8 { - // bits 0..4 - (self.access_type as u8) + - // bit 4 - (self.lock_rule as u8).shl(4) + - // bits 5..7 - (self.update_rule as u8).shl(5) - } -} - -#[derive(Debug, Serialize, Deserialize)] -#[repr(u8)] -pub enum AmlSerdeFieldAccessType { - Any = 0, - Byte = 1, - Word = 2, - DWord = 3, - QWord = 4, - Buffer = 5, -} - -#[derive(Debug, Serialize, Deserialize)] -#[repr(u8)] -pub enum AmlSerdeFieldUpdateRule { - Preserve = 0, - WriteAsOnes = 1, - WriteAsZeros = 2, -} - -#[derive(Debug, Serialize, Deserialize)] -pub enum AmlSerdeReferenceKind { - RefOf, - Local, - Arg, - Index, - Named, - Unresolved, -} - -impl AmlSerde { - pub fn default() -> Self { - Self { - name: "name".to_owned(), - value: AmlSerdeValue::String(String::default()), - } - } - - pub fn from_aml(aml_context: &Interpreter, aml_name: &AmlName) -> Option { - //TODO: why does namespace.get not take a reference to aml_name - let aml_value = if let Ok(aml_value) = aml_context.namespace.lock().get(aml_name.clone()) { - aml_value - } else { - return None; - }; - - let value = if let Some(value) = AmlSerdeValue::from_aml_value(aml_value.deref()) { - value - } else { - return None; - }; - - Some(AmlSerde { - name: aml_name.to_string(), - value, - }) - } -} - -impl AmlSerdeValue { - pub fn default() -> Self { - AmlSerdeValue::String("".to_owned()) - } - - pub fn from_aml_value(aml_value: &Object) -> Option { - Some(match aml_value { - Object::Uninitialized => AmlSerdeValue::Uninitialized, - Object::Integer(n) => AmlSerdeValue::Integer(n.to_owned()), - Object::String(s) => AmlSerdeValue::String(s.to_owned()), - Object::OpRegion(region) => AmlSerdeValue::OpRegion { - region: match region.space { - RegionSpace::SystemMemory => AmlSerdeRegionSpace::SystemMemory, - RegionSpace::SystemIO => AmlSerdeRegionSpace::SystemIo, - RegionSpace::PciConfig => AmlSerdeRegionSpace::PciConfig, - RegionSpace::EmbeddedControl => AmlSerdeRegionSpace::EmbeddedControl, - RegionSpace::SmBus => AmlSerdeRegionSpace::SMBus, - RegionSpace::SystemCmos => AmlSerdeRegionSpace::SystemCmos, - RegionSpace::PciBarTarget => AmlSerdeRegionSpace::PciBarTarget, - RegionSpace::Ipmi => AmlSerdeRegionSpace::IPMI, - RegionSpace::GeneralPurposeIo => AmlSerdeRegionSpace::GeneralPurposeIo, - RegionSpace::GenericSerialBus => AmlSerdeRegionSpace::GenericSerialBus, - RegionSpace::Pcc => AmlSerdeRegionSpace::Pcc, - RegionSpace::Oem(n) => AmlSerdeRegionSpace::OemDefined(n.to_owned()), - }, - offset: region.base, - length: region.length, - parent_device: region.parent_device_path.to_string(), - }, - Object::FieldUnit(field) => AmlSerdeValue::Field { - kind: match &field.kind { - FieldUnitKind::Normal { region } => AmlSerdeFieldKind::Normal { - region: AmlSerdeValue::from_aml_value(region.deref()).map(Box::new)?, - }, - FieldUnitKind::Bank { - region, - bank, - bank_value, - } => AmlSerdeFieldKind::Bank { - region: AmlSerdeValue::from_aml_value(region.deref()).map(Box::new)?, - bank: AmlSerdeValue::from_aml_value(bank.deref()).map(Box::new)?, - bank_value: bank_value.to_owned(), - }, - FieldUnitKind::Index { index, data } => AmlSerdeFieldKind::Index { - index: AmlSerdeValue::from_aml_value(index.deref()).map(Box::new)?, - data: AmlSerdeValue::from_aml_value(data.deref()).map(Box::new)?, - }, - }, - flags: AmlSerdeFieldFlags { - access_type: match field.flags.access_type() { - Ok(FieldAccessType::Any) => AmlSerdeFieldAccessType::Any, - Ok(FieldAccessType::Byte) => AmlSerdeFieldAccessType::Byte, - Ok(FieldAccessType::Word) => AmlSerdeFieldAccessType::Word, - Ok(FieldAccessType::DWord) => AmlSerdeFieldAccessType::DWord, - Ok(FieldAccessType::QWord) => AmlSerdeFieldAccessType::QWord, - Ok(FieldAccessType::Buffer) => AmlSerdeFieldAccessType::Buffer, - _ => return None, - }, - lock_rule: field.flags.lock_rule(), - update_rule: match field.flags.update_rule() { - FieldUpdateRule::Preserve => AmlSerdeFieldUpdateRule::Preserve, - FieldUpdateRule::WriteAsOnes => AmlSerdeFieldUpdateRule::WriteAsOnes, - FieldUpdateRule::WriteAsZeros => AmlSerdeFieldUpdateRule::WriteAsZeros, - }, - }, - offset: field.bit_index as u64, - length: field.bit_length as u64, - }, - Object::Device => AmlSerdeValue::Device, - Object::Event(event) => AmlSerdeValue::Event(event.load(Ordering::Relaxed)), - Object::Method { flags, code: _ } => AmlSerdeValue::Method { - arg_count: flags.arg_count(), - serialize: flags.serialize(), - sync_level: flags.sync_level(), - }, - //TODO: distinguish from Method? - Object::NativeMethod { f: _, flags } => AmlSerdeValue::Method { - arg_count: flags.arg_count(), - serialize: flags.serialize(), - sync_level: flags.sync_level(), - }, - Object::Buffer(buffer_data) => AmlSerdeValue::Buffer(buffer_data.to_owned()), - Object::BufferField { - buffer, - offset, - length, - } => AmlSerdeValue::BufferField { - offset: offset.to_owned() as u64, - length: length.to_owned() as u64, - data: AmlSerdeValue::from_aml_value(buffer.deref()).map(Box::new)?, - }, - Object::Processor { - proc_id, - pblk_address, - pblk_length, - } => AmlSerdeValue::Processor { - id: proc_id.to_owned(), - pblk_address: pblk_address.to_owned(), - pblk_len: pblk_length.to_owned(), - }, - Object::Mutex { mutex, sync_level } => AmlSerdeValue::Mutex { - mutex: mutex.0, - sync_level: sync_level.to_owned(), - }, - Object::Reference { kind, inner } => AmlSerdeValue::Reference { - kind: match kind { - ReferenceKind::RefOf => AmlSerdeReferenceKind::RefOf, - ReferenceKind::Local => AmlSerdeReferenceKind::Local, - ReferenceKind::Arg => AmlSerdeReferenceKind::Arg, - ReferenceKind::Index => AmlSerdeReferenceKind::Index, - ReferenceKind::Named => AmlSerdeReferenceKind::Named, - ReferenceKind::Unresolved => AmlSerdeReferenceKind::Unresolved, - }, - inner: AmlSerdeValue::from_aml_value(inner.deref()).map(Box::new)?, - }, - Object::Package(aml_contents) => AmlSerdeValue::Package { - contents: aml_contents - .iter() - .filter_map(|item| AmlSerdeValue::from_aml_value(item)) - .collect(), - }, - Object::PowerResource { - system_level, - resource_order, - } => AmlSerdeValue::PowerResource { - system_level: system_level.to_owned(), - resource_order: resource_order.to_owned(), - }, - Object::RawDataBuffer => AmlSerdeValue::RawDataBuffer, - Object::ThermalZone => AmlSerdeValue::ThermalZone, - Object::Debug => AmlSerdeValue::Debug, - }) - } - pub fn to_aml_object(self) -> Option { - Some(match self { - AmlSerdeValue::Uninitialized => Object::Uninitialized, - AmlSerdeValue::Integer(n) => Object::Integer(n), - AmlSerdeValue::String(s) => Object::String(s), - AmlSerdeValue::OpRegion { - region, - offset, - length, - parent_device, - } => Object::OpRegion(OpRegion { - space: match region { - AmlSerdeRegionSpace::PciConfig => RegionSpace::PciConfig, - AmlSerdeRegionSpace::EmbeddedControl => RegionSpace::EmbeddedControl, - AmlSerdeRegionSpace::SMBus => RegionSpace::SmBus, - AmlSerdeRegionSpace::SystemCmos => RegionSpace::SystemCmos, - AmlSerdeRegionSpace::PciBarTarget => RegionSpace::PciBarTarget, - AmlSerdeRegionSpace::IPMI => RegionSpace::Ipmi, - AmlSerdeRegionSpace::GeneralPurposeIo => RegionSpace::GeneralPurposeIo, - AmlSerdeRegionSpace::GenericSerialBus => RegionSpace::GenericSerialBus, - AmlSerdeRegionSpace::SystemMemory => RegionSpace::SystemMemory, - AmlSerdeRegionSpace::SystemIo => RegionSpace::SystemIO, - AmlSerdeRegionSpace::Pcc => RegionSpace::Pcc, - AmlSerdeRegionSpace::OemDefined(n) => RegionSpace::Oem(n), - }, - base: offset, - length, - // - parent_device_path: AmlName::from_str(&parent_device).ok()?, // TODO: Error value hidden - }), - AmlSerdeValue::Field { - kind, - flags, - offset, - length, - } => Object::FieldUnit(FieldUnit { - kind: match kind { - AmlSerdeFieldKind::Normal { region } => FieldUnitKind::Normal { - region: region.to_aml_object()?.wrap(), - }, - AmlSerdeFieldKind::Bank { - region, - bank, - bank_value, - } => FieldUnitKind::Bank { - region: region.to_aml_object()?.wrap(), - bank: bank.to_aml_object()?.wrap(), - bank_value: bank_value.to_owned(), - }, - AmlSerdeFieldKind::Index { index, data } => FieldUnitKind::Index { - index: index.to_aml_object()?.wrap(), - data: data.to_aml_object()?.wrap(), - }, - }, - flags: FieldFlags(flags.into()), - bit_index: offset as usize, - bit_length: length as usize, - }), - AmlSerdeValue::Device => Object::Device, - AmlSerdeValue::Event(event) => Object::Event(Arc::new(AtomicU64::new(event))), - AmlSerdeValue::Method { - arg_count, - serialize, - sync_level, - } => Object::Method { - code: (return None), //TODO figure out what to do here - //TODO check specs to see if all bit patterns are allowed - flags: MethodFlags( - (arg_count as u8).clamp(0, 7) - + (serialize as u8).shl(3) - + sync_level.clamp(0, 15).shl(4), - ), - }, - //TODO: handle native method? - AmlSerdeValue::Buffer(buffer_data) => Object::Buffer(buffer_data), - AmlSerdeValue::BufferField { - data, - offset, - length, - } => Object::BufferField { - offset: offset as usize, - length: length as usize, - buffer: data.to_aml_object()?.wrap(), - }, - AmlSerdeValue::Processor { - id, - pblk_address, - pblk_len, - } => Object::Processor { - proc_id: id, - pblk_address, - pblk_length: pblk_len, - }, - AmlSerdeValue::Mutex { mutex, sync_level } => Object::Mutex { - mutex: Handle(mutex), - sync_level: sync_level, - }, - AmlSerdeValue::Reference { kind, inner } => Object::Reference { - kind: match kind { - AmlSerdeReferenceKind::RefOf => ReferenceKind::RefOf, - AmlSerdeReferenceKind::Local => ReferenceKind::Local, - AmlSerdeReferenceKind::Arg => ReferenceKind::Arg, - AmlSerdeReferenceKind::Index => ReferenceKind::Index, - AmlSerdeReferenceKind::Named => ReferenceKind::Named, - AmlSerdeReferenceKind::Unresolved => ReferenceKind::Unresolved, - }, - inner: inner.to_aml_object()?.wrap(), - }, - AmlSerdeValue::Package { contents } => Object::Package( - contents - .into_iter() - .map(|item| item.to_aml_object().map(Object::wrap)) // TODO: see if errors should be ignored here - .collect::>>()?, - ), - AmlSerdeValue::PowerResource { - system_level, - resource_order, - } => Object::PowerResource { - system_level: system_level.to_owned(), - resource_order: resource_order.to_owned(), - }, - AmlSerdeValue::RawDataBuffer => Object::RawDataBuffer, - AmlSerdeValue::ThermalZone => Object::ThermalZone, - AmlSerdeValue::Debug => Object::Debug, - }) - } -} - -pub mod aml_serde_name { - use acpi::aml::namespace::AmlName; - - /// Add a leading backslash to make the name a valid - /// namespace reference - pub fn to_aml_format(pretty_name: &String) -> String { - format!("\\{}", pretty_name) - } - - /// convert a string from AML namespace style to - /// acpi symbol style - pub fn to_symbol(aml_style_name: &String) -> String { - let mut name = aml_style_name.to_owned(); - - // remove leading slash - name = name.trim_start_matches("\\").to_owned(); - // remove unnecessary underscores - while let Some(index) = name.find("_.") { - name.remove(index); - } - while name.len() > 0 && &name[name.len() - 1..] == "_" { - name.pop(); - } - name.shrink_to_fit(); - name - } - - /// Convert to string and remove - /// trailing underscores from each name segment - pub fn aml_to_symbol(aml_name: &AmlName) -> String { - to_symbol(&aml_name.as_string()) - } -} diff --git a/recipes/core/base/drivers/audio/ac97d/Cargo.toml b/recipes/core/base/drivers/audio/ac97d/Cargo.toml deleted file mode 100644 index 97b163dbe9..0000000000 --- a/recipes/core/base/drivers/audio/ac97d/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "ac97d" -description = "AC'97 driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -common = { path = "../../common" } -libredox.workspace = true -log.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true -spin.workspace = true - -daemon = { path = "../../../daemon" } -pcid = { path = "../../pcid" } -redox-scheme.workspace = true -scheme-utils = { path = "../../../scheme-utils" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/audio/ac97d/config.toml b/recipes/core/base/drivers/audio/ac97d/config.toml deleted file mode 100644 index 106ce703a3..0000000000 --- a/recipes/core/base/drivers/audio/ac97d/config.toml +++ /dev/null @@ -1,5 +0,0 @@ -[[drivers]] -name = "AC97 Audio" -class = 0x04 -subclass = 0x01 -command = ["ac97d"] diff --git a/recipes/core/base/drivers/audio/ac97d/src/device.rs b/recipes/core/base/drivers/audio/ac97d/src/device.rs deleted file mode 100644 index a9217dbab6..0000000000 --- a/recipes/core/base/drivers/audio/ac97d/src/device.rs +++ /dev/null @@ -1,333 +0,0 @@ -use common::io::Pio; -use redox_scheme::scheme::SchemeSync; -use redox_scheme::CallerCtx; -use redox_scheme::OpenResult; -use scheme_utils::{FpathWriter, HandleMap}; -use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, ENOENT}; -use syscall::schemev2::NewFdFlags; -use syscall::EWOULDBLOCK; - -use common::{ - dma::Dma, - io::{Io, Mmio}, -}; -use spin::Mutex; - -const NUM_SUB_BUFFS: usize = 32; -const SUB_BUFF_SIZE: usize = 2048; - -enum Handle { - Todo, - SchemeRoot, -} - -#[allow(dead_code)] -struct MixerRegs { - /* 0x00 */ reset: Pio, - /* 0x02 */ master_volume: Pio, - /* 0x04 */ aux_out_volume: Pio, - /* 0x06 */ mono_volume: Pio, - /* 0x08 */ master_tone: Pio, - /* 0x0A */ pc_beep_volume: Pio, - /* 0x0C */ phone_volume: Pio, - /* 0x0E */ mic_volume: Pio, - /* 0x10 */ line_in_volume: Pio, - /* 0x12 */ cd_volume: Pio, - /* 0x14 */ video_volume: Pio, - /* 0x16 */ aux_in_volume: Pio, - /* 0x18 */ pcm_out_volume: Pio, - /* 0x1A */ record_select: Pio, - /* 0x1C */ record_gain: Pio, - /* 0x1E */ record_gain_mic: Pio, - /* 0x20 */ general_purpose: Pio, - /* 0x22 */ control_3d: Pio, - /* 0x24 */ audio_int_paging: Pio, - /* 0x26 */ powerdown: Pio, - /* 0x28 */ extended_id: Pio, - /* 0x2A */ extended_ctrl: Pio, - /* 0x2C */ vra_pcm_front: Pio, -} - -impl MixerRegs { - fn new(bar0: u16) -> Self { - Self { - reset: Pio::new(bar0 + 0x00), - master_volume: Pio::new(bar0 + 0x02), - aux_out_volume: Pio::new(bar0 + 0x04), - mono_volume: Pio::new(bar0 + 0x06), - master_tone: Pio::new(bar0 + 0x08), - pc_beep_volume: Pio::new(bar0 + 0x0A), - phone_volume: Pio::new(bar0 + 0x0C), - mic_volume: Pio::new(bar0 + 0x0E), - line_in_volume: Pio::new(bar0 + 0x10), - cd_volume: Pio::new(bar0 + 0x12), - video_volume: Pio::new(bar0 + 0x14), - aux_in_volume: Pio::new(bar0 + 0x16), - pcm_out_volume: Pio::new(bar0 + 0x18), - record_select: Pio::new(bar0 + 0x1A), - record_gain: Pio::new(bar0 + 0x1C), - record_gain_mic: Pio::new(bar0 + 0x1E), - general_purpose: Pio::new(bar0 + 0x20), - control_3d: Pio::new(bar0 + 0x22), - audio_int_paging: Pio::new(bar0 + 0x24), - powerdown: Pio::new(bar0 + 0x26), - extended_id: Pio::new(bar0 + 0x28), - extended_ctrl: Pio::new(bar0 + 0x2A), - vra_pcm_front: Pio::new(bar0 + 0x2C), - } - } -} - -#[allow(dead_code)] -struct BusBoxRegs { - /// Buffer descriptor list base address - /* 0x00 */ - bdbar: Pio, - /// Current index value - /* 0x04 */ - civ: Pio, - /// Last valid index - /* 0x05 */ - lvi: Pio, - /// Status - /* 0x06 */ - sr: Pio, - /// Position in current buffer - /* 0x08 */ - picb: Pio, - /// Prefetched index value - /* 0x0A */ - piv: Pio, - /// Control - /* 0x0B */ - cr: Pio, -} - -impl BusBoxRegs { - fn new(base: u16) -> Self { - Self { - bdbar: Pio::new(base + 0x00), - civ: Pio::new(base + 0x04), - lvi: Pio::new(base + 0x05), - sr: Pio::new(base + 0x06), - picb: Pio::new(base + 0x08), - piv: Pio::new(base + 0x0A), - cr: Pio::new(base + 0x0B), - } - } -} - -#[allow(dead_code)] -struct BusRegs { - /// PCM in register box - /* 0x00 */ - pi: BusBoxRegs, - /// PCM out register box - /* 0x10 */ - po: BusBoxRegs, - /// Microphone register box - /* 0x20 */ - mc: BusBoxRegs, -} - -impl BusRegs { - fn new(bar1: u16) -> Self { - Self { - pi: BusBoxRegs::new(bar1 + 0x00), - po: BusBoxRegs::new(bar1 + 0x10), - mc: BusBoxRegs::new(bar1 + 0x20), - } - } -} - -#[repr(C, packed)] -pub struct BufferDescriptor { - /* 0x00 */ addr: Mmio, - /* 0x04 */ samples: Mmio, - /* 0x06 */ flags: Mmio, -} - -pub struct Ac97 { - mixer: MixerRegs, - bus: BusRegs, - bdl: Dma<[BufferDescriptor; NUM_SUB_BUFFS]>, - buf: Dma<[u8; NUM_SUB_BUFFS * SUB_BUFF_SIZE]>, - handles: Mutex>, -} - -impl Ac97 { - pub unsafe fn new(bar0: u16, bar1: u16) -> Result { - let mut module = Ac97 { - mixer: MixerRegs::new(bar0), - bus: BusRegs::new(bar1), - bdl: Dma::zeroed( - //TODO: PhysBox::new_in_32bit_space(bdl_size)? - )? - .assume_init(), - buf: Dma::zeroed( - //TODO: PhysBox::new_in_32bit_space(buf_size)? - )? - .assume_init(), - handles: Mutex::new(HandleMap::new()), - }; - - module.init()?; - - Ok(module) - } - - fn init(&mut self) -> Result<()> { - //TODO: support other sample rates, or just the default of 48000 Hz - { - // Check if VRA is supported - if !self.mixer.extended_id.readf(1 << 0) { - println!("ac97d: VRA not supported and is currently required"); - return Err(Error::new(ENOENT)); - } - - // Enable VRA - self.mixer.extended_ctrl.writef(1 << 0, true); - - // Attempt to set sample rate for PCM front to 44100 Hz - let desired_sample_rate = 44100; - self.mixer.vra_pcm_front.write(desired_sample_rate); - - // Read back real sample rate - let real_sample_rate = self.mixer.vra_pcm_front.read(); - println!("ac97d: set sample rate to {}", real_sample_rate); - - // Error if we cannot set the sample rate as desired - if real_sample_rate != desired_sample_rate { - println!( - "ac97d: sample rate is {} but only {} is supported", - real_sample_rate, desired_sample_rate - ); - return Err(Error::new(ENOENT)); - } - } - - // Ensure PCM out is stopped - self.bus.po.cr.writef(1, false); - - // Reset PCM out - self.bus.po.cr.writef(1 << 1, true); - while self.bus.po.cr.readf(1 << 1) { - // Spinning on resetting PCM out - //TODO: relax - } - - // Initialize BDL for PCM out - for i in 0..NUM_SUB_BUFFS { - self.bdl[i] - .addr - .write((self.buf.physical() + i * SUB_BUFF_SIZE) as u32); - self.bdl[i] - .samples - .write((SUB_BUFF_SIZE / 2/* Each sample is i16 or 2 bytes */) as u16); - self.bdl[i] - .flags - .write(1 << 15 /* Interrupt on completion */); - } - self.bus.po.bdbar.write(self.bdl.physical() as u32); - - // Enable interrupt on completion - self.bus.po.cr.writef(1 << 4, true); - - // Start bus master - self.bus.po.cr.writef(1 << 0, true); - - // Set master volume to 0 db (loudest output, DANGER!) - self.mixer.master_volume.write(0); - - // Set PCM output volume to 0 db (medium) - self.mixer.pcm_out_volume.write(0x808); - - Ok(()) - } - - pub fn irq(&mut self) -> bool { - let ints = self.bus.po.sr.read() & 0b11100; - if ints != 0 { - self.bus.po.sr.write(ints); - true - } else { - false - } - } -} - -impl SchemeSync for Ac97 { - fn scheme_root(&mut self) -> Result { - Ok(self.handles.lock().insert(Handle::SchemeRoot)) - } - fn openat( - &mut self, - dirfd: usize, - _path: &str, - _flags: usize, - _fcntl_flags: u32, - ctx: &CallerCtx, - ) -> Result { - { - let handles = self.handles.lock(); - let handle = handles.get(dirfd)?; - if !matches!(handle, Handle::SchemeRoot) { - return Err(Error::new(EACCES)); - } - } - if ctx.uid == 0 { - let id = self.handles.lock().insert(Handle::Todo); - Ok(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::empty(), - }) - } else { - Err(Error::new(EACCES)) - } - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - _offset: u64, - _flags: u32, - _ctx: &CallerCtx, - ) -> Result { - { - let mut handles = self.handles.lock(); - let handle = handles.get_mut(id)?; - if !matches!(handle, Handle::Todo) { - return Err(Error::new(EBADF)); - } - } - - if buf.len() != SUB_BUFF_SIZE { - return Err(Error::new(EINVAL)); - } - - let civ = self.bus.po.civ.read() as usize; - let mut lvi = self.bus.po.lvi.read() as usize; - if lvi == (civ + 3) % NUM_SUB_BUFFS { - // Block if we already are 3 buffers ahead - Err(Error::new(EWOULDBLOCK)) - } else { - // Fill next buffer - lvi = (lvi + 1) % NUM_SUB_BUFFS; - for i in 0..SUB_BUFF_SIZE { - self.buf[lvi * SUB_BUFF_SIZE + i] = buf[i]; - } - self.bus.po.lvi.write(lvi as u8); - - Ok(SUB_BUFF_SIZE) - } - } - - fn fpath(&mut self, _id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with(buf, "audiohw", |_| Ok(())) - } - - fn on_close(&mut self, id: usize) { - self.handles.lock().remove(id); - } -} diff --git a/recipes/core/base/drivers/audio/ac97d/src/main.rs b/recipes/core/base/drivers/audio/ac97d/src/main.rs deleted file mode 100644 index ffa8a94b7a..0000000000 --- a/recipes/core/base/drivers/audio/ac97d/src/main.rs +++ /dev/null @@ -1,134 +0,0 @@ -use std::io::{Read, Write}; -use std::os::unix::io::AsRawFd; -use std::usize; - -use event::{user_data, EventQueue}; -use pcid_interface::PciFunctionHandle; -use redox_scheme::scheme::register_sync_scheme; -use redox_scheme::Socket; -use scheme_utils::ReadinessBased; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub mod device; - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! { - let pci_config = pcid_handle.config(); - - let mut name = pci_config.func.name(); - name.push_str("_ac97"); - - let bar0 = pci_config.func.bars[0].expect_port(); - let bar1 = pci_config.func.bars[1].expect_port(); - - let irq = pci_config - .func - .legacy_interrupt_line - .expect("ac97d: no legacy interrupts supported"); - - println!(" + ac97 {}", pci_config.func.display()); - - common::setup_logging( - "audio", - "pci", - &name, - common::output_level(), - common::file_level(), - ); - - common::acquire_port_io_rights().expect("ac97d: failed to set I/O privilege level to Ring 3"); - - let mut irq_file = irq.irq_handle("ac97d"); - - let socket = Socket::nonblock().expect("ac97d: failed to create socket"); - let mut device = - unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") }; - let mut readiness_based = ReadinessBased::new(&socket, 16); - - user_data! { - enum Source { - Irq, - Scheme, - } - } - - let event_queue = EventQueue::::new().expect("ac97d: Could not create event queue."); - event_queue - .subscribe( - irq_file.as_raw_fd() as usize, - Source::Irq, - event::EventFlags::READ, - ) - .unwrap(); - event_queue - .subscribe( - socket.inner().raw(), - Source::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - - register_sync_scheme(&socket, "audiohw", &mut device) - .expect("ac97d: failed to register audiohw scheme to namespace"); - daemon.ready(); - - libredox::call::setrens(0, 0).expect("ac97d: failed to enter null namespace"); - - let all = [Source::Irq, Source::Scheme]; - for event in all - .into_iter() - .chain(event_queue.map(|e| e.expect("ac97d: failed to get next event").user_data)) - { - match event { - Source::Irq => { - let mut irq = [0; 8]; - irq_file.read(&mut irq).unwrap(); - - if !device.irq() { - continue; - } - irq_file.write(&mut irq).unwrap(); - - readiness_based - .poll_all_requests(&mut device) - .expect("ac97d: failed to poll requests"); - readiness_based - .write_responses() - .expect("ac97d: failed to write to socket"); - - /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - } - Source::Scheme => { - readiness_based - .read_and_process_requests(&mut device) - .expect("ac97d: failed to read from socket"); - readiness_based - .write_responses() - .expect("ac97d: failed to write to socket"); - - /* - let next_read = device.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - } - } - } - - std::process::exit(0); -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! { - unimplemented!() -} diff --git a/recipes/core/base/drivers/audio/ihdad/Cargo.toml b/recipes/core/base/drivers/audio/ihdad/Cargo.toml deleted file mode 100644 index 49f8171525..0000000000 --- a/recipes/core/base/drivers/audio/ihdad/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "ihdad" -description = "Intel HD Audio chipset driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -bitflags.workspace = true -libredox.workspace = true -log.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true -spin.workspace = true - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -pcid = { path = "../../pcid" } -redox-scheme.workspace = true -scheme-utils = { path = "../../../scheme-utils" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/audio/ihdad/config.toml b/recipes/core/base/drivers/audio/ihdad/config.toml deleted file mode 100644 index 8be0418577..0000000000 --- a/recipes/core/base/drivers/audio/ihdad/config.toml +++ /dev/null @@ -1,5 +0,0 @@ -[[drivers]] -name = "Intel HD Audio" -class = 0x04 -subclass = 0x03 -command = ["ihdad"] diff --git a/recipes/core/base/drivers/audio/ihdad/src/hda/cmdbuff.rs b/recipes/core/base/drivers/audio/ihdad/src/hda/cmdbuff.rs deleted file mode 100644 index f968f0dcce..0000000000 --- a/recipes/core/base/drivers/audio/ihdad/src/hda/cmdbuff.rs +++ /dev/null @@ -1,501 +0,0 @@ -use common::dma::Dma; -use common::io::{Io, Mmio}; -use common::timeout::Timeout; -use syscall::error::{Error, Result, EIO}; - -use super::common::*; - -// CORBCTL -const CMEIE: u8 = 1 << 0; // 1 bit -const CORBRUN: u8 = 1 << 1; // 1 bit - -// CORBSIZE -const CORBSZCAP: (u8, u8) = (4, 4); -const CORBSIZE: (u8, u8) = (0, 2); - -// CORBRP -const CORBRPRST: u16 = 1 << 15; - -// RIRBWP -const RIRBWPRST: u16 = 1 << 15; - -// RIRBCTL -const RINTCTL: u8 = 1 << 0; // 1 bit -const RIRBDMAEN: u8 = 1 << 1; // 1 bit - -const CORB_OFFSET: usize = 0x00; -const RIRB_OFFSET: usize = 0x10; -const ICMD_OFFSET: usize = 0x20; - -// ICS -const ICB: u16 = 1 << 0; -const IRV: u16 = 1 << 1; - -// CORB and RIRB offset - -const COMMAND_BUFFER_OFFSET: usize = 0x40; -const CORB_BUFF_MAX_SIZE: usize = 1024; - -struct CommandBufferRegs { - corblbase: Mmio, - corbubase: Mmio, - corbwp: Mmio, - corbrp: Mmio, - corbctl: Mmio, - corbsts: Mmio, - corbsize: Mmio, - rsvd5: Mmio, - - rirblbase: Mmio, - rirbubase: Mmio, - rirbwp: Mmio, - rintcnt: Mmio, - rirbctl: Mmio, - rirbsts: Mmio, - rirbsize: Mmio, - rsvd6: Mmio, -} - -struct CorbRegs { - corblbase: Mmio, - corbubase: Mmio, - corbwp: Mmio, - corbrp: Mmio, - corbctl: Mmio, - corbsts: Mmio, - corbsize: Mmio, - rsvd5: Mmio, -} - -struct Corb { - regs: &'static mut CorbRegs, - corb_base: *mut u32, - corb_base_phys: usize, - corb_count: usize, -} - -impl Corb { - pub fn new(regs_addr: usize, corb_buff_phys: usize, corb_buff_virt: *mut u32) -> Corb { - unsafe { - Corb { - regs: &mut *(regs_addr as *mut CorbRegs), - corb_base: corb_buff_virt, - corb_base_phys: corb_buff_phys, - corb_count: 0, - } - } - } - - //Intel 4.4.1.3 - pub fn init(&mut self) -> Result<()> { - self.stop()?; - //Determine CORB and RIRB size and allocate buffer - - //3.3.24 - let corbsize_reg = self.regs.corbsize.read(); - let corbszcap = (corbsize_reg >> 4) & 0xF; - - let mut corbsize_bytes: usize = 0; - let mut corbsize: u8 = 0; - - if (corbszcap & 4) == 4 { - corbsize = 2; - corbsize_bytes = 1024; - - self.corb_count = 256; - } else if (corbszcap & 2) == 2 { - corbsize = 1; - corbsize_bytes = 64; - - self.corb_count = 16; - } else if (corbszcap & 1) == 1 { - corbsize = 0; - corbsize_bytes = 8; - - self.corb_count = 2; - } - - assert!(self.corb_count != 0); - let addr = self.corb_base_phys; - self.set_address(addr); - self.regs.corbsize.write((corbsize_reg & 0xFC) | corbsize); - - self.reset_read_pointer()?; - let old_wp = self.regs.corbwp.read(); - self.regs.corbwp.write(old_wp & 0xFF00); - - Ok(()) - } - - pub fn start(&mut self) { - self.regs.corbctl.writef(CORBRUN, true); - } - - #[inline(never)] - pub fn stop(&mut self) -> Result<()> { - let timeout = Timeout::from_secs(1); - while self.regs.corbctl.readf(CORBRUN) { - self.regs.corbctl.writef(CORBRUN, false); - timeout.run().map_err(|()| { - log::error!("timeout on clearing CORBRUN"); - Error::new(EIO) - })?; - } - Ok(()) - } - - pub fn set_address(&mut self, addr: usize) { - self.regs.corblbase.write((addr & 0xFFFFFFFF) as u32); - self.regs.corbubase.write(((addr as u64) >> 32) as u32); - } - - pub fn reset_read_pointer(&mut self) -> Result<()> { - // 3.3.21 - - self.stop()?; - - // Set CORBRPRST to 1 - log::trace!("CORBRP {:X}", self.regs.corbrp.read()); - self.regs.corbrp.writef(CORBRPRST, true); - log::trace!("CORBRP {:X}", self.regs.corbrp.read()); - - { - // Wait for it to become 1 - let timeout = Timeout::from_secs(1); - while !self.regs.corbrp.readf(CORBRPRST) { - self.regs.corbrp.writef(CORBRPRST, true); - timeout.run().map_err(|()| { - log::error!("timeout on setting CORBRPRST"); - Error::new(EIO) - })?; - } - } - - // Clear the bit again - self.regs.corbrp.writef(CORBRPRST, false); - - { - // Read back the bit until zero to verify that it is cleared. - let timeout = Timeout::from_secs(1); - loop { - if !self.regs.corbrp.readf(CORBRPRST) { - break; - } - self.regs.corbrp.writef(CORBRPRST, false); - timeout.run().map_err(|()| { - log::error!("timeout on clearing CORBRPRST"); - Error::new(EIO) - })?; - } - } - - Ok(()) - } - - fn send_command(&mut self, cmd: u32) -> Result<()> { - { - // wait for the commands to finish - let timeout = Timeout::from_secs(1); - while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) { - timeout.run().map_err(|()| { - log::error!("timeout on CORB command"); - Error::new(EIO) - })?; - } - } - let write_pos: usize = ((self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count; - unsafe { - *self.corb_base.offset(write_pos as isize) = cmd; - } - - self.regs.corbwp.write(write_pos as u16); - - log::trace!("Corb: {:08X}", cmd); - Ok(()) - } -} - -struct RirbRegs { - rirblbase: Mmio, - rirbubase: Mmio, - rirbwp: Mmio, - rintcnt: Mmio, - rirbctl: Mmio, - rirbsts: Mmio, - rirbsize: Mmio, - rsvd6: Mmio, -} - -struct Rirb { - regs: &'static mut RirbRegs, - rirb_base: *mut u64, - rirb_base_phys: usize, - rirb_rp: u16, - rirb_count: usize, -} - -impl Rirb { - pub fn new(regs_addr: usize, rirb_buff_phys: usize, rirb_buff_virt: *mut u64) -> Rirb { - unsafe { - Rirb { - regs: &mut *(regs_addr as *mut RirbRegs), - rirb_base: rirb_buff_virt, - rirb_rp: 0, - rirb_base_phys: rirb_buff_phys, - rirb_count: 0, - } - } - } - //Intel 4.4.1.3 - pub fn init(&mut self) -> Result<()> { - self.stop()?; - - let rirbsize_reg = self.regs.rirbsize.read(); - let rirbszcap = (rirbsize_reg >> 4) & 0xF; - - let mut rirbsize_bytes: usize = 0; - let mut rirbsize: u8 = 0; - - if (rirbszcap & 4) == 4 { - rirbsize = 2; - rirbsize_bytes = 2048; - - self.rirb_count = 256; - } else if (rirbszcap & 2) == 2 { - rirbsize = 1; - rirbsize_bytes = 128; - - self.rirb_count = 8; - } else if (rirbszcap & 1) == 1 { - rirbsize = 0; - rirbsize_bytes = 16; - - self.rirb_count = 2; - } - - assert!(self.rirb_count != 0); - - let addr = self.rirb_base_phys; - self.set_address(addr); - - self.reset_write_pointer(); - self.rirb_rp = 0; - - self.regs.rintcnt.write(1); - - Ok(()) - } - - pub fn start(&mut self) { - self.regs.rirbctl.writef(RIRBDMAEN | RINTCTL, true); - } - - pub fn stop(&mut self) -> Result<()> { - let timeout = Timeout::from_secs(1); - while self.regs.rirbctl.readf(RIRBDMAEN) { - self.regs.rirbctl.writef(RIRBDMAEN, false); - timeout.run().map_err(|()| { - log::error!("timeout on clearing RIRBDMAEN"); - Error::new(EIO) - })?; - } - Ok(()) - } - - pub fn set_address(&mut self, addr: usize) { - self.regs.rirblbase.write((addr & 0xFFFFFFFF) as u32); - self.regs.rirbubase.write(((addr as u64) >> 32) as u32); - } - - pub fn reset_write_pointer(&mut self) { - self.regs.rirbwp.writef(RIRBWPRST, true); - } - - fn read_response(&mut self) -> Result { - { - // wait for response - let timeout = Timeout::from_secs(1); - while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) { - timeout.run().map_err(|()| { - log::error!("timeout on RIRB response"); - Error::new(EIO) - })?; - } - } - let read_pos: u16 = (self.rirb_rp + 1) % self.rirb_count as u16; - - let res: u64; - unsafe { - res = *self.rirb_base.offset(read_pos as isize); - } - self.rirb_rp = read_pos; - log::trace!("Rirb: {:08X}", res); - Ok(res) - } -} - -struct ImmediateCommandRegs { - icoi: Mmio, - irii: Mmio, - ics: Mmio, - rsvd7: [Mmio; 6], -} - -pub struct ImmediateCommand { - regs: &'static mut ImmediateCommandRegs, -} - -impl ImmediateCommand { - pub fn new(regs_addr: usize) -> ImmediateCommand { - unsafe { - ImmediateCommand { - regs: &mut *(regs_addr as *mut ImmediateCommandRegs), - } - } - } - - pub fn cmd(&mut self, cmd: u32) -> Result { - { - // wait for ready - let timeout = Timeout::from_secs(1); - while self.regs.ics.readf(ICB) { - timeout.run().map_err(|()| { - log::error!("timeout on immediate command"); - Error::new(EIO) - })?; - } - } - - // write command - self.regs.icoi.write(cmd); - - // set ICB bit to send command - self.regs.ics.writef(ICB, true); - - { - // wait for IRV bit to be set to indicate a response is latched - let timeout = Timeout::from_secs(1); - while !self.regs.ics.readf(IRV) { - timeout.run().map_err(|()| { - log::error!("timeout on immediate response"); - Error::new(EIO) - })?; - } - } - - // read the result register twice, total of 8 bytes - // highest 4 will most likely be zeros (so I've heard) - let mut res: u64 = self.regs.irii.read() as u64; - res |= (self.regs.irii.read() as u64) << 32; - - // clear the bit so we know when the next response comes - self.regs.ics.writef(IRV, false); - - Ok(res) - } -} - -pub struct CommandBuffer { - // regs: &'static mut CommandBufferRegs, - corb: Corb, - rirb: Rirb, - icmd: ImmediateCommand, - - use_immediate_cmd: bool, - mem: Dma<[u8; 0x1000]>, -} - -impl CommandBuffer { - pub fn new(regs_addr: usize, mut cmd_buff: Dma<[u8; 0x1000]>) -> CommandBuffer { - let corb = Corb::new( - regs_addr + CORB_OFFSET, - cmd_buff.physical(), - cmd_buff.as_mut_ptr().cast(), - ); - let rirb = Rirb::new( - regs_addr + RIRB_OFFSET, - cmd_buff.physical() + CORB_BUFF_MAX_SIZE, - cmd_buff - .as_mut_ptr() - .cast::() - .wrapping_add(CORB_BUFF_MAX_SIZE) - .cast(), - ); - - let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET); - - let cmdbuff = CommandBuffer { - corb, - rirb, - icmd, - - use_immediate_cmd: false, - - mem: cmd_buff, - }; - - cmdbuff - } - - pub fn init(&mut self, use_imm_cmds: bool) -> Result<()> { - self.corb.init()?; - self.rirb.init()?; - self.set_use_imm_cmds(use_imm_cmds)?; - Ok(()) - } - - pub fn stop(&mut self) -> Result<()> { - self.corb.stop()?; - self.rirb.stop()?; - Ok(()) - } - - pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> Result { - let mut ncmd: u32 = 0; - - ncmd |= (addr.0 as u32 & 0x00F) << 28; - ncmd |= (addr.1 as u32 & 0x0FF) << 20; - ncmd |= (command & 0xFFF) << 8; - ncmd |= (data as u32 & 0x0FF) << 0; - self.cmd(ncmd) - } - pub fn cmd4(&mut self, addr: WidgetAddr, command: u32, data: u16) -> Result { - let mut ncmd: u32 = 0; - - ncmd |= (addr.0 as u32 & 0x000F) << 28; - ncmd |= (addr.1 as u32 & 0x00FF) << 20; - ncmd |= (command & 0x000F) << 16; - ncmd |= (data as u32 & 0xFFFF) << 0; - self.cmd(ncmd) - } - - pub fn cmd(&mut self, cmd: u32) -> Result { - if self.use_immediate_cmd { - self.cmd_imm(cmd) - } else { - self.cmd_buff(cmd) - } - } - - pub fn cmd_imm(&mut self, cmd: u32) -> Result { - self.icmd.cmd(cmd) - } - - pub fn cmd_buff(&mut self, cmd: u32) -> Result { - self.corb.send_command(cmd)?; - self.rirb.read_response() - } - - pub fn set_use_imm_cmds(&mut self, use_imm: bool) -> Result<()> { - self.use_immediate_cmd = use_imm; - - if self.use_immediate_cmd { - self.corb.stop()?; - self.rirb.stop()?; - } else { - self.corb.start(); - self.rirb.start(); - } - Ok(()) - } -} diff --git a/recipes/core/base/drivers/audio/ihdad/src/hda/common.rs b/recipes/core/base/drivers/audio/ihdad/src/hda/common.rs deleted file mode 100644 index c2d5215e94..0000000000 --- a/recipes/core/base/drivers/audio/ihdad/src/hda/common.rs +++ /dev/null @@ -1,195 +0,0 @@ -use std::fmt; -use std::mem::transmute; - -pub type HDANodeAddr = u16; -pub type HDACodecAddr = u8; - -pub type NodeAddr = u16; -pub type CodecAddr = u8; - -pub type WidgetAddr = (CodecAddr, NodeAddr); -/* -impl fmt::Display for WidgetAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:01X}:{:02X}\n", self.0, self.1) - } -}*/ - -#[derive(Debug, PartialEq)] -#[repr(u8)] -pub enum HDAWidgetType { - AudioOutput = 0x0, - AudioInput = 0x1, - AudioMixer = 0x2, - AudioSelector = 0x3, - PinComplex = 0x4, - Power = 0x5, - VolumeKnob = 0x6, - BeepGenerator = 0x7, - - VendorDefined = 0xf, -} - -impl fmt::Display for HDAWidgetType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -#[derive(Debug, PartialEq)] -#[repr(u8)] -pub enum DefaultDevice { - LineOut = 0x0, - Speaker = 0x1, - HPOut = 0x2, - CD = 0x3, - SPDIF = 0x4, - DigitalOtherOut = 0x5, - ModemLineSide = 0x6, - ModemHandsetSide = 0x7, - LineIn = 0x8, - AUX = 0x9, - MicIn = 0xA, - Telephony = 0xB, - SPDIFIn = 0xC, - DigitalOtherIn = 0xD, - Reserved = 0xE, - Other = 0xF, -} - -#[derive(Debug)] -#[repr(u8)] -pub enum PortConnectivity { - ConnectedToJack = 0x0, - NoPhysicalConnection = 0x1, - FixedFunction = 0x2, - JackAndInternal = 0x3, -} - -#[derive(Debug)] -#[repr(u8)] -pub enum GrossLocation { - ExternalOnPrimary = 0x0, - Internal = 0x1, - SeperateChasis = 0x2, - Other = 0x3, -} - -#[derive(Debug)] -#[repr(u8)] -pub enum GeometricLocation { - NA = 0x0, - Rear = 0x1, - Front = 0x2, - Left = 0x3, - Right = 0x4, - Top = 0x5, - Bottom = 0x6, - Special1 = 0x7, - Special2 = 0x8, - Special3 = 0x9, - Resvd1 = 0xA, - Resvd2 = 0xB, - Resvd3 = 0xC, - Resvd4 = 0xD, - Resvd5 = 0xE, - Resvd6 = 0xF, -} - -#[derive(Debug)] -#[repr(u8)] -pub enum Color { - Unknown = 0x0, - Black = 0x1, - Grey = 0x2, - Blue = 0x3, - Green = 0x4, - Red = 0x5, - Orange = 0x6, - Yellow = 0x7, - Purple = 0x8, - Pink = 0x9, - Resvd1 = 0xA, - Resvd2 = 0xB, - Resvd3 = 0xC, - Resvd4 = 0xD, - White = 0xE, - Other = 0xF, -} - -pub struct ConfigurationDefault { - value: u32, -} - -impl ConfigurationDefault { - pub fn from_u32(value: u32) -> ConfigurationDefault { - ConfigurationDefault { value: value } - } - - pub fn color(&self) -> Color { - unsafe { transmute(((self.value >> 12) & 0xF) as u8) } - } - - pub fn default_device(&self) -> DefaultDevice { - unsafe { transmute(((self.value >> 20) & 0xF) as u8) } - } - - pub fn port_connectivity(&self) -> PortConnectivity { - unsafe { transmute(((self.value >> 30) & 0x3) as u8) } - } - - pub fn gross_location(&self) -> GrossLocation { - unsafe { transmute(((self.value >> 28) & 0x3) as u8) } - } - - pub fn geometric_location(&self) -> GeometricLocation { - unsafe { transmute(((self.value >> 24) & 0x7) as u8) } - } - - pub fn is_output(&self) -> bool { - match self.default_device() { - DefaultDevice::LineOut - | DefaultDevice::Speaker - | DefaultDevice::HPOut - | DefaultDevice::CD - | DefaultDevice::SPDIF - | DefaultDevice::DigitalOtherOut - | DefaultDevice::ModemLineSide => true, - _ => false, - } - } - - pub fn is_input(&self) -> bool { - match self.default_device() { - DefaultDevice::ModemHandsetSide - | DefaultDevice::LineIn - | DefaultDevice::AUX - | DefaultDevice::MicIn - | DefaultDevice::Telephony - | DefaultDevice::SPDIFIn - | DefaultDevice::DigitalOtherIn => true, - _ => false, - } - } - - pub fn sequence(&self) -> u8 { - (self.value & 0xF) as u8 - } - - pub fn default_association(&self) -> u8 { - ((self.value >> 4) & 0xF) as u8 - } -} - -impl fmt::Display for ConfigurationDefault { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "{:?} {:?} {:?} {:?}", - self.default_device(), - self.color(), - self.gross_location(), - self.geometric_location() - ) - } -} diff --git a/recipes/core/base/drivers/audio/ihdad/src/hda/device.rs b/recipes/core/base/drivers/audio/ihdad/src/hda/device.rs deleted file mode 100755 index 78e8f0a281..0000000000 --- a/recipes/core/base/drivers/audio/ihdad/src/hda/device.rs +++ /dev/null @@ -1,1086 +0,0 @@ -#![allow(dead_code)] - -use std::collections::HashMap; -use std::fmt::Write; -use std::str; -use std::task::Poll; -use std::thread; -use std::time::Duration; - -use common::dma::Dma; -use common::io::{Io, Mmio}; -use common::timeout::Timeout; -use redox_scheme::scheme::SchemeSync; -use redox_scheme::CallerCtx; -use redox_scheme::OpenResult; -use scheme_utils::{FpathWriter, HandleMap}; -use syscall::error::{Error, Result, EACCES, EBADF, EIO, ENODEV, EWOULDBLOCK}; - -use spin::Mutex; -use syscall::schemev2::NewFdFlags; - -use super::common::*; -use super::BitsPerSample; -use super::BufferDescriptorListEntry; -use super::CommandBuffer; -use super::HDANode; -use super::OutputStream; -use super::StreamBuffer; -use super::StreamDescriptorRegs; - -// GCTL - Global Control -const CRST: u32 = 1 << 0; // 1 bit -const FNCTRL: u32 = 1 << 1; // 1 bit -const UNSOL: u32 = 1 << 8; // 1 bit - -// CORBCTL -const CMEIE: u8 = 1 << 0; // 1 bit -const CORBRUN: u8 = 1 << 1; // 1 bit - -// CORBSIZE -const CORBSZCAP: (u8, u8) = (4, 4); -const CORBSIZE: (u8, u8) = (0, 2); - -// CORBRP -const CORBRPRST: u16 = 1 << 15; - -// RIRBWP -const RIRBWPRST: u16 = 1 << 15; - -// RIRBCTL -const RINTCTL: u8 = 1 << 0; // 1 bit -const RIRBDMAEN: u8 = 1 << 1; // 1 bit - -// ICS -const ICB: u16 = 1 << 0; -const IRV: u16 = 1 << 1; - -// CORB and RIRB offset - -const COMMAND_BUFFER_OFFSET: usize = 0x40; - -const NUM_SUB_BUFFS: usize = 32; -const SUB_BUFF_SIZE: usize = 2048; - -enum Handle { - Todo, - Pcmout(usize, usize, usize), // Card, index, block_ptr - Pcmin(usize, usize, usize), // Card, index, block_ptr - StrBuf(Vec), - SchemeRoot, -} - -#[repr(C, packed)] -#[allow(dead_code)] -struct Regs { - gcap: Mmio, - vmin: Mmio, - vmaj: Mmio, - outpay: Mmio, - inpay: Mmio, - gctl: Mmio, - wakeen: Mmio, - statests: Mmio, - gsts: Mmio, - rsvd0: [Mmio; 6], - outstrmpay: Mmio, - instrmpay: Mmio, - rsvd1: [Mmio; 4], - intctl: Mmio, - intsts: Mmio, - rsvd2: [Mmio; 8], - walclk: Mmio, - rsvd3: Mmio, - ssync: Mmio, - rsvd4: Mmio, - - corblbase: Mmio, - corbubase: Mmio, - corbwp: Mmio, - corbrp: Mmio, - corbctl: Mmio, - corbsts: Mmio, - corbsize: Mmio, - rsvd5: Mmio, - - rirblbase: Mmio, - rirbubase: Mmio, - rirbwp: Mmio, - rintcnt: Mmio, - rirbctl: Mmio, - rirbsts: Mmio, - rirbsize: Mmio, - rsvd6: Mmio, - - icoi: Mmio, - irii: Mmio, - ics: Mmio, - rsvd7: [Mmio; 6], - - dplbase: Mmio, // 0x70 - dpubase: Mmio, // 0x74 -} - -pub struct IntelHDA { - vend_prod: u32, - - base: usize, - regs: &'static mut Regs, - - //corb_rirb_base_phys: usize, - cmd: CommandBuffer, - - codecs: Vec, - - outputs: Vec, - inputs: Vec, - - widget_map: HashMap, - - output_pins: Vec, - input_pins: Vec, - - beep_addr: WidgetAddr, - - buff_desc: Dma<[BufferDescriptorListEntry; 256]>, - - output_streams: Vec, - - buffs: Vec>, - - int_counter: usize, - handles: Mutex>, -} - -impl IntelHDA { - pub unsafe fn new(base: usize, vend_prod: u32) -> Result { - let regs = &mut *(base as *mut Regs); - - let buff_desc = Dma::<[BufferDescriptorListEntry; 256]>::zeroed() - .expect("Could not allocate physical memory for buffer descriptor list.") - .assume_init(); - - log::debug!( - "Virt: {:016X}, Phys: {:016X}", - buff_desc.as_ptr() as usize, - buff_desc.physical() - ); - - let cmd_buff = Dma::<[u8; 0x1000]>::zeroed() - .expect("Could not allocate physical memory for CORB and RIRB.") - .assume_init(); - - log::debug!( - "Virt: {:016X}, Phys: {:016X}", - cmd_buff.as_ptr() as usize, - cmd_buff.physical() - ); - let mut module = IntelHDA { - vend_prod, - base, - regs, - - cmd: CommandBuffer::new(base + COMMAND_BUFFER_OFFSET, cmd_buff), - - beep_addr: (0, 0), - - widget_map: HashMap::::new(), - - codecs: Vec::::new(), - - outputs: Vec::::new(), - inputs: Vec::::new(), - - output_pins: Vec::::new(), - input_pins: Vec::::new(), - - buff_desc, - - output_streams: Vec::::new(), - - buffs: Vec::>::new(), - - int_counter: 0, - handles: Mutex::new(HandleMap::new()), - }; - - module.init()?; - - module.info(); - module.enumerate()?; - - module.configure()?; - log::debug!("IHDA: Initialization finished."); - Ok(module) - } - - pub fn init(&mut self) -> Result<()> { - self.reset_controller()?; - - let use_immediate_command_interface = match self.vend_prod { - 0x8086_2668 => false, - _ => true, - }; - - self.cmd.init(use_immediate_command_interface)?; - self.init_interrupts(); - - Ok(()) - } - - pub fn init_interrupts(&mut self) { - // TODO: provide a function to enable certain interrupts - // This just enables the first output stream interupt and the global interrupt - - let iss = self.num_input_streams(); - self.regs - .intctl - .write((1 << 31) | /* (1 << 30) |*/ (1 << iss)); - } - - pub fn irq(&mut self) -> bool { - self.int_counter += 1; - - self.handle_interrupts() - } - - pub fn int_count(&self) -> usize { - self.int_counter - } - - pub fn read_node(&mut self, addr: WidgetAddr) -> Result { - let mut node = HDANode::new(); - let mut temp: u64; - - node.addr = addr; - - temp = self.cmd.cmd12(addr, 0xF00, 0x04)?; - - node.subnode_count = (temp & 0xff) as u16; - node.subnode_start = ((temp >> 16) & 0xff) as u16; - - if addr == (0, 0) { - return Ok(node); - } - temp = self.cmd.cmd12(addr, 0xF00, 0x04)?; - - node.function_group_type = (temp & 0xff) as u8; - - temp = self.cmd.cmd12(addr, 0xF00, 0x09)?; - node.capabilities = temp as u32; - - temp = self.cmd.cmd12(addr, 0xF00, 0x0E)?; - - node.conn_list_len = (temp & 0xFF) as u8; - - node.connections = self.node_get_connection_list(&node)?; - - node.connection_default = self.cmd.cmd12(addr, 0xF01, 0x00)? as u8; - - node.config_default = self.cmd.cmd12(addr, 0xF1C, 0x00)? as u32; - - Ok(node) - } - - pub fn node_get_connection_list(&mut self, node: &HDANode) -> Result> { - let len_field: u8 = (self.cmd.cmd12(node.addr, 0xF00, 0x0E)? & 0xFF) as u8; - - // Highest bit is if addresses are represented in longer notation - // lower 7 is actual count - - let count: u8 = len_field & 0x7F; - let use_long_addr: bool = (len_field >> 7) & 0x1 == 1; - - let mut current: u8 = 0; - - let mut list = Vec::::new(); - - while current < count { - let response: u32 = (self.cmd.cmd12(node.addr, 0xF02, current)? & 0xFFFFFFFF) as u32; - - if use_long_addr { - for i in 0..2 { - let addr_field = ((response >> (16 * i)) & 0xFFFF) as u16; - let addr = addr_field & 0x7FFF; - - if addr == 0 { - break; - } - - if (addr_field >> 15) & 0x1 == 0x1 { - for i in list.pop().unwrap().1..(addr + 1) { - list.push((node.addr.0, i)); - } - } else { - list.push((node.addr.0, addr)); - } - } - } else { - for i in 0..4 { - let addr_field = ((response >> (8 * i)) & 0xff) as u16; - let addr = addr_field & 0x7F; - - if addr == 0 { - break; - } - - if (addr_field >> 7) & 0x1 == 0x1 { - for i in list.pop().unwrap().1..(addr + 1) { - list.push((node.addr.0, i)); - } - } else { - list.push((node.addr.0, addr)); - } - } - } - - current = list.len() as u8; - } - - Ok(list) - } - - pub fn enumerate(&mut self) -> Result<()> { - self.output_pins.clear(); - self.input_pins.clear(); - - let codec: u8 = 0; - - let root = self.read_node((codec, 0))?; - - log::debug!("{}", root); - - let root_count = root.subnode_count; - let root_start = root.subnode_start; - - //FIXME: So basically the way this is set up is to only support one codec and hopes the first one is an audio - for i in 0..root_count { - let afg = self.read_node((codec, root_start + i))?; - log::debug!("{}", afg); - let afg_count = afg.subnode_count; - let afg_start = afg.subnode_start; - - for j in 0..afg_count { - let mut widget = self.read_node((codec, afg_start + j))?; - widget.is_widget = true; - match widget.widget_type() { - HDAWidgetType::AudioOutput => self.outputs.push(widget.addr), - HDAWidgetType::AudioInput => self.inputs.push(widget.addr), - HDAWidgetType::BeepGenerator => self.beep_addr = widget.addr, - HDAWidgetType::PinComplex => { - let config = widget.configuration_default(); - if config.is_output() { - self.output_pins.push(widget.addr); - } else if config.is_input() { - self.input_pins.push(widget.addr); - } - } - _ => {} - } - - log::debug!("{}", widget); - self.widget_map.insert(widget.addr(), widget); - } - } - - Ok(()) - } - - pub fn find_best_output_pin(&mut self) -> Result { - let outs = &self.output_pins; - if outs.len() == 1 { - return Ok(outs[0]); - } else if outs.len() > 1 { - //TODO: change output based on "unsolicited response" interrupts - // Check for devices in this order: Headphone, Speaker, Line Out - for supported_device in &[DefaultDevice::HPOut, DefaultDevice::Speaker] { - for &out in outs { - let widget = self.widget_map.get(&out).unwrap(); - let cd = widget.configuration_default(); - if cd.sequence() == 0 && &cd.default_device() == supported_device { - // Check for jack detect bit - let pin_caps = self.cmd.cmd12(widget.addr, 0xF00, 0x0C)?; - if pin_caps & (1 << 2) != 0 { - // Check for presence - let pin_sense = self.cmd.cmd12(widget.addr, 0xF09, 0)?; - if pin_sense & (1 << 31) == 0 { - // Skip if nothing is plugged in - continue; - } - } - return Ok(out); - } - } - } - } - Err(Error::new(ENODEV)) - } - - pub fn find_path_to_dac(&self, addr: WidgetAddr) -> Option> { - let widget = self.widget_map.get(&addr).unwrap(); - if widget.widget_type() == HDAWidgetType::AudioOutput { - Some(vec![addr]) - } else { - let connection = widget.connections.get(widget.connection_default as usize)?; - let mut path = self.find_path_to_dac(*connection)?; - path.insert(0, addr); - Some(path) - } - } - - /* - Here we update the buffers and split them into 128 byte sub chunks - because each BufferDescriptorList needs to be 128 byte aligned, - this makes it so each of the streams can have up to 128/16 (8) buffer descriptors - */ - /* - Vec of a Vec was doing something weird and causing the driver to hang. - So now we have a set of variables instead. - - - Fixed? - */ - - pub fn update_sound_buffers(&mut self) { - /* - for i in 0..self.buffs.len(){ - for j in 0.. min(self.buffs[i].len(), 128/16 ) { - self.buff_desc[i * 128/16 + j].set_address(self.buffs[i][j].phys()); - self.buff_desc[i * 128/16 + j].set_length(self.buffs[i][j].length() as u32); - self.buff_desc[i * 128/16 + j].set_interrupt_on_complete(true); - } - }*/ - - let r = self.get_output_stream_descriptor(0).unwrap(); - - self.output_streams - .push(OutputStream::new(NUM_SUB_BUFFS, SUB_BUFF_SIZE, r)); - - let o = self.output_streams.get_mut(0).unwrap(); - - for i in 0..NUM_SUB_BUFFS { - self.buff_desc[i].set_address((o.phys() + o.block_size() * i) as u64); - self.buff_desc[i].set_length(o.block_size() as u32); - self.buff_desc[i].set_interrupt_on_complete(true); - } - } - - pub fn configure(&mut self) -> Result<()> { - let outpin = self.find_best_output_pin()?; - - log::debug!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); - - let path = self.find_path_to_dac(outpin).unwrap(); - - let dac = *path.last().unwrap(); - let pin = *path.first().unwrap(); - - log::debug!("Path to DAC: {:X?}", path); - - // Set power state 0 (on) for all widgets in path - for &addr in &path { - self.set_power_state(addr, 0)?; - } - - // Pin enable (0x80 = headphone amp enable, 0x40 = output enable) - self.cmd.cmd12(pin, 0x707, 0xC0)?; - - // EAPD enable - self.cmd.cmd12(pin, 0x70C, 2)?; - - // Set DAC stream and channel - self.set_stream_channel(dac, 1, 0)?; - - self.update_sound_buffers(); - - log::debug!( - "Supported Formats: {:08X}", - self.get_supported_formats((0, 0x1))? - ); - log::debug!("Capabilities: {:08X}", self.get_capabilities(path[0])?); - - // Create output stream - let output = self.get_output_stream_descriptor(0).unwrap(); - output.set_address(self.buff_desc.physical()); - output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); - output.set_cyclic_buffer_length((NUM_SUB_BUFFS * SUB_BUFF_SIZE) as u32); // number of bytes - output.set_stream_number(1); - output.set_last_valid_index((NUM_SUB_BUFFS - 1) as u16); - output.set_interrupt_on_completion(true); - - // Set DAC converter format - self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2)?; - - // Get DAC converter format - //TODO: should validate? - self.cmd.cmd12(dac, 0xA00, 0)?; - - // Unmute and set gain to 0db for input and output amplifiers on all widgets in path - for &addr in &path { - // Read widget capabilities - let caps = self.cmd.cmd12(addr, 0xF00, 0x09)?; - - //TODO: do we need to set any other indexes? - let left = true; - let right = true; - let index = 0; - let mute = false; - - // Check for input amp - if (caps & (1 << 1)) != 0 { - // Read input capabilities - let in_caps = self.cmd.cmd12(addr, 0xF00, 0x0D)?; - let in_gain = (in_caps & 0x7f) as u8; - // Set input gain - let output = false; - let input = true; - self.set_amplifier_gain_mute( - addr, output, input, left, right, index, mute, in_gain, - )?; - log::debug!("Set {:X?} input gain to 0x{:X}", addr, in_gain); - } - - // Check for output amp - if (caps & (1 << 2)) != 0 { - // Read output capabilities - let out_caps = self.cmd.cmd12(addr, 0xF00, 0x12)?; - let out_gain = (out_caps & 0x7f) as u8; - // Set output gain - let output = true; - let input = false; - self.set_amplifier_gain_mute( - addr, output, input, left, right, index, mute, out_gain, - )?; - log::debug!("Set {:X?} output gain to 0x{:X}", addr, out_gain); - } - } - - //TODO: implement hda-verb? - - output.run(); - { - log::debug!("Waiting for output 0 to start running..."); - let timeout = Timeout::from_secs(1); - while output.control() & (1 << 1) == 0 { - timeout.run().map_err(|()| { - log::error!("timeout on output running"); - Error::new(EIO) - })?; - } - } - - log::debug!( - "Output 0 CONTROL {:#X} STATUS {:#X} POS {:#X}", - output.control(), - output.status(), - output.link_position() - ); - Ok(()) - } - /* - - pub fn configure_vbox(&mut self) { - - let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); - - log::debug!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); - - let path = self.find_path_to_dac(outpin).unwrap(); - log::debug!("Path to DAC: {:X?}", path); - - // Pin enable - self.cmd.cmd12((0,0xC), 0x707, 0x40); - - - // EAPD enable - self.cmd.cmd12((0,0xC), 0x70C, 2); - - self.set_stream_channel((0,0x3), 1, 0); - - self.update_sound_buffers(); - - - log::debug!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); - log::debug!("Capabilities: {:08X}", self.get_capabilities((0,0x1))); - - let output = self.get_output_stream_descriptor(0).unwrap(); - - output.set_address(self.buff_desc_phys); - - output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); - output.set_cyclic_buffer_length((NUM_SUB_BUFFS * SUB_BUFF_SIZE) as u32); - output.set_stream_number(1); - output.set_last_valid_index((NUM_SUB_BUFFS - 1) as u16); - output.set_interrupt_on_completion(true); - - - self.set_power_state((0,0x3), 0); // Power state 0 is fully on - self.set_converter_format((0,0x3), &super::SR_44_1, BitsPerSample::Bits16, 2); - - - self.cmd.cmd12((0,0x3), 0xA00, 0); - - // Unmute and set gain for pin complex and DAC - self.set_amplifier_gain_mute((0,0x3), true, true, true, true, 0, false, 0x7f); - self.set_amplifier_gain_mute((0,0xC), true, true, true, true, 0, false, 0x7f); - - output.run(); - - self.beep(1); - - } - - */ - - pub fn dump_codec(&self, codec: u8) -> String { - let mut string = String::new(); - - for (_, widget) in self.widget_map.iter() { - let _ = writeln!(string, "{}", widget); - } - - string - } - - // BEEP!! - pub fn beep(&mut self, div: u8) { - let addr = self.beep_addr; - if addr != (0, 0) { - let _ = self.cmd.cmd12(addr, 0xF0A, div); - } - } - - pub fn reset_controller(&mut self) -> Result<()> { - self.cmd.stop()?; - - self.regs.statests.write(0x7FFF); - - // 3.3.7 - { - let timeout = Timeout::from_secs(1); - self.regs.gctl.writef(CRST, false); - loop { - if !self.regs.gctl.readf(CRST) { - break; - } - timeout.run().map_err(|()| { - log::error!("failed to start reset"); - Error::new(EIO) - })?; - } - } - - thread::sleep(Duration::from_millis(1)); - - { - let timeout = Timeout::from_secs(1); - self.regs.gctl.writef(CRST, true); - loop { - if self.regs.gctl.readf(CRST) { - break; - } - timeout.run().map_err(|()| { - log::error!("failed to finish reset"); - Error::new(EIO) - })?; - } - } - - thread::sleep(Duration::from_millis(2)); - - let mut ticks: u32 = 0; - while self.regs.statests.read() == 0 { - ticks += 1; - if ticks > 10000 { - break; - } - } - - let statests = self.regs.statests.read(); - log::debug!("Statests: {:04X}", statests); - - for i in 0..15 { - if (statests >> i) & 0x1 == 1 { - self.codecs.push(i as CodecAddr); - } - } - Ok(()) - } - - pub fn num_output_streams(&self) -> usize { - let gcap = self.regs.gcap.read(); - ((gcap >> 12) & 0xF) as usize - } - - pub fn num_input_streams(&self) -> usize { - let gcap = self.regs.gcap.read(); - ((gcap >> 8) & 0xF) as usize - } - - pub fn num_bidirectional_streams(&self) -> usize { - let gcap = self.regs.gcap.read(); - ((gcap >> 3) & 0xF) as usize - } - - pub fn num_serial_data_out(&self) -> usize { - let gcap = self.regs.gcap.read(); - ((gcap >> 1) & 0x3) as usize - } - - pub fn info(&self) { - log::debug!( - "Intel HD Audio Version {}.{}", - self.regs.vmaj.read(), - self.regs.vmin.read() - ); - log::debug!("IHDA: Input Streams: {}", self.num_input_streams()); - log::debug!("IHDA: Output Streams: {}", self.num_output_streams()); - log::debug!( - "IHDA: Bidirectional Streams: {}", - self.num_bidirectional_streams() - ); - log::debug!("IHDA: Serial Data Outputs: {}", self.num_serial_data_out()); - log::debug!("IHDA: 64-Bit: {}", self.regs.gcap.read() & 1 == 1); - } - - fn get_input_stream_descriptor( - &self, - index: usize, - ) -> Option<&'static mut StreamDescriptorRegs> { - unsafe { - if index < self.num_input_streams() { - Some(&mut *((self.base + 0x80 + index * 0x20) as *mut StreamDescriptorRegs)) - } else { - None - } - } - } - - fn get_output_stream_descriptor( - &self, - index: usize, - ) -> Option<&'static mut StreamDescriptorRegs> { - unsafe { - if index < self.num_output_streams() { - Some( - &mut *((self.base + 0x80 + self.num_input_streams() * 0x20 + index * 0x20) - as *mut StreamDescriptorRegs), - ) - } else { - None - } - } - } - - fn get_bidirectional_stream_descriptor( - &self, - index: usize, - ) -> Option<&'static mut StreamDescriptorRegs> { - unsafe { - if index < self.num_bidirectional_streams() { - Some( - &mut *((self.base - + 0x80 - + self.num_input_streams() * 0x20 - + self.num_output_streams() * 0x20 - + index * 0x20) as *mut StreamDescriptorRegs), - ) - } else { - None - } - } - } - - fn set_dma_position_buff_addr(&mut self, addr: u64) { - let addr_val = addr & !0x7F; - self.regs.dplbase.write((addr_val & 0xFFFFFFFF) as u32); - self.regs.dpubase.write((addr_val >> 32) as u32); - } - - fn set_stream_channel(&mut self, addr: WidgetAddr, stream: u8, channel: u8) -> Result<()> { - let val = ((stream & 0xF) << 4) | (channel & 0xF); - self.cmd.cmd12(addr, 0x706, val)?; - Ok(()) - } - - fn set_power_state(&mut self, addr: WidgetAddr, state: u8) -> Result<()> { - self.cmd.cmd12(addr, 0x705, state & 0xF)?; - Ok(()) - } - - fn get_supported_formats(&mut self, addr: WidgetAddr) -> Result { - Ok(self.cmd.cmd12(addr, 0xF00, 0x0A)? as u32) - } - - fn get_capabilities(&mut self, addr: WidgetAddr) -> Result { - Ok(self.cmd.cmd12(addr, 0xF00, 0x09)? as u32) - } - - fn set_converter_format( - &mut self, - addr: WidgetAddr, - sr: &super::SampleRate, - bps: BitsPerSample, - channels: u8, - ) -> Result<()> { - let fmt = super::format_to_u16(sr, bps, channels); - self.cmd.cmd4(addr, 0x2, fmt)?; - Ok(()) - } - - fn set_amplifier_gain_mute( - &mut self, - addr: WidgetAddr, - output: bool, - input: bool, - left: bool, - right: bool, - index: u8, - mute: bool, - gain: u8, - ) -> Result<()> { - let mut payload: u16 = 0; - - if output { - payload |= 1 << 15; - } - if input { - payload |= 1 << 14; - } - if left { - payload |= 1 << 13; - } - if right { - payload |= 1 << 12; - } - if mute { - payload |= 1 << 7; - } - payload |= ((index as u16) & 0x0F) << 8; - payload |= (gain as u16) & 0x7F; - - self.cmd.cmd4(addr, 0x3, payload)?; - Ok(()) - } - - pub fn write_to_output(&mut self, index: u8, buf: &[u8]) -> Poll> { - let output = self.get_output_stream_descriptor(index as usize).unwrap(); - let os = self.output_streams.get_mut(index as usize).unwrap(); - - //let sample_size:usize = output.sample_size(); - let open_block = (output.link_position() as usize) / os.block_size(); - - //log::trace!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}", output.status(), output.link_position(), output.control()); - - if os.current_block() == (open_block + 3) % NUM_SUB_BUFFS { - // Block if we already are 3 buffers ahead - Poll::Pending - } else { - Poll::Ready(os.write_block(buf)) - } - } - - pub fn handle_interrupts(&mut self) -> bool { - let intsts = self.regs.intsts.read(); - if ((intsts >> 31) & 1) == 1 { - // Global Interrupt Status - if ((intsts >> 30) & 1) == 1 { - // Controller Interrupt Status - self.handle_controller_interrupt(); - } - - let sis = intsts & 0x3FFFFFFF; - if sis != 0 { - self.handle_stream_interrupts(sis); - } - } - intsts != 0 - } - - pub fn handle_controller_interrupt(&mut self) {} - - pub fn handle_stream_interrupts(&mut self, sis: u32) { - let iss = self.num_input_streams(); - let oss = self.num_output_streams(); - let bss = self.num_bidirectional_streams(); - - for i in 0..iss { - if ((sis >> i) & 1) == 1 { - let input = self.get_input_stream_descriptor(i).unwrap(); - input.clear_interrupts(); - } - } - - for i in 0..oss { - if ((sis >> (i + iss)) & 1) == 1 { - let output = self.get_output_stream_descriptor(i).unwrap(); - output.clear_interrupts(); - } - } - - for i in 0..bss { - if ((sis >> (i + iss + oss)) & 1) == 1 { - let bid = self.get_bidirectional_stream_descriptor(i).unwrap(); - bid.clear_interrupts(); - } - } - } - - fn validate_path(&mut self, path: &Vec<&str>) -> bool { - log::debug!("Path: {:?}", path); - let mut it = path.iter(); - match it.next() { - Some(card_str) if (*card_str).starts_with("card") => { - match usize::from_str_radix(&(*card_str)[4..], 10) { - Ok(card_num) => { - log::debug!("Card# {}", card_num); - match it.next() { - Some(codec_str) if (*codec_str).starts_with("codec#") => { - match usize::from_str_radix(&(*codec_str)[6..], 10) { - Ok(_codec_num) => { - //let id = self.next_id.fetch_add(1, Ordering::SeqCst); - //self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0)); - true - } - _ => false, - } - } - Some(pcmout_str) if (*pcmout_str).starts_with("pcmout") => { - match usize::from_str_radix(&(*pcmout_str)[6..], 10) { - Ok(pcmout_num) => { - log::debug!("pcmout {}", pcmout_num); - true - } - _ => false, - } - } - Some(pcmin_str) if (*pcmin_str).starts_with("pcmin") => { - match usize::from_str_radix(&(*pcmin_str)[6..], 10) { - Ok(pcmin_num) => { - log::debug!("pcmin {}", pcmin_num); - true - } - _ => false, - } - } - _ => false, - } - } - _ => false, - } - } - Some(cards_str) if *cards_str == "cards" => true, - _ => false, - } - } -} - -impl Drop for IntelHDA { - fn drop(&mut self) { - log::debug!("IHDA: Deallocating IHDA driver."); - } -} - -impl SchemeSync for IntelHDA { - fn scheme_root(&mut self) -> Result { - Ok(self.handles.lock().insert(Handle::SchemeRoot)) - } - fn openat( - &mut self, - dirfd: usize, - path: &str, - _flags: usize, - _fcntl_flags: u32, - ctx: &CallerCtx, - ) -> Result { - { - let handles = self.handles.lock(); - let handle = handles.get(dirfd)?; - if !matches!(handle, Handle::SchemeRoot) { - return Err(Error::new(EACCES)); - } - } - //let path: Vec<&str>; - /* - match str::from_utf8(_path) { - Ok(p) => { - path = p.split("/").collect(); - if !self.validate_path(&path) { - return Err(Error::new(EINVAL)); - - }, - Err(_) => {return Err(Error::new(EINVAL));}, - }*/ - - // TODO: - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - let handle = match path.trim_matches('/') { - //TODO: allow multiple codecs - "codec" => Handle::StrBuf(self.dump_codec(0).into_bytes()), - _ => Handle::Todo, - }; - let id = self.handles.lock().insert(handle); - - // TODO: always positioned? - Ok(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - }) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _flags: u32, - _ctx: &CallerCtx, - ) -> Result { - let handles = self.handles.lock(); - let Handle::StrBuf(strbuf) = handles.get(id)? else { - return Err(Error::new(EBADF)); - }; - - let src = usize::try_from(offset) - .ok() - .and_then(|o| strbuf.get(o..)) - .unwrap_or(&[]); - let len = src.len().min(buf.len()); - buf[..len].copy_from_slice(&src[..len]); - Ok(len) - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - _offset: u64, - _flags: u32, - _ctx: &CallerCtx, - ) -> Result { - let index = { - let mut handles = self.handles.lock(); - match handles.get_mut(id)? { - Handle::Todo => 0, - _ => return Err(Error::new(EBADF)), - } - }; - - //log::debug!("Int count: {}", self.int_counter); - - match self.write_to_output(index, buf) { - Poll::Ready(r) => r, - Poll::Pending => Err(Error::new(EWOULDBLOCK)), - } - } - - fn fpath(&mut self, _id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with(buf, "audiohw", |_| Ok(())) - } - - fn on_close(&mut self, id: usize) { - self.handles.lock().remove(id); - } -} diff --git a/recipes/core/base/drivers/audio/ihdad/src/hda/mod.rs b/recipes/core/base/drivers/audio/ihdad/src/hda/mod.rs deleted file mode 100644 index 7f01daf8ca..0000000000 --- a/recipes/core/base/drivers/audio/ihdad/src/hda/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![allow(dead_code)] -pub mod cmdbuff; -pub mod common; -pub mod device; -pub mod node; -pub mod stream; - -pub use self::node::*; -pub use self::stream::*; - -pub use self::cmdbuff::*; -pub use self::device::IntelHDA; -pub use self::stream::BitsPerSample; -pub use self::stream::BufferDescriptorListEntry; -pub use self::stream::StreamBuffer; -pub use self::stream::StreamDescriptorRegs; diff --git a/recipes/core/base/drivers/audio/ihdad/src/hda/node.rs b/recipes/core/base/drivers/audio/ihdad/src/hda/node.rs deleted file mode 100644 index 06c5121fd7..0000000000 --- a/recipes/core/base/drivers/audio/ihdad/src/hda/node.rs +++ /dev/null @@ -1,108 +0,0 @@ -use super::common::*; -use std::{fmt, mem}; - -#[derive(Clone)] -pub struct HDANode { - pub addr: WidgetAddr, - - // 0x4 - pub subnode_count: u16, - pub subnode_start: u16, - - // 0x5 - pub function_group_type: u8, - - // 0x9 - pub capabilities: u32, - - // 0xE - pub conn_list_len: u8, - - pub connections: Vec, - - pub connection_default: u8, - - pub is_widget: bool, - - pub config_default: u32, -} - -impl HDANode { - pub fn new() -> HDANode { - HDANode { - addr: (0, 0), - subnode_count: 0, - subnode_start: 0, - function_group_type: 0, - capabilities: 0, - conn_list_len: 0, - - config_default: 0, - is_widget: false, - connections: Vec::::new(), - connection_default: 0, - } - } - - pub fn widget_type(&self) -> HDAWidgetType { - unsafe { mem::transmute(((self.capabilities >> 20) & 0xF) as u8) } - } - - pub fn device_default(&self) -> Option { - if self.widget_type() != HDAWidgetType::PinComplex { - None - } else { - Some(unsafe { mem::transmute(((self.config_default >> 20) & 0xF) as u8) }) - } - } - - pub fn configuration_default(&self) -> ConfigurationDefault { - ConfigurationDefault::from_u32(self.config_default) - } - - pub fn addr(&self) -> WidgetAddr { - self.addr - } -} - -impl fmt::Display for HDANode { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.addr == (0, 0) { - write!( - f, - "Addr: {:02X}:{:02X}, Root Node.", - self.addr.0, self.addr.1 - ) - } else if self.is_widget { - match self.widget_type() { - HDAWidgetType::PinComplex => write!( - f, - "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {}/{}: {:X?}.", - self.addr.0, - self.addr.1, - self.widget_type(), - self.device_default().unwrap(), - self.connection_default, - self.conn_list_len, - self.connections - ), - _ => write!( - f, - "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {}/{}: {:X?}.", - self.addr.0, - self.addr.1, - self.widget_type(), - self.connection_default, - self.conn_list_len, - self.connections - ), - } - } else { - write!( - f, - "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", - self.addr.0, self.addr.1, self.function_group_type, self.subnode_count - ) - } - } -} diff --git a/recipes/core/base/drivers/audio/ihdad/src/hda/stream.rs b/recipes/core/base/drivers/audio/ihdad/src/hda/stream.rs deleted file mode 100644 index caa3c36445..0000000000 --- a/recipes/core/base/drivers/audio/ihdad/src/hda/stream.rs +++ /dev/null @@ -1,387 +0,0 @@ -use common::dma::Dma; -use common::io::{Io, Mmio}; -use std::cmp::min; -use std::ptr::copy_nonoverlapping; -use std::result; -use syscall::error::{Error, Result, EIO}; -use syscall::PAGE_SIZE; - -extern crate syscall; - -pub enum BaseRate { - BR44_1, - BR48, -} - -pub struct SampleRate { - base: BaseRate, - mult: u16, - div: u16, -} - -use self::BaseRate::{BR44_1, BR48}; - -pub const SR_8: SampleRate = SampleRate { - base: BR48, - mult: 1, - div: 6, -}; -pub const SR_11_025: SampleRate = SampleRate { - base: BR44_1, - mult: 1, - div: 4, -}; -pub const SR_16: SampleRate = SampleRate { - base: BR48, - mult: 1, - div: 3, -}; -pub const SR_22_05: SampleRate = SampleRate { - base: BR44_1, - mult: 1, - div: 2, -}; -pub const SR_32: SampleRate = SampleRate { - base: BR48, - mult: 2, - div: 3, -}; - -pub const SR_44_1: SampleRate = SampleRate { - base: BR44_1, - mult: 1, - div: 1, -}; -pub const SR_48: SampleRate = SampleRate { - base: BR48, - mult: 1, - div: 1, -}; -pub const SR_88_1: SampleRate = SampleRate { - base: BR44_1, - mult: 2, - div: 1, -}; -pub const SR_96: SampleRate = SampleRate { - base: BR48, - mult: 2, - div: 1, -}; -pub const SR_176_4: SampleRate = SampleRate { - base: BR44_1, - mult: 4, - div: 1, -}; -pub const SR_192: SampleRate = SampleRate { - base: BR48, - mult: 4, - div: 1, -}; - -#[repr(u8)] -pub enum BitsPerSample { - Bits8 = 0, - Bits16 = 1, - Bits20 = 2, - Bits24 = 3, - Bits32 = 4, -} - -pub fn format_to_u16(sr: &SampleRate, bps: BitsPerSample, channels: u8) -> u16 { - // 3.3.41 - - let base: u16 = match sr.base { - BaseRate::BR44_1 => 1 << 14, - BaseRate::BR48 => 0, - }; - - let mult = ((sr.mult - 1) & 0x7) << 11; - - let div = ((sr.div - 1) & 0x7) << 8; - - let bits = (bps as u16) << 4; - - let chan = ((channels - 1) & 0xF) as u16; - - let val: u16 = base | mult | div | bits | chan; - - val -} - -#[repr(C, packed)] -pub struct StreamDescriptorRegs { - ctrl_lo: Mmio, - ctrl_hi: Mmio, - status: Mmio, - link_pos: Mmio, - buff_length: Mmio, - last_valid_index: Mmio, - resv1: Mmio, - fifo_size_: Mmio, - format: Mmio, - resv2: Mmio, - buff_desc_list_lo: Mmio, - buff_desc_list_hi: Mmio, -} - -impl StreamDescriptorRegs { - pub fn status(&self) -> u8 { - self.status.read() - } - - pub fn set_status(&mut self, status: u8) { - self.status.write(status); - } - - pub fn control(&self) -> u32 { - let mut ctrl = self.ctrl_lo.read() as u32; - ctrl |= (self.ctrl_hi.read() as u32) << 16; - ctrl - } - - pub fn set_control(&mut self, control: u32) { - self.ctrl_lo.write((control & 0xFFFF) as u16); - self.ctrl_hi.write(((control >> 16) & 0xFF) as u8); - } - - pub fn set_pcm_format(&mut self, sr: &SampleRate, bps: BitsPerSample, channels: u8) { - // 3.3.41 - - let val = format_to_u16(sr, bps, channels); - self.format.write(val); - } - - pub fn fifo_size(&self) -> u16 { - self.fifo_size_.read() - } - - pub fn set_cyclic_buffer_length(&mut self, length: u32) { - self.buff_length.write(length); - } - - pub fn cyclic_buffer_length(&self) -> u32 { - self.buff_length.read() - } - - pub fn run(&mut self) { - let val = self.control() | (1 << 1); - self.set_control(val); - } - - pub fn stop(&mut self) { - let val = self.control() & !(1 << 1); - self.set_control(val); - } - - pub fn stream_number(&self) -> u8 { - ((self.control() >> 20) & 0xF) as u8 - } - - pub fn set_stream_number(&mut self, stream_number: u8) { - let val = (self.control() & 0x00FFFF) | (((stream_number & 0xF) as u32) << 20); - self.set_control(val); - } - - pub fn set_address(&mut self, addr: usize) { - self.buff_desc_list_lo.write((addr & 0xFFFFFFFF) as u32); - self.buff_desc_list_hi - .write((((addr as u64) >> 32) & 0xFFFFFFFF) as u32); - } - - pub fn set_last_valid_index(&mut self, index: u16) { - self.last_valid_index.write(index); - } - - pub fn link_position(&self) -> u32 { - self.link_pos.read() - } - - pub fn set_interrupt_on_completion(&mut self, enable: bool) { - let mut ctrl = self.control(); - if enable { - ctrl |= 1 << 2; - } else { - ctrl &= !(1 << 2); - } - self.set_control(ctrl); - } - - pub fn buffer_complete(&self) -> bool { - self.status.readf(1 << 2) - } - - pub fn clear_interrupts(&mut self) { - self.status.write(0x7 << 2); - } - - // get sample size in bytes - pub fn sample_size(&self) -> usize { - let format = self.format.read(); - let chan = (format & 0xF) as usize; - let bits = ((format >> 4) & 0xF) as usize; - match bits { - 0 => 1 * (chan + 1), - 1 => 2 * (chan + 1), - _ => 4 * (chan + 1), - } - } -} - -pub struct OutputStream { - buff: StreamBuffer, - - desc_regs: &'static mut StreamDescriptorRegs, -} - -impl OutputStream { - pub fn new( - block_count: usize, - block_length: usize, - regs: &'static mut StreamDescriptorRegs, - ) -> OutputStream { - OutputStream { - buff: StreamBuffer::new(block_length, block_count).unwrap(), - - desc_regs: regs, - } - } - - pub fn write_block(&mut self, buf: &[u8]) -> Result { - self.buff.write_block(buf) - } - - pub fn block_size(&self) -> usize { - self.buff.block_size() - } - - pub fn block_count(&self) -> usize { - self.buff.block_count() - } - - pub fn current_block(&self) -> usize { - self.buff.current_block() - } - - pub fn addr(&self) -> usize { - self.buff.addr() - } - - pub fn phys(&self) -> usize { - self.buff.phys() - } -} - -#[repr(C, packed)] -pub struct BufferDescriptorListEntry { - addr_low: Mmio, - addr_high: Mmio, - len: Mmio, - ioc_resv: Mmio, -} - -impl BufferDescriptorListEntry { - pub fn address(&self) -> u64 { - (self.addr_low.read() as u64) | ((self.addr_high.read() as u64) << 32) - } - - pub fn set_address(&mut self, addr: u64) { - self.addr_low.write(addr as u32); - self.addr_high.write((addr >> 32) as u32); - } - - pub fn length(&self) -> u32 { - self.len.read() - } - - pub fn set_length(&mut self, length: u32) { - self.len.write(length) - } - - pub fn interrupt_on_completion(&self) -> bool { - (self.ioc_resv.read() & 0x1) == 0x1 - } - - pub fn set_interrupt_on_complete(&mut self, ioc: bool) { - self.ioc_resv.writef(1, ioc); - } -} - -pub struct StreamBuffer { - mem: Dma<[u8]>, - - block_cnt: usize, - block_len: usize, - - cur_pos: usize, -} - -impl StreamBuffer { - pub fn new( - block_length: usize, - block_count: usize, - ) -> result::Result { - let page_aligned_size = (block_length * block_count).next_multiple_of(PAGE_SIZE); - let mem = unsafe { - Dma::zeroed_slice(page_aligned_size) - .map_err(|_| "Could not allocate physical memory for buffer.")? - .assume_init() - }; - - Ok(StreamBuffer { - mem, - block_len: block_length, - block_cnt: block_count, - cur_pos: 0, - }) - } - - pub fn length(&self) -> usize { - self.block_len * self.block_cnt - } - - pub fn addr(&self) -> usize { - self.mem.as_ptr() as usize - } - - pub fn phys(&self) -> usize { - self.mem.physical() - } - - pub fn block_size(&self) -> usize { - self.block_len - } - - pub fn block_count(&self) -> usize { - self.block_cnt - } - - pub fn current_block(&self) -> usize { - self.cur_pos - } - - pub fn write_block(&mut self, buf: &[u8]) -> Result { - if buf.len() != self.block_size() { - return Err(Error::new(EIO)); - } - let len = min(self.block_size(), buf.len()); - - //log::trace!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}", self.phys(), self.addr(), self.current_block() * self.block_size(), len); - unsafe { - copy_nonoverlapping( - buf.as_ptr(), - (self.addr() + self.current_block() * self.block_size()) as *mut u8, - len, - ); - } - - self.cur_pos += 1; - self.cur_pos %= self.block_count(); - - Ok(len) - } -} -impl Drop for StreamBuffer { - fn drop(&mut self) { - log::debug!("IHDA: Deallocating buffer."); - } -} diff --git a/recipes/core/base/drivers/audio/ihdad/src/main.rs b/recipes/core/base/drivers/audio/ihdad/src/main.rs deleted file mode 100755 index 31a2add737..0000000000 --- a/recipes/core/base/drivers/audio/ihdad/src/main.rs +++ /dev/null @@ -1,135 +0,0 @@ -use redox_scheme::scheme::register_sync_scheme; -use redox_scheme::Socket; -use scheme_utils::ReadinessBased; -use std::io::{Read, Write}; -use std::os::unix::io::AsRawFd; -use std::usize; - -use event::{user_data, EventQueue}; -use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; -use pcid_interface::PciFunctionHandle; - -pub mod hda; - -/* -VEND:PROD -Virtualbox 8086:2668 -QEMU ICH9 8086:293E -82801H ICH8 8086:284B -*/ - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - let pci_config = pcid_handle.config(); - - let mut name = pci_config.func.name(); - name.push_str("_ihda"); - - common::setup_logging( - "audio", - "pci", - &name, - common::output_level(), - common::file_level(), - ); - - log::info!("IHDA {}", pci_config.func.display()); - - let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; - - let irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "ihdad"); - - { - let vend_prod: u32 = ((pci_config.func.full_device_id.vendor_id as u32) << 16) - | (pci_config.func.full_device_id.device_id as u32); - - user_data! { - enum Source { - Irq, - Scheme, - } - } - - let event_queue = - EventQueue::::new().expect("ihdad: Could not create event queue."); - let socket = Socket::nonblock().expect("ihdad: failed to create socket"); - let mut device = unsafe { - hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") - }; - let mut readiness_based = ReadinessBased::new(&socket, 16); - - register_sync_scheme(&socket, "audiohw", &mut device) - .expect("ihdad: failed to register audiohw scheme to namespace"); - daemon.ready(); - - event_queue - .subscribe( - socket.inner().raw(), - Source::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - event_queue - .subscribe( - irq_file.irq_handle().as_raw_fd() as usize, - Source::Irq, - event::EventFlags::READ, - ) - .unwrap(); - - libredox::call::setrens(0, 0).expect("ihdad: failed to enter null namespace"); - - let all = [Source::Irq, Source::Scheme]; - - for event in all - .into_iter() - .chain(event_queue.map(|e| e.expect("failed to get next event").user_data)) - { - match event { - Source::Irq => { - let mut irq = [0; 8]; - irq_file.irq_handle().read(&mut irq).unwrap(); - - if !device.irq() { - continue; - } - irq_file.irq_handle().write(&mut irq).unwrap(); - - readiness_based - .poll_all_requests(&mut device) - .expect("ihdad: failed to poll requests"); - readiness_based - .write_responses() - .expect("ihdad: failed to write to socket"); - - /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - } - Source::Scheme => { - readiness_based - .read_and_process_requests(&mut device) - .expect("ihdad: failed to read from socket"); - readiness_based - .write_responses() - .expect("ihdad: failed to write to socket"); - - /* - let next_read = device.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - } - } - } - - std::process::exit(0); - } -} diff --git a/recipes/core/base/drivers/audio/sb16d/Cargo.toml b/recipes/core/base/drivers/audio/sb16d/Cargo.toml deleted file mode 100644 index a54c7287a8..0000000000 --- a/recipes/core/base/drivers/audio/sb16d/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "sb16d" -description = "Sound Blaster sound card driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -bitflags.workspace = true -common = { path = "../../common" } -libredox.workspace = true -log.workspace = true -daemon = { path = "../../../daemon" } -redox_event.workspace = true -redox_syscall.workspace = true -spin.workspace = true -redox-scheme.workspace = true -scheme-utils = { path = "../../../scheme-utils" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/audio/sb16d/src/device.rs b/recipes/core/base/drivers/audio/sb16d/src/device.rs deleted file mode 100644 index 5667ce764a..0000000000 --- a/recipes/core/base/drivers/audio/sb16d/src/device.rs +++ /dev/null @@ -1,232 +0,0 @@ -use std::{thread, time}; - -use common::io::{Io, Pio, ReadOnly, WriteOnly}; - -use redox_scheme::scheme::SchemeSync; -use redox_scheme::CallerCtx; -use redox_scheme::OpenResult; -use scheme_utils::{FpathWriter, HandleMap}; -use syscall::error::{Error, Result, EACCES, EBADF, ENODEV}; -use syscall::schemev2::NewFdFlags; - -use spin::Mutex; - -const NUM_SUB_BUFFS: usize = 32; -const SUB_BUFF_SIZE: usize = 2048; - -enum Handle { - Todo, - SchemeRoot, -} - -#[allow(dead_code)] -pub struct Sb16 { - handles: Mutex>, - pub(crate) irqs: Vec, - dmas: Vec, - // Regs - /* 0x04 */ mixer_addr: WriteOnly>, - /* 0x05 */ mixer_data: Pio, - /* 0x06 */ dsp_reset: WriteOnly>, - /* 0x0A */ dsp_read_data: ReadOnly>, - /* 0x0C */ dsp_write_data: WriteOnly>, - /* 0x0C */ dsp_write_status: ReadOnly>, - /* 0x0E */ dsp_read_status: ReadOnly>, -} - -impl Sb16 { - pub unsafe fn new(addr: u16) -> Result { - let mut module = Sb16 { - handles: Mutex::new(HandleMap::new()), - irqs: Vec::new(), - dmas: Vec::new(), - // Regs - mixer_addr: WriteOnly::new(Pio::new(addr + 0x04)), - mixer_data: Pio::new(addr + 0x05), - dsp_reset: WriteOnly::new(Pio::new(addr + 0x06)), - dsp_read_data: ReadOnly::new(Pio::new(addr + 0x0A)), - dsp_write_data: WriteOnly::new(Pio::new(addr + 0x0C)), - dsp_write_status: ReadOnly::new(Pio::new(addr + 0x0C)), - dsp_read_status: ReadOnly::new(Pio::new(addr + 0x0E)), - }; - - module.init()?; - - Ok(module) - } - - fn mixer_read(&mut self, index: u8) -> u8 { - self.mixer_addr.write(index); - self.mixer_data.read() - } - - fn mixer_write(&mut self, index: u8, value: u8) { - self.mixer_addr.write(index); - self.mixer_data.write(value); - } - - fn dsp_read(&mut self) -> Result { - // Bit 7 must be 1 before data can be sent - while !self.dsp_read_status.readf(1 << 7) { - //TODO: timeout! - std::thread::yield_now(); - } - - Ok(self.dsp_read_data.read()) - } - - fn dsp_write(&mut self, value: u8) -> Result<()> { - // Bit 7 must be 0 before data can be sent - while self.dsp_write_status.readf(1 << 7) { - //TODO: timeout! - std::thread::yield_now(); - } - - self.dsp_write_data.write(value); - Ok(()) - } - - fn init(&mut self) -> Result<()> { - // Perform DSP reset - { - // Write 1 to reset port - self.dsp_reset.write(1); - - // Wait 3us - thread::sleep(time::Duration::from_micros(3)); - - // Write 0 to reset port - self.dsp_reset.write(0); - - //TODO: Wait for ready byte (0xAA) using read status - thread::sleep(time::Duration::from_micros(100)); - - let ready = self.dsp_read()?; - if ready != 0xAA { - log::error!("ready byte was 0x{:02X} instead of 0xAA", ready); - return Err(Error::new(ENODEV)); - } - } - - // Read DSP version - { - self.dsp_write(0xE1)?; - - let major = self.dsp_read()?; - let minor = self.dsp_read()?; - log::info!("DSP version {}.{:02}", major, minor); - - if major != 4 { - log::error!("Unsupported DSP major version {}", major); - return Err(Error::new(ENODEV)); - } - } - - // Get available IRQs and DMAs - { - self.irqs.clear(); - let irq_mask = self.mixer_read(0x80); - if (irq_mask & (1 << 0)) != 0 { - self.irqs.push(2); - } - if (irq_mask & (1 << 1)) != 0 { - self.irqs.push(5); - } - if (irq_mask & (1 << 2)) != 0 { - self.irqs.push(7); - } - if (irq_mask & (1 << 3)) != 0 { - self.irqs.push(10); - } - - self.dmas.clear(); - let dma_mask = self.mixer_read(0x81); - if (dma_mask & (1 << 0)) != 0 { - self.dmas.push(0); - } - if (dma_mask & (1 << 1)) != 0 { - self.dmas.push(1); - } - if (dma_mask & (1 << 3)) != 0 { - self.dmas.push(3); - } - if (dma_mask & (1 << 5)) != 0 { - self.dmas.push(5); - } - if (dma_mask & (1 << 6)) != 0 { - self.dmas.push(6); - } - if (dma_mask & (1 << 7)) != 0 { - self.dmas.push(7); - } - - log::info!("IRQs {:02X?} DMAs {:02X?}", self.irqs, self.dmas); - } - - // Set output sample rate to 44100 Hz (Redox OS standard) - { - let rate = 44100u16; - self.dsp_write(0x41)?; - self.dsp_write((rate >> 8) as u8)?; - self.dsp_write(rate as u8)?; - } - - Ok(()) - } - - pub fn irq(&mut self) -> bool { - //TODO - false - } -} - -impl SchemeSync for Sb16 { - fn scheme_root(&mut self) -> Result { - Ok(self.handles.lock().insert(Handle::SchemeRoot)) - } - fn openat( - &mut self, - dirfd: usize, - _path: &str, - _flags: usize, - _fcntl_flags: u32, - ctx: &CallerCtx, - ) -> Result { - { - let handles = self.handles.lock(); - let handle = handles.get(dirfd)?; - if !matches!(handle, Handle::SchemeRoot) { - return Err(Error::new(EACCES)); - } - } - if ctx.uid == 0 { - let id = self.handles.lock().insert(Handle::Todo); - Ok(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::empty(), - }) - } else { - Err(Error::new(EACCES)) - } - } - - fn write( - &mut self, - _id: usize, - _buf: &[u8], - _offset: u64, - _flags: u32, - _ctx: &CallerCtx, - ) -> Result { - //TODO - Err(Error::new(EBADF)) - } - - fn fpath(&mut self, _id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with(buf, "audiohw", |_| Ok(())) - } - - fn on_close(&mut self, id: usize) { - self.handles.lock().remove(id); - } -} diff --git a/recipes/core/base/drivers/audio/sb16d/src/main.rs b/recipes/core/base/drivers/audio/sb16d/src/main.rs deleted file mode 100644 index 9e351629d3..0000000000 --- a/recipes/core/base/drivers/audio/sb16d/src/main.rs +++ /dev/null @@ -1,118 +0,0 @@ -use libredox::{flag, Fd}; -use redox_scheme::scheme::register_sync_scheme; -use redox_scheme::Socket; -use scheme_utils::ReadinessBased; -use std::{env, usize}; - -use event::{user_data, EventQueue}; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub mod device; - -fn main() { - daemon::Daemon::new(daemon); -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn daemon(daemon: daemon::Daemon) -> ! { - let mut args = env::args().skip(1); - - let addr_str = args.next().unwrap_or("220".to_string()); - let addr = u16::from_str_radix(&addr_str, 16).expect("sb16: failed to parse address"); - - println!(" + sb16 at 0x{:X}\n", addr); - - common::setup_logging( - "audio", - "pci", - "sb16", - common::output_level(), - common::file_level(), - ); - - common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights"); - - let socket = Socket::nonblock().expect("sb16d: failed to create socket"); - let mut device = unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") }; - let mut readiness_based = ReadinessBased::new(&socket, 16); - - //TODO: error on multiple IRQs? - let irq_file = match device.irqs.first() { - Some(irq) => Fd::open(&format!("/scheme/irq/{}", irq), flag::O_RDWR, 0) - .expect("sb16d: failed to open IRQ file"), - None => panic!("sb16d: no IRQs found"), - }; - user_data! { - enum Source { - Irq, - Scheme, - } - } - - let event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); - event_queue - .subscribe(irq_file.raw(), Source::Irq, event::EventFlags::READ) - .unwrap(); - event_queue - .subscribe( - socket.inner().raw(), - Source::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - - register_sync_scheme(&socket, "sb16d", &mut device) - .expect("sb16d: failed to register audiohw scheme to namespace"); - - daemon.ready(); - - libredox::call::setrens(0, 0).expect("sb16d: failed to enter null namespace"); - - let all = [Source::Irq, Source::Scheme]; - - for event in all - .into_iter() - .chain(event_queue.map(|e| e.expect("sb16d: failed to get next event").user_data)) - { - match event { - Source::Irq => { - let mut irq = [0; 8]; - irq_file.read(&mut irq).unwrap(); - - if !device.irq() { - continue; - } - irq_file.write(&mut irq).unwrap(); - - readiness_based - .poll_all_requests(&mut device) - .expect("sb16d: failed to poll requests"); - readiness_based - .write_responses() - .expect("sb16d: failed to write to socket"); - - /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - } - Source::Scheme => { - readiness_based - .read_and_process_requests(&mut device) - .expect("sb16d: failed to read from socket"); - readiness_based - .write_responses() - .expect("sb16d: failed to write to socket"); - } - } - } - - std::process::exit(0); -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -fn daemon(daemon: daemon::Daemon) -> ! { - unimplemented!() -} diff --git a/recipes/core/base/drivers/common/Cargo.toml b/recipes/core/base/drivers/common/Cargo.toml deleted file mode 100644 index b61be20f66..0000000000 --- a/recipes/core/base/drivers/common/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "common" -description = "Shared driver code library" -version = "0.1.0" -edition = "2021" -authors = ["4lDO2 <4lDO2@protonmail.com>"] -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -libredox.workspace = true -log.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -redox-log.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/common/src/dma.rs b/recipes/core/base/drivers/common/src/dma.rs deleted file mode 100644 index 3d359f4b3b..0000000000 --- a/recipes/core/base/drivers/common/src/dma.rs +++ /dev/null @@ -1,265 +0,0 @@ -use std::mem::{self, size_of, MaybeUninit}; -use std::ops::{Deref, DerefMut}; -use std::ptr; -use std::sync::LazyLock; - -use libredox::call::MmapArgs; -use libredox::{error::Result, flag, Fd}; -use syscall::PAGE_SIZE; - -use crate::{memory_root_fd, MemoryType, VirtaddrTranslationHandle}; - -/// Defines the platform-specific memory type for DMA operations -/// -/// - On x86 systems, DMA uses Write-back memory ([`MemoryType::Writeback`]) -/// - On aarch64 systems, DMA uses uncacheable memory ([`MemoryType::Uncacheable`]) -const DMA_MEMTY: MemoryType = { - if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { - // x86 ensures cache coherence with DMA memory - MemoryType::Writeback - } else if cfg!(target_arch = "aarch64") { - // aarch64 currently must map DMA memory without caching to ensure coherence - MemoryType::Uncacheable - } else if cfg!(target_arch = "riscv64") { - // FIXME check this out more - MemoryType::Uncacheable - } else { - panic!("invalid arch") - } -}; - -/// Returns a file descriptor for zeroized physically-contiguous DMA memory. -/// -/// # Returns -/// -/// A [Result] containing: -/// - '[Ok]' - A [Fd] (file descriptor) to zeroized, physically continuous DMA usable memory -/// - '[Err]' - The error returned by the provider of the /scheme/memory/zeroed scheme. -/// -/// # Errors -/// -/// This function can return an error in the following case: -/// -/// - The request for the physical memory fails. -pub(crate) fn phys_contiguous_fd() -> Result { - memory_root_fd().openat( - &format!("zeroed@{DMA_MEMTY}?phys_contiguous"), - flag::O_CLOEXEC, - 0, - ) -} - -/// Allocates a chunk of physical memory for DMA, and then maps it to virtual memory. -/// -/// # Arguments -/// 'length: [usize]' - The length of the memory region. Must be a multiple of [`PAGE_SIZE`] -/// -/// # Returns -/// -/// This function returns a [Result] containing the following: -/// - A '[Ok]([usize], *[mut] ())' containing a Tuple of the physical address of the region, and a raw pointer to that region in virtual memory. -/// - An '[Err]' - containing the error for the operation. -/// -/// # Errors -/// -/// This function asserts if: -/// - length is not a multiple of [`PAGE_SIZE`] -/// -/// This function returns an error if: -/// - A file descriptor to physically contiguous memory of type [`DMA_MEMTY`] could not be acquired -/// - A virtual mapping for the physically contiguous memory could not be created -/// - The virtual address returned by the memory manager was invalid. -fn alloc_and_map(length: usize, handle: &VirtaddrTranslationHandle) -> Result<(usize, *mut ())> { - assert_eq!(length % PAGE_SIZE, 0); - unsafe { - let fd = phys_contiguous_fd()?; - let virt = libredox::call::mmap(MmapArgs { - fd: fd.raw(), - offset: 0, // ignored - addr: core::ptr::null_mut(), // ignored - length, - flags: flag::MAP_PRIVATE, - prot: flag::PROT_READ | flag::PROT_WRITE, - })?; - let phys = handle.translate(virt as usize)?; - for i in 1..length.div_ceil(PAGE_SIZE) { - debug_assert_eq!( - handle.translate(virt as usize + i * PAGE_SIZE), - Ok(phys + i * PAGE_SIZE), - "NOT CONTIGUOUS" - ); - } - Ok((phys, virt as *mut ())) - } -} - -/// A safe accessor for DMA memory. -pub struct Dma { - /// The physical address of the memory - phys: usize, - /// The page-aligned length of the memory. Will be a multiple of [`PAGE_SIZE`] - aligned_len: usize, - /// The pointer to the Dma memory in the virtual address space. - virt: *mut T, -} - -impl Dma { - /// [Dma] constructor that allocates and initializes a region of DMA memory with the page-aligned - /// size and initial value of some T - /// - /// # Arguments - /// 'value: T' - The initial value to write to the allocated region - /// - /// # Returns - /// - /// This function returns a [Result] containing the following: - /// - /// - A '[Ok] (`[Dma]`)' containing the initialized region - /// - An '[Err]' containing an error. - pub fn new(value: T) -> Result { - unsafe { - let mut zeroed = Self::zeroed()?; - zeroed.as_mut_ptr().write(value); - Ok(zeroed.assume_init()) - } - } - - /// [Dma] constructor that allocates and zeroizes a memory region of the page-aligned size of T - /// - /// # Returns - /// - /// This function returns a [Result] containing the following: - /// - /// - A '[Ok] (`[Dma]<[MaybeUninit]>`)' containing the allocated and zeroized memory - /// - An '[Err]' containing an error. - pub fn zeroed() -> Result>> { - let aligned_len = size_of::().next_multiple_of(PAGE_SIZE); - let (phys, virt) = alloc_and_map(aligned_len, &*VIRTTOPHYS_HANDLE)?; - Ok(Dma { - phys, - virt: virt.cast(), - aligned_len, - }) - } -} - -impl Dma> { - /// Assumes that possibly uninitialized DMA memory has been initialized, and returns a new - /// instance of an object of type `[Dma]`. - /// - /// # Returns - /// - `[Dma]` - The original structure without the [`MaybeUninit`] wrapper around its contents. - /// - /// # Notes - /// - This is unsafe because it assumes that the memory stored within the `[Dma]` is a valid - /// instance of T. If it isn't (for example -- if it was initialized with [`Dma::zeroed`]), - /// then the underlying memory may not contain the expected T structure. - pub unsafe fn assume_init(self) -> Dma { - let Dma { - phys, - aligned_len, - virt, - } = self; - mem::forget(self); - - Dma { - phys, - aligned_len, - virt: virt.cast(), - } - } -} -impl Dma { - /// Returns the physical address of the physical memory that this [Dma] structure references. - /// - /// # Returns - /// [usize] - The physical address of the memory. - pub fn physical(&self) -> usize { - self.phys - } -} -// TODO: there should exist a "context" struct that drivers create at start, which would be passed -// to the respective functions -static VIRTTOPHYS_HANDLE: LazyLock = LazyLock::new(|| { - VirtaddrTranslationHandle::new().expect("failed to acquire virttophys translation handle") -}); - -impl Dma<[T]> { - /// Returns a [Dma] object containing a zeroized slice of T with a given count. - /// - /// # Arguments - /// - /// - 'count: [usize]' - The number of elements of type T in the allocated slice. - pub fn zeroed_slice(count: usize) -> Result]>> { - let aligned_len = count - .checked_mul(size_of::()) - .unwrap() - .next_multiple_of(PAGE_SIZE); - let (phys, virt) = alloc_and_map(aligned_len, &*VIRTTOPHYS_HANDLE)?; - - Ok(Dma { - phys, - aligned_len, - virt: ptr::slice_from_raw_parts_mut(virt.cast(), count), - }) - } - - /// Casts the slice from type T to type U. - /// - /// # Returns - /// '`[DMA]`' - A cast handle to the Dma memory. - pub unsafe fn cast_slice(self) -> Dma<[U]> { - let Dma { - phys, - virt, - aligned_len, - } = self; - core::mem::forget(self); - - Dma { - phys, - virt: virt as *mut [U], - aligned_len, - } - } -} -impl Dma<[MaybeUninit]> { - /// See [`Dma>::assume_init`] - pub unsafe fn assume_init(self) -> Dma<[T]> { - let &Dma { - phys, - aligned_len, - virt, - } = &self; - mem::forget(self); - - Dma { - phys, - aligned_len, - virt: virt as *mut [T], - } - } -} - -impl Deref for Dma { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.virt } - } -} - -impl DerefMut for Dma { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.virt } - } -} - -impl Drop for Dma { - fn drop(&mut self) { - unsafe { - ptr::drop_in_place(self.virt); - let _ = libredox::call::munmap(self.virt as *mut (), self.aligned_len); - } - } -} diff --git a/recipes/core/base/drivers/common/src/io.rs b/recipes/core/base/drivers/common/src/io.rs deleted file mode 100644 index 6c7ad20839..0000000000 --- a/recipes/core/base/drivers/common/src/io.rs +++ /dev/null @@ -1,95 +0,0 @@ -use core::{ - cmp::PartialEq, - ops::{BitAnd, BitOr, Not}, -}; - -mod mmio; -mod mmio_ptr; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod pio; - -pub use mmio::*; -pub use mmio_ptr::*; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub use pio::*; - -/// IO abstraction -pub trait Io { - /// Value type for IO, usually some unsigned number - type Value: Copy - + PartialEq - + BitAnd - + BitOr - + Not; - - /// Read the underlying valu2e - fn read(&self) -> Self::Value; - /// Write the underlying value - fn write(&mut self, value: Self::Value); - - /// Check whether the underlying value contains bit flags - #[inline(always)] - fn readf(&self, flags: Self::Value) -> bool { - (self.read() & flags) as Self::Value == flags - } - - /// Enable or disable specific bit flags - #[inline(always)] - fn writef(&mut self, flags: Self::Value, value: bool) { - let tmp: Self::Value = match value { - true => self.read() | flags, - false => self.read() & !flags, - }; - self.write(tmp); - } -} - -/// Read-only IO -#[repr(transparent)] -pub struct ReadOnly { - inner: I, -} - -impl ReadOnly { - /// Wraps IO - pub const fn new(inner: I) -> ReadOnly { - ReadOnly { inner } - } -} - -impl ReadOnly { - /// Calls [`Io::read`] - #[inline(always)] - pub fn read(&self) -> I::Value { - self.inner.read() - } - - /// Calls [`Io::readf`] - #[inline(always)] - pub fn readf(&self, flags: I::Value) -> bool { - self.inner.readf(flags) - } -} - -#[repr(transparent)] -/// Write-only IO -pub struct WriteOnly { - inner: I, -} - -impl WriteOnly { - /// Wraps IO - pub const fn new(inner: I) -> WriteOnly { - WriteOnly { inner } - } -} - -impl WriteOnly { - /// Calls [`Io::write`] - #[inline(always)] - pub fn write(&mut self, value: I::Value) { - self.inner.write(value) - } - - // writef requires read which is not valid when write-only -} diff --git a/recipes/core/base/drivers/common/src/io/mmio.rs b/recipes/core/base/drivers/common/src/io/mmio.rs deleted file mode 100644 index 1edb71014c..0000000000 --- a/recipes/core/base/drivers/common/src/io/mmio.rs +++ /dev/null @@ -1,173 +0,0 @@ -use core::{mem::MaybeUninit, ptr}; - -use super::Io; - -/// MMIO abstraction -#[repr(C, packed)] -pub struct Mmio { - value: MaybeUninit, -} - -impl Mmio { - /// Creates a zeroed instance - pub unsafe fn zeroed() -> Self { - Self { - value: MaybeUninit::zeroed(), - } - } - - /// Creates an unitialized instance - pub unsafe fn uninit() -> Self { - Self { - value: MaybeUninit::uninit(), - } - } - - /// Creates a new instance - pub const fn new(value: T) -> Self { - Self { - value: MaybeUninit::new(value), - } - } -} - -// Generic implementation (WARNING: requires aligned pointers!) -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -impl Io for Mmio -where - T: Copy - + PartialEq - + core::ops::BitAnd - + core::ops::BitOr - + core::ops::Not, -{ - type Value = T; - - fn read(&self) -> T { - unsafe { ptr::read_volatile(ptr::addr_of!(self.value).cast::()) } - } - - fn write(&mut self, value: T) { - unsafe { ptr::write_volatile(ptr::addr_of_mut!(self.value).cast::(), value) }; - } -} - -// x86 u8 implementation -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -impl Io for Mmio { - type Value = u8; - - fn read(&self) -> Self::Value { - unsafe { - let value: Self::Value; - let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); - core::arch::asm!( - "mov {}, [{}]", - out(reg_byte) value, - in(reg) ptr - ); - value - } - } - - fn write(&mut self, value: Self::Value) { - unsafe { - let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); - core::arch::asm!( - "mov [{}], {}", - in(reg) ptr, - in(reg_byte) value, - ); - } - } -} - -// x86 u16 implementation -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -impl Io for Mmio { - type Value = u16; - - fn read(&self) -> Self::Value { - unsafe { - let value: Self::Value; - let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); - core::arch::asm!( - "mov {:x}, [{}]", - out(reg) value, - in(reg) ptr - ); - value - } - } - - fn write(&mut self, value: Self::Value) { - unsafe { - let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); - core::arch::asm!( - "mov [{}], {:x}", - in(reg) ptr, - in(reg) value, - ); - } - } -} - -// x86 u32 implementation -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -impl Io for Mmio { - type Value = u32; - - fn read(&self) -> Self::Value { - unsafe { - let value: Self::Value; - let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); - core::arch::asm!( - "mov {:e}, [{}]", - out(reg) value, - in(reg) ptr - ); - value - } - } - - fn write(&mut self, value: Self::Value) { - unsafe { - let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); - core::arch::asm!( - "mov [{}], {:e}", - in(reg) ptr, - in(reg) value, - ); - } - } -} - -// x86 u64 implementation (x86_64 only) -#[cfg(target_arch = "x86_64")] -impl Io for Mmio { - type Value = u64; - - fn read(&self) -> Self::Value { - unsafe { - let value: Self::Value; - let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); - core::arch::asm!( - "mov {:r}, [{}]", - out(reg) value, - in(reg) ptr - ); - value - } - } - - fn write(&mut self, value: Self::Value) { - unsafe { - let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); - core::arch::asm!( - "mov [{}], {:r}", - in(reg) ptr, - in(reg) value, - ); - } - } -} diff --git a/recipes/core/base/drivers/common/src/io/mmio_ptr.rs b/recipes/core/base/drivers/common/src/io/mmio_ptr.rs deleted file mode 100644 index 07c31fec64..0000000000 --- a/recipes/core/base/drivers/common/src/io/mmio_ptr.rs +++ /dev/null @@ -1,157 +0,0 @@ -use super::Io; - -/// MMIO using pointer instead of wrapped type -pub struct MmioPtr { - ptr: *mut T, -} - -impl MmioPtr { - //TODO: reads and writes are unsafe, not new. - /// Creates a `MmioPtr`. - pub unsafe fn new(ptr: *mut T) -> Self { - Self { ptr } - } - - /// Creates a const pointer from a `MmioPtr`. - pub const fn as_ptr(&self) -> *const T { - self.ptr - } - - /// Creates a mutable pointer from a `MmioPtr`. - pub const fn as_mut_ptr(&mut self) -> *mut T { - self.ptr - } -} - -// Generic implementation (WARNING: requires aligned pointers!) -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -impl Io for MmioPtr -where - T: Copy - + PartialEq - + core::ops::BitAnd - + core::ops::BitOr - + core::ops::Not, -{ - type Value = T; - - fn read(&self) -> T { - unsafe { core::ptr::read_volatile(self.ptr) } - } - - fn write(&mut self, value: T) { - unsafe { core::ptr::write_volatile(self.ptr, value) }; - } -} - -// x86 u8 implementation -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -impl Io for MmioPtr { - type Value = u8; - - fn read(&self) -> Self::Value { - unsafe { - let value: Self::Value; - core::arch::asm!( - "mov {}, [{}]", - out(reg_byte) value, - in(reg) self.ptr - ); - value - } - } - - fn write(&mut self, value: Self::Value) { - unsafe { - core::arch::asm!( - "mov [{}], {}", - in(reg) self.ptr, - in(reg_byte) value, - ); - } - } -} - -// x86 u16 implementation -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -impl Io for MmioPtr { - type Value = u16; - - fn read(&self) -> Self::Value { - unsafe { - let value: Self::Value; - core::arch::asm!( - "mov {:x}, [{}]", - out(reg) value, - in(reg) self.ptr - ); - value - } - } - - fn write(&mut self, value: Self::Value) { - unsafe { - core::arch::asm!( - "mov [{}], {:x}", - in(reg) self.ptr, - in(reg) value, - ); - } - } -} - -// x86 u32 implementation -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -impl Io for MmioPtr { - type Value = u32; - - fn read(&self) -> Self::Value { - unsafe { - let value: Self::Value; - core::arch::asm!( - "mov {:e}, [{}]", - out(reg) value, - in(reg) self.ptr - ); - value - } - } - - fn write(&mut self, value: Self::Value) { - unsafe { - core::arch::asm!( - "mov [{}], {:e}", - in(reg) self.ptr, - in(reg) value, - ); - } - } -} - -// x86 u64 implementation (x86_64 only) -#[cfg(target_arch = "x86_64")] -impl Io for MmioPtr { - type Value = u64; - - fn read(&self) -> Self::Value { - unsafe { - let value: Self::Value; - core::arch::asm!( - "mov {:r}, [{}]", - out(reg) value, - in(reg) self.ptr - ); - value - } - } - - fn write(&mut self, value: Self::Value) { - unsafe { - core::arch::asm!( - "mov [{}], {:r}", - in(reg) self.ptr, - in(reg) value, - ); - } - } -} diff --git a/recipes/core/base/drivers/common/src/io/pio.rs b/recipes/core/base/drivers/common/src/io/pio.rs deleted file mode 100644 index 187e4734c3..0000000000 --- a/recipes/core/base/drivers/common/src/io/pio.rs +++ /dev/null @@ -1,89 +0,0 @@ -use core::{arch::asm, marker::PhantomData}; - -use super::Io; - -/// Generic PIO -#[derive(Copy, Clone)] -pub struct Pio { - port: u16, - value: PhantomData, -} - -impl Pio { - /// Create a PIO from a given port - pub const fn new(port: u16) -> Self { - Pio:: { - port, - value: PhantomData, - } - } -} - -/// Read/Write for byte PIO -impl Io for Pio { - type Value = u8; - - /// Read - #[inline(always)] - fn read(&self) -> u8 { - let value: u8; - unsafe { - asm!("in al, dx", in("dx") self.port, out("al") value, options(nostack, nomem, preserves_flags)); - } - value - } - - /// Write - #[inline(always)] - fn write(&mut self, value: u8) { - unsafe { - asm!("out dx, al", in("dx") self.port, in("al") value, options(nostack, nomem, preserves_flags)); - } - } -} - -/// Read/Write for word PIO -impl Io for Pio { - type Value = u16; - - /// Read - #[inline(always)] - fn read(&self) -> u16 { - let value: u16; - unsafe { - asm!("in ax, dx", in("dx") self.port, out("ax") value, options(nostack, nomem, preserves_flags)); - } - value - } - - /// Write - #[inline(always)] - fn write(&mut self, value: u16) { - unsafe { - asm!("out dx, ax", in("dx") self.port, in("ax") value, options(nostack, nomem, preserves_flags)); - } - } -} - -/// Read/Write for doubleword PIO -impl Io for Pio { - type Value = u32; - - /// Read - #[inline(always)] - fn read(&self) -> u32 { - let value: u32; - unsafe { - asm!("in eax, dx", in("dx") self.port, out("eax") value, options(nostack, nomem, preserves_flags)); - } - value - } - - /// Write - #[inline(always)] - fn write(&mut self, value: u32) { - unsafe { - asm!("out dx, eax", in("dx") self.port, in("eax") value, options(nostack, nomem, preserves_flags)); - } - } -} diff --git a/recipes/core/base/drivers/common/src/lib.rs b/recipes/core/base/drivers/common/src/lib.rs deleted file mode 100644 index b6661e3aaa..0000000000 --- a/recipes/core/base/drivers/common/src/lib.rs +++ /dev/null @@ -1,331 +0,0 @@ -//! This crate provides various abstractions for use by all drivers in the Redox drivers repo. -//! -//! This includes direct memory access via [dma], and Scatter-Gather List support via [sgl]. It also -//! provides various memory management structures for use with drivers, and some logging support. - -use libredox::call::MmapArgs; -use libredox::flag::{self, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; -use libredox::{ - errno::EINVAL, - error::{Error, Result}, - Fd, -}; -use syscall::{ProcSchemeVerb, PAGE_SIZE}; - -/// The Direct Memory Access (DMA) API for drivers -pub mod dma; -/// MMIO utilities -pub mod io; -mod logger; -/// The Scatter Gather List (SGL) API for drivers. -pub mod sgl; -/// Low latency timeout for driver loops -pub mod timeout; - -pub use logger::{file_level, output_level, setup_logging}; - -use std::sync::OnceLock; - -static MEMORY_ROOT_FD: OnceLock = OnceLock::new(); - -/// Initializes a file descriptor to be used as the root memory for a driver. -/// -/// # Panics -/// -/// This function will panic if: -/// - `libredox` is unable to open a file descriptor. -/// - The memory root file descriptor has already been set (this function has already been called). -pub fn init() { - if MEMORY_ROOT_FD - .set( - libredox::Fd::open("/scheme/memory/scheme-root", 0, 0) - .expect("drivers common: failed to open memory root fd"), - ) - .is_err() - { - panic!("drivers common: failed to set memory root fd"); - } -} - -/// Gets the memory root file descriptor. -/// -/// # Panics -/// -/// This function will panic if `init` has not already been called first. -pub fn memory_root_fd() -> &'static libredox::Fd { - MEMORY_ROOT_FD - .get() - .expect("drivers common: memory root fd not initialized. Please call `common::init` in your main function.") -} - -/// Specifies the write behavior for a specific region of memory -/// -/// These types indicate to the driver how writes to a specific memory region are handled by the -/// system. This usually refers to the caching behavior that the processor or I/O device responsible -/// for that memory implements. -/// -/// aarch64 and x86 have very different cache-coherency rules, so this API as written is likely -/// not sufficient to describe the memory caching behavior in a cross-platform manner. As such, -/// consider this API unstable. -#[derive(Clone, Copy, Debug)] -pub enum MemoryType { - /// A region of memory that implements Write-back caching. - /// - /// In write-back caching, the processor will first store data in its local cache, and then - /// flush it to the actual storage location at regular intervals, or as applications access - /// the data. - Writeback, - /// A region of memory that does not implement caching. Writes to these regions are immediate. - Uncacheable, - /// A region of memory that implements write combining. - /// - /// Write combining memory regions store all writes in a temporary buffer called a Write - /// Combine Buffer. Multiple writes to the location are stored in a single buffer, and then - /// released to the memory location in an unspecified order. Write-Combine memory does not - /// guarantee that the order at which you write to it is the order at which those writes are - /// committed to memory. - WriteCombining, - /// Memory stored in an intermediate Write Combine Buffer and released later - /// Memory-Mapped I/O. This is an aarch64-specific term. - DeviceMemory, -} -impl Default for MemoryType { - fn default() -> Self { - Self::Writeback - } -} - -/// Represents the protection level of an area of memory. -/// -/// This structure shouldn't be used directly -- instead, use the [`Prot::RO`] (Read-Only), -/// [`Prot::WO`] (Write-Only) and [`Prot::RW`] (Read-Write) constants to specify the memory's protection -/// level. -#[derive(Clone, Copy, Debug)] -pub struct Prot { - /// The memory is readable - pub read: bool, - /// The memory is writeable - pub write: bool, -} - -/// Implements the memory protection level constants -impl Prot { - /// A constant representing Read-Only memory. - pub const RO: Self = Self { - read: true, - write: false, - }; - - /// A constant representing Write-Only memory - pub const WO: Self = Self { - read: false, - write: true, - }; - - /// A constant representing Read-Write memory - pub const RW: Self = Self { - read: true, - write: true, - }; -} - -/// Maps physical memory to virtual memory -/// -/// # Arguments -/// -/// * '`base_phys`: [usize]' - The base address of the physical memory to map. -/// * 'len: [usize]' - The length of the physical memory to map (Should be a multiple of [`PAGE_SIZE`] -/// * '_: [Prot]' - The memory protection level of the mapping. -/// * 'type: [`MemoryType`]' - The caching behavior specification of the memory. -/// -/// # Returns -/// -/// A '[Result]<*mut ()>' which is: -/// - '[Ok]' containing a raw pointer to the mapped memory. -/// - '[Err]' which contains an error on failure. -/// -/// # Errors -/// -/// This function will return an error if: -/// - An invalid value is provided to 'read' or 'write' -/// - The system could not open a file descriptor to the memory scheme for the specified [`MemoryType`]. -/// - The system failed to map the physical address to a virtual address. See [`libredox::call::mmap`] -/// -/// # Safety -/// -/// Safe, as the kernel ensures it doesn't conflict with any other memory described in the memory -/// map for regular RAM. -/// -/// # Notes -/// - This function is unsafe, and upon using it you will be responsible for freeing the memory with -/// [`libredox::call::munmap`]. If you want a safe accessor, use [`PhysBorrowed`] instead. -/// - The `MemoryType` specified is used to tell the function which memory scheme to access. (i.e -/// /scheme/memory/physical@wb, /scheme/memory/physical@uc, etc). -pub unsafe fn physmap( - base_phys: usize, - len: usize, - Prot { read, write }: Prot, - ty: MemoryType, -) -> Result<*mut ()> { - // TODO: arraystring? - - //Return an error rather than potentially crash the kernel. - if base_phys == 0 { - return Err(Error::new(EINVAL)); - } - - let path = format!( - "physical@{}", - match ty { - MemoryType::Writeback => "wb", - MemoryType::Uncacheable => "uc", - MemoryType::WriteCombining => "wc", - MemoryType::DeviceMemory => "dev", - } - ); - let mode = match (read, write) { - (true, true) => O_RDWR, - (true, false) => O_RDONLY, - (false, true) => O_WRONLY, - (false, false) => return Err(Error::new(EINVAL)), - }; - let mut prot = 0; - if read { - prot |= flag::PROT_READ; - } - if write { - prot |= flag::PROT_WRITE; - } - - let fd = memory_root_fd().openat(&path, O_CLOEXEC | mode, 0)?; - Ok(libredox::call::mmap(MmapArgs { - fd: fd.raw(), - offset: base_phys as u64, - length: len.next_multiple_of(PAGE_SIZE), - flags: flag::MAP_SHARED, - prot, - addr: core::ptr::null_mut(), - })? as *mut ()) -} - -impl std::fmt::Display for MemoryType { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - match self { - Self::Writeback => "wb", - Self::Uncacheable => "uc", - Self::WriteCombining => "wc", - Self::DeviceMemory => "dev", - } - ) - } -} - -/// A safe virtual mapping to physical memory that unmaps the memory when the structure goes out -/// of scope. -/// -/// This function provides a safe binding to [physmap]. It implements Drop to free the mapped memory -/// when the structure goes out of scope. -pub struct PhysBorrowed { - mem: *mut (), - len: usize, -} -impl PhysBorrowed { - /// Constructs a `PhysBorrowed` instance. - /// - /// # Arguments - /// See [physmap] for a description of the parameters. - /// - /// # Returns - /// A '[Result]' which contains the following: - /// - A '[`PhysBorrowed`]' which represents the newly mapped region. - /// - An 'Err' if a memory mapping error occurs. - /// - /// # Errors - /// See [physmap] for a description of the error cases. - pub fn map(base_phys: usize, len: usize, prot: Prot, ty: MemoryType) -> Result { - let mem = unsafe { physmap(base_phys, len, prot, ty)? }; - Ok(Self { - mem, - len: len.next_multiple_of(PAGE_SIZE), - }) - } - - /// Gets a raw pointer to the borrowed region. - /// - /// # Returns - /// - self.mem - A pointer to the mapped region in virtual memory. - /// - /// # Notes - /// - The pointer may live beyond the lifetime of [`PhysBorrowed`], so dereferences to the pointer - /// must be treated as unsafe. - /// - pub fn as_ptr(&self) -> *mut () { - self.mem - } - - /// Gets the length of the mapped region. - /// - /// # Returns - /// - self.len - The length of the mapped region. It should be a multiple of [`PAGE_SIZE`] - pub fn mapped_len(&self) -> usize { - self.len - } -} - -impl Drop for PhysBorrowed { - /// Frees the mapped memory region. - fn drop(&mut self) { - unsafe { - let _ = libredox::call::munmap(self.mem, self.len); - } - } -} - -/// Instructs the kernel to enable I/O ports for this (usermode) process (x86-specific). -/// -/// On Redox, x86 privilege ring 3 represents userspace. Most Redox drivers run in userspace to -/// prevent system instability caused by a faulty driver. Processes with (bitmap-enabled) IO port -/// rights can use the IN/OUT instructions. This is not the same as IOPL 3; the CLI instruction is -/// still not allowed. -pub fn acquire_port_io_rights() -> Result<()> { - extern "C" { - fn redox_cur_thrfd_v0() -> usize; - } - let kernel_fd = syscall::dup(unsafe { redox_cur_thrfd_v0() }, b"open_via_dup")?; - let res = libredox::call::call_wo( - kernel_fd, - &[], - syscall::CallFlags::empty(), - &[ProcSchemeVerb::Iopl as u64], - ); - let _ = syscall::close(kernel_fd); - res?; - Ok(()) -} - -/// Kernel handle for translating virtual addresses in the current address space, to their -/// underlying physical addresses. -/// -/// It is currently unspecified whether this handle is specific to the address space at the time it -/// was created, or whether all calls reference the currently active address space. -pub struct VirtaddrTranslationHandle { - fd: Fd, -} - -impl VirtaddrTranslationHandle { - /// Create a new handle, requires uid=0 but this may change. - pub fn new() -> Result { - Ok(Self { - fd: memory_root_fd().openat("translation", O_CLOEXEC, 0)?, - }) - } - /// Translate physical => virtual. - pub fn translate(&self, physical: usize) -> Result { - let mut buf = physical.to_ne_bytes(); - libredox::call::call_ro(self.fd.raw(), &mut buf, syscall::CallFlags::empty(), &[])?; - Ok(usize::from_ne_bytes(buf)) - } -} diff --git a/recipes/core/base/drivers/common/src/logger.rs b/recipes/core/base/drivers/common/src/logger.rs deleted file mode 100644 index 82ec2bd054..0000000000 --- a/recipes/core/base/drivers/common/src/logger.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::str::FromStr; - -use libredox::{flag, Fd}; -use redox_log::{OutputBuilder, RedoxLogger}; - -/// Get the log verbosity for the output level. -pub fn output_level() -> log::LevelFilter { - log::LevelFilter::Info -} - -/// Get the log verbosity for the file level. -pub fn file_level() -> log::LevelFilter { - log::LevelFilter::Info -} - -/// Configures logging for a single driver. -#[cfg_attr(not(target_os = "redox"), allow(unused_variables, unused_mut))] -pub fn setup_logging( - category: &str, - subcategory: &str, - logfile_base: &str, - mut output_level: log::LevelFilter, - file_level: log::LevelFilter, -) { - RedoxLogger::init_timezone(); - if let Some(log_level) = read_bootloader_log_level_env(category, subcategory) { - output_level = log_level; - } - - let mut logger = RedoxLogger::new().with_output( - OutputBuilder::stderr() - .with_filter(output_level) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme( - category, - subcategory, - format!("{logfile_base}.log"), - ) { - Ok(b) => { - logger = logger.with_output(b.with_filter(file_level).flush_on_newline(true).build()) - } - Err(error) => eprintln!("Failed to create {logfile_base}.log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme( - category, - subcategory, - format!("{logfile_base}.ansi.log"), - ) { - Ok(b) => { - logger = logger.with_output( - b.with_filter(file_level) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ) - } - Err(error) => eprintln!("Failed to create {logfile_base}.ansi.log: {}", error), - } - - logger.enable().expect("failed to set default logger"); -} - -fn read_bootloader_log_level_env(category: &str, subcategory: &str) -> Option { - let mut env_bytes = [0_u8; 4096]; - - // TODO: Have the kernel env can specify prefixed env key instead of having to read all of them - let envs = { - let Ok(fd) = Fd::open("/scheme/sys/env", flag::O_RDONLY | flag::O_CLOEXEC, 0) else { - return None; - }; - let Ok(bytes_read) = fd.read(&mut env_bytes) else { - return None; - }; - if bytes_read >= env_bytes.len() { - return None; - } - let env_bytes = &mut env_bytes[..bytes_read]; - - env_bytes - .split(|&c| c == b'\n') - .filter(|var| var.starts_with(b"DRIVER_")) - .collect::>() - }; - - let log_env_keys = [ - format!("DRIVER_{}_LOG_LEVEL=", subcategory.to_ascii_uppercase()), - format!("DRIVER_{}_LOG_LEVEL=", category.to_ascii_uppercase()), - "DRIVER_LOG_LEVEL=".to_string(), - ]; - - for log_env_key in log_env_keys { - let log_env_key = log_env_key.as_bytes(); - if let Some(log_env) = envs.iter().find_map(|var| var.strip_prefix(log_env_key)) { - if let Ok(Ok(log_level)) = str::from_utf8(&log_env).map(log::LevelFilter::from_str) { - return Some(log_level); - } - } - } - - None -} diff --git a/recipes/core/base/drivers/common/src/sgl.rs b/recipes/core/base/drivers/common/src/sgl.rs deleted file mode 100644 index e5d781a4bd..0000000000 --- a/recipes/core/base/drivers/common/src/sgl.rs +++ /dev/null @@ -1,130 +0,0 @@ -use std::num::NonZeroUsize; - -use libredox::call::MmapArgs; -use libredox::errno::EINVAL; -use libredox::error::{Error, Result}; -use libredox::flag::{MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE}; -use syscall::{MAP_FIXED, PAGE_SIZE}; - -use crate::dma::phys_contiguous_fd; -use crate::VirtaddrTranslationHandle; - -/// A Scatter-Gather List data structure -/// -/// See: -#[derive(Debug)] -pub struct Sgl { - /// A raw pointer to the SGL in virtual memory - virt: *mut u8, - /// The length of the allocated memory, guaranteed to be a multiple of [`PAGE_SIZE`]. - aligned_length: usize, - /// The length of the allocated memory. This value is NOT guaranteed to be a multiple of [`PAGE_SIZE`] - unaligned_length: NonZeroUsize, - /// The vector of chunks tracked by this [Sgl] object. This is the sparsely-populated vector in the SGL algorithm. - chunks: Vec, -} - -/// A structure representing a chunk of memory in the sparsely-populated vector of the SGL -#[derive(Debug)] -pub struct Chunk { - /// The offset of the chunk in the sparsely-populated vector. - pub offset: usize, - /// The physical address of the chunk - pub phys: usize, - /// A raw pointer to the chunk in virtual memory - pub virt: *mut u8, - /// The length of the chunk in bytes. - pub length: usize, -} - -impl Sgl { - /// Constructor for the scatter/gather list. - /// - /// # Arguments - /// - /// '`unaligned_length`: [usize]' - The length of the SGL, not necessarily aligned to the nearest - /// page. - pub fn new(unaligned_length: usize) -> Result { - let unaligned_length = NonZeroUsize::new(unaligned_length).ok_or(Error::new(EINVAL))?; - - // TODO: Both PAGE_SIZE and MAX_ALLOC_SIZE should be dynamic. - let aligned_length = unaligned_length.get().next_multiple_of(PAGE_SIZE); - const MAX_ALLOC_SIZE: usize = 1 << 22; - - unsafe { - let virt = libredox::call::mmap(MmapArgs { - flags: MAP_PRIVATE, - prot: PROT_NONE, - length: aligned_length, - - offset: 0, - fd: !0, - addr: core::ptr::null_mut(), - })? - .cast::(); - - let mut this = Self { - virt, - aligned_length, - unaligned_length, - chunks: Vec::new(), - }; - - // TODO: SglContext to avoid reopening these fds? - let phys_contiguous_fd = phys_contiguous_fd()?; - let virttophys_handle = VirtaddrTranslationHandle::new()?; - - let mut offset = 0; - while offset < aligned_length { - let preferred_chunk_length = (aligned_length - offset) - .min(MAX_ALLOC_SIZE) - .next_power_of_two(); - let chunk_length = if preferred_chunk_length > aligned_length - offset { - preferred_chunk_length / 2 - } else { - preferred_chunk_length - }; - libredox::call::mmap(MmapArgs { - addr: virt.add(offset).cast(), - flags: MAP_PRIVATE | (MAP_FIXED.bits() as u32), - prot: PROT_READ | PROT_WRITE, - length: chunk_length, - fd: phys_contiguous_fd.raw(), - - offset: 0, - })?; - let phys = virttophys_handle.translate(virt as usize + offset)?; - this.chunks.push(Chunk { - offset, - phys, - length: (unaligned_length.get() - offset).min(chunk_length), - virt: virt.add(offset), - }); - offset += chunk_length; - } - - Ok(this) - } - } - /// Returns an immutable reference to the vector of chunks - pub fn chunks(&self) -> &[Chunk] { - &self.chunks - } - - /// Returns a raw pointer to the vector of chunks in virtual memory - pub fn as_ptr(&self) -> *mut u8 { - self.virt - } - /// Returns the length of the scatter-gather list. - pub fn len(&self) -> usize { - self.unaligned_length.get() - } -} - -impl Drop for Sgl { - fn drop(&mut self) { - unsafe { - let _ = libredox::call::munmap(self.virt.cast(), self.aligned_length); - } - } -} diff --git a/recipes/core/base/drivers/common/src/timeout.rs b/recipes/core/base/drivers/common/src/timeout.rs deleted file mode 100644 index 4a2b19814c..0000000000 --- a/recipes/core/base/drivers/common/src/timeout.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::time::{Duration, Instant}; - -/// Represents an amount of time for a driver to give up to the OS scheduler. -pub struct Timeout { - instant: Instant, - duration: Duration, -} - -impl Timeout { - /// Create a new `Timeout` from a `Duration`. - #[inline] - pub fn new(duration: Duration) -> Self { - Self { - instant: Instant::now(), - duration, - } - } - - /// Create a new `Timeout` by specifying the amount of microseconds. - #[inline] - pub fn from_micros(micros: u64) -> Self { - Self::new(Duration::from_micros(micros)) - } - - /// Create a new `Timeout` by specifying the amount of milliseconds. - #[inline] - pub fn from_millis(millis: u64) -> Self { - Self::new(Duration::from_millis(millis)) - } - - /// Create a new `Timeout` by specifying the amount of seconds. - #[inline] - pub fn from_secs(secs: u64) -> Self { - Self::new(Duration::from_secs(secs)) - } - - /// Execute the `Timeout`. - /// - /// # Errors - /// - /// Returns an `Err` if the duration of the `Timeout` has already elapsed - /// between creating the `Timeout` and calling this function. - #[inline] - pub fn run(&self) -> Result<(), ()> { - if self.instant.elapsed() < self.duration { - // Sleeps in Redox are only evaluated on PIT ticks (a few ms), which is not - // short enough for a reasonably responsive timeout. However, the clock is - // highly accurate. So, we yield instead of sleep to reduce latency. - //TODO: allow timeout that spins instead of yields? - std::thread::yield_now(); - Ok(()) - } else { - Err(()) - } - } -} diff --git a/recipes/core/base/drivers/executor/Cargo.toml b/recipes/core/base/drivers/executor/Cargo.toml deleted file mode 100644 index a910e3c24e..0000000000 --- a/recipes/core/base/drivers/executor/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "executor" -description = "Asynchronous framework for queue-based hardware interfaces" -authors = ["4lDO2 <4lDO2@protonmail.com>"] -version = "0.1.0" -edition = "2021" -license = "MIT" - -[dependencies] -log.workspace = true -redox_event.workspace = true -slab.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/executor/src/lib.rs b/recipes/core/base/drivers/executor/src/lib.rs deleted file mode 100644 index 6b54e07bc1..0000000000 --- a/recipes/core/base/drivers/executor/src/lib.rs +++ /dev/null @@ -1,396 +0,0 @@ -use std::cell::{Cell, RefCell}; -use std::collections::{HashMap, VecDeque}; -use std::fmt::Debug; -use std::fs::File; -use std::future::{Future, IntoFuture}; -use std::hash::Hash; -use std::io::{Read, Write}; -use std::marker::PhantomData; -use std::os::fd::AsRawFd; -use std::panic::AssertUnwindSafe; -use std::pin::Pin; -use std::ptr::NonNull; -use std::rc::Rc; -use std::task; - -use event::{EventFlags, RawEventQueue}; -use slab::Slab; - -type EventUserData = usize; - -type FutIdx = usize; - -pub trait Hardware: Sized { - type CmdId: Clone + Copy + Debug + Hash + Eq + PartialEq; - type CqId: Clone + Copy + Debug + Hash + Eq + PartialEq; - type SqId: Clone + Copy + Debug + Hash + Eq + PartialEq; - type Sqe: Debug + Clone + Copy; - type Cqe; - type Iv: Clone + Copy + Debug; - - type GlobalCtxt; - - // TODO: the kernel should also do this automatically before sending EOI messages to the IC - fn mask_vector(ctxt: &Self::GlobalCtxt, iv: Self::Iv); - fn unmask_vector(ctxt: &Self::GlobalCtxt, iv: Self::Iv); - - fn set_sqe_cmdid(sqe: &mut Self::Sqe, id: Self::CmdId); - fn get_cqe_cmdid(cqe: &Self::Cqe) -> Self::CmdId; - - // TODO: support multiple SQs per CQ or vice versa? - fn sq_cq(ctxt: &Self::GlobalCtxt, id: Self::CqId) -> Self::SqId; - - fn current() -> Rc>; - fn vtable() -> &'static task::RawWakerVTable; - - fn try_submit( - ctxt: &Self::GlobalCtxt, - sq_id: Self::SqId, - success: impl FnOnce(Self::CmdId) -> Self::Sqe, - fail: impl FnOnce(), - ) -> Option<(Self::CqId, Self::CmdId)>; - fn poll_cqes(ctxt: &Self::GlobalCtxt, handle: impl FnMut(Self::CqId, Self::Cqe)); -} - -/// Async executor, single IV, thread-per-core architecture -pub struct LocalExecutor { - global_ctxt: Hw::GlobalCtxt, - - queue: RawEventQueue, - vector: Hw::Iv, - irq_handle: File, - intx: bool, - - // TODO: One IV and SQ/CQ per core (where the admin queue can be managed by the main thread). - awaiting_submission: RefCell>>, - awaiting_completion: - RefCell>)>>>, - - external_event: RefCell)>>, - next_user_data: Cell, - - ready_futures: RefCell>, - futures: RefCell + 'static>>>>, - is_polling: Cell, -} - -impl LocalExecutor { - pub fn register_external_event( - &self, - fd: usize, - flags: event::EventFlags, - ) -> ExternalEventSource { - let user_data = self.next_user_data.get(); - self.next_user_data.set(user_data.checked_add(1).unwrap()); - - self.queue - .subscribe(fd, user_data, flags) - .expect("failed to subscribe to event"); - - ExternalEventSource { - flags: event::EventFlags::empty(), - user_data, - _not_send_or_unpin: PhantomData, - } - } - pub fn current() -> Rc { - Hw::current() - } - pub fn poll(&self) -> usize { - assert!(!self.is_polling.replace(true)); - - let mut finished = 0; - - for future_idx in self.ready_futures.borrow_mut().drain(..) { - let waker = waker::(future_idx); - - let mut futures = self.futures.borrow_mut(); - let res = match std::panic::catch_unwind(AssertUnwindSafe(|| { - futures[future_idx] - .as_mut() - .poll(&mut task::Context::from_waker(&waker)) - })) { - Ok(r) => r, - Err(_) => { - log::error!("Task panicked!"); - core::mem::forget(futures.remove(future_idx)); - continue; - } - }; - if res.is_ready() { - drop(futures.remove(future_idx)); - finished += 1; - } - } - self.is_polling.set(false); - - finished - } - pub fn spawn(&self, fut: impl IntoFuture + 'static) { - let idx = self - .futures - .borrow_mut() - .insert(Box::pin(fut.into_future())); - self.ready_futures.borrow_mut().push_back(idx); - } - pub fn block_on<'a, O: 'a>(&self, fut: impl IntoFuture + 'a) -> O { - let retval = Rc::new(RefCell::new(None)); - - let retval2 = Rc::clone(&retval); - let idx = self.futures.borrow_mut().insert({ - let t1: Pin + 'a>> = Box::pin(async move { - *retval2.borrow_mut() = Some(fut.await); - }); - // SAFETY: Apart from the lifetimes, the types are exactly the same. We also know - // block_on simply cannot return without having fully awaited and dropped the future, - // even if that future panics (cf. the catch_unwind invocation). - let t2: Pin + 'static>> = - unsafe { std::mem::transmute(t1) }; - - t2 - }); - - self.ready_futures.borrow_mut().push_front(idx); - - loop { - let finished = self.poll(); - if retval.borrow().is_some() { - break; - } - if finished == 0 { - self.react(); - } - } - - let o = retval.borrow_mut().take().unwrap(); - o - } - fn react(&self) { - let event = self.queue.next_event().expect("failed to get next event"); - - if event.user_data != 0 { - let Some((fut_idx, flags_ptr)) = - self.external_event.borrow_mut().remove(&event.user_data) - else { - // Spurious event - return; - }; - unsafe { - flags_ptr - .as_ptr() - .write(event::EventFlags::from_bits_retain(event.flags)); - } - self.ready_futures.borrow_mut().push_back(fut_idx); - return; - } - - if self.intx { - let mut buf = [0_u8; core::mem::size_of::()]; - if (&self.irq_handle).read(&mut buf).unwrap() != 0 { - (&self.irq_handle).write(&buf).unwrap(); - } - } - - // TODO: The kernel should probably do the masking (when using MSI/MSI-X at least), which - // should happen before EOI messages to the interrupt controller. - Hw::mask_vector(&self.global_ctxt, self.vector); - Hw::poll_cqes(&self.global_ctxt, |cq_id, cqe| { - if let Some((fut_idx, comp_ptr)) = self - .awaiting_completion - .borrow_mut() - .get_mut(&cq_id) - .and_then(|per_cmd| per_cmd.remove(&Hw::get_cqe_cmdid(&cqe))) - { - unsafe { - comp_ptr.as_ptr().write(Some(cqe)); - } - self.ready_futures.borrow_mut().push_back(fut_idx); - - if let Some(submitting) = self - .awaiting_submission - .borrow_mut() - .get_mut(&Hw::sq_cq(&self.global_ctxt, cq_id)) - .and_then(|q| q.pop_front()) - { - self.ready_futures.borrow_mut().push_back(submitting); - } - } - }); - Hw::unmask_vector(&self.global_ctxt, self.vector); - } - pub async fn submit(&self, sq_id: Hw::SqId, cmd: Hw::Sqe) -> Hw::Cqe { - CqeFuture:: { - state: State::::Submitting { sq_id, cmd }, - comp: None, - _not_send: PhantomData, - } - .await - } -} - -struct CqeFuture { - pub state: State, - pub comp: Option, - pub _not_send: PhantomData<*const ()>, -} -enum State { - Submitting { sq_id: Hw::SqId, cmd: Hw::Sqe }, - Completing { cq_id: Hw::CqId, cmd_id: Hw::CmdId }, -} - -fn current_executor_and_idx( - cx: &mut task::Context<'_>, -) -> (Rc>, FutIdx) { - let executor = LocalExecutor::current(); - - let idx = cx.waker().data() as FutIdx; - assert_eq!( - cx.waker().vtable() as *const _, - Hw::vtable(), - "incompatible executor for CqeFuture" - ); - - (executor, idx) -} - -impl Future for CqeFuture { - type Output = Hw::Cqe; - - fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll { - let this = unsafe { self.get_unchecked_mut() }; - - let (executor, idx) = current_executor_and_idx::(cx); - - match this.state { - State::Submitting { sq_id, mut cmd } => { - let mut awaiting = executor.awaiting_submission.borrow_mut(); - - if let Some((cq_id, cmd_id)) = Hw::try_submit( - &executor.global_ctxt, - sq_id, - |cmd_id| { - Hw::set_sqe_cmdid(&mut cmd, cmd_id); - log::trace!("About to submit {cmd:?}"); - cmd - }, - || { - awaiting.entry(sq_id).or_default().push_back(idx); - }, - ) { - executor - .awaiting_completion - .borrow_mut() - .entry(cq_id) - .or_default() - .insert(cmd_id, (idx, (&mut this.comp).into())); - this.state = State::Completing { cq_id, cmd_id }; - } - task::Poll::Pending - } - State::Completing { cq_id, cmd_id } => match this.comp.take() { - Some(comp) => { - log::trace!("ready!"); - task::Poll::Ready(comp) - } - - // Shouldn't technically be possible - None => { - log::trace!("spurious poll"); - executor - .awaiting_completion - .borrow_mut() - .entry(cq_id) - .or_default() - .insert(cmd_id, (idx, (&mut this.comp).into())); - task::Poll::Pending - } - }, - } - } -} - -unsafe fn vt_clone(idx: *const ()) -> task::RawWaker { - task::RawWaker::new(idx, Hw::vtable()) -} -unsafe fn vt_drop(_idx: *const ()) {} -unsafe fn vt_wake(idx: *const ()) { - Hw::current() - .ready_futures - .borrow_mut() - .push_back(idx as FutIdx); -} - -fn waker(idx: FutIdx) -> task::Waker { - unsafe { task::Waker::from_raw(task::RawWaker::new(idx as *const (), Hw::vtable())) } -} -pub const fn vtable() -> task::RawWakerVTable { - task::RawWakerVTable::new(vt_clone::, vt_wake::, vt_wake::, vt_drop) -} - -pub struct ExternalEventSource { - flags: event::EventFlags, - user_data: EventUserData, - _not_send_or_unpin: PhantomData<(*const (), fn() -> Hw)>, -} -pub struct Event { - flags: event::EventFlags, - _not_send: PhantomData<*const ()>, -} -impl Event { - pub fn flags(&self) -> event::EventFlags { - self.flags - } -} -impl ExternalEventSource { - fn poll_next(self: Pin<&mut Self>, cx: &mut task::Context) -> task::Poll> { - let this = unsafe { self.get_unchecked_mut() }; - - let flags = std::mem::take(&mut this.flags); - - if flags.is_empty() { - let (executor, idx) = current_executor_and_idx::(cx); - executor - .external_event - .borrow_mut() - .insert(this.user_data, (idx, (&mut this.flags).into())); - return task::Poll::Pending; - } - task::Poll::Ready(Some(Event { - flags, - _not_send: PhantomData, - })) - } - pub async fn next(mut self: Pin<&mut Self>) -> Option { - core::future::poll_fn(|cx| self.as_mut().poll_next(cx)).await - } -} -pub fn init_raw( - global_ctxt: Hw::GlobalCtxt, - vector: Hw::Iv, - intx: bool, - irq_handle: File, -) -> LocalExecutor { - let queue = RawEventQueue::new().expect("failed to allocate event queue for local executor"); - - // TODO: Multiple CPUs - queue - .subscribe(irq_handle.as_raw_fd() as usize, 0, EventFlags::READ) - .expect("failed to subscribe to IRQ event"); - - LocalExecutor { - global_ctxt, - - queue, - vector, - intx, - irq_handle, - - awaiting_submission: RefCell::new(HashMap::new()), - awaiting_completion: RefCell::new(HashMap::new()), - external_event: RefCell::new(HashMap::new()), - next_user_data: Cell::new(1), - ready_futures: RefCell::new(VecDeque::new()), - futures: RefCell::new(Slab::with_capacity(16)), - is_polling: Cell::new(false), - } -} diff --git a/recipes/core/base/drivers/gpio/gpiod/Cargo.toml b/recipes/core/base/drivers/gpio/gpiod/Cargo.toml deleted file mode 100644 index 7e087bd776..0000000000 --- a/recipes/core/base/drivers/gpio/gpiod/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "gpiod" -description = "GPIO controller registry daemon" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow.workspace = true -log.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -libredox.workspace = true -redox-scheme.workspace = true -ron.workspace = true -serde.workspace = true - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -scheme-utils = { path = "../../../scheme-utils" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/gpio/gpiod/src/main.rs b/recipes/core/base/drivers/gpio/gpiod/src/main.rs deleted file mode 100644 index 41618ba1ac..0000000000 --- a/recipes/core/base/drivers/gpio/gpiod/src/main.rs +++ /dev/null @@ -1,496 +0,0 @@ -use std::collections::BTreeMap; -use std::process; - -use anyhow::{Context, Result}; -use redox_scheme::scheme::SchemeSync; -use redox_scheme::{CallerCtx, OpenResult, Socket}; -use scheme_utils::{Blocking, HandleMap}; -use serde::{Deserialize, Serialize}; -use syscall::schemev2::NewFdFlags; -use syscall::{Error as SysError, EACCES, EBADF, EINVAL, ENOENT}; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct GpioControllerInfo { - pub id: u32, - pub name: String, - pub pin_count: usize, - pub supports_interrupt: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum GpioControlRequest { - RegisterController { info: GpioControllerInfo }, - ReadPin { controller_id: u32, pin: u32 }, - WritePin { controller_id: u32, pin: u32, value: bool }, - ConfigurePin { controller_id: u32, pin: u32, config: PinConfig }, - ListControllers, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct PinConfig { - pub direction: PinDirection, - pub pull: PullMode, - pub interrupt_mode: Option, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum PinDirection { - Input, - Output, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum PullMode { - None, - Up, - Down, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum InterruptMode { - EdgeRising, - EdgeFalling, - EdgeBoth, - LevelHigh, - LevelLow, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -enum GpioControlResponse { - ControllerRegistered { id: u32 }, - Controllers(Vec), - Controller(GpioControllerInfo), - PinValue(bool), - Ack, - Error(String), -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -enum PinOpKind { - Read, - Write, - Configure, -} - -enum Handle { - SchemeRoot, - Register { pending: Vec }, - Provider { controller_id: u32, pending: Vec }, - ControllersDir { pending: Vec }, - ControllerDetail { id: u32, pending: Vec }, - PinOp { kind: PinOpKind, pending: Vec }, -} - -struct ControllerEntry { - info: GpioControllerInfo, - provider_handle: usize, -} - -struct GpioDaemon { - handles: HandleMap, - controllers: BTreeMap, - next_id: u32, -} - -impl GpioDaemon { - fn new() -> Self { - Self { - handles: HandleMap::new(), - controllers: BTreeMap::new(), - next_id: 0, - } - } - - fn controller_list(&self) -> Vec { - self.controllers - .values() - .map(|entry| entry.info.clone()) - .collect() - } - - fn serialize_response(response: &GpioControlResponse) -> syscall::Result> { - ron::ser::to_string(response) - .map(|text| text.into_bytes()) - .map_err(|err| { - log::error!("gpiod: failed to serialize control response: {err}"); - SysError::new(EINVAL) - }) - } - - fn deserialize_request(buf: &[u8]) -> syscall::Result { - let text = std::str::from_utf8(buf).map_err(|err| { - log::warn!("gpiod: invalid UTF-8 request payload: {err}"); - SysError::new(EINVAL) - })?; - - ron::from_str(text).map_err(|err| { - log::warn!("gpiod: failed to decode control request: {err}"); - SysError::new(EINVAL) - }) - } - - fn set_pending_response(handle: &mut Handle, response: GpioControlResponse) -> syscall::Result<()> { - let pending = Self::serialize_response(&response)?; - Self::set_pending_bytes(handle, pending) - } - - fn set_pending_bytes(handle: &mut Handle, pending: Vec) -> syscall::Result<()> { - match handle { - Handle::Register { pending: slot } - | Handle::Provider { pending: slot, .. } - | Handle::ControllersDir { pending: slot } - | Handle::ControllerDetail { pending: slot, .. } - | Handle::PinOp { pending: slot, .. } => { - *slot = pending; - Ok(()) - } - Handle::SchemeRoot => Err(SysError::new(EBADF)), - } - } - - fn copy_pending(handle: &mut Handle, buf: &mut [u8], offset: u64) -> syscall::Result { - let pending = match handle { - Handle::Register { pending } - | Handle::Provider { pending, .. } - | Handle::ControllersDir { pending } - | Handle::ControllerDetail { pending, .. } - | Handle::PinOp { pending, .. } => pending, - Handle::SchemeRoot => return Err(SysError::new(EBADF)), - }; - - let offset = usize::try_from(offset).map_err(|_| SysError::new(EINVAL))?; - if offset >= pending.len() { - return Ok(0); - } - - let copy_len = buf.len().min(pending.len() - offset); - buf[..copy_len].copy_from_slice(&pending[offset..offset + copy_len]); - Ok(copy_len) - } - - fn validate_pin_target( - &self, - controller_id: u32, - pin: u32, - ) -> std::result::Result { - let entry = self - .controllers - .get(&controller_id) - .ok_or_else(|| format!("unknown controller {controller_id}"))?; - if usize::try_from(pin) - .ok() - .filter(|pin| *pin < entry.info.pin_count) - .is_none() - { - return Err(format!( - "pin {pin} is out of range for controller {} (pin_count={})", - entry.info.name, entry.info.pin_count - )); - } - Ok(entry.info.clone()) - } -} - -impl SchemeSync for GpioDaemon { - fn scheme_root(&mut self) -> syscall::Result { - Ok(self.handles.insert(Handle::SchemeRoot)) - } - - fn openat( - &mut self, - dirfd: usize, - path: &str, - _flags: usize, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> syscall::Result { - let handle = self.handles.get(dirfd)?; - let segments = path.trim_matches('/'); - - let new_handle = match handle { - Handle::SchemeRoot => { - if segments.is_empty() { - return Err(SysError::new(EINVAL)); - } - - let mut parts = segments.split('/'); - match parts.next() { - Some("register") if parts.next().is_none() => Handle::Register { - pending: Vec::new(), - }, - Some("controllers") => match parts.next() { - None => Handle::ControllersDir { - pending: Vec::new(), - }, - Some(id) if parts.next().is_none() => Handle::ControllerDetail { - id: id.parse::().map_err(|_| SysError::new(EINVAL))?, - pending: Vec::new(), - }, - _ => return Err(SysError::new(EINVAL)), - }, - Some("read_pin") if parts.next().is_none() => Handle::PinOp { - kind: PinOpKind::Read, - pending: Vec::new(), - }, - Some("write_pin") if parts.next().is_none() => Handle::PinOp { - kind: PinOpKind::Write, - pending: Vec::new(), - }, - Some("configure_pin") if parts.next().is_none() => Handle::PinOp { - kind: PinOpKind::Configure, - pending: Vec::new(), - }, - _ => return Err(SysError::new(ENOENT)), - } - } - Handle::ControllersDir { .. } => { - if segments.is_empty() { - return Err(SysError::new(EINVAL)); - } - - Handle::ControllerDetail { - id: segments.parse::().map_err(|_| SysError::new(EINVAL))?, - pending: Vec::new(), - } - } - _ => return Err(SysError::new(EACCES)), - }; - - let fd = self.handles.insert(new_handle); - Ok(OpenResult::ThisScheme { - number: fd, - flags: NewFdFlags::empty(), - }) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> syscall::Result { - let controllers = self.controller_list(); - let detail = match self.handles.get(id)? { - Handle::ControllerDetail { id, .. } => self.controllers.get(id).map(|entry| entry.info.clone()), - _ => None, - }; - - let handle = self.handles.get_mut(id)?; - match handle { - Handle::ControllersDir { pending } if pending.is_empty() => { - *pending = Self::serialize_response(&GpioControlResponse::Controllers(controllers))?; - } - Handle::ControllerDetail { id, pending } if pending.is_empty() => { - let info = detail.ok_or(SysError::new(ENOENT))?; - *pending = Self::serialize_response(&GpioControlResponse::Controller(info))?; - log::debug!("gpiod: served controller detail for id={id}"); - } - _ => {} - } - - Self::copy_pending(handle, buf, offset) - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> syscall::Result { - let request = Self::deserialize_request(buf)?; - - match request { - GpioControlRequest::RegisterController { mut info } => { - if !matches!(self.handles.get(id)?, Handle::Register { .. }) { - return Err(SysError::new(EINVAL)); - } - - let controller_id = self.next_id; - self.next_id = self.next_id.checked_add(1).ok_or(SysError::new(EINVAL))?; - info.id = controller_id; - self.controllers.insert( - controller_id, - ControllerEntry { - info: info.clone(), - provider_handle: id, - }, - ); - - let handle = self.handles.get_mut(id)?; - *handle = Handle::Provider { - controller_id, - pending: Self::serialize_response(&GpioControlResponse::ControllerRegistered { - id: controller_id, - })?, - }; - - log::info!( - "RB_GPIOD_CONTROLLER_REGISTERED id={} name={} pin_count={} supports_interrupt={}", - info.id, - info.name, - info.pin_count, - info.supports_interrupt, - ); - Ok(buf.len()) - } - GpioControlRequest::ListControllers => { - let controllers = self.controller_list(); - let handle = self.handles.get_mut(id)?; - Self::set_pending_response(handle, GpioControlResponse::Controllers(controllers))?; - Ok(buf.len()) - } - GpioControlRequest::ReadPin { controller_id, pin } => { - let validation = self.validate_pin_target(controller_id, pin); - let handle = self.handles.get_mut(id)?; - match handle { - Handle::PinOp { - kind: PinOpKind::Read, - .. - } => { - match validation { - Ok(info) => { - log::info!( - "RB_GPIOD_PIN_READ controller_id={} name={} pin={} routed=stub", - controller_id, - info.name, - pin, - ); - Self::set_pending_response(handle, GpioControlResponse::PinValue(false))?; - } - Err(message) => { - Self::set_pending_response(handle, GpioControlResponse::Error(message))?; - } - } - Ok(buf.len()) - } - _ => Err(SysError::new(EINVAL)), - } - } - GpioControlRequest::WritePin { - controller_id, - pin, - value, - } => { - let validation = self.validate_pin_target(controller_id, pin); - let handle = self.handles.get_mut(id)?; - match handle { - Handle::PinOp { - kind: PinOpKind::Write, - .. - } => { - match validation { - Ok(info) => { - log::info!( - "RB_GPIOD_PIN_WRITE controller_id={} name={} pin={} value={} routed=stub", - controller_id, - info.name, - pin, - value, - ); - Self::set_pending_response(handle, GpioControlResponse::Ack)?; - } - Err(message) => { - Self::set_pending_response(handle, GpioControlResponse::Error(message))?; - } - } - Ok(buf.len()) - } - _ => Err(SysError::new(EINVAL)), - } - } - GpioControlRequest::ConfigurePin { - controller_id, - pin, - config, - } => { - let validation = self.validate_pin_target(controller_id, pin); - let handle = self.handles.get_mut(id)?; - match handle { - Handle::PinOp { - kind: PinOpKind::Configure, - .. - } => { - match validation { - Ok(info) => { - log::info!( - "RB_GPIOD_PIN_CONFIG controller_id={} name={} pin={} direction={:?} pull={:?} interrupt={:?} routed=stub", - controller_id, - info.name, - pin, - config.direction, - config.pull, - config.interrupt_mode, - ); - Self::set_pending_response(handle, GpioControlResponse::Ack)?; - } - Err(message) => { - Self::set_pending_response(handle, GpioControlResponse::Error(message))?; - } - } - Ok(buf.len()) - } - _ => Err(SysError::new(EINVAL)), - } - } - } - } - - fn on_close(&mut self, id: usize) { - let Some(handle) = self.handles.remove(id) else { - return; - }; - if let Handle::Provider { controller_id, .. } = handle { - if let Some(entry) = self.controllers.remove(&controller_id) { - log::info!( - "RB_GPIOD_CONTROLLER_REMOVED id={} name={} provider_handle={}", - controller_id, - entry.info.name, - entry.provider_handle, - ); - } - } - } -} - -fn run_daemon(daemon: daemon::SchemeDaemon) -> Result<()> { - let socket = Socket::create().context("failed to create gpio scheme socket")?; - let mut scheme = GpioDaemon::new(); - let handler = Blocking::new(&socket, 16); - - daemon - .ready_sync_scheme(&socket, &mut scheme) - .context("failed to publish gpio scheme root")?; - - log::info!("RB_GPIOD_SCHEMA version=1"); - - libredox::call::setrens(0, 0).context("failed to enter null namespace")?; - - handler - .process_requests_blocking(scheme) - .context("failed to process gpiod requests")?; -} - -fn daemon_runner(daemon: daemon::SchemeDaemon) -> ! { - if let Err(err) = run_daemon(daemon) { - log::error!("gpiod: {err:#}"); - process::exit(1); - } - - process::exit(0); -} - -fn main() { - common::setup_logging( - "gpio", - "gpio", - "gpiod", - common::output_level(), - common::file_level(), - ); - - daemon::SchemeDaemon::new(daemon_runner); -} diff --git a/recipes/core/base/drivers/gpio/i2c-gpio-expanderd/Cargo.toml b/recipes/core/base/drivers/gpio/i2c-gpio-expanderd/Cargo.toml deleted file mode 100644 index 3e168e968f..0000000000 --- a/recipes/core/base/drivers/gpio/i2c-gpio-expanderd/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "i2c-gpio-expanderd" -description = "I2C GPIO expander bridge daemon" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow.workspace = true -log.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -libredox.workspace = true -serde.workspace = true -ron.workspace = true - -acpi-resource = { path = "../../acpi-resource" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -i2c-interface = { path = "../../i2c/i2c-interface" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/gpio/i2c-gpio-expanderd/src/main.rs b/recipes/core/base/drivers/gpio/i2c-gpio-expanderd/src/main.rs deleted file mode 100644 index d457d2df6d..0000000000 --- a/recipes/core/base/drivers/gpio/i2c-gpio-expanderd/src/main.rs +++ /dev/null @@ -1,454 +0,0 @@ -use std::collections::BTreeMap; -use std::fs::{self, File, OpenOptions}; -use std::io::{Read, Write}; -use std::path::Path; -use std::process; - -use acpi_resource::{GpioDescriptor, I2cSerialBusDescriptor, ResourceDescriptor}; -use anyhow::{Context, Result}; -use i2c_interface::{ - I2cAdapterInfo, I2cControlRequest, I2cControlResponse, I2cTransferRequest, - I2cTransferResponse, I2cTransferSegment, -}; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Deserialize)] -struct AmlSymbol { - name: String, - value: AmlValue, -} - -#[derive(Debug, Deserialize)] -enum AmlValue { - Integer(u64), - String(String), -} - -#[derive(Clone, Debug)] -struct ExpanderResources { - i2c: I2cSerialBusDescriptor, - pin_count: usize, - gpio_int_count: usize, - gpio_io_count: usize, -} - -#[derive(Debug)] -struct ExpanderDescriptor { - device: String, - hid: String, - resources: ExpanderResources, -} - -struct RegisteredExpander { - _registration: File, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -struct GpioControllerInfo { - id: u32, - name: String, - pin_count: usize, - supports_interrupt: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -enum GpioControlRequest { - RegisterController { info: GpioControllerInfo }, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -enum GpioControlResponse { - ControllerRegistered { id: u32 }, - Error(String), -} - -fn main() { - common::setup_logging( - "gpio", - "i2c-gpio-expander", - "i2c-gpio-expanderd", - common::output_level(), - common::file_level(), - ); - - daemon::Daemon::new(daemon_runner); -} - -fn daemon_runner(daemon: daemon::Daemon) -> ! { - if let Err(err) = daemon_main(daemon) { - log::error!("i2c-gpio-expanderd: {err:#}"); - process::exit(1); - } - - process::exit(0); -} - -fn daemon_main(daemon: daemon::Daemon) -> Result<()> { - let expanders = discover_expanders().context("failed to discover ACPI I2C GPIO expanders")?; - if expanders.is_empty() { - log::info!("i2c-gpio-expanderd: no probable ACPI I2C GPIO expanders found"); - } - - let adapters = list_i2c_adapters().unwrap_or_else(|err| { - log::warn!("i2c-gpio-expanderd: unable to query i2cd adapters: {err:#}"); - Vec::new() - }); - - let mut registered = Vec::new(); - for expander in expanders { - match register_expander(expander, &adapters) { - Ok(expander) => registered.push(expander), - Err(err) => log::warn!("i2c-gpio-expanderd: expander registration skipped: {err:#}"), - } - } - - daemon.ready(); - libredox::call::setrens(0, 0).context("failed to enter null namespace")?; - - log::info!("i2c-gpio-expanderd: registered {} expander(s)", registered.len()); - - loop { - std::thread::park(); - } -} - -fn discover_expanders() -> Result> { - let mut matched = BTreeMap::new(); - - let entries = match fs::read_dir("/scheme/acpi/symbols") { - Ok(entries) => entries, - Err(err) if err.kind() == std::io::ErrorKind::WouldBlock || err.raw_os_error() == Some(11) => { - log::debug!("i2c-gpio-expanderd: ACPI symbols are not ready yet"); - return Ok(Vec::new()); - } - Err(err) => return Err(err).context("failed to read /scheme/acpi/symbols"), - }; - - for entry in entries { - let entry = entry.context("failed to read ACPI symbol directory entry")?; - let Some(file_name) = entry.file_name().to_str().map(str::to_owned) else { - continue; - }; - if !file_name.ends_with("_HID") && !file_name.ends_with("_CID") { - continue; - } - - let Some(id) = read_symbol_id(&entry.path())? else { - continue; - }; - if is_excluded_device_id(&id) { - continue; - } - - let Some(device) = file_name - .strip_suffix("_HID") - .or_else(|| file_name.strip_suffix("_CID")) - .map(str::to_owned) - else { - continue; - }; - - let resources = match read_expander_resources(&device) { - Ok(resources) => resources, - Err(err) => { - log::debug!("i2c-gpio-expanderd: skipping {device}: {err:#}"); - continue; - } - }; - if resources.gpio_int_count == 0 && resources.gpio_io_count == 0 { - continue; - } - - matched.entry(device).or_insert((id, resources)); - } - - let mut expanders = Vec::new(); - for (device, (hid, resources)) in matched { - expanders.push(ExpanderDescriptor { - device, - hid, - resources, - }); - } - Ok(expanders) -} - -fn read_symbol_id(path: &Path) -> Result> { - let contents = fs::read_to_string(path) - .with_context(|| format!("failed to read ACPI symbol {}", path.display()))?; - let symbol = match ron::from_str::(&contents) { - Ok(symbol) => symbol, - Err(err) => { - log::debug!( - "i2c-gpio-expanderd: skipping {} because the symbol payload was not a scalar ID: {err}", - path.display(), - ); - return Ok(None); - } - }; - - let id = match symbol.value { - AmlValue::Integer(integer) => eisa_id_from_integer(integer), - AmlValue::String(string) => string, - }; - - log::debug!("i2c-gpio-expanderd: {} -> {id}", symbol.name); - Ok(Some(id)) -} - -fn read_expander_resources(device: &str) -> Result { - let contents = fs::read_to_string(format!("/scheme/acpi/resources/{device}")) - .with_context(|| format!("failed to read /scheme/acpi/resources/{device}"))?; - let resources = ron::from_str::>(&contents) - .with_context(|| format!("failed to decode RON resources for {device}"))?; - - let mut i2c = None; - let mut pin_count = 0usize; - let mut gpio_int_count = 0usize; - let mut gpio_io_count = 0usize; - - for resource in resources { - match resource { - ResourceDescriptor::I2cSerialBus(bus) if i2c.is_none() => i2c = Some(bus), - ResourceDescriptor::GpioInt(descriptor) => { - gpio_int_count += 1; - pin_count = pin_count.max(pin_count_from_descriptor(&descriptor)); - } - ResourceDescriptor::GpioIo(descriptor) => { - gpio_io_count += 1; - pin_count = pin_count.max(pin_count_from_descriptor(&descriptor)); - } - _ => {} - } - } - - Ok(ExpanderResources { - i2c: i2c.context("no I2cSerialBus resource was found")?, - pin_count, - gpio_int_count, - gpio_io_count, - }) -} - -fn pin_count_from_descriptor(descriptor: &GpioDescriptor) -> usize { - descriptor - .pins - .iter() - .copied() - .max() - .map(|pin| usize::from(pin).saturating_add(1)) - .unwrap_or(0) -} - -fn is_excluded_device_id(id: &str) -> bool { - matches!( - id, - "PNP0C50" - | "ACPI0C50" - | "INT34C5" - | "INTC1055" - | "INT33C2" - | "INT33C3" - | "INT3432" - | "INT3433" - | "INTC10EF" - | "AMDI0010" - | "AMDI0019" - | "AMDI0510" - | "PNP0CA0" - | "AMDI0042" - ) || id.starts_with("ELAN") - || id.starts_with("CYAP") - || id.starts_with("SYNA") -} - -fn register_expander(expander: ExpanderDescriptor, adapters: &[I2cAdapterInfo]) -> Result { - let ExpanderDescriptor { - device, - hid, - resources, - } = expander; - - let adapter_name = resources - .i2c - .resource_source - .as_ref() - .map(|source| source.source.clone()) - .filter(|source| !source.is_empty()) - .unwrap_or_else(|| String::from("ACPI-I2C")); - let adapter = match match_i2c_adapter(adapters, &adapter_name) { - Some(adapter) => Some(adapter.clone()), - None => { - log::warn!( - "i2c-gpio-expanderd: unable to resolve I2C adapter {} for {}", - adapter_name, - device, - ); - None - } - }; - - if let Some(adapter) = adapter.as_ref() { - if let Err(err) = probe_expander(adapter, &adapter_name, resources.i2c.slave_address) { - log::warn!( - "i2c-gpio-expanderd: expander {} probe on {}@{:04x} failed: {err:#}", - device, - adapter_name, - resources.i2c.slave_address, - ); - } - } - - let info = GpioControllerInfo { - id: 0, - name: format!("i2c-gpio-expander:{device}"), - pin_count: resources.pin_count, - supports_interrupt: resources.gpio_int_count > 0, - }; - let mut registration = register_with_gpiod(&info) - .with_context(|| format!("failed to register {device} with gpiod"))?; - let response = read_gpio_registration_response(&mut registration) - .with_context(|| format!("failed to read gpiod registration response for {device}"))?; - - match response { - GpioControlResponse::ControllerRegistered { id } => { - log::info!( - "RB_I2C_GPIO_EXPANDERD_DEVICE device={} hid={} controller_id={} adapter={} addr={:04x} pin_count={} gpio_int={} gpio_io={}", - device, - hid, - id, - adapter_name, - resources.i2c.slave_address, - info.pin_count, - resources.gpio_int_count, - resources.gpio_io_count, - ); - } - GpioControlResponse::Error(message) => { - anyhow::bail!("gpiod rejected expander {device}: {message}"); - } - } - - Ok(RegisteredExpander { - _registration: registration, - }) -} - -fn list_i2c_adapters() -> Result> { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .open("/scheme/i2c/adapters") - .context("failed to open /scheme/i2c/adapters")?; - - let payload = ron::ser::to_string(&I2cControlRequest::ListAdapters) - .context("failed to encode I2C list-adapters request")?; - file.write_all(payload.as_bytes()) - .context("failed to request I2C adapter list")?; - - let response = read_i2c_control_response(&mut file)?; - match response { - I2cControlResponse::AdapterList(adapters) => Ok(adapters), - I2cControlResponse::Error(message) => anyhow::bail!("i2cd returned an error: {message}"), - other => anyhow::bail!("unexpected i2cd list-adapters response: {other:?}"), - } -} - -fn match_i2c_adapter<'a>(adapters: &'a [I2cAdapterInfo], wanted: &str) -> Option<&'a I2cAdapterInfo> { - adapters - .iter() - .find(|adapter| adapter.name == wanted) - .or_else(|| adapters.iter().find(|adapter| adapter.name.ends_with(wanted))) - .or_else(|| adapters.iter().find(|adapter| wanted.ends_with(&adapter.name))) -} - -fn probe_expander(adapter: &I2cAdapterInfo, adapter_name: &str, address: u16) -> Result { - let request = I2cTransferRequest { - adapter: adapter_name.to_string(), - segments: vec![I2cTransferSegment::read(address, 1)], - stop: true, - }; - - let mut file = OpenOptions::new() - .read(true) - .write(true) - .open("/scheme/i2c/transfer") - .context("failed to open /scheme/i2c/transfer")?; - let payload = ron::ser::to_string(&I2cControlRequest::Transfer { - adapter_id: adapter.id, - request, - }) - .context("failed to encode I2C expander probe request")?; - file.write_all(payload.as_bytes()) - .context("failed to send I2C expander probe request")?; - - let response = read_i2c_control_response(&mut file)?; - match response { - I2cControlResponse::TransferResult(result) => { - if !result.ok { - let detail = result - .error - .clone() - .unwrap_or_else(|| String::from("unknown I2C transfer failure")); - anyhow::bail!("I2C probe failed: {detail}"); - } - Ok(result) - } - I2cControlResponse::Error(message) => anyhow::bail!("i2cd returned an error: {message}"), - other => anyhow::bail!("unexpected I2C transfer response: {other:?}"), - } -} - -fn register_with_gpiod(info: &GpioControllerInfo) -> Result { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .open("/scheme/gpio/register") - .context("failed to open /scheme/gpio/register")?; - let payload = ron::ser::to_string(&GpioControlRequest::RegisterController { info: info.clone() }) - .context("failed to encode GPIO controller registration")?; - file.write_all(payload.as_bytes()) - .context("failed to send GPIO controller registration")?; - Ok(file) -} - -fn read_gpio_registration_response(file: &mut File) -> Result { - let mut buffer = vec![0_u8; 4096]; - let count = file - .read(&mut buffer) - .context("failed to read GPIO registration response")?; - buffer.truncate(count); - let text = std::str::from_utf8(&buffer).context("GPIO registration response was not UTF-8")?; - ron::from_str(text).context("failed to decode GPIO registration response") -} - -fn read_i2c_control_response(file: &mut File) -> Result { - let mut buffer = vec![0_u8; 4096]; - let count = file - .read(&mut buffer) - .context("failed to read I2C control response")?; - buffer.truncate(count); - let text = std::str::from_utf8(&buffer).context("I2C control response was not UTF-8")?; - let trimmed = text.trim(); - if trimmed.is_empty() { - return Ok(I2cControlResponse::AdapterList(Vec::new())); - } - ron::from_str(trimmed).context("failed to decode I2C control response") -} - -fn eisa_id_from_integer(integer: u64) -> String { - let vendor = integer & 0xFFFF; - let device = (integer >> 16) & 0xFFFF; - let vendor_rev = ((vendor & 0xFF) << 8) | (vendor >> 8); - let vendor_1 = (((vendor_rev >> 10) & 0x1F) as u8 + 64) as char; - let vendor_2 = (((vendor_rev >> 5) & 0x1F) as u8 + 64) as char; - let vendor_3 = (((vendor_rev >> 0) & 0x1F) as u8 + 64) as char; - let device_1 = (device >> 4) & 0xF; - let device_2 = (device >> 0) & 0xF; - let device_3 = (device >> 12) & 0xF; - let device_4 = (device >> 8) & 0xF; - - format!( - "{vendor_1}{vendor_2}{vendor_3}{device_1:01X}{device_2:01X}{device_3:01X}{device_4:01X}" - ) -} diff --git a/recipes/core/base/drivers/gpio/intel-gpiod/Cargo.toml b/recipes/core/base/drivers/gpio/intel-gpiod/Cargo.toml deleted file mode 100644 index f5ac93554a..0000000000 --- a/recipes/core/base/drivers/gpio/intel-gpiod/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "intel-gpiod" -description = "Intel ACPI GPIO registrar daemon" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow.workspace = true -log.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -libredox.workspace = true -serde.workspace = true -ron.workspace = true - -acpi-resource = { path = "../../acpi-resource" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/gpio/intel-gpiod/src/main.rs b/recipes/core/base/drivers/gpio/intel-gpiod/src/main.rs deleted file mode 100644 index 78e6099076..0000000000 --- a/recipes/core/base/drivers/gpio/intel-gpiod/src/main.rs +++ /dev/null @@ -1,401 +0,0 @@ -use std::collections::BTreeMap; -use std::fs::{self, File, OpenOptions}; -use std::io::{Read, Write}; -use std::path::Path; -use std::process; - -use acpi_resource::{ - AddressResourceType, ExtendedIrqDescriptor, FixedMemory32Descriptor, GpioDescriptor, - IrqDescriptor, Memory32RangeDescriptor, ResourceDescriptor, -}; -use anyhow::{Context, Result}; -use common::{MemoryType, PhysBorrowed, Prot}; -use serde::{Deserialize, Serialize}; - -const SUPPORTED_IDS: &[&str] = &["INT34C5", "INTC1055"]; - -const PADNFGPIO_OWN_BASE: usize = 0x20; -const PADNFGPIO_PADCFG_BASE: usize = 0x700; -const GPI_INT_STATUS: usize = 0x100; -const GPI_INT_EN: usize = 0x120; -const INTEL_GPIO_MMIO_WINDOW: usize = PADNFGPIO_PADCFG_BASE + core::mem::size_of::(); - -#[derive(Debug, Deserialize)] -struct AmlSymbol { - name: String, - value: AmlValue, -} - -#[derive(Debug, Deserialize)] -enum AmlValue { - Integer(u64), - String(String), -} - -#[derive(Clone, Debug)] -struct ControllerResources { - mmio_base: usize, - mmio_len: usize, - pin_count: usize, - supports_interrupt: bool, - gpio_int_count: usize, - gpio_io_count: usize, -} - -#[derive(Debug)] -struct ControllerDescriptor { - device: String, - hid: String, - resources: ControllerResources, -} - -struct RegisteredController { - _mmio: Option, - _registration: File, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -struct GpioControllerInfo { - id: u32, - name: String, - pin_count: usize, - supports_interrupt: bool, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -enum GpioControlRequest { - RegisterController { info: GpioControllerInfo }, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -enum GpioControlResponse { - ControllerRegistered { id: u32 }, - Error(String), -} - -fn main() { - common::setup_logging( - "gpio", - "intel-gpio", - "intel-gpiod", - common::output_level(), - common::file_level(), - ); - - daemon::Daemon::new(daemon_runner); -} - -fn daemon_runner(daemon: daemon::Daemon) -> ! { - if let Err(err) = daemon_main(daemon) { - log::error!("intel-gpiod: {err:#}"); - process::exit(1); - } - - process::exit(0); -} - -fn daemon_main(daemon: daemon::Daemon) -> Result<()> { - common::init(); - - let controllers = - discover_controllers(SUPPORTED_IDS).context("failed to discover Intel GPIO controllers")?; - if controllers.is_empty() { - log::info!("intel-gpiod: no supported Intel GPIO ACPI controllers found"); - } - - let mut registered = Vec::new(); - for controller in controllers { - match register_controller(controller) { - Ok(controller) => registered.push(controller), - Err(err) => log::warn!("intel-gpiod: controller registration skipped: {err:#}"), - } - } - - daemon.ready(); - libredox::call::setrens(0, 0).context("failed to enter null namespace")?; - - log::info!("intel-gpiod: registered {} controller(s)", registered.len()); - - loop { - std::thread::park(); - } -} - -fn discover_controllers(supported_ids: &[&str]) -> Result> { - let mut matched = BTreeMap::new(); - - let entries = match fs::read_dir("/scheme/acpi/symbols") { - Ok(entries) => entries, - Err(err) if err.kind() == std::io::ErrorKind::WouldBlock || err.raw_os_error() == Some(11) => { - log::debug!("intel-gpiod: ACPI symbols are not ready yet"); - return Ok(Vec::new()); - } - Err(err) => return Err(err).context("failed to read /scheme/acpi/symbols"), - }; - - for entry in entries { - let entry = entry.context("failed to read ACPI symbol directory entry")?; - let Some(file_name) = entry.file_name().to_str().map(str::to_owned) else { - continue; - }; - if !file_name.ends_with("_HID") && !file_name.ends_with("_CID") { - continue; - } - - let Some(id) = read_symbol_id(&entry.path())? else { - continue; - }; - if !supported_ids.iter().any(|candidate| *candidate == id) { - continue; - } - - let device = file_name - .strip_suffix("_HID") - .or_else(|| file_name.strip_suffix("_CID")) - .map(str::to_owned); - if let Some(device) = device { - matched.entry(device).or_insert(id); - } - } - - let mut controllers = Vec::new(); - for (device, hid) in matched { - let resources = read_controller_resources(&device) - .with_context(|| format!("failed to read resources for {device}"))?; - controllers.push(ControllerDescriptor { - device, - hid, - resources, - }); - } - - Ok(controllers) -} - -fn read_symbol_id(path: &Path) -> Result> { - let contents = fs::read_to_string(path) - .with_context(|| format!("failed to read ACPI symbol {}", path.display()))?; - let symbol = match ron::from_str::(&contents) { - Ok(symbol) => symbol, - Err(err) => { - log::debug!( - "intel-gpiod: skipping {} because the symbol payload was not a scalar ID: {err}", - path.display(), - ); - return Ok(None); - } - }; - - let id = match symbol.value { - AmlValue::Integer(integer) => eisa_id_from_integer(integer), - AmlValue::String(string) => string, - }; - - log::debug!("intel-gpiod: {} -> {id}", symbol.name); - Ok(Some(id)) -} - -fn read_controller_resources(device: &str) -> Result { - let contents = fs::read_to_string(format!("/scheme/acpi/resources/{device}")) - .with_context(|| format!("failed to read /scheme/acpi/resources/{device}"))?; - let resources = ron::from_str::>(&contents) - .with_context(|| format!("failed to decode RON resources for {device}"))?; - - let mut mmio = None; - let mut supports_interrupt = false; - let mut gpio_int_count = 0usize; - let mut gpio_io_count = 0usize; - let mut pin_count = 0usize; - - for resource in &resources { - match resource { - ResourceDescriptor::FixedMemory32(FixedMemory32Descriptor { - address, - address_length, - .. - }) if mmio.is_none() => { - mmio = Some(( - *address as usize, - (*address_length as usize).max(INTEL_GPIO_MMIO_WINDOW), - )); - } - ResourceDescriptor::Memory32Range(Memory32RangeDescriptor { - minimum, - maximum, - address_length, - .. - }) if mmio.is_none() && maximum >= minimum => { - let span = maximum.saturating_sub(*minimum).saturating_add(1) as usize; - mmio = Some(( - *minimum as usize, - span.max((*address_length as usize).max(INTEL_GPIO_MMIO_WINDOW)), - )); - } - ResourceDescriptor::Address32(descriptor) - if mmio.is_none() - && matches!(descriptor.resource_type, AddressResourceType::MemoryRange) => - { - mmio = Some(( - descriptor.minimum as usize, - (descriptor.address_length as usize).max(INTEL_GPIO_MMIO_WINDOW), - )); - } - ResourceDescriptor::Address64(descriptor) - if mmio.is_none() - && matches!(descriptor.resource_type, AddressResourceType::MemoryRange) => - { - let base = usize::try_from(descriptor.minimum) - .context("64-bit MMIO base does not fit in usize")?; - let len = usize::try_from(descriptor.address_length) - .context("64-bit MMIO length does not fit in usize")?; - mmio = Some((base, len.max(INTEL_GPIO_MMIO_WINDOW))); - } - ResourceDescriptor::Irq(IrqDescriptor { interrupts, .. }) => { - supports_interrupt |= !interrupts.is_empty(); - } - ResourceDescriptor::ExtendedIrq(ExtendedIrqDescriptor { interrupts, .. }) => { - supports_interrupt |= !interrupts.is_empty(); - } - ResourceDescriptor::GpioInt(descriptor) => { - gpio_int_count += 1; - supports_interrupt = true; - pin_count = pin_count.max(pin_count_from_descriptor(descriptor)); - } - ResourceDescriptor::GpioIo(descriptor) => { - gpio_io_count += 1; - pin_count = pin_count.max(pin_count_from_descriptor(descriptor)); - } - _ => {} - } - } - - let (mmio_base, mmio_len) = mmio.context("no MMIO resource was found")?; - Ok(ControllerResources { - mmio_base, - mmio_len, - pin_count, - supports_interrupt, - gpio_int_count, - gpio_io_count, - }) -} - -fn pin_count_from_descriptor(descriptor: &GpioDescriptor) -> usize { - descriptor - .pins - .iter() - .copied() - .max() - .map(|pin| usize::from(pin).saturating_add(1)) - .unwrap_or(0) -} - -fn register_controller(controller: ControllerDescriptor) -> Result { - let ControllerDescriptor { - device, - hid, - resources, - } = controller; - - let mmio = match PhysBorrowed::map( - resources.mmio_base, - resources.mmio_len, - Prot::RW, - MemoryType::Uncacheable, - ) { - Ok(mapping) => Some(mapping), - Err(err) => { - log::warn!( - "intel-gpiod: failed to map MMIO for {device} ({:#x}, len {:#x}): {err}", - resources.mmio_base, - resources.mmio_len, - ); - None - } - }; - - log::info!( - "intel-gpiod: discovered {device} hid={hid} mmio={:#x}+{:#x} pin_count={} gpio_int={} gpio_io={} supports_interrupt={}", - resources.mmio_base, - resources.mmio_len, - resources.pin_count, - resources.gpio_int_count, - resources.gpio_io_count, - resources.supports_interrupt, - ); - log::debug!( - "intel-gpiod: register model own={PADNFGPIO_OWN_BASE:#x} padcfg={PADNFGPIO_PADCFG_BASE:#x} gpi_int_status={GPI_INT_STATUS:#x} gpi_int_en={GPI_INT_EN:#x}", - ); - - let info = GpioControllerInfo { - id: 0, - name: format!("intel-gpio:{device}"), - pin_count: resources.pin_count, - supports_interrupt: resources.supports_interrupt, - }; - let mut registration = register_with_gpiod(&info) - .with_context(|| format!("failed to register {device} with gpiod"))?; - let response = read_registration_response(&mut registration) - .with_context(|| format!("failed to read gpiod registration response for {device}"))?; - - match response { - GpioControlResponse::ControllerRegistered { id } => { - log::info!( - "RB_INTEL_GPIOD_DEVICE device={} hid={} controller_id={} pin_count={} supports_interrupt={}", - device, - hid, - id, - info.pin_count, - info.supports_interrupt, - ); - } - GpioControlResponse::Error(message) => { - anyhow::bail!("gpiod rejected Intel GPIO controller {device}: {message}"); - } - } - - Ok(RegisteredController { - _mmio: mmio, - _registration: registration, - }) -} - -fn register_with_gpiod(info: &GpioControllerInfo) -> Result { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .open("/scheme/gpio/register") - .context("failed to open /scheme/gpio/register")?; - let payload = ron::ser::to_string(&GpioControlRequest::RegisterController { info: info.clone() }) - .context("failed to encode GPIO controller registration")?; - file.write_all(payload.as_bytes()) - .context("failed to send GPIO controller registration")?; - Ok(file) -} - -fn read_registration_response(file: &mut File) -> Result { - let mut buffer = vec![0_u8; 4096]; - let count = file - .read(&mut buffer) - .context("failed to read GPIO registration response")?; - buffer.truncate(count); - let text = std::str::from_utf8(&buffer).context("GPIO registration response was not UTF-8")?; - ron::from_str(text).context("failed to decode GPIO registration response") -} - -fn eisa_id_from_integer(integer: u64) -> String { - let vendor = integer & 0xFFFF; - let device = (integer >> 16) & 0xFFFF; - let vendor_rev = ((vendor & 0xFF) << 8) | (vendor >> 8); - let vendor_1 = (((vendor_rev >> 10) & 0x1F) as u8 + 64) as char; - let vendor_2 = (((vendor_rev >> 5) & 0x1F) as u8 + 64) as char; - let vendor_3 = (((vendor_rev >> 0) & 0x1F) as u8 + 64) as char; - let device_1 = (device >> 4) & 0xF; - let device_2 = (device >> 0) & 0xF; - let device_3 = (device >> 12) & 0xF; - let device_4 = (device >> 8) & 0xF; - - format!( - "{vendor_1}{vendor_2}{vendor_3}{device_1:01X}{device_2:01X}{device_3:01X}{device_4:01X}" - ) -} diff --git a/recipes/core/base/drivers/graphics/console-draw/Cargo.toml b/recipes/core/base/drivers/graphics/console-draw/Cargo.toml deleted file mode 100644 index c92a7b9f42..0000000000 --- a/recipes/core/base/drivers/graphics/console-draw/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "console-draw" -description = "Shared terminal drawing code library" -version = "0.1.0" -edition = "2021" - -[dependencies] -drm.workspace = true -orbclient.workspace = true -ransid.workspace = true - -graphics-ipc = { path = "../graphics-ipc" } - -[features] -default = [] - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/graphics/console-draw/src/lib.rs b/recipes/core/base/drivers/graphics/console-draw/src/lib.rs deleted file mode 100644 index 5eb951df54..0000000000 --- a/recipes/core/base/drivers/graphics/console-draw/src/lib.rs +++ /dev/null @@ -1,460 +0,0 @@ -extern crate ransid; - -use std::collections::VecDeque; -use std::convert::{TryFrom, TryInto}; -use std::{cmp, io, mem, ptr}; - -use drm::buffer::{Buffer, DrmFourcc}; -use drm::control::{connector, crtc, framebuffer, ClipRect, Device, Mode}; -use graphics_ipc::{CpuBackedBuffer, V2GraphicsHandle}; -use orbclient::FONT; - -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct Damage { - pub x: u32, - pub y: u32, - pub width: u32, - pub height: u32, -} - -impl Damage { - pub const NONE: Self = Damage { - x: 0, - y: 0, - width: 0, - height: 0, - }; - - pub fn merge(self, other: Self) -> Self { - if self.width == 0 || self.height == 0 { - return other; - } - - if other.width == 0 || other.height == 0 { - return self; - } - - let x = cmp::min(self.x, other.x); - let y = cmp::min(self.y, other.y); - let x2 = cmp::max(self.x + self.width, other.x + other.width); - let y2 = cmp::max(self.y + self.height, other.y + other.height); - - Damage { - x, - y, - width: x2 - x, - height: y2 - y, - } - } -} - -pub struct V2DisplayMap { - pub display_handle: V2GraphicsHandle, - connector: connector::Handle, - crtc: crtc::Handle, - fb: framebuffer::Handle, - pub buffer: CpuBackedBuffer, -} - -impl V2DisplayMap { - pub fn new(display_handle: V2GraphicsHandle) -> io::Result { - let connector = display_handle.first_display().unwrap(); - let connector_info = display_handle.get_connector(connector, true).unwrap(); - - let mode = connector_info.modes()[0]; - let (width, height) = mode.size(); - - // FIXME do something smarter that avoids conflicts - let crtc = display_handle.resource_handles().unwrap().filter_crtcs( - display_handle - .get_encoder(connector_info.encoders()[0]) - .unwrap() - .possible_crtcs(), - )[0]; - - let buffer = CpuBackedBuffer::new( - &display_handle, - (width.into(), height.into()), - DrmFourcc::Argb8888, - 32, - )?; - let fb = display_handle.add_framebuffer(buffer.buffer(), 32, 32)?; - - display_handle.set_crtc(crtc, Some(fb), (0, 0), &[connector], Some(mode))?; - - Ok(Self { - display_handle, - connector, - crtc, - fb, - buffer, - }) - } - - unsafe fn console_map(&mut self) -> DisplayMap { - let size = self.buffer.buffer().size(); - let shadow_buf = self.buffer.shadow_buf(); - - DisplayMap { - offscreen: ptr::slice_from_raw_parts_mut( - shadow_buf.as_mut_ptr() as *mut u32, - shadow_buf.len() / 4, - ), - width: size.0 as usize, - height: size.1 as usize, - } - } - - pub fn dirty_fb(&mut self, damage: Damage) -> io::Result<()> { - self.buffer - .sync_rect(damage.x, damage.y, damage.width, damage.height); - - self.display_handle.dirty_framebuffer( - self.fb, - &[ClipRect::new( - damage.x as u16, - damage.y as u16, - (damage.x + damage.width) as u16, - (damage.y + damage.height) as u16, - )], - ) - } -} - -struct DisplayMap { - offscreen: *mut [u32], - width: usize, - height: usize, -} - -pub struct TextScreen { - console: ransid::Console, -} - -impl TextScreen { - pub fn new() -> TextScreen { - TextScreen { - // Width and height will be filled in on the next write to the console - console: ransid::Console::new(0, 0), - } - } - - /// Draw a rectangle - fn rect(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize, color: u32) { - let start_y = cmp::min(map.height, y); - let end_y = cmp::min(map.height, y + h); - - let start_x = cmp::min(map.width, x); - let len = cmp::min(map.width, x + w) - start_x; - - let mut offscreen_ptr = map.offscreen as *mut u8 as usize; - - let stride = map.width * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - - let mut rows = end_y - start_y; - while rows > 0 { - for i in 0..len { - unsafe { - *(offscreen_ptr as *mut u32).add(i) = color; - } - } - offscreen_ptr += stride; - rows -= 1; - } - } - - /// Invert a rectangle - fn invert(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize) { - let start_y = cmp::min(map.height, y); - let end_y = cmp::min(map.height, y + h); - - let start_x = cmp::min(map.width, x); - let len = cmp::min(map.width, x + w) - start_x; - - let mut offscreen_ptr = map.offscreen as *mut u8 as usize; - - let stride = map.width * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - - let mut rows = end_y - start_y; - while rows > 0 { - let mut row_ptr = offscreen_ptr; - let mut cols = len; - while cols > 0 { - unsafe { - let color = *(row_ptr as *mut u32); - *(row_ptr as *mut u32) = !color; - } - row_ptr += 4; - cols -= 1; - } - offscreen_ptr += stride; - rows -= 1; - } - } - - /// Draw a character - fn char( - map: &mut DisplayMap, - x: usize, - y: usize, - character: char, - color: u32, - _bold: bool, - _italic: bool, - ) { - if x + 8 <= map.width && y + 16 <= map.height { - let mut dst = map.offscreen as *mut u8 as usize + (y * map.width + x) * 4; - - let font_i = 16 * (character as usize); - if font_i + 16 <= FONT.len() { - for row in 0..16 { - let row_data = FONT[font_i + row]; - for col in 0..8 { - if (row_data >> (7 - col)) & 1 == 1 { - unsafe { - *((dst + col * 4) as *mut u32) = color; - } - } - } - dst += map.width * 4; - } - } - } - } -} - -impl TextScreen { - pub fn write( - &mut self, - map: &mut V2DisplayMap, - buf: &[u8], - input: &mut VecDeque, - ) -> Damage { - let map = unsafe { &mut map.console_map() }; - - let mut min_changed = map.height; - let mut max_changed = 0; - let mut line_changed = |line| { - if line < min_changed { - min_changed = line; - } - if line > max_changed { - max_changed = line; - } - }; - - self.console.resize(map.width / 8, map.height / 16); - if self.console.state.x >= self.console.state.w { - self.console.state.x = self.console.state.w - 1; - } - if self.console.state.y >= self.console.state.h { - self.console.state.y = self.console.state.h - 1; - } - - if self.console.state.cursor - && self.console.state.x < self.console.state.w - && self.console.state.y < self.console.state.h - { - let x = self.console.state.x; - let y = self.console.state.y; - Self::invert(map, x * 8, y * 16, 8, 16); - line_changed(y); - } - - self.console.write(buf, |event| match event { - ransid::Event::Char { - x, - y, - c, - color, - bold, - .. - } => { - Self::char(map, x * 8, y * 16, c, color.as_rgb(), bold, false); - line_changed(y); - } - ransid::Event::Input { data } => input.extend(data), - ransid::Event::Rect { x, y, w, h, color } => { - Self::rect(map, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); - for y2 in y..y + h { - line_changed(y2); - } - } - ransid::Event::ScreenBuffer { .. } => (), - ransid::Event::Move { - from_x, - from_y, - to_x, - to_y, - w, - h, - } => { - let width = map.width; - let pixels = unsafe { &mut *map.offscreen }; - - for raw_y in 0..h { - let y = if from_y > to_y { raw_y } else { h - raw_y - 1 }; - - for pixel_y in 0..16 { - { - let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8; - let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8; - let len = w * 8; - - if off_from + len <= pixels.len() && off_to + len <= pixels.len() { - unsafe { - let data_ptr = pixels.as_mut_ptr() as *mut u32; - ptr::copy( - data_ptr.offset(off_from as isize), - data_ptr.offset(off_to as isize), - len, - ); - } - } - } - } - - line_changed(to_y + y); - } - } - ransid::Event::Resize { .. } => (), - ransid::Event::Title { .. } => (), - }); - - if self.console.state.cursor - && self.console.state.x < self.console.state.w - && self.console.state.y < self.console.state.h - { - let x = self.console.state.x; - let y = self.console.state.y; - Self::invert(map, x * 8, y * 16, 8, 16); - line_changed(y); - } - - let width = map.width.try_into().unwrap(); - let damage = Damage { - x: 0, - y: u32::try_from(min_changed).unwrap() * 16, - width, - height: u32::try_from(max_changed.saturating_sub(min_changed) + 1).unwrap() * 16, - }; - - damage - } - - pub fn resize(&mut self, map: &mut V2DisplayMap, mode: Mode) -> io::Result<()> { - // FIXME fold row when target is narrower and maybe unfold when it is wider - fn copy_row( - old_map: &mut DisplayMap, - new_map: &mut DisplayMap, - from_row: usize, - to_row: usize, - ) { - for x in 0..cmp::min(old_map.width, new_map.width) { - let old_idx = from_row * old_map.width + x; - let new_idx = to_row * new_map.width + x; - unsafe { - (*new_map.offscreen)[new_idx] = (*old_map.offscreen)[old_idx]; - } - } - } - - let mut new_buffer = CpuBackedBuffer::new( - &map.display_handle, - (u32::from(mode.size().0), u32::from(mode.size().1)), - DrmFourcc::Argb8888, - 32, - )?; - let new_fb = map - .display_handle - .add_framebuffer(new_buffer.buffer(), 24, 32)?; - - new_buffer.shadow_buf().fill(0); - - { - let old_map = unsafe { &mut map.console_map() }; - - let new_size = new_buffer.buffer().size(); - let new_shadow_buf = new_buffer.shadow_buf(); - let new_map = &mut DisplayMap { - offscreen: ptr::slice_from_raw_parts_mut( - new_shadow_buf.as_mut_ptr() as *mut u32, - new_shadow_buf.len() / 4, - ), - width: new_size.0 as usize, - height: new_size.1 as usize, - }; - - if new_map.height >= old_map.height { - for row in 0..old_map.height { - copy_row(old_map, new_map, row, row); - } - } else { - let deleted_rows = (old_map.height - new_map.height).div_ceil(16); - for row in 0..new_map.height { - if row + (deleted_rows + 1) * 16 >= old_map.height { - break; - } - copy_row(old_map, new_map, row + deleted_rows * 16, row); - } - self.console.state.y = self.console.state.y.saturating_sub(deleted_rows); - } - } - - let old_buffer = mem::replace(&mut map.buffer, new_buffer); - old_buffer.destroy(&map.display_handle)?; - - let old_fb = mem::replace(&mut map.fb, new_fb); - map.display_handle.set_crtc( - map.crtc, - Some(map.fb), - (0, 0), - &[map.connector], - Some(mode), - )?; - let _ = map.display_handle.destroy_framebuffer(old_fb); - - Ok(()) - } -} - -pub struct TextBuffer { - pub lines: VecDeque>, - pub lines_max: usize, -} - -impl TextBuffer { - pub fn new(max: usize) -> Self { - let mut lines = VecDeque::new(); - lines.push_back(Vec::new()); - Self { - lines, - lines_max: max, - } - } - pub fn write(&mut self, buf: &[u8]) { - if buf.is_empty() { - return; - } - - for &byte in buf { - self.lines.back_mut().unwrap().push(byte); - - if byte == b'\n' { - self.lines.push_back(Vec::new()); - } - } - - let max_len = self.lines_max; - while self.lines.len() > max_len { - self.lines.pop_front(); - } - } -} diff --git a/recipes/core/base/drivers/graphics/driver-graphics/Cargo.toml b/recipes/core/base/drivers/graphics/driver-graphics/Cargo.toml deleted file mode 100644 index 31e02335c8..0000000000 --- a/recipes/core/base/drivers/graphics/driver-graphics/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "driver-graphics" -description = "Shared video and graphics code library" -version = "0.1.0" -edition = "2021" - -[dependencies] -drm-fourcc = "2.2.0" -drm-sys.workspace = true -edid.workspace = true #TODO: edid is abandoned, fork it and maintain? -log.workspace = true -redox-ioctl.workspace = true -redox-scheme.workspace = true -scheme-utils = { path = "../../../scheme-utils" } -redox_syscall.workspace = true -libredox.workspace = true - -common = { path = "../../common" } -inputd = { path = "../../inputd" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/graphics/driver-graphics/src/kms/connector.rs b/recipes/core/base/drivers/graphics/driver-graphics/src/kms/connector.rs deleted file mode 100644 index c885f41351..0000000000 --- a/recipes/core/base/drivers/graphics/driver-graphics/src/kms/connector.rs +++ /dev/null @@ -1,249 +0,0 @@ -use std::ffi::c_char; -use std::fmt::Debug; -use std::sync::Mutex; - -use drm_sys::{ - drm_mode_modeinfo, DRM_MODE_CONNECTOR_Unknown, DRM_MODE_DPMS_OFF, DRM_MODE_DPMS_ON, - DRM_MODE_DPMS_STANDBY, DRM_MODE_DPMS_SUSPEND, DRM_MODE_TYPE_PREFERRED, -}; -use syscall::Result; - -use crate::kms::objects::{KmsObjectId, KmsObjects}; -use crate::kms::properties::{define_object_props, KmsPropertyData, CRTC_ID, DPMS, EDID}; -use crate::GraphicsAdapter; - -impl KmsObjects { - pub fn add_connector( - &mut self, - driver_data: T::Connector, - driver_data_state: ::State, - crtcs: &[KmsObjectId], - ) -> KmsObjectId { - let mut possible_crtcs = 0; - for &crtc in crtcs { - possible_crtcs = 1 << self.get_crtc(crtc).unwrap().lock().unwrap().crtc_index; - } - - let encoder_id = self.add(KmsEncoder { - crtc_id: KmsObjectId::INVALID, - possible_crtcs: possible_crtcs, - possible_clones: 1 << self.encoders.len(), - }); - self.encoders.push(encoder_id); - - let connector_id = self.add(Mutex::new(KmsConnector { - encoder_id, - modes: vec![], - connector_type: DRM_MODE_CONNECTOR_Unknown, - connector_type_id: self.connectors.len() as u32, // FIXME maybe pick unique id within connector type? - connection: KmsConnectorStatus::Unknown, - mm_width: 0, - mm_height: 0, - subpixel: DrmSubpixelOrder::Unknown, - properties: KmsConnector::base_properties(), - edid: KmsObjectId::INVALID, - state: KmsConnectorState { - dpms: KmsDpms::On, - crtc_id: KmsObjectId::INVALID, - driver_data: driver_data_state, - }, - driver_data, - })); - self.connectors.push(connector_id); - - connector_id - } - - pub fn connector_ids(&self) -> &[KmsObjectId] { - &self.connectors - } - - pub fn connectors(&self) -> impl Iterator>> + use<'_, T> { - self.connectors - .iter() - .map(|&id| self.get_connector(id).unwrap()) - } - - pub fn get_connector(&self, id: KmsObjectId) -> Result<&Mutex>> { - self.get(id) - } - - pub fn encoder_ids(&self) -> &[KmsObjectId] { - &self.encoders - } - - pub fn get_encoder(&self, id: KmsObjectId) -> Result<&KmsEncoder> { - self.get(id) - } -} - -pub trait KmsConnectorDriver: Debug { - type State: Clone + Debug; -} - -impl KmsConnectorDriver for () { - type State = (); -} - -#[derive(Debug)] -pub struct KmsConnector { - pub encoder_id: KmsObjectId, - pub modes: Vec, - pub connector_type: u32, - pub connector_type_id: u32, - pub connection: KmsConnectorStatus, - pub mm_width: u32, - pub mm_height: u32, - pub subpixel: DrmSubpixelOrder, - pub properties: Vec>, - pub edid: KmsObjectId, - pub state: KmsConnectorState, - pub driver_data: T::Connector, -} - -#[derive(Debug)] -pub struct KmsConnectorState { - pub dpms: KmsDpms, - pub crtc_id: KmsObjectId, - pub driver_data: ::State, -} - -impl Clone for KmsConnectorState { - fn clone(&self) -> Self { - Self { - dpms: self.dpms.clone(), - crtc_id: self.crtc_id.clone(), - driver_data: self.driver_data.clone(), - } - } -} - -define_object_props!(object, KmsConnector { - EDID { - get => u64::from(object.edid.0), - } - DPMS { - get => object.state.dpms as u64, - } - CRTC_ID { - get => u64::from(object.state.crtc_id.0), - } -}); - -impl KmsConnector { - pub fn update_from_size(&mut self, width: u32, height: u32) { - self.modes = vec![modeinfo_for_size(width, height)]; - } - - pub fn update_from_edid(&mut self, edid: &[u8]) { - let edid = edid::parse(edid).unwrap().1; - - if let Some(first_detailed_timing) = - edid.descriptors - .iter() - .find_map(|descriptor| match descriptor { - edid::Descriptor::DetailedTiming(detailed_timing) => Some(detailed_timing), - _ => None, - }) - { - self.mm_width = first_detailed_timing.horizontal_size.into(); - self.mm_height = first_detailed_timing.vertical_size.into(); - } else { - log::error!("No edid timing descriptor detected"); - } - - self.modes = edid - .descriptors - .iter() - .filter_map(|descriptor| { - match descriptor { - edid::Descriptor::DetailedTiming(detailed_timing) => { - // FIXME extract full information - Some(modeinfo_for_size( - u32::from(detailed_timing.horizontal_active_pixels), - u32::from(detailed_timing.vertical_active_lines), - )) - } - _ => None, - } - }) - .collect::>(); - - // First detailed timing descriptor indicates preferred mode. - for mode in self.modes.iter_mut().skip(1) { - mode.flags &= !DRM_MODE_TYPE_PREFERRED; - } - - // FIXME update the EDID property - } -} - -pub(crate) fn modeinfo_for_size(width: u32, height: u32) -> drm_mode_modeinfo { - let mut modeinfo = drm_mode_modeinfo { - // The actual visible display size - hdisplay: width as u16, - vdisplay: height as u16, - - // These are used to calculate the refresh rate - clock: 60 * width * height / 1000, - htotal: width as u16, - vtotal: height as u16, - vscan: 0, - vrefresh: 60, - - type_: drm_sys::DRM_MODE_TYPE_PREFERRED | drm_sys::DRM_MODE_TYPE_DRIVER, - name: [0; 32], - - // These only matter when modesetting physical display adapters. For - // those we should be able to parse the EDID blob. - hsync_start: width as u16, - hsync_end: width as u16, - hskew: 0, - vsync_start: height as u16, - vsync_end: height as u16, - flags: 0, - }; - - let name = format!("{width}x{height}").into_bytes(); - for (to, from) in modeinfo.name.iter_mut().zip(name) { - *to = from as c_char; - } - - modeinfo -} - -#[derive(Debug, Copy, Clone)] -#[repr(u32)] -pub enum KmsConnectorStatus { - Disconnected = 0, - Connected = 1, - Unknown = 2, -} - -#[derive(Debug, Copy, Clone)] -#[repr(u32)] -pub enum DrmSubpixelOrder { - Unknown = 0, - HorizontalRGB, - HorizontalBGR, - VerticalRGB, - VerticalBGR, - None, -} - -#[derive(Debug, Copy, Clone)] -#[repr(u64)] -pub enum KmsDpms { - On = DRM_MODE_DPMS_ON as u64, - Standby = DRM_MODE_DPMS_STANDBY as u64, - Suspend = DRM_MODE_DPMS_SUSPEND as u64, - Off = DRM_MODE_DPMS_OFF as u64, -} - -// FIXME can we represent connector and encoder using a single struct? -#[derive(Debug)] -pub struct KmsEncoder { - pub crtc_id: KmsObjectId, - pub possible_crtcs: u32, - pub possible_clones: u32, -} diff --git a/recipes/core/base/drivers/graphics/driver-graphics/src/kms/mod.rs b/recipes/core/base/drivers/graphics/driver-graphics/src/kms/mod.rs deleted file mode 100644 index 0181030ff2..0000000000 --- a/recipes/core/base/drivers/graphics/driver-graphics/src/kms/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod connector; -pub mod objects; -pub mod properties; diff --git a/recipes/core/base/drivers/graphics/driver-graphics/src/kms/objects.rs b/recipes/core/base/drivers/graphics/driver-graphics/src/kms/objects.rs deleted file mode 100644 index 1daf32212d..0000000000 --- a/recipes/core/base/drivers/graphics/driver-graphics/src/kms/objects.rs +++ /dev/null @@ -1,237 +0,0 @@ -use std::collections::HashMap; -use std::fmt::Debug; -use std::marker::PhantomData; -use std::sync::{Arc, Mutex}; - -use drm_sys::{ - drm_mode_modeinfo, DRM_MODE_OBJECT_BLOB, DRM_MODE_OBJECT_CONNECTOR, DRM_MODE_OBJECT_CRTC, - DRM_MODE_OBJECT_ENCODER, DRM_MODE_OBJECT_FB, DRM_MODE_OBJECT_PROPERTY, -}; -use syscall::{Error, Result, EINVAL}; - -use crate::kms::connector::{KmsConnector, KmsEncoder}; -use crate::kms::properties::{ - define_object_props, init_standard_props, KmsBlob, KmsProperty, KmsPropertyData, -}; -use crate::GraphicsAdapter; - -#[derive(Debug)] -pub struct KmsObjects { - next_id: KmsObjectId, - pub(crate) connectors: Vec, - pub(crate) encoders: Vec, - crtcs: Vec, - framebuffers: Vec, - pub(crate) objects: HashMap>, - _marker: PhantomData, -} - -impl KmsObjects { - pub(crate) fn new() -> Self { - let mut objects = KmsObjects { - next_id: KmsObjectId(1), - connectors: vec![], - encoders: vec![], - crtcs: vec![], - framebuffers: vec![], - objects: HashMap::new(), - _marker: PhantomData, - }; - init_standard_props(&mut objects); - objects - } - - pub(crate) fn add>>(&mut self, data: U) -> KmsObjectId { - let id = self.next_id; - self.objects.insert(id, data.into()); - self.next_id.0 += 1; - - id - } - - pub(crate) fn get<'a, U: 'a>(&'a self, id: KmsObjectId) -> Result<&'a U> - where - &'a U: TryFrom<&'a KmsObject>, - { - let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?; - if let Ok(object) = object.try_into() { - Ok(object) - } else { - Err(Error::new(EINVAL)) - } - } - - pub fn object_type(&self, id: KmsObjectId) -> Result { - let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?; - Ok(object.object_type()) - } - - pub fn add_crtc( - &mut self, - driver_data: T::Crtc, - driver_data_state: ::State, - ) -> KmsObjectId { - let crtc_index = self.crtcs.len() as u32; - let id = self.add(Mutex::new(KmsCrtc { - crtc_index, - gamma_size: 0, - properties: KmsCrtc::base_properties(), - state: KmsCrtcState { - fb_id: None, - mode: None, - driver_data: driver_data_state, - }, - driver_data, - })); - self.crtcs.push(id); - - id - } - - pub fn crtc_ids(&self) -> &[KmsObjectId] { - &self.crtcs - } - - pub fn crtcs(&self) -> impl Iterator>> + use<'_, T> { - self.crtcs - .iter() - .map(|&id| self.get::>>(id).unwrap()) - } - - pub fn get_crtc(&self, id: KmsObjectId) -> Result<&Mutex>> { - self.get(id) - } - - pub fn add_framebuffer(&mut self, fb: KmsFramebuffer) -> KmsObjectId { - let id = self.add(fb); - self.framebuffers.push(id); - id - } - - pub fn remove_framebuffer(&mut self, id: KmsObjectId) -> Result<()> { - let Some(object) = self.objects.get(&id) else { - return Err(Error::new(EINVAL)); - }; - let KmsObject::Framebuffer(_) = object else { - return Err(Error::new(EINVAL)); - }; - self.objects.remove(&id).unwrap(); - - Ok(()) - } - - pub fn fb_ids(&self) -> &[KmsObjectId] { - &self.framebuffers - } - - pub fn get_framebuffer(&self, id: KmsObjectId) -> Result<&KmsFramebuffer> { - self.get(id) - } -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] -pub struct KmsObjectId(pub(crate) u32); - -impl KmsObjectId { - pub const INVALID: KmsObjectId = KmsObjectId(0); -} - -impl From for u64 { - fn from(value: KmsObjectId) -> Self { - value.0.into() - } -} - -macro_rules! define_object_kinds { - (<$T:ident> $( - $variant:ident($data:ty) = $type:ident, - )*) => { - #[derive(Debug)] - pub(crate) enum KmsObject<$T: GraphicsAdapter> { - $($variant($data),)* - } - - impl<$T: GraphicsAdapter> KmsObject<$T> { - fn object_type(&self) -> u32 { - match self { - $(Self::$variant(_) => $type,)* - } - } - } - - $( - impl<$T: GraphicsAdapter> From<$data> for KmsObject<$T> { - fn from(value: $data) -> Self { - Self::$variant(value) - } - } - - impl<'a, $T: GraphicsAdapter> TryFrom<&'a KmsObject<$T>> for &'a $data { - type Error = (); - - fn try_from(value: &'a KmsObject) -> Result { - match value { - KmsObject::$variant(data) => Ok(data), - _ => Err(()), - } - } - } - )* - }; -} - -define_object_kinds! { - Crtc(Mutex>) = DRM_MODE_OBJECT_CRTC, - Connector(Mutex>) = DRM_MODE_OBJECT_CONNECTOR, - Encoder(KmsEncoder) = DRM_MODE_OBJECT_ENCODER, - Property(KmsProperty) = DRM_MODE_OBJECT_PROPERTY, - Framebuffer(KmsFramebuffer) = DRM_MODE_OBJECT_FB, - Blob(KmsBlob) = DRM_MODE_OBJECT_BLOB, -} - -pub trait KmsCrtcDriver: Debug { - type State: Clone + Debug; -} - -impl KmsCrtcDriver for () { - type State = (); -} - -#[derive(Debug)] -pub struct KmsCrtc { - pub crtc_index: u32, - pub gamma_size: u32, - pub properties: Vec>, - pub state: KmsCrtcState, - pub driver_data: T::Crtc, -} - -#[derive(Debug)] -pub struct KmsCrtcState { - pub fb_id: Option, - pub mode: Option, - pub driver_data: ::State, -} - -impl Clone for KmsCrtcState { - fn clone(&self) -> Self { - Self { - fb_id: self.fb_id.clone(), - mode: self.mode.clone(), - driver_data: self.driver_data.clone(), - } - } -} - -define_object_props!(object, KmsCrtc {}); - -#[derive(Debug)] -pub struct KmsFramebuffer { - pub width: u32, - pub height: u32, - pub pitch: u32, - pub bpp: u32, - pub depth: u32, - pub buffer: Arc, - pub driver_data: T::Framebuffer, -} diff --git a/recipes/core/base/drivers/graphics/driver-graphics/src/kms/properties.rs b/recipes/core/base/drivers/graphics/driver-graphics/src/kms/properties.rs deleted file mode 100644 index e22527a702..0000000000 --- a/recipes/core/base/drivers/graphics/driver-graphics/src/kms/properties.rs +++ /dev/null @@ -1,241 +0,0 @@ -use std::ffi::c_char; -use std::fmt::Debug; -use std::mem; - -use drm_sys::{ - DRM_MODE_DPMS_OFF, DRM_MODE_DPMS_ON, DRM_MODE_DPMS_STANDBY, DRM_MODE_DPMS_SUSPEND, - DRM_MODE_OBJECT_CRTC, DRM_MODE_OBJECT_FB, DRM_PLANE_TYPE_CURSOR, DRM_PLANE_TYPE_OVERLAY, - DRM_PLANE_TYPE_PRIMARY, DRM_PROP_NAME_LEN, -}; -use syscall::{Error, Result, EINVAL}; - -use crate::kms::objects::{KmsObject, KmsObjectId, KmsObjects}; -use crate::GraphicsAdapter; - -impl KmsObjects { - pub fn add_property( - &mut self, - name: &str, - immutable: bool, - atomic: bool, - kind: KmsPropertyKind, - ) -> KmsObjectId { - match &kind { - KmsPropertyKind::Range(start, end) => assert!(start < end), - KmsPropertyKind::Enum(_variants) => { - // FIXME check duplicate variant numbers - } - KmsPropertyKind::Blob => {} - KmsPropertyKind::Bitmask(_bitmask_flags) => { - // FIXME check overlapping flag numbers - } - KmsPropertyKind::Object { type_: _ } => {} - KmsPropertyKind::SignedRange(start, end) => assert!(start < end), - } - - let mut name_bytes = [0; DRM_PROP_NAME_LEN as usize]; - for (to, &from) in name_bytes.iter_mut().zip(name.as_bytes()) { - *to = from as c_char; - } - - self.add(KmsProperty { - name: KmsPropertyName::new("Property name", name), - immutable, - atomic, - kind, - }) - } - - pub fn get_property(&self, id: KmsObjectId) -> Result<&KmsProperty> { - self.get(id) - } - - pub fn get_object_properties_data(&self, id: KmsObjectId) -> Result<(Vec, Vec)> { - let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?; - match object { - KmsObject::Crtc(crtc) => { - let crtc = crtc.lock().unwrap(); - let props = &crtc.properties; - Ok(( - props.iter().map(|prop| prop.id.0).collect::>(), - props - .iter() - .map(|prop| (prop.getter)(&crtc)) - .collect::>(), - )) - } - KmsObject::Connector(connector) => { - let connector = connector.lock().unwrap(); - let props = &connector.properties; - Ok(( - props.iter().map(|prop| prop.id.0).collect::>(), - props - .iter() - .map(|prop| (prop.getter)(&connector)) - .collect::>(), - )) - } - KmsObject::Encoder(_) - | KmsObject::Property(_) - | KmsObject::Framebuffer(_) - | KmsObject::Blob(_) => Ok((vec![], vec![])), - } - } - - pub fn add_blob(&mut self, data: Vec) -> KmsObjectId { - self.add(KmsBlob { data }) - } - - pub fn get_blob(&self, id: KmsObjectId) -> Result<&[u8]> { - Ok(&self.get::(id)?.data) - } -} - -#[derive(Copy, Clone)] -pub struct KmsPropertyName(pub [c_char; DRM_PROP_NAME_LEN as usize]); - -impl KmsPropertyName { - fn new(context: &str, name: &str) -> KmsPropertyName { - if name.len() > DRM_PROP_NAME_LEN as usize { - panic!("{context} {name} is too long"); - } - - let mut name_bytes = [0; DRM_PROP_NAME_LEN as usize]; - for (to, &from) in name_bytes.iter_mut().zip(name.as_bytes()) { - *to = from as c_char; - } - - KmsPropertyName(name_bytes) - } -} - -impl Debug for KmsPropertyName { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let u8_bytes = unsafe { mem::transmute::<&[c_char], &[u8]>(&self.0) }; - f.write_str(&String::from_utf8_lossy(u8_bytes).trim_end_matches('\0')) - } -} - -#[derive(Debug)] -pub struct KmsProperty { - pub name: KmsPropertyName, - pub immutable: bool, - pub atomic: bool, - pub kind: KmsPropertyKind, -} - -#[derive(Debug)] -pub enum KmsPropertyKind { - Range(u64, u64), - Enum(Vec<(KmsPropertyName, u64)>), - Blob, - Bitmask(Vec<(KmsPropertyName, u64)>), - Object { type_: u32 }, - SignedRange(i64, i64), -} - -#[derive(Debug)] -pub struct KmsPropertyData { - pub id: KmsObjectId, - pub getter: fn(&T) -> u64, -} - -#[derive(Debug)] -pub struct KmsBlob { - data: Vec, -} - -macro_rules! define_properties { - ($($prop:ident $($prop_name:literal)?: $prop_type:ident $({$($prop_content:tt)*})? [$($prop_flag:ident)?],)*) => { - $(#[allow(non_upper_case_globals)] pub const $prop: KmsObjectId = KmsObjectId(1 + ${index()});)* - - pub(super) fn init_standard_props(objects: &mut KmsObjects) { - $( - assert_eq!(objects.add_property( - define_properties!(@prop_name $prop $($prop_name)?), - define_properties!(@is_immutable $($prop_flag)?), - define_properties!(@is_atomic $($prop_flag)?), - define_properties!(@prop_kind $prop_type $({$($prop_content)*})?), - ), $prop); - )* - } - }; - (@prop_name $prop:ident $prop_name:literal) => { $prop_name }; - (@prop_name $prop:ident) => { stringify!($prop) }; - (@is_immutable) => { false }; - (@is_immutable immutable) => { true }; - (@is_immutable atomic) => { false }; - (@is_atomic) => { false }; - (@is_atomic immutable) => { false }; - (@is_atomic atomic) => { true }; - (@prop_kind range { $start:expr, $end:expr }) => { - KmsPropertyKind::Range($start, $end) - }; - (@prop_kind enum { $($variant:ident = $value:expr,)* }) => { - KmsPropertyKind::Enum(vec![ - $((KmsPropertyName::new("Property variant name", stringify!($variant)), $value)),*] - ) - }; - (@prop_kind blob) => { - KmsPropertyKind::Blob - }; - (@prop_kind object { $type:ident }) => { - KmsPropertyKind::Object { type_: $type } - }; - (@prop_kind srange { $start:expr, $end:expr }) => { - KmsPropertyKind::SignedRange($start, $end) - }; -} - -define_properties! { - // Connector + Plane - CRTC_ID: object { DRM_MODE_OBJECT_CRTC } [atomic], - - // Connector - EDID: blob [immutable], - DPMS: enum { - On = u64::from(DRM_MODE_DPMS_ON), - Standby = u64::from(DRM_MODE_DPMS_STANDBY), - Suspend = u64::from(DRM_MODE_DPMS_SUSPEND), - Off = u64::from(DRM_MODE_DPMS_OFF), - } [], - - // CRTC - ACTIVE: range { 0,1 } [atomic], - MODE_ID: blob [atomic], - - // Plane - type_ "type": enum { - Overlay = u64::from(DRM_PLANE_TYPE_OVERLAY), - Primary = u64::from(DRM_PLANE_TYPE_PRIMARY), - Cursor = u64::from(DRM_PLANE_TYPE_CURSOR), - } [immutable], - FB_ID: object { DRM_MODE_OBJECT_FB } [atomic], - CRTC_X: srange { i64::from(i32::MIN), i64::from(i32::MAX) } [atomic], - CRTC_Y: srange { i64::from(i32::MIN), i64::from(i32::MAX) } [atomic], - CRTC_W: range { 0, u64::from(u32::MAX) } [atomic], - CRTC_H: range { 0, u64::from(u32::MAX) } [atomic], - SRC_X: range { 0, u64::from(u32::MAX) } [atomic], - SRC_Y: range { 0, u64::from(u32::MAX) } [atomic], - SRC_W: range { 0, u64::from(u32::MAX) } [atomic], - SRC_H: range { 0, u64::from(u32::MAX) } [atomic], - FB_DAMAGE_CLIPS: blob [atomic], -} - -macro_rules! define_object_props { - ($object:ident, $obj:ident$(<$($T:ident$(: $bound:ident)?),*>)? { $( - $prop:ident { - get => $get:expr, - } - )* }) => { - impl$(<$($T$(: $bound)?),*>)? $obj$(<$($T),*>)? { - pub(super) fn base_properties() -> Vec> { - vec![$(KmsPropertyData { - id: $prop, - getter: |$object| $get - }),*] - } - } - }; -} -pub(super) use define_object_props; diff --git a/recipes/core/base/drivers/graphics/driver-graphics/src/lib.rs b/recipes/core/base/drivers/graphics/driver-graphics/src/lib.rs deleted file mode 100644 index eab0be9c3e..0000000000 --- a/recipes/core/base/drivers/graphics/driver-graphics/src/lib.rs +++ /dev/null @@ -1,986 +0,0 @@ -#![feature(macro_metavar_expr)] - -use std::collections::HashMap; -use std::fmt::Debug; -use std::fs::File; -use std::io::{self, Write}; -use std::os::fd::BorrowedFd; -use std::sync::{Arc, Mutex}; -use std::{cmp, mem}; - -use drm_fourcc::DrmFourcc; -use drm_sys::{ - drm_mode_property_enum, DRM_MODE_CURSOR_BO, DRM_MODE_CURSOR_MOVE, DRM_MODE_PROP_ATOMIC, - DRM_MODE_PROP_BITMASK, DRM_MODE_PROP_BLOB, DRM_MODE_PROP_ENUM, DRM_MODE_PROP_IMMUTABLE, - DRM_MODE_PROP_OBJECT, DRM_MODE_PROP_RANGE, DRM_MODE_PROP_SIGNED_RANGE, -}; -use inputd::{DisplayHandle, VtEventKind}; -use libredox::Fd; -use redox_scheme::scheme::{register_scheme_inner, SchemeState, SchemeSync}; -use redox_scheme::{CallerCtx, OpenResult, RequestKind, SignalBehavior, Socket}; -use scheme_utils::{FpathWriter, HandleMap}; -use syscall::schemev2::NewFdFlags; -use syscall::{Error, MapFlags, Result, EACCES, EAGAIN, EINVAL, ENOENT, EOPNOTSUPP}; - -use crate::kms::connector::{KmsConnectorDriver, KmsConnectorState}; -use crate::kms::objects::{self, KmsCrtc, KmsCrtcDriver, KmsCrtcState, KmsObjectId, KmsObjects}; -use crate::kms::properties::KmsPropertyKind; - -pub mod kms; - -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct Damage { - pub x: u32, - pub y: u32, - pub width: u32, - pub height: u32, -} - -impl Damage { - fn merge(self, other: Self) -> Self { - if self.width == 0 || self.height == 0 { - return other; - } - - if other.width == 0 || other.height == 0 { - return self; - } - - let x = cmp::min(self.x, other.x); - let y = cmp::min(self.y, other.y); - let x2 = cmp::max(self.x + self.width, other.x + other.width); - let y2 = cmp::max(self.y + self.height, other.y + other.height); - - Damage { - x, - y, - width: x2 - x, - height: y2 - y, - } - } - - #[must_use] - pub fn clip(mut self, width: u32, height: u32) -> Self { - // Clip damage - let x2 = self.x + self.width; - self.x = cmp::min(self.x, width); - if x2 > width { - self.width = width - self.x; - } - - let y2 = self.y + self.height; - self.y = cmp::min(self.y, height); - if y2 > height { - self.height = height - self.y; - } - self - } -} - -pub trait GraphicsAdapter: Sized + Debug { - type Connector: KmsConnectorDriver; - type Crtc: KmsCrtcDriver; - - type Buffer: Buffer; - type Framebuffer: Framebuffer; - - fn name(&self) -> &'static [u8]; - fn desc(&self) -> &'static [u8]; - - fn init(&mut self, objects: &mut KmsObjects); - - fn get_cap(&self, cap: u32) -> Result; - fn set_client_cap(&self, cap: u32, value: u64) -> Result<()>; - - fn probe_connector(&mut self, objects: &mut KmsObjects, id: KmsObjectId); - - fn create_dumb_buffer(&mut self, width: u32, height: u32) -> (Self::Buffer, u32); - fn map_dumb_buffer(&mut self, buffer: &Self::Buffer) -> *mut u8; - - fn create_framebuffer(&mut self, buffer: &Self::Buffer) -> Self::Framebuffer; - - fn set_crtc( - &mut self, - objects: &KmsObjects, - crtc: &Mutex>, - new_state: KmsCrtcState, - damage: Damage, - ) -> syscall::Result<()>; - - fn hw_cursor_size(&self) -> Option<(u32, u32)>; - fn handle_cursor(&mut self, cursor: &CursorPlane, dirty_fb: bool); -} - -pub trait Buffer: Debug { - fn size(&self) -> usize; -} - -pub trait Framebuffer: Debug {} - -impl Framebuffer for () {} - -pub struct CursorPlane { - pub x: i32, - pub y: i32, - pub hot_x: i32, - pub hot_y: i32, - pub buffer: Option>, -} - -pub struct GraphicsScheme { - inner: GraphicsSchemeInner, - inputd_handle: DisplayHandle, - state: SchemeState, -} - -impl GraphicsScheme { - pub fn new(mut adapter: T, scheme_name: String, early: bool) -> Self { - assert!(scheme_name.starts_with("display")); - let socket = Socket::nonblock().expect("failed to create graphics scheme"); - - let disable_graphical_debug = Some( - File::open("/scheme/debug/disable-graphical-debug") - .expect("vesad: Failed to open /scheme/debug/disable-graphical-debug"), - ); - - let mut objects = KmsObjects::new(); - adapter.init(&mut objects); - for connector_id in objects.connector_ids().to_vec() { - adapter.probe_connector(&mut objects, connector_id) - } - - let mut inner = GraphicsSchemeInner { - adapter, - scheme_name, - disable_graphical_debug, - socket, - objects, - handles: HandleMap::new(), - active_vt: 0, - vts: HashMap::new(), - }; - - let cap_id = inner.scheme_root().expect("failed to get this scheme root"); - register_scheme_inner(&inner.socket, &inner.scheme_name, cap_id) - .expect("failed to register graphics scheme root"); - - let display_handle = if early { - DisplayHandle::new_early(&inner.scheme_name).unwrap() - } else { - DisplayHandle::new(&inner.scheme_name).unwrap() - }; - - Self { - inner, - inputd_handle: display_handle, - state: SchemeState::new(), - } - } - - pub fn event_handle(&self) -> &Fd { - self.inner.socket.inner() - } - - pub fn inputd_event_handle(&self) -> BorrowedFd<'_> { - self.inputd_handle.inner() - } - - pub fn adapter(&self) -> &T { - &self.inner.adapter - } - - pub fn adapter_mut(&mut self) -> &mut T { - &mut self.inner.adapter - } - - pub fn kms_objects(&self) -> &KmsObjects { - &self.inner.objects - } - - pub fn kms_objects_mut(&mut self) -> &mut KmsObjects { - &mut self.inner.objects - } - - pub fn adapter_and_kms_objects_mut(&mut self) -> (&mut T, &mut KmsObjects) { - (&mut self.inner.adapter, &mut self.inner.objects) - } - - pub fn handle_vt_events(&mut self) { - while let Some(vt_event) = self - .inputd_handle - .read_vt_event() - .expect("driver-graphics: failed to read display handle") - { - match vt_event.kind { - VtEventKind::Activate => self.inner.activate_vt(vt_event.vt), - } - } - } - - pub fn notify_displays_changed(&mut self) { - // FIXME notify clients - } - - /// Process new scheme requests. - /// - /// This needs to be called each time there is a new event on the scheme - /// file. - pub fn tick(&mut self) -> io::Result<()> { - loop { - let request = match self.inner.socket.next_request(SignalBehavior::Restart) { - Ok(Some(request)) => request, - Ok(None) => { - // Scheme likely got unmounted - std::process::exit(0); - } - Err(err) if err.errno == EAGAIN => break, - Err(err) => panic!("driver-graphics: failed to read display scheme: {err}"), - }; - - match request.kind() { - RequestKind::Call(call) => { - let response = call.handle_sync(&mut self.inner, &mut self.state); - self.inner - .socket - .write_response(response, SignalBehavior::Restart) - .expect("driver-graphics: failed to write response"); - } - RequestKind::OnClose { id } => { - self.inner.on_close(id); - } - _ => (), - } - } - - Ok(()) - } -} - -struct GraphicsSchemeInner { - adapter: T, - - scheme_name: String, - disable_graphical_debug: Option, - socket: Socket, - objects: KmsObjects, - handles: HandleMap>, - - active_vt: usize, - vts: HashMap>, -} - -struct VtState { - connector_state: Vec>, - crtc_state: Vec>, - cursor_plane: CursorPlane, -} - -enum Handle { - V2 { - vt: usize, - next_id: u32, - buffers: HashMap>, - }, - SchemeRoot, -} - -impl GraphicsSchemeInner { - fn get_or_create_vt<'a>( - objects: &KmsObjects, - vts: &'a mut HashMap>, - vt: usize, - ) -> &'a mut VtState { - vts.entry(vt).or_insert_with(|| VtState { - connector_state: objects - .connectors() - .map(|connector| connector.lock().unwrap().state.clone()) - .collect(), - crtc_state: objects - .crtcs() - .map(|crtc| crtc.lock().unwrap().state.clone()) - .collect(), - cursor_plane: CursorPlane { - x: 0, - y: 0, - hot_x: 0, - hot_y: 0, - buffer: None, - }, - }) - } - - fn activate_vt(&mut self, vt: usize) { - log::info!("activate {}", vt); - - // Disable the kernel graphical debug writing once switching vt's for the - // first time. This way the kernel graphical debug remains enabled if the - // userspace logging infrastructure doesn't start up because for example a - // kernel panic happened prior to it starting up or logd crashed. - if let Some(mut disable_graphical_debug) = self.disable_graphical_debug.take() { - let _ = disable_graphical_debug.write(&[1]); - } - - self.active_vt = vt; - - let vt_state = GraphicsSchemeInner::get_or_create_vt(&self.objects, &mut self.vts, vt); - - for (connector_idx, connector_state) in vt_state.connector_state.iter().enumerate() { - let connector_id = self.objects.connector_ids()[connector_idx]; - let mut connector = self - .objects - .get_connector(connector_id) - .unwrap() - .lock() - .unwrap(); - connector.state = connector_state.clone(); - } - - for (crtc_idx, crtc_state) in vt_state.crtc_state.iter().enumerate() { - let crtc_id = self.objects.crtc_ids()[crtc_idx]; - let crtc = self.objects.get_crtc(crtc_id).unwrap(); - let connector_id = self.objects.connector_ids()[crtc_idx]; - - let fb = crtc_state.fb_id.map(|fb_id| { - self.objects - .get_framebuffer(fb_id) - .expect("removed framebuffers should be unset") - }); - - self.adapter - .set_crtc( - &self.objects, - crtc, - crtc_state.clone(), - Damage { - x: 0, - y: 0, - width: fb.map_or(0, |fb| fb.width), - height: fb.map_or(0, |fb| fb.height), - }, - ) - .unwrap(); - - self.objects - .get_connector(connector_id) - .unwrap() - .lock() - .unwrap() - .state - .crtc_id = crtc_id; - } - - if self.adapter.hw_cursor_size().is_some() { - self.adapter.handle_cursor(&vt_state.cursor_plane, true); - } - } -} - -const MAP_FAKE_OFFSET_MULTIPLIER: usize = 0x10_000_000; - -impl SchemeSync for GraphicsSchemeInner { - fn scheme_root(&mut self) -> Result { - Ok(self.handles.insert(Handle::SchemeRoot)) - } - fn openat( - &mut self, - dirfd: usize, - path: &str, - _flags: usize, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - if !matches!(self.handles.get(dirfd)?, Handle::SchemeRoot) { - return Err(Error::new(EACCES)); - } - if path.is_empty() { - return Err(Error::new(EINVAL)); - } - - let handle = if path.starts_with("v") { - if !path.starts_with("v2/") { - return Err(Error::new(ENOENT)); - } - let vt = path["v2/".len()..] - .parse::() - .map_err(|_| Error::new(EINVAL))?; - - // Ensure the VT exists such that the rest of the methods can freely access it. - Self::get_or_create_vt(&self.objects, &mut self.vts, vt); - - Handle::V2 { - vt, - next_id: 0, - buffers: HashMap::new(), - } - } else { - return Err(Error::new(EINVAL)); - }; - let id = self.handles.insert(handle); - Ok(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::empty(), - }) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> syscall::Result { - FpathWriter::with(buf, &self.scheme_name, |w| { - match self.handles.get(id)? { - Handle::V2 { - vt, - next_id: _, - buffers: _, - } => write!(w, "v2/{vt}").unwrap(), - Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)), - }; - Ok(()) - }) - } - - fn call( - &mut self, - id: usize, - payload: &mut [u8], - metadata: &[u64], - _ctx: &CallerCtx, - ) -> Result { - use redox_ioctl::drm as ipc; - - fn id_index(id: u32) -> u32 { - id & 0xFF - } - - fn plane_id(i: u32) -> u32 { - id_index(i) | (1 << 13) - } - - match self.handles.get_mut(id)? { - Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)), - Handle::V2 { - vt, - next_id, - buffers, - } => match metadata[0] { - ipc::VERSION => ipc::DrmVersion::with(payload, |mut data| { - data.set_version_major(1); - data.set_version_minor(4); - data.set_version_patchlevel(0); - - data.set_name(unsafe { mem::transmute(self.adapter.name()) }); - data.set_date(unsafe { mem::transmute(&b"0"[..]) }); - data.set_desc(unsafe { mem::transmute(self.adapter.desc()) }); - - Ok(0) - }), - ipc::GET_CAP => ipc::DrmGetCap::with(payload, |mut data| { - data.set_value( - self.adapter.get_cap( - data.capability() - .try_into() - .map_err(|_| syscall::Error::new(EINVAL))?, - )?, - ); - Ok(0) - }), - ipc::SET_CLIENT_CAP => ipc::DrmSetClientCap::with(payload, |data| { - self.adapter.set_client_cap( - data.capability() - .try_into() - .map_err(|_| syscall::Error::new(EINVAL))?, - data.value(), - )?; - Ok(0) - }), - ipc::MODE_CARD_RES => ipc::DrmModeCardRes::with(payload, |mut data| { - let conn_ids = self - .objects - .connector_ids() - .iter() - .map(|id| id.0) - .collect::>(); - let crtc_ids = self - .objects - .crtc_ids() - .iter() - .map(|id| id.0) - .collect::>(); - let enc_ids = self - .objects - .encoder_ids() - .iter() - .map(|id| id.0) - .collect::>(); - let fb_ids = self - .objects - .fb_ids() - .iter() - .map(|id| id.0) - .collect::>(); - data.set_fb_id_ptr(&fb_ids); - data.set_crtc_id_ptr(&crtc_ids); - data.set_connector_id_ptr(&conn_ids); - data.set_encoder_id_ptr(&enc_ids); - data.set_min_width(0); - data.set_max_width(16384); - data.set_min_height(0); - data.set_max_height(16384); - Ok(0) - }), - ipc::MODE_GET_CRTC => ipc::DrmModeCrtc::with(payload, |mut data| { - let crtc = self - .objects - .get_crtc(KmsObjectId(data.crtc_id()))? - .lock() - .unwrap(); - // Don't touch set_connectors, that is only used by MODE_SET_CRTC - data.set_fb_id(crtc.state.fb_id.unwrap_or(KmsObjectId::INVALID).0); - // FIXME fill x and y with the data from the primary plane - data.set_x(0); - data.set_y(0); - data.set_gamma_size(crtc.gamma_size); - if let Some(mode) = crtc.state.mode { - data.set_mode_valid(1); - data.set_mode(mode); - } else { - data.set_mode_valid(0); - data.set_mode(Default::default()); - } - Ok(0) - }), - ipc::MODE_SET_CRTC => ipc::DrmModeCrtc::with(payload, |data| { - let crtc = self.objects.get_crtc(KmsObjectId(data.crtc_id()))?; - let connector_ids: Vec = data - .set_connectors_ptr() - .iter() - .take(data.count_connectors() as usize) - .map(|&id| KmsObjectId(id)) - .collect(); - let fb_id = if data.fb_id() != 0 { - Some(KmsObjectId(data.fb_id())) - } else { - None - }; - let mode = if data.mode_valid() != 0 { - Some(data.mode()) - } else { - None - }; - let mut new_state = crtc.lock().unwrap().state.clone(); - new_state.fb_id = fb_id; - new_state.mode = mode; - if *vt == self.active_vt { - self.adapter.set_crtc( - &self.objects, - crtc, - new_state.clone(), - Damage { - x: data.x(), - y: data.y(), - width: mode.map_or(0, |m| m.hdisplay as u32), - height: mode.map_or(0, |m| m.vdisplay as u32), - }, - )?; - - for connector in connector_ids { - self.objects - .get_connector(connector)? - .lock() - .unwrap() - .state - .crtc_id = KmsObjectId(data.crtc_id()); - } - } - self.vts.get_mut(vt).unwrap().crtc_state - [crtc.lock().unwrap().crtc_index as usize] = new_state; - Ok(0) - }), - ipc::MODE_CURSOR => ipc::DrmModeCursor::with(payload, |data| { - let vt_state = self.vts.get_mut(vt).unwrap(); - - let cursor_plane = &mut vt_state.cursor_plane; - - let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; - if update_buffer { - cursor_plane.buffer = if data.handle() == 0 { - None - } else if let Some(buffer) = buffers.get(&data.handle()) { - Some(buffer.clone()) - } else { - return Err(Error::new(EINVAL)); - }; - } - - if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { - cursor_plane.x = data.x(); - cursor_plane.y = data.y(); - } - - self.adapter.handle_cursor(cursor_plane, update_buffer); - - Ok(0) - }), - ipc::MODE_GET_ENCODER => ipc::DrmModeGetEncoder::with(payload, |mut data| { - let encoder = self.objects.get_encoder(KmsObjectId(data.encoder_id()))?; - data.set_crtc_id(encoder.crtc_id.0); - data.set_possible_crtcs(encoder.possible_crtcs); - data.set_possible_clones(encoder.possible_clones); - Ok(0) - }), - ipc::MODE_GET_CONNECTOR => ipc::DrmModeGetConnector::with(payload, |mut data| { - if data.count_modes() == 0 { - self.adapter - .probe_connector(&mut self.objects, KmsObjectId(data.connector_id())); - } - let connector = self - .objects - .get_connector(KmsObjectId(data.connector_id()))? - .lock() - .unwrap(); - data.set_encoders_ptr(&[connector.encoder_id.0]); - data.set_modes_ptr(&connector.modes); - data.set_connector_type(data.connector_type()); - data.set_connector_type_id(data.connector_type_id()); - data.set_connection(connector.connection as u32); - data.set_mm_width(connector.mm_width); - data.set_mm_height(connector.mm_width); - data.set_subpixel(connector.subpixel as u32); - drop(connector); - let (props, prop_vals) = self - .objects - .get_object_properties_data(KmsObjectId(data.connector_id()))?; - data.set_props_ptr(&props); - data.set_prop_values_ptr(&prop_vals); - Ok(0) - }), - ipc::MODE_GET_PROPERTY => ipc::DrmModeGetProperty::with(payload, |mut data| { - let property = self.objects.get_property(KmsObjectId(data.prop_id()))?; - data.set_name(property.name.0); - let mut flags = 0; - if property.immutable { - flags |= DRM_MODE_PROP_IMMUTABLE; - } - if property.atomic { - flags |= DRM_MODE_PROP_ATOMIC; - } - match &property.kind { - &KmsPropertyKind::Range(start, end) => { - data.set_flags(flags | DRM_MODE_PROP_RANGE); - data.set_values_ptr(&[start, end]); - data.set_enum_blob_ptr(&[]); - } - KmsPropertyKind::Enum(variants) => { - data.set_flags(flags | DRM_MODE_PROP_ENUM); - data.set_values_ptr( - &variants.iter().map(|&(_, value)| value).collect::>(), - ); - data.set_enum_blob_ptr( - &variants - .iter() - .map(|&(name, value)| drm_mode_property_enum { - name: name.0, - value, - }) - .collect::>(), - ); - } - KmsPropertyKind::Blob => { - data.set_flags(flags | DRM_MODE_PROP_BLOB); - data.set_values_ptr(&[]); - data.set_enum_blob_ptr(&[]); - } - KmsPropertyKind::Bitmask(bitmask_flags) => { - data.set_flags(flags | DRM_MODE_PROP_BITMASK); - data.set_values_ptr( - &bitmask_flags - .iter() - .map(|&(_, value)| value) - .collect::>(), - ); - data.set_enum_blob_ptr( - &bitmask_flags - .iter() - .map(|&(name, value)| drm_mode_property_enum { - name: name.0, - value, - }) - .collect::>(), - ); - } - KmsPropertyKind::Object { type_ } => { - data.set_flags(flags | DRM_MODE_PROP_OBJECT); - data.set_values_ptr(&[u64::from(*type_)]); - data.set_enum_blob_ptr(&[]); - } - &KmsPropertyKind::SignedRange(start, end) => { - data.set_flags(flags | DRM_MODE_PROP_SIGNED_RANGE); - data.set_values_ptr(&[start as u64, end as u64]); - data.set_enum_blob_ptr(&[]); - } - } - Ok(0) - }), - ipc::MODE_GET_PROP_BLOB => ipc::DrmModeGetBlob::with(payload, |mut data| { - let blob = self.objects.get_blob(KmsObjectId(data.blob_id()))?; - data.set_data(&blob); - Ok(0) - }), - ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { - let fb = self.objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - *next_id += 1; - buffers.insert(*next_id, fb.buffer.clone()); - - data.set_width(fb.width); - data.set_height(fb.height); - data.set_pitch(fb.pitch); - data.set_bpp(fb.bpp); - data.set_depth(fb.depth); - data.set_handle(*next_id); - Ok(0) - }), - ipc::MODE_ADD_FB => ipc::DrmModeFbCmd::with(payload, |mut data| { - let buffer = buffers.get(&data.handle()).ok_or(Error::new(EINVAL))?; - - let fb = self.adapter.create_framebuffer(buffer); - - let id = self.objects.add_framebuffer(objects::KmsFramebuffer { - width: data.width(), - height: data.height(), - pitch: data.pitch(), - bpp: data.bpp(), - depth: data.depth(), - buffer: buffer.clone(), - driver_data: fb, - }); - - data.set_fb_id(id.0); - - Ok(0) - }), - ipc::MODE_RM_FB => ipc::StandinForUint::with(payload, |data| { - let fb_id = KmsObjectId(data.inner()); - self.objects.remove_framebuffer(fb_id)?; - - // Disable planes that use this framebuffer. - for (vt, vt_data) in &mut self.vts { - for (crtc_idx, crtc_state) in vt_data.crtc_state.iter_mut().enumerate() { - if crtc_state.fb_id != Some(fb_id) { - continue; - } - crtc_state.fb_id = None; - - if *vt != self.active_vt { - continue; - } - let crtc = self.objects.crtcs().nth(crtc_idx).unwrap(); - self.adapter - .set_crtc( - &self.objects, - crtc, - crtc_state.clone(), - Damage { - x: 0, - y: 0, - width: 0, - height: 0, - }, - ) - .unwrap(); - } - } - - Ok(0) - }), - ipc::MODE_DIRTYFB => ipc::DrmModeFbDirtyCmd::with(payload, |data| { - let fb = self.objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - let damage = data - .clips_ptr() - .iter() - .map(|rect| Damage { - x: u32::from(rect.x1), - y: u32::from(rect.y1), - width: u32::from(rect.x2 - rect.x1), - height: u32::from(rect.y2 - rect.y1), - }) - .reduce(Damage::merge) - .unwrap_or(Damage { - x: 0, - y: 0, - width: fb.width, - height: fb.height, - }); - - if *vt == self.active_vt { - for crtc in self.objects.crtcs() { - let state = crtc.lock().unwrap().state.clone(); - if state.fb_id == Some(KmsObjectId(data.fb_id())) { - self.adapter.set_crtc(&self.objects, crtc, state, damage)?; - } - } - } - - Ok(0) - }), - ipc::MODE_CREATE_DUMB => ipc::DrmModeCreateDumb::with(payload, |mut data| { - if data.bpp() != 32 || data.flags() != 0 { - return Err(Error::new(EINVAL)); - } - - let (buffer, pitch) = - self.adapter.create_dumb_buffer(data.width(), data.height()); - - data.set_pitch(pitch); - data.set_size(buffer.size() as u64); - - *next_id += 1; - buffers.insert(*next_id, Arc::new(buffer)); - data.set_handle(*next_id as u32); - Ok(0) - }), - ipc::MODE_MAP_DUMB => ipc::DrmModeMapDumb::with(payload, |mut data| { - if data.offset() != 0 { - return Err(Error::new(EINVAL)); - } - - let buffer_id = data.handle(); - - if !buffers.contains_key(&buffer_id) { - return Err(Error::new(EINVAL)); - } - - // FIXME use a better scheme for creating map offsets - assert!(buffers[&buffer_id].size() < MAP_FAKE_OFFSET_MULTIPLIER); - - data.set_offset((buffer_id as usize * MAP_FAKE_OFFSET_MULTIPLIER) as u64); - - Ok(0) - }), - ipc::MODE_DESTROY_DUMB => ipc::DrmModeDestroyDumb::with(payload, |data| { - if buffers.remove(&data.handle()).is_none() { - return Err(Error::new(ENOENT)); - } - Ok(0) - }), - ipc::MODE_GET_PLANE_RES => ipc::DrmModeGetPlaneRes::with(payload, |mut data| { - let count = self.objects.crtc_ids().len(); - let mut ids = Vec::with_capacity(count); - for i in 0..(count as u32) { - ids.push(plane_id(i)); - } - data.set_plane_id_ptr(&ids); - Ok(0) - }), - ipc::MODE_GET_PLANE => ipc::DrmModeGetPlane::with(payload, |mut data| { - let i = id_index(data.plane_id()); - let crtc_id = self.objects.crtc_ids()[i as usize]; - let crtc = self.objects.get_crtc(crtc_id).unwrap(); - data.set_crtc_id(crtc_id.0); - data.set_fb_id( - crtc.lock() - .unwrap() - .state - .fb_id - .unwrap_or(KmsObjectId::INVALID) - .0, - ); - data.set_possible_crtcs(1 << i); - data.set_format_type_ptr(&[DrmFourcc::Argb8888 as u32]); - Ok(0) - }), - ipc::MODE_OBJ_GET_PROPERTIES => { - ipc::DrmModeObjGetProperties::with(payload, |mut data| { - // FIXME remove once all drm objects are materialized in self.objects - if data.obj_id() >= 1 << 11 { - data.set_props_ptr(&[]); - data.set_prop_values_ptr(&[]); - return Ok(0); - } - - let (props, prop_vals) = self - .objects - .get_object_properties_data(KmsObjectId(data.obj_id()))?; - data.set_props_ptr(&props); - data.set_prop_values_ptr(&prop_vals); - data.set_obj_type(self.objects.object_type(KmsObjectId(data.obj_id()))?); - Ok(0) - }) - } - ipc::MODE_CURSOR2 => ipc::DrmModeCursor2::with(payload, |data| { - let vt_state = self.vts.get_mut(vt).unwrap(); - - let cursor_plane = &mut vt_state.cursor_plane; - - let update_buffer = data.flags() & DRM_MODE_CURSOR_BO != 0; - if update_buffer { - cursor_plane.buffer = if data.handle() == 0 { - None - } else if let Some(buffer) = buffers.get(&data.handle()) { - Some(buffer.clone()) - } else { - return Err(Error::new(EINVAL)); - }; - cursor_plane.hot_x = data.hot_x(); - cursor_plane.hot_y = data.hot_y(); - } - - if data.flags() & DRM_MODE_CURSOR_MOVE != 0 { - cursor_plane.x = data.x(); - cursor_plane.y = data.y(); - } - - self.adapter.handle_cursor(cursor_plane, update_buffer); - - Ok(0) - }), - ipc::MODE_GET_FB2 => ipc::DrmModeFbCmd2::with(payload, |mut data| { - let fb = self.objects.get_framebuffer(KmsObjectId(data.fb_id()))?; - - *next_id += 1; - buffers.insert(*next_id, fb.buffer.clone()); - - data.set_width(fb.width); - data.set_height(fb.height); - data.set_pixel_format(DrmFourcc::Argb8888 as u32); - data.set_handles([*next_id, 0, 0, 0]); - data.set_pitches([fb.width * 4, 0, 0, 0]); - data.set_offsets([0; 4]); - data.set_modifier([0; 4]); - Ok(0) - }), - _ => return Err(Error::new(EINVAL)), - }, - } - } - - fn mmap_prep( - &mut self, - id: usize, - offset: u64, - _size: usize, - _flags: MapFlags, - _ctx: &CallerCtx, - ) -> syscall::Result { - // log::trace!("KSMSG MMAP {} {:?} {} {}", id, _flags, _offset, _size); - let (framebuffer, offset) = match self.handles.get(id)? { - Handle::V2 { - vt: _, - next_id: _, - buffers, - } => ( - buffers - .get(&((offset as usize / MAP_FAKE_OFFSET_MULTIPLIER) as u32)) - .ok_or(Error::new(EINVAL)) - .unwrap(), - offset & (MAP_FAKE_OFFSET_MULTIPLIER as u64 - 1), - ), - Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)), - }; - let ptr = T::map_dumb_buffer(&mut self.adapter, framebuffer); - Ok(unsafe { ptr.add(offset as usize) } as usize) - } - - fn on_close(&mut self, id: usize) { - self.handles.remove(id); - } -} diff --git a/recipes/core/base/drivers/graphics/fbbootlogd/Cargo.toml b/recipes/core/base/drivers/graphics/fbbootlogd/Cargo.toml deleted file mode 100644 index a891507842..0000000000 --- a/recipes/core/base/drivers/graphics/fbbootlogd/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "fbbootlogd" -description = "Boot log drawing daemon" -version = "0.1.0" -edition = "2021" - -[dependencies] -drm.workspace = true -orbclient.workspace = true -ransid.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true -redox-scheme.workspace = true -scheme-utils = { path = "../../../scheme-utils" } - -console-draw = { path = "../console-draw" } -daemon = { path = "../../../daemon" } -graphics-ipc = { path = "../graphics-ipc" } -inputd = { path = "../../inputd" } -libredox.workspace = true - -[features] -default = [] - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/graphics/fbbootlogd/src/main.rs b/recipes/core/base/drivers/graphics/fbbootlogd/src/main.rs deleted file mode 100644 index 3e42d590ca..0000000000 --- a/recipes/core/base/drivers/graphics/fbbootlogd/src/main.rs +++ /dev/null @@ -1,115 +0,0 @@ -//! Fbbootlogd renders the boot log and presents it on VT1. -//! -//! While fbbootlogd is superficially similar to fbcond, the major difference is: -//! -//! * Fbbootlogd doesn't accept input coming from the keyboard. It only allows getting written to. -//! -//! In the future fbbootlogd may also pull from logd as opposed to have logd push logs to it. And it -//! it could display a boot splash like plymouth instead of a boot log when booting in quiet mode. - -use std::ops::ControlFlow; -use std::os::fd::AsRawFd; - -use event::EventQueue; -use inputd::ConsumerHandleEvent; -use orbclient::Event; -use redox_scheme::Socket; -use scheme_utils::Blocking; - -use crate::scheme::FbbootlogScheme; - -mod scheme; - -fn main() { - daemon::SchemeDaemon::new(daemon); -} -fn daemon(daemon: daemon::SchemeDaemon) -> ! { - let event_queue = EventQueue::new().expect("fbbootlogd: failed to create event queue"); - - event::user_data! { - enum Source { - Scheme, - Input, - } - } - - let socket = Socket::nonblock().expect("fbbootlogd: failed to create fbbootlog scheme"); - - let mut scheme = FbbootlogScheme::new(); - let mut handler = Blocking::new(&socket, 16); - - event_queue - .subscribe( - socket.inner().raw(), - Source::Scheme, - event::EventFlags::READ, - ) - .expect("fbbootlogd: failed to subscribe to scheme events"); - - event_queue - .subscribe( - scheme.input_handle.event_handle().as_raw_fd() as usize, - Source::Input, - event::EventFlags::READ, - ) - .expect("fbbootlogd: failed to subscribe to scheme events"); - - { - let log_fd = socket - .create_this_scheme_fd(0, 0, 0, 0) - .expect("fbbootlogd: failed to create log fd"); - // Add ourself as log sink - let log_file = libredox::Fd::open( - "/scheme/log/add_sink", - libredox::flag::O_WRONLY | libredox::flag::O_CLOEXEC, - 0, - ) - .expect("fbbootlogd: failed to open log/add_sink"); - log_file - .call_wo(&log_fd.to_ne_bytes(), syscall::CallFlags::FD, &[]) - .expect("fbbootlogd: failed to send log fd to log scheme."); - } - - let _ = daemon.ready_sync_scheme(&socket, &mut scheme); - - // This is not possible for now as fbbootlogd needs to open new displays at runtime for graphics - // driver handoff. In the future inputd may directly pass a handle to the display instead. - //libredox::call::setrens(0, 0).expect("fbbootlogd: failed to enter null namespace"); - - for event in event_queue { - match event.expect("fbbootlogd: failed to get event").user_data { - Source::Scheme => loop { - match handler - .process_requests_nonblocking(&mut scheme) - .expect("fbbootlogd: failed to process requests") - { - ControlFlow::Continue(()) => {} - ControlFlow::Break(()) => break, - } - }, - Source::Input => { - let mut events = [Event::new(); 16]; - loop { - match scheme - .input_handle - .read_events(&mut events) - .expect("fbbootlogd: error while reading events") - { - ConsumerHandleEvent::Events(&[]) => break, - ConsumerHandleEvent::Events(events) => { - for event in events { - scheme.handle_input(&event); - } - } - ConsumerHandleEvent::Handoff => { - eprintln!("fbbootlogd: handoff requested"); - scheme.handle_handoff(); - } - } - } - } - } - } - - std::process::exit(0); -} diff --git a/recipes/core/base/drivers/graphics/fbbootlogd/src/scheme.rs b/recipes/core/base/drivers/graphics/fbbootlogd/src/scheme.rs deleted file mode 100644 index 812c4a5bc3..0000000000 --- a/recipes/core/base/drivers/graphics/fbbootlogd/src/scheme.rs +++ /dev/null @@ -1,244 +0,0 @@ -use std::cmp; -use std::collections::VecDeque; - -use console_draw::{Damage, TextScreen, V2DisplayMap}; -use drm::buffer::Buffer; -use drm::control::Device; -use graphics_ipc::V2GraphicsHandle; -use inputd::ConsumerHandle; -use orbclient::{Event, EventOption}; -use redox_scheme::scheme::SchemeSync; -use redox_scheme::{CallerCtx, OpenResult}; -use scheme_utils::FpathWriter; -use syscall::schemev2::NewFdFlags; -use syscall::{Error, Result, EACCES, EBADF, EINVAL, ENOENT}; - -pub struct FbbootlogScheme { - pub input_handle: ConsumerHandle, - display_map: Option, - text_screen: console_draw::TextScreen, - text_buffer: console_draw::TextBuffer, - is_scrollback: bool, - scrollback_offset: usize, - shift: bool, -} - -impl FbbootlogScheme { - pub fn new() -> FbbootlogScheme { - let mut scheme = FbbootlogScheme { - input_handle: ConsumerHandle::bootlog_vt().expect("fbbootlogd: Failed to open vt"), - display_map: None, - text_screen: console_draw::TextScreen::new(), - text_buffer: console_draw::TextBuffer::new(1000), - is_scrollback: false, - scrollback_offset: 1000, - shift: false, - }; - - scheme.handle_handoff(); - - scheme - } - - pub fn handle_handoff(&mut self) { - let new_display_handle = match self.input_handle.open_display_v2() { - Ok(display) => V2GraphicsHandle::from_file(display).unwrap(), - Err(err) => { - eprintln!("fbbootlogd: No display present yet: {err}"); - return; - } - }; - - match V2DisplayMap::new(new_display_handle) { - Ok(display_map) => self.display_map = Some(display_map), - Err(err) => { - eprintln!("fbbootlogd: failed to open display: {}", err); - return; - } - }; - - eprintln!("fbbootlogd: mapped display"); - } - - pub fn handle_input(&mut self, ev: &Event) { - match ev.to_option() { - EventOption::Key(key_event) => { - if key_event.scancode == 0x2A || key_event.scancode == 0x36 { - self.shift = key_event.pressed; - } else if !key_event.pressed || !self.shift { - return; - } - match key_event.scancode { - 0x48 => { - // Up - if self.scrollback_offset >= 1 { - self.scrollback_offset -= 1; - } - } - 0x49 => { - // Page up - if self.scrollback_offset >= 10 { - self.scrollback_offset -= 10; - } else { - self.scrollback_offset = 0; - } - } - 0x50 => { - // Down - self.scrollback_offset += 1; - } - 0x51 => { - // Page down - self.scrollback_offset += 10; - } - 0x47 => { - // Home - self.scrollback_offset = 0; - } - 0x4F => { - // End - self.scrollback_offset = self.text_buffer.lines_max; - } - _ => return, - } - } - _ => return, - } - self.handle_scrollback_render(); - } - - fn handle_scrollback_render(&mut self) { - let Some(map) = &mut self.display_map else { - return; - }; - let buffer_len = self.text_buffer.lines.len(); - // for both extra space on wrapping text and a scrollback indicator - let spare_lines = 3; - self.is_scrollback = true; - self.scrollback_offset = cmp::min( - self.scrollback_offset, - buffer_len - map.buffer.buffer().size().1 as usize / 16 + spare_lines, - ); - let mut i = self.scrollback_offset; - self.text_screen - .write(map, b"\x1B[1;1H\x1B[2J", &mut VecDeque::new()); - - let mut total_damage = Damage::NONE; - while i < buffer_len { - let mut damage = - self.text_screen - .write(map, &self.text_buffer.lines[i][..], &mut VecDeque::new()); - i += 1; - let yd = (damage.y + damage.height) as usize; - if i == buffer_len || yd + spare_lines * 16 > map.buffer.buffer().size().1 as usize { - // render until end of screen - damage.height = map.buffer.buffer().size().1 - damage.y; - total_damage = total_damage.merge(damage); - self.is_scrollback = i < buffer_len; - break; - } else { - total_damage = total_damage.merge(damage); - } - } - map.dirty_fb(total_damage).unwrap(); - } - - fn handle_resize(map: &mut V2DisplayMap, text_screen: &mut TextScreen) { - let mode = match map - .display_handle - .first_display() - .and_then(|handle| Ok(map.display_handle.get_connector(handle, true)?.modes()[0])) - { - Ok(mode) => mode, - Err(err) => { - eprintln!("fbbootlogd: failed to get display size: {}", err); - return; - } - }; - - if (u32::from(mode.size().0), u32::from(mode.size().1)) != map.buffer.buffer().size() { - match text_screen.resize(map, mode) { - Ok(()) => eprintln!("fbbootlogd: mapped display"), - Err(err) => { - eprintln!("fbbootlogd: failed to create or map framebuffer: {}", err); - return; - } - } - } - } -} - -const SCHEME_ROOT_ID: usize = 1; - -impl SchemeSync for FbbootlogScheme { - fn scheme_root(&mut self) -> Result { - Ok(SCHEME_ROOT_ID) - } - - fn openat( - &mut self, - dirfd: usize, - path_str: &str, - _flags: usize, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - if dirfd != SCHEME_ROOT_ID { - return Err(Error::new(EACCES)); - } - if !path_str.is_empty() { - return Err(Error::new(ENOENT)); - } - - Ok(OpenResult::ThisScheme { - number: 0, - flags: NewFdFlags::empty(), - }) - } - - fn fpath(&mut self, _id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with_legacy(buf, "fbbootlog", |_| Ok(())) - } - - fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> { - Ok(()) - } - - fn read( - &mut self, - _id: usize, - _buf: &mut [u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - Err(Error::new(EINVAL)) - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - if id == SCHEME_ROOT_ID { - return Err(Error::new(EBADF)); - } - if let Some(map) = &mut self.display_map { - Self::handle_resize(map, &mut self.text_screen); - self.text_buffer.write(buf); - - if !self.is_scrollback { - let damage = self.text_screen.write(map, buf, &mut VecDeque::new()); - - if let Some(map) = &mut self.display_map { - map.dirty_fb(damage).unwrap(); - } - } - } - - Ok(buf.len()) - } -} diff --git a/recipes/core/base/drivers/graphics/fbcond/Cargo.toml b/recipes/core/base/drivers/graphics/fbcond/Cargo.toml deleted file mode 100644 index ea9e2d6759..0000000000 --- a/recipes/core/base/drivers/graphics/fbcond/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "fbcond" -description = "Terminal daemon" -version = "0.1.0" -edition = "2021" - -[dependencies] -drm.workspace = true -log.workspace = true -orbclient.workspace = true -ransid.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true -redox-scheme.workspace = true -scheme-utils = { path = "../../../scheme-utils" } - -common = { path = "../../common" } -console-draw = { path = "../console-draw" } -daemon = { path = "../../../daemon" } -graphics-ipc = { path = "../graphics-ipc" } -inputd = { path = "../../inputd" } -libredox.workspace = true - -[features] -default = [] - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/graphics/fbcond/src/display.rs b/recipes/core/base/drivers/graphics/fbcond/src/display.rs deleted file mode 100644 index eb09b97e9c..0000000000 --- a/recipes/core/base/drivers/graphics/fbcond/src/display.rs +++ /dev/null @@ -1,83 +0,0 @@ -use console_draw::{Damage, TextScreen, V2DisplayMap}; -use drm::buffer::Buffer; -use drm::control::Device; -use graphics_ipc::V2GraphicsHandle; -use inputd::ConsumerHandle; -use std::io; - -pub struct Display { - pub input_handle: ConsumerHandle, - pub map: Option, -} - -impl Display { - pub fn open_new_vt() -> io::Result { - let mut display = Self { - input_handle: ConsumerHandle::new_vt()?, - map: None, - }; - - display.reopen_for_handoff(); - - Ok(display) - } - - /// Re-open the display after a handoff. - pub fn reopen_for_handoff(&mut self) { - let display_file = match self.input_handle.open_display_v2() { - Ok(display_file) => display_file, - Err(err) => { - log::error!("fbcond: No display present yet: {err}"); - return; - } - }; - let new_display_handle = V2GraphicsHandle::from_file(display_file).unwrap(); - - log::debug!("fbcond: Opened new display"); - - match V2DisplayMap::new(new_display_handle) { - Ok(map) => { - log::debug!( - "fbcond: Mapped new display with size {}x{}", - map.buffer.buffer().size().0, - map.buffer.buffer().size().1, - ); - self.map = Some(map) - } - Err(err) => { - log::error!("fbcond: failed to map new display: {err}"); - return; - } - } - } - - pub fn handle_resize(map: &mut V2DisplayMap, text_screen: &mut TextScreen) { - let mode = match map - .display_handle - .first_display() - .and_then(|handle| Ok(map.display_handle.get_connector(handle, true)?.modes()[0])) - { - Ok(mode) => mode, - Err(err) => { - eprintln!("fbcond: failed to get display size: {}", err); - return; - } - }; - - if (u32::from(mode.size().0), u32::from(mode.size().1)) != map.buffer.buffer().size() { - match text_screen.resize(map, mode) { - Ok(()) => eprintln!("fbcond: mapped display"), - Err(err) => { - eprintln!("fbcond: failed to create or map framebuffer: {}", err); - return; - } - } - } - } - - pub fn sync_rect(&mut self, damage: Damage) { - if let Some(map) = &mut self.map { - map.dirty_fb(damage).unwrap(); - } - } -} diff --git a/recipes/core/base/drivers/graphics/fbcond/src/main.rs b/recipes/core/base/drivers/graphics/fbcond/src/main.rs deleted file mode 100644 index eb4f9addb8..0000000000 --- a/recipes/core/base/drivers/graphics/fbcond/src/main.rs +++ /dev/null @@ -1,253 +0,0 @@ -use event::EventQueue; -use inputd::ConsumerHandleEvent; -use libredox::errno::{EAGAIN, EINTR}; -use orbclient::Event; -use redox_scheme::{ - scheme::{Op, SchemeResponse, SchemeState, SchemeSync}, - CallerCtx, RequestKind, Response, SignalBehavior, Socket, -}; -use std::env; -use syscall::{EOPNOTSUPP, EVENT_READ}; - -use crate::scheme::{FbconScheme, Handle, VtIndex}; - -mod display; -mod scheme; -mod text; - -fn main() { - daemon::SchemeDaemon::new(daemon); -} -fn daemon(daemon: daemon::SchemeDaemon) -> ! { - let vt_ids = env::args() - .skip(1) - .map(|arg| arg.parse().expect("invalid vt number")) - .collect::>(); - - common::setup_logging( - "graphics", - "fbcond", - "fbcond", - common::output_level(), - common::file_level(), - ); - let mut event_queue = EventQueue::new().expect("fbcond: failed to create event queue"); - - // FIXME listen for resize events from inputd and handle them - - let mut socket = Socket::nonblock().expect("fbcond: failed to create fbcon scheme"); - event_queue - .subscribe( - socket.inner().raw(), - VtIndex::SCHEMA_SENTINEL, - event::EventFlags::READ, - ) - .expect("fbcond: failed to subscribe to scheme events"); - - let mut state = SchemeState::new(); - let mut scheme = FbconScheme::new(&vt_ids, &mut event_queue); - - let _ = daemon.ready_sync_scheme(&socket, &mut scheme); - - // This is not possible for now as fbcond needs to open new displays at runtime for graphics - // driver handoff. In the future inputd may directly pass a handle to the display instead. - // libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace"); - - let mut blocked = Vec::new(); - - // Handle all events that could have happened before registering with the event queue. - handle_event( - &mut socket, - &mut scheme, - &mut state, - &mut blocked, - VtIndex::SCHEMA_SENTINEL, - ); - for vt_i in scheme.vts.keys().copied().collect::>() { - handle_event(&mut socket, &mut scheme, &mut state, &mut blocked, vt_i); - } - - for event in event_queue { - let event = event.expect("fbcond: failed to read event from event queue"); - handle_event( - &mut socket, - &mut scheme, - &mut state, - &mut blocked, - event.user_data, - ); - } - - std::process::exit(0); -} - -fn handle_event( - socket: &mut Socket, - scheme: &mut FbconScheme, - state: &mut SchemeState, - blocked: &mut Vec<(Op, CallerCtx)>, - event: VtIndex, -) { - match event { - VtIndex::SCHEMA_SENTINEL => loop { - let request = match socket.next_request(SignalBehavior::Restart) { - Ok(Some(request)) => request, - Ok(None) => { - // Scheme likely got unmounted - std::process::exit(0); - } - Err(err) if err.errno == EAGAIN => { - break; - } - Err(err) => panic!("fbcond: failed to read display scheme: {err}"), - }; - - match request.kind() { - RequestKind::Call(req) => { - let caller = req.caller(); - let mut op = match req.op() { - Ok(op) => op, - Err(req) => { - let _ = socket - .write_response( - Response::err(EOPNOTSUPP, req), - SignalBehavior::Restart, - ) - .expect("fbcond: failed to write responses to fbcon scheme"); - continue; - } - }; - match op.handle_sync_dont_consume(&caller, scheme, state) { - SchemeResponse::Opened(Err(e)) | SchemeResponse::Regular(Err(e)) - if libredox::error::Error::from(e).is_wouldblock() - && !op.is_explicitly_nonblock() => - { - blocked.push((op, caller)); - } - SchemeResponse::Regular(r) => { - let _ = socket - .write_response(Response::new(r, op), SignalBehavior::Restart) - .expect("fbcond: failed to write responses to fbcon scheme"); - } - SchemeResponse::Opened(o) => { - let _ = socket - .write_response( - Response::open_dup_like(o, op), - SignalBehavior::Restart, - ) - .expect("fbcond: failed to write responses to fbcon scheme"); - } - SchemeResponse::RegularAndNotifyOnDetach(status) => { - let _ = socket - .write_response( - Response::new_notify_on_detach(status, op), - SignalBehavior::Restart, - ) - .expect("fbcond: failed to write scheme"); - } - } - } - RequestKind::OnClose { id } => { - scheme.on_close(id); - } - RequestKind::Cancellation(cancellation_request) => { - if let Some(i) = blocked - .iter() - .position(|(_op, caller)| caller.id == cancellation_request.id) - { - let (blocked_req, _) = blocked.remove(i); - let resp = Response::err(EINTR, blocked_req); - socket - .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); - } - } - _ => {} - } - }, - vt_i => { - let vt = scheme.vts.get_mut(&vt_i).unwrap(); - - let mut events = [Event::new(); 16]; - loop { - match vt - .display - .input_handle - .read_events(&mut events) - .expect("fbcond: Error while reading events") - { - ConsumerHandleEvent::Events(&[]) => break, - - ConsumerHandleEvent::Events(events) => { - for event in events { - vt.input(event) - } - } - ConsumerHandleEvent::Handoff => vt.handle_handoff(), - } - } - } - } - - // If there are blocked readers, try to handle them. - { - let mut i = 0; - while i < blocked.len() { - let (op, caller) = blocked - .get_mut(i) - .expect("vesad: Failed to get blocked request"); - let resp = match op.handle_sync_dont_consume(&caller, scheme, state) { - SchemeResponse::Opened(Err(e)) | SchemeResponse::Regular(Err(e)) - if libredox::error::Error::from(e).is_wouldblock() - && !op.is_explicitly_nonblock() => - { - i += 1; - continue; - } - SchemeResponse::Regular(r) => { - let (op, _) = blocked.remove(i); - Response::new(r, op) - } - SchemeResponse::Opened(o) => { - let (op, _) = blocked.remove(i); - Response::open_dup_like(o, op) - } - SchemeResponse::RegularAndNotifyOnDetach(status) => { - let (op, _) = blocked.remove(i); - Response::new_notify_on_detach(status, op) - } - }; - let _ = socket - .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); - } - } - - for (handle_id, handle) in scheme.handles.iter_mut() { - let handle = match handle { - Handle::SchemeRoot => continue, - Handle::Vt(handle) => handle, - }; - - if !handle.events.contains(EVENT_READ) { - continue; - } - - let can_read = scheme - .vts - .get(&handle.vt_i) - .map_or(false, |console| console.can_read()); - - if can_read { - if !handle.notified_read { - handle.notified_read = true; - let response = Response::post_fevent(*handle_id, EVENT_READ.bits()); - socket - .write_response(response, SignalBehavior::Restart) - .expect("fbcond: failed to write display event"); - } - } else { - handle.notified_read = false; - } - } -} diff --git a/recipes/core/base/drivers/graphics/fbcond/src/scheme.rs b/recipes/core/base/drivers/graphics/fbcond/src/scheme.rs deleted file mode 100644 index 1bee134e29..0000000000 --- a/recipes/core/base/drivers/graphics/fbcond/src/scheme.rs +++ /dev/null @@ -1,193 +0,0 @@ -use std::collections::BTreeMap; -use std::os::fd::AsRawFd; - -use event::{EventQueue, UserData}; -use redox_scheme::scheme::SchemeSync; -use redox_scheme::{CallerCtx, OpenResult}; -use scheme_utils::{FpathWriter, HandleMap}; -use syscall::schemev2::NewFdFlags; -use syscall::{Error, EventFlags, Result, EACCES, EAGAIN, EBADF, ENOENT, O_NONBLOCK}; - -use crate::display::Display; -use crate::text::TextScreen; - -#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)] -pub struct VtIndex(usize); - -impl VtIndex { - pub const SCHEMA_SENTINEL: VtIndex = VtIndex(usize::MAX); -} - -impl UserData for VtIndex { - fn into_user_data(self) -> usize { - self.0 - } - - fn from_user_data(user_data: usize) -> Self { - VtIndex(user_data) - } -} - -pub struct FdHandle { - pub vt_i: VtIndex, - pub flags: usize, - pub events: EventFlags, - pub notified_read: bool, -} - -pub enum Handle { - Vt(FdHandle), - SchemeRoot, -} - -pub struct FbconScheme { - pub vts: BTreeMap, - pub handles: HandleMap, -} - -impl FbconScheme { - pub fn new(vt_ids: &[usize], event_queue: &mut EventQueue) -> FbconScheme { - let mut vts = BTreeMap::new(); - - for &vt_i in vt_ids { - let display = Display::open_new_vt().expect("Failed to open display for vt"); - event_queue - .subscribe( - display.input_handle.event_handle().as_raw_fd() as usize, - VtIndex(vt_i), - event::EventFlags::READ, - ) - .expect("Failed to subscribe to input events for vt"); - vts.insert(VtIndex(vt_i), TextScreen::new(display)); - } - - FbconScheme { - vts, - handles: HandleMap::new(), - } - } - - fn get_vt_handle_mut(&mut self, id: usize) -> Result<&mut FdHandle> { - match self.handles.get_mut(id)? { - Handle::Vt(handle) => Ok(handle), - Handle::SchemeRoot => Err(Error::new(EBADF)), - } - } -} - -impl SchemeSync for FbconScheme { - fn scheme_root(&mut self) -> Result { - Ok(self.handles.insert(Handle::SchemeRoot)) - } - - fn openat( - &mut self, - dirfd: usize, - path_str: &str, - flags: usize, - fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - if !matches!(self.handles.get(dirfd)?, Handle::SchemeRoot) { - return Err(Error::new(EACCES)); - } - - let vt_i = VtIndex(path_str.parse::().map_err(|_| Error::new(ENOENT))?); - if self.vts.contains_key(&vt_i) { - let id = self.handles.insert(Handle::Vt(FdHandle { - vt_i, - flags: flags | fcntl_flags as usize, - events: EventFlags::empty(), - notified_read: false, - })); - - Ok(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::empty(), - }) - } else { - Err(Error::new(ENOENT)) - } - } - - fn fevent( - &mut self, - id: usize, - flags: syscall::EventFlags, - _ctx: &CallerCtx, - ) -> Result { - let handle = self.get_vt_handle_mut(id)?; - - handle.notified_read = false; - handle.events = flags; - - Ok(syscall::EventFlags::empty()) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with_legacy(buf, "fbcon", |w| { - let handle = self.get_vt_handle_mut(id)?; - write!(w, "{}", handle.vt_i.0).unwrap(); - Ok(()) - }) - } - - fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> { - let _handle = self.get_vt_handle_mut(id)?; - Ok(()) - } - - fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result { - self.handles.get(id)?; - Ok(0) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - let handle = match self.handles.get(id)? { - Handle::Vt(handle) => Ok(handle), - Handle::SchemeRoot => Err(Error::new(EBADF)), - }?; - - if let Some(screen) = self.vts.get_mut(&handle.vt_i) { - if !screen.can_read() { - if handle.flags & O_NONBLOCK != 0 { - Err(Error::new(EAGAIN)) - } else { - Err(Error::new(EAGAIN)) - } - } else { - screen.read(buf) - } - } else { - Err(Error::new(EBADF)) - } - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - let vt_i = self.get_vt_handle_mut(id)?.vt_i; - - if let Some(console) = self.vts.get_mut(&vt_i) { - console.write(buf) - } else { - Err(Error::new(EBADF)) - } - } - - fn on_close(&mut self, id: usize) { - self.handles.remove(id); - } -} diff --git a/recipes/core/base/drivers/graphics/fbcond/src/text.rs b/recipes/core/base/drivers/graphics/fbcond/src/text.rs deleted file mode 100644 index 8a24bbebe6..0000000000 --- a/recipes/core/base/drivers/graphics/fbcond/src/text.rs +++ /dev/null @@ -1,134 +0,0 @@ -use std::collections::VecDeque; - -use orbclient::{Event, EventOption}; -use syscall::error::*; - -use crate::display::Display; - -pub struct TextScreen { - pub display: Display, - inner: console_draw::TextScreen, - ctrl: bool, - input: VecDeque, -} - -impl TextScreen { - pub fn new(display: Display) -> TextScreen { - TextScreen { - display, - inner: console_draw::TextScreen::new(), - ctrl: false, - input: VecDeque::new(), - } - } - - pub fn handle_handoff(&mut self) { - log::info!("fbcond: Performing handoff"); - self.display.reopen_for_handoff(); - } - - pub fn input(&mut self, event: &Event) { - let mut buf = vec![]; - - match event.to_option() { - EventOption::Key(key_event) => { - if key_event.scancode == 0x1D { - self.ctrl = key_event.pressed; - } else if key_event.pressed { - match key_event.scancode { - 0x0E => { - // Backspace - buf.extend_from_slice(b"\x7F"); - } - 0x47 => { - // Home - buf.extend_from_slice(b"\x1B[H"); - } - 0x48 => { - // Up - buf.extend_from_slice(b"\x1B[A"); - } - 0x49 => { - // Page up - buf.extend_from_slice(b"\x1B[5~"); - } - 0x4B => { - // Left - buf.extend_from_slice(b"\x1B[D"); - } - 0x4D => { - // Right - buf.extend_from_slice(b"\x1B[C"); - } - 0x4F => { - // End - buf.extend_from_slice(b"\x1B[F"); - } - 0x50 => { - // Down - buf.extend_from_slice(b"\x1B[B"); - } - 0x51 => { - // Page down - buf.extend_from_slice(b"\x1B[6~"); - } - 0x52 => { - // Insert - buf.extend_from_slice(b"\x1B[2~"); - } - 0x53 => { - // Delete - buf.extend_from_slice(b"\x1B[3~"); - } - _ => { - let c = match key_event.character { - c @ 'A'..='Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char, - c @ 'a'..='z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char, - c => c, - }; - - if c != '\0' { - let mut b = [0; 4]; - buf.extend_from_slice(c.encode_utf8(&mut b).as_bytes()); - } - } - } - } - } - _ => (), //TODO: Mouse in terminal - } - - for &b in buf.iter() { - self.input.push_back(b); - } - } - - pub fn can_read(&self) -> bool { - !self.input.is_empty() - } -} - -impl TextScreen { - pub fn read(&mut self, buf: &mut [u8]) -> Result { - let mut i = 0; - - while i < buf.len() && !self.input.is_empty() { - buf[i] = self.input.pop_front().unwrap(); - i += 1; - } - - Ok(i) - } - - pub fn write(&mut self, buf: &[u8]) -> Result { - if let Some(map) = &mut self.display.map { - Display::handle_resize(map, &mut self.inner); - - let damage = self.inner.write(map, buf, &mut self.input); - - self.display.sync_rect(damage); - } - - Ok(buf.len()) - } -} diff --git a/recipes/core/base/drivers/graphics/graphics-ipc/Cargo.toml b/recipes/core/base/drivers/graphics/graphics-ipc/Cargo.toml deleted file mode 100644 index edeb40f80d..0000000000 --- a/recipes/core/base/drivers/graphics/graphics-ipc/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "graphics-ipc" -description = "Shared graphics IPC code library" -version = "0.1.0" -edition = "2021" - -[dependencies] -drm.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/graphics/graphics-ipc/src/lib.rs b/recipes/core/base/drivers/graphics/graphics-ipc/src/lib.rs deleted file mode 100644 index 285b304372..0000000000 --- a/recipes/core/base/drivers/graphics/graphics-ipc/src/lib.rs +++ /dev/null @@ -1,127 +0,0 @@ -use std::fs::File; -use std::os::fd::{AsFd, BorrowedFd}; -use std::{io, mem, ptr}; - -use drm::buffer::Buffer; -use drm::control::connector::{self, State}; -use drm::control::dumbbuffer::{DumbBuffer, DumbMapping}; -use drm::control::Device as _; -use drm::{Device as _, DriverCapability}; - -/// A graphics handle using the v2 graphics API. -/// -/// The v2 graphics API allows creating framebuffers on the fly, using them for page flipping and -/// handles all displays using a single fd. This is basically a subset of the Linux DRM interface -/// with a couple of custom ioctls in the place of the KMS ioctls that are missing. -pub struct V2GraphicsHandle { - file: File, -} - -impl AsFd for V2GraphicsHandle { - fn as_fd(&self) -> BorrowedFd<'_> { - self.file.as_fd() - } -} - -impl drm::Device for V2GraphicsHandle {} -impl drm::control::Device for V2GraphicsHandle {} - -impl V2GraphicsHandle { - pub fn from_file(file: File) -> io::Result { - let handle = V2GraphicsHandle { file }; - assert!(handle.get_driver_capability(DriverCapability::DumbBuffer)? == 1); - Ok(handle) - } - - pub fn first_display(&self) -> io::Result { - for &connector in self.resource_handles().unwrap().connectors() { - if self.get_connector(connector, true)?.state() == State::Connected { - return Ok(connector); - } - } - Err(io::Error::other("no connected display")) - } -} - -pub struct CpuBackedBuffer { - buffer: DumbBuffer, - map: DumbMapping<'static>, - shadow: Option>, -} - -impl CpuBackedBuffer { - pub fn new( - display_handle: &V2GraphicsHandle, - size: (u32, u32), - format: drm::buffer::DrmFourcc, - bpp: u32, - ) -> io::Result { - let mut buffer = display_handle.create_dumb_buffer(size, format, bpp)?; - - let map = display_handle.map_dumb_buffer(&mut buffer)?; - let map = unsafe { mem::transmute::, DumbMapping<'static>>(map) }; - - let shadow = if display_handle - .get_driver_capability(DriverCapability::DumbPreferShadow) - .unwrap_or(1) - == 0 - { - None - } else { - Some(vec![0; map.len()].into_boxed_slice()) - }; - - Ok(CpuBackedBuffer { - buffer, - map, - shadow, - }) - } - - pub fn buffer(&self) -> &DumbBuffer { - &self.buffer - } - - pub fn has_shadow_buf(&self) -> bool { - self.shadow.is_some() - } - - pub fn shadow_buf(&mut self) -> &mut [u8] { - self.shadow.as_deref_mut().unwrap_or(&mut *self.map) - } - - pub fn sync_rect(&mut self, x: u32, y: u32, width: u32, height: u32) { - let Some(shadow) = &self.shadow else { - return; // No shadow buffer; all writes are already propagated to the GPU. - }; - - assert!(x.checked_add(width).unwrap() <= self.buffer.size().0); - assert!(y.checked_add(height).unwrap() <= self.buffer.size().1); - - let start_x: usize = x.try_into().unwrap(); - let start_y: usize = y.try_into().unwrap(); - let w: usize = width.try_into().unwrap(); - let h: usize = height.try_into().unwrap(); - - let offscreen_ptr = shadow.as_ptr().cast::(); - let onscreen_ptr = self.map.as_mut_ptr().cast::(); - - for row in start_y..start_y + h { - unsafe { - ptr::copy_nonoverlapping( - offscreen_ptr.add(row * self.buffer.pitch() as usize / 4 + start_x), - onscreen_ptr.add(row * self.buffer.pitch() as usize / 4 + start_x), - w, - ); - } - } - - // No need for a wbinvd to flush the write combining writes as they are - // already flushed on the next syscall anyway. And the user will need - // to do a DRM ioctl to actually present the changes on the display. - } - - pub fn destroy(self, display_handle: &V2GraphicsHandle) -> io::Result<()> { - display_handle.destroy_dumb_buffer(self.buffer) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/Cargo.toml b/recipes/core/base/drivers/graphics/ihdgd/Cargo.toml deleted file mode 100644 index 25d04eac8b..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "ihdgd" -description = "Intel graphics driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -bitbang-hal = "0.3" -drm-sys.workspace = true -edid.workspace = true #TODO: edid is abandoned, fork it and maintain? -#TODO: waiting for bitbang-hal to update to embedded-hal 1.0 -embedded-hal = { version = "0.2.7", features = ["unproven"] } -log.workspace = true -nb = "1.0" -# Patched to allow for exact range allocation -range-alloc = { git = "https://github.com/jackpot51/range-alloc.git" } -void = "1.0" - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-graphics = { path = "../driver-graphics" } -pcid = { path = "../../pcid" } - -libredox.workspace = true -redox-scheme.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/graphics/ihdgd/config.toml b/recipes/core/base/drivers/graphics/ihdgd/config.toml deleted file mode 100644 index acbb4e7879..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/config.toml +++ /dev/null @@ -1,55 +0,0 @@ -[[drivers]] -name = "Intel HD Graphics" -class = 0x03 -ids = { 0x8086 = [ - # Kaby Lake from Volume 4: Configurations in - # https://www.intel.com/content/www/us/en/docs/graphics-for-linux/developer-reference/1-0/kaby-lake.html - 0x5912, - 0x5916, - 0x591B, - 0x591E, - 0x5926, - # Comet Lake from Volume 1: Configurations in - # https://www.intel.com/content/www/us/en/docs/graphics-for-linux/developer-reference/1-0/comet-lake.html - 0x9B21, - 0x9B41, - 0x9BA4, - 0x9BAA, - 0x9BAC, - 0x9BC4, - 0x9BC5, - 0x9BC6, - 0x9BC8, - 0x9BCA, - 0x9BCC, - 0x9BE6, - 0x9BF6, - # Tiger Lake Mobile from Volume 4: Configurations in - # https://www.intel.com/content/www/us/en/docs/graphics-for-linux/developer-reference/1-0/tiger-lake.html - 0x9A40, - 0x9A49, - 0x9A60, - 0x9A68, - 0x9A70, - 0x9A78, - # Alchemist from Volume 4: Configurations in - # https://www.intel.com/content/www/us/en/docs/graphics-for-linux/developer-reference/1-0/alchemist-arctic-sound-m.html - 0x5690, # A770M - 0x5691, # A730M - 0x5692, # A550M - 0x5693, # A370M - 0x5694, # A350M - 0x5696, # A570M - 0x5697, # A530M - 0x56A0, # A770 - 0x56A1, # A750 - 0x56A5, # A380 - 0x56A6, # A310 - 0x56B0, # Pro A30M - 0x56B1, # Pro A40/A50 - 0x56B2, # Pro A60M - 0x56B3, # Pro A60 - 0x56C0, # GPU Flex 170 - 0x56C1, # GPU Flex 140 -] } -command = ["ihdgd"] diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/aux.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/aux.rs deleted file mode 100644 index 5a33f516d2..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/aux.rs +++ /dev/null @@ -1,169 +0,0 @@ -use common::{io::Io, timeout::Timeout}; -use embedded_hal::blocking::i2c::{self, Operation, SevenBitAddress, Transactional}; - -use super::ddi::*; - -pub struct Aux<'a> { - ddi: &'a mut Ddi, -} - -impl<'a> Aux<'a> { - pub fn new(ddi: &'a mut Ddi) -> Self { - Self { ddi } - } -} - -impl<'a> Transactional for Aux<'a> { - type Error = (); - fn exec(&mut self, addr7: SevenBitAddress, full_ops: &mut [Operation<'_>]) -> Result<(), ()> { - // Break ops into 16-byte chunks that will fit into aux data - let mut ops = Vec::new(); - for op in full_ops.iter_mut() { - match op { - Operation::Read(buf) => { - for chunk in buf.chunks_mut(16) { - ops.push(Operation::Read(chunk)); - } - } - Operation::Write(buf) => { - for chunk in buf.chunks(16) { - ops.push(Operation::Write(chunk)); - } - } - } - } - - let ops_len = ops.len(); - for (i, op) in ops.iter_mut().enumerate() { - // Write header and data - let mut header = 0; - match op { - Operation::Read(_) => { - header |= 1 << 4; - } - Operation::Write(_) => (), - } - if (i + 1) < ops_len { - // Middle of transaction - header |= 1 << 6; - } - let mut aux_datas = [0u8; 20]; - let mut aux_data_i = 0; - aux_datas[aux_data_i] = header; - aux_data_i += 1; - //TODO: what is this byte? - aux_datas[aux_data_i] = 0; - aux_data_i += 1; - aux_datas[aux_data_i] = addr7; - aux_data_i += 1; - match op { - Operation::Read(buf) => { - if !buf.is_empty() { - aux_datas[aux_data_i] = (buf.len() - 1) as u8; - aux_data_i += 1; - } - } - Operation::Write(buf) => { - if !buf.is_empty() { - aux_datas[aux_data_i] = (buf.len() - 1) as u8; - aux_data_i += 1; - for b in buf.iter() { - aux_datas[aux_data_i] = *b; - aux_data_i += 1; - } - } - } - } - - // Write data to registers (big endian, dword access only) - for (i, chunk) in aux_datas.chunks(4).enumerate() { - let mut bytes = [0; 4]; - bytes[..chunk.len()].copy_from_slice(&chunk); - self.ddi.aux_datas[i].write(u32::from_be_bytes(bytes)); - } - - let mut v = self.ddi.aux_ctl.read(); - // Set length - v &= !DDI_AUX_CTL_SIZE_MASK; - v |= (aux_data_i as u32) << DDI_AUX_CTL_SIZE_SHIFT; - // Set timeout - v &= !DDI_AUX_CTL_TIMEOUT_MASK; - v |= DDI_AUX_CTL_TIMEOUT_4000US; - // Set I/O select to legacy (cleared) - //TODO: TBT support? - v &= !DDI_AUX_CTL_IO_SELECT; - // Start transaction - v |= DDI_AUX_CTL_BUSY; - self.ddi.aux_ctl.write(v); - - // Wait while busy - let timeout = Timeout::from_secs(1); - while self.ddi.aux_ctl.readf(DDI_AUX_CTL_BUSY) { - timeout.run().map_err(|()| { - log::debug!( - "AUX I2C transaction wait timeout 0x{:08X}", - self.ddi.aux_ctl.read() - ); - () - })?; - } - - // Read result - v = self.ddi.aux_ctl.read(); - if (v & DDI_AUX_CTL_TIMEOUT_ERROR) != 0 { - log::debug!("AUX I2C transaction timeout error"); - return Err(()); - } - if (v & DDI_AUX_CTL_RECEIVE_ERROR) != 0 { - log::debug!("AUX I2C transaction receive error"); - return Err(()); - } - if (v & DDI_AUX_CTL_DONE) == 0 { - log::debug!("AUX I2C transaction done not set"); - return Err(()); - } - - // Read data from registers (big endian, dword access only) - for (i, chunk) in aux_datas.chunks_mut(4).enumerate() { - let bytes = self.ddi.aux_datas[i].read().to_be_bytes(); - chunk.copy_from_slice(&bytes[..chunk.len()]); - } - - aux_data_i = 0; - let response = aux_datas[aux_data_i]; - if response != 0 { - log::debug!("AUX I2C unexpected response {:02X}", response); - return Err(()); - } - aux_data_i += 1; - match op { - Operation::Read(buf) => { - if !buf.is_empty() { - for b in buf.iter_mut() { - *b = aux_datas[aux_data_i]; - aux_data_i += 1; - } - } - } - Operation::Write(_) => (), - } - } - - Ok(()) - } -} - -impl<'a> i2c::WriteRead for Aux<'a> { - type Error = (); - fn write_read( - &mut self, - addr7: SevenBitAddress, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result<(), ()> { - self.exec( - addr7, - &mut [Operation::Write(bytes), Operation::Read(buffer)], - ) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/bios.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/bios.rs deleted file mode 100644 index cd19af07be..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/bios.rs +++ /dev/null @@ -1,233 +0,0 @@ -use common::io::{Io, Mmio, ReadOnly}; -use std::mem; -use syscall::error::{Error, Result, EIO}; - -use super::MmioRegion; - -const MBOX_VBT: u32 = 1 << 3; - -fn read_bios_string(array: &[ReadOnly>]) -> String { - let mut string = String::new(); - for reg in array.iter() { - let b = reg.read(); - if b == 0 { - break; - } - string.push(b as char); - } - string -} - -#[repr(C, packed)] -pub struct BiosHeader { - signature: [ReadOnly>; 16], - size: ReadOnly>, - struct_version: ReadOnly>, - system_bios_version: [ReadOnly>; 32], - video_bios_version: [ReadOnly>; 16], - //TODO: should we write graphics driver version? - graphics_driver_version: [ReadOnly>; 16], - mailboxes: ReadOnly>, - driver_model: Mmio, - platform_config: ReadOnly>, - gop_version: [ReadOnly>; 32], -} - -impl BiosHeader { - pub fn dump(&self) { - eprint!(" op region header"); - eprint!(" signature {:?}", read_bios_string(&self.signature)); - eprint!(" size {:08X}", self.size.read()); - eprint!(" struct_version {:08X}", self.struct_version.read()); - eprint!( - " system_bios_version {:?}", - read_bios_string(&self.system_bios_version) - ); - eprint!( - " video_bios_version {:?}", - read_bios_string(&self.video_bios_version) - ); - eprint!( - " graphics_driver_version {:?}", - read_bios_string(&self.graphics_driver_version) - ); - eprint!(" mailboxes {:08X}", self.mailboxes.read()); - eprint!(" driver_model {:08X}", self.driver_model.read()); - eprint!(" platform_config {:08X}", self.platform_config.read()); - eprint!(" gop_version {:?}", read_bios_string(&self.gop_version)); - eprintln!(); - } -} - -#[repr(C, packed)] -pub struct VbtHeader { - signature: [ReadOnly>; 20], - version: Mmio, - header_size: Mmio, - vbt_size: Mmio, - vbt_checksum: Mmio, - _rsvd: Mmio, - bdb_offset: Mmio, - aim_offsets: [Mmio; 4], -} - -impl VbtHeader { - pub fn dump(&self) { - eprint!(" VBT header"); - eprint!(" signature {:?}", read_bios_string(&self.signature)); - eprint!(" version {:04X}", self.version.read()); - eprint!(" header_size {:04X}", self.header_size.read()); - eprint!(" vbt_size {:04X}", self.vbt_size.read()); - eprint!(" vbt_checksum {:02X}", self.vbt_checksum.read()); - eprint!(" bdb_offset {:08X}", self.bdb_offset.read()); - for (i, aim_offset) in self.aim_offsets.iter().enumerate() { - eprint!(" aim_offset{} {:08X}", i, aim_offset.read()); - } - eprintln!(); - } -} - -#[repr(C, packed)] -pub struct BdbHeader { - signature: [ReadOnly>; 16], - version: Mmio, - header_size: Mmio, - bdb_size: Mmio, -} - -impl BdbHeader { - pub fn dump(&self) { - eprint!(" BDB header"); - eprint!(" signature {:?}", read_bios_string(&self.signature)); - eprint!(" version {:04X}", self.version.read()); - eprint!(" header_size {:04X}", self.header_size.read()); - eprint!(" bdb_size {:04X}", self.bdb_size.read()); - eprintln!(); - } -} - -#[repr(C, packed)] -pub struct BdbBlock { - id: Mmio, - size: Mmio, -} - -impl BdbBlock { - pub fn dump(&self) { - eprint!(" BDB block"); - eprint!(" id {}", self.id.read()); - eprint!(" size {}", self.size.read()); - eprintln!(); - } -} - -#[repr(C, packed)] -pub struct BdbGeneralDefinitions { - crt_ddc_gmbus_pin: Mmio, - dpms: Mmio, - boot_displays: [Mmio; 2], - child_dev_size: Mmio, -} - -impl BdbGeneralDefinitions { - pub fn dump(&self) { - eprint!(" BDB general definitions"); - eprint!(" crt_ddc_gmbus_pin {:02X}", self.crt_ddc_gmbus_pin.read()); - eprint!(" dpms {:02X}", self.dpms.read()); - for (i, boot_display) in self.boot_displays.iter().enumerate() { - eprint!(" boot_display{} {:02X}", i, boot_display.read()); - } - eprint!(" child_dev_size {:02X}", self.child_dev_size.read()); - eprintln!(); - } -} - -pub struct Bios { - region: MmioRegion, - header: &'static mut BiosHeader, -} - -impl Bios { - pub fn new(region: MmioRegion) -> Result { - let header = unsafe { &mut *(region.virt as *mut BiosHeader) }; - header.dump(); - - { - let sig = read_bios_string(&header.signature); - if sig != "IntelGraphicsMem" { - log::warn!("invalid op region signature {:?}", sig); - return Err(Error::new(EIO)); - } - } - - let size = (header.size.read() as usize) * 1024; - if size != region.size { - log::warn!("invalid op region size {}", size); - return Err(Error::new(EIO)); - } - - //TODO: other mailboxes? - - if header.mailboxes.read() & MBOX_VBT == 0 { - log::warn!("op region does not support VBT mailbox"); - return Err(Error::new(EIO)); - } - - //TODO: read VBT from mailbox 3 RVDA (0x3BA) and RVDS (0x3C2) if missing in mailbox 4 - let vbt_addr = region.virt + 1024; - let vbt_header = unsafe { &*(vbt_addr as *const VbtHeader) }; - vbt_header.dump(); - - //TODO: check vbt checksum - { - let sig = read_bios_string(&vbt_header.signature); - if !sig.starts_with("$VBT") { - log::warn!("invalid VBT signature {:?}", sig); - return Err(Error::new(EIO)); - } - } - - let bdb_addr = vbt_addr + (vbt_header.bdb_offset.read() as usize); - let bdb_header = unsafe { &*(bdb_addr as *const BdbHeader) }; - bdb_header.dump(); - { - let sig = read_bios_string(&bdb_header.signature); - if sig != "BIOS_DATA_BLOCK " { - log::warn!("invalid BDB signature {:?}", sig); - bdb_header.dump(); - return Err(Error::new(EIO)); - } - } - - let mut block_addr = bdb_addr + bdb_header.header_size.read() as usize; - let block_end = bdb_addr + bdb_header.bdb_size.read() as usize; - while block_addr + mem::size_of::() <= block_end { - let block = unsafe { &*(block_addr as *const BdbBlock) }; - //TODO: mipi sequence v3 has different size field - let id = block.id.read(); - let size = block.size.read() as usize; - block_addr += mem::size_of::(); - if block_addr + size <= block_end { - match id { - 2 => { - if size >= mem::size_of::() { - let gen_defs = - unsafe { &*(block_addr as *const BdbGeneralDefinitions) }; - gen_defs.dump(); - } else { - log::warn!("BDB general definitions too small"); - block.dump(); - } - } - _ => block.dump(), - } - block_addr += block.size.read() as usize; - } else { - log::warn!("truncated block id {} size {}", id, size); - break; - } - } - - Ok(Self { region, header }) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/buffer.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/buffer.rs deleted file mode 100644 index 4ffbc8937f..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/buffer.rs +++ /dev/null @@ -1,46 +0,0 @@ -use std::{ptr, slice}; - -use crate::device::ggtt::GlobalGtt; -use crate::device::MmioRegion; - -#[derive(Debug)] -pub struct GpuBuffer { - pub virt: *mut u8, - pub gm_offset: u32, - pub size: u32, -} - -impl GpuBuffer { - pub unsafe fn new(gm: &MmioRegion, gm_offset: u32, size: u32, clear: bool) -> Self { - let virt = ptr::with_exposed_provenance_mut::(gm.virt + gm_offset as usize); - - if clear { - let onscreen = slice::from_raw_parts_mut(virt, size as usize); - onscreen.fill(0); - } - - Self { - virt, - gm_offset, - size, - } - } - - pub fn alloc(gm: &MmioRegion, ggtt: &mut GlobalGtt, size: u32) -> syscall::Result { - let gm_offset = ggtt.alloc_phys_mem(size)?; - - Ok(unsafe { GpuBuffer::new(gm, gm_offset, size, true) }) - } - - pub fn alloc_dumb( - gm: &MmioRegion, - ggtt: &mut GlobalGtt, - width: u32, - height: u32, - ) -> syscall::Result<(Self, u32)> { - //TODO: documentation on this is not great - let stride = (width * 4).next_multiple_of(64); - - Ok((GpuBuffer::alloc(gm, ggtt, stride * height)?, stride)) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/ddi.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/ddi.rs deleted file mode 100644 index ac4ce1bd87..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/ddi.rs +++ /dev/null @@ -1,758 +0,0 @@ -use common::io::{Io, MmioPtr, WriteOnly}; -use common::timeout::Timeout; -use embedded_hal::prelude::*; -use std::sync::Arc; -use syscall::error::{Error, Result, EIO}; - -use crate::device::aux::Aux; -use crate::device::power::PowerWells; -use crate::device::{CallbackGuard, Gmbus}; - -use super::{GpioPort, MmioRegion}; - -// IHD-OS-TGL-Vol 2c-12.21 DDI_AUX_CTL -pub const DDI_AUX_CTL_BUSY: u32 = 1 << 31; -pub const DDI_AUX_CTL_DONE: u32 = 1 << 30; -pub const DDI_AUX_CTL_TIMEOUT_ERROR: u32 = 1 << 28; -pub const DDI_AUX_CTL_TIMEOUT_SHIFT: u32 = 26; -pub const DDI_AUX_CTL_TIMEOUT_MASK: u32 = 0b11 << DDI_AUX_CTL_TIMEOUT_SHIFT; -pub const DDI_AUX_CTL_TIMEOUT_4000US: u32 = 0b11 << DDI_AUX_CTL_TIMEOUT_SHIFT; -pub const DDI_AUX_CTL_RECEIVE_ERROR: u32 = 1 << 25; -pub const DDI_AUX_CTL_SIZE_SHIFT: u32 = 20; -pub const DDI_AUX_CTL_SIZE_MASK: u32 = 0b11111 << 20; -pub const DDI_AUX_CTL_IO_SELECT: u32 = 1 << 11; - -// IHD-OS-TGL-Vol 2c-12.21 DDI_BUF_CTL -pub const DDI_BUF_CTL_ENABLE: u32 = 1 << 31; -pub const DDI_BUF_CTL_IDLE: u32 = 1 << 7; - -// IHD-OS-TGL-Vol 2c-12.21 PORT_CL_DW5 -pub const PORT_CL_DW5_SUS_CLOCK_MASK: u32 = 0b11 << 0; - -// IHD-OS-TGL-Vol 2c-12.21 PORT_CL_DW10 -pub const PORT_CL_DW10_EDP4K2K_MODE_OVRD_EN: u32 = 1 << 3; -pub const PORT_CL_DW10_EDP4K2K_MODE_OVRD_VAL: u32 = 1 << 2; - -// IHD-OS-TGL-Vol 2c-12.21 PORT_PCS_DW9 -pub const PORT_PCS_DW1_CMNKEEPER_ENABLE: u32 = 1 << 26; - -// IHD-OS-TGL-Vol 2c-12.21 PORT_TX_DW2 -pub const PORT_TX_DW2_SWING_SEL_UPPER_SHIFT: u32 = 15; -pub const PORT_TX_DW2_SWING_SEL_UPPER_MASK: u32 = 1 << PORT_TX_DW2_SWING_SEL_UPPER_SHIFT; -pub const PORT_TX_DW2_SWING_SEL_LOWER_SHIFT: u32 = 11; -pub const PORT_TX_DW2_SWING_SEL_LOWER_MASK: u32 = 0b111 << PORT_TX_DW2_SWING_SEL_LOWER_SHIFT; -pub const PORT_TX_DW2_RCOMP_SCALAR_SHIFT: u32 = 0; -pub const PORT_TX_DW2_RCOMP_SCALAR_MASK: u32 = 0xFF << PORT_TX_DW2_RCOMP_SCALAR_SHIFT; - -// IHD-OS-TGL-Vol 2c-12.21 PORT_TX_DW4 -pub const PORT_TX_DW4_SELECT: u32 = 1 << 31; -pub const PORT_TX_DW4_POST_CURSOR_1_SHIFT: u32 = 12; -pub const PORT_TX_DW4_POST_CURSOR_1_MASK: u32 = 0b111111 << PORT_TX_DW4_POST_CURSOR_1_SHIFT; -pub const PORT_TX_DW4_POST_CURSOR_2_SHIFT: u32 = 6; -pub const PORT_TX_DW4_POST_CURSOR_2_MASK: u32 = 0b111111 << PORT_TX_DW4_POST_CURSOR_2_SHIFT; -pub const PORT_TX_DW4_CURSOR_COEFF_SHIFT: u32 = 0; -pub const PORT_TX_DW4_CURSOR_COEFF_MASK: u32 = 0b111111 << PORT_TX_DW4_CURSOR_COEFF_SHIFT; - -// IHD-OS-TGL-Vol 2c-12.21 PORT_TX_DW5 -pub const PORT_TX_DW5_TRAINING_ENABLE: u32 = 1 << 31; -pub const PORT_TX_DW5_DISABLE_2_TAP_SHIFT: u32 = 29; -pub const PORT_TX_DW5_DISABLE_2_TAP: u32 = 1 << PORT_TX_DW5_DISABLE_2_TAP_SHIFT; -pub const PORT_TX_DW5_DISABLE_3_TAP: u32 = 1 << 29; -pub const PORT_TX_DW5_CURSOR_PROGRAM: u32 = 1 << 26; -pub const PORT_TX_DW5_COEFF_POLARITY: u32 = 1 << 25; -pub const PORT_TX_DW5_SCALING_MODE_SEL_SHIFT: u32 = 18; -pub const PORT_TX_DW5_SCALING_MODE_SEL_MASK: u32 = 0b111 << PORT_TX_DW5_SCALING_MODE_SEL_SHIFT; -pub const PORT_TX_DW5_RTERM_SELECT_SHIFT: u32 = 3; -pub const PORT_TX_DW5_RTERM_SELECT_MASK: u32 = 0b111 << PORT_TX_DW5_RTERM_SELECT_SHIFT; - -// IHD-OS-TGL-Vol 2c-12.21 PORT_TX_DW7 -pub const PORT_TX_DW7_N_SCALAR_SHIFT: u32 = 24; - -#[derive(Clone, Copy, Debug)] -#[repr(usize)] -pub enum PortClReg { - Dw5 = 0x14, - Dw10 = 0x28, - Dw12 = 0x30, - Dw15 = 0x3C, - Dw16 = 0x40, -} - -#[derive(Clone, Copy, Debug)] -#[repr(usize)] -pub enum PortCompReg { - Dw0 = 0x100, - Dw1 = 0x104, - Dw3 = 0x10C, - Dw8 = 0x120, - Dw9 = 0x124, - Dw10 = 0x128, -} - -#[derive(Clone, Copy, Debug)] -#[repr(usize)] -pub enum PortPcsReg { - Dw1 = 0x04, - Dw9 = 0x24, -} - -#[derive(Clone, Copy, Debug)] -#[repr(usize)] -pub enum PortTxReg { - Dw0 = 0x80, - Dw1 = 0x84, - Dw2 = 0x88, - Dw4 = 0x90, - Dw5 = 0x94, - Dw6 = 0x98, - Dw7 = 0x9C, - Dw8 = 0xA0, -} - -#[derive(Clone, Copy, Debug)] -#[repr(usize)] -pub enum PortLane { - Aux = 0x300, - Grp = 0x600, - Ln0 = 0x800, - Ln1 = 0x900, - Ln2 = 0xA00, - Ln3 = 0xB00, -} - -pub struct Ddi { - pub name: &'static str, - pub index: usize, - pub gttmm: Arc, - pub port_base: Option, - pub aux_ctl: MmioPtr, - pub aux_datas: [MmioPtr; 5], - pub buf_ctl: MmioPtr, - pub dpclka_cfgcr0_clock_shift: Option, - pub dpclka_cfgcr0_clock_off: Option, - pub gmbus_pin_pair: Option, - pub gpio_port: Option, - pub pwr_well_ctl_aux_request: u32, - pub pwr_well_ctl_aux_state: u32, - pub pwr_well_ctl_ddi_request: u32, - pub pwr_well_ctl_ddi_state: u32, - pub sde_interrupt_hotplug: Option, - pub transcoder_index: Option, -} - -//TODO: verify offsets and count using DeviceKind? -impl Ddi { - pub fn dump(&self) { - eprint!("Ddi {} {}", self.name, self.index); - eprint!(" buf_ctl {:08X}", self.buf_ctl.read()); - let lanes = [PortLane::Ln0, PortLane::Ln1, PortLane::Ln2, PortLane::Ln3]; - for reg in [ - PortClReg::Dw5, - PortClReg::Dw10, - PortClReg::Dw12, - PortClReg::Dw15, - PortClReg::Dw16, - ] { - if let Some(mmio) = self.port_cl(reg) { - eprint!(" CL_{:?} {:08X}", reg, mmio.read()); - } - } - for reg in [PortPcsReg::Dw1, PortPcsReg::Dw9] { - for lane in lanes { - if let Some(mmio) = self.port_pcs(reg, lane) { - eprint!(" PCS_{:?}_{:?} {:08X}", reg, lane, mmio.read()); - } - } - } - for reg in [ - PortTxReg::Dw0, - PortTxReg::Dw1, - PortTxReg::Dw2, - PortTxReg::Dw4, - PortTxReg::Dw5, - PortTxReg::Dw6, - PortTxReg::Dw7, - PortTxReg::Dw8, - ] { - for lane in lanes { - if let Some(mmio) = self.port_tx(reg, lane) { - eprint!(" TX_{:?}_{:?} {:08X}", reg, lane, mmio.read()); - } - } - } - eprintln!(); - } - - fn port_reg(&self, offset: usize) -> Option> { - //TODO: handle gttmm.mmio error? - unsafe { self.gttmm.mmio(self.port_base? + offset).ok() } - } - - pub fn port_cl(&self, reg: PortClReg) -> Option> { - self.port_reg(reg as usize) - } - - pub fn port_comp(&self, reg: PortCompReg) -> Option> { - self.port_reg(reg as usize) - } - - //TODO: return WriteOnly if PortLane::Grp? - pub fn port_pcs(&self, reg: PortPcsReg, lane: PortLane) -> Option> { - self.port_reg((reg as usize) + (lane as usize)) - } - - //TODO: return WriteOnly if PortLane::Grp? - pub fn port_tx(&self, reg: PortTxReg, lane: PortLane) -> Option> { - self.port_reg((reg as usize) + (lane as usize)) - } - - pub fn probe_edid( - &mut self, - power_wells: &mut PowerWells, - gttmm: &MmioRegion, - gmbus: &mut Gmbus, - ) -> Result, Error> { - if let Some(port_comp_dw0) = self.port_comp(PortCompReg::Dw0) { - log::debug!("PORT_COMP_DW0_{}: {:08X}", self.name, port_comp_dw0.read()); - } - let mut aux_read_edid = |ddi: &mut Ddi| -> Result<[u8; 128]> { - //TODO: BLOCK TCCOLD? - - //TODO: the request can be shared by multiple DDIs - let pwr_well_ctl_aux_request = ddi.pwr_well_ctl_aux_request; - let pwr_well_ctl_aux_state = ddi.pwr_well_ctl_aux_state; - let mut pwr_well_ctl_aux = unsafe { MmioPtr::new(power_wells.ctl_aux.as_mut_ptr()) }; - let _pwr_guard = CallbackGuard::new( - &mut pwr_well_ctl_aux, - |pwr_well_ctl_aux| { - // Enable aux power - pwr_well_ctl_aux.writef(pwr_well_ctl_aux_request, true); - let timeout = Timeout::from_micros(1500); - while !pwr_well_ctl_aux.readf(pwr_well_ctl_aux_state) { - timeout.run().map_err(|()| { - log::debug!("timeout while requesting DDI {} aux power", ddi.name); - Error::new(EIO) - })?; - } - Ok(()) - }, - |pwr_well_ctl_aux| { - // Disable aux power - pwr_well_ctl_aux.writef(pwr_well_ctl_aux_request, false); - }, - )?; - - let mut edid_data = [0; 128]; - Aux::new(ddi) - .write_read(0x50, &[0x00], &mut edid_data) - .map_err(|_err| Error::new(EIO))?; - - Ok(edid_data) - }; - let mut gmbus_read_edid = |ddi: &mut Ddi| -> Result<[u8; 128]> { - let Some(pin_pair) = ddi.gmbus_pin_pair else { - return Err(Error::new(EIO)); - }; - - let mut edid_data = [0; 128]; - gmbus - .pin_pair(pin_pair) - .write_read(0x50, &[0x00], &mut edid_data) - .map_err(|_err| Error::new(EIO))?; - - Ok(edid_data) - }; - let gpio_read_edid = |ddi: &mut Ddi| -> Result<[u8; 128]> { - let Some(port) = &ddi.gpio_port else { - return Err(Error::new(EIO)); - }; - - let mut edid_data = [0; 128]; - unsafe { port.i2c(gttmm)? } - .write_read(0x50, &[0x00], &mut edid_data) - .map_err(|_err| Error::new(EIO))?; - - Ok(edid_data) - }; - match aux_read_edid(self) { - Ok(edid_data) => return Ok(Some(("AUX", edid_data))), - Err(err) => { - log::debug!("DDI {} failed to read EDID from AUX: {}", self.name, err); - } - } - match gmbus_read_edid(self) { - Ok(edid_data) => return Ok(Some(("GMBUS", edid_data))), - Err(err) => { - log::debug!("DDI {} failed to read EDID from GMBUS: {}", self.name, err); - } - } - match gpio_read_edid(self) { - Ok(edid_data) => return Ok(Some(("GPIO", edid_data))), - Err(err) => { - log::debug!("DDI {} failed to read EDID from GPIO: {}", self.name, err); - } - } - // Will try again but not fail the driver - Ok(None) - } - - pub fn voltage_swing_hdmi( - &mut self, - gttmm: &MmioRegion, - timing: &edid::DetailedTiming, - ) -> Result<()> { - struct Setting { - dw2_swing_sel: u32, - dw7_n_scalar: u32, - dw4_cursor_coeff: u32, - dw4_post_cursor_1: u32, - dw5_2_tap_disable: u32, - } - - impl Setting { - pub fn new( - dw2_swing_sel: u32, - dw7_n_scalar: u32, - dw4_cursor_coeff: u32, - dw4_post_cursor_1: u32, - dw5_2_tap_disable: u32, - ) -> Self { - Self { - dw2_swing_sel, - dw7_n_scalar, - dw4_cursor_coeff, - dw4_post_cursor_1, - dw5_2_tap_disable, - } - } - } - - // IHD-OS-TGL-Vol 12-1.22-Rev2.0 "Voltage Swing Programming" - let settings = vec![ - // HDMI 450mV, 450mV, 0.0dB - Setting::new(0b1010, 0x60, 0x3F, 0x00, 0b0), - // HDMI 450mV, 650mV, 3.2dB - Setting::new(0b1011, 0x73, 0x36, 0x09, 0b0), - // HDMI 450mV, 850mV, 5.5dB - Setting::new(0b0110, 0x7F, 0x31, 0x0E, 0b0), - // HDMI 650mV, 650mV, 0.0dB - Setting::new(0b1011, 0x73, 0x3F, 0x00, 0b0), - // HDMI 650mV, 850mV, 2.3dB - Setting::new(0b0110, 0x7F, 0x37, 0x08, 0b0), - // HDMI 850mV, 850mV, 0.0dB - Setting::new(0b0110, 0x7F, 0x3F, 0x00, 0b0), - // HDMI 600mV, 850mV, 3.0dB - Setting::new(0b0110, 0x7F, 0x35, 0x0A, 0b0), - ]; - - // Last setting is the default - //TODO: get correct setting index from BIOS - let setting = settings.last().unwrap(); - - // This allows unwraps on port functions below without panic - if self.port_base.is_none() { - log::error!("HDMI voltage swing procedure only implemented on combo DDI"); - return Err(Error::new(EIO)); - }; - - // Clear cmnkeeper_enable for HDMI - { - // It is not possible to read from GRP register, so use LN0 as template - let pcs_dw1_ln0 = self.port_pcs(PortPcsReg::Dw1, PortLane::Ln0).unwrap(); - let mut pcs_dw1_grp = - WriteOnly::new(self.port_pcs(PortPcsReg::Dw1, PortLane::Grp).unwrap()); - let mut v = pcs_dw1_ln0.read(); - v &= !PORT_PCS_DW1_CMNKEEPER_ENABLE; - pcs_dw1_grp.write(v); - } - - // Program loadgen select - //TODO: this assumes bit rate <= 6 GHz and 4 lanes enabled - { - let mut tx_dw4_ln0 = self.port_tx(PortTxReg::Dw4, PortLane::Ln0).unwrap(); - tx_dw4_ln0.writef(PORT_TX_DW4_SELECT, false); - - let mut tx_dw4_ln1 = self.port_tx(PortTxReg::Dw4, PortLane::Ln1).unwrap(); - tx_dw4_ln1.writef(PORT_TX_DW4_SELECT, true); - - let mut tx_dw4_ln2 = self.port_tx(PortTxReg::Dw4, PortLane::Ln2).unwrap(); - tx_dw4_ln2.writef(PORT_TX_DW4_SELECT, true); - - let mut tx_dw4_ln3 = self.port_tx(PortTxReg::Dw4, PortLane::Ln3).unwrap(); - tx_dw4_ln3.writef(PORT_TX_DW4_SELECT, true); - } - - // Set PORT_CL_DW5 sus clock config to 11b - { - let mut cl_dw5 = self.port_cl(PortClReg::Dw5).unwrap(); - cl_dw5.writef(PORT_CL_DW5_SUS_CLOCK_MASK, true); - } - - // Clear training enable to change swing values - let tx_dw5_ln0 = self.port_tx(PortTxReg::Dw5, PortLane::Ln0).unwrap(); - let mut tx_dw5_grp = WriteOnly::new(self.port_tx(PortTxReg::Dw5, PortLane::Grp).unwrap()); - { - let mut v = tx_dw5_ln0.read(); - v &= !PORT_TX_DW5_TRAINING_ENABLE; - tx_dw5_grp.write(v); - } - - // Program swing and de-emphasis - - // Disable eDP bits in PORT_CL_DW10 - let mut cl_dw10 = self.port_cl(PortClReg::Dw10).unwrap(); - cl_dw10.writef( - PORT_CL_DW10_EDP4K2K_MODE_OVRD_EN | PORT_CL_DW10_EDP4K2K_MODE_OVRD_VAL, - false, - ); - - // For PORT_TX_DW5: - // - Set 2 tap disable from settings - // - Set scaling mode sel to 010b - // - Set rterm select to 110b - // - Set 3 tap disable to 1 - // - Set cursor program to 0 - // - Set coeff polarity to 0 - { - let mut v = tx_dw5_ln0.read(); - v &= !(PORT_TX_DW5_DISABLE_2_TAP - | PORT_TX_DW5_CURSOR_PROGRAM - | PORT_TX_DW5_COEFF_POLARITY - | PORT_TX_DW5_SCALING_MODE_SEL_MASK - | PORT_TX_DW5_RTERM_SELECT_MASK); - v |= (setting.dw5_2_tap_disable << PORT_TX_DW5_DISABLE_2_TAP_SHIFT) - | PORT_TX_DW5_DISABLE_3_TAP - | (0b010 << PORT_TX_DW5_SCALING_MODE_SEL_SHIFT) - | (0b110 << PORT_TX_DW5_RTERM_SELECT_SHIFT); - tx_dw5_grp.write(v); - } - - // Individual lane settings are used to avoid overwriting lane-specific settings, and because - // group registers cannot be read - let lanes = [PortLane::Ln0, PortLane::Ln1, PortLane::Ln2, PortLane::Ln3]; - - // For PORT_TX_DW2: - // - Set swing sel from settings - // - Set rcomp scalar to 0x98 - for lane in lanes { - let mut tx_dw2 = self.port_tx(PortTxReg::Dw2, lane).unwrap(); - let mut v = tx_dw2.read(); - v &= !(PORT_TX_DW2_SWING_SEL_UPPER_MASK - | PORT_TX_DW2_SWING_SEL_LOWER_MASK - | PORT_TX_DW2_RCOMP_SCALAR_MASK); - v |= (((setting.dw2_swing_sel >> 3) & 1) << PORT_TX_DW2_SWING_SEL_UPPER_SHIFT) - | ((setting.dw2_swing_sel & 0b111) << PORT_TX_DW2_SWING_SEL_LOWER_SHIFT) - | (0x98 << PORT_TX_DW2_RCOMP_SCALAR_SHIFT); - tx_dw2.write(v); - } - - // For PORT_TX_DW4: - // - Set post cursor 1 from settings - // - Set post cursor 2 to 0x0 - // - Set cursor coeff from settings - for lane in lanes { - let mut tx_dw4 = self.port_tx(PortTxReg::Dw4, lane).unwrap(); - let mut v = tx_dw4.read(); - v &= !(PORT_TX_DW4_POST_CURSOR_1_MASK - | PORT_TX_DW4_POST_CURSOR_2_MASK - | PORT_TX_DW4_CURSOR_COEFF_MASK); - v |= (setting.dw4_post_cursor_1 << PORT_TX_DW4_POST_CURSOR_1_SHIFT) - | (setting.dw4_cursor_coeff << PORT_TX_DW4_CURSOR_COEFF_SHIFT); - tx_dw4.write(v); - } - - // For PORT_TX_DW7: - // - Set n scalar from settings - for lane in lanes { - let mut tx_dw7 = self.port_tx(PortTxReg::Dw7, lane).unwrap(); - // All other bits are spare - tx_dw7.write(setting.dw7_n_scalar << PORT_TX_DW7_N_SCALAR_SHIFT); - } - - // Set training enable to trigger update - { - let mut v = tx_dw5_ln0.read(); - v |= PORT_TX_DW5_TRAINING_ENABLE; - tx_dw5_grp.write(v); - } - - Ok(()) - } - - pub fn kabylake(gttmm: &Arc) -> Result> { - let mut ddis = Vec::new(); - for (i, name) in [ - "A", "B", "C", "D", - //TODO: missing AUX regs? "E", - ] - .iter() - .enumerate() - { - ddis.push(Self { - name, - index: i, - port_base: None, //TODO: port regs - gttmm: gttmm.clone(), - // IHD-OS-KBL-Vol 2c-1.17 DDI_AUX_CTL - aux_ctl: unsafe { gttmm.mmio(0x64010 + i * 0x100)? }, - // IHD-OS-KBL-Vol 2c-1.17 DDI_AUX_DATA - aux_datas: [ - unsafe { gttmm.mmio(0x64014 + i * 0x100)? }, - unsafe { gttmm.mmio(0x64018 + i * 0x100)? }, - unsafe { gttmm.mmio(0x6401C + i * 0x100)? }, - unsafe { gttmm.mmio(0x64020 + i * 0x100)? }, - unsafe { gttmm.mmio(0x64024 + i * 0x100)? }, - ], - // IHD-OS-KBL-Vol 2c-1.17 DDI_BUF_CTL - buf_ctl: unsafe { gttmm.mmio(0x64000 + i * 0x100)? }, - // N/A - dpclka_cfgcr0_clock_shift: None, - dpclka_cfgcr0_clock_off: None, - // IHD-OS-KBL-Vol 2c-1.17 GMBUS0 - gmbus_pin_pair: match *name { - "B" => Some(0b101), - "C" => Some(0b100), - "D" => Some(0b110), - _ => None, - }, - // IHD-OS-KBL-Vol 12-1.17 GMBUS and GPIO - gpio_port: match *name { - "B" => Some(GpioPort::Port4), - "C" => Some(GpioPort::Port3), - "D" => Some(GpioPort::Port5), - _ => None, - }, - // IHD-OS-KBL-Vol 2c-1.17 PWR_WELL_CTL - // All auxes go through the same Misc IO request - pwr_well_ctl_aux_request: 1 << 1, - pwr_well_ctl_aux_state: 1 << 0, - pwr_well_ctl_ddi_request: match *name { - "A" | "E" => 1 << 3, - "B" => 1 << 5, - "C" => 1 << 7, - "D" => 1 << 9, - _ => unreachable!(), - }, - pwr_well_ctl_ddi_state: match *name { - "A" | "E" => 1 << 2, - "B" => 1 << 4, - "C" => 1 << 6, - "D" => 1 << 8, - _ => unreachable!(), - }, - // IHD-OS-KBL-Vol 2c-1.17 SDE_INTERRUPT - sde_interrupt_hotplug: match *name { - "A" => Some(1 << 24), - "B" => Some(1 << 21), - "C" => Some(1 << 22), - "D" => Some(1 << 23), - "E" => Some(1 << 25), - _ => None, - }, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_CLK_SEL - transcoder_index: match *name { - "B" => Some(0b010), - "C" => Some(0b011), - "D" => Some(0b100), - "E" => Some(0b101), - _ => None, - }, - }); - } - Ok(ddis) - } - - pub fn tigerlake(gttmm: &Arc) -> Result> { - let mut ddis = Vec::new(); - for (i, name) in [ - "A", "B", "C", "USBC1", "USBC2", "USBC3", "USBC4", "USBC5", "USBC6", - ] - .iter() - .enumerate() - { - let port_base = match i { - 0 => Some(0x162000), - 1 => Some(0x6C000), - 2 => Some(0x160000), - _ => None, - }; - ddis.push(Self { - name, - index: i, - port_base, - gttmm: gttmm.clone(), - // IHD-OS-TGL-Vol 2c-12.21 DDI_AUX_CTL - aux_ctl: unsafe { gttmm.mmio(0x64010 + i * 0x100)? }, - // IHD-OS-TGL-Vol 2c-12.21 DDI_AUX_DATA - aux_datas: [ - unsafe { gttmm.mmio(0x64014 + i * 0x100)? }, - unsafe { gttmm.mmio(0x64018 + i * 0x100)? }, - unsafe { gttmm.mmio(0x6401C + i * 0x100)? }, - unsafe { gttmm.mmio(0x64020 + i * 0x100)? }, - unsafe { gttmm.mmio(0x64024 + i * 0x100)? }, - ], - // IHD-OS-TGL-Vol 2c-12.21 DDI_BUF_CTL - buf_ctl: unsafe { gttmm.mmio(0x64000 + i * 0x100)? }, - // IHD-OS-TGL-Vol 2c-12.21 DPCLKA_CFGCR0 - dpclka_cfgcr0_clock_shift: match i { - 0 => Some(0), - 1 => Some(2), - 2 => Some(4), - _ => None, - }, - dpclka_cfgcr0_clock_off: match i { - // DDI - 0 => Some(1 << 10), - 1 => Some(1 << 11), - 2 => Some(1 << 24), - // Type C - 3 => Some(1 << 12), - 4 => Some(1 << 13), - 5 => Some(1 << 14), - 6 => Some(1 << 21), - 7 => Some(1 << 22), - 8 => Some(1 << 23), - _ => None, - }, - //TODO: link to docs - gmbus_pin_pair: match i { - // DDI pins - 0 => Some(1), - 1 => Some(2), - 2 => Some(3), - // Type C pins - 3 => Some(9), - 4 => Some(10), - 5 => Some(11), - 6 => Some(12), - 7 => Some(13), - 8 => Some(14), - _ => None, - }, - // IHD-OS-TGL-Vol 12-1.22-Rev2.0 GMBUS and GPIO - gpio_port: match *name { - "A" => Some(GpioPort::Port1), - "B" => Some(GpioPort::Port2), - "C" => Some(GpioPort::Port3), - "USBC1" => Some(GpioPort::Port9), - "USBC2" => Some(GpioPort::Port10), - "USBC3" => Some(GpioPort::Port11), - "USBC4" => Some(GpioPort::Port12), - "USBC5" => Some(GpioPort::Port13), - "USBC6" => Some(GpioPort::Port14), - _ => None, - }, - // IHD-OS-TGL-Vol 2c-12.21 PWR_WELL_CTL_AUX - pwr_well_ctl_aux_request: 2 << (i * 2), - pwr_well_ctl_aux_state: 1 << (i * 2), - // IHD-OS-TGL-Vol 2c-12.21 PWR_WELL_CTL_DDI - pwr_well_ctl_ddi_request: 2 << (i * 2), - pwr_well_ctl_ddi_state: 1 << (i * 2), - // IHD-OS-TGL-Vol 2c-12.21 SDE_INTERRUPT - sde_interrupt_hotplug: match i { - 0 => Some(1 << 16), - 1 => Some(1 << 17), - 2 => Some(1 << 18), - _ => None, - }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_CLK_SEL - transcoder_index: Some((i + 1) as u32), - }) - } - Ok(ddis) - } - - pub fn alchemist(gttmm: &Arc) -> Result> { - let mut ddis = Vec::new(); - for (i, name) in ["A", "B", "C", "USBC1", "USBC2", "USBC3", "USBC4", "D", "E"] - .iter() - .enumerate() - { - let port_base = match i { - 0 => Some(0x162000), - 1 => Some(0x6C000), - 2 => Some(0x160000), - _ => None, - }; - ddis.push(Self { - name, - index: i, - port_base, - gttmm: gttmm.clone(), - // IHD-OS-ACM-Vol 2c-3.23 DDI_AUX_CTL - aux_ctl: unsafe { gttmm.mmio(0x64010 + i * 0x100)? }, - // IHD-OS-ACM-Vol 2c-3.23 DDI_AUX_DATA - aux_datas: [ - unsafe { gttmm.mmio(0x64014 + i * 0x100)? }, - unsafe { gttmm.mmio(0x64018 + i * 0x100)? }, - unsafe { gttmm.mmio(0x6401C + i * 0x100)? }, - unsafe { gttmm.mmio(0x64020 + i * 0x100)? }, - unsafe { gttmm.mmio(0x64024 + i * 0x100)? }, - ], - // IHD-OS-ACM-Vol 2c-3.23 DDI_BUF_CTL - buf_ctl: unsafe { gttmm.mmio(0x64000 + i * 0x100)? }, - // IHD-OS-ACM-Vol 2c-3.23 DPCLKA_CFGCR0 - dpclka_cfgcr0_clock_shift: match i { - 0 => Some(0), - 1 => Some(2), - 2 => Some(4), - _ => None, - }, - dpclka_cfgcr0_clock_off: match i { - // DDI - 0 => Some(1 << 10), - 1 => Some(1 << 11), - 2 => Some(1 << 24), - // Type C - 3 => Some(1 << 12), - 4 => Some(1 << 13), - 5 => Some(1 << 14), - 6 => Some(1 << 21), - 7 => Some(1 << 22), - 8 => Some(1 << 23), - _ => None, - }, - //TODO: link to docs - gmbus_pin_pair: match i { - // DDI pins - 0 => Some(1), - 1 => Some(2), - 2 => Some(3), - // Type C pins - 3 => Some(9), - 4 => Some(10), - 5 => Some(11), - 6 => Some(12), - 7 => Some(13), - 8 => Some(14), - _ => None, - }, - // IHD-OS-ACM-Vol 12-3.23 GMBUS and GPIO - gpio_port: match *name { - "A" => Some(GpioPort::Port1), - "B" => Some(GpioPort::Port2), - "C" => Some(GpioPort::Port3), - "D" => Some(GpioPort::Port4), - "USBC1" => Some(GpioPort::Port9), - _ => None, - }, - // IHD-OS-ACM-Vol 2c-3.23 PWR_WELL_CTL_AUX - pwr_well_ctl_aux_request: 2 << (i * 2), - pwr_well_ctl_aux_state: 1 << (i * 2), - // IHD-OS-ACM-Vol 2c-3.23 PWR_WELL_CTL_DDI - pwr_well_ctl_ddi_request: 2 << (i * 2), - pwr_well_ctl_ddi_state: 1 << (i * 2), - // IHD-OS-ACM-Vol 2c-3.23 SDE_INTERRUPT - sde_interrupt_hotplug: match i { - 0 => Some(1 << 16), - 1 => Some(1 << 17), - 2 => Some(1 << 18), - _ => None, - }, - // IHD-OS-ACM-Vol 2c-3.23 TRANS_CLK_SEL - transcoder_index: Some((i + 1) as u32), - }) - } - Ok(ddis) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/dpll.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/dpll.rs deleted file mode 100644 index 1e4dfdf681..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/dpll.rs +++ /dev/null @@ -1,197 +0,0 @@ -use common::io::{Io, MmioPtr}; -use syscall::error::{Error, Result, EIO}; - -use super::MmioRegion; - -pub const DPLL_CFGCR1_QDIV_RATIO_SHIFT: u32 = 10; -pub const DPLL_CFGCR1_QDIV_RATIO_MASK: u32 = 0xFF << DPLL_CFGCR1_QDIV_RATIO_SHIFT; -pub const DPLL_CFGCR1_QDIV_MODE: u32 = 1 << 9; -pub const DPLL_CFGCR1_KDIV_1: u32 = 0b001 << 6; -pub const DPLL_CFGCR1_KDIV_2: u32 = 0b010 << 6; -pub const DPLL_CFGCR1_KDIV_3: u32 = 0b100 << 6; -pub const DPLL_CFGCR1_KDIV_MASK: u32 = 0b111 << 6; -pub const DPLL_CFGCR1_PDIV_2: u32 = 0b0001 << 2; -pub const DPLL_CFGCR1_PDIV_3: u32 = 0b0010 << 2; -pub const DPLL_CFGCR1_PDIV_5: u32 = 0b0100 << 2; -pub const DPLL_CFGCR1_PDIV_7: u32 = 0b1000 << 2; -pub const DPLL_CFGCR1_PDIV_MASK: u32 = 0b1111 << 2; - -pub const DPLL_ENABLE_ENABLE: u32 = 1 << 31; -pub const DPLL_ENABLE_LOCK: u32 = 1 << 30; -pub const DPLL_ENABLE_POWER_ENABLE: u32 = 1 << 27; -pub const DPLL_ENABLE_POWER_STATE: u32 = 1 << 26; - -pub const DPLL_SSC_ENABLE: u32 = 1 << 9; - -pub struct Dpll { - pub name: &'static str, - // IHD-OS-TGL-Vol 2c-12.21 DPLL_CFGCR0 - pub cfgcr0: MmioPtr, - // IHD-OS-TGL-Vol 2c-12.21 DPLL_CFGCR1 - pub cfgcr1: MmioPtr, - // IHD-OS-TGL-Vol 2c-12.21 DPLL_DIV0 - pub div0: MmioPtr, - // IHD-OS-TGL-Vol 2c-12.21 DPCLKA_CFGCR0 - pub dpclka_cfgcr0_clock_value: u32, - // IHD-OS-TGL-Vol 2c-12.21 DPLL_ENABLE - pub enable: MmioPtr, - // IHD-OS-TGL-Vol 2c-12.21 DPLL_SSC - pub ssc: MmioPtr, -} - -//TODO: verify offsets and count using DeviceKind? -impl Dpll { - pub fn dump(&self) { - eprint!("Dpll {}", self.name); - eprint!(" cfgcr0 {:08X}", self.cfgcr0.read()); - eprint!(" cfgcr1 {:08X}", self.cfgcr1.read()); - eprint!(" div0 {:08X}", self.div0.read()); - eprint!(" enable {:08X}", self.enable.read()); - eprint!(" ssc {:08X}", self.ssc.read()); - eprintln!(); - } - - pub fn set_freq_hdmi( - &mut self, - mut ref_freq: u64, - timing: &edid::DetailedTiming, - ) -> Result<()> { - // IHD-OS-TGL-Vol 12-1.22-Rev2.0 "Formula for HDMI Mode DPLL Programming" - const KHz: u64 = 1_000; - const MHz: u64 = KHz * 1_000; - let dco_min: u64 = 7_998 * MHz; - let dco_mid: u64 = 8_999 * MHz; - let dco_max: u64 = 10_000 * MHz; - - // If reference frequency is 38.4, use 19.2 because the DPLL automatically divides that by 2. - if ref_freq == 38_400_000 { - ref_freq /= 2; - } - - //TODO: this symbol frequency is only valid for RGB 8 bits per color - let symbol_freq = (timing.pixel_clock as u64) * KHz; - let pll_freq = symbol_freq * 5; - - #[derive(Debug)] - struct Setting { - pdiv: u64, - kdiv: u64, - qdiv: u64, - cfgcr1: u32, - dco: u64, - dco_dist: u64, - } - - let mut best_setting: Option = None; - for (pdiv, pdiv_reg) in [ - (2, DPLL_CFGCR1_PDIV_2), - (3, DPLL_CFGCR1_PDIV_3), - (5, DPLL_CFGCR1_PDIV_5), - (7, DPLL_CFGCR1_PDIV_7), - ] { - for (kdiv, kdiv_reg) in [ - (1, DPLL_CFGCR1_KDIV_1), - (2, DPLL_CFGCR1_KDIV_2), - (3, DPLL_CFGCR1_KDIV_3), - ] { - let qdiv_range = if kdiv == 2 { 1..=0xFF } else { 1..=1 }; - for qdiv in qdiv_range { - let qdiv_reg = if qdiv == 1 { - 0 - } else { - ((qdiv as u32) << DPLL_CFGCR1_QDIV_RATIO_SHIFT) | DPLL_CFGCR1_QDIV_MODE - }; - - let dco = pll_freq * pdiv * kdiv * qdiv; - if dco <= dco_min || dco >= dco_max { - // DCO outside of valid range - continue; - } - - let dco_dist = dco.abs_diff(dco_mid); - - let setting = Setting { - pdiv, - kdiv, - qdiv, - cfgcr1: pdiv_reg | kdiv_reg | qdiv_reg, - dco, - dco_dist, - }; - - best_setting = match best_setting.take() { - Some(other) if other.dco_dist < setting.dco_dist => Some(other), - _ => Some(setting), - }; - } - } - } - - let Some(setting) = best_setting else { - log::error!("failed to find valid DPLL setting"); - return Err(Error::new(EIO)); - }; - - eprintln!("{:?}", setting); - - // Configure DPLL_CFGCR0 to set DCO frequency - { - let dco_int = setting.dco / ref_freq; - let dco_fract = ((setting.dco - (dco_int * ref_freq)) << 15) / ref_freq; - self.cfgcr0 - .write(((dco_fract as u32) << 10) | (dco_int as u32)); - } - - // Configure DPLL_CFGCR1 to set the dividers - { - let mut v = self.cfgcr1.read(); - let mask = DPLL_CFGCR1_QDIV_RATIO_MASK - | DPLL_CFGCR1_QDIV_MODE - | DPLL_CFGCR1_KDIV_MASK - | DPLL_CFGCR1_PDIV_MASK; - v &= !mask; - v |= setting.cfgcr1 & mask; - self.cfgcr1.write(v); - } - - // Read back DPLL_CFGCR0 and DPLL_CFGCR1 to ensure writes are complete - let _ = self.cfgcr0.read(); - let _ = self.cfgcr1.read(); - - Ok(()) - } - - pub fn tigerlake(gttmm: &MmioRegion) -> Result> { - let mut dplls = Vec::new(); - dplls.push(Self { - name: "0", - cfgcr0: unsafe { gttmm.mmio(0x164284)? }, - cfgcr1: unsafe { gttmm.mmio(0x164288)? }, - div0: unsafe { gttmm.mmio(0x164B00)? }, - dpclka_cfgcr0_clock_value: 0b00, - enable: unsafe { gttmm.mmio(0x46010)? }, - ssc: unsafe { gttmm.mmio(0x164B10)? }, - }); - dplls.push(Self { - name: "1", - cfgcr0: unsafe { gttmm.mmio(0x16428C)? }, - cfgcr1: unsafe { gttmm.mmio(0x164290)? }, - div0: unsafe { gttmm.mmio(0x164C00)? }, - dpclka_cfgcr0_clock_value: 0b01, - enable: unsafe { gttmm.mmio(0x46014)? }, - ssc: unsafe { gttmm.mmio(0x164C10)? }, - }); - /*TODO: not present on U-class CPUs - dplls.push(Self { - name: "4", - cfgcr0: unsafe { gttmm.mmio(0x164294)? }, - cfgcr1: unsafe { gttmm.mmio(0x164298)? }, - div0: unsafe { gttmm.mmio(0x164E00)? }, - dpclka_cfgcr0_clock_value: 0b10, - enable: unsafe { gttmm.mmio(0x46018)? }, - ssc: unsafe { gttmm.mmio(0x164E10)? }, - }); - */ - Ok(dplls) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/ggtt.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/ggtt.rs deleted file mode 100644 index 5e39827aa6..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/ggtt.rs +++ /dev/null @@ -1,134 +0,0 @@ -use std::sync::Arc; -use std::{mem, ptr}; - -use pcid_interface::PciFunctionHandle; -use range_alloc::RangeAllocator; -use syscall::{Error, EIO}; - -use crate::device::MmioRegion; - -/// Global Graphics Translation Table (global GTT) -/// -/// The global GTT is a page table used by all parts of the GPU that don't use -/// the PPGTT (Per-Process GTT). This includes the display engine and the GM -/// aperture that the CPU can access. -/// -/// The global GTT is located in the GTTMM BAR at offset 8MiB, is up to 8MiB big -/// and consists of 64bit entries. Each entry has a present bit as LSB and the -/// address of the frame at bits 12 through 38. The rest of the bits are ignored. -/// -/// Source: Pages 6 and 75 of intel-gfx-prm-osrc-kbl-vol05-memory_views.pdf -pub struct GlobalGtt { - gttmm: Arc, - /// Base the GTT - gtt_base: *mut u64, - /// Size of the GTT - gtt_size: usize, - - /// Allocator for GM aperture pages - gm_alloc: RangeAllocator, - - // FIXME reuse DSM memory for something useful - /// Base Data of Stolen Memory (DSM) - base_dsm: *mut (), - /// Size of DSM - size_data_stolen_memory: usize, -} - -const GTT_PAGE_SIZE: u32 = 4096; - -impl GlobalGtt { - pub unsafe fn new( - pcid_handle: &mut PciFunctionHandle, - gttmm: Arc, - gm_size: u32, - ) -> Self { - let gtt_offset = 8 * 1024 * 1024; - let gtt_base = ptr::with_exposed_provenance_mut(gttmm.virt + gtt_offset); - - let base_dsm = unsafe { pcid_handle.read_config(0x5C) }; - let ggc = unsafe { pcid_handle.read_config(0x50) }; - - let dsm_size = match (ggc >> 8) & 0xFF { - size if size & 0xF0 == 0 => size * 32 * 1024 * 1024, - size => (size & !0xF0) * 4 * 1024 * 1024, - } as usize; - let gtt_size = match (ggc >> 6) & 0x3 { - 0 => 0, - 1 => 2 * 1024 * 1024, - 2 => 4 * 1024 * 1024, - 3 => 8 * 1024 * 1024, - _ => unreachable!(), - } as usize; - - log::info!("Base DSM: {:X}", base_dsm); - log::info!( - "GGC: {:X} => global GTT size: {}MiB; DSM size: {}MiB", - ggc, - gtt_size / 1024 / 1024, - dsm_size / 1024 / 1024, - ); - - let gm_alloc = RangeAllocator::new(0..gm_size / 4096); - - GlobalGtt { - gttmm, - gtt_base, - gtt_size, - gm_alloc, - base_dsm: core::ptr::with_exposed_provenance_mut(base_dsm as usize), - size_data_stolen_memory: dsm_size, - } - } - - /// Reset the global GTT by clearing out all existing mappings. - pub unsafe fn reset(&mut self) { - for i in 0..self.gtt_size / 8 { - unsafe { *self.gtt_base.add(i) = 0 }; - } - } - - pub fn reserve(&mut self, surf: u32, surf_size: u32) { - assert!(surf.is_multiple_of(GTT_PAGE_SIZE)); - assert!(surf_size.is_multiple_of(GTT_PAGE_SIZE)); - - self.gm_alloc - .allocate_exact_range( - surf / GTT_PAGE_SIZE..surf / GTT_PAGE_SIZE + surf_size / GTT_PAGE_SIZE, - ) - .unwrap_or_else(|err| { - panic!( - "failed to allocate pre-existing surface at 0x{:x} of size {}: {:?}", - surf, surf_size, err - ); - }); - } - - pub fn alloc_phys_mem(&mut self, size: u32) -> syscall::Result { - let size = size.next_multiple_of(GTT_PAGE_SIZE); - - let sgl = common::sgl::Sgl::new(size as usize)?; - - let range = self - .gm_alloc - .allocate_range(size / GTT_PAGE_SIZE) - .map_err(|err| { - log::warn!("failed to allocate buffer of size {}: {:?}", size, err); - Error::new(EIO) - })?; - - for chunk in sgl.chunks() { - for i in 0..chunk.length / GTT_PAGE_SIZE as usize { - unsafe { - *self - .gtt_base - .add(range.start as usize + chunk.offset / GTT_PAGE_SIZE as usize + i) = - chunk.phys as u64 + i as u64 * u64::from(GTT_PAGE_SIZE) + 1; - } - } - } - mem::forget(sgl); - - Ok(range.start * 4096) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/gmbus.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/gmbus.rs deleted file mode 100644 index a8e16bfe95..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/gmbus.rs +++ /dev/null @@ -1,150 +0,0 @@ -use common::{ - io::{Io, MmioPtr}, - timeout::Timeout, -}; -use embedded_hal::blocking::i2c::{self, Operation, SevenBitAddress, Transactional}; - -use super::MmioRegion; - -const GMBUS1_SW_RDY: u32 = 1 << 30; -const GMBUS1_CYCLE_STOP: u32 = 1 << 27; -const GMBUS1_CYCLE_INDEX: u32 = 1 << 26; -const GMBUS1_CYCLE_WAIT: u32 = 1 << 25; -const GMBUS1_SIZE_SHIFT: u32 = 16; -const GMBUS1_INDEX_SHIFT: u32 = 8; - -const GMBUS2_HW_RDY: u32 = 1 << 11; -const GMBUS2_ACTIVE: u32 = 1 << 9; - -pub struct Gmbus { - regs: [MmioPtr; 6], -} - -impl Gmbus { - pub unsafe fn new(gttmm: &MmioRegion) -> syscall::Result { - Ok(Self { - regs: [ - gttmm.mmio(0xC5100)?, - gttmm.mmio(0xC5104)?, - gttmm.mmio(0xC5108)?, - gttmm.mmio(0xC510C)?, - gttmm.mmio(0xC5110)?, - gttmm.mmio(0xC5120)?, - ], - }) - } - - pub fn pin_pair<'a>(&'a mut self, pin_pair: u8) -> GmbusPinPair<'a> { - GmbusPinPair { - regs: &mut self.regs, - pin_pair, - } - } -} - -pub struct GmbusPinPair<'a> { - regs: &'a mut [MmioPtr; 6], - pin_pair: u8, -} - -impl<'a> Transactional for GmbusPinPair<'a> { - type Error = (); - fn exec(&mut self, addr7: SevenBitAddress, ops: &mut [Operation<'_>]) -> Result<(), ()> { - let mut ops_iter = ops.iter_mut(); - //TODO: gmbus is actually smbus, not fully i2c compatible! - // The first operation MUST be a write of the index - let index = match ops_iter.next() { - Some(Operation::Write(buf)) if buf.len() == 1 => buf[0], - unsupported => { - log::error!("GMBUS unsupported first operation {:?}", unsupported); - return Err(()); - } - }; - - // Reset - self.regs[1].write(0); - - // Set pin pair, enabling interface - self.regs[0].write(self.pin_pair as u32); - - for op in ops_iter { - // Start operation - let (addr8, size) = match op { - Operation::Read(buf) => ((addr7 << 1) | 1, buf.len() as u32), - Operation::Write(buf) => (addr7 << 1, buf.len() as u32), - }; - if size >= 512 { - log::error!("GMBUS transaction size {} too large", size); - return Err(()); - } - self.regs[1].write( - GMBUS1_SW_RDY - | GMBUS1_CYCLE_INDEX - | GMBUS1_CYCLE_WAIT - | (size << GMBUS1_SIZE_SHIFT) - | (index as u32) << GMBUS1_INDEX_SHIFT - | (addr8 as u32), - ); - - // Perform transaction - match op { - Operation::Read(buf) => { - for chunk in buf.chunks_mut(4) { - { - //TODO: ideal timeout for gmbus read? - let timeout = Timeout::from_millis(10); - while !self.regs[2].readf(GMBUS2_HW_RDY) { - timeout.run().map_err(|()| { - log::debug!( - "timeout on GMBUS read 0x{:08x}", - self.regs[2].read() - ); - () - })?; - } - } - - let bytes = self.regs[3].read().to_le_bytes(); - chunk.copy_from_slice(&bytes[..chunk.len()]); - } - } - Operation::Write(buf) => { - log::warn!("TODO: GMBUS WRITE"); - return Err(()); - } - } - } - - // Stop transaction - self.regs[1].write(GMBUS1_SW_RDY | GMBUS1_CYCLE_STOP); - - // Wait idle - let timeout = Timeout::from_millis(10); - while self.regs[2].readf(GMBUS2_ACTIVE) { - timeout.run().map_err(|()| { - log::debug!("timeout on GMBUS active 0x{:08x}", self.regs[2].read()); - () - })?; - } - - // Disable GMBUS interface - self.regs[0].write(0); - - Ok(()) - } -} - -impl<'a> i2c::WriteRead for GmbusPinPair<'a> { - type Error = (); - fn write_read( - &mut self, - addr7: SevenBitAddress, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result<(), ()> { - self.exec( - addr7, - &mut [Operation::Write(bytes), Operation::Read(buffer)], - ) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/gpio.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/gpio.rs deleted file mode 100644 index fe87e6b108..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/gpio.rs +++ /dev/null @@ -1,99 +0,0 @@ -use std::convert::Infallible; -use std::time::Duration; - -use common::io::{Io, MmioPtr}; -use embedded_hal::digital::v2 as digital; - -use crate::device::HalTimer; - -use super::MmioRegion; - -const GPIO_DIR_MASK: u32 = 1 << 0; -const GPIO_DIR_OUT: u32 = 1 << 1; -const GPIO_VAL_MASK: u32 = 1 << 2; -const GPIO_VAL_OUT: u32 = 1 << 3; -const GPIO_VAL_IN: u32 = 1 << 4; -const GPIO_CLOCK_SHIFT: u32 = 0; -const GPIO_DATA_SHIFT: u32 = 8; - -#[derive(Copy, Clone, Debug)] -#[repr(usize)] -pub enum GpioPort { - Port0 = 0xC5010, - Port1 = 0xC5014, - Port2 = 0xC5018, - Port3 = 0xC501C, - Port4 = 0xC5020, - Port5 = 0xC5024, - Port6 = 0xC5028, - Port7 = 0xC502C, - Port8 = 0xC5030, - Port9 = 0xC5034, - Port10 = 0xC5038, - Port11 = 0xC503C, - Port12 = 0xC5040, - Port13 = 0xC5044, - Port14 = 0xC5048, - Port15 = 0xC504C, -} - -impl GpioPort { - pub unsafe fn i2c( - &self, - gttmm: &MmioRegion, - ) -> syscall::Result> { - let i2c_freq = 100_000.0; - let (scl, sda) = unsafe { - ( - GpioPin { - ctl: gttmm.mmio(*self as usize)?, - shift: GPIO_CLOCK_SHIFT, - }, - GpioPin { - ctl: gttmm.mmio(*self as usize)?, - shift: GPIO_DATA_SHIFT, - }, - ) - }; - Ok(bitbang_hal::i2c::I2cBB::new( - scl, - sda, - HalTimer::new(Duration::from_secs_f64(1.0 / i2c_freq)), - )) - } -} - -pub struct GpioPin { - ctl: MmioPtr, - shift: u32, -} - -impl digital::InputPin for GpioPin { - type Error = Infallible; - - fn is_high(&self) -> Result { - Ok(((self.ctl.read() >> self.shift) & GPIO_VAL_IN) == GPIO_VAL_IN) - } - - fn is_low(&self) -> Result { - Ok(((self.ctl.read() >> self.shift) & GPIO_VAL_IN) == 0) - } -} - -impl digital::OutputPin for GpioPin { - type Error = Infallible; - - fn set_low(&mut self) -> Result<(), Infallible> { - // Set GPIO to output with value 0 - let value = GPIO_DIR_MASK | GPIO_DIR_OUT | GPIO_VAL_MASK; - self.ctl.write(value << self.shift); - Ok(()) - } - - fn set_high(&mut self) -> Result<(), Infallible> { - // Assuming external pull-up, set GPIO to input - let value = GPIO_DIR_MASK; - self.ctl.write(value << self.shift); - Ok(()) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/hal/mod.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/hal/mod.rs deleted file mode 100644 index f3f81d2de5..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/hal/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -mod timer; -pub use self::timer::*; diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/hal/timer.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/hal/timer.rs deleted file mode 100644 index 35552692e3..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/hal/timer.rs +++ /dev/null @@ -1,38 +0,0 @@ -use embedded_hal::timer; -use std::time::{Duration, Instant}; -use void::Void; - -pub struct HalTimer { - instant: Instant, - duration: Duration, -} - -impl HalTimer { - pub fn new(duration: Duration) -> Self { - Self { - instant: Instant::now(), - duration, - } - } -} - -impl timer::CountDown for HalTimer { - type Time = Duration; - fn start>(&mut self, duration: T) { - self.instant = Instant::now(); - self.duration = duration.into(); - } - - fn wait(&mut self) -> nb::Result<(), Void> { - if self.instant.elapsed() < self.duration { - std::thread::yield_now(); - Err(nb::Error::WouldBlock) - } else { - // Since this is periodic it must trigger at the next duration - self.instant += self.duration; - Ok(()) - } - } -} - -impl timer::Periodic for HalTimer {} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/mod.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/mod.rs deleted file mode 100644 index ced9dd561a..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/mod.rs +++ /dev/null @@ -1,966 +0,0 @@ -use common::{ - io::{Io, MmioPtr}, - timeout::Timeout, -}; -use pcid_interface::{PciFunction, PciFunctionHandle}; -use range_alloc::RangeAllocator; -use std::{collections::VecDeque, fmt, mem, sync::Arc}; -use syscall::error::{Error, Result, EIO, ENODEV, ERANGE}; - -mod aux; -mod bios; -use self::bios::*; -mod buffer; -mod ddi; -use self::ddi::*; -mod dpll; -use self::dpll::*; -mod gmbus; -pub use self::gmbus::*; -mod gpio; -pub use self::gpio::*; -mod ggtt; -use ggtt::*; -mod hal; -pub use self::hal::*; -mod pipe; -use self::pipe::*; -mod power; -use self::power::*; -mod scheme; -mod transcoder; -use self::transcoder::*; - -//TODO: move to common? -pub struct CallbackGuard<'a, T, F: FnOnce(&mut T)> { - value: &'a mut T, - fini: Option, -} - -impl<'a, T, F: FnOnce(&mut T)> CallbackGuard<'a, T, F> { - // Note that fini will also run if init fails - pub fn new(value: &'a mut T, init: impl FnOnce(&mut T) -> Result<()>, fini: F) -> Result { - let mut this = Self { - value, - fini: Some(fini), - }; - init(&mut this.value)?; - Ok(this) - } -} - -impl<'a, T, F: FnOnce(&mut T)> Drop for CallbackGuard<'a, T, F> { - fn drop(&mut self) { - let fini = self.fini.take().unwrap(); - fini(&mut self.value); - } -} - -pub struct ChangeDetect { - name: &'static str, - reg: MmioPtr, - value: u32, -} - -impl ChangeDetect { - fn new(name: &'static str, reg: MmioPtr) -> Self { - let value = reg.read(); - Self { name, reg, value } - } - - fn log(&self) { - log::info!("{} {:08X}", self.name, self.value); - } - - fn check(&mut self) { - let value = self.reg.read(); - if value != self.value { - self.value = value; - self.log(); - } - } -} - -#[derive(Clone, Copy, Debug)] -pub enum DeviceKind { - KabyLake, - TigerLake, - Alchemist, -} - -pub enum Event { - DdiHotplug(&'static str), -} - -pub struct InterruptRegs { - // Interrupt status register, has live status of interrupts - pub isr: MmioPtr, - // Interrupt mask register, masks isr for iir, 0 is unmasked - pub imr: MmioPtr, - // Interrupt identity register, write 1 to clear - pub iir: MmioPtr, - // Interrupt enable register, 1 allows interrupt to propogate - pub ier: MmioPtr, -} - -pub struct Interrupter { - change_detects: Vec, - display_int_ctl: MmioPtr, - display_int_ctl_enable: u32, - display_int_ctl_sde: u32, - gfx_mstr_intr: Option>, - gfx_mstr_intr_display: u32, - gfx_mstr_intr_enable: u32, - sde_interrupt: InterruptRegs, -} - -#[derive(Debug)] -pub struct MmioRegion { - phys: usize, - virt: usize, - size: usize, -} - -impl MmioRegion { - fn new(phys: usize, size: usize, memory_type: common::MemoryType) -> Result { - let virt = unsafe { common::physmap(phys, size, common::Prot::RW, memory_type)? as usize }; - Ok(Self { phys, virt, size }) - } - - unsafe fn mmio(&self, offset: usize) -> Result> { - // Any errors here will return ERANGE - let err = Error::new(ERANGE); - if offset.checked_add(mem::size_of::()).ok_or(err)? > self.size { - return Err(err); - } - let addr = self.virt.checked_add(offset).ok_or(err)?; - Ok(unsafe { MmioPtr::new(addr as *mut u32) }) - } -} - -impl Drop for MmioRegion { - fn drop(&mut self) { - unsafe { - let _ = libredox::call::munmap(self.virt as *mut (), self.size); - } - } -} - -#[derive(Clone, Copy, Debug)] -enum VideoInput { - Hdmi, - Dp, -} - -pub struct Device { - kind: DeviceKind, - alloc_buffers: RangeAllocator, - bios: Option, - ddis: Vec, - dpclka_cfgcr0: Option>, - dplls: Vec, - events: VecDeque, - framebuffers: Vec, - int: Interrupter, - gttmm: Arc, - ggtt: GlobalGtt, - gm: MmioRegion, - gmbus: Gmbus, - pipes: Vec, - power_wells: PowerWells, - ref_freq: u64, - transcoders: Vec, -} - -impl fmt::Debug for Device { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Device") - .field("kind", &self.kind) - .field("alloc_buffers", &self.alloc_buffers) - .field("gttmm", &self.gttmm) - .field("gm", &self.gm) - .field("ref_freq", &self.ref_freq) - .finish_non_exhaustive() - } -} - -impl Device { - pub fn new(pcid_handle: &mut PciFunctionHandle, func: &PciFunction) -> Result { - let kind = match (func.full_device_id.vendor_id, func.full_device_id.device_id) { - // Kaby Lake - (0x8086, 0x5912) | - (0x8086, 0x5916) | - (0x8086, 0x591B) | - (0x8086, 0x591E) | - (0x8086, 0x5926) | - // Comet Lake, seems to be compatible with Kaby Lake - (0x8086, 0x9B21) | - (0x8086, 0x9B41) | - (0x8086, 0x9BA4) | - (0x8086, 0x9BAA) | - (0x8086, 0x9BAC) | - (0x8086, 0x9BC4) | - (0x8086, 0x9BC5) | - (0x8086, 0x9BC6) | - (0x8086, 0x9BC8) | - (0x8086, 0x9BCA) | - (0x8086, 0x9BCC) | - (0x8086, 0x9BE6) | - (0x8086, 0x9BF6) => { - DeviceKind::KabyLake - } - // Tiger Lake - (0x8086, 0x9A40) | - (0x8086, 0x9A49) | - (0x8086, 0x9A60) | - (0x8086, 0x9A68) | - (0x8086, 0x9A70) | - (0x8086, 0x9A78) => { - DeviceKind::TigerLake - } - // Alchemist - (0x8086, 0x5690) | // A770M - (0x8086, 0x5691) | // A730M - (0x8086, 0x5692) | // A550M - (0x8086, 0x5693) | // A370M - (0x8086, 0x5694) | // A350M - (0x8086, 0x5696) | // A570M - (0x8086, 0x5697) | // A530M - (0x8086, 0x56A0) | // A770 - (0x8086, 0x56A1) | // A750 - (0x8086, 0x56A5) | // A380 - (0x8086, 0x56A6) | // A310 - (0x8086, 0x56B0) | // Pro A30M - (0x8086, 0x56B1) | // Pro A40/A50 - (0x8086, 0x56B2) | // Pro A60M - (0x8086, 0x56B3) | // Pro A60 - (0x8086, 0x56C0) | // GPU Flex 170 - (0x8086, 0x56C1) // GPU Flex 140 - => { - DeviceKind::Alchemist - } - (vendor_id, device_id) => { - log::error!("unsupported ID {:04X}:{:04X}", vendor_id, device_id); - return Err(Error::new(ENODEV)); - } - }; - - let gttmm = { - let (phys, size) = func.bars[0].expect_mem(); - Arc::new(MmioRegion::new( - phys, - size, - common::MemoryType::Uncacheable, - )?) - }; - log::info!("GTTMM {:X?}", gttmm); - let gm = { - let (phys, size) = func.bars[2].expect_mem(); - MmioRegion::new(phys, size, common::MemoryType::WriteCombining)? - }; - log::info!("GM {:X?}", gm); - /* IOBAR not used, not present on all generations - let iobar = func.bars[4].expect_port(); - log::debug!("IOBAR {:X?}", iobar); - */ - - // IGD OpRegion/Software SCI/_DSM for Skylake Processors - let bios_base = unsafe { pcid_handle.read_config(0xFC) }; - let bios = if bios_base != 0 { - log::info!("BIOS {:X?}", bios_base); - // This is the default BIOS size - let bios_size = 8 * 1024; - match MmioRegion::new( - bios_base as usize, - bios_size, - common::MemoryType::Uncacheable, - ) { - Ok(region) => match Bios::new(region) { - Ok(bios) => Some(bios), - Err(err) => { - log::warn!("failed to parse BIOS at {:08X}: {}", bios_base, err); - None - } - }, - Err(err) => { - log::warn!("failed to map BIOS at {:08X}: {}", bios_base, err); - None - } - } - } else { - None - }; - - let ggtt = unsafe { - GlobalGtt::new( - pcid_handle, - gttmm.clone(), - //TODO: how to use 64-bit surface addresses? - gm.size.min(u32::MAX as usize) as u32, - ) - }; - //unsafe { ggtt.reset() }; - - // GMBUS seems to be stable for all generations - let gmbus = unsafe { Gmbus::new(>tmm)? }; - - let dpclka_cfgcr0; - let int; - let ref_freq; - match kind { - DeviceKind::KabyLake => { - dpclka_cfgcr0 = None; - - int = Interrupter { - change_detects: Vec::new(), - // IHD-OS-KBL-Vol 2c-1.17 MASTER_INT_CTL - display_int_ctl: unsafe { gttmm.mmio(0x44200)? }, - display_int_ctl_enable: 1 << 31, - display_int_ctl_sde: 1 << 23, - gfx_mstr_intr: None, - gfx_mstr_intr_display: 0, - gfx_mstr_intr_enable: 0, - sde_interrupt: InterruptRegs { - isr: unsafe { gttmm.mmio(0xC4000)? }, - imr: unsafe { gttmm.mmio(0xC4004)? }, - iir: unsafe { gttmm.mmio(0xC4008)? }, - ier: unsafe { gttmm.mmio(0xC400C)? }, - }, - }; - - // IHD-OS-KBL-Vol 12-1.17 - ref_freq = 24_000_000; - } - DeviceKind::TigerLake | DeviceKind::Alchemist => { - // TigerLake: IHD-OS-TGL-Vol 2c-12.21 - // Alchemist: IHD-OS-ACM-Vol 2c-3.23 - - dpclka_cfgcr0 = Some(unsafe { gttmm.mmio(0x164280)? }); - - let dssm = unsafe { gttmm.mmio(0x51004)? }; - log::debug!("dssm {:08X}", dssm.read()); - - const DSSM_REF_FREQ_24_MHZ: u32 = 0b000 << 29; - const DSSM_REF_FREQ_19_2_MHZ: u32 = 0b001 << 29; - const DSSM_REF_FREQ_38_4_MHZ: u32 = 0b010 << 29; - const DSSM_REF_FREQ_MASK: u32 = 0b111 << 29; - ref_freq = match dssm.read() & DSSM_REF_FREQ_MASK { - DSSM_REF_FREQ_24_MHZ => 24_000_000, - DSSM_REF_FREQ_19_2_MHZ => 19_200_000, - DSSM_REF_FREQ_38_4_MHZ => 38_400_000, - unknown => { - log::error!("unknown DSSM reference frequency {}", unknown); - return Err(Error::new(EIO)); - } - }; - - int = Interrupter { - change_detects: vec![ - ChangeDetect::new("de_hpd_interrupt", unsafe { gttmm.mmio(0x44470)? }), - ChangeDetect::new("de_port_interrupt", unsafe { gttmm.mmio(0x44440)? }), - ChangeDetect::new("shotplug_ctl_ddi", unsafe { gttmm.mmio(0xC4030)? }), - ChangeDetect::new("shotplug_ctl_tc", unsafe { gttmm.mmio(0xC4034)? }), - ChangeDetect::new("tbt_hotplug_ctl", unsafe { gttmm.mmio(0x44030)? }), - ChangeDetect::new("tc_hotplug_ctl", unsafe { gttmm.mmio(0x44038)? }), - ], - display_int_ctl: unsafe { gttmm.mmio(0x44200)? }, - display_int_ctl_enable: 1 << 31, - display_int_ctl_sde: 1 << 23, - gfx_mstr_intr: Some(unsafe { gttmm.mmio(0x190010)? }), - gfx_mstr_intr_display: 1 << 16, - gfx_mstr_intr_enable: 1 << 31, - sde_interrupt: InterruptRegs { - isr: unsafe { gttmm.mmio(0xC4000)? }, - imr: unsafe { gttmm.mmio(0xC4004)? }, - iir: unsafe { gttmm.mmio(0xC4008)? }, - ier: unsafe { gttmm.mmio(0xC400C)? }, - }, - }; - } - } - - let ddis; - let dplls; - let pipes; - let power_wells; - let transcoders; - match kind { - DeviceKind::KabyLake => { - ddis = Ddi::kabylake(>tmm)?; - //TODO: kaby lake dplls - dplls = Vec::new(); - pipes = Pipe::kabylake(>tmm)?; - power_wells = PowerWells::kabylake(>tmm)?; - transcoders = Transcoder::kabylake(>tmm)?; - } - DeviceKind::TigerLake => { - ddis = Ddi::tigerlake(>tmm)?; - dplls = Dpll::tigerlake(>tmm)?; - pipes = Pipe::tigerlake(>tmm)?; - power_wells = PowerWells::tigerlake(>tmm)?; - transcoders = Transcoder::tigerlake(>tmm)?; - } - DeviceKind::Alchemist => { - // Many registers are identical to tigerlake - dplls = Dpll::tigerlake(>tmm)?; - pipes = Pipe::alchemist(>tmm)?; - // FIXME transcoders are probably different too - transcoders = Transcoder::tigerlake(>tmm)?; - // Power wells are distinct - ddis = Ddi::alchemist(>tmm)?; - power_wells = PowerWells::alchemist(>tmm)?; - } - } - - //TODO: get number of available buffers - let buffers = 1024; - Ok(Self { - kind, - alloc_buffers: RangeAllocator::new(0..buffers), - bios, - ddis, - dpclka_cfgcr0, - dplls, - events: VecDeque::new(), - framebuffers: Vec::new(), - int, - gttmm, - ggtt, - gm, - gmbus, - pipes, - power_wells, - ref_freq, - transcoders, - }) - } - - pub fn init_inner(&mut self) { - // Discover current framebuffers - self.alloc_buffers.reset(); - self.framebuffers.clear(); - for pipe in self.pipes.iter() { - for plane in pipe.planes.iter() { - if plane.ctl.readf(PLANE_CTL_ENABLE) { - plane.fetch_modeset(&mut self.alloc_buffers); - - self.framebuffers - .push(plane.fetch_framebuffer(&self.gm, &mut self.ggtt)); - } - } - } - - // Probe all DDIs - let ddi_names: Vec<&str> = self.ddis.iter().map(|ddi| ddi.name).collect(); - for ddi_name in ddi_names { - self.probe_ddi(ddi_name).expect("failed to probe DDI"); - } - - self.dump(); - - log::info!( - "device initialized with {} framebuffers", - self.framebuffers.len() - ); - - // Enable SDE interrupts - { - let mut mask = 0; - for ddi in self.ddis.iter() { - if let Some(sde_interrupt_hotplug) = ddi.sde_interrupt_hotplug { - mask |= sde_interrupt_hotplug; - } - } - let sde_int = &mut self.int.sde_interrupt; - // Enable DDI hotplug interrupts - sde_int.ier.write(mask); - // Clear identity register - sde_int.iir.write(sde_int.iir.read()); - // Unmask all interrupts - sde_int.imr.write(0); - } - // Enable display interrupts - self.int - .display_int_ctl - .write(self.int.display_int_ctl_enable); - if let Some(gfx_mstr_intr) = &mut self.int.gfx_mstr_intr { - // Enable graphics interrupts - gfx_mstr_intr.write(self.int.gfx_mstr_intr_enable); - } - for change_detect in self.int.change_detects.iter_mut() { - change_detect.log(); - } - } - - pub fn dump(&self) { - for ddi in self.ddis.iter() { - if ddi.buf_ctl.readf(DDI_BUF_CTL_ENABLE) { - ddi.dump(); - } - } - - if let Some(dpclka_cfgcr0) = &self.dpclka_cfgcr0 { - eprintln!("dpclka_cfgcr0 {:08X}", dpclka_cfgcr0.read()); - } - for dpll in self.dplls.iter() { - if dpll.enable.readf(DPLL_ENABLE_ENABLE) { - dpll.dump(); - } - } - - for (transcoder, pipe) in self.transcoders.iter().zip(self.pipes.iter()) { - if transcoder.conf.readf(TRANS_CONF_ENABLE) { - transcoder.dump(); - pipe.dump(); - for plane in pipe.planes.iter() { - if plane.index == 0 || plane.ctl.readf(PLANE_CTL_ENABLE) { - eprint!(" "); - plane.dump(); - } - } - } - } - } - - pub fn probe_ddi(&mut self, name: &str) -> Result { - let Some(ddi) = self.ddis.iter_mut().find(|ddi| ddi.name == name) else { - log::warn!("DDI {} not found", name); - return Err(Error::new(EIO)); - }; - - // Enable DDI power well - self.power_wells.enable_well_by_ddi(ddi.name)?; - - let Some((source, edid_data)) = - ddi.probe_edid(&mut self.power_wells, &self.gttmm, &mut self.gmbus)? - else { - return Ok(false); - }; - - let edid = match edid::parse(&edid_data).to_full_result() { - Ok(edid) => { - log::info!("DDI {} EDID from {}: {:?}", ddi.name, source, edid); - edid - } - Err(err) => { - log::warn!( - "DDI {} failed to parse EDID from {}: {:?}", - ddi.name, - source, - err - ); - // Will try again but not fail the driver - return Ok(false); - } - }; - - let timing_opt = edid.descriptors.iter().find_map(|desc| match desc { - edid::Descriptor::DetailedTiming(timing) => Some(timing), - _ => None, - }); - let Some(timing) = timing_opt else { - log::warn!( - "DDI {} EDID from {} missing detailed timing", - ddi.name, - source - ); - // Will try again but not fail the driver - return Ok(false); - }; - - let mut modeset = |ddi: &mut Ddi, input: VideoInput| -> Result<()> { - // IHD-OS-TGL-Vol 12-1.22-Rev2.0 "Sequences for HDMI and DVI" - - // Power wells should already be enabled - - //TODO: Type-C needs aux power enabled and max lanes set - - // Enable port PLL without SSC. Not required on Type-C ports - if let Some(clock_shift) = ddi.dpclka_cfgcr0_clock_shift { - // Find free DPLL - let dpll = self - .dplls - .iter_mut() - .find(|dpll| !dpll.enable.readf(DPLL_ENABLE_ENABLE)) - .ok_or_else(|| { - log::error!("failed to find free DPLL"); - Error::new(EIO) - })?; - - // DPLL power guard - let mut dpll_enable = unsafe { MmioPtr::new(dpll.enable.as_mut_ptr()) }; - let dpll_power_guard = CallbackGuard::new( - &mut dpll_enable, - |dpll_enable| { - // Enable DPLL power - dpll_enable.writef(DPLL_ENABLE_POWER_ENABLE, true); - //TODO: timeout not specified in docs, should be very fast - let timeout = Timeout::from_micros(1); - while !dpll_enable.readf(DPLL_ENABLE_POWER_STATE) { - timeout.run().map_err(|()| { - log::debug!("timeout while enabling DPLL {} power", dpll.name); - Error::new(EIO) - })?; - } - Ok(()) - }, - |dpll_enable| { - // Disable DPLL power - dpll_enable.writef(DPLL_ENABLE_POWER_ENABLE, false); - }, - )?; - - match input { - VideoInput::Hdmi => { - // Set SSC enable/disable. For HDMI, always disable - dpll.ssc.writef(DPLL_SSC_ENABLE, false); - - // Configure DPLL frequency - dpll.set_freq_hdmi(self.ref_freq, &timing)?; - } - VideoInput::Dp => { - log::warn!("DPLL for DisplayPort not implemented"); - return Err(Error::new(EIO)); - } - } - - //TODO: "Sequence Before Frequency Change" - - // Enable DPLL - //TODO: use guard? - { - dpll.enable.writef(DPLL_ENABLE_ENABLE, true); - let timeout = Timeout::from_micros(50); - while !dpll.enable.readf(DPLL_ENABLE_LOCK) { - timeout.run().map_err(|()| { - log::debug!("timeout while enabling DPLL {}", dpll.name); - Error::new(EIO) - })?; - } - } - - //TODO: "Sequence After Frequency Change" - - // Update DPLL mapping - if let Some(dpclka_cfgcr0) = &mut self.dpclka_cfgcr0 { - const DPCLKA_CFGCR0_CLOCK_MASK: u32 = 0b11; - - let mut v = dpclka_cfgcr0.read(); - v &= !(DPCLKA_CFGCR0_CLOCK_MASK << clock_shift); - v |= dpll.dpclka_cfgcr0_clock_value << clock_shift; - dpclka_cfgcr0.write(v); - } - - // Continue to allow DPLL power - mem::forget(dpll_power_guard); - } - - // Enable DPLL clock (must be done separately from PLL mapping) - if let Some(dpclka_cfgcr0) = &mut self.dpclka_cfgcr0 { - if let Some(clock_off) = ddi.dpclka_cfgcr0_clock_off { - dpclka_cfgcr0.writef(clock_off, false); - } - } - - // Enable IO power - //TODO: the request can be shared by multiple DDIs - //TODO: skip if TBT - let pwr_well_ctl_ddi_request = ddi.pwr_well_ctl_ddi_request; - let pwr_well_ctl_ddi_state = ddi.pwr_well_ctl_ddi_state; - let mut pwr_well_ctl_ddi = - unsafe { MmioPtr::new(self.power_wells.ctl_ddi.as_mut_ptr()) }; - let pwr_guard = CallbackGuard::new( - &mut pwr_well_ctl_ddi, - |pwr_well_ctl_ddi| { - // Enable IO power - pwr_well_ctl_ddi.writef(pwr_well_ctl_ddi_request, true); - let timeout = Timeout::from_micros(30); - while !pwr_well_ctl_ddi.readf(pwr_well_ctl_ddi_state) { - timeout.run().map_err(|()| { - log::debug!("timeout while requesting DDI {} IO power", ddi.name); - Error::new(EIO) - })?; - } - Ok(()) - }, - |pwr_well_ctl_ddi| { - // Disable IO power - pwr_well_ctl_ddi.writef(pwr_well_ctl_ddi_request, false); - }, - )?; - - //TODO: Type-C DP_MODE - - // Enable planes, pipe, and transcoder - { - // Find free transcoder with free pipe - let mut transcoder_pipe = None; - for (transcoder, pipe) in self.transcoders.iter_mut().zip(self.pipes.iter_mut()) { - if transcoder.conf.readf(TRANS_CONF_ENABLE) { - continue; - } - //TODO: how would we know if pipe is in use? - transcoder_pipe = Some((transcoder, pipe)); - break; - } - let Some((transcoder, pipe)) = transcoder_pipe else { - log::error!("free transcoder and pipe not found"); - return Err(Error::new(EIO)); - }; - - // Enable pipe and transcoder power wells - self.power_wells.enable_well_by_pipe(pipe.name)?; - self.power_wells - .enable_well_by_transcoder(transcoder.name)?; - - // Configure transcoder clock select - if let Some(transcoder_index) = ddi.transcoder_index { - transcoder - .clk_sel - .write(transcoder_index << transcoder.clk_sel_shift); - } - - // Set pipe bottom color to blue for debugging - pipe.bottom_color.write(0x3FF); - - // Configure and enable planes - //TODO: THIS IS HACKY - if let Some(plane) = pipe.planes.first_mut() { - let width = timing.horizontal_active_pixels as u32; - let height = timing.vertical_active_lines as u32; - - let fb = DeviceFb::alloc(&self.gm, &mut self.ggtt, width, height)?; - - plane.modeset(&mut self.alloc_buffers)?; - plane.set_framebuffer(&fb); - - self.framebuffers.push(fb); - } - - //TODO: VGA and panel fitter steps? - - // Configure transcoder timings and other pipe and transcoder settings - transcoder.modeset(pipe, &timing); - - // Configure and enable TRANS_DDI_FUNC_CTL - { - let mut ddi_func_ctl = TRANS_DDI_FUNC_CTL_ENABLE | - //TODO: allow different bits per color - TRANS_DDI_FUNC_CTL_BPC_8 | - //TODO: correct port width selection - TRANS_DDI_FUNC_CTL_PORT_WIDTH_4; - - if let Some(transcoder_index) = ddi.transcoder_index { - ddi_func_ctl |= transcoder_index << transcoder.ddi_func_ctl_ddi_shift; - } - - match input { - VideoInput::Hdmi => { - ddi_func_ctl |= TRANS_DDI_FUNC_CTL_MODE_HDMI; - - // Set HDMI scrambling and high TMDS char rate based on symbol rate > 340 MHz - if timing.pixel_clock > 340_000 { - ddi_func_ctl |= transcoder.ddi_func_ctl_hdmi_scrambling - | transcoder.ddi_func_ctl_high_tmds_char_rate; - } - } - VideoInput::Dp => { - //TODO: MST - ddi_func_ctl |= TRANS_DDI_FUNC_CTL_MODE_DP_SST; - } - } - - match (timing.features >> 3) & 0b11 { - // Digital sync, separate - 0b11 => { - if (timing.features & (1 << 2)) != 0 { - ddi_func_ctl |= TRANS_DDI_FUNC_CTL_SYNC_POLARITY_VSHIGH; - } - if (timing.features & (1 << 1)) != 0 { - ddi_func_ctl |= TRANS_DDI_FUNC_CTL_SYNC_POLARITY_HSHIGH; - } - } - unsupported => { - log::warn!("unsupported sync {:#x}", unsupported); - } - } - - transcoder.ddi_func_ctl.write(ddi_func_ctl); - } - - // Configure and enable TRANS_CONF - let mut conf = transcoder.conf.read(); - // Set mode to progressive - conf &= !TRANS_CONF_MODE_MASK; - // Enable transcoder - conf |= TRANS_CONF_ENABLE; - transcoder.conf.write(conf); - //TODO: what is the correct timeout? - let timeout = Timeout::from_millis(100); - while !transcoder.conf.readf(TRANS_CONF_STATE) { - timeout.run().map_err(|()| { - log::error!( - "timeout on DDI {} transcoder {} enable", - ddi.name, - transcoder.name - ); - Error::new(EIO) - })?; - } - } - - // Enable port - { - // Configure voltage swing and related IO settings - match input { - VideoInput::Hdmi => { - ddi.voltage_swing_hdmi(&self.gttmm, &timing)?; - } - VideoInput::Dp => { - //TODO ddi.voltage_swing_dp(&self.gttmm)?; - log::error!("voltage swing for DP not implemented"); - return Err(Error::new(EIO)); - } - } - - // Configure PORT_CL_DW10 static power down to power up all lanes - //TODO: only power up required lanes - if let Some(mut port_cl_dw10) = ddi.port_cl(PortClReg::Dw10) { - port_cl_dw10.writef(0b1111 << 4, false); - } - - // Configure and enable DDI_BUF_CTL - //TODO: more DDI_BUF_CTL bits? - ddi.buf_ctl.writef(DDI_BUF_CTL_ENABLE, true); - - // Wait for DDI_BUF_CTL IDLE = 0, timeout after 500 us - let timeout = Timeout::from_micros(500); - while ddi.buf_ctl.readf(DDI_BUF_CTL_IDLE) { - timeout.run().map_err(|()| { - log::warn!("timeout while waiting for DDI {} active", ddi.name); - Error::new(EIO) - })?; - } - } - - // Keep IO power on if finished - mem::forget(pwr_guard); - - Ok(()) - }; - - if ddi.buf_ctl.readf(DDI_BUF_CTL_IDLE) { - log::info!("DDI {} idle, will attempt mode setting", ddi.name); - const EDID_VIDEO_INPUT_UNDEFINED: u8 = (1 << 7) | 0b0000; - const EDID_VIDEO_INPUT_DVI: u8 = (1 << 7) | 0b0001; - const EDID_VIDEO_INPUT_HDMI_A: u8 = (1 << 7) | 0b0010; - const EDID_VIDEO_INPUT_HDMI_B: u8 = (1 << 7) | 0b0011; - const EDID_VIDEO_INPUT_DP: u8 = (1 << 7) | 0b0101; - const EDID_VIDEO_INPUT_MASK: u8 = (1 << 7) | 0b1111; - let input = match edid_data[20] & EDID_VIDEO_INPUT_MASK { - //TODO: how to accurately discover input type? - //TODO: HDMI often shows up as undefined, do others? - EDID_VIDEO_INPUT_UNDEFINED - | EDID_VIDEO_INPUT_DVI - | EDID_VIDEO_INPUT_HDMI_A - | EDID_VIDEO_INPUT_HDMI_B => VideoInput::Hdmi, - EDID_VIDEO_INPUT_DP => VideoInput::Dp, - unknown => { - log::warn!("EDID video input 0x{:02X} not supported", unknown); - return Err(Error::new(EIO)); - } - }; - //TODO: DisplayPort modeset not complete - match modeset(ddi, input) { - Ok(()) => { - log::info!("DDI {} modeset {:?} finished", ddi.name, input); - } - Err(err) => { - log::warn!("DDI {} modeset {:?} failed: {}", ddi.name, input, err); - // Will try again but not fail the driver - return Ok(false); - } - } - } else { - log::info!("DDI {} already active", ddi.name); - } - - Ok(true) - } - - pub fn handle_display_irq(&mut self) -> bool { - let display_ints = self.int.display_int_ctl.read() & !self.int.display_int_ctl_enable; - if display_ints != 0 { - log::info!(" display ints {:08X}", display_ints); - if display_ints & self.int.display_int_ctl_sde != 0 { - let sde_ints = self.int.sde_interrupt.iir.read(); - self.int.sde_interrupt.iir.write(sde_ints); - log::info!(" south display engine ints {:08X}", sde_ints); - for ddi in self.ddis.iter() { - if let Some(sde_interrupt_hotplug) = ddi.sde_interrupt_hotplug { - if sde_ints & sde_interrupt_hotplug == sde_interrupt_hotplug { - self.events.push_back(Event::DdiHotplug(ddi.name)); - } - } - } - } - true - } else { - false - } - } - - pub fn handle_irq(&mut self) -> bool { - let had_irq = if let Some(gfx_mstr_intr) = &mut self.int.gfx_mstr_intr { - let gfx_ints = gfx_mstr_intr.read() & !self.int.gfx_mstr_intr_enable; - if gfx_ints != 0 { - log::info!("gfx ints {:08X}", gfx_ints); - gfx_mstr_intr.write(gfx_ints | self.int.gfx_mstr_intr_enable); - - if gfx_ints & self.int.gfx_mstr_intr_display != 0 { - self.handle_display_irq(); - } - - true - } else { - false - } - } else { - self.handle_display_irq() - }; - - if had_irq { - for change_detect in self.int.change_detects.iter_mut() { - change_detect.check(); - } - } - - had_irq - } - - pub fn handle_events(&mut self) { - while let Some(event) = self.events.pop_front() { - match event { - Event::DdiHotplug(ddi_name) => { - log::info!("DDI {} plugged", ddi_name); - for _attempt in 0..4 { - //TODO: gmbus times out! - match self.probe_ddi(ddi_name) { - Ok(true) => { - break; - } - Ok(false) => { - log::warn!("timeout probing {}", ddi_name); - } - Err(err) => { - log::warn!("failed to probe {}: {}", ddi_name, err); - } - } - //TODO: do this asynchronously so scheme events can be handled - std::thread::sleep(std::time::Duration::from_secs(1)); - } - } - } - } - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/pipe.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/pipe.rs deleted file mode 100644 index 0e99ffe431..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/pipe.rs +++ /dev/null @@ -1,356 +0,0 @@ -use common::io::{Io, MmioPtr}; -use range_alloc::RangeAllocator; -use syscall::error::Result; -use syscall::{Error, EIO}; - -use super::buffer::GpuBuffer; -use super::{GlobalGtt, MmioRegion}; - -pub const PLANE_CTL_ENABLE: u32 = 1 << 31; - -pub const PLANE_WM_ENABLE: u32 = 1 << 31; -pub const PLANE_WM_LINES_SHIFT: u32 = 14; - -#[derive(Debug)] -pub struct DeviceFb { - pub buffer: GpuBuffer, - pub width: u32, - pub height: u32, - pub stride: u32, -} - -impl DeviceFb { - pub unsafe fn new( - gm: &MmioRegion, - surf: u32, - width: u32, - height: u32, - stride: u32, - clear: bool, - ) -> Self { - Self { - buffer: unsafe { GpuBuffer::new(gm, surf, stride * height, clear) }, - width, - height, - stride, - } - } - - pub fn alloc( - gm: &MmioRegion, - ggtt: &mut GlobalGtt, - width: u32, - height: u32, - ) -> syscall::Result { - let (buffer, stride) = GpuBuffer::alloc_dumb(gm, ggtt, width, height)?; - - Ok(DeviceFb { - buffer, - width, - height, - stride, - }) - } -} - -pub struct Plane { - pub name: &'static str, - pub index: usize, - pub buf_cfg: MmioPtr, - pub color_ctl: Option>, - pub color_ctl_gamma_disable: u32, - pub ctl: MmioPtr, - pub ctl_source_rgb_8888: u32, - pub ctl_source_mask: u32, - pub offset: MmioPtr, - pub pos: MmioPtr, - pub size: MmioPtr, - pub stride: MmioPtr, - pub surf: MmioPtr, - pub wm: [MmioPtr; 8], - pub wm_trans: MmioPtr, -} - -impl Plane { - pub fn fetch_modeset(&self, alloc_buffers: &mut RangeAllocator) { - let buf_cfg = self.buf_cfg.read(); - let buffer_start = buf_cfg & 0x7FF; - let buffer_end = (buf_cfg >> 16) & 0x7FF; - alloc_buffers - .allocate_exact_range(buffer_start..(buffer_end + 1)) - .unwrap_or_else(|err| { - panic!( - "failed to allocate pre-existing buffer blocks {} to {}: {:?}", - buffer_start, buffer_end, err - ); - }); - } - - pub fn modeset(&mut self, alloc_buffers: &mut RangeAllocator) -> syscall::Result<()> { - // FIXME handle runtime buffer reconfiguration - //TODO: enable DBUF if more buffers needed - //TODO: more blocks would mean better power usage - // Minimum is 8 blocks for linear planes, 160 blocks is recommended for pre-OS init - let buffer_size = 160; - let buffer = alloc_buffers.allocate_range(buffer_size).map_err(|err| { - log::warn!( - "failed to allocate {} buffer blocks: {:?}", - buffer_size, - err - ); - Error::new(EIO) - })?; - self.buf_cfg.write(buffer.start | (buffer.end << 16)); - - //TODO: correct watermark calculation - self.wm[0].write(PLANE_WM_ENABLE | (2 << PLANE_WM_LINES_SHIFT) | buffer.len() as u32); - for i in 1..self.wm.len() { - self.wm[i].writef(PLANE_WM_ENABLE, false); - } - self.wm_trans.writef(PLANE_WM_ENABLE, false); - - Ok(()) - } - - pub fn fetch_framebuffer(&self, gm: &MmioRegion, ggtt: &mut GlobalGtt) -> DeviceFb { - let size = self.size.read(); - let width = (size & 0xFFFF) + 1; - let height = ((size >> 16) & 0xFFFF) + 1; - let stride_64 = self.stride.read() & 0x7FF; - //TODO: this will be wrong for tiled planes - let stride = stride_64 * 64; - let surf = self.surf.read() & 0xFFFFF000; - //TODO: read bits per pixel - let surf_size = (stride * height).next_multiple_of(4096); - ggtt.reserve(surf, surf_size); - - unsafe { DeviceFb::new(gm, surf, width, height, stride, true) } - } - - pub fn set_framebuffer(&mut self, fb: &DeviceFb) { - //TODO: documentation on this is not great - let stride_64 = fb.stride / 64; - - self.size.write((fb.width - 1) | ((fb.height - 1) << 16)); - self.stride.write(stride_64); - - self.surf.write(fb.buffer.gm_offset); - - // Disable gamma - if let Some(color_ctl) = &mut self.color_ctl { - color_ctl.write(self.color_ctl_gamma_disable); - } - - //TODO: more PLANE_CTL bits - self.ctl.write(PLANE_CTL_ENABLE | self.ctl_source_rgb_8888); - } - - pub fn dump(&self) { - eprint!("Plane {}", self.name); - eprint!(" buf_cfg {:08X}", self.buf_cfg.read()); - if let Some(reg) = &self.color_ctl { - eprint!(" color_ctl {:08X}", reg.read()); - } - eprint!(" ctl {:08X}", self.ctl.read()); - eprint!(" offset {:08X}", self.offset.read()); - eprint!(" pos {:08X}", self.offset.read()); - eprint!(" size {:08X}", self.size.read()); - eprint!(" stride {:08X}", self.stride.read()); - eprint!(" surf {:08X}", self.surf.read()); - for i in 0..self.wm.len() { - eprint!(" wm_{} {:08X}", i, self.wm[i].read()); - } - eprint!(" wm_trans {:08X}", self.wm_trans.read()); - eprintln!(); - } -} - -pub struct Pipe { - pub name: &'static str, - pub index: usize, - pub planes: Vec, - pub bottom_color: MmioPtr, - pub misc: MmioPtr, - pub srcsz: MmioPtr, -} - -impl Pipe { - pub fn dump(&self) { - eprint!("Pipe {}", self.name); - eprint!(" bottom_color {:08X}", self.bottom_color.read()); - eprint!(" misc {:08X}", self.misc.read()); - eprint!(" srcsz {:08X}", self.srcsz.read()); - eprintln!(); - } - - pub fn kabylake(gttmm: &MmioRegion) -> Result> { - let mut pipes = Vec::with_capacity(3); - for (i, name) in ["A", "B", "C"].iter().enumerate() { - let mut planes = Vec::new(); - //TODO: cursor plane - for (j, name) in ["1", "2", "3"].iter().enumerate() { - planes.push(Plane { - name, - index: j, - // IHD-OS-KBL-Vol 2c-1.17 PLANE_BUF_CFG - buf_cfg: unsafe { gttmm.mmio(0x7027C + i * 0x1000 + j * 0x100)? }, - // N/A - color_ctl: None, - color_ctl_gamma_disable: 0, - // IHD-OS-KBL-Vol 2c-1.17 PLANE_CTL - ctl: unsafe { gttmm.mmio(0x70180 + i * 0x1000 + j * 0x100)? }, - ctl_source_rgb_8888: 0b0100 << 24, - ctl_source_mask: 0b1111 << 24, - // IHD-OS-KBL-Vol 2c-1.17 PLANE_OFFSET - offset: unsafe { gttmm.mmio(0x701A4 + i * 0x1000 + j * 0x100)? }, - // IHD-OS-KBL-Vol 2c-1.17 PLANE_POS - pos: unsafe { gttmm.mmio(0x7018C + i * 0x1000 + j * 0x100)? }, - // IHD-OS-KBL-Vol 2c-1.17 PLANE_SIZE - size: unsafe { gttmm.mmio(0x70190 + i * 0x1000 + j * 0x100)? }, - // IHD-OS-KBL-Vol 2c-1.17 PLANE_STRIDE - stride: unsafe { gttmm.mmio(0x70188 + i * 0x1000 + j * 0x100)? }, - // IHD-OS-KBL-Vol 2c-1.17 PLANE_SURF - surf: unsafe { gttmm.mmio(0x7019C + i * 0x1000 + j * 0x100)? }, - // IHD-OS-KBL-Vol 2c-1.17 PLANE_WM - wm: [ - unsafe { gttmm.mmio(0x70240 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70244 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70248 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x7024C + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70250 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70254 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70258 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x7025C + i * 0x1000 + j * 0x100)? }, - ], - wm_trans: unsafe { gttmm.mmio(0x70268 + i * 0x1000 + j * 0x100)? }, - }); - } - pipes.push(Pipe { - name, - index: i, - planes, - // IHD-OS-KBL-Vol 2c-1.17 PIPE_BOTTOM_COLOR - bottom_color: unsafe { gttmm.mmio(0x70034 + i * 0x1000)? }, - // IHD-OS-KBL-Vol 2c-1.17 PIPE_MISC - misc: unsafe { gttmm.mmio(0x70030 + i * 0x1000)? }, - // IHD-OS-KBL-Vol 2c-1.17 PIPE_SRCSZ - srcsz: unsafe { gttmm.mmio(0x6001C + i * 0x1000)? }, - }) - } - Ok(pipes) - } - - pub fn tigerlake(gttmm: &MmioRegion) -> Result> { - let mut pipes = Vec::with_capacity(4); - for (i, name) in ["A", "B", "C", "D"].iter().enumerate() { - let mut planes = Vec::new(); - //TODO: cursor plane - for (j, name) in ["1", "2", "3", "4", "5", "6", "7"].iter().enumerate() { - planes.push(Plane { - name, - index: j, - // IHD-OS-TGL-Vol 2c-12.21 PLANE_BUF_CFG - buf_cfg: unsafe { gttmm.mmio(0x7027C + i * 0x1000 + j * 0x100)? }, - // IHD-OS-TGL-Vol 2c-12.21 PLANE_COLOR_CTL - color_ctl: Some(unsafe { gttmm.mmio(0x701CC + i * 0x1000 + j * 0x100)? }), - color_ctl_gamma_disable: 1 << 13, - // IHD-OS-TGL-Vol 2c-12.21 PLANE_CTL - ctl: unsafe { gttmm.mmio(0x70180 + i * 0x1000 + j * 0x100)? }, - ctl_source_rgb_8888: 0b01000 << 23, - ctl_source_mask: 0b11111 << 23, - // IHD-OS-TGL-Vol 2c-12.21 PLANE_OFFSET - offset: unsafe { gttmm.mmio(0x701A4 + i * 0x1000 + j * 0x100)? }, - // IHD-OS-TGL-Vol 2c-12.21 PLANE_POS - pos: unsafe { gttmm.mmio(0x7018C + i * 0x1000 + j * 0x100)? }, - // IHD-OS-TGL-Vol 2c-12.21 PLANE_SIZE - size: unsafe { gttmm.mmio(0x70190 + i * 0x1000 + j * 0x100)? }, - // IHD-OS-TGL-Vol 2c-12.21 PLANE_STRIDE - stride: unsafe { gttmm.mmio(0x70188 + i * 0x1000 + j * 0x100)? }, - // IHD-OS-TGL-Vol 2c-12.21 PLANE_SURF - surf: unsafe { gttmm.mmio(0x7019C + i * 0x1000 + j * 0x100)? }, - // IHD-OS-TGL-Vol 2c-12.21 PLANE_WM - wm: [ - unsafe { gttmm.mmio(0x70240 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70244 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70248 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x7024C + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70250 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70254 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70258 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x7025C + i * 0x1000 + j * 0x100)? }, - ], - wm_trans: unsafe { gttmm.mmio(0x70268 + i * 0x1000 + j * 0x100)? }, - }); - } - pipes.push(Pipe { - name, - index: i, - planes, - // IHD-OS-TGL-Vol 2c-12.21 PIPE_BOTTOM_COLOR - bottom_color: unsafe { gttmm.mmio(0x70034 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 PIPE_MISC - misc: unsafe { gttmm.mmio(0x70030 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 PIPE_SRCSZ - srcsz: unsafe { gttmm.mmio(0x6001C + i * 0x1000)? }, - }) - } - Ok(pipes) - } - - pub fn alchemist(gttmm: &MmioRegion) -> Result> { - let mut pipes = Vec::with_capacity(4); - for (i, name) in ["A", "B", "C", "D"].iter().enumerate() { - let mut planes = Vec::new(); - //TODO: cursor plane - for (j, name) in ["1", "2", "3", "4", "5"].iter().enumerate() { - planes.push(Plane { - name, - index: j, - // IHD-OS-ACM-Vol 2c-3.23 PLANE_BUF_CFG - buf_cfg: unsafe { gttmm.mmio(0x7057C + i * 0x1000 + j * 0x100)? }, - // IHD-OS-ACM-Vol 2c-3.23 PLANE_COLOR_CTL - color_ctl: Some(unsafe { gttmm.mmio(0x704CC + i * 0x1000 + j * 0x100)? }), - color_ctl_gamma_disable: 1 << 13, - // IHD-OS-ACM-Vol 2c-3.23 PLANE_CTL - ctl: unsafe { gttmm.mmio(0x70480 + i * 0x1000 + j * 0x100)? }, - ctl_source_rgb_8888: 0b01000 << 23, - ctl_source_mask: 0b11111 << 23, - // IHD-OS-ACM-Vol 2c-3.23 PLANE_OFFSET - offset: unsafe { gttmm.mmio(0x704A4 + i * 0x1000 + j * 0x100)? }, - // IHD-OS-ACM-Vol 2c-3.23 PLANE_POS - pos: unsafe { gttmm.mmio(0x7048C + i * 0x1000 + j * 0x100)? }, - // IHD-OS-ACM-Vol 2c-3.23 PLANE_SIZE - size: unsafe { gttmm.mmio(0x70490 + i * 0x1000 + j * 0x100)? }, - // IHD-OS-ACM-Vol 2c-3.23 PLANE_STRIDE - stride: unsafe { gttmm.mmio(0x70488 + i * 0x1000 + j * 0x100)? }, - // IHD-OS-ACM-Vol 2c-3.23 PLANE_SURF - surf: unsafe { gttmm.mmio(0x7049C + i * 0x1000 + j * 0x100)? }, - // IHD-OS-ACM-Vol 2c-3.23 PLANE_WM - wm: [ - unsafe { gttmm.mmio(0x70540 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70544 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70548 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x7054C + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70550 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70554 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x70558 + i * 0x1000 + j * 0x100)? }, - unsafe { gttmm.mmio(0x7055C + i * 0x1000 + j * 0x100)? }, - ], - wm_trans: unsafe { gttmm.mmio(0x70568 + i * 0x1000 + j * 0x100)? }, - }); - } - pipes.push(Pipe { - name, - index: i, - planes, - // IHD-OS-ACM-Vol 2c-3.23 PIPE_BOTTOM_COLOR - bottom_color: unsafe { gttmm.mmio(0x70034 + i * 0x1000)? }, - // IHD-OS-ACM-Vol 2c-3.23 PIPE_MISC - misc: unsafe { gttmm.mmio(0x70030 + i * 0x1000)? }, - // IHD-OS-ACM-Vol 2c-3.23 PIPE_SRCSZ - srcsz: unsafe { gttmm.mmio(0x6001C + i * 0x1000)? }, - }) - } - Ok(pipes) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/power.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/power.rs deleted file mode 100644 index 77335ae064..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/power.rs +++ /dev/null @@ -1,323 +0,0 @@ -use common::{ - io::{Io, MmioPtr}, - timeout::Timeout, -}; -use syscall::error::{Error, Result, EIO}; - -use super::MmioRegion; - -#[derive(Clone, Copy)] -pub struct PowerWell { - pub name: &'static str, - pub depends: &'static [&'static str], - pub ddis: &'static [&'static str], - pub pipes: &'static [&'static str], - pub transcoders: &'static [&'static str], - pub request: u32, - pub state: u32, - pub fuse_status: u32, -} - -pub struct PowerWells { - pub ctl: MmioPtr, - pub ctl_aux: MmioPtr, - pub ctl_ddi: MmioPtr, - pub fuse_status: MmioPtr, - pub fuse_status_pg0: u32, - pub wells: Vec, -} - -impl PowerWells { - //TODO: return guard? - pub fn enable_well(&mut self, name: &'static str) -> Result<()> { - // Wait 20us for distribution of PG0 - { - let timeout = Timeout::from_micros(20); - while !self.fuse_status.readf(self.fuse_status_pg0) { - timeout.run().map_err(|()| { - log::warn!("timeout on distribution of power well 0"); - Error::new(EIO) - })?; - } - } - - // self.wells iter copied to allow mutable self.enable_well later - for well in self.wells.iter().copied() { - if well.name == name { - // Enable dependent wells - for depend in well.depends.iter() { - self.enable_well(depend)?; - } - - if !self.ctl.readf(well.request) { - log::info!("enabling power well {}", well.name); - } - - // Set request bit - self.ctl.writef(well.request, true); - - // Wait 100us for enabled state - { - let timeout = Timeout::from_micros(100); - while !self.ctl.readf(well.state) { - timeout.run().map_err(|()| { - log::warn!("timeout enabling power well {}", well.name); - Error::new(EIO) - })?; - } - } - - // Wait 20us for distribution - { - let timeout = Timeout::from_micros(20); - while !self.fuse_status.readf(well.fuse_status) { - timeout.run().map_err(|()| { - log::warn!("timeout on distribution of power well {}", well.name); - Error::new(EIO) - })?; - } - } - - return Ok(()); - } - } - log::warn!("power well {} not found", name); - Err(Error::new(EIO)) - } - - pub fn enable_well_by_ddi(&mut self, name: &'static str) -> Result<()> { - for well in self.wells.iter() { - if well.ddis.contains(&name) { - return self.enable_well(well.name); - } - } - log::warn!("power well for DDI {} not found", name); - Err(Error::new(EIO)) - } - - pub fn enable_well_by_pipe(&mut self, name: &'static str) -> Result<()> { - for well in self.wells.iter() { - if well.pipes.contains(&name) { - return self.enable_well(well.name); - } - } - log::warn!("power well for pipe {} not found", name); - Err(Error::new(EIO)) - } - - pub fn enable_well_by_transcoder(&mut self, name: &'static str) -> Result<()> { - for well in self.wells.iter() { - if well.transcoders.contains(&name) { - return self.enable_well(well.name); - } - } - log::warn!("power well for transcoder {} not found", name); - Err(Error::new(EIO)) - } - - pub fn kabylake(gttmm: &MmioRegion) -> Result { - // IHD-OS-KBL-Vol 2c-1.17 PWR_WELL_CTL - let ctl = unsafe { gttmm.mmio(0x45404)? }; - // Hack since these power ctl registers are combined - let ctl_aux = unsafe { gttmm.mmio(0x45404)? }; - let ctl_ddi = unsafe { gttmm.mmio(0x45404)? }; - // IHD-OS-KBL-Vol 2c-1.17 FUSE_STATUS - let fuse_status = unsafe { gttmm.mmio(0x42000)? }; - let fuse_status_pg0 = 1 << 27; - let wells = vec![ - PowerWell { - name: "1", - depends: &[], - ddis: &["A"], - pipes: &["A"], - transcoders: &["EDP"], - request: 1 << 29, - state: 1 << 28, - fuse_status: 1 << 26, - }, - PowerWell { - name: "2", - depends: &["1"], - ddis: &["B", "C", "D", "E"], - pipes: &["B", "C"], - transcoders: &["A", "B", "C"], - request: 1 << 31, - state: 1 << 30, - fuse_status: 1 << 25, - }, - ]; - Ok(Self { - ctl, - ctl_aux, - ctl_ddi, - fuse_status, - fuse_status_pg0, - wells, - }) - } - - pub fn tigerlake(gttmm: &MmioRegion) -> Result { - // IHD-OS-TGL-Vol 2c-12.21 PWR_WELL_CTL - let ctl = unsafe { gttmm.mmio(0x45404)? }; - // IHD-OS-TGL-Vol 2c-12.21 PWR_WELL_CTL_AUX - let ctl_aux = unsafe { gttmm.mmio(0x45444)? }; - // IHD-OS-TGL-Vol 2c-12.21 PWR_WELL_CTL_DDI - let ctl_ddi = unsafe { gttmm.mmio(0x45454)? }; - // IHD-OS-TGL-Vol 2c-12.21 FUSE_STATUS - let fuse_status = unsafe { gttmm.mmio(0x42000)? }; - let fuse_status_pg0 = 1 << 27; - let wells = vec![ - // DBUF functionality, Pipe A, Transcoder A and DSI, DDI A-C, FBC, DSS - PowerWell { - name: "1", - depends: &[], - ddis: &["A", "B", "C"], - pipes: &["A"], - transcoders: &["A"], - request: 1 << 1, - state: 1 << 0, - fuse_status: 1 << 26, - }, - // VDSC for pipe A - PowerWell { - name: "2", - depends: &["1"], - ddis: &[], - pipes: &[], - transcoders: &[], - request: 1 << 3, - state: 1 << 2, - fuse_status: 1 << 25, - }, - // Pipe B, Audio, Transcoder WD, VGA, Transcoder B, DDI USBC1-6, KVMR - PowerWell { - name: "3", - depends: &["2"], - ddis: &["USBC1", "USBC2", "USBC3", "USBC4", "USBC5", "USBC6"], - pipes: &["B"], - transcoders: &["B"], - request: 1 << 5, - state: 1 << 4, - fuse_status: 1 << 24, - }, - // Pipe C, Transcoder C - PowerWell { - name: "4", - depends: &["3"], - ddis: &[], - pipes: &["C"], - transcoders: &["C"], - request: 1 << 7, - state: 1 << 6, - fuse_status: 1 << 23, - }, - // Pipe D, Transcoder D - PowerWell { - name: "5", - depends: &["4"], - ddis: &[], - pipes: &["D"], - transcoders: &["D"], - request: 1 << 9, - state: 1 << 8, - fuse_status: 1 << 22, - }, - ]; - Ok(Self { - ctl, - ctl_aux, - ctl_ddi, - fuse_status, - fuse_status_pg0, - wells, - }) - } - - pub fn alchemist(gttmm: &MmioRegion) -> Result { - // IHD-OS-ACM-Vol 2c-3.23 PWR_WELL_CTL - let ctl = unsafe { gttmm.mmio(0x45404)? }; - // IHD-OS-ACM-Vol 2c-3.23 PWR_WELL_CTL_AUX - let ctl_aux = unsafe { gttmm.mmio(0x45444)? }; - // IHD-OS-ACM-Vol 2c-3.23 PWR_WELL_CTL_DDI - let ctl_ddi = unsafe { gttmm.mmio(0x45454)? }; - // IHD-OS-ACM-Vol 2c-3.23 FUSE_STATUS - let fuse_status = unsafe { gttmm.mmio(0x42000)? }; - let fuse_status_pg0 = 1 << 27; - let wells = vec![ - // DBUF functionality, Transcoder A, DDI A-B - PowerWell { - name: "1", - depends: &[], - ddis: &["A", "B"], - pipes: &[], - transcoders: &["A"], - request: 1 << 1, - state: 1 << 0, - fuse_status: 1 >> 26, - }, - // Audio playback, Transcoder WD, VGA, DDI C-E, Type-C, KVMR - PowerWell { - name: "2", - depends: &["1"], - ddis: &["C", "D", "E", "USBC1", "USBC2", "USBC3", "USBC4"], - pipes: &[], - transcoders: &[], - request: 1 << 3, - state: 1 << 2, - fuse_status: 1 << 25, - }, - // Pipe A, FBC - PowerWell { - name: "A", - depends: &["1"], - ddis: &[], - pipes: &["A"], - transcoders: &[], - request: 1 << 11, - state: 1 << 10, - fuse_status: 1 << 21, - }, - // Pipe B, Transcoder B - PowerWell { - name: "B", - depends: &["2"], - ddis: &[], - pipes: &["B"], - transcoders: &["B"], - request: 1 << 13, - state: 1 << 12, - fuse_status: 1 << 20, - }, - // Pipe C, Transcoder C - PowerWell { - name: "C", - depends: &["2"], - ddis: &[], - pipes: &["C"], - transcoders: &["C"], - request: 1 << 15, - state: 1 << 14, - fuse_status: 1 << 19, - }, - // Pipe D, Transcoder D - PowerWell { - name: "D", - depends: &["2"], - ddis: &[], - pipes: &["D"], - transcoders: &["D"], - request: 1 << 17, - state: 1 << 16, - fuse_status: 1 << 18, - }, - ]; - Ok(Self { - ctl, - ctl_aux, - ctl_ddi, - fuse_status, - fuse_status_pg0, - wells, - }) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/scheme.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/scheme.rs deleted file mode 100644 index 95db5bbffb..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/scheme.rs +++ /dev/null @@ -1,208 +0,0 @@ -//TODO: this is copied from vesad and should be adapted - -use std::alloc::{self, Layout}; -use std::convert::TryInto; -use std::ptr::{self, NonNull}; -use std::sync::Mutex; - -use driver_graphics::kms::connector::{KmsConnectorDriver, KmsConnectorStatus}; -use driver_graphics::kms::objects::{KmsCrtc, KmsCrtcState, KmsObjectId, KmsObjects}; -use driver_graphics::{Buffer, CursorPlane, Damage, GraphicsAdapter}; -use drm_sys::{ - DRM_CAP_DUMB_BUFFER, DRM_CAP_DUMB_PREFER_SHADOW, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT, -}; -use syscall::{error::EINVAL, PAGE_SIZE}; - -use super::pipe::DeviceFb; -use super::Device; - -#[derive(Debug)] -pub struct Connector { - framebuffer_id: usize, -} - -impl KmsConnectorDriver for Connector { - type State = (); -} - -impl GraphicsAdapter for Device { - type Connector = Connector; - type Crtc = (); - - type Buffer = DumbFb; - type Framebuffer = (); - - fn name(&self) -> &'static [u8] { - b"ihdgd" - } - - fn desc(&self) -> &'static [u8] { - b"Intel HD Graphics" - } - - fn init(&mut self, objects: &mut KmsObjects) { - self.init_inner(); - - // FIXME enumerate actual connectors - for (framebuffer_id, _) in self.framebuffers.iter().enumerate() { - let crtc = objects.add_crtc((), ()); - - objects.add_connector(Connector { framebuffer_id }, (), &[crtc]); - } - } - - fn get_cap(&self, cap: u32) -> syscall::Result { - match cap { - DRM_CAP_DUMB_BUFFER => Ok(1), - DRM_CAP_DUMB_PREFER_SHADOW => Ok(0), - _ => Err(syscall::Error::new(EINVAL)), - } - } - - fn set_client_cap(&self, cap: u32, _value: u64) -> syscall::Result<()> { - match cap { - // FIXME hide cursor plane unless this client cap is set - DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT => Ok(()), - _ => Err(syscall::Error::new(EINVAL)), - } - } - - fn probe_connector(&mut self, objects: &mut KmsObjects, id: KmsObjectId) { - let mut connector = objects.get_connector(id).unwrap().lock().unwrap(); - let framebuffer = &self.framebuffers[connector.driver_data.framebuffer_id]; - connector.connection = KmsConnectorStatus::Connected; - connector.update_from_size(framebuffer.width as u32, framebuffer.height as u32); - // FIXME fetch EDID - } - - fn create_dumb_buffer(&mut self, width: u32, height: u32) -> (Self::Buffer, u32) { - (DumbFb::new(width as usize, height as usize), width * 4) - } - - fn map_dumb_buffer(&mut self, framebuffer: &Self::Buffer) -> *mut u8 { - framebuffer.ptr.as_ptr().cast::() - } - - fn create_framebuffer(&mut self, _buffer: &Self::Buffer) -> Self::Framebuffer { - () - } - - fn set_crtc( - &mut self, - objects: &KmsObjects, - crtc: &Mutex>, - state: KmsCrtcState, - damage: Damage, - ) -> syscall::Result<()> { - let mut crtc = crtc.lock().unwrap(); - let buffer = state - .fb_id - .map(|fb_id| objects.get_framebuffer(fb_id)) - .transpose()?; - crtc.state = state; - - for connector in objects.connectors() { - let connector = connector.lock().unwrap(); - - if connector.state.crtc_id != objects.crtc_ids()[crtc.crtc_index as usize] { - continue; - } - - let framebuffer_id = connector.driver_data.framebuffer_id; - - let framebuffer = &mut self.framebuffers[framebuffer_id]; - if let Some(buffer) = buffer { - buffer.buffer.sync(framebuffer, damage) - } else { - let onscreen_ptr = framebuffer.buffer.virt.cast::(); - for row in 0..framebuffer.height { - unsafe { - ptr::write_bytes( - onscreen_ptr.add((row * framebuffer.stride) as usize), - 0, - framebuffer.width as usize, - ); - } - } - } - } - - Ok(()) - } - - fn hw_cursor_size(&self) -> Option<(u32, u32)> { - None - } - - fn handle_cursor(&mut self, _cursor: &CursorPlane, _dirty_fb: bool) { - unimplemented!("ihdgd does not support this function"); - } -} - -#[derive(Debug)] -pub struct DumbFb { - width: usize, - height: usize, - ptr: NonNull<[u32]>, -} - -impl DumbFb { - fn new(width: usize, height: usize) -> DumbFb { - let len = width * height; - let layout = Self::layout(len); - let ptr = unsafe { alloc::alloc_zeroed(layout) }; - let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len); - let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout)); - - DumbFb { width, height, ptr } - } - - #[inline] - fn layout(len: usize) -> Layout { - // optimizes to an integer mul - Layout::array::(len) - .unwrap() - .align_to(PAGE_SIZE) - .unwrap() - } -} - -impl Drop for DumbFb { - fn drop(&mut self) { - let layout = Self::layout(self.ptr.len()); - unsafe { alloc::dealloc(self.ptr.as_ptr().cast(), layout) }; - } -} - -impl Buffer for DumbFb { - fn size(&self) -> usize { - self.width * self.height * 4 - } -} - -impl DumbFb { - fn sync(&self, framebuffer: &mut DeviceFb, sync_rect: Damage) { - let sync_rect = sync_rect.clip( - self.width.try_into().unwrap(), - self.height.try_into().unwrap(), - ); - - let start_x: usize = sync_rect.x.try_into().unwrap(); - let start_y: usize = sync_rect.y.try_into().unwrap(); - let w: usize = sync_rect.width.try_into().unwrap(); - let h: usize = sync_rect.height.try_into().unwrap(); - - let offscreen_ptr = self.ptr.as_ptr() as *mut u32; - let onscreen_ptr = framebuffer.buffer.virt.cast::(); - - for row in start_y..start_y + h { - unsafe { - ptr::copy( - offscreen_ptr.add(row * self.width + start_x), - onscreen_ptr.add(row * framebuffer.stride as usize / 4 + start_x), - w, - ); - } - } - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/device/transcoder.rs b/recipes/core/base/drivers/graphics/ihdgd/src/device/transcoder.rs deleted file mode 100644 index f5a23be1e2..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/device/transcoder.rs +++ /dev/null @@ -1,258 +0,0 @@ -use common::io::{Io, MmioPtr}; -use syscall::error::Result; - -use super::{MmioRegion, Pipe}; - -// IHD-OS-KBL-Vol 2c-1.17 TRANS_CONF -// IHD-OS-TGL-Vol 2c-12.21 TRANS_CONF -pub const TRANS_CONF_ENABLE: u32 = 1 << 31; -pub const TRANS_CONF_STATE: u32 = 1 << 30; -pub const TRANS_CONF_MODE_MASK: u32 = 0b11 << 21; - -// IHD-OS-KBL-Vol 2c-1.17 TRANS_DDI_FUNC_CTL -// IHD-OS-TGL-Vol 2c-12.21 TRANS_DDI_FUNC_CTL -pub const TRANS_DDI_FUNC_CTL_ENABLE: u32 = 1 << 31; -pub const TRANS_DDI_FUNC_CTL_MODE_HDMI: u32 = 0b000 << 24; -pub const TRANS_DDI_FUNC_CTL_MODE_DVI: u32 = 0b001 << 24; -pub const TRANS_DDI_FUNC_CTL_MODE_DP_SST: u32 = 0b010 << 24; -pub const TRANS_DDI_FUNC_CTL_MODE_DP_MST: u32 = 0b011 << 24; -pub const TRANS_DDI_FUNC_CTL_BPC_8: u32 = 0b000 << 20; -pub const TRANS_DDI_FUNC_CTL_BPC_10: u32 = 0b001 << 20; -pub const TRANS_DDI_FUNC_CTL_BPC_6: u32 = 0b010 << 20; -pub const TRANS_DDI_FUNC_CTL_BPC_12: u32 = 0b011 << 20; -pub const TRANS_DDI_FUNC_CTL_SYNC_POLARITY_HSHIGH: u32 = 0b01 << 16; -pub const TRANS_DDI_FUNC_CTL_SYNC_POLARITY_VSHIGH: u32 = 0b10 << 16; -pub const TRANS_DDI_FUNC_CTL_DSI_INPUT_PIPE_SHIFT: u32 = 12; -pub const TRANS_DDI_FUNC_CTL_PORT_WIDTH_1: u32 = 0b000 << 1; -pub const TRANS_DDI_FUNC_CTL_PORT_WIDTH_2: u32 = 0b001 << 1; -pub const TRANS_DDI_FUNC_CTL_PORT_WIDTH_3: u32 = 0b010 << 1; -pub const TRANS_DDI_FUNC_CTL_PORT_WIDTH_4: u32 = 0b011 << 1; - -pub struct Transcoder { - pub name: &'static str, - pub index: usize, - pub clk_sel: MmioPtr, - pub clk_sel_shift: u32, - pub conf: MmioPtr, - pub ddi_func_ctl: MmioPtr, - pub ddi_func_ctl_ddi_shift: u32, - pub ddi_func_ctl_hdmi_scrambling: u32, - pub ddi_func_ctl_high_tmds_char_rate: u32, - pub ddi_func_ctl2: Option>, - pub hblank: MmioPtr, - pub hsync: MmioPtr, - pub htotal: MmioPtr, - pub msa_misc: MmioPtr, - pub mult: MmioPtr, - pub push: Option>, - pub space: MmioPtr, - pub stereo3d_ctl: MmioPtr, - pub vblank: MmioPtr, - pub vrr_ctl: Option>, - pub vrr_flipline: Option>, - pub vrr_status: Option>, - pub vrr_status2: Option>, - pub vrr_vmax: Option>, - pub vrr_vmaxshift: Option>, - pub vrr_vmin: Option>, - pub vrr_vtotal_prev: Option>, - pub vsync: MmioPtr, - pub vsyncshift: MmioPtr, - pub vtotal: MmioPtr, -} - -impl Transcoder { - pub fn dump(&self) { - eprint!("Transcoder {} {}", self.name, self.index); - eprint!(" clk_sel {:08X}", self.clk_sel.read()); - eprint!(" conf {:08X}", self.conf.read()); - eprint!(" ddi_func_ctl {:08X}", self.ddi_func_ctl.read()); - if let Some(reg) = &self.ddi_func_ctl2 { - eprint!(" ddi_func_ctl2 {:08X}", reg.read()); - } - eprint!(" hblank {:08X}", self.hblank.read()); - eprint!(" hsync {:08X}", self.hsync.read()); - eprint!(" htotal {:08X}", self.htotal.read()); - eprint!(" msa_misc {:08X}", self.msa_misc.read()); - eprint!(" mult {:08X}", self.mult.read()); - if let Some(reg) = &self.push { - eprint!(" push {:08X}", reg.read()); - } - eprint!(" space {:08X}", self.space.read()); - eprint!(" stereo3d_ctl {:08X}", self.stereo3d_ctl.read()); - eprint!(" vblank {:08X}", self.vblank.read()); - if let Some(reg) = &self.vrr_ctl { - eprint!(" vrr_ctl {:08X}", reg.read()); - } - if let Some(reg) = &self.vrr_flipline { - eprint!(" vrr_flipline {:08X}", reg.read()); - } - if let Some(reg) = &self.vrr_status { - eprint!(" vrr_status {:08X}", reg.read()); - } - if let Some(reg) = &self.vrr_status2 { - eprint!(" vrr_status2 {:08X}", reg.read()); - } - if let Some(reg) = &self.vrr_vmax { - eprint!(" vrr_vmax {:08X}", reg.read()); - } - if let Some(reg) = &self.vrr_vmaxshift { - eprint!(" vrr_vmaxshift {:08X}", reg.read()); - } - if let Some(reg) = &self.vrr_vmin { - eprint!(" vrr_vmin {:08X}", reg.read()); - } - if let Some(reg) = &self.vrr_vtotal_prev { - eprint!(" vrr_vtotal_prev {:08X}", reg.read()); - } - eprint!(" vsync {:08X}", self.vsync.read()); - eprint!(" vsyncshift {:08X}", self.vsyncshift.read()); - eprint!(" vtotal {:08X}", self.vtotal.read()); - eprintln!(); - } - - pub fn modeset(&mut self, pipe: &mut Pipe, timing: &edid::DetailedTiming) { - let hactive = (timing.horizontal_active_pixels as u32) - 1; - let htotal = hactive + (timing.horizontal_blanking_pixels as u32); - let hsync_start = hactive + (timing.horizontal_front_porch as u32); - let hsync_end = hsync_start + (timing.horizontal_sync_width as u32); - let vactive = (timing.vertical_active_lines as u32) - 1; - let vtotal = vactive + (timing.vertical_blanking_lines as u32); - let vsync_start = vactive + (timing.vertical_front_porch as u32); - let vsync_end = vsync_start + (timing.vertical_sync_width as u32); - - // Configure horizontal sync - self.htotal.write(hactive | (htotal << 16)); - self.hblank.write(hactive | (htotal << 16)); - self.hsync.write(hsync_start | (hsync_end << 16)); - - // Configure vertical sync - self.vtotal.write(vactive | (vtotal << 16)); - self.vblank.write(vactive | (vtotal << 16)); - self.vsync.write(vsync_start | (vsync_end << 16)); - - // Configure pipe - pipe.srcsz.write(vactive | (hactive << 16)); - } - - pub fn kabylake(gttmm: &MmioRegion) -> Result> { - let mut transcoders = Vec::with_capacity(4); - //TODO: Transcoder EDP - for (i, name) in ["A", "B", "C"].iter().enumerate() { - transcoders.push(Transcoder { - name, - index: i, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_CLK_SEL - clk_sel: unsafe { gttmm.mmio(0x46140 + i * 0x4)? }, - clk_sel_shift: 29, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_CONF - conf: unsafe { gttmm.mmio(0x70008 + i * 0x1000)? }, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_DDI_FUNC_CTL - ddi_func_ctl: unsafe { gttmm.mmio(0x60400 + i * 0x1000)? }, - ddi_func_ctl_ddi_shift: 28, - // HDMI scrambling not supported on Kaby Lake - ddi_func_ctl_hdmi_scrambling: 0, - ddi_func_ctl_high_tmds_char_rate: 0, - // N/A - ddi_func_ctl2: None, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_HBLANK - hblank: unsafe { gttmm.mmio(0x60004 + i * 0x1000)? }, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_HSYNC - hsync: unsafe { gttmm.mmio(0x60008 + i * 0x1000)? }, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_HTOTAL - htotal: unsafe { gttmm.mmio(0x60000 + i * 0x1000)? }, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_MSA_MISC - msa_misc: unsafe { gttmm.mmio(0x60410 + i * 0x1000)? }, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_MULT - mult: unsafe { gttmm.mmio(0x6002C + i * 0x1000)? }, - // N/A - push: None, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_SPACE - space: unsafe { gttmm.mmio(0x60020 + i * 0x1000)? }, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_STEREO3D_CTL - stereo3d_ctl: unsafe { gttmm.mmio(0x70020 + i * 0x1000)? }, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_VBLANK - vblank: unsafe { gttmm.mmio(0x60010 + i * 0x1000)? }, - // N/A - vrr_ctl: None, - vrr_flipline: None, - vrr_status: None, - vrr_status2: None, - vrr_vmax: None, - vrr_vmaxshift: None, - vrr_vmin: None, - vrr_vtotal_prev: None, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_VSYNC - vsync: unsafe { gttmm.mmio(0x60014 + i * 0x1000)? }, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_VSYNCSHIFT - vsyncshift: unsafe { gttmm.mmio(0x60028 + i * 0x1000)? }, - // IHD-OS-KBL-Vol 2c-1.17 TRANS_VTOTAL - vtotal: unsafe { gttmm.mmio(0x6000C + i * 0x1000)? }, - }); - } - Ok(transcoders) - } - - pub fn tigerlake(gttmm: &MmioRegion) -> Result> { - let mut transcoders = Vec::with_capacity(4); - for (i, name) in ["A", "B", "C", "D"].iter().enumerate() { - transcoders.push(Transcoder { - name, - index: i, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_CLK_SEL - clk_sel: unsafe { gttmm.mmio(0x46140 + i * 0x4)? }, - clk_sel_shift: 28, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_CONF - conf: unsafe { gttmm.mmio(0x70008 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_DDI_FUNC_CTL - ddi_func_ctl: unsafe { gttmm.mmio(0x60400 + i * 0x1000)? }, - ddi_func_ctl_ddi_shift: 27, - ddi_func_ctl_hdmi_scrambling: 1 << 0, - ddi_func_ctl_high_tmds_char_rate: 1 << 4, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_DDI_FUNC_CTL2 - ddi_func_ctl2: Some(unsafe { gttmm.mmio(0x60404 + i * 0x1000)? }), - // IHD-OS-TGL-Vol 2c-12.21 TRANS_HBLANK - hblank: unsafe { gttmm.mmio(0x60004 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_HSYNC - hsync: unsafe { gttmm.mmio(0x60008 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_HTOTAL - htotal: unsafe { gttmm.mmio(0x60000 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_MSA_MISC - msa_misc: unsafe { gttmm.mmio(0x60410 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_MULT - mult: unsafe { gttmm.mmio(0x6002C + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_PUSH - push: Some(unsafe { gttmm.mmio(0x60A70 + i * 0x1000)? }), - // IHD-OS-TGL-Vol 2c-12.21 TRANS_SPACE - space: unsafe { gttmm.mmio(0x60020 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_STEREO3D_CTL - stereo3d_ctl: unsafe { gttmm.mmio(0x70020 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VBLANK - vblank: unsafe { gttmm.mmio(0x60010 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VRR_CTL - vrr_ctl: Some(unsafe { gttmm.mmio(0x60420 + i * 0x1000)? }), - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VRR_FLIPLINE - vrr_flipline: Some(unsafe { gttmm.mmio(0x60438 + i * 0x1000)? }), - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VRR_STATUS - vrr_status: Some(unsafe { gttmm.mmio(0x6042C + i * 0x1000)? }), - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VRR_STATUS2 - vrr_status2: Some(unsafe { gttmm.mmio(0x6043C + i * 0x1000)? }), - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VRR_VMAX - vrr_vmax: Some(unsafe { gttmm.mmio(0x60424 + i * 0x1000)? }), - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VRR_VMAXSHIFT - vrr_vmaxshift: Some(unsafe { gttmm.mmio(0x60428 + i * 0x1000)? }), - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VRR_VMIN - vrr_vmin: Some(unsafe { gttmm.mmio(0x60434 + i * 0x1000)? }), - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VRR_VTOTAL_PREV - vrr_vtotal_prev: Some(unsafe { gttmm.mmio(0x60480 + i * 0x1000)? }), - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VSYNC - vsync: unsafe { gttmm.mmio(0x60014 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VSYNCSHIFT - vsyncshift: unsafe { gttmm.mmio(0x60028 + i * 0x1000)? }, - // IHD-OS-TGL-Vol 2c-12.21 TRANS_VTOTAL - vtotal: unsafe { gttmm.mmio(0x6000C + i * 0x1000)? }, - }) - } - Ok(transcoders) - } -} diff --git a/recipes/core/base/drivers/graphics/ihdgd/src/main.rs b/recipes/core/base/drivers/graphics/ihdgd/src/main.rs deleted file mode 100644 index a8b6cc6038..0000000000 --- a/recipes/core/base/drivers/graphics/ihdgd/src/main.rs +++ /dev/null @@ -1,105 +0,0 @@ -use driver_graphics::GraphicsScheme; -use event::{user_data, EventQueue}; -use pcid_interface::{irq_helpers::pci_allocate_interrupt_vector, PciFunctionHandle}; -use std::{ - io::{Read, Write}, - os::fd::AsRawFd, -}; - -mod device; -use self::device::Device; - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - let pci_config = pcid_handle.config(); - - let mut name = pci_config.func.name(); - name.push_str("_ihdg"); - - common::setup_logging( - "graphics", - "pci", - &name, - common::output_level(), - common::file_level(), - ); - - log::info!("IHDG {}", pci_config.func.display()); - - let device = Device::new(&mut pcid_handle, &pci_config.func) - .expect("ihdgd: failed to initialize device"); - - let irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "ihdgd"); - - // Needs to be before GraphicsScheme::new to avoid a deadlock due to initnsmgr blocking on - // /scheme/event as it is already blocked on opening /scheme/display.ihdg.*. - // FIXME change the initnsmgr to not block on openat for the target scheme. - let event_queue: EventQueue = - EventQueue::new().expect("ihdgd: failed to create event queue"); - - let mut scheme = GraphicsScheme::new(device, format!("display.ihdg.{}", name), false); - - user_data! { - enum Source { - Input, - Irq, - Scheme, - } - } - - event_queue - .subscribe( - scheme.inputd_event_handle().as_raw_fd() as usize, - Source::Input, - event::EventFlags::READ, - ) - .unwrap(); - event_queue - .subscribe( - irq_file.irq_handle().as_raw_fd() as usize, - Source::Irq, - event::EventFlags::READ, - ) - .unwrap(); - event_queue - .subscribe( - scheme.event_handle().raw(), - Source::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - - libredox::call::setrens(0, 0).expect("ihdgd: failed to enter null namespace"); - - daemon.ready(); - - let all = [Source::Input, Source::Irq, Source::Scheme]; - for event in all - .into_iter() - .chain(event_queue.map(|e| e.expect("ihdgd: failed to get next event").user_data)) - { - match event { - Source::Input => scheme.handle_vt_events(), - Source::Irq => { - let mut irq = [0; 8]; - irq_file.irq_handle().read(&mut irq).unwrap(); - if scheme.adapter_mut().handle_irq() { - irq_file.irq_handle().write(&mut irq).unwrap(); - - scheme.adapter_mut().handle_events(); - scheme.tick().unwrap(); - } - } - Source::Scheme => { - scheme - .tick() - .expect("ihdgd: failed to handle scheme events"); - } - } - } - - std::process::exit(0); -} diff --git a/recipes/core/base/drivers/graphics/vesad/Cargo.toml b/recipes/core/base/drivers/graphics/vesad/Cargo.toml deleted file mode 100644 index a248b31488..0000000000 --- a/recipes/core/base/drivers/graphics/vesad/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "vesad" -description = "VESA driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -drm-sys.workspace = true -orbclient.workspace = true -ransid.workspace = true -redox_syscall.workspace = true -redox_event.workspace = true - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-graphics = { path = "../driver-graphics" } -libredox.workspace = true - -[features] -default = [] - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/graphics/vesad/src/main.rs b/recipes/core/base/drivers/graphics/vesad/src/main.rs deleted file mode 100644 index a4c07d1ee5..0000000000 --- a/recipes/core/base/drivers/graphics/vesad/src/main.rs +++ /dev/null @@ -1,133 +0,0 @@ -extern crate orbclient; -extern crate syscall; - -use driver_graphics::GraphicsScheme; -use event::{user_data, EventQueue}; -use std::collections::HashMap; -use std::env; -use std::os::fd::AsRawFd; - -use crate::scheme::{FbAdapter, FrameBuffer}; - -mod scheme; - -fn main() { - common::init(); - daemon::Daemon::new(daemon); -} -fn daemon(daemon: daemon::Daemon) -> ! { - if env::var("FRAMEBUFFER_WIDTH").is_err() { - println!("vesad: No boot framebuffer"); - daemon.ready(); - std::process::exit(0); - } - - let width = usize::from_str_radix( - &env::var("FRAMEBUFFER_WIDTH").expect("FRAMEBUFFER_WIDTH not set"), - 16, - ) - .expect("failed to parse FRAMEBUFFER_WIDTH"); - let height = usize::from_str_radix( - &env::var("FRAMEBUFFER_HEIGHT").expect("FRAMEBUFFER_HEIGHT not set"), - 16, - ) - .expect("failed to parse FRAMEBUFFER_HEIGHT"); - let phys = usize::from_str_radix( - &env::var("FRAMEBUFFER_ADDR").expect("FRAMEBUFFER_ADDR not set"), - 16, - ) - .expect("failed to parse FRAMEBUFFER_ADDR"); - let stride = usize::from_str_radix( - &env::var("FRAMEBUFFER_STRIDE").expect("FRAMEBUFFER_STRIDE not set"), - 16, - ) - .expect("failed to parse FRAMEBUFFER_STRIDE"); - - println!( - "vesad: {}x{} stride {} at 0x{:X}", - width, height, stride, phys - ); - - if phys == 0 { - println!("vesad: Boot framebuffer at address 0"); - daemon.ready(); - std::process::exit(0); - } - - let mut framebuffers = vec![unsafe { FrameBuffer::new(phys, width, height, stride) }]; - - //TODO: ideal maximum number of outputs? - let bootloader_env = std::fs::read_to_string("/scheme/sys/env") - .expect("failed to read env") - .lines() - .map(|line| { - let (env, value) = line.split_once('=').unwrap(); - (env.to_owned(), value.to_owned()) - }) - .collect::>(); - for i in 1..1024 { - match bootloader_env.get(&format!("FRAMEBUFFER{}", i)) { - Some(var) => match unsafe { FrameBuffer::parse(&var) } { - Some(fb) => { - println!( - "vesad: framebuffer {}: {}x{} stride {} at 0x{:X}", - i, fb.width, fb.height, fb.stride, fb.phys - ); - framebuffers.push(fb); - } - None => { - eprintln!("vesad: framebuffer {}: failed to parse '{}'", i, var); - } - }, - None => break, - }; - } - - let mut scheme = - GraphicsScheme::new(FbAdapter { framebuffers }, "display.vesa".to_owned(), true); - - user_data! { - enum Source { - Input, - Scheme, - } - } - - let event_queue: EventQueue = - EventQueue::new().expect("vesad: failed to create event queue"); - event_queue - .subscribe( - scheme.inputd_event_handle().as_raw_fd() as usize, - Source::Input, - event::EventFlags::READ, - ) - .unwrap(); - event_queue - .subscribe( - scheme.event_handle().raw(), - Source::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - - libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); - - daemon.ready(); - - let all = [Source::Input, Source::Scheme]; - for event in all - .into_iter() - .chain(event_queue.map(|e| e.expect("vesad: failed to get next event").user_data)) - { - match event { - Source::Input => scheme.handle_vt_events(), - Source::Scheme => { - scheme - .tick() - .expect("vesad: failed to handle scheme events"); - } - } - } - - panic!(); -} diff --git a/recipes/core/base/drivers/graphics/vesad/src/scheme.rs b/recipes/core/base/drivers/graphics/vesad/src/scheme.rs deleted file mode 100644 index 5bf2be9125..0000000000 --- a/recipes/core/base/drivers/graphics/vesad/src/scheme.rs +++ /dev/null @@ -1,275 +0,0 @@ -use std::alloc::{self, Layout}; -use std::convert::TryInto; -use std::ptr::{self, NonNull}; -use std::sync::Mutex; - -use driver_graphics::kms::connector::{KmsConnectorDriver, KmsConnectorStatus}; -use driver_graphics::kms::objects::{KmsCrtc, KmsCrtcState, KmsObjectId, KmsObjects}; -use driver_graphics::{Buffer, CursorPlane, Damage, GraphicsAdapter}; -use drm_sys::{ - DRM_CAP_DUMB_BUFFER, DRM_CAP_DUMB_PREFER_SHADOW, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT, -}; -use syscall::{EINVAL, PAGE_SIZE}; - -#[derive(Debug)] -pub struct FbAdapter { - pub framebuffers: Vec, -} - -#[derive(Debug)] -pub struct Connector { - width: u32, - height: u32, - framebuffer_id: usize, -} - -impl KmsConnectorDriver for Connector { - type State = (); -} - -impl GraphicsAdapter for FbAdapter { - type Connector = Connector; - type Crtc = (); - - type Buffer = GraphicScreen; - type Framebuffer = (); - - fn name(&self) -> &'static [u8] { - b"vesad" - } - - fn desc(&self) -> &'static [u8] { - b"VESA" - } - - fn init(&mut self, objects: &mut KmsObjects) { - for (framebuffer_id, framebuffer) in self.framebuffers.iter().enumerate() { - let crtc = objects.add_crtc((), ()); - - objects.add_connector( - Connector { - width: framebuffer.width as u32, - height: framebuffer.height as u32, - framebuffer_id, - }, - (), - &[crtc], - ); - } - } - - fn get_cap(&self, cap: u32) -> syscall::Result { - match cap { - DRM_CAP_DUMB_BUFFER => Ok(1), - DRM_CAP_DUMB_PREFER_SHADOW => Ok(0), - _ => Err(syscall::Error::new(EINVAL)), - } - } - - fn set_client_cap(&self, cap: u32, _value: u64) -> syscall::Result<()> { - match cap { - DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT => Ok(()), - _ => Err(syscall::Error::new(EINVAL)), - } - } - - fn probe_connector(&mut self, objects: &mut KmsObjects, id: KmsObjectId) { - let mut connector = objects.get_connector(id).unwrap().lock().unwrap(); - let connector = &mut *connector; - connector.connection = KmsConnectorStatus::Connected; - connector.update_from_size(connector.driver_data.width, connector.driver_data.height); - } - - fn create_dumb_buffer(&mut self, width: u32, height: u32) -> (Self::Buffer, u32) { - ( - GraphicScreen::new(width as usize, height as usize), - width * 4, - ) - } - - fn map_dumb_buffer(&mut self, framebuffer: &Self::Buffer) -> *mut u8 { - framebuffer.ptr.as_ptr().cast::() - } - - fn create_framebuffer(&mut self, _buffer: &Self::Buffer) -> Self::Framebuffer { - () - } - - fn set_crtc( - &mut self, - objects: &KmsObjects, - crtc: &Mutex>, - state: KmsCrtcState, - damage: Damage, - ) -> syscall::Result<()> { - let mut crtc = crtc.lock().unwrap(); - let buffer = state - .fb_id - .map(|fb_id| objects.get_framebuffer(fb_id)) - .transpose()?; - crtc.state = state; - - for connector in objects.connectors() { - let connector = connector.lock().unwrap(); - - if connector.state.crtc_id != objects.crtc_ids()[crtc.crtc_index as usize] { - continue; - } - - let framebuffer_id = connector.driver_data.framebuffer_id; - let framebuffer = &mut self.framebuffers[framebuffer_id]; - - if let Some(buffer) = buffer { - buffer.buffer.sync(framebuffer, damage) - } else { - let onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable - for row in 0..framebuffer.height { - unsafe { - ptr::write_bytes( - onscreen_ptr.add(row * framebuffer.stride), - 0, - framebuffer.width, - ); - } - } - } - } - - Ok(()) - } - - fn hw_cursor_size(&self) -> Option<(u32, u32)> { - None - } - - fn handle_cursor(&mut self, _cursor: &CursorPlane, _dirty_fb: bool) { - unimplemented!("Vesad does not support this function"); - } -} - -#[derive(Debug)] -pub struct FrameBuffer { - pub onscreen: *mut [u32], - pub phys: usize, - pub width: usize, - pub height: usize, - pub stride: usize, -} - -impl FrameBuffer { - pub unsafe fn new(phys: usize, width: usize, height: usize, stride: usize) -> Self { - let size = stride * height; - let virt = common::physmap( - phys, - size * 4, - common::Prot { - read: true, - write: true, - }, - common::MemoryType::WriteCombining, - ) - .expect("vesad: failed to map framebuffer") as *mut u32; - - let onscreen = ptr::slice_from_raw_parts_mut(virt, size); - - Self { - onscreen, - phys, - width, - height, - stride, - } - } - - pub unsafe fn parse(var: &str) -> Option { - fn parse_number(part: &str) -> Option { - let (start, radix) = if part.starts_with("0x") { - (2, 16) - } else { - (0, 10) - }; - match usize::from_str_radix(&part[start..], radix) { - Ok(ok) => Some(ok), - Err(err) => { - eprintln!("vesad: failed to parse '{}': {}", part, err); - None - } - } - } - - let mut parts = var.split(','); - let phys = parse_number(parts.next()?)?; - let width = parse_number(parts.next()?)?; - let height = parse_number(parts.next()?)?; - let stride = parse_number(parts.next()?)?; - Some(Self::new(phys, width, height, stride)) - } -} - -#[derive(Debug)] -pub struct GraphicScreen { - width: usize, - height: usize, - ptr: NonNull<[u32]>, -} - -impl GraphicScreen { - fn new(width: usize, height: usize) -> GraphicScreen { - let len = width * height; - let layout = Self::layout(len); - let ptr = unsafe { alloc::alloc_zeroed(layout) }; - let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len); - let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout)); - - GraphicScreen { width, height, ptr } - } - - #[inline] - fn layout(len: usize) -> Layout { - // optimizes to an integer mul - Layout::array::(len) - .unwrap() - .align_to(PAGE_SIZE) - .unwrap() - } -} - -impl Drop for GraphicScreen { - fn drop(&mut self) { - let layout = Self::layout(self.ptr.len()); - unsafe { alloc::dealloc(self.ptr.as_ptr().cast(), layout) }; - } -} - -impl Buffer for GraphicScreen { - fn size(&self) -> usize { - self.width * self.height * 4 - } -} - -impl GraphicScreen { - fn sync(&self, framebuffer: &mut FrameBuffer, sync_rect: Damage) { - let sync_rect = sync_rect.clip( - self.width.try_into().unwrap(), - self.height.try_into().unwrap(), - ); - - let start_x: usize = sync_rect.x.try_into().unwrap(); - let start_y: usize = sync_rect.y.try_into().unwrap(); - let w: usize = sync_rect.width.try_into().unwrap(); - let h: usize = sync_rect.height.try_into().unwrap(); - - let offscreen_ptr = self.ptr.as_ptr() as *mut u32; - let onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable - - for row in start_y..start_y + h { - unsafe { - ptr::copy( - offscreen_ptr.add(row * self.width + start_x), - onscreen_ptr.add(row * framebuffer.stride + start_x), - w, - ); - } - } - } -} diff --git a/recipes/core/base/drivers/graphics/virtio-gpud/Cargo.toml b/recipes/core/base/drivers/graphics/virtio-gpud/Cargo.toml deleted file mode 100644 index c36b783f1b..0000000000 --- a/recipes/core/base/drivers/graphics/virtio-gpud/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "virtio-gpud" -description = "VirtIO-GPU driver" -version = "0.1.0" -edition = "2021" -authors = ["Anhad Singh "] - -[dependencies] -drm-sys.workspace = true -log.workspace = true -static_assertions.workspace = true -futures = { version = "0.3.28", features = ["executor"] } -anyhow.workspace = true - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-graphics = { path = "../driver-graphics" } -virtio-core = { path = "../../virtio-core" } -pcid = { path = "../../pcid" } - -redox_event.workspace = true -redox_syscall.workspace = true -orbclient.workspace = true -spin.workspace = true -libredox.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/graphics/virtio-gpud/src/main.rs b/recipes/core/base/drivers/graphics/virtio-gpud/src/main.rs deleted file mode 100644 index 57e25ba70c..0000000000 --- a/recipes/core/base/drivers/graphics/virtio-gpud/src/main.rs +++ /dev/null @@ -1,615 +0,0 @@ -//! `virtio-gpu` is a virtio based graphics adapter. It can operate in 2D mode and in 3D mode. -//! -//! XXX: 3D mode will offload rendering ops to the host gpu and therefore requires a GPU with 3D support -//! on the host machine. - -// Notes for the future: -// -// `virtio-gpu` 2D acceleration is just blitting. 3D acceleration has 2 kinds: -// - virgl - OpenGL -// - venus - Vulkan -// -// The Venus driver requires support for the following from the `virtio-gpu` kernel driver: -// - VIRTGPU_PARAM_3D_FEATURES -// - VIRTGPU_PARAM_CAPSET_QUERY_FIX -// - VIRTGPU_PARAM_RESOURCE_BLOB -// - VIRTGPU_PARAM_HOST_VISIBLE -// - VIRTGPU_PARAM_CROSS_DEVICE -// - VIRTGPU_PARAM_CONTEXT_INIT -// -// cc https://docs.mesa3d.org/drivers/venus.html -// cc https://docs.mesa3d.org/drivers/virgl.html - -use std::os::fd::AsRawFd; -use std::sync::atomic::{AtomicU32, Ordering}; - -use driver_graphics::GraphicsAdapter; -use event::{user_data, EventQueue}; -use pcid_interface::PciFunctionHandle; - -use virtio_core::utils::VolatileCell; -use virtio_core::MSIX_PRIMARY_VECTOR; - -mod scheme; - -//const VIRTIO_GPU_F_VIRGL: u32 = 0; -const VIRTIO_GPU_F_EDID: u32 = 1; -//const VIRTIO_GPU_F_RESOURCE_UUID: u32 = 2; -//const VIRTIO_GPU_F_RESOURCE_BLOB: u32 = 3; -//const VIRTIO_GPU_F_CONTEXT_INIT: u32 = 4; - -const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0; -const VIRTIO_GPU_MAX_SCANOUTS: usize = 16; - -#[repr(C)] -pub struct GpuConfig { - /// Signals pending events to the driver. - pub events_read: VolatileCell, // read-only - /// Clears pending events in the device (write-to-clear). - pub events_clear: VolatileCell, // write-only - - pub num_scanouts: VolatileCell, - pub num_capsets: VolatileCell, -} - -impl GpuConfig { - #[inline] - pub fn num_scanouts(&self) -> u32 { - self.num_scanouts.get() - } -} - -#[derive(Debug, Copy, Clone, PartialEq)] -#[repr(u32)] -pub enum CommandTy { - Undefined = 0, - - // 2D commands - GetDisplayInfo = 0x0100, - ResourceCreate2d, - ResourceUnref, - SetScanout, - ResourceFlush, - TransferToHost2d, - ResourceAttachBacking, - ResourceDetachBacking, - GetCapsetInfo, - GetCapset, - GetEdid, - ResourceAssignUuid, - ResourceCreateBlob, - SetScanoutBlob, - - // 3D commands - CtxCreate = 0x0200, - CtxDestroy, - CtxAttachResource, - CtxDetachResource, - ResourceCreate3d, - TransferToHost3d, - TransferFromHost3d, - Submit3d, - ResourceMapBlob, - ResourceUnmapBlob, - - // cursor commands - UpdateCursor = 0x0300, - MoveCursor, - - // success responses - RespOkNodata = 0x1100, - RespOkDisplayInfo, - RespOkCapsetInfo, - RespOkCapset, - RespOkEdid, - RespOkResourceUuid, - RespOkMapInfo, - - // error responses - RespErrUnspec = 0x1200, - RespErrOutOfMemory, - RespErrInvalidScanoutId, - RespErrInvalidResourceId, - RespErrInvalidContextId, - RespErrInvalidParameter, -} - -static_assertions::const_assert_eq!(core::mem::size_of::(), 4); - -const VIRTIO_GPU_FLAG_FENCE: u32 = 1 << 0; -//const VIRTIO_GPU_FLAG_INFO_RING_IDX: u32 = 1 << 1; - -#[derive(Debug)] -#[repr(C)] -pub struct ControlHeader { - pub ty: CommandTy, - pub flags: u32, - pub fence_id: u64, - pub ctx_id: u32, - pub ring_index: u8, - padding: [u8; 3], -} - -impl ControlHeader { - pub fn with_ty(ty: CommandTy) -> Self { - Self { - ty, - ..Default::default() - } - } -} - -impl Default for ControlHeader { - fn default() -> Self { - Self { - ty: CommandTy::Undefined, - flags: 0, - fence_id: 0, - ctx_id: 0, - ring_index: 0, - padding: [0; 3], - } - } -} - -#[derive(Debug, Copy, Clone)] -#[repr(C)] -pub struct GpuRect { - pub x: u32, - pub y: u32, - pub width: u32, - pub height: u32, -} - -impl GpuRect { - pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self { - Self { - x, - y, - width, - height, - } - } -} - -#[derive(Debug)] -#[repr(C)] -pub struct DisplayInfo { - rect: GpuRect, - pub enabled: u32, - pub flags: u32, -} - -#[derive(Debug)] -#[repr(C)] -pub struct GetDisplayInfo { - pub header: ControlHeader, - pub display_info: [DisplayInfo; VIRTIO_GPU_MAX_SCANOUTS], -} - -impl Default for GetDisplayInfo { - fn default() -> Self { - Self { - header: ControlHeader { - ty: CommandTy::GetDisplayInfo, - ..Default::default() - }, - - display_info: unsafe { core::mem::zeroed() }, - } - } -} - -static RESOURCE_ALLOC: AtomicU32 = AtomicU32::new(1); // XXX: 0 is reserved for whatever that takes `resource_id`. - -#[derive(PartialEq, Eq, Debug, Copy, Clone)] -#[repr(C)] -pub struct ResourceId(u32); - -impl ResourceId { - const NONE: ResourceId = ResourceId(0); - - fn alloc() -> Self { - ResourceId(RESOURCE_ALLOC.fetch_add(1, Ordering::SeqCst)) - } -} - -#[derive(Debug, Copy, Clone)] -#[repr(u32)] -pub enum ResourceFormat { - Unknown = 0, - - Bgrx = 2, - Xrgb = 4, -} - -#[derive(Debug)] -#[repr(C)] -pub struct ResourceCreate2d { - pub header: ControlHeader, - resource_id: ResourceId, - format: ResourceFormat, - width: u32, - height: u32, -} - -impl ResourceCreate2d { - fn new(resource_id: ResourceId, format: ResourceFormat, width: u32, height: u32) -> Self { - Self { - header: ControlHeader::with_ty(CommandTy::ResourceCreate2d), - resource_id, - format, - width, - height, - } - } -} - -#[derive(Debug)] -#[repr(C)] -pub struct MemEntry { - pub address: u64, - pub length: u32, - pub padding: u32, -} - -#[derive(Debug)] -#[repr(C)] -pub struct AttachBacking { - pub header: ControlHeader, - pub resource_id: ResourceId, - pub num_entries: u32, -} - -impl AttachBacking { - pub fn new(resource_id: ResourceId, num_entries: u32) -> Self { - Self { - header: ControlHeader::with_ty(CommandTy::ResourceAttachBacking), - resource_id, - num_entries, - } - } -} - -#[derive(Debug)] -#[repr(C)] -pub struct DetachBacking { - pub header: ControlHeader, - pub resource_id: ResourceId, - pub padding: u32, -} - -impl DetachBacking { - pub fn new(resource_id: ResourceId) -> Self { - Self { - header: ControlHeader::with_ty(CommandTy::ResourceDetachBacking), - resource_id, - padding: 0, - } - } -} - -#[derive(Debug)] -#[repr(C)] -pub struct ResourceFlush { - pub header: ControlHeader, - pub rect: GpuRect, - pub resource_id: ResourceId, - pub padding: u32, -} - -impl ResourceFlush { - pub fn new(resource_id: ResourceId, rect: GpuRect) -> Self { - Self { - header: ControlHeader::with_ty(CommandTy::ResourceFlush), - rect, - resource_id, - padding: 0, - } - } -} - -#[derive(Debug)] -#[repr(C)] -pub struct ResourceUnref { - pub header: ControlHeader, - pub resource_id: ResourceId, - pub padding: u32, -} - -impl ResourceUnref { - pub fn new(resource_id: ResourceId) -> Self { - Self { - header: ControlHeader::with_ty(CommandTy::ResourceUnref), - resource_id, - padding: 0, - } - } -} - -#[repr(C)] -#[derive(Debug)] -pub struct SetScanout { - pub header: ControlHeader, - pub rect: GpuRect, - pub scanout_id: u32, - pub resource_id: ResourceId, -} - -impl SetScanout { - pub fn new(scanout_id: u32, resource_id: ResourceId, rect: GpuRect) -> Self { - Self { - header: ControlHeader::with_ty(CommandTy::SetScanout), - - rect, - scanout_id, - resource_id, - } - } -} - -#[derive(Debug)] -#[repr(C)] -pub struct XferToHost2d { - pub header: ControlHeader, - pub rect: GpuRect, - pub offset: u64, - pub resource_id: ResourceId, - pub padding: u32, -} - -impl XferToHost2d { - pub fn new(resource_id: ResourceId, rect: GpuRect, offset: u64) -> Self { - Self { - header: ControlHeader::with_ty(CommandTy::TransferToHost2d), - rect, - offset, - resource_id, - padding: 0, - } - } -} - -#[derive(Debug)] -#[repr(C)] -pub struct GetEdid { - pub header: ControlHeader, - pub scanout: u32, - pub padding: u32, -} - -impl GetEdid { - pub fn new(scanout_id: u32) -> Self { - Self { - header: ControlHeader::with_ty(CommandTy::GetEdid), - scanout: scanout_id, - padding: 0, - } - } -} - -#[derive(Debug)] -#[repr(C)] -pub struct GetEdidResp { - pub header: ControlHeader, - pub size: u32, - pub padding: u32, - pub edid: [u8; 1024], -} - -impl GetEdidResp { - pub fn new() -> Self { - Self { - header: ControlHeader::with_ty(CommandTy::GetEdid), - size: 0, - padding: 0, - edid: [0; 1024], - } - } -} - -#[derive(Debug)] -#[repr(C)] -pub struct CursorPos { - pub scanout_id: u32, - pub x: i32, - pub y: i32, - _padding: u32, -} - -impl CursorPos { - pub fn new(scanout_id: u32, x: i32, y: i32) -> Self { - Self { - scanout_id, - x, - y, - _padding: 0, - } - } -} - -/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */ -#[derive(Debug)] -#[repr(C)] -pub struct UpdateCursor { - pub header: ControlHeader, - pub pos: CursorPos, - pub resource_id: ResourceId, - pub hot_x: i32, - pub hot_y: i32, - _padding: u32, -} - -impl UpdateCursor { - pub fn update_cursor(x: i32, y: i32, hot_x: i32, hot_y: i32, resource_id: ResourceId) -> Self { - Self { - header: ControlHeader::with_ty(CommandTy::UpdateCursor), - pos: CursorPos::new(0, x, y), - resource_id, - hot_x, - hot_y, - _padding: 0, - } - } -} - -pub struct MoveCursor { - pub header: ControlHeader, - pub pos: CursorPos, - pub resource_id: ResourceId, - pub hot_x: i32, - pub hot_y: i32, - _padding: u32, -} - -impl MoveCursor { - pub fn move_cursor(x: i32, y: i32) -> Self { - Self { - header: ControlHeader::with_ty(CommandTy::MoveCursor), - pos: CursorPos::new(0, x, y), - resource_id: ResourceId(0), - hot_x: 0, - hot_y: 0, - _padding: 0, - } - } -} - -static DEVICE: spin::Once = spin::Once::new(); - -fn main() { - pcid_interface::pci_daemon(daemon_runner); -} - -fn daemon_runner(redox_daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! { - daemon(redox_daemon, pcid_handle).unwrap(); - unreachable!(); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow::Result<()> { - common::setup_logging( - "graphics", - "pci", - "virtio-gpud", - common::output_level(), - common::file_level(), - ); - - // Double check that we have the right device. - // - // 0x1050 - virtio-gpu - let pci_config = pcid_handle.config(); - - assert_eq!(pci_config.func.full_device_id.device_id, 0x1050); - log::info!("virtio-gpu: initiating startup sequence :^)"); - - let device = DEVICE.try_call_once(|| virtio_core::probe_device(&mut pcid_handle))?; - let config = unsafe { &mut *(device.device_space as *mut GpuConfig) }; - - // Negotiate features. - let has_edid = device.transport.check_device_feature(VIRTIO_GPU_F_EDID); - if has_edid { - device.transport.ack_driver_feature(VIRTIO_GPU_F_EDID); - } - device.transport.finalize_features(); - - // Queue for sending control commands. - let control_queue = device - .transport - .setup_queue(MSIX_PRIMARY_VECTOR, &device.irq_handle)?; - - // Queue for sending cursor updates. - let cursor_queue = device - .transport - .setup_queue(MSIX_PRIMARY_VECTOR, &device.irq_handle)?; - - device.transport.setup_config_notify(MSIX_PRIMARY_VECTOR); - - device.transport.run_device(); - - // Needs to be before GpuScheme::new to avoid a deadlock due to initnsmgr blocking on - // /scheme/event as it is already blocked on opening /scheme/display.virtio-gpu. - // FIXME change the initnsmgr to not block on openat for the target scheme. - let event_queue: EventQueue = - EventQueue::new().expect("virtio-gpud: failed to create event queue"); - - let mut scheme = scheme::GpuScheme::new( - config, - control_queue.clone(), - cursor_queue.clone(), - device.transport.clone(), - has_edid, - )?; - daemon.ready(); - - user_data! { - enum Source { - Input, - Scheme, - Interrupt, - } - } - - event_queue - .subscribe( - scheme.inputd_event_handle().as_raw_fd() as usize, - Source::Input, - event::EventFlags::READ, - ) - .unwrap(); - event_queue - .subscribe( - scheme.event_handle().raw(), - Source::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - event_queue - .subscribe( - device.irq_handle.as_raw_fd() as usize, - Source::Interrupt, - event::EventFlags::READ, - ) - .unwrap(); - - let all = [Source::Input, Source::Scheme, Source::Interrupt]; - for event in all - .into_iter() - .chain(event_queue.map(|e| e.expect("virtio-gpud: failed to get next event").user_data)) - { - match event { - Source::Input => scheme.handle_vt_events(), - Source::Scheme => { - scheme - .tick() - .expect("virtio-gpud: failed to process scheme events"); - } - Source::Interrupt => loop { - let before_gen = device.transport.config_generation(); - - let events = scheme.adapter().config.events_read.get(); - - if events & VIRTIO_GPU_EVENT_DISPLAY != 0 { - let (adapter, objects) = scheme.adapter_and_kms_objects_mut(); - futures::executor::block_on(async { adapter.update_displays().await.unwrap() }); - for connector_id in objects.connector_ids().to_vec() { - adapter.probe_connector(objects, connector_id); - } - scheme.notify_displays_changed(); - scheme - .adapter_mut() - .config - .events_clear - .set(VIRTIO_GPU_EVENT_DISPLAY); - } - - let after_gen = device.transport.config_generation(); - if before_gen == after_gen { - break; - } - }, - } - } - - std::process::exit(0); -} diff --git a/recipes/core/base/drivers/graphics/virtio-gpud/src/scheme.rs b/recipes/core/base/drivers/graphics/virtio-gpud/src/scheme.rs deleted file mode 100644 index 22a985ee4e..0000000000 --- a/recipes/core/base/drivers/graphics/virtio-gpud/src/scheme.rs +++ /dev/null @@ -1,528 +0,0 @@ -use std::fmt; -use std::sync::{Arc, Mutex}; - -use common::{dma::Dma, sgl}; -use driver_graphics::kms::connector::{KmsConnectorDriver, KmsConnectorStatus}; -use driver_graphics::kms::objects::{KmsCrtc, KmsCrtcState, KmsObjectId, KmsObjects}; -use driver_graphics::{Buffer as DrmBuffer, CursorPlane, Damage, GraphicsAdapter, GraphicsScheme}; -use drm_sys::{ - DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH, DRM_CAP_DUMB_BUFFER, DRM_CAP_DUMB_PREFER_SHADOW, - DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT, -}; - -use syscall::{EINVAL, PAGE_SIZE}; - -use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; -use virtio_core::transport::{Error, Queue, Transport}; - -use crate::*; - -impl Into for Damage { - fn into(self) -> GpuRect { - GpuRect { - x: self.x, - y: self.y, - width: self.width, - height: self.height, - } - } -} - -#[derive(Debug)] -pub struct VirtGpuConnector { - display_id: u32, -} - -impl KmsConnectorDriver for VirtGpuConnector { - type State = (); -} - -pub struct VirtGpuFramebuffer<'a> { - queue: Arc>, - id: ResourceId, - sgl: sgl::Sgl, - width: u32, - height: u32, -} - -impl<'a> fmt::Debug for VirtGpuFramebuffer<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("VirtGpuFramebuffer") - .field("id", &self.id) - .field("sgl", &self.sgl) - .field("width", &self.width) - .field("height", &self.height) - .finish_non_exhaustive() - } -} - -impl DrmBuffer for VirtGpuFramebuffer<'_> { - fn size(&self) -> usize { - (self.width * self.height * 4) as usize - } -} - -impl Drop for VirtGpuFramebuffer<'_> { - fn drop(&mut self) { - futures::executor::block_on(async { - let request = Dma::new(ResourceUnref::new(self.id)).unwrap(); - - let header = Dma::new(ControlHeader::default()).unwrap(); - let command = ChainBuilder::new() - .chain(Buffer::new(&request)) - .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - self.queue.send(command).await; - }); - } -} - -#[derive(Debug, Clone)] -pub struct Display { - enabled: bool, - width: u32, - height: u32, - edid: Vec, - active_resource: Option, -} - -pub struct VirtGpuAdapter<'a> { - pub config: &'a mut GpuConfig, - control_queue: Arc>, - cursor_queue: Arc>, - transport: Arc, - has_edid: bool, - displays: Vec, - hidden_cursor: Option>>, -} - -impl<'a> fmt::Debug for VirtGpuAdapter<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("VirtGpuAdapter") - .field("displays", &self.displays) - .finish_non_exhaustive() - } -} - -impl VirtGpuAdapter<'_> { - pub async fn update_displays(&mut self) -> Result<(), Error> { - let display_info = self.get_display_info().await?; - let raw_displays = &display_info.display_info[..self.config.num_scanouts() as usize]; - - self.displays.resize( - raw_displays.len(), - Display { - enabled: false, - width: 0, - height: 0, - edid: vec![], - active_resource: None, - }, - ); - for (i, info) in raw_displays.iter().enumerate() { - log::info!( - "virtio-gpu: display {i} ({}x{}px)", - info.rect.width, - info.rect.height - ); - - self.displays[i].enabled = info.enabled != 0; - - if info.rect.width == 0 || info.rect.height == 0 { - // QEMU gives all displays other than the first a zero width and height, but trying - // to attach a zero sized framebuffer to the display will result an error, so - // default to 640x480px. - self.displays[i].width = 640; - self.displays[i].height = 480; - } else { - self.displays[i].width = info.rect.width; - self.displays[i].height = info.rect.height; - } - - if self.has_edid { - let edid = self.get_edid(i as u32).await?; - self.displays[i].edid = edid.edid[..edid.size as usize].to_vec(); - } - } - - Ok(()) - } - - async fn send_request(&self, request: Dma) -> Result, Error> { - let header = Dma::new(ControlHeader::default())?; - let command = ChainBuilder::new() - .chain(Buffer::new(&request)) - .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - self.control_queue.send(command).await; - Ok(header) - } - - async fn send_request_fenced(&self, request: Dma) -> Result, Error> { - let mut header = Dma::new(ControlHeader::default())?; - header.flags |= VIRTIO_GPU_FLAG_FENCE; - let command = ChainBuilder::new() - .chain(Buffer::new(&request)) - .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - self.control_queue.send(command).await; - Ok(header) - } - - async fn get_display_info(&self) -> Result, Error> { - let header = Dma::new(ControlHeader::with_ty(CommandTy::GetDisplayInfo))?; - - let response = Dma::new(GetDisplayInfo::default())?; - let command = ChainBuilder::new() - .chain(Buffer::new(&header)) - .chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - self.control_queue.send(command).await; - assert!(response.header.ty == CommandTy::RespOkDisplayInfo); - - Ok(response) - } - - async fn get_edid(&self, scanout_id: u32) -> Result, Error> { - let header = Dma::new(GetEdid::new(scanout_id))?; - - let response = Dma::new(GetEdidResp::new())?; - let command = ChainBuilder::new() - .chain(Buffer::new(&header)) - .chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - self.control_queue.send(command).await; - assert!(response.header.ty == CommandTy::RespOkEdid); - - Ok(response) - } - - fn update_cursor( - &mut self, - cursor: &VirtGpuFramebuffer, - x: i32, - y: i32, - hot_x: i32, - hot_y: i32, - ) { - //Transfering cursor resource to host - futures::executor::block_on(async { - let transfer_request = Dma::new(XferToHost2d::new( - cursor.id, - GpuRect { - x: 0, - y: 0, - width: 64, - height: 64, - }, - 0, - )) - .unwrap(); - let header = self.send_request_fenced(transfer_request).await.unwrap(); - assert_eq!(header.ty, CommandTy::RespOkNodata); - }); - - //Update the cursor position - let request = Dma::new(UpdateCursor::update_cursor(x, y, hot_x, hot_y, cursor.id)).unwrap(); - futures::executor::block_on(async { - let command = ChainBuilder::new().chain(Buffer::new(&request)).build(); - self.cursor_queue.send(command).await; - }); - } - - fn move_cursor(&mut self, x: i32, y: i32) { - let request = Dma::new(MoveCursor::move_cursor(x, y)).unwrap(); - - futures::executor::block_on(async { - let command = ChainBuilder::new().chain(Buffer::new(&request)).build(); - self.cursor_queue.send(command).await; - }); - } - - fn disable_cursor(&mut self) { - if self.hidden_cursor.is_none() { - let (width, height) = self.hw_cursor_size().unwrap(); - let (cursor, stride) = self.create_dumb_buffer(width, height); - unsafe { - core::ptr::write_bytes( - cursor.sgl.as_ptr() as *mut u8, - 0, - (stride * height) as usize, - ); - } - self.hidden_cursor = Some(Arc::new(cursor)); - } - let hidden_cursor = self.hidden_cursor.as_ref().unwrap().clone(); - - self.update_cursor(&hidden_cursor, 0, 0, 0, 0); - } -} - -impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> { - type Connector = VirtGpuConnector; - type Crtc = (); - - type Buffer = VirtGpuFramebuffer<'a>; - type Framebuffer = (); - - fn name(&self) -> &'static [u8] { - b"virtio-gpud" - } - - fn desc(&self) -> &'static [u8] { - b"VirtIO GPU" - } - - fn init(&mut self, objects: &mut KmsObjects) { - futures::executor::block_on(async { - self.update_displays().await.unwrap(); - }); - - for display_id in 0..self.config.num_scanouts.get() { - let crtc = objects.add_crtc((), ()); - - objects.add_connector(VirtGpuConnector { display_id }, (), &[crtc]); - } - } - - fn get_cap(&self, cap: u32) -> syscall::Result { - match cap { - DRM_CAP_DUMB_BUFFER => Ok(1), - DRM_CAP_DUMB_PREFER_SHADOW => Ok(0), - DRM_CAP_CURSOR_WIDTH => Ok(64), - DRM_CAP_CURSOR_HEIGHT => Ok(64), - _ => Err(syscall::Error::new(EINVAL)), - } - } - - fn set_client_cap(&self, cap: u32, _value: u64) -> syscall::Result<()> { - match cap { - // FIXME hide cursor plane unless this client cap is set - DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT => Ok(()), - _ => Err(syscall::Error::new(EINVAL)), - } - } - - fn probe_connector(&mut self, objects: &mut KmsObjects, id: KmsObjectId) { - futures::executor::block_on(async { - let mut connector = objects.get_connector(id).unwrap().lock().unwrap(); - let display = &self.displays[connector.driver_data.display_id as usize]; - - connector.connection = if display.enabled { - KmsConnectorStatus::Connected - } else { - KmsConnectorStatus::Disconnected - }; - - if self.has_edid { - connector.update_from_edid(&display.edid); - - drop(connector); - - let blob = objects.add_blob(display.edid.clone()); - objects.get_connector(id).unwrap().lock().unwrap().edid = blob; - } else { - connector.update_from_size(display.width, display.height); - } - }); - } - - fn create_dumb_buffer(&mut self, width: u32, height: u32) -> (Self::Buffer, u32) { - futures::executor::block_on(async { - let bpp = 32; - let fb_size = width as usize * height as usize * bpp / 8; - let sgl = sgl::Sgl::new(fb_size).unwrap(); - - unsafe { - core::ptr::write_bytes(sgl.as_ptr() as *mut u8, 255, fb_size); - } - - let res_id = ResourceId::alloc(); - - // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. - let request = Dma::new(ResourceCreate2d::new( - res_id, - ResourceFormat::Bgrx, - width, - height, - )) - .unwrap(); - - let header = self.send_request(request).await.unwrap(); - assert_eq!(header.ty, CommandTy::RespOkNodata); - - // Use the allocated framebuffer from the guest ram, and attach it as backing - // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. - - let mut mem_entries = - unsafe { Dma::zeroed_slice(sgl.chunks().len()).unwrap().assume_init() }; - for (entry, chunk) in mem_entries.iter_mut().zip(sgl.chunks().iter()) { - *entry = MemEntry { - address: chunk.phys as u64, - length: chunk.length.next_multiple_of(PAGE_SIZE) as u32, - padding: 0, - }; - } - - let attach_request = - Dma::new(AttachBacking::new(res_id, mem_entries.len() as u32)).unwrap(); - let header = Dma::new(ControlHeader::default()).unwrap(); - let command = ChainBuilder::new() - .chain(Buffer::new(&attach_request)) - .chain(Buffer::new_unsized(&mem_entries)) - .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - self.control_queue.send(command).await; - assert_eq!(header.ty, CommandTy::RespOkNodata); - - ( - VirtGpuFramebuffer { - queue: self.control_queue.clone(), - id: res_id, - sgl, - width, - height, - }, - width * 4, - ) - }) - } - - fn map_dumb_buffer(&mut self, buffer: &Self::Buffer) -> *mut u8 { - buffer.sgl.as_ptr() - } - - fn create_framebuffer(&mut self, _buffer: &Self::Buffer) -> Self::Framebuffer { - () - } - - fn set_crtc( - &mut self, - objects: &KmsObjects, - crtc: &Mutex>, - state: KmsCrtcState, - damage: Damage, - ) -> syscall::Result<()> { - futures::executor::block_on(async { - let mut crtc = crtc.lock().unwrap(); - let framebuffer = state - .fb_id - .map(|fb_id| objects.get_framebuffer(fb_id)) - .transpose()?; - crtc.state = state; - - for connector in objects.connectors() { - let connector = connector.lock().unwrap(); - - if connector.state.crtc_id != objects.crtc_ids()[crtc.crtc_index as usize] { - continue; - } - - let display_id = connector.driver_data.display_id; - - let Some(framebuffer) = framebuffer else { - let scanout_request = Dma::new(SetScanout::new( - display_id, - ResourceId::NONE, - GpuRect::new(0, 0, 0, 0), - )) - .unwrap(); - let header = self.send_request(scanout_request).await.unwrap(); - assert_eq!(header.ty, CommandTy::RespOkNodata); - self.displays[display_id as usize].active_resource = None; - return Ok(()); - }; - - let req = Dma::new(XferToHost2d::new( - framebuffer.buffer.id, - GpuRect { - x: 0, - y: 0, - width: framebuffer.width, - height: framebuffer.height, - }, - 0, - )) - .unwrap(); - let header = self.send_request(req).await.unwrap(); - assert_eq!(header.ty, CommandTy::RespOkNodata); - - // FIXME once we support resizing we also need to check that the current and target size match - if self.displays[display_id as usize].active_resource != Some(framebuffer.buffer.id) - { - let scanout_request = Dma::new(SetScanout::new( - display_id, - framebuffer.buffer.id, - GpuRect::new(0, 0, framebuffer.width, framebuffer.height), - )) - .unwrap(); - let header = self.send_request(scanout_request).await.unwrap(); - assert_eq!(header.ty, CommandTy::RespOkNodata); - self.displays[display_id as usize].active_resource = - Some(framebuffer.buffer.id); - } - - let flush = ResourceFlush::new( - framebuffer.buffer.id, - damage.clip(framebuffer.width, framebuffer.height).into(), - ); - let header = self.send_request(Dma::new(flush).unwrap()).await.unwrap(); - assert_eq!(header.ty, CommandTy::RespOkNodata); - } - - Ok(()) - }) - } - - fn hw_cursor_size(&self) -> Option<(u32, u32)> { - Some((64, 64)) - } - - fn handle_cursor(&mut self, cursor: &CursorPlane, dirty_fb: bool) { - if let Some(buffer) = &cursor.buffer { - if dirty_fb { - self.update_cursor(buffer, cursor.x, cursor.y, cursor.hot_x, cursor.hot_y); - } else { - self.move_cursor(cursor.x, cursor.y); - } - } else { - if dirty_fb { - self.disable_cursor(); - } - } - } -} - -pub struct GpuScheme {} - -impl<'a> GpuScheme { - pub fn new( - config: &'a mut GpuConfig, - control_queue: Arc>, - cursor_queue: Arc>, - transport: Arc, - has_edid: bool, - ) -> Result>, Error> { - let adapter = VirtGpuAdapter { - config, - control_queue, - cursor_queue, - transport, - has_edid, - displays: vec![], - hidden_cursor: None, - }; - - Ok(GraphicsScheme::new( - adapter, - "display.virtio-gpu".to_owned(), - false, - )) - } -} diff --git a/recipes/core/base/drivers/hwd/.gitignore b/recipes/core/base/drivers/hwd/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/recipes/core/base/drivers/hwd/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/recipes/core/base/drivers/hwd/Cargo.toml b/recipes/core/base/drivers/hwd/Cargo.toml deleted file mode 100644 index 3d37cfb3f3..0000000000 --- a/recipes/core/base/drivers/hwd/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "hwd" -description = "ACPI and DeviceTree handling daemon" -version = "0.1.0" -edition = "2018" - -[dependencies] -fdt.workspace = true -log.workspace = true -ron.workspace = true -libredox = { workspace = true, default-features = false, features = ["std", "call"] } - -amlserde = { path = "../amlserde" } -common = { path = "../common" } -daemon = { path = "../../daemon" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/hwd/src/backend/acpi.rs b/recipes/core/base/drivers/hwd/src/backend/acpi.rs deleted file mode 100644 index 3da41d6382..0000000000 --- a/recipes/core/base/drivers/hwd/src/backend/acpi.rs +++ /dev/null @@ -1,111 +0,0 @@ -use amlserde::{AmlSerde, AmlSerdeValue}; -use std::{error::Error, fs, process::Command}; - -use super::Backend; - -pub struct AcpiBackend { - rxsdt: Vec, -} - -impl Backend for AcpiBackend { - fn new() -> Result> { - let rxsdt = fs::read("/scheme/kernel.acpi/rxsdt")?; - - // Spawn acpid - //TODO: pass rxsdt data to acpid? - #[allow(deprecated, reason = "we can't yet move this to init")] - daemon::Daemon::spawn(Command::new("acpid")); - - Ok(Self { rxsdt }) - } - - fn probe(&mut self) -> Result<(), Box> { - // Read symbols from acpi scheme - let entries = fs::read_dir("/scheme/acpi/symbols")?; - // TODO: Reimplement with getdents? - let symbols_fd = libredox::Fd::open( - "/scheme/acpi/symbols", - libredox::flag::O_DIRECTORY | libredox::flag::O_RDONLY, - 0, - )?; - for entry_res in entries { - let entry = entry_res?; - if let Some(file_name) = entry.file_name().to_str() { - if file_name.ends_with("_CID") || file_name.ends_with("_HID") { - let symbol_fd = symbols_fd.openat(file_name, libredox::flag::O_RDONLY, 0)?; - let stat = symbol_fd.stat()?; - let mut buf: Vec = vec![0u8; stat.st_size as usize]; - let count = symbol_fd.read(&mut buf)?; - buf.truncate(count); - let ron = String::from_utf8(buf)?; - let AmlSerde { name, value } = ron::from_str(&ron)?; - let id = match value { - AmlSerdeValue::Integer(integer) => { - let vendor = integer & 0xFFFF; - let device = (integer >> 16) & 0xFFFF; - let vendor_rev = ((vendor & 0xFF) << 8) | vendor >> 8; - let vendor_1 = (((vendor_rev >> 10) & 0x1f) as u8 + 64) as char; - let vendor_2 = (((vendor_rev >> 5) & 0x1f) as u8 + 64) as char; - let vendor_3 = (((vendor_rev >> 0) & 0x1f) as u8 + 64) as char; - //TODO: simplify this nibble swap - let device_1 = (device >> 4) & 0xF; - let device_2 = (device >> 0) & 0xF; - let device_3 = (device >> 12) & 0xF; - let device_4 = (device >> 8) & 0xF; - format!( - "{}{}{}{:01X}{:01X}{:01X}{:01X}", - vendor_1, - vendor_2, - vendor_3, - device_1, - device_2, - device_3, - device_4 - ) - } - AmlSerdeValue::String(string) => string, - _ => { - log::warn!("{}: unsupported value {:x?}", name, value); - continue; - } - }; - let what = match id.as_str() { - // https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html - "ACPI0003" => "Power source", - "ACPI0006" => "GPE block", - "ACPI0007" => "Processor", - "ACPI0010" => "Processor control", - // https://uefi.org/sites/default/files/resources/devids%20%285%29.txt - "PNP0000" => "AT interrupt controller", - "PNP0100" => "AT timer", - "PNP0103" => "HPET", - "PNP0200" => "AT DMA controller", - "PNP0303" => "IBM Enhanced (101/102-key, PS/2 mouse support)", - "PNP030B" => "PS/2 keyboard", - "PNP0400" => "Standard LPT printer port", - "PNP0501" => "16550A-compatible COM port", - "PNP0A03" | "PNP0A08" => "PCI bus", - "PNP0A05" => "Generic ACPI bus", - "PNP0A06" => "Generic ACPI Extended-IO bus (EIO bus)", - "PNP0B00" => "AT real-time clock", - "PNP0C01" => "System board", - "PNP0C02" => "Reserved resources", - "PNP0C04" => "Math coprocessor", - "PNP0C09" => "Embedded controller", - "PNP0C0A" => "Battery", - "PNP0C0B" => "Fan", - "PNP0C0C" => "Power button", - "PNP0C0D" => "Lid sensor", - "PNP0C0E" => "Sleep button", - "PNP0C0F" => "PCI interrupt link", - "PNP0C50" => "I2C HID", - "PNP0F13" => "PS/2 port for PS/2-style mouse", - _ => "?", - }; - log::debug!("{}: {} ({})", name, id, what); - } - } - } - Ok(()) - } -} diff --git a/recipes/core/base/drivers/hwd/src/backend/devicetree.rs b/recipes/core/base/drivers/hwd/src/backend/devicetree.rs deleted file mode 100644 index 8a91d04e42..0000000000 --- a/recipes/core/base/drivers/hwd/src/backend/devicetree.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::{error::Error, fs}; - -use super::Backend; - -pub struct DeviceTreeBackend { - dtb: Vec, -} - -impl DeviceTreeBackend { - fn dump(node: &fdt::node::FdtNode<'_, '_>, level: usize) { - let mut line = String::new(); - for _ in 0..level { - line.push_str(" "); - } - line.push_str(node.name); - if let Some(compatible) = node.compatible() { - line.push_str(":"); - for id in compatible.all() { - line.push_str(" "); - line.push_str(id); - } - } - log::debug!("{}", line); - for child in node.children() { - Self::dump(&child, level + 1); - } - } -} - -impl Backend for DeviceTreeBackend { - fn new() -> Result> { - let dtb = fs::read("/scheme/kernel.dtb")?; - let dt = fdt::Fdt::new(&dtb).map_err(|err| format!("failed to parse dtb: {}", err))?; - Ok(Self { dtb }) - } - - fn probe(&mut self) -> Result<(), Box> { - let dt = fdt::Fdt::new(&self.dtb).map_err(|err| format!("failed to parse dtb: {}", err))?; - let root = dt - .find_node("/") - .ok_or_else(|| format!("failed to find root node"))?; - Self::dump(&root, 0); - Ok(()) - } -} diff --git a/recipes/core/base/drivers/hwd/src/backend/legacy.rs b/recipes/core/base/drivers/hwd/src/backend/legacy.rs deleted file mode 100644 index 23e9c1f24f..0000000000 --- a/recipes/core/base/drivers/hwd/src/backend/legacy.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::error::Error; - -use super::Backend; - -pub struct LegacyBackend; - -impl Backend for LegacyBackend { - fn new() -> Result> { - Ok(Self) - } - - fn probe(&mut self) -> Result<(), Box> { - log::info!("TODO: handle driver spawning from legacy backend"); - Ok(()) - } -} diff --git a/recipes/core/base/drivers/hwd/src/backend/mod.rs b/recipes/core/base/drivers/hwd/src/backend/mod.rs deleted file mode 100644 index 815b48aa75..0000000000 --- a/recipes/core/base/drivers/hwd/src/backend/mod.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::error::Error; - -mod acpi; -mod devicetree; -mod legacy; - -pub use self::{acpi::AcpiBackend, devicetree::DeviceTreeBackend, legacy::LegacyBackend}; - -pub trait Backend { - fn new() -> Result> - where - Self: Sized; - fn probe(&mut self) -> Result<(), Box>; -} diff --git a/recipes/core/base/drivers/hwd/src/main.rs b/recipes/core/base/drivers/hwd/src/main.rs deleted file mode 100644 index 79360e34ee..0000000000 --- a/recipes/core/base/drivers/hwd/src/main.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::process; - -mod backend; -use self::backend::{AcpiBackend, Backend, DeviceTreeBackend, LegacyBackend}; - -fn daemon(daemon: daemon::Daemon) -> ! { - common::setup_logging( - "misc", - "hwd", - "hwd", - common::output_level(), - common::file_level(), - ); - - // Prefer DTB if available (matches kernel preference) - let mut backend: Box = match DeviceTreeBackend::new() { - Ok(ok) => { - log::info!("using devicetree backend"); - Box::new(ok) - } - Err(err) => { - log::debug!("cannot use devicetree backend: {}", err); - match AcpiBackend::new() { - Ok(ok) => { - log::info!("using ACPI backend"); - Box::new(ok) - } - Err(err) => { - log::debug!("cannot use ACPI backend: {}", err); - - log::info!("using legacy backend"); - Box::new(LegacyBackend) - } - } - } - }; - - //TODO: launch pcid based on backend information? - // Must launch after acpid but before probe calls /scheme/acpi/symbols - #[allow(deprecated, reason = "we can't yet move this to init")] - daemon::Daemon::spawn(process::Command::new("pcid")); - - daemon.ready(); - - //TODO: HWD is meant to locate PCI/XHCI/etc devices in ACPI and DeviceTree definitions and start their drivers - match backend.probe() { - Ok(()) => { - process::exit(0); - } - Err(err) => { - log::error!("failed to probe with error {}", err); - process::exit(1); - } - } -} - -fn main() { - daemon::Daemon::new(daemon); -} diff --git a/recipes/core/base/drivers/i2c/amd-mp2-i2cd/Cargo.toml b/recipes/core/base/drivers/i2c/amd-mp2-i2cd/Cargo.toml deleted file mode 100644 index 357ca948c7..0000000000 --- a/recipes/core/base/drivers/i2c/amd-mp2-i2cd/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "amd-mp2-i2cd" -description = "AMD MP2 PCI I2C controller driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow.workspace = true -log.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -libredox.workspace = true -serde.workspace = true -ron.workspace = true - -acpi-resource = { path = "../../acpi-resource" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -i2c-interface = { path = "../i2c-interface" } -pcid = { path = "../../pcid" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/i2c/amd-mp2-i2cd/src/main.rs b/recipes/core/base/drivers/i2c/amd-mp2-i2cd/src/main.rs deleted file mode 100644 index 925b45e75f..0000000000 --- a/recipes/core/base/drivers/i2c/amd-mp2-i2cd/src/main.rs +++ /dev/null @@ -1,106 +0,0 @@ -use std::fs::{File, OpenOptions}; -use std::io::{Read, Write}; -use std::process; - -use anyhow::{Context, Result}; -use i2c_interface::{I2cAdapterInfo, I2cControlRequest, I2cControlResponse}; -use pcid_interface::PciFunctionHandle; - -const MP2_MAILBOX_STATUS: usize = 0x00; -const MP2_MAILBOX_COMMAND: usize = 0x04; -const MP2_MAILBOX_ARGUMENT0: usize = 0x08; -const MP2_MAILBOX_ARGUMENT1: usize = 0x0C; - -fn main() { - pcid_interface::pci_daemon(daemon_runner); -} - -fn daemon_runner(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - if let Err(err) = daemon_main(daemon, &mut pcid_handle) { - log::error!("amd-mp2-i2cd: {err:#}"); - process::exit(1); - } - - process::exit(0); -} - -fn daemon_main(daemon: daemon::Daemon, pcid_handle: &mut PciFunctionHandle) -> Result<()> { - let pci_config = pcid_handle.config(); - let log_name = format!("{}_amd-mp2-i2c", pci_config.func.name()); - - common::setup_logging( - "bus", - "i2c", - &log_name, - common::output_level(), - common::file_level(), - ); - - let mapped_bar = unsafe { pcid_handle.map_bar(0) }; - let bar_addr = mapped_bar.ptr.as_ptr() as usize; - let bar_size = mapped_bar.bar_size; - - log::info!( - "amd-mp2-i2cd: {} BAR0={:#x}+{:#x} mapped={:p}+{:#x}", - pci_config.func.display(), - bar_addr, - bar_size, - mapped_bar.ptr.as_ptr(), - mapped_bar.bar_size, - ); - log::debug!( - "amd-mp2-i2cd: MP2 mailbox regs status={MP2_MAILBOX_STATUS:#x} cmd={MP2_MAILBOX_COMMAND:#x} arg0={MP2_MAILBOX_ARGUMENT0:#x} arg1={MP2_MAILBOX_ARGUMENT1:#x}", - ); - - let info = I2cAdapterInfo { - id: 0, - name: format!("amd-mp2:{}", pci_config.func.name()), - max_transaction_size: 0, - supports_10bit_addr: false, - }; - let mut registration = register_adapter(&info) - .context("failed to register AMD MP2 controller with i2cd")?; - let response = read_registration_response(&mut registration) - .context("failed to read AMD MP2 i2cd registration response")?; - - match response { - I2cControlResponse::AdapterRegistered { id } => { - log::info!("amd-mp2-i2cd: controller registered with i2cd as adapter {id}"); - } - other => anyhow::bail!("unexpected i2cd registration response: {other:?}"), - } - - daemon.ready(); - libredox::call::setrens(0, 0).context("failed to enter null namespace")?; - - let _keep_registration = registration; - let _keep_pcid = pcid_handle; - - loop { - std::thread::park(); - } -} - -fn register_adapter(info: &I2cAdapterInfo) -> Result { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .open("/scheme/i2c/register") - .context("failed to open /scheme/i2c/register")?; - let payload = ron::ser::to_string(&I2cControlRequest::RegisterAdapter { info: info.clone() }) - .context("failed to encode AMD MP2 I2C registration payload")?; - file.write_all(payload.as_bytes()) - .context("failed to send AMD MP2 I2C registration payload")?; - Ok(file) -} - -fn read_registration_response(file: &mut File) -> Result { - let mut buffer = vec![0_u8; 4096]; - let count = file - .read(&mut buffer) - .context("failed to read AMD MP2 I2C registration response")?; - buffer.truncate(count); - let text = std::str::from_utf8(&buffer) - .context("AMD MP2 I2C registration response was not UTF-8")?; - ron::from_str(text).context("failed to decode AMD MP2 I2C registration response") -} diff --git a/recipes/core/base/drivers/i2c/dw-acpi-i2cd/Cargo.toml b/recipes/core/base/drivers/i2c/dw-acpi-i2cd/Cargo.toml deleted file mode 100644 index a90b48cce3..0000000000 --- a/recipes/core/base/drivers/i2c/dw-acpi-i2cd/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "dw-acpi-i2cd" -description = "Generic DesignWare ACPI I2C controller driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow.workspace = true -log.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -libredox.workspace = true -serde.workspace = true -ron.workspace = true - -acpi-resource = { path = "../../acpi-resource" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -i2c-interface = { path = "../i2c-interface" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/i2c/dw-acpi-i2cd/src/main.rs b/recipes/core/base/drivers/i2c/dw-acpi-i2cd/src/main.rs deleted file mode 100644 index b22a27739d..0000000000 --- a/recipes/core/base/drivers/i2c/dw-acpi-i2cd/src/main.rs +++ /dev/null @@ -1,361 +0,0 @@ -use std::collections::BTreeMap; -use std::fs::{self, File, OpenOptions}; -use std::io::{Read, Write}; -use std::path::Path; -use std::process; - -use acpi_resource::{ - AddressResourceType, ExtendedIrqDescriptor, FixedMemory32Descriptor, I2cSerialBusDescriptor, - IrqDescriptor, Memory32RangeDescriptor, ResourceDescriptor, -}; -use anyhow::{Context, Result}; -use common::{MemoryType, PhysBorrowed, Prot}; -use i2c_interface::{I2cAdapterInfo, I2cControlRequest, I2cControlResponse}; -use serde::Deserialize; - -const SUPPORTED_IDS: &[&str] = &["80860F41", "808622C1", "AMDI0010", "AMDI0019", "AMDI0510"]; - -const DW_IC_CON: usize = 0x00; -const DW_IC_TAR: usize = 0x04; -const DW_IC_SS_SCL_HCNT: usize = 0x14; -const DW_IC_SS_SCL_LCNT: usize = 0x18; -const DW_IC_DATA_CMD: usize = 0x10; -const DW_IC_INTR_MASK: usize = 0x30; -const DW_IC_CLR_INTR: usize = 0x40; -const DW_IC_ENABLE: usize = 0x6C; -const DW_IC_STATUS: usize = 0x70; -const DW_MMIO_WINDOW: usize = DW_IC_STATUS + core::mem::size_of::(); - -#[derive(Debug, Deserialize)] -struct AmlSymbol { - name: String, - value: AmlValue, -} - -#[derive(Debug, Deserialize)] -enum AmlValue { - Integer(u64), - String(String), -} - -#[derive(Clone, Debug)] -struct ControllerResources { - mmio_base: usize, - mmio_len: usize, - irq: Option, - serial_bus: Option, -} - -#[derive(Debug)] -struct ControllerDescriptor { - device: String, - hid: String, - resources: ControllerResources, -} - -struct RegisteredController { - _mmio: Option, - _registration: File, -} - -fn main() { - common::setup_logging( - "bus", - "i2c", - "dw-acpi-i2cd", - common::output_level(), - common::file_level(), - ); - - daemon::Daemon::new(daemon_runner); -} - -fn daemon_runner(daemon: daemon::Daemon) -> ! { - if let Err(err) = daemon_main(daemon) { - log::error!("dw-acpi-i2cd: {err:#}"); - process::exit(1); - } - - process::exit(0); -} - -fn daemon_main(daemon: daemon::Daemon) -> Result<()> { - common::init(); - - let controllers = discover_controllers(SUPPORTED_IDS) - .context("failed to discover DesignWare ACPI I2C controllers")?; - if controllers.is_empty() { - log::info!("dw-acpi-i2cd: no supported ACPI controllers found"); - } - - let mut registered = Vec::new(); - for controller in controllers { - match register_controller("dw-acpi", controller) { - Ok(controller) => registered.push(controller), - Err(err) => log::warn!("dw-acpi-i2cd: controller registration skipped: {err:#}"), - } - } - - daemon.ready(); - libredox::call::setrens(0, 0).context("failed to enter null namespace")?; - - log::info!("dw-acpi-i2cd: registered {} controller(s)", registered.len()); - - loop { - std::thread::park(); - } -} - -fn discover_controllers(supported_ids: &[&str]) -> Result> { - let mut matched = BTreeMap::new(); - - let entries = match fs::read_dir("/scheme/acpi/symbols") { - Ok(entries) => entries, - Err(err) - if err.kind() == std::io::ErrorKind::WouldBlock || err.raw_os_error() == Some(11) => - { - log::debug!("dw-acpi-i2cd: ACPI symbols are not ready yet"); - return Ok(Vec::new()); - } - Err(err) => return Err(err).context("failed to read /scheme/acpi/symbols"), - }; - - for entry in entries { - let entry = entry.context("failed to read ACPI symbol directory entry")?; - let Some(file_name) = entry.file_name().to_str().map(str::to_owned) else { - continue; - }; - if !file_name.ends_with("_HID") && !file_name.ends_with("_CID") { - continue; - } - - let Some(id) = read_symbol_id(&entry.path())? else { - continue; - }; - if !supported_ids.iter().any(|candidate| *candidate == id) { - continue; - } - - let device = file_name - .strip_suffix("_HID") - .or_else(|| file_name.strip_suffix("_CID")) - .map(str::to_owned); - if let Some(device) = device { - matched.entry(device).or_insert(id); - } - } - - let mut controllers = Vec::new(); - for (device, hid) in matched { - let resources = read_controller_resources(&device) - .with_context(|| format!("failed to read resources for {device}"))?; - controllers.push(ControllerDescriptor { - device, - hid, - resources, - }); - } - - Ok(controllers) -} - -fn read_symbol_id(path: &Path) -> Result> { - let contents = fs::read_to_string(path) - .with_context(|| format!("failed to read ACPI symbol {}", path.display()))?; - let symbol = match ron::from_str::(&contents) { - Ok(symbol) => symbol, - Err(err) => { - log::debug!( - "dw-acpi-i2cd: skipping {} because the symbol payload was not a scalar ID: {err}", - path.display(), - ); - return Ok(None); - } - }; - - let id = match symbol.value { - AmlValue::Integer(integer) => eisa_id_from_integer(integer), - AmlValue::String(string) => string, - }; - - log::debug!("dw-acpi-i2cd: {} -> {id}", symbol.name); - Ok(Some(id)) -} - -fn read_controller_resources(device: &str) -> Result { - let contents = fs::read_to_string(format!("/scheme/acpi/resources/{device}")) - .with_context(|| format!("failed to read /scheme/acpi/resources/{device}"))?; - let resources = ron::from_str::>(&contents) - .with_context(|| format!("failed to decode RON resources for {device}"))?; - - let mut mmio = None; - let mut irq = None; - let mut serial_bus = None; - - for resource in &resources { - match resource { - ResourceDescriptor::FixedMemory32(FixedMemory32Descriptor { - address, - address_length, - .. - }) if mmio.is_none() => { - mmio = Some((*address as usize, (*address_length as usize).max(DW_MMIO_WINDOW))); - } - ResourceDescriptor::Memory32Range(Memory32RangeDescriptor { - minimum, - maximum, - address_length, - .. - }) if mmio.is_none() && maximum >= minimum => { - let span = maximum.saturating_sub(*minimum).saturating_add(1) as usize; - mmio = Some(( - *minimum as usize, - span.max((*address_length as usize).max(DW_MMIO_WINDOW)), - )); - } - ResourceDescriptor::Address32(descriptor) - if mmio.is_none() - && matches!(descriptor.resource_type, AddressResourceType::MemoryRange) => - { - mmio = Some(( - descriptor.minimum as usize, - (descriptor.address_length as usize).max(DW_MMIO_WINDOW), - )); - } - ResourceDescriptor::Address64(descriptor) - if mmio.is_none() - && matches!(descriptor.resource_type, AddressResourceType::MemoryRange) => - { - let base = usize::try_from(descriptor.minimum) - .context("64-bit MMIO base does not fit in usize")?; - let len = usize::try_from(descriptor.address_length) - .context("64-bit MMIO length does not fit in usize")?; - mmio = Some((base, len.max(DW_MMIO_WINDOW))); - } - ResourceDescriptor::Irq(IrqDescriptor { interrupts, .. }) if irq.is_none() => { - irq = interrupts.first().copied().map(u32::from); - } - ResourceDescriptor::ExtendedIrq(ExtendedIrqDescriptor { interrupts, .. }) - if irq.is_none() => - { - irq = interrupts.first().copied(); - } - ResourceDescriptor::I2cSerialBus(descriptor) if serial_bus.is_none() => { - serial_bus = Some(descriptor.clone()); - } - _ => {} - } - } - - let (mmio_base, mmio_len) = mmio.context("no MMIO resource was found")?; - Ok(ControllerResources { - mmio_base, - mmio_len, - irq, - serial_bus, - }) -} - -fn register_controller(prefix: &str, controller: ControllerDescriptor) -> Result { - let ControllerDescriptor { - device, - hid, - resources, - } = controller; - - let mmio = match PhysBorrowed::map( - resources.mmio_base, - resources.mmio_len, - Prot::RW, - MemoryType::Uncacheable, - ) { - Ok(mapping) => Some(mapping), - Err(err) => { - log::warn!( - "dw-acpi-i2cd: failed to map MMIO for {device} ({:#x}, len {:#x}): {err}", - resources.mmio_base, - resources.mmio_len, - ); - None - } - }; - - log::info!( - "dw-acpi-i2cd: discovered {device} hid={hid} mmio={:#x}+{:#x} irq={:?}", - resources.mmio_base, - resources.mmio_len, - resources.irq, - ); - log::debug!( - "dw-acpi-i2cd: DesignWare regs con={DW_IC_CON:#x} tar={DW_IC_TAR:#x} data_cmd={DW_IC_DATA_CMD:#x} intr_mask={DW_IC_INTR_MASK:#x} clr_intr={DW_IC_CLR_INTR:#x} enable={DW_IC_ENABLE:#x} ss_hcnt={DW_IC_SS_SCL_HCNT:#x} ss_lcnt={DW_IC_SS_SCL_LCNT:#x}", - ); - - let info = I2cAdapterInfo { - id: 0, - name: format!("{prefix}:{device}"), - max_transaction_size: 0, - supports_10bit_addr: resources - .serial_bus - .as_ref() - .map(|bus| bus.access_mode_10bit) - .unwrap_or(false), - }; - let mut registration = register_adapter(&info) - .with_context(|| format!("failed to register {device} with i2cd"))?; - let response = read_registration_response(&mut registration) - .with_context(|| format!("failed to read i2cd registration response for {device}"))?; - - match response { - I2cControlResponse::AdapterRegistered { id } => { - log::info!("dw-acpi-i2cd: adapter {device} registered with i2cd as {id}"); - } - other => { - anyhow::bail!("unexpected i2cd registration response for {device}: {other:?}"); - } - } - - Ok(RegisteredController { - _mmio: mmio, - _registration: registration, - }) -} - -fn register_adapter(info: &I2cAdapterInfo) -> Result { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .open("/scheme/i2c/register") - .context("failed to open /scheme/i2c/register")?; - let payload = ron::ser::to_string(&I2cControlRequest::RegisterAdapter { info: info.clone() }) - .context("failed to encode I2C adapter registration")?; - file.write_all(payload.as_bytes()) - .context("failed to send I2C adapter registration")?; - Ok(file) -} - -fn read_registration_response(file: &mut File) -> Result { - let mut buffer = vec![0_u8; 4096]; - let count = file - .read(&mut buffer) - .context("failed to read I2C registration response")?; - buffer.truncate(count); - let text = std::str::from_utf8(&buffer).context("I2C registration response was not UTF-8")?; - ron::from_str(text).context("failed to decode I2C registration response") -} - -fn eisa_id_from_integer(integer: u64) -> String { - let vendor = integer & 0xFFFF; - let device = (integer >> 16) & 0xFFFF; - let vendor_rev = ((vendor & 0xFF) << 8) | (vendor >> 8); - let vendor_1 = (((vendor_rev >> 10) & 0x1F) as u8 + 64) as char; - let vendor_2 = (((vendor_rev >> 5) & 0x1F) as u8 + 64) as char; - let vendor_3 = (((vendor_rev >> 0) & 0x1F) as u8 + 64) as char; - let device_1 = (device >> 4) & 0xF; - let device_2 = (device >> 0) & 0xF; - let device_3 = (device >> 12) & 0xF; - let device_4 = (device >> 8) & 0xF; - - format!( - "{vendor_1}{vendor_2}{vendor_3}{device_1:01X}{device_2:01X}{device_3:01X}{device_4:01X}" - ) -} diff --git a/recipes/core/base/drivers/i2c/i2c-interface/Cargo.toml b/recipes/core/base/drivers/i2c/i2c-interface/Cargo.toml deleted file mode 100644 index fa9bbe4f85..0000000000 --- a/recipes/core/base/drivers/i2c/i2c-interface/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "i2c-interface" -description = "Shared I2C transfer and registry types" -version = "0.1.0" -edition = "2021" - -[dependencies] -serde.workspace = true -redox_syscall = { workspace = true, features = ["std"] } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/i2c/i2c-interface/src/lib.rs b/recipes/core/base/drivers/i2c/i2c-interface/src/lib.rs deleted file mode 100644 index 9e5ab4448e..0000000000 --- a/recipes/core/base/drivers/i2c/i2c-interface/src/lib.rs +++ /dev/null @@ -1,92 +0,0 @@ -use serde::{Deserialize, Serialize}; - -pub use syscall; - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum I2cTransferOp { - Write(Vec), - Read(usize), -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct I2cTransferSegment { - pub address: u16, - pub ten_bit_address: bool, - pub op: I2cTransferOp, -} - -impl I2cTransferSegment { - pub fn write(address: u16, payload: impl Into>) -> Self { - Self { - address, - ten_bit_address: false, - op: I2cTransferOp::Write(payload.into()), - } - } - - pub fn read(address: u16, len: usize) -> Self { - Self { - address, - ten_bit_address: false, - op: I2cTransferOp::Read(len), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct I2cTransferRequest { - pub adapter: String, - pub segments: Vec, - pub stop: bool, -} - -#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] -pub struct I2cTransferResponse { - pub ok: bool, - pub read_data: Vec>, - pub error: Option, -} - -#[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct I2cAdapterRegistration { - pub name: String, - pub description: String, - pub acpi_companion: Option, - pub slave_address_override: Option, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct I2cAdapterInfo { - pub id: u32, - pub name: String, - pub max_transaction_size: usize, - pub supports_10bit_addr: bool, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum I2cTransferStatus { - Ok, - Nack, - Timeout, - Error, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum I2cControlRequest { - RegisterAdapter { info: I2cAdapterInfo }, - OpenAdapter { id: u32 }, - Transfer { - adapter_id: u32, - request: I2cTransferRequest, - }, - ListAdapters, -} - -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub enum I2cControlResponse { - AdapterRegistered { id: u32 }, - AdapterOpened, - TransferResult(I2cTransferResponse), - AdapterList(Vec), - Error(String), -} diff --git a/recipes/core/base/drivers/i2c/i2cd/Cargo.toml b/recipes/core/base/drivers/i2c/i2cd/Cargo.toml deleted file mode 100644 index 0fdd6911fe..0000000000 --- a/recipes/core/base/drivers/i2c/i2cd/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "i2cd" -description = "I2C adapter registry scheme daemon" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow.workspace = true -log.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -libredox.workspace = true -redox-scheme.workspace = true -serde.workspace = true -ron.workspace = true - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -scheme-utils = { path = "../../../scheme-utils" } -i2c-interface = { path = "../i2c-interface" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/i2c/i2cd/src/main.rs b/recipes/core/base/drivers/i2c/i2cd/src/main.rs deleted file mode 100644 index b7b7d89aab..0000000000 --- a/recipes/core/base/drivers/i2c/i2cd/src/main.rs +++ /dev/null @@ -1,377 +0,0 @@ -use std::collections::BTreeMap; -use std::process; - -use anyhow::{Context, Result}; -use i2c_interface::{ - I2cAdapterInfo, I2cControlRequest, I2cControlResponse, I2cTransferRequest, - I2cTransferResponse, -}; -use redox_scheme::scheme::SchemeSync; -use redox_scheme::{CallerCtx, OpenResult, Socket}; -use scheme_utils::{Blocking, HandleMap}; -use syscall::schemev2::NewFdFlags; -use syscall::{Error as SysError, EACCES, EBADF, EINVAL, ENOENT}; - -enum Handle { - SchemeRoot, - Register { pending: Vec }, - Provider { adapter_id: u32, pending: Vec }, - Adapters { pending: Vec }, - AdapterDetail { id: u32, pending: Vec }, - Transfer { pending: Vec }, -} - -struct AdapterEntry { - info: I2cAdapterInfo, - provider_handle: usize, -} - -struct I2cDaemon { - handles: HandleMap, - adapters: BTreeMap, - next_id: u32, -} - -impl I2cDaemon { - fn new() -> Self { - Self { - handles: HandleMap::new(), - adapters: BTreeMap::new(), - next_id: 0, - } - } - - fn adapter_list(&self) -> Vec { - self.adapters.values().map(|entry| entry.info.clone()).collect() - } - - fn serialize_response(response: &I2cControlResponse) -> syscall::Result> { - ron::ser::to_string(response) - .map(|text| text.into_bytes()) - .map_err(|err| { - log::error!("i2cd: failed to serialize control response: {err}"); - SysError::new(EINVAL) - }) - } - - fn deserialize_request(buf: &[u8]) -> syscall::Result { - let text = std::str::from_utf8(buf).map_err(|err| { - log::warn!("i2cd: invalid UTF-8 control payload: {err}"); - SysError::new(EINVAL) - })?; - - ron::from_str(text).map_err(|err| { - log::warn!("i2cd: failed to decode control request: {err}"); - SysError::new(EINVAL) - }) - } - - fn set_pending_response(handle: &mut Handle, response: I2cControlResponse) -> syscall::Result<()> { - let pending = Self::serialize_response(&response)?; - match handle { - Handle::Register { pending: slot } - | Handle::Provider { pending: slot, .. } - | Handle::Adapters { pending: slot } - | Handle::AdapterDetail { pending: slot, .. } - | Handle::Transfer { pending: slot } => { - *slot = pending; - Ok(()) - } - Handle::SchemeRoot => Err(SysError::new(EBADF)), - } - } - - fn queue_adapter_list(handle: &mut Handle, adapters: Vec) -> syscall::Result<()> { - Self::set_pending_response(handle, I2cControlResponse::AdapterList(adapters)) - } - - fn queue_transfer_stub( - handle: &mut Handle, - adapter: &I2cAdapterInfo, - request: &I2cTransferRequest, - ) -> syscall::Result<()> { - let write_bytes = request - .segments - .iter() - .filter_map(|segment| match &segment.op { - i2c_interface::I2cTransferOp::Write(bytes) => Some(bytes.len()), - i2c_interface::I2cTransferOp::Read(_) => None, - }) - .sum::(); - let read_segments = request - .segments - .iter() - .filter(|segment| matches!(segment.op, i2c_interface::I2cTransferOp::Read(_))) - .count(); - - log::info!( - "i2cd: routing transfer to adapter {} ({}) name={} segments={} write_bytes={} read_segments={} stop={} (stubbed)", - adapter.id, - adapter.name, - request.adapter, - request.segments.len(), - write_bytes, - read_segments, - request.stop, - ); - - Self::set_pending_response( - handle, - I2cControlResponse::TransferResult(I2cTransferResponse { - ok: false, - read_data: Vec::new(), - error: Some(String::from("I2C controller transfer path is not implemented yet")), - }), - ) - } - - fn copy_pending(handle: &mut Handle, buf: &mut [u8], offset: u64) -> syscall::Result { - let pending = match handle { - Handle::Register { pending } - | Handle::Provider { pending, .. } - | Handle::Adapters { pending } - | Handle::AdapterDetail { pending, .. } - | Handle::Transfer { pending } => pending, - Handle::SchemeRoot => return Err(SysError::new(EBADF)), - }; - - let offset = usize::try_from(offset).map_err(|_| SysError::new(EINVAL))?; - if offset >= pending.len() { - return Ok(0); - } - - let copy_len = buf.len().min(pending.len() - offset); - buf[..copy_len].copy_from_slice(&pending[offset..offset + copy_len]); - Ok(copy_len) - } -} - -impl SchemeSync for I2cDaemon { - fn scheme_root(&mut self) -> syscall::Result { - Ok(self.handles.insert(Handle::SchemeRoot)) - } - - fn openat( - &mut self, - dirfd: usize, - path: &str, - _flags: usize, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> syscall::Result { - let handle = self.handles.get(dirfd)?; - let segments = path.trim_matches('/'); - - let new_handle = match handle { - Handle::SchemeRoot => { - if segments.is_empty() { - return Err(SysError::new(EINVAL)); - } - - let mut parts = segments.split('/'); - match parts.next() { - Some("register") if parts.next().is_none() => Handle::Register { - pending: Vec::new(), - }, - Some("adapters") => match parts.next() { - None => Handle::Adapters { - pending: Vec::new(), - }, - Some(id) if parts.next().is_none() => { - let id = id.parse::().map_err(|_| SysError::new(EINVAL))?; - Handle::AdapterDetail { - id, - pending: Vec::new(), - } - } - _ => return Err(SysError::new(EINVAL)), - }, - Some("transfer") if parts.next().is_none() => Handle::Transfer { - pending: Vec::new(), - }, - _ => return Err(SysError::new(ENOENT)), - } - } - Handle::Adapters { .. } => { - if segments.is_empty() { - return Err(SysError::new(EINVAL)); - } - - let id = segments.parse::().map_err(|_| SysError::new(EINVAL))?; - Handle::AdapterDetail { - id, - pending: Vec::new(), - } - } - _ => return Err(SysError::new(EACCES)), - }; - - let fd = self.handles.insert(new_handle); - Ok(OpenResult::ThisScheme { - number: fd, - flags: NewFdFlags::empty(), - }) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> syscall::Result { - let adapters = self.adapter_list(); - let handle = self.handles.get_mut(id)?; - - match handle { - Handle::Adapters { pending } if pending.is_empty() => { - *pending = Self::serialize_response(&I2cControlResponse::AdapterList(adapters))?; - } - Handle::AdapterDetail { id, pending } if pending.is_empty() => { - let info = self - .adapters - .get(id) - .map(|entry| entry.info.clone()) - .ok_or(SysError::new(ENOENT))?; - *pending = Self::serialize_response(&I2cControlResponse::AdapterList(vec![info]))?; - } - _ => {} - } - - Self::copy_pending(handle, buf, offset) - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> syscall::Result { - let request = Self::deserialize_request(buf)?; - - match request { - I2cControlRequest::RegisterAdapter { mut info } => { - let adapter_id = self.next_id; - self.next_id = self.next_id.checked_add(1).ok_or(SysError::new(EINVAL))?; - info.id = adapter_id; - - self.adapters.insert( - adapter_id, - AdapterEntry { - info: info.clone(), - provider_handle: id, - }, - ); - - let handle = self.handles.get_mut(id)?; - *handle = Handle::Provider { - adapter_id, - pending: Self::serialize_response(&I2cControlResponse::AdapterRegistered { - id: adapter_id, - })?, - }; - - log::info!( - "RB_I2CD_ADAPTER_REGISTERED id={} name={} max_transaction_size={} supports_10bit_addr={}", - info.id, - info.name, - info.max_transaction_size, - info.supports_10bit_addr, - ); - Ok(buf.len()) - } - I2cControlRequest::ListAdapters => { - let adapters = self.adapter_list(); - let handle = self.handles.get_mut(id)?; - Self::queue_adapter_list(handle, adapters)?; - Ok(buf.len()) - } - I2cControlRequest::OpenAdapter { id: adapter_id } => { - if !self.adapters.contains_key(&adapter_id) { - return Err(SysError::new(ENOENT)); - } - - let handle = self.handles.get_mut(id)?; - match handle { - Handle::Adapters { .. } | Handle::AdapterDetail { .. } => { - Self::set_pending_response(handle, I2cControlResponse::AdapterOpened)?; - Ok(buf.len()) - } - _ => Err(SysError::new(EINVAL)), - } - } - I2cControlRequest::Transfer { - adapter_id, - request, - } => { - let entry = self.adapters.get(&adapter_id).ok_or(SysError::new(ENOENT))?; - log::debug!( - "i2cd: transfer requested for adapter {} via provider fd {}", - adapter_id, - entry.provider_handle, - ); - - let adapter_info = entry.info.clone(); - let handle = self.handles.get_mut(id)?; - match handle { - Handle::Transfer { .. } => { - Self::queue_transfer_stub(handle, &adapter_info, &request)?; - Ok(buf.len()) - } - _ => Err(SysError::new(EINVAL)), - } - } - } - } - - fn on_close(&mut self, id: usize) { - let Some(handle) = self.handles.remove(id) else { - return; - }; - if let Handle::Provider { adapter_id, .. } = handle { - self.adapters.remove(&adapter_id); - } - } -} - -fn run_daemon(daemon: daemon::SchemeDaemon) -> Result<()> { - let socket = Socket::create().context("failed to create i2c scheme socket")?; - let mut scheme = I2cDaemon::new(); - let handler = Blocking::new(&socket, 16); - - daemon - .ready_sync_scheme(&socket, &mut scheme) - .context("failed to publish i2c scheme root")?; - - log::info!("RB_I2CD_SCHEMA"); - - libredox::call::setrens(0, 0).context("failed to enter null namespace")?; - - handler - .process_requests_blocking(scheme) - .context("failed to process i2cd requests")?; -} - -fn daemon_runner(daemon: daemon::SchemeDaemon) -> ! { - if let Err(err) = run_daemon(daemon) { - log::error!("i2cd: {err:#}"); - process::exit(1); - } - - process::exit(0); -} - -fn main() { - common::setup_logging( - "bus", - "i2c", - "i2cd", - common::output_level(), - common::file_level(), - ); - - daemon::SchemeDaemon::new(daemon_runner); -} diff --git a/recipes/core/base/drivers/i2c/intel-lpss-i2cd/Cargo.toml b/recipes/core/base/drivers/i2c/intel-lpss-i2cd/Cargo.toml deleted file mode 100644 index 0e74cf94d6..0000000000 --- a/recipes/core/base/drivers/i2c/intel-lpss-i2cd/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "intel-lpss-i2cd" -description = "Intel LPSS ACPI I2C controller driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow.workspace = true -log.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -libredox.workspace = true -serde.workspace = true -ron.workspace = true - -acpi-resource = { path = "../../acpi-resource" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -i2c-interface = { path = "../i2c-interface" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/i2c/intel-lpss-i2cd/src/main.rs b/recipes/core/base/drivers/i2c/intel-lpss-i2cd/src/main.rs deleted file mode 100644 index ca3ead4374..0000000000 --- a/recipes/core/base/drivers/i2c/intel-lpss-i2cd/src/main.rs +++ /dev/null @@ -1,361 +0,0 @@ -use std::collections::BTreeMap; -use std::fs::{self, File, OpenOptions}; -use std::io::{Read, Write}; -use std::path::Path; -use std::process; - -use acpi_resource::{ - AddressResourceType, ExtendedIrqDescriptor, FixedMemory32Descriptor, I2cSerialBusDescriptor, - IrqDescriptor, Memory32RangeDescriptor, ResourceDescriptor, -}; -use anyhow::{Context, Result}; -use common::{MemoryType, PhysBorrowed, Prot}; -use i2c_interface::{I2cAdapterInfo, I2cControlRequest, I2cControlResponse}; -use serde::Deserialize; - -const SUPPORTED_IDS: &[&str] = &["INT33C2", "INT33C3", "INT3432", "INT3433", "INTC10EF"]; - -const DW_IC_CON: usize = 0x00; -const DW_IC_TAR: usize = 0x04; -const DW_IC_SS_SCL_HCNT: usize = 0x14; -const DW_IC_SS_SCL_LCNT: usize = 0x18; -const DW_IC_DATA_CMD: usize = 0x10; -const DW_IC_INTR_MASK: usize = 0x30; -const DW_IC_CLR_INTR: usize = 0x40; -const DW_IC_ENABLE: usize = 0x6C; -const DW_IC_STATUS: usize = 0x70; -const DW_MMIO_WINDOW: usize = DW_IC_STATUS + core::mem::size_of::(); - -#[derive(Debug, Deserialize)] -struct AmlSymbol { - name: String, - value: AmlValue, -} - -#[derive(Debug, Deserialize)] -enum AmlValue { - Integer(u64), - String(String), -} - -#[derive(Clone, Debug)] -struct ControllerResources { - mmio_base: usize, - mmio_len: usize, - irq: Option, - serial_bus: Option, -} - -#[derive(Debug)] -struct ControllerDescriptor { - device: String, - hid: String, - resources: ControllerResources, -} - -struct RegisteredController { - _mmio: Option, - _registration: File, -} - -fn main() { - common::setup_logging( - "bus", - "i2c", - "intel-lpss-i2cd", - common::output_level(), - common::file_level(), - ); - - daemon::Daemon::new(daemon_runner); -} - -fn daemon_runner(daemon: daemon::Daemon) -> ! { - if let Err(err) = daemon_main(daemon) { - log::error!("intel-lpss-i2cd: {err:#}"); - process::exit(1); - } - - process::exit(0); -} - -fn daemon_main(daemon: daemon::Daemon) -> Result<()> { - common::init(); - - let controllers = discover_controllers(SUPPORTED_IDS) - .context("failed to discover Intel LPSS ACPI I2C controllers")?; - if controllers.is_empty() { - log::info!("intel-lpss-i2cd: no supported ACPI controllers found"); - } - - let mut registered = Vec::new(); - for controller in controllers { - match register_controller("intel-lpss", controller) { - Ok(controller) => registered.push(controller), - Err(err) => log::warn!("intel-lpss-i2cd: controller registration skipped: {err:#}"), - } - } - - daemon.ready(); - libredox::call::setrens(0, 0).context("failed to enter null namespace")?; - - log::info!("intel-lpss-i2cd: registered {} controller(s)", registered.len()); - - loop { - std::thread::park(); - } -} - -fn discover_controllers(supported_ids: &[&str]) -> Result> { - let mut matched = BTreeMap::new(); - - let entries = match fs::read_dir("/scheme/acpi/symbols") { - Ok(entries) => entries, - Err(err) - if err.kind() == std::io::ErrorKind::WouldBlock || err.raw_os_error() == Some(11) => - { - log::debug!("intel-lpss-i2cd: ACPI symbols are not ready yet"); - return Ok(Vec::new()); - } - Err(err) => return Err(err).context("failed to read /scheme/acpi/symbols"), - }; - - for entry in entries { - let entry = entry.context("failed to read ACPI symbol directory entry")?; - let Some(file_name) = entry.file_name().to_str().map(str::to_owned) else { - continue; - }; - if !file_name.ends_with("_HID") && !file_name.ends_with("_CID") { - continue; - } - - let Some(id) = read_symbol_id(&entry.path())? else { - continue; - }; - if !supported_ids.iter().any(|candidate| *candidate == id) { - continue; - } - - let device = file_name - .strip_suffix("_HID") - .or_else(|| file_name.strip_suffix("_CID")) - .map(str::to_owned); - if let Some(device) = device { - matched.entry(device).or_insert(id); - } - } - - let mut controllers = Vec::new(); - for (device, hid) in matched { - let resources = read_controller_resources(&device) - .with_context(|| format!("failed to read resources for {device}"))?; - controllers.push(ControllerDescriptor { - device, - hid, - resources, - }); - } - - Ok(controllers) -} - -fn read_symbol_id(path: &Path) -> Result> { - let contents = fs::read_to_string(path) - .with_context(|| format!("failed to read ACPI symbol {}", path.display()))?; - let symbol = match ron::from_str::(&contents) { - Ok(symbol) => symbol, - Err(err) => { - log::debug!( - "intel-lpss-i2cd: skipping {} because the symbol payload was not a scalar ID: {err}", - path.display(), - ); - return Ok(None); - } - }; - - let id = match symbol.value { - AmlValue::Integer(integer) => eisa_id_from_integer(integer), - AmlValue::String(string) => string, - }; - - log::debug!("intel-lpss-i2cd: {} -> {id}", symbol.name); - Ok(Some(id)) -} - -fn read_controller_resources(device: &str) -> Result { - let contents = fs::read_to_string(format!("/scheme/acpi/resources/{device}")) - .with_context(|| format!("failed to read /scheme/acpi/resources/{device}"))?; - let resources = ron::from_str::>(&contents) - .with_context(|| format!("failed to decode RON resources for {device}"))?; - - let mut mmio = None; - let mut irq = None; - let mut serial_bus = None; - - for resource in &resources { - match resource { - ResourceDescriptor::FixedMemory32(FixedMemory32Descriptor { - address, - address_length, - .. - }) if mmio.is_none() => { - mmio = Some((*address as usize, (*address_length as usize).max(DW_MMIO_WINDOW))); - } - ResourceDescriptor::Memory32Range(Memory32RangeDescriptor { - minimum, - maximum, - address_length, - .. - }) if mmio.is_none() && maximum >= minimum => { - let span = maximum.saturating_sub(*minimum).saturating_add(1) as usize; - mmio = Some(( - *minimum as usize, - span.max((*address_length as usize).max(DW_MMIO_WINDOW)), - )); - } - ResourceDescriptor::Address32(descriptor) - if mmio.is_none() - && matches!(descriptor.resource_type, AddressResourceType::MemoryRange) => - { - mmio = Some(( - descriptor.minimum as usize, - (descriptor.address_length as usize).max(DW_MMIO_WINDOW), - )); - } - ResourceDescriptor::Address64(descriptor) - if mmio.is_none() - && matches!(descriptor.resource_type, AddressResourceType::MemoryRange) => - { - let base = usize::try_from(descriptor.minimum) - .context("64-bit MMIO base does not fit in usize")?; - let len = usize::try_from(descriptor.address_length) - .context("64-bit MMIO length does not fit in usize")?; - mmio = Some((base, len.max(DW_MMIO_WINDOW))); - } - ResourceDescriptor::Irq(IrqDescriptor { interrupts, .. }) if irq.is_none() => { - irq = interrupts.first().copied().map(u32::from); - } - ResourceDescriptor::ExtendedIrq(ExtendedIrqDescriptor { interrupts, .. }) - if irq.is_none() => - { - irq = interrupts.first().copied(); - } - ResourceDescriptor::I2cSerialBus(descriptor) if serial_bus.is_none() => { - serial_bus = Some(descriptor.clone()); - } - _ => {} - } - } - - let (mmio_base, mmio_len) = mmio.context("no MMIO resource was found")?; - Ok(ControllerResources { - mmio_base, - mmio_len, - irq, - serial_bus, - }) -} - -fn register_controller(prefix: &str, controller: ControllerDescriptor) -> Result { - let ControllerDescriptor { - device, - hid, - resources, - } = controller; - - let mmio = match PhysBorrowed::map( - resources.mmio_base, - resources.mmio_len, - Prot::RW, - MemoryType::Uncacheable, - ) { - Ok(mapping) => Some(mapping), - Err(err) => { - log::warn!( - "intel-lpss-i2cd: failed to map MMIO for {device} ({:#x}, len {:#x}): {err}", - resources.mmio_base, - resources.mmio_len, - ); - None - } - }; - - log::info!( - "intel-lpss-i2cd: discovered {device} hid={hid} mmio={:#x}+{:#x} irq={:?}", - resources.mmio_base, - resources.mmio_len, - resources.irq, - ); - log::debug!( - "intel-lpss-i2cd: DesignWare regs con={DW_IC_CON:#x} tar={DW_IC_TAR:#x} data_cmd={DW_IC_DATA_CMD:#x} intr_mask={DW_IC_INTR_MASK:#x} clr_intr={DW_IC_CLR_INTR:#x} enable={DW_IC_ENABLE:#x} ss_hcnt={DW_IC_SS_SCL_HCNT:#x} ss_lcnt={DW_IC_SS_SCL_LCNT:#x}", - ); - - let info = I2cAdapterInfo { - id: 0, - name: format!("{prefix}:{device}"), - max_transaction_size: 0, - supports_10bit_addr: resources - .serial_bus - .as_ref() - .map(|bus| bus.access_mode_10bit) - .unwrap_or(false), - }; - let mut registration = register_adapter(&info) - .with_context(|| format!("failed to register {device} with i2cd"))?; - let response = read_registration_response(&mut registration) - .with_context(|| format!("failed to read i2cd registration response for {device}"))?; - - match response { - I2cControlResponse::AdapterRegistered { id } => { - log::info!("intel-lpss-i2cd: adapter {device} registered with i2cd as {id}"); - } - other => { - anyhow::bail!("unexpected i2cd registration response for {device}: {other:?}"); - } - } - - Ok(RegisteredController { - _mmio: mmio, - _registration: registration, - }) -} - -fn register_adapter(info: &I2cAdapterInfo) -> Result { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .open("/scheme/i2c/register") - .context("failed to open /scheme/i2c/register")?; - let payload = ron::ser::to_string(&I2cControlRequest::RegisterAdapter { info: info.clone() }) - .context("failed to encode I2C adapter registration")?; - file.write_all(payload.as_bytes()) - .context("failed to send I2C adapter registration")?; - Ok(file) -} - -fn read_registration_response(file: &mut File) -> Result { - let mut buffer = vec![0_u8; 4096]; - let count = file - .read(&mut buffer) - .context("failed to read I2C registration response")?; - buffer.truncate(count); - let text = std::str::from_utf8(&buffer).context("I2C registration response was not UTF-8")?; - ron::from_str(text).context("failed to decode I2C registration response") -} - -fn eisa_id_from_integer(integer: u64) -> String { - let vendor = integer & 0xFFFF; - let device = (integer >> 16) & 0xFFFF; - let vendor_rev = ((vendor & 0xFF) << 8) | (vendor >> 8); - let vendor_1 = (((vendor_rev >> 10) & 0x1F) as u8 + 64) as char; - let vendor_2 = (((vendor_rev >> 5) & 0x1F) as u8 + 64) as char; - let vendor_3 = (((vendor_rev >> 0) & 0x1F) as u8 + 64) as char; - let device_1 = (device >> 4) & 0xF; - let device_2 = (device >> 0) & 0xF; - let device_3 = (device >> 12) & 0xF; - let device_4 = (device >> 8) & 0xF; - - format!( - "{vendor_1}{vendor_2}{vendor_3}{device_1:01X}{device_2:01X}{device_3:01X}{device_4:01X}" - ) -} diff --git a/recipes/core/base/drivers/initfs.toml b/recipes/core/base/drivers/initfs.toml deleted file mode 100644 index 12290f9b38..0000000000 --- a/recipes/core/base/drivers/initfs.toml +++ /dev/null @@ -1,37 +0,0 @@ -## Drivers for InitFS ## - -# ahcid -[[drivers]] -name = "AHCI storage" -class = 1 -subclass = 6 -command = ["/scheme/initfs/lib/drivers/ahcid"] - -# ided -[[drivers]] -name = "IDE storage" -class = 1 -subclass = 1 -command = ["/scheme/initfs/lib/drivers/ided"] - -# nvmed -[[drivers]] -name = "NVME storage" -class = 1 -subclass = 8 -command = ["/scheme/initfs/lib/drivers/nvmed"] - -[[drivers]] -name = "virtio-blk" -class = 1 -subclass = 0 -vendor = 0x1AF4 -device = 0x1001 -command = ["/scheme/initfs/lib/drivers/virtio-blkd"] - -[[drivers]] -name = "virtio-gpu" -class = 3 -vendor = 0x1AF4 -device = 0x1050 -command = ["/scheme/initfs/lib/drivers/virtio-gpud"] diff --git a/recipes/core/base/drivers/input/i2c-hidd/Cargo.toml b/recipes/core/base/drivers/input/i2c-hidd/Cargo.toml deleted file mode 100644 index db7b3f03ba..0000000000 --- a/recipes/core/base/drivers/input/i2c-hidd/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "i2c-hidd" -description = "I2C HID client daemon" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow.workspace = true -log.workspace = true -orbclient.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -libredox.workspace = true -redox-scheme.workspace = true -ron.workspace = true -serde.workspace = true - -acpi-resource = { path = "../../acpi-resource" } -amlserde = { path = "../../amlserde" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -i2c-interface = { path = "../../i2c/i2c-interface" } -inputd = { path = "../../inputd" } -scheme-utils = { path = "../../../scheme-utils" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/input/i2c-hidd/src/acpi.rs b/recipes/core/base/drivers/input/i2c-hidd/src/acpi.rs deleted file mode 100644 index 1132154cf1..0000000000 --- a/recipes/core/base/drivers/input/i2c-hidd/src/acpi.rs +++ /dev/null @@ -1,307 +0,0 @@ -use acpi_resource::{GpioDescriptor, ResourceDescriptor}; -use amlserde::{AmlSerde, AmlSerdeValue}; -use anyhow::{anyhow, bail, Context, Result}; -use libredox::flag::{O_CLOEXEC, O_RDWR}; -use std::collections::BTreeSet; -use std::fs::{self, OpenOptions}; -use std::io::{ErrorKind, Read}; - -use crate::quirks::ProbeFailureQuirk; - -const I2C_HID_DSM_GUID: [u8; 16] = [ - 0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45, 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x41, 0x76, -]; - -#[derive(Clone, Debug)] -pub struct I2cBinding { - pub adapter: String, - pub address: u16, -} - -#[derive(Clone, Debug)] -pub struct AcpiDeviceResources { - pub i2c: I2cBinding, - pub irq: Option, - pub gpio_int: Vec, - pub gpio_io: Vec, -} - -pub fn scan_acpi_i2c_hid_devices() -> Result> { - let entries = match fs::read_dir("/scheme/acpi/symbols") { - Ok(entries) => entries, - Err(err) if err.kind() == ErrorKind::WouldBlock || err.raw_os_error() == Some(11) => { - return Ok(Vec::new()); - } - Err(err) => return Err(err).context("failed to read /scheme/acpi/symbols"), - }; - - let mut devices = BTreeSet::new(); - for entry in entries { - let entry = entry.context("failed to enumerate ACPI symbol entry")?; - let Some(file_name) = entry.file_name().to_str().map(str::to_owned) else { - continue; - }; - if !file_name.ends_with("._HID") && !file_name.ends_with("._CID") { - continue; - } - - let symbol = read_aml_symbol(&file_name) - .with_context(|| format!("failed to read ACPI symbol {file_name}"))?; - let Some(id) = decode_hardware_id(&symbol.value) else { - continue; - }; - - if matches!(id.as_str(), "PNP0C50" | "ACPI0C50") { - let device = symbol - .name - .strip_suffix("._HID") - .or_else(|| symbol.name.strip_suffix("._CID")) - .unwrap_or(&symbol.name) - .trim_start_matches('\\') - .trim_matches('/') - .replace('/', "."); - if !device.is_empty() { - devices.insert(device); - } - } - } - - Ok(devices.into_iter().collect()) -} - -pub fn read_decoded_resources(path: &str) -> Result { - let resource_path = format!("/scheme/acpi/resources/{}", normalize_device_path(path)); - let serialized = fs::read_to_string(&resource_path) - .with_context(|| format!("failed to read {resource_path}"))?; - let descriptors: Vec = ron::from_str(&serialized) - .with_context(|| format!("invalid ACPI resources in {resource_path}"))?; - - let mut i2c = None; - let mut irq = None; - let mut gpio_int = Vec::new(); - let mut gpio_io = Vec::new(); - - for descriptor in descriptors { - match descriptor { - ResourceDescriptor::I2cSerialBus(bus) => { - if i2c.is_none() { - let adapter = bus - .resource_source - .as_ref() - .map(|source| source.source.clone()) - .filter(|source| !source.is_empty()) - .unwrap_or_else(|| "ACPI-I2C".to_string()); - i2c = Some(I2cBinding { - adapter, - address: bus.slave_address, - }); - } - } - ResourceDescriptor::Irq(descriptor) => { - if irq.is_none() { - irq = descriptor.interrupts.first().copied().map(u32::from); - } - } - ResourceDescriptor::ExtendedIrq(descriptor) => { - if irq.is_none() { - irq = descriptor.interrupts.first().copied(); - } - } - ResourceDescriptor::GpioInt(descriptor) => gpio_int.push(descriptor), - ResourceDescriptor::GpioIo(descriptor) => gpio_io.push(descriptor), - _ => {} - } - } - - let mut resources = AcpiDeviceResources { - i2c: i2c.ok_or_else(|| anyhow!("no I2cSerialBus resource in _CRS"))?, - irq, - gpio_int, - gpio_io, - }; - - if let Some(override_address) = companion_icrs_override(path)? { - log::info!( - "{}: applying THC companion ICRS override {:04x} -> {:04x}", - path, - resources.i2c.address, - override_address - ); - resources.i2c.address = override_address; - } - - Ok(resources) -} - -pub fn prepare_acpi_device(path: &str) -> Result<()> { - let sta = evaluate_integer_method(path, "_STA").ok(); - if let Some(sta) = sta { - if sta & 0x01 == 0 { - bail!("ACPI device is not present according to _STA={sta:#x}"); - } - } - - let _ = evaluate_method(path, "_PS0", &[]); - let _ = evaluate_method(path, "_INI", &[]); - Ok(()) -} - -pub fn recover_acpi_device( - path: &str, - resources: &AcpiDeviceResources, - quirk: Option<&ProbeFailureQuirk>, -) -> Result<()> { - let _ = evaluate_method(path, "_PS3", &[]); - - if let Some(quirk) = quirk { - if !resources.gpio_io.is_empty() { - log::warn!( - "{}: applying GPIO probe-failure recovery quirk {} vendor={:?} product={:?} board={:?} across {} GPIO IO resources", - path, - quirk.name, - quirk.system_vendor, - quirk.product_name, - quirk.board_name, - resources.gpio_io.len() - ); - } else { - log::warn!( - "{}: quirk {} vendor={:?} product={:?} board={:?} matched but no GPIO IO resource was exposed", - path, - quirk.name - , - quirk.system_vendor, - quirk.product_name, - quirk.board_name - ); - } - } - - let _ = evaluate_method(path, "_PS0", &[]); - let _ = evaluate_method(path, "_INI", &[]); - Ok(()) -} - -pub fn hid_descriptor_address(path: &str) -> Result { - let args = [ - AmlSerdeValue::Buffer(I2C_HID_DSM_GUID.to_vec()), - AmlSerdeValue::Integer(1), - AmlSerdeValue::Integer(1), - AmlSerdeValue::Package { - contents: Vec::new(), - }, - ]; - - match evaluate_method(path, "_DSM", &args) { - Ok(AmlSerdeValue::Integer(value)) => { - return u16::try_from(value).context("_DSM descriptor address out of range") - } - Ok(other) => log::warn!( - "{}._DSM returned unexpected value {:?}; retrying fallback index", - path, - other - ), - Err(err) => log::warn!( - "{}._DSM function 1 failed: {err}; retrying function 0", - path - ), - } - - let fallback = [ - AmlSerdeValue::Buffer(I2C_HID_DSM_GUID.to_vec()), - AmlSerdeValue::Integer(1), - AmlSerdeValue::Integer(0), - AmlSerdeValue::Package { - contents: Vec::new(), - }, - ]; - - match evaluate_method(path, "_DSM", &fallback)? { - AmlSerdeValue::Integer(value) => { - u16::try_from(value).context("fallback _DSM descriptor address out of range") - } - other => bail!("fallback _DSM returned unexpected value {other:?}"), - } -} - -fn companion_icrs_override(path: &str) -> Result> { - let value = match evaluate_integer_method(path, "ICRS") { - Ok(value) => value, - Err(_) => return Ok(None), - }; - Ok(Some( - u16::try_from(value).context("ICRS override out of range")?, - )) -} - -pub fn evaluate_integer_method(path: &str, method: &str) -> Result { - match evaluate_method(path, method, &[])? { - AmlSerdeValue::Integer(value) => Ok(value), - other => bail!( - "{}.{} returned non-integer AML value {other:?}", - path, - method - ), - } -} - -pub fn evaluate_method(path: &str, method: &str, args: &[AmlSerdeValue]) -> Result { - let symbol_name = format!("{}.{}", normalize_device_path(path), method); - let symbol_path = format!("/scheme/acpi/symbols/{symbol_name}"); - let fd = libredox::Fd::open(&symbol_path, O_RDWR | O_CLOEXEC, 0) - .with_context(|| format!("failed to open {symbol_path} for ACPI evaluation"))?; - - let serialized = ron::to_string(args) - .with_context(|| format!("failed to serialize ACPI arguments for {symbol_name}"))?; - let mut payload = serialized.into_bytes(); - payload.resize(payload.len() + 4096, 0); - - let used = libredox::call::call_ro(fd.raw(), &mut payload, syscall::CallFlags::empty(), &[]) - .with_context(|| format!("ACPI evaluation failed for {symbol_name}"))?; - let response = std::str::from_utf8(&payload[..used]) - .with_context(|| format!("invalid UTF-8 ACPI response for {symbol_name}"))?; - ron::from_str(response) - .with_context(|| format!("failed to decode ACPI response for {symbol_name}")) -} - -fn read_aml_symbol(file_name: &str) -> Result { - let path = format!("/scheme/acpi/symbols/{file_name}"); - let mut file = OpenOptions::new() - .read(true) - .open(&path) - .with_context(|| format!("failed to open {path}"))?; - let mut ron_text = String::new(); - file.read_to_string(&mut ron_text) - .with_context(|| format!("failed to read {path}"))?; - ron::from_str(&ron_text).with_context(|| format!("failed to decode {path}")) -} - -fn decode_hardware_id(value: &AmlSerdeValue) -> Option { - match value { - AmlSerdeValue::String(value) => Some(value.clone()), - AmlSerdeValue::Integer(integer) => { - let vendor = integer & 0xFFFF; - let device = (integer >> 16) & 0xFFFF; - let vendor_rev = ((vendor & 0xFF) << 8) | (vendor >> 8); - let vendor_1 = (((vendor_rev >> 10) & 0x1f) as u8 + 64) as char; - let vendor_2 = (((vendor_rev >> 5) & 0x1f) as u8 + 64) as char; - let vendor_3 = (((vendor_rev >> 0) & 0x1f) as u8 + 64) as char; - let device_1 = (device >> 4) & 0xF; - let device_2 = (device >> 0) & 0xF; - let device_3 = (device >> 12) & 0xF; - let device_4 = (device >> 8) & 0xF; - - Some(format!( - "{}{}{}{:01X}{:01X}{:01X}{:01X}", - vendor_1, vendor_2, vendor_3, device_1, device_2, device_3, device_4 - )) - } - _ => None, - } -} - -pub fn normalize_device_path(path: &str) -> String { - path.trim_start_matches('\\') - .trim_matches('/') - .replace('/', ".") -} diff --git a/recipes/core/base/drivers/input/i2c-hidd/src/hid.rs b/recipes/core/base/drivers/input/i2c-hidd/src/hid.rs deleted file mode 100644 index dd18e36c58..0000000000 --- a/recipes/core/base/drivers/input/i2c-hidd/src/hid.rs +++ /dev/null @@ -1,195 +0,0 @@ -use std::fs::OpenOptions; -use std::io::{Read, Write}; - -use anyhow::{bail, Context, Result}; -use i2c_interface::{I2cTransferRequest, I2cTransferResponse, I2cTransferSegment}; -use serde::{Deserialize, Serialize}; - -use crate::acpi::I2cBinding; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct HidDescriptor { - pub hid_desc_length: u16, - pub bcd_version: u16, - pub report_desc_length: u16, - pub report_desc_register: u16, - pub input_register: u16, - pub max_input_length: u16, - pub output_register: u16, - pub max_output_length: u16, - pub command_register: u16, - pub data_register: u16, -} - -#[derive(Clone, Debug, Default)] -pub struct ReportDescriptorSummary { - pub has_keyboard_page: bool, - pub has_pointer_page: bool, - pub report_ids: bool, -} - -#[derive(Clone, Debug)] -pub struct I2cAdapterClient { - binding: I2cBinding, -} - -impl I2cAdapterClient { - pub fn new(binding: I2cBinding) -> Self { - Self { binding } - } - pub fn transfer(&self, segments: Vec) -> Result { - let request = I2cTransferRequest { - adapter: self.binding.adapter.clone(), - segments, - stop: true, - }; - - let serialized = ron::to_string(&request).context("failed to serialize I2C request")?; - let mut handle = OpenOptions::new() - .read(true) - .write(true) - .open("/scheme/i2c/transfer") - .context("failed to open /scheme/i2c/transfer")?; - handle - .write_all(serialized.as_bytes()) - .context("failed to write I2C transfer request")?; - - let mut response = String::new(); - handle - .read_to_string(&mut response) - .context("failed to read I2C transfer response")?; - - let transfer: I2cTransferResponse = - ron::from_str(&response).context("failed to decode I2C transfer response")?; - if !transfer.ok { - bail!( - "I2C transfer failed: {}", - transfer - .error - .unwrap_or_else(|| "unspecified transfer error".to_string()) - ); - } - Ok(transfer) - } - - pub fn write_read(&self, address: u16, write_data: &[u8], read_len: usize) -> Result> { - let response = self.transfer(vec![ - I2cTransferSegment::write(address, write_data.to_vec()), - I2cTransferSegment::read(address, read_len), - ])?; - - response - .read_data - .last() - .cloned() - .ok_or_else(|| anyhow::anyhow!("I2C transfer returned no readable segment payload")) - } -} - -pub fn fetch_hid_descriptor( - adapter: &I2cAdapterClient, - address: u16, - hid_desc_addr: u16, -) -> Result { - let prefix = adapter - .write_read(address, &hid_desc_addr.to_le_bytes(), 2) - .context("failed to read HID descriptor length prefix")?; - if prefix.len() < 2 { - bail!("short HID descriptor prefix: {} bytes", prefix.len()); - } - - let hid_desc_length = u16::from_le_bytes([prefix[0], prefix[1]]); - if hid_desc_length < 18 { - bail!("invalid HID descriptor length {hid_desc_length}"); - } - - let raw = adapter - .write_read( - address, - &hid_desc_addr.to_le_bytes(), - usize::from(hid_desc_length), - ) - .context("failed to read full HID descriptor")?; - parse_hid_descriptor(&raw) -} - -pub fn fetch_report_descriptor( - adapter: &I2cAdapterClient, - address: u16, - desc: &HidDescriptor, -) -> Result> { - adapter - .write_read( - address, - &desc.report_desc_register.to_le_bytes(), - usize::from(desc.report_desc_length), - ) - .context("failed to read HID report descriptor") -} - -pub fn stream_input_reports( - adapter: &I2cAdapterClient, - address: u16, - desc: &HidDescriptor, - report_desc: &[u8], - sink: &mut crate::input::InputForwarder, -) -> Result<()> { - let summary = summarize_report_descriptor(report_desc); - let input_len = usize::from(desc.max_input_length.max(4)); - - loop { - let report = adapter - .write_read(address, &desc.input_register.to_le_bytes(), input_len) - .context("failed to fetch I2C HID input report")?; - sink.forward_report(&summary, &report)?; - } -} - -fn parse_hid_descriptor(bytes: &[u8]) -> Result { - if bytes.len() < 18 { - bail!("short HID descriptor: {} bytes", bytes.len()); - } - - Ok(HidDescriptor { - hid_desc_length: le16(bytes, 0)?, - bcd_version: le16(bytes, 2)?, - report_desc_length: le16(bytes, 4)?, - report_desc_register: le16(bytes, 6)?, - input_register: le16(bytes, 8)?, - max_input_length: le16(bytes, 10)?, - output_register: le16(bytes, 12)?, - max_output_length: le16(bytes, 14)?, - command_register: le16(bytes, 16)?, - data_register: if bytes.len() >= 20 { - le16(bytes, 18)? - } else { - 0 - }, - }) -} - -fn summarize_report_descriptor(report_desc: &[u8]) -> ReportDescriptorSummary { - let mut summary = ReportDescriptorSummary::default(); - - for window in report_desc.windows(2) { - match window { - [0x05, 0x01] => summary.has_pointer_page = true, - [0x05, 0x07] => summary.has_keyboard_page = true, - [0x85, _] => summary.report_ids = true, - _ => {} - } - } - - if !summary.has_keyboard_page && !summary.has_pointer_page { - summary.has_pointer_page = true; - } - - summary -} - -fn le16(bytes: &[u8], offset: usize) -> Result { - let slice = bytes - .get(offset..offset + 2) - .ok_or_else(|| anyhow::anyhow!("short LE16 field at offset {offset}"))?; - Ok(u16::from_le_bytes([slice[0], slice[1]])) -} diff --git a/recipes/core/base/drivers/input/i2c-hidd/src/input.rs b/recipes/core/base/drivers/input/i2c-hidd/src/input.rs deleted file mode 100644 index 432a0782f6..0000000000 --- a/recipes/core/base/drivers/input/i2c-hidd/src/input.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::collections::BTreeSet; - -use anyhow::Result; -use inputd::ProducerHandle; -use orbclient::{ - ButtonEvent, KeyEvent, MouseRelativeEvent, ScrollEvent, K_ALT, K_ALT_GR, K_BKSP, K_BRACE_CLOSE, - K_BRACE_OPEN, K_CAPS, K_COMMA, K_ENTER, K_EQUALS, K_ESC, K_LEFT_CTRL, K_LEFT_SHIFT, - K_LEFT_SUPER, K_MINUS, K_PERIOD, K_QUOTE, K_RIGHT_CTRL, K_RIGHT_SHIFT, K_RIGHT_SUPER, - K_SEMICOLON, K_SLASH, K_SPACE, K_TAB, K_TICK, -}; - -use crate::hid::ReportDescriptorSummary; - -pub struct InputForwarder { - producer: ProducerHandle, - keyboard_state: BTreeSet, - last_buttons: u8, -} - -impl InputForwarder { - pub fn new() -> Result { - Ok(Self { - producer: ProducerHandle::new()?, - keyboard_state: BTreeSet::new(), - last_buttons: 0, - }) - } - - pub fn forward_report( - &mut self, - summary: &ReportDescriptorSummary, - report: &[u8], - ) -> Result<()> { - if report.is_empty() { - return Ok(()); - } - - if summary.has_keyboard_page && report.len() >= 8 { - self.forward_boot_keyboard(report)?; - return Ok(()); - } - - if summary.has_pointer_page && report.len() >= 3 { - self.forward_boot_pointer(report)?; - return Ok(()); - } - - Ok(()) - } - - fn forward_boot_keyboard(&mut self, report: &[u8]) -> Result<()> { - let modifiers = report[0]; - for (bit, scancode) in [ - (0_u8, K_LEFT_CTRL), - (1, K_LEFT_SHIFT), - (2, K_ALT), - (3, K_LEFT_SUPER), - (4, K_RIGHT_CTRL), - (5, K_RIGHT_SHIFT), - (6, K_ALT_GR), - (7, K_RIGHT_SUPER), - ] { - self.producer.write_event( - KeyEvent { - character: '\0', - scancode, - pressed: modifiers & (1 << bit) != 0, - } - .to_event(), - )?; - } - - let current = report[2..8] - .iter() - .copied() - .filter(|code| *code != 0) - .collect::>(); - - for code in current.difference(&self.keyboard_state) { - if let Some(scancode) = map_boot_keyboard_usage(*code) { - self.producer.write_event( - KeyEvent { - character: '\0', - scancode, - pressed: true, - } - .to_event(), - )?; - } - } - for code in self.keyboard_state.difference(¤t) { - if let Some(scancode) = map_boot_keyboard_usage(*code) { - self.producer.write_event( - KeyEvent { - character: '\0', - scancode, - pressed: false, - } - .to_event(), - )?; - } - } - - self.keyboard_state = current; - Ok(()) - } - - fn forward_boot_pointer(&mut self, report: &[u8]) -> Result<()> { - let dx = i8::from_ne_bytes([report[1]]) as i32; - let dy = i8::from_ne_bytes([report[2]]) as i32; - if dx != 0 || dy != 0 { - self.producer - .write_event(MouseRelativeEvent { dx, dy }.to_event())?; - } - - if let Some(scroll) = report.get(3).copied() { - let scroll = i8::from_ne_bytes([scroll]) as i32; - if scroll != 0 { - self.producer - .write_event(ScrollEvent { x: 0, y: scroll }.to_event())?; - } - } - - let buttons = report[0] & 0x07; - for index in 0..3 { - let mask = 1 << index; - if (buttons & mask) != (self.last_buttons & mask) { - self.producer.write_event( - ButtonEvent { - left: buttons & 0x01 != 0, - middle: buttons & 0x04 != 0, - right: buttons & 0x02 != 0, - } - .to_event(), - )?; - break; - } - } - self.last_buttons = buttons; - Ok(()) - } -} - -fn map_boot_keyboard_usage(usage: u8) -> Option { - Some(match usage { - 0x04..=0x1D => b'a' + (usage - 0x04), - 0x1E => b'1', - 0x1F => b'2', - 0x20 => b'3', - 0x21 => b'4', - 0x22 => b'5', - 0x23 => b'6', - 0x24 => b'7', - 0x25 => b'8', - 0x26 => b'9', - 0x27 => b'0', - 0x28 => K_ENTER, - 0x29 => K_ESC, - 0x2A => K_BKSP, - 0x2B => K_TAB, - 0x2C => K_SPACE, - 0x2D => K_MINUS, - 0x2E => K_EQUALS, - 0x2F => K_BRACE_OPEN, - 0x30 => K_BRACE_CLOSE, - 0x33 => K_SEMICOLON, - 0x34 => K_QUOTE, - 0x35 => K_TICK, - 0x36 => K_COMMA, - 0x37 => K_PERIOD, - 0x38 => K_SLASH, - 0x39 => K_CAPS, - _ => return None, - }) -} diff --git a/recipes/core/base/drivers/input/i2c-hidd/src/main.rs b/recipes/core/base/drivers/input/i2c-hidd/src/main.rs deleted file mode 100644 index 88270e37b8..0000000000 --- a/recipes/core/base/drivers/input/i2c-hidd/src/main.rs +++ /dev/null @@ -1,114 +0,0 @@ -use std::process; -use std::thread; -use std::time::Duration; - -use anyhow::{Context, Result}; - -mod acpi; -mod hid; -mod input; -mod quirks; - -use acpi::{ - hid_descriptor_address, prepare_acpi_device, read_decoded_resources, recover_acpi_device, - scan_acpi_i2c_hid_devices, -}; -use hid::{fetch_hid_descriptor, fetch_report_descriptor, stream_input_reports, I2cAdapterClient}; -use input::InputForwarder; -use quirks::match_probe_failure_quirk; - -fn main() { - daemon::Daemon::new(daemon); -} - -fn daemon(daemon: daemon::Daemon) -> ! { - common::setup_logging( - "input", - "i2c-hid", - "i2c-hidd", - common::output_level(), - common::file_level(), - ); - - if let Err(err) = run(daemon) { - log::error!("RB_I2C_HIDD_BLOCKER stage=startup error={err:#}"); - process::exit(1); - } - - process::exit(0); -} - -fn run(daemon: daemon::Daemon) -> Result<()> { - log::info!("RB_I2C_HIDD_SCHEMA version=1"); - - let devices = scan_acpi_i2c_hid_devices().context("failed to scan ACPI I2C HID devices")?; - if devices.is_empty() { - log::warn!("RB_I2C_HIDD_BLOCKER stage=scan error=no PNP0C50/ACPI0C50 devices found"); - } - - let mut workers = Vec::new(); - for device in devices { - log::info!("RB_I2C_HIDD_SNAPSHOT device={device}"); - workers.push(thread::spawn(move || { - if let Err(err) = bind_device(&device) { - log::error!("RB_I2C_HIDD_BLOCKER device={} error={:#}", device, err); - } - })); - } - - daemon.ready(); - - if workers.is_empty() { - loop { - thread::sleep(Duration::from_secs(5)); - } - } - - for worker in workers { - let _ = worker.join(); - } - Ok(()) -} - -pub fn bind_device(device_path: &str) -> Result<()> { - prepare_acpi_device(device_path) - .with_context(|| format!("failed to prepare ACPI device {device_path}"))?; - - let resources = read_decoded_resources(device_path) - .with_context(|| format!("failed to decode _CRS for {device_path}"))?; - log::info!( - "RB_I2C_HIDD_SNAPSHOT device={} adapter={} addr={:04x} irq={:?} gpio_int={} gpio_io={}", - device_path, - resources.i2c.adapter, - resources.i2c.address, - resources.irq, - resources.gpio_int.len(), - resources.gpio_io.len() - ); - - let hid_desc_addr = hid_descriptor_address(device_path) - .with_context(|| format!("failed to evaluate _DSM for {device_path}"))?; - let adapter = I2cAdapterClient::new(resources.i2c.clone()); - let hid_desc = fetch_hid_descriptor(&adapter, resources.i2c.address, hid_desc_addr) - .with_context(|| format!("failed to fetch HID descriptor for {device_path}"))?; - let report_desc = fetch_report_descriptor(&adapter, resources.i2c.address, &hid_desc) - .with_context(|| format!("failed to fetch report descriptor for {device_path}"))?; - let mut forwarder = InputForwarder::new().context("failed to connect to inputd producer")?; - - match stream_input_reports( - &adapter, - resources.i2c.address, - &hid_desc, - &report_desc, - &mut forwarder, - ) { - Ok(()) => Ok(()), - Err(err) => { - let quirk = - match_probe_failure_quirk().context("failed to evaluate DMI recovery quirks")?; - recover_acpi_device(device_path, &resources, quirk.as_ref()) - .with_context(|| format!("failed ACPI recovery for {device_path}"))?; - Err(err).with_context(|| format!("streaming input reports failed for {device_path}")) - } - } -} diff --git a/recipes/core/base/drivers/input/i2c-hidd/src/quirks.rs b/recipes/core/base/drivers/input/i2c-hidd/src/quirks.rs deleted file mode 100644 index 450cb19b1b..0000000000 --- a/recipes/core/base/drivers/input/i2c-hidd/src/quirks.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::fs; - -use anyhow::{Context, Result}; -use serde::Deserialize; - -#[derive(Clone, Debug)] -pub struct ProbeFailureQuirk { - pub name: String, - pub system_vendor: Option, - pub product_name: Option, - pub board_name: Option, -} - -#[derive(Clone, Debug, Default, Deserialize)] -struct ProbeFailureQuirkFile { - quirks: Vec, -} - -#[derive(Clone, Debug, Deserialize)] -struct ProbeFailureQuirkEntry { - name: String, - system_vendor: Option, - product_name: Option, - board_name: Option, -} - -#[derive(Default)] -struct DmiSnapshot { - system_vendor: String, - product_name: String, - board_name: String, -} - -pub fn match_probe_failure_quirk() -> Result> { - let snapshot = read_dmi_snapshot()?; - for entry in load_quirks()? { - if field_matches(&entry.system_vendor, &snapshot.system_vendor) - && field_matches(&entry.product_name, &snapshot.product_name) - && field_matches(&entry.board_name, &snapshot.board_name) - { - return Ok(Some(ProbeFailureQuirk { - name: entry.name, - system_vendor: entry.system_vendor, - product_name: entry.product_name, - board_name: entry.board_name, - })); - } - } - - Ok(None) -} - -fn load_quirks() -> Result> { - let path = "/etc/i2c-hidd-quirks.ron"; - let text = match fs::read_to_string(path) { - Ok(text) => text, - Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(Vec::new()), - Err(err) => return Err(err).with_context(|| format!("failed to read {path}")), - }; - - let file: ProbeFailureQuirkFile = - ron::from_str(&text).with_context(|| format!("failed to decode {path}"))?; - Ok(file.quirks) -} - -fn read_dmi_snapshot() -> Result { - Ok(DmiSnapshot { - system_vendor: read_dmi_field("system_vendor")?, - product_name: read_dmi_field("product_name")?, - board_name: read_dmi_field("board_name")?, - }) -} - -fn read_dmi_field(field: &str) -> Result { - let path = format!("/scheme/acpi/dmi/{field}"); - match fs::read_to_string(&path) { - Ok(value) => Ok(value.trim().to_string()), - Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(String::new()), - Err(err) => Err(err).with_context(|| format!("failed to read {path}")), - } -} - -fn field_matches(expected: &Option, actual: &str) -> bool { - expected - .as_deref() - .map(|expected| actual.eq_ignore_ascii_case(expected)) - .unwrap_or(true) -} diff --git a/recipes/core/base/drivers/input/intel-thc-hidd/Cargo.toml b/recipes/core/base/drivers/input/intel-thc-hidd/Cargo.toml deleted file mode 100644 index f6aa224832..0000000000 --- a/recipes/core/base/drivers/input/intel-thc-hidd/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "intel-thc-hidd" -description = "Intel THC QuickI2C HID transport daemon" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow.workspace = true -log.workspace = true -pci_types = "0.10.1" -redox_syscall = { workspace = true, features = ["std"] } -libredox.workspace = true -redox-scheme.workspace = true -ron.workspace = true -serde.workspace = true - -acpi-resource = { path = "../../acpi-resource" } -amlserde = { path = "../../amlserde" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -i2c-interface = { path = "../../i2c/i2c-interface" } -pcid = { path = "../../pcid" } -scheme-utils = { path = "../../../scheme-utils" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/input/intel-thc-hidd/src/main.rs b/recipes/core/base/drivers/input/intel-thc-hidd/src/main.rs deleted file mode 100644 index 423977e05d..0000000000 --- a/recipes/core/base/drivers/input/intel-thc-hidd/src/main.rs +++ /dev/null @@ -1,260 +0,0 @@ -use std::collections::BTreeSet; -use std::fs::{self, OpenOptions}; -use std::io::Read; -use std::process; -use std::thread; -use std::time::Duration; - -use acpi_resource::ResourceDescriptor; -use amlserde::{AmlSerde, AmlSerdeValue}; -use anyhow::{bail, Context, Result}; -use libredox::flag::{O_CLOEXEC, O_RDWR}; -use pcid_interface::PciFunctionHandle; - -mod quicki2c; -mod thc; - -use quicki2c::QuickI2cTransport; -use thc::{ThcController, SUPPORTED_PCI_IDS}; - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - common::setup_logging( - "input", - "intel-thc", - "intel-thc-hidd", - common::output_level(), - common::file_level(), - ); - - if let Err(err) = run(daemon, &mut pcid_handle) { - log::error!("RB_THC_HIDD_FATAL error={err:#}"); - process::exit(1); - } - - process::exit(0); -} - -fn run(daemon: daemon::Daemon, pcid_handle: &mut PciFunctionHandle) -> Result<()> { - log::info!("RB_THC_HIDD_SCHEMA version=1"); - - let pci_config = pcid_handle.config(); - let id = ( - pci_config.func.full_device_id.vendor_id, - pci_config.func.full_device_id.device_id, - ); - if !SUPPORTED_PCI_IDS.contains(&id) { - bail!("unsupported Intel THC PCI device {:04x}:{:04x}", id.0, id.1); - } - - pcid_handle.enable_device(); - let bar = unsafe { pcid_handle.map_bar(0) }; - let controller = ThcController::new(bar.ptr.as_ptr(), bar.bar_size) - .context("failed to create THC controller")?; - - let companion = resolve_acpi_companion(&pci_config.func.addr) - .context("failed to resolve ACPI companion for THC device")?; - let override_address = companion - .as_deref() - .map(companion_slave_address_override) - .transpose() - .context("failed to evaluate THC slave-address override")? - .flatten(); - let hid_devices = scan_bound_i2c_hid_devices(companion.as_deref()) - .context("failed to scan PNP0C50 devices for THC controller")?; - - let effective_address = override_address.unwrap_or(0x0015); - let transport = QuickI2cTransport::new(controller, effective_address); - transport.prime_controller(); - transport.emulate_transfer(&[]); - log::debug!("RB_THC_HIDD status={:#x}", transport.status()); - - match transport.register_with_i2cd(companion.as_deref(), override_address) { - Ok(()) => {} - Err(err) => { - log::warn!("RB_THC_HIDD registration error={err:#}"); - } - } - - log::info!( - "RB_THC_HIDD pci={} companion={:?} override={:?} hid_devices={}", - pci_config.func.name(), - companion, - override_address, - hid_devices.len() - ); - - daemon.ready(); - - loop { - thread::sleep(Duration::from_secs(5)); - } -} - -fn resolve_acpi_companion(addr: &pci_types::PciAddress) -> Result> { - let entries = - fs::read_dir("/scheme/acpi/symbols").context("failed to read /scheme/acpi/symbols")?; - let expected_adr = (u64::from(addr.device()) << 16) | u64::from(addr.function()); - - for entry in entries { - let entry = entry.context("failed to enumerate ACPI symbol entry")?; - let Some(file_name) = entry.file_name().to_str().map(str::to_owned) else { - continue; - }; - if !file_name.ends_with("._ADR") { - continue; - } - - let symbol = read_aml_symbol(&file_name)?; - if !matches!(symbol.value, AmlSerdeValue::Integer(value) if value == expected_adr) { - continue; - } - - let device = symbol - .name - .strip_suffix("._ADR") - .unwrap_or(&symbol.name) - .trim_start_matches('\\') - .replace('/', "."); - return Ok(Some(device)); - } - - Ok(None) -} - -fn companion_slave_address_override(path: &str) -> Result> { - let icrs = evaluate_integer_method(path, "ICRS").ok(); - let isub = evaluate_integer_method(path, "ISUB").ok(); - Ok(icrs - .or(isub) - .map(|value| u16::try_from(value)) - .transpose() - .context("THC ACPI override out of range")?) -} - -fn scan_bound_i2c_hid_devices(companion: Option<&str>) -> Result> { - let entries = - fs::read_dir("/scheme/acpi/symbols").context("failed to read /scheme/acpi/symbols")?; - let mut devices = BTreeSet::new(); - - for entry in entries { - let entry = entry.context("failed to enumerate ACPI HID entry")?; - let Some(file_name) = entry.file_name().to_str().map(str::to_owned) else { - continue; - }; - if !file_name.ends_with("._HID") && !file_name.ends_with("._CID") { - continue; - } - - let symbol = read_aml_symbol(&file_name)?; - let is_hid = matches!( - decode_hardware_id(&symbol.value).as_deref(), - Some("PNP0C50" | "ACPI0C50") - ); - if !is_hid { - continue; - } - - let device = symbol - .name - .strip_suffix("._HID") - .or_else(|| symbol.name.strip_suffix("._CID")) - .unwrap_or(&symbol.name) - .trim_start_matches('\\') - .replace('/', "."); - if let Some(companion) = companion { - if !is_bound_to_companion(&device, companion)? { - continue; - } - } - devices.insert(device); - } - - Ok(devices.into_iter().collect()) -} - -fn is_bound_to_companion(device: &str, companion: &str) -> Result { - let resource_path = format!("/scheme/acpi/resources/{device}"); - let serialized = match fs::read_to_string(&resource_path) { - Ok(serialized) => serialized, - Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(false), - Err(err) => return Err(err).with_context(|| format!("failed to read {resource_path}")), - }; - - let resources: Vec = - ron::from_str(&serialized).with_context(|| format!("failed to decode {resource_path}"))?; - Ok(resources.into_iter().any(|resource| match resource { - ResourceDescriptor::I2cSerialBus(bus) => bus - .resource_source - .as_ref() - .map(|source| source.source == companion) - .unwrap_or(false), - _ => false, - })) -} - -fn evaluate_integer_method(path: &str, method: &str) -> Result { - let symbol_name = format!("{}.{}", normalize_device_path(path), method); - let symbol_path = format!("/scheme/acpi/symbols/{symbol_name}"); - let fd = libredox::Fd::open(&symbol_path, O_RDWR | O_CLOEXEC, 0) - .with_context(|| format!("failed to open {symbol_path}"))?; - - let mut payload = ron::to_string(&Vec::::new()) - .context("failed to serialize ACPI call arguments")? - .into_bytes(); - payload.resize(payload.len() + 2048, 0); - let used = libredox::call::call_ro(fd.raw(), &mut payload, syscall::CallFlags::empty(), &[]) - .with_context(|| format!("ACPI evaluation failed for {symbol_name}"))?; - let response = std::str::from_utf8(&payload[..used]) - .with_context(|| format!("invalid UTF-8 ACPI response for {symbol_name}"))?; - match ron::from_str::(response) - .with_context(|| format!("failed to decode ACPI response for {symbol_name}"))? - { - AmlSerdeValue::Integer(value) => Ok(value), - other => bail!("{}.{} returned non-integer value {other:?}", path, method), - } -} - -fn read_aml_symbol(file_name: &str) -> Result { - let path = format!("/scheme/acpi/symbols/{file_name}"); - let mut file = OpenOptions::new() - .read(true) - .open(&path) - .with_context(|| format!("failed to open {path}"))?; - let mut ron_text = String::new(); - file.read_to_string(&mut ron_text) - .with_context(|| format!("failed to read {path}"))?; - ron::from_str(&ron_text).with_context(|| format!("failed to decode {path}")) -} - -fn decode_hardware_id(value: &AmlSerdeValue) -> Option { - match value { - AmlSerdeValue::String(value) => Some(value.clone()), - AmlSerdeValue::Integer(integer) => { - let vendor = integer & 0xFFFF; - let device = (integer >> 16) & 0xFFFF; - let vendor_rev = ((vendor & 0xFF) << 8) | (vendor >> 8); - let vendor_1 = (((vendor_rev >> 10) & 0x1f) as u8 + 64) as char; - let vendor_2 = (((vendor_rev >> 5) & 0x1f) as u8 + 64) as char; - let vendor_3 = (((vendor_rev >> 0) & 0x1f) as u8 + 64) as char; - let device_1 = (device >> 4) & 0xF; - let device_2 = (device >> 0) & 0xF; - let device_3 = (device >> 12) & 0xF; - let device_4 = (device >> 8) & 0xF; - Some(format!( - "{}{}{}{:01X}{:01X}{:01X}{:01X}", - vendor_1, vendor_2, vendor_3, device_1, device_2, device_3, device_4 - )) - } - _ => None, - } -} - -fn normalize_device_path(path: &str) -> String { - path.trim_start_matches('\\') - .trim_matches('/') - .replace('/', ".") -} diff --git a/recipes/core/base/drivers/input/intel-thc-hidd/src/quicki2c.rs b/recipes/core/base/drivers/input/intel-thc-hidd/src/quicki2c.rs deleted file mode 100644 index 721f0be3b8..0000000000 --- a/recipes/core/base/drivers/input/intel-thc-hidd/src/quicki2c.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::fs::OpenOptions; -use std::io::Write; - -use anyhow::{Context, Result}; -use i2c_interface::{I2cAdapterRegistration, I2cTransferSegment}; - -use crate::thc::ThcController; - -const QUICKI2C_OPCODE_WRITE: u32 = 0x1; -const QUICKI2C_OPCODE_READ: u32 = 0x2; - -pub struct QuickI2cTransport { - controller: ThcController, - slave_address: u16, -} - -impl QuickI2cTransport { - pub fn new(controller: ThcController, slave_address: u16) -> Self { - Self { - controller, - slave_address, - } - } - - pub fn prime_controller(&self) { - self.controller.initialize_quicki2c_mode(); - } - - pub fn emulate_transfer(&self, segments: &[I2cTransferSegment]) { - for segment in segments { - match &segment.op { - i2c_interface::I2cTransferOp::Write(data) => { - self.controller.program_subip_transaction( - QUICKI2C_OPCODE_WRITE, - segment.address, - data.len(), - ); - for (index, chunk) in data.chunks(4).enumerate() { - let mut word = [0_u8; 4]; - word[..chunk.len()].copy_from_slice(chunk); - self.controller - .write_subip_data(index * 4, u32::from_le_bytes(word)); - } - } - i2c_interface::I2cTransferOp::Read(len) => { - self.controller.program_subip_transaction( - QUICKI2C_OPCODE_READ, - segment.address, - *len, - ); - let _ = self.controller.read_subip_data(0); - } - } - } - } - - pub fn status(&self) -> u32 { - self.controller.status() - } - - pub fn register_with_i2cd( - &self, - acpi_companion: Option<&str>, - override_address: Option, - ) -> Result<()> { - let registration = I2cAdapterRegistration { - name: "intel-thc-quicki2c".to_string(), - description: format!( - "Intel THC QuickI2C adapter for slave {:04x}", - self.slave_address - ), - acpi_companion: acpi_companion.map(str::to_owned), - slave_address_override: override_address, - }; - let payload = - ron::to_string(®istration).context("failed to serialize i2cd registration")?; - - let mut file = OpenOptions::new() - .write(true) - .open("/scheme/i2c/register") - .context("failed to open /scheme/i2c/register")?; - file.write_all(payload.as_bytes()) - .context("failed to write i2cd adapter registration")?; - Ok(()) - } -} diff --git a/recipes/core/base/drivers/input/intel-thc-hidd/src/thc.rs b/recipes/core/base/drivers/input/intel-thc-hidd/src/thc.rs deleted file mode 100644 index e06a6f8a6d..0000000000 --- a/recipes/core/base/drivers/input/intel-thc-hidd/src/thc.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::ptr::NonNull; - -use anyhow::{bail, Result}; - -pub const SUPPORTED_PCI_IDS: &[(u16, u16)] = &[ - (0x8086, 0x7eb8), - (0x8086, 0x7eb9), - (0x8086, 0x7ebd), - (0x8086, 0x7ebe), - (0x8086, 0xa8b8), - (0x8086, 0xa8b9), -]; - -pub const REG_CONTROL: usize = 0x0000; -pub const REG_STATUS: usize = 0x0004; -pub const REG_MODE: usize = 0x0010; -pub const REG_SUBIP_OPCODE: usize = 0x0800; -pub const REG_SUBIP_ADDRESS: usize = 0x0804; -pub const REG_SUBIP_LENGTH: usize = 0x0808; -pub const REG_SUBIP_DOORBELL: usize = 0x080C; -pub const REG_SUBIP_DATA: usize = 0x0810; - -#[derive(Clone, Copy)] -pub struct ThcController { - base: NonNull, - len: usize, -} - -impl ThcController { - pub fn new(base: *mut u8, len: usize) -> Result { - let Some(base) = NonNull::new(base) else { - bail!("THC BAR mapping returned null base pointer"); - }; - Ok(Self { base, len }) - } - - pub fn initialize_quicki2c_mode(&self) { - self.write32(REG_MODE, 0x1); - self.write32(REG_CONTROL, 0x1); - } - - pub fn status(&self) -> u32 { - self.read32(REG_STATUS) - } - - pub fn program_subip_transaction(&self, opcode: u32, address: u16, len: usize) { - self.write32(REG_SUBIP_OPCODE, opcode); - self.write32(REG_SUBIP_ADDRESS, u32::from(address)); - self.write32(REG_SUBIP_LENGTH, len as u32); - self.write32(REG_SUBIP_DOORBELL, 1); - } - - pub fn write_subip_data(&self, offset: usize, value: u32) { - self.write32(REG_SUBIP_DATA + offset, value); - } - - pub fn read_subip_data(&self, offset: usize) -> u32 { - self.read32(REG_SUBIP_DATA + offset) - } - - fn read32(&self, offset: usize) -> u32 { - if offset + 4 > self.len { - return 0; - } - - let ptr = unsafe { self.base.as_ptr().add(offset).cast::() }; - unsafe { ptr.read_volatile() } - } - - fn write32(&self, offset: usize, value: u32) { - if offset + 4 > self.len { - return; - } - - let ptr = unsafe { self.base.as_ptr().add(offset).cast::() }; - unsafe { ptr.write_volatile(value) }; - } -} diff --git a/recipes/core/base/drivers/input/ps2d/.gitignore b/recipes/core/base/drivers/input/ps2d/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/recipes/core/base/drivers/input/ps2d/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/recipes/core/base/drivers/input/ps2d/Cargo.toml b/recipes/core/base/drivers/input/ps2d/Cargo.toml deleted file mode 100644 index fdba06b634..0000000000 --- a/recipes/core/base/drivers/input/ps2d/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "ps2d" -description = "PS/2 driver" -version = "0.1.0" -edition = "2018" - -[dependencies] -bitflags.workspace = true -log.workspace = true -orbclient.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true -redox-scheme.workspace = true -libredox.workspace = true - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -inputd = { path = "../../inputd" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/input/ps2d/src/controller.rs b/recipes/core/base/drivers/input/ps2d/src/controller.rs deleted file mode 100644 index d7af4cba2c..0000000000 --- a/recipes/core/base/drivers/input/ps2d/src/controller.rs +++ /dev/null @@ -1,389 +0,0 @@ -//! PS/2 controller, see: -//! - https://wiki.osdev.org/I8042_PS/2_Controller -//! - http://www.mcamafia.de/pdf/ibm_hitrc07.pdf - -use common::{ - io::{Io, ReadOnly, WriteOnly}, - timeout::Timeout, -}; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use common::io::Pio; - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -use common::io::Mmio; - -use log::{debug, error, info, trace, warn}; - -use std::fmt; - -#[derive(Debug)] -pub enum Error { - CommandRetry, - NoMoreTries, - ReadTimeout, - WriteTimeout, - CommandTimeout(Command), - WriteConfigTimeout(ConfigFlags), - KeyboardCommandFail(KeyboardCommand), - KeyboardCommandDataFail(KeyboardCommandData), -} - -bitflags! { - pub struct StatusFlags: u8 { - const OUTPUT_FULL = 1; - const INPUT_FULL = 1 << 1; - const SYSTEM = 1 << 2; - const COMMAND = 1 << 3; - // Chipset specific - const KEYBOARD_LOCK = 1 << 4; - // Chipset specific - const SECOND_OUTPUT_FULL = 1 << 5; - const TIME_OUT = 1 << 6; - const PARITY = 1 << 7; - } -} - -bitflags! { - #[derive(Clone, Copy, Debug)] - pub struct ConfigFlags: u8 { - const FIRST_INTERRUPT = 1 << 0; - const SECOND_INTERRUPT = 1 << 1; - const POST_PASSED = 1 << 2; - // 1 << 3 should be zero - const CONFIG_RESERVED_3 = 1 << 3; - const FIRST_DISABLED = 1 << 4; - const SECOND_DISABLED = 1 << 5; - const FIRST_TRANSLATE = 1 << 6; - // 1 << 7 should be zero - const CONFIG_RESERVED_7 = 1 << 7; - } -} - -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -#[allow(dead_code)] -enum Command { - ReadConfig = 0x20, - WriteConfig = 0x60, - DisableSecond = 0xA7, - EnableSecond = 0xA8, - TestSecond = 0xA9, - TestController = 0xAA, - TestFirst = 0xAB, - Diagnostic = 0xAC, - DisableFirst = 0xAD, - EnableFirst = 0xAE, - WriteSecond = 0xD4, -} - -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -#[allow(dead_code)] -enum KeyboardCommand { - EnableReporting = 0xF4, - SetDefaultsDisable = 0xF5, - SetDefaults = 0xF6, - Reset = 0xFF, -} - -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -enum KeyboardCommandData { - ScancodeSet = 0xF0, -} - -// Default timeout in microseconds -const DEFAULT_TIMEOUT: u64 = 50_000; -// Reset timeout in microseconds -const RESET_TIMEOUT: u64 = 1_000_000; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub struct Ps2 { - data: Pio, - status: ReadOnly>, - command: WriteOnly>, - //TODO: keep in state instead - pub mouse_resets: usize, -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -pub struct Ps2 { - data: Mmio, - status: ReadOnly>, - command: WriteOnly>, - //TODO: keep in state instead - pub mouse_resets: usize, -} - -impl Ps2 { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub fn new() -> Self { - Ps2 { - data: Pio::new(0x60), - status: ReadOnly::new(Pio::new(0x64)), - command: WriteOnly::new(Pio::new(0x64)), - mouse_resets: 0, - } - } - - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - pub fn new() -> Self { - unimplemented!() - } - - fn status(&mut self) -> StatusFlags { - StatusFlags::from_bits_truncate(self.status.read()) - } - - fn wait_read(&mut self, micros: u64) -> Result<(), Error> { - let timeout = Timeout::from_micros(micros); - loop { - if self.status().contains(StatusFlags::OUTPUT_FULL) { - return Ok(()); - } - timeout.run().map_err(|()| Error::ReadTimeout)? - } - } - - fn wait_write(&mut self, micros: u64) -> Result<(), Error> { - let timeout = Timeout::from_micros(micros); - loop { - if !self.status().contains(StatusFlags::INPUT_FULL) { - return Ok(()); - } - timeout.run().map_err(|()| Error::WriteTimeout)? - } - } - - fn command(&mut self, command: Command) -> Result<(), Error> { - self.wait_write(DEFAULT_TIMEOUT) - .map_err(|_| Error::CommandTimeout(command))?; - self.command.write(command as u8); - Ok(()) - } - - fn read(&mut self) -> Result { - self.read_timeout(DEFAULT_TIMEOUT) - } - - fn read_timeout(&mut self, micros: u64) -> Result { - self.wait_read(micros)?; - let data = self.data.read(); - Ok(data) - } - - fn write(&mut self, data: u8) -> Result<(), Error> { - self.wait_write(DEFAULT_TIMEOUT)?; - self.data.write(data); - Ok(()) - } - - fn retry Result>( - &mut self, - name: fmt::Arguments, - retries: usize, - f: F, - ) -> Result { - trace!("{}", name); - let mut res = Err(Error::NoMoreTries); - for retry in 0..retries { - res = f(self); - match res { - Ok(ok) => { - return Ok(ok); - } - Err(ref err) => { - debug!("{}: retry {}/{}: {:?}", name, retry + 1, retries, err); - } - } - } - res - } - - fn config(&mut self) -> Result { - self.retry(format_args!("read config"), 4, |x| { - x.command(Command::ReadConfig)?; - x.read() - }) - .map(ConfigFlags::from_bits_truncate) - } - - fn set_config(&mut self, config: ConfigFlags) -> Result<(), Error> { - self.retry(format_args!("write config {:?}", config), 4, |x| { - x.command(Command::WriteConfig)?; - x.write(config.bits()) - .map_err(|_| Error::WriteConfigTimeout(config))?; - Ok(0) - })?; - Ok(()) - } - - fn keyboard_command_inner(&mut self, command: u8) -> Result { - self.write(command)?; - match self.read()? { - 0xFE => Err(Error::CommandRetry), - value => Ok(value), - } - } - - fn keyboard_command(&mut self, command: KeyboardCommand) -> Result { - self.retry(format_args!("keyboard command {:?}", command), 4, |x| { - x.keyboard_command_inner(command as u8) - .map_err(|_| Error::KeyboardCommandFail(command)) - }) - } - - fn keyboard_command_data( - &mut self, - command: KeyboardCommandData, - data: u8, - ) -> Result { - self.retry( - format_args!("keyboard command {:?} {:#x}", command, data), - 4, - |x| { - let res = x - .keyboard_command_inner(command as u8) - .map_err(|_| Error::KeyboardCommandDataFail(command))?; - if res != 0xFA { - warn!("keyboard incorrect result of set command: {command:?} {res:02X}"); - return Ok(res); - } - x.write(data)?; - x.read() - }, - ) - } - - pub fn mouse_command_async(&mut self, command: u8) -> Result<(), Error> { - self.command(Command::WriteSecond)?; - self.write(command as u8) - } - - pub fn next(&mut self) -> Option<(bool, u8)> { - let status = self.status(); - if status.contains(StatusFlags::OUTPUT_FULL) { - let data = self.data.read(); - Some((!status.contains(StatusFlags::SECOND_OUTPUT_FULL), data)) - } else { - None - } - } - - pub fn init_keyboard(&mut self) -> Result<(), Error> { - let mut b; - - { - // Enable first device - self.command(Command::EnableFirst)?; - } - - { - // Reset keyboard - b = self.keyboard_command(KeyboardCommand::Reset)?; - if b == 0xFA { - b = self.read().unwrap_or(0); - if b != 0xAA { - error!("keyboard failed self test: {:02X}", b); - } - } else { - error!("keyboard failed to reset: {:02X}", b); - } - } - - { - // Set scancode set to 2 - let scancode_set = 2; - b = self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set)?; - if b != 0xFA { - error!( - "keyboard failed to set scancode set {}: {:02X}", - scancode_set, b - ); - } - } - - Ok(()) - } - - pub fn init(&mut self) -> Result<(), Error> { - { - // Disable devices - self.command(Command::DisableFirst)?; - self.command(Command::DisableSecond)?; - } - - // Disable clocks, disable interrupts, and disable translate - { - // Since the default config may have interrupts enabled, and the kernel may eat up - // our data in that case, we will write a config without reading the current one - let config = ConfigFlags::POST_PASSED - | ConfigFlags::FIRST_DISABLED - | ConfigFlags::SECOND_DISABLED; - self.set_config(config)?; - } - - // The keyboard seems to still collect bytes even when we disable - // the port, so we must disable the keyboard too - self.retry(format_args!("keyboard defaults"), 4, |x| { - // Set defaults and disable scanning - let b = x.keyboard_command(KeyboardCommand::SetDefaultsDisable)?; - if b != 0xFA { - error!("keyboard failed to set defaults: {:02X}", b); - return Err(Error::CommandRetry); - } - - Ok(b) - })?; - - { - // Perform the self test - self.command(Command::TestController)?; - let r = self.read()?; - if r != 0x55 { - warn!("self test unexpected value: {:02X}", r); - } - } - - // Initialize keyboard - if let Err(err) = self.init_keyboard() { - error!("failed to initialize keyboard: {:?}", err); - return Err(err); - } - - // Enable second device - let enable_mouse = match self.command(Command::EnableSecond) { - Ok(()) => true, - Err(err) => { - error!("failed to initialize mouse: {:?}", err); - false - } - }; - - { - // Enable keyboard data reporting - // Use inner function to prevent retries - // Response is ignored since scanning is now on - if let Err(err) = self.keyboard_command_inner(KeyboardCommand::EnableReporting as u8) { - error!("failed to initialize keyboard reporting: {:?}", err); - //TODO: fix by using interrupts? - } - } - - // Enable clocks and interrupts - { - let config = ConfigFlags::POST_PASSED - | ConfigFlags::FIRST_INTERRUPT - | ConfigFlags::FIRST_TRANSLATE - | if enable_mouse { - ConfigFlags::SECOND_INTERRUPT - } else { - ConfigFlags::SECOND_DISABLED - }; - self.set_config(config)?; - } - - Ok(()) - } -} diff --git a/recipes/core/base/drivers/input/ps2d/src/main.rs b/recipes/core/base/drivers/input/ps2d/src/main.rs deleted file mode 100644 index db17de2a62..0000000000 --- a/recipes/core/base/drivers/input/ps2d/src/main.rs +++ /dev/null @@ -1,135 +0,0 @@ -#[macro_use] -extern crate bitflags; -extern crate orbclient; -extern crate syscall; - -use std::fs::OpenOptions; -use std::io::Read; -use std::os::unix::fs::OpenOptionsExt; -use std::os::unix::io::AsRawFd; -use std::process; - -use common::acquire_port_io_rights; -use event::{user_data, EventQueue}; -use inputd::ProducerHandle; - -use crate::state::Ps2d; - -mod controller; -mod mouse; -mod state; -mod vm; - -fn daemon(daemon: daemon::Daemon) -> ! { - common::setup_logging( - "input", - "ps2", - "ps2", - common::output_level(), - common::file_level(), - ); - - acquire_port_io_rights().expect("ps2d: failed to get I/O permission"); - - let input = ProducerHandle::new().expect("ps2d: failed to open input producer"); - - user_data! { - enum Source { - Keyboard, - Mouse, - Time, - } - } - - let event_queue: EventQueue = - EventQueue::new().expect("ps2d: failed to create event queue"); - - let mut key_file = OpenOptions::new() - .read(true) - .write(true) - .custom_flags(syscall::O_NONBLOCK as i32) - .open("/scheme/serio/0") - .expect("ps2d: failed to open /scheme/serio/0"); - - event_queue - .subscribe( - key_file.as_raw_fd() as usize, - Source::Keyboard, - event::EventFlags::READ, - ) - .unwrap(); - - let mut mouse_file = OpenOptions::new() - .read(true) - .write(true) - .custom_flags(syscall::O_NONBLOCK as i32) - .open("/scheme/serio/1") - .expect("ps2d: failed to open /scheme/serio/1"); - - event_queue - .subscribe( - mouse_file.as_raw_fd() as usize, - Source::Mouse, - event::EventFlags::READ, - ) - .unwrap(); - - let time_file = OpenOptions::new() - .read(true) - .write(true) - .custom_flags(syscall::O_NONBLOCK as i32) - .open(format!("/scheme/time/{}", syscall::CLOCK_MONOTONIC)) - .expect("ps2d: failed to open /scheme/time"); - - event_queue - .subscribe( - time_file.as_raw_fd() as usize, - Source::Time, - event::EventFlags::READ, - ) - .unwrap(); - - libredox::call::setrens(0, 0).expect("ps2d: failed to enter null namespace"); - - daemon.ready(); - - let mut ps2d = Ps2d::new(input, time_file); - - let mut data = [0; 256]; - for event in event_queue.map(|e| e.expect("ps2d: failed to get next event").user_data) { - // There are some gotchas with ps/2 controllers that require this weird - // way of doing things. You read key and mouse data from the same - // place. There is a status register that may show you which the data - // came from, but if it is even implemented it can have a race - // condition causing keyboard data to be read as mouse data. - // - // Due to this, we have a kernel driver doing a small amount of work - // to grab bytes and sort them based on the source - - let (file, keyboard) = match event { - Source::Keyboard => (&mut key_file, true), - Source::Mouse => (&mut mouse_file, false), - Source::Time => { - ps2d.time_event(); - continue; - } - }; - - loop { - let count = match file.read(&mut data) { - Ok(0) => break, - Ok(count) => count, - Err(_) => break, - }; - for i in 0..count { - ps2d.handle(keyboard, data[i]); - } - } - } - - process::exit(0); -} - -fn main() { - daemon::Daemon::new(daemon); -} diff --git a/recipes/core/base/drivers/input/ps2d/src/mouse.rs b/recipes/core/base/drivers/input/ps2d/src/mouse.rs deleted file mode 100644 index 9e95ab889b..0000000000 --- a/recipes/core/base/drivers/input/ps2d/src/mouse.rs +++ /dev/null @@ -1,387 +0,0 @@ -use crate::controller::Ps2; -use std::time::Duration; - -pub const RESET_RETRIES: usize = 10; -pub const RESET_TIMEOUT: Duration = Duration::from_millis(1000); -pub const COMMAND_TIMEOUT: Duration = Duration::from_millis(100); - -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -#[allow(dead_code)] -enum MouseCommand { - SetScaling1To1 = 0xE6, - SetScaling2To1 = 0xE7, - StatusRequest = 0xE9, - GetDeviceId = 0xF2, - EnableReporting = 0xF4, - SetDefaultsDisable = 0xF5, - SetDefaults = 0xF6, - Reset = 0xFF, -} - -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -enum MouseCommandData { - SetResolution = 0xE8, - SetSampleRate = 0xF3, -} - -#[derive(Debug)] -struct MouseTx { - write: &'static [u8], - write_i: usize, - read: Vec, - read_bytes: usize, -} - -impl MouseTx { - fn new(write: &'static [u8], read_bytes: usize, ps2: &mut Ps2) -> Result { - let mut this = Self { - write, - write_i: 0, - read: Vec::with_capacity(read_bytes), - read_bytes, - }; - this.try_write(ps2)?; - Ok(this) - } - - fn try_write(&mut self, ps2: &mut Ps2) -> Result<(), ()> { - if let Some(write) = self.write.get(self.write_i) { - if let Err(err) = ps2.mouse_command_async(*write) { - log::error!("failed to write {:02X} to mouse: {:?}", write, err); - return Err(()); - } - } - Ok(()) - } - - fn handle(&mut self, data: u8, ps2: &mut Ps2) -> Result { - if self.write_i < self.write.len() { - if data == 0xFA { - self.write_i += 1; - self.try_write(ps2)?; - } else { - log::error!("unknown mouse response {:02X}", data); - return Err(()); - } - } else { - self.read.push(data); - } - Ok(self.write_i >= self.write.len() && self.read.len() >= self.read_bytes) - } -} - -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -#[allow(dead_code)] -enum MouseId { - /// Mouse sends three bytes - Base = 0x00, - /// Mouse sends fourth byte with scroll - Intellimouse1 = 0x03, - /// Mouse sends fourth byte with scroll, button 4, and button 5 - //TODO: support this mouse type - Intellimouse2 = 0x04, -} - -// From Synaptics TouchPad Interfacing Guide -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -pub enum TouchpadCommand { - Identify = 0x00, -} - -#[derive(Debug)] -pub enum MouseState { - /// No mouse found - None, - /// Ready to initialize mouse - Init, - /// Reset command is sent - Reset, - /// BAT completion code returned - Bat, - /// Identify touchpad - IdentifyTouchpad { tx: MouseTx }, - /// Enable intellimouse features - EnableIntellimouse { tx: MouseTx }, - /// Status request - Status { index: usize }, - /// Device ID update - DeviceId, - /// Enable reporting command sent - EnableReporting { id: u8 }, - /// Mouse is streaming - Streaming { id: u8 }, -} - -#[derive(Debug)] -#[must_use] -pub enum MouseResult { - None, - Packet(u8, bool), - Timeout(Duration), -} - -impl MouseState { - pub fn reset(&mut self, ps2: &mut Ps2) -> MouseResult { - if ps2.mouse_resets < RESET_RETRIES { - ps2.mouse_resets += 1; - } else { - log::error!("tried to reset mouse {} times, giving up", ps2.mouse_resets); - *self = MouseState::None; - return MouseResult::None; - } - match ps2.mouse_command_async(MouseCommand::Reset as u8) { - Ok(()) => { - *self = MouseState::Reset; - MouseResult::Timeout(RESET_TIMEOUT) - } - Err(err) => { - log::error!("failed to send mouse reset command: {:?}", err); - //TODO: retry reset? - *self = MouseState::None; - MouseResult::None - } - } - } - - fn enable_reporting(&mut self, id: u8, ps2: &mut Ps2) -> MouseResult { - match ps2.mouse_command_async(MouseCommand::EnableReporting as u8) { - Ok(()) => { - *self = MouseState::EnableReporting { id }; - MouseResult::Timeout(COMMAND_TIMEOUT) - } - Err(err) => { - log::error!("failed to enable mouse reporting: {:?}", err); - //TODO: reset mouse? - *self = MouseState::None; - MouseResult::None - } - } - } - - fn request_status(&mut self, ps2: &mut Ps2) -> MouseResult { - match ps2.mouse_command_async(MouseCommand::StatusRequest as u8) { - Ok(()) => { - *self = MouseState::Status { index: 0 }; - MouseResult::Timeout(COMMAND_TIMEOUT) - } - Err(err) => { - log::error!("failed to request mouse status: {:?}", err); - //TODO: reset mouse instead? - self.request_id(ps2) - } - } - } - - fn request_id(&mut self, ps2: &mut Ps2) -> MouseResult { - match ps2.mouse_command_async(MouseCommand::GetDeviceId as u8) { - Ok(()) => { - *self = MouseState::DeviceId; - MouseResult::Timeout(COMMAND_TIMEOUT) - } - Err(err) => { - log::error!("failed to request mouse id: {:?}", err); - //TODO: reset mouse instead? - self.enable_reporting(MouseId::Base as u8, ps2) - } - } - } - - fn identify_touchpad(&mut self, ps2: &mut Ps2) -> MouseResult { - let cmd = TouchpadCommand::Identify as u8; - match MouseTx::new( - &[ - // Ensure command alignment - MouseCommand::SetScaling1To1 as u8, - // Send special identify touchpad command - MouseCommandData::SetResolution as u8, - 0, - MouseCommandData::SetResolution as u8, - 0, - MouseCommandData::SetResolution as u8, - 0, - MouseCommandData::SetResolution as u8, - 0, - // Status request - MouseCommand::StatusRequest as u8, - ], - 3, - ps2, - ) { - Ok(tx) => { - *self = MouseState::IdentifyTouchpad { tx }; - MouseResult::Timeout(COMMAND_TIMEOUT) - } - Err(()) => self.enable_intellimouse(ps2), - } - } - - fn enable_intellimouse(&mut self, ps2: &mut Ps2) -> MouseResult { - match MouseTx::new( - &[ - MouseCommandData::SetSampleRate as u8, - 200, - MouseCommandData::SetSampleRate as u8, - 100, - MouseCommandData::SetSampleRate as u8, - 80, - ], - 0, - ps2, - ) { - Ok(tx) => { - *self = MouseState::EnableIntellimouse { tx }; - MouseResult::Timeout(COMMAND_TIMEOUT) - } - Err(()) => self.request_id(ps2), - } - } - - pub fn handle(&mut self, data: u8, ps2: &mut Ps2) -> MouseResult { - match *self { - MouseState::None | MouseState::Init => { - //TODO: enable port in this case, mouse hotplug may send 0xAA 0x00 - log::error!( - "received mouse byte {:02X} when mouse not initialized", - data - ); - MouseResult::None - } - MouseState::Reset => { - if data == 0xFA { - log::debug!("mouse reset ok"); - MouseResult::Timeout(RESET_TIMEOUT) - } else if data == 0xAA { - log::debug!("BAT completed"); - *self = MouseState::Bat; - MouseResult::Timeout(COMMAND_TIMEOUT) - } else { - log::warn!("unknown mouse response {:02X} after reset", data); - self.reset(ps2) - } - } - MouseState::Bat => { - if data == MouseId::Base as u8 { - // Enable intellimouse features - log::debug!("BAT mouse id {:02X} (base)", data); - self.identify_touchpad(ps2) - } else if data == MouseId::Intellimouse1 as u8 { - // Extra packet already enabled - log::debug!("BAT mouse id {:02X} (intellimouse)", data); - self.enable_reporting(data, ps2) - } else { - log::warn!("unknown mouse id {:02X} after BAT", data); - MouseResult::Timeout(RESET_TIMEOUT) - } - } - MouseState::IdentifyTouchpad { ref mut tx } => { - match tx.handle(data, ps2) { - Ok(done) => { - if done { - //TODO: handle touchpad identification - // If tx.read[1] == 0x47, this is a synaptics touchpad - self.request_status(ps2) - } else { - MouseResult::Timeout(COMMAND_TIMEOUT) - } - } - Err(()) => self.enable_intellimouse(ps2), - } - } - MouseState::EnableIntellimouse { ref mut tx } => match tx.handle(data, ps2) { - Ok(done) => { - if done { - self.request_status(ps2) - } else { - MouseResult::Timeout(COMMAND_TIMEOUT) - } - } - Err(()) => self.request_status(ps2), - }, - MouseState::Status { index } => { - match index { - 0 => { - //TODO: check response - *self = MouseState::Status { index: 1 }; - MouseResult::Timeout(COMMAND_TIMEOUT) - } - 1 => { - *self = MouseState::Status { index: 2 }; - MouseResult::Timeout(COMMAND_TIMEOUT) - } - 2 => { - *self = MouseState::Status { index: 3 }; - MouseResult::Timeout(COMMAND_TIMEOUT) - } - _ => self.request_id(ps2), - } - } - MouseState::DeviceId => { - if data == 0xFA { - // Command OK response - //TODO: handle this separately? - MouseResult::Timeout(COMMAND_TIMEOUT) - } else if data == MouseId::Base as u8 || data == MouseId::Intellimouse1 as u8 { - log::debug!("mouse id {:02X}", data); - self.enable_reporting(data, ps2) - } else { - log::warn!("unknown mouse id {:02X} after requesting id", data); - self.reset(ps2) - } - } - MouseState::EnableReporting { id } => { - log::debug!("mouse id {:02X} enable reporting {:02X}", id, data); - //TODO: handle response ok/error - *self = MouseState::Streaming { id }; - MouseResult::None - } - MouseState::Streaming { id } => { - MouseResult::Packet(data, id == MouseId::Intellimouse1 as u8) - } - } - } - - pub fn handle_timeout(&mut self, ps2: &mut Ps2) -> MouseResult { - match *self { - MouseState::None | MouseState::Streaming { .. } => MouseResult::None, - MouseState::Init => { - // The state uses a timeout on init to request a reset - self.reset(ps2) - } - MouseState::Reset => { - log::warn!("timeout waiting for mouse reset"); - self.reset(ps2) - } - MouseState::Bat => { - log::warn!("timeout waiting for BAT completion"); - self.reset(ps2) - } - MouseState::IdentifyTouchpad { .. } => { - //TODO: retry? - log::warn!("timeout identifying touchpad"); - self.request_status(ps2) - } - MouseState::EnableIntellimouse { .. } => { - //TODO: retry? - log::warn!("timeout enabling intellimouse"); - self.request_status(ps2) - } - MouseState::Status { index } => { - log::warn!("timeout waiting for mouse status {}", index); - self.request_id(ps2) - } - MouseState::DeviceId => { - log::warn!("timeout requesting mouse id"); - self.enable_reporting(0, ps2) - } - MouseState::EnableReporting { id } => { - log::warn!("timeout enabling reporting"); - //TODO: limit number of retries - self.enable_reporting(id, ps2) - } - } - } -} diff --git a/recipes/core/base/drivers/input/ps2d/src/state.rs b/recipes/core/base/drivers/input/ps2d/src/state.rs deleted file mode 100644 index 9018dc6b31..0000000000 --- a/recipes/core/base/drivers/input/ps2d/src/state.rs +++ /dev/null @@ -1,487 +0,0 @@ -use inputd::ProducerHandle; -use log::{error, warn}; -use orbclient::{ButtonEvent, KeyEvent, MouseEvent, MouseRelativeEvent, ScrollEvent}; -use std::{ - convert::TryInto, - fs::File, - io::{Read, Write}, - time::Duration, -}; -use syscall::TimeSpec; - -use crate::controller::Ps2; -use crate::mouse::{MouseResult, MouseState}; -use crate::vm; - -bitflags! { - pub struct MousePacketFlags: u8 { - const LEFT_BUTTON = 1; - const RIGHT_BUTTON = 1 << 1; - const MIDDLE_BUTTON = 1 << 2; - const ALWAYS_ON = 1 << 3; - const X_SIGN = 1 << 4; - const Y_SIGN = 1 << 5; - const X_OVERFLOW = 1 << 6; - const Y_OVERFLOW = 1 << 7; - } -} - -fn timespec_from_duration(duration: Duration) -> TimeSpec { - TimeSpec { - tv_sec: duration.as_secs().try_into().unwrap(), - tv_nsec: duration.subsec_nanos().try_into().unwrap(), - } -} - -fn duration_from_timespec(timespec: TimeSpec) -> Duration { - Duration::new( - timespec.tv_sec.try_into().unwrap(), - timespec.tv_nsec.try_into().unwrap(), - ) -} - -pub struct Ps2d { - ps2: Ps2, - vmmouse: bool, - vmmouse_relative: bool, - input: ProducerHandle, - time_file: File, - extended: bool, - mouse_x: i32, - mouse_y: i32, - mouse_left: bool, - mouse_middle: bool, - mouse_right: bool, - mouse_state: MouseState, - mouse_timeout: Option, - packets: [u8; 4], - packet_i: usize, -} - -impl Ps2d { - pub fn new(input: ProducerHandle, time_file: File) -> Self { - let mut ps2 = Ps2::new(); - ps2.init().expect("failed to initialize"); - - // FIXME add an option for orbital to disable this when an app captures the mouse. - let vmmouse_relative = false; - let vmmouse = vm::enable(vmmouse_relative); - - // TODO: QEMU hack, maybe do this when Init timed out? - if vmmouse { - // 3 = MouseId::Intellimouse1 - MouseState::Bat.handle(3, &mut ps2); - } - - let mut this = Ps2d { - ps2, - vmmouse, - vmmouse_relative, - input, - time_file, - extended: false, - mouse_x: 0, - mouse_y: 0, - mouse_left: false, - mouse_middle: false, - mouse_right: false, - mouse_state: MouseState::Init, - mouse_timeout: None, - packets: [0; 4], - packet_i: 0, - }; - - if !this.vmmouse { - // This triggers initializing the mouse - this.handle_mouse(None); - } - - this - } - - pub fn irq(&mut self) { - while let Some((keyboard, data)) = self.ps2.next() { - self.handle(keyboard, data); - } - } - - pub fn time_event(&mut self) { - let mut time = TimeSpec::default(); - match self.time_file.read(&mut time) { - Ok(_count) => {} - Err(err) => { - log::error!("failed to read time file: {}", err); - return; - } - } - if let Some(mouse_timeout) = self.mouse_timeout { - if time.tv_sec > mouse_timeout.tv_sec - || (time.tv_sec == mouse_timeout.tv_sec && time.tv_nsec >= mouse_timeout.tv_nsec) - { - self.handle_mouse(None); - } - } - } - - pub fn handle(&mut self, keyboard: bool, data: u8) { - if keyboard { - if data == 0xE0 { - self.extended = true; - } else { - let (ps2_scancode, pressed) = if data >= 0x80 { - (data - 0x80, false) - } else { - (data, true) - }; - - let scancode = if self.extended { - self.extended = false; - match ps2_scancode { - 0x1C => orbclient::K_NUM_ENTER, - 0x1D => orbclient::K_RIGHT_CTRL, - 0x20 => orbclient::K_VOLUME_TOGGLE, - 0x22 => orbclient::K_MEDIA_PLAY_PAUSE, - 0x24 => orbclient::K_MEDIA_STOP, - 0x10 => orbclient::K_MEDIA_REWIND, - 0x19 => orbclient::K_MEDIA_FAST_FORWARD, - 0x2E => orbclient::K_VOLUME_DOWN, - 0x30 => orbclient::K_VOLUME_UP, - 0x35 => orbclient::K_NUM_SLASH, - 0x38 => orbclient::K_ALT_GR, - 0x47 => orbclient::K_HOME, - 0x48 => orbclient::K_UP, - 0x49 => orbclient::K_PGUP, - 0x4B => orbclient::K_LEFT, - 0x4D => orbclient::K_RIGHT, - 0x4F => orbclient::K_END, - 0x50 => orbclient::K_DOWN, - 0x51 => orbclient::K_PGDN, - 0x52 => orbclient::K_INS, - 0x53 => orbclient::K_DEL, - 0x5B => orbclient::K_LEFT_SUPER, - 0x5C => orbclient::K_RIGHT_SUPER, - 0x5D => orbclient::K_APP, - 0x5E => orbclient::K_POWER, - 0x5F => orbclient::K_SLEEP, - /* 0x80 to 0xFF used for press/release detection */ - _ => { - if pressed { - warn!("unknown extended scancode {:02X}", ps2_scancode); - } - 0 - } - } - } else { - match ps2_scancode { - /* 0x00 unused */ - 0x01 => orbclient::K_ESC, - 0x02 => orbclient::K_1, - 0x03 => orbclient::K_2, - 0x04 => orbclient::K_3, - 0x05 => orbclient::K_4, - 0x06 => orbclient::K_5, - 0x07 => orbclient::K_6, - 0x08 => orbclient::K_7, - 0x09 => orbclient::K_8, - 0x0A => orbclient::K_9, - 0x0B => orbclient::K_0, - 0x0C => orbclient::K_MINUS, - 0x0D => orbclient::K_EQUALS, - 0x0E => orbclient::K_BKSP, - 0x0F => orbclient::K_TAB, - 0x10 => orbclient::K_Q, - 0x11 => orbclient::K_W, - 0x12 => orbclient::K_E, - 0x13 => orbclient::K_R, - 0x14 => orbclient::K_T, - 0x15 => orbclient::K_Y, - 0x16 => orbclient::K_U, - 0x17 => orbclient::K_I, - 0x18 => orbclient::K_O, - 0x19 => orbclient::K_P, - 0x1A => orbclient::K_BRACE_OPEN, - 0x1B => orbclient::K_BRACE_CLOSE, - 0x1C => orbclient::K_ENTER, - 0x1D => orbclient::K_CTRL, - 0x1E => orbclient::K_A, - 0x1F => orbclient::K_S, - 0x20 => orbclient::K_D, - 0x21 => orbclient::K_F, - 0x22 => orbclient::K_G, - 0x23 => orbclient::K_H, - 0x24 => orbclient::K_J, - 0x25 => orbclient::K_K, - 0x26 => orbclient::K_L, - 0x27 => orbclient::K_SEMICOLON, - 0x28 => orbclient::K_QUOTE, - 0x29 => orbclient::K_TICK, - 0x2A => orbclient::K_LEFT_SHIFT, - 0x2B => orbclient::K_BACKSLASH, - 0x2C => orbclient::K_Z, - 0x2D => orbclient::K_X, - 0x2E => orbclient::K_C, - 0x2F => orbclient::K_V, - 0x30 => orbclient::K_B, - 0x31 => orbclient::K_N, - 0x32 => orbclient::K_M, - 0x33 => orbclient::K_COMMA, - 0x34 => orbclient::K_PERIOD, - 0x35 => orbclient::K_SLASH, - 0x36 => orbclient::K_RIGHT_SHIFT, - 0x37 => orbclient::K_NUM_ASTERISK, - 0x38 => orbclient::K_ALT, - 0x39 => orbclient::K_SPACE, - 0x3A => orbclient::K_CAPS, - 0x3B => orbclient::K_F1, - 0x3C => orbclient::K_F2, - 0x3D => orbclient::K_F3, - 0x3E => orbclient::K_F4, - 0x3F => orbclient::K_F5, - 0x40 => orbclient::K_F6, - 0x41 => orbclient::K_F7, - 0x42 => orbclient::K_F8, - 0x43 => orbclient::K_F9, - 0x44 => orbclient::K_F10, - 0x45 => orbclient::K_NUM, - 0x46 => orbclient::K_SCROLL, - 0x47 => orbclient::K_NUM_7, - 0x48 => orbclient::K_NUM_8, - 0x49 => orbclient::K_NUM_9, - 0x4A => orbclient::K_NUM_MINUS, - 0x4B => orbclient::K_NUM_4, - 0x4C => orbclient::K_NUM_5, - 0x4D => orbclient::K_NUM_6, - 0x4E => orbclient::K_NUM_PLUS, - 0x4F => orbclient::K_NUM_1, - 0x50 => orbclient::K_NUM_2, - 0x51 => orbclient::K_NUM_3, - 0x52 => orbclient::K_NUM_0, - 0x53 => orbclient::K_NUM_PERIOD, - /* 0x54 to 0x55 unused */ - 0x56 => 0x56, // UK Backslash - 0x57 => orbclient::K_F11, - 0x58 => orbclient::K_F12, - /* 0x59 to 0x7F unused */ - /* 0x80 to 0xFF used for press/release detection */ - _ => { - if pressed { - warn!("unknown scancode {:02X}", ps2_scancode); - } - 0 - } - } - }; - - if scancode != 0 { - self.input - .write_event( - KeyEvent { - character: '\0', - scancode, - pressed, - } - .to_event(), - ) - .expect("failed to write key event"); - } - } - } else if self.vmmouse { - for _i in 0..256 { - let (status, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) }; - //TODO if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) - - let queue_length = status & 0xffff; - if queue_length == 0 { - break; - } - - if queue_length % 4 != 0 { - error!("queue length not a multiple of 4: {}", queue_length); - break; - } - - let (status, dx, dy, dz) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; - - if self.vmmouse_relative { - if dx != 0 || dy != 0 { - self.input - .write_event( - MouseRelativeEvent { - dx: dx as i32, - dy: dy as i32, - } - .to_event(), - ) - .expect("ps2d: failed to write mouse event"); - } - } else { - let x = dx as i32; - let y = dy as i32; - if x != self.mouse_x || y != self.mouse_y { - self.mouse_x = x; - self.mouse_y = y; - self.input - .write_event(MouseEvent { x, y }.to_event()) - .expect("ps2d: failed to write mouse event"); - } - }; - - if dz != 0 { - self.input - .write_event( - ScrollEvent { - x: 0, - y: -(dz as i32), - } - .to_event(), - ) - .expect("ps2d: failed to write scroll event"); - } - - let left = status & vm::LEFT_BUTTON == vm::LEFT_BUTTON; - let middle = status & vm::MIDDLE_BUTTON == vm::MIDDLE_BUTTON; - let right = status & vm::RIGHT_BUTTON == vm::RIGHT_BUTTON; - if left != self.mouse_left - || middle != self.mouse_middle - || right != self.mouse_right - { - self.mouse_left = left; - self.mouse_middle = middle; - self.mouse_right = right; - self.input - .write_event( - ButtonEvent { - left, - middle, - right, - } - .to_event(), - ) - .expect("ps2d: failed to write button event"); - } - } - } else { - self.handle_mouse(Some(data)); - } - } - - pub fn handle_mouse(&mut self, data_opt: Option) { - // log::trace!( - // "handle_mouse state {:?} data {:?}", - // self.mouse_state, - // data_opt - // ); - let mouse_res = match data_opt { - Some(data) => self.mouse_state.handle(data, &mut self.ps2), - None => self.mouse_state.handle_timeout(&mut self.ps2), - }; - self.mouse_timeout = None; - let (packet_data, extra_packet) = match mouse_res { - MouseResult::None => { - return; - } - MouseResult::Packet(packet_data, extra_packet) => (packet_data, extra_packet), - MouseResult::Timeout(duration) => { - // Read current time - let mut time = TimeSpec::default(); - match self.time_file.read(&mut time) { - Ok(_count) => {} - Err(err) => { - log::error!("failed to read time file: {}", err); - return; - } - } - - // Add duration to time - time = timespec_from_duration(duration_from_timespec(time) + duration); - - // Write next time - match self.time_file.write(&time) { - Ok(_count) => {} - Err(err) => { - log::error!("failed to write time file: {}", err); - } - } - - self.mouse_timeout = Some(time); - return; - } - }; - - self.packets[self.packet_i] = packet_data; - self.packet_i += 1; - - let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); - if !flags.contains(MousePacketFlags::ALWAYS_ON) { - error!("mouse misalign {:X}", self.packets[0]); - - self.packets = [0; 4]; - self.packet_i = 0; - } else if self.packet_i >= self.packets.len() || (!extra_packet && self.packet_i >= 3) { - if !flags.contains(MousePacketFlags::X_OVERFLOW) - && !flags.contains(MousePacketFlags::Y_OVERFLOW) - { - let mut dx = self.packets[1] as i32; - if flags.contains(MousePacketFlags::X_SIGN) { - dx -= 0x100; - } - - let mut dy = -(self.packets[2] as i32); - if flags.contains(MousePacketFlags::Y_SIGN) { - dy += 0x100; - } - - let mut dz = 0; - if extra_packet { - let mut scroll = (self.packets[3] & 0xF) as i8; - if scroll & (1 << 3) == 1 << 3 { - scroll -= 16; - } - dz = -scroll as i32; - } - - if dx != 0 || dy != 0 { - self.input - .write_event(MouseRelativeEvent { dx, dy }.to_event()) - .expect("ps2d: failed to write mouse event"); - } - - if dz != 0 { - self.input - .write_event(ScrollEvent { x: 0, y: dz }.to_event()) - .expect("ps2d: failed to write scroll event"); - } - - let left = flags.contains(MousePacketFlags::LEFT_BUTTON); - let middle = flags.contains(MousePacketFlags::MIDDLE_BUTTON); - let right = flags.contains(MousePacketFlags::RIGHT_BUTTON); - if left != self.mouse_left - || middle != self.mouse_middle - || right != self.mouse_right - { - self.mouse_left = left; - self.mouse_middle = middle; - self.mouse_right = right; - self.input - .write_event( - ButtonEvent { - left, - middle, - right, - } - .to_event(), - ) - .expect("ps2d: failed to write button event"); - } - } else { - warn!( - "overflow {:X} {:X} {:X} {:X}", - self.packets[0], self.packets[1], self.packets[2], self.packets[3] - ); - } - - self.packets = [0; 4]; - self.packet_i = 0; - } - } -} diff --git a/recipes/core/base/drivers/input/ps2d/src/vm.rs b/recipes/core/base/drivers/input/ps2d/src/vm.rs deleted file mode 100644 index 71b7141704..0000000000 --- a/recipes/core/base/drivers/input/ps2d/src/vm.rs +++ /dev/null @@ -1,107 +0,0 @@ -// This code is informed by the QEMU implementation found here: -// https://github.com/qemu/qemu/blob/master/hw/input/vmmouse.c -// -// As well as the Linux implementation here: -// http://elixir.free-electrons.com/linux/v4.1/source/drivers/input/mouse/vmmouse.c - -use core::arch::asm; - -use log::{error, info, trace}; - -const MAGIC: u32 = 0x564D5868; -const PORT: u16 = 0x5658; - -pub const GETVERSION: u32 = 10; -pub const ABSPOINTER_DATA: u32 = 39; -pub const ABSPOINTER_STATUS: u32 = 40; -pub const ABSPOINTER_COMMAND: u32 = 41; - -pub const CMD_ENABLE: u32 = 0x45414552; -pub const CMD_DISABLE: u32 = 0x000000f5; -pub const CMD_REQUEST_ABSOLUTE: u32 = 0x53424152; -pub const CMD_REQUEST_RELATIVE: u32 = 0x4c455252; - -const VERSION: u32 = 0x3442554a; - -pub const RELATIVE_PACKET: u32 = 0x00010000; - -pub const LEFT_BUTTON: u32 = 0x20; -pub const RIGHT_BUTTON: u32 = 0x10; -pub const MIDDLE_BUTTON: u32 = 0x08; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32) { - let a: u32; - let b: u32; - let c: u32; - let d: u32; - - // ebx can't be used as input or output constraint in rust as LLVM reserves it. - // Use xchg to pass it through r9 instead while restoring the original value in - // rbx when leaving the inline asm block. si and di are clobbered too. - #[cfg(not(target_arch = "x86"))] - asm!( - "xchg r9, rbx; in eax, dx; xchg r9, rbx", - inout("eax") MAGIC => a, - inout("r9") arg => b, - inout("ecx") cmd => c, - inout("edx") PORT as u32 => d, - out("rsi") _, - out("rdi") _, - ); - - // On x86 we don't have a spare register, so push ebx to the stack instead. - #[cfg(target_arch = "x86")] - asm!( - "push ebx; mov ebx, edi; in eax, dx; mov edi, ebx; pop ebx", - inout("eax") MAGIC => a, - inout("edi") arg => b, - inout("ecx") cmd => c, - inout("edx") PORT as u32 => d, - ); - - (a, b, c, d) -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32) { - unimplemented!() -} - -pub fn enable(relative: bool) -> bool { - trace!("Enable vmmouse"); - - unsafe { - let (eax, ebx, _, _) = cmd(GETVERSION, 0); - if ebx != MAGIC || eax == 0xFFFFFFFF { - info!("No vmmouse support"); - return false; - } - - let _ = cmd(ABSPOINTER_COMMAND, CMD_ENABLE); - - let (status, _, _, _) = cmd(ABSPOINTER_STATUS, 0); - if (status & 0x0000ffff) == 0 { - info!("No vmmouse"); - return false; - } - - let (version, _, _, _) = cmd(ABSPOINTER_DATA, 1); - if version != VERSION { - error!( - "Invalid vmmouse version: {} instead of {}", - version, VERSION - ); - let _ = cmd(ABSPOINTER_COMMAND, CMD_DISABLE); - return false; - } - - if relative { - cmd(ABSPOINTER_COMMAND, CMD_REQUEST_RELATIVE); - } else { - cmd(ABSPOINTER_COMMAND, CMD_REQUEST_ABSOLUTE); - } - } - - return true; -} diff --git a/recipes/core/base/drivers/input/usbhidd/.gitignore b/recipes/core/base/drivers/input/usbhidd/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/recipes/core/base/drivers/input/usbhidd/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/recipes/core/base/drivers/input/usbhidd/Cargo.toml b/recipes/core/base/drivers/input/usbhidd/Cargo.toml deleted file mode 100644 index 2c0cda1915..0000000000 --- a/recipes/core/base/drivers/input/usbhidd/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "usbhidd" -description = "USB HID driver" -version = "0.1.0" -authors = ["4lDO2 <4lDO2@protonmail.com>"] -edition = "2018" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -anyhow.workspace = true -bitflags.workspace = true -log.workspace = true -orbclient.workspace = true -redox_syscall.workspace = true -rehid = { git = "https://gitlab.redox-os.org/redox-os/rehid.git" } -xhcid = { path = "../../usb/xhcid" } - -common = { path = "../../common" } -inputd = { path = "../../inputd" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/input/usbhidd/src/main.rs b/recipes/core/base/drivers/input/usbhidd/src/main.rs deleted file mode 100644 index 15c5b77820..0000000000 --- a/recipes/core/base/drivers/input/usbhidd/src/main.rs +++ /dev/null @@ -1,457 +0,0 @@ -use anyhow::{Context, Result}; -use std::{env, thread, time}; - -use inputd::ProducerHandle; -use orbclient::KeyEvent as OrbKeyEvent; -use rehid::{ - report_desc::{ReportTy, REPORT_DESC_TY}, - report_handler::ReportHandler, - usage_tables::{GenericDesktopUsage, UsagePage}, -}; -use xhcid_interface::{ - ConfigureEndpointsReq, DevDesc, EndpDirection, EndpointTy, PortId, PortReqRecipient, - XhciClientHandle, -}; - -mod reqs; - -fn send_key_event(display: &mut ProducerHandle, usage_page: u16, usage: u16, pressed: bool) { - let scancode = match usage_page { - 0x07 => match usage { - 0x04 => orbclient::K_A, - 0x05 => orbclient::K_B, - 0x06 => orbclient::K_C, - 0x07 => orbclient::K_D, - 0x08 => orbclient::K_E, - 0x09 => orbclient::K_F, - 0x0A => orbclient::K_G, - 0x0B => orbclient::K_H, - 0x0C => orbclient::K_I, - 0x0D => orbclient::K_J, - 0x0E => orbclient::K_K, - 0x0F => orbclient::K_L, - 0x10 => orbclient::K_M, - 0x11 => orbclient::K_N, - 0x12 => orbclient::K_O, - 0x13 => orbclient::K_P, - 0x14 => orbclient::K_Q, - 0x15 => orbclient::K_R, - 0x16 => orbclient::K_S, - 0x17 => orbclient::K_T, - 0x18 => orbclient::K_U, - 0x19 => orbclient::K_V, - 0x1A => orbclient::K_W, - 0x1B => orbclient::K_X, - 0x1C => orbclient::K_Y, - 0x1D => orbclient::K_Z, - 0x1E => orbclient::K_1, - 0x1F => orbclient::K_2, - 0x20 => orbclient::K_3, - 0x21 => orbclient::K_4, - 0x22 => orbclient::K_5, - 0x23 => orbclient::K_6, - 0x24 => orbclient::K_7, - 0x25 => orbclient::K_8, - 0x26 => orbclient::K_9, - 0x27 => orbclient::K_0, - 0x28 => orbclient::K_ENTER, - 0x29 => orbclient::K_ESC, - 0x2A => orbclient::K_BKSP, - 0x2B => orbclient::K_TAB, - 0x2C => orbclient::K_SPACE, - 0x2D => orbclient::K_MINUS, - 0x2E => orbclient::K_EQUALS, - 0x2F => orbclient::K_BRACE_OPEN, - 0x30 => orbclient::K_BRACE_CLOSE, - 0x31 => orbclient::K_BACKSLASH, - // 0x32 non-us # and ~ - 0x32 => 0x56, - 0x33 => orbclient::K_SEMICOLON, - 0x34 => orbclient::K_QUOTE, - 0x35 => orbclient::K_TICK, - 0x36 => orbclient::K_COMMA, - 0x37 => orbclient::K_PERIOD, - 0x38 => orbclient::K_SLASH, - 0x39 => orbclient::K_CAPS, - 0x3A => orbclient::K_F1, - 0x3B => orbclient::K_F2, - 0x3C => orbclient::K_F3, - 0x3D => orbclient::K_F4, - 0x3E => orbclient::K_F5, - 0x3F => orbclient::K_F6, - 0x40 => orbclient::K_F7, - 0x41 => orbclient::K_F8, - 0x42 => orbclient::K_F9, - 0x43 => orbclient::K_F10, - 0x44 => orbclient::K_F11, - 0x45 => orbclient::K_F12, - 0x46 => orbclient::K_PRTSC, - 0x47 => orbclient::K_SCROLL, - // 0x48 pause - 0x49 => orbclient::K_INS, - 0x4A => orbclient::K_HOME, - 0x4B => orbclient::K_PGUP, - 0x4C => orbclient::K_DEL, - 0x4D => orbclient::K_END, - 0x4E => orbclient::K_PGDN, - 0x4F => orbclient::K_RIGHT, - 0x50 => orbclient::K_LEFT, - 0x51 => orbclient::K_DOWN, - 0x52 => orbclient::K_UP, - 0x53 => orbclient::K_NUM, - 0x54 => orbclient::K_NUM_SLASH, - 0x55 => orbclient::K_NUM_ASTERISK, - 0x56 => orbclient::K_NUM_MINUS, - 0x57 => orbclient::K_NUM_PLUS, - 0x58 => orbclient::K_NUM_ENTER, - 0x59 => orbclient::K_NUM_1, - 0x5A => orbclient::K_NUM_2, - 0x5B => orbclient::K_NUM_3, - 0x5C => orbclient::K_NUM_4, - 0x5D => orbclient::K_NUM_5, - 0x5E => orbclient::K_NUM_6, - 0x5F => orbclient::K_NUM_7, - 0x60 => orbclient::K_NUM_8, - 0x61 => orbclient::K_NUM_9, - 0x62 => orbclient::K_NUM_0, - // 0x62 num . - // 0x64 non-us \ and | - 0x64 => orbclient::K_APP, - 0x66 => orbclient::K_POWER, - // 0x67 num = - // unmapped values - 0xE0 => orbclient::K_LEFT_CTRL, - 0xE1 => orbclient::K_LEFT_SHIFT, - 0xE2 => orbclient::K_ALT, - 0xE3 => orbclient::K_LEFT_SUPER, - 0xE4 => orbclient::K_RIGHT_CTRL, - 0xE5 => orbclient::K_RIGHT_SHIFT, - 0xE6 => orbclient::K_ALT_GR, - 0xE7 => orbclient::K_RIGHT_SUPER, - // reserved values - _ => { - log::warn!("unknown usage_page {:#x} usage {:#x}", usage_page, usage); - return; - } - }, - _ => { - log::warn!("unknown usage_page {:#x}", usage_page); - return; - } - }; - - let key_event = OrbKeyEvent { - character: '\0', - scancode, - pressed, - }; - - match display.write_event(key_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send key event to orbital: {}", err); - } - } -} - -fn main() -> Result<()> { - let mut args = env::args().skip(1); - - const USAGE: &'static str = "usbhidd "; - - let scheme = args.next().expect(USAGE); - let port = args - .next() - .expect(USAGE) - .parse::() - .expect("Expected port ID"); - let interface_num = args - .next() - .expect(USAGE) - .parse::() - .expect("Expected integer as input of interface"); - - let name = format!("{}_{}_{}_hid", scheme, port, interface_num); - common::setup_logging( - "usb", - "usbhid", - &name, - common::output_level(), - common::file_level(), - ); - - log::info!( - "USB HID driver spawned with scheme `{}`, port {}, interface {}", - scheme, - port, - interface_num - ); - - let handle = XhciClientHandle::new(scheme, port).context("Failed to open XhciClientHandle")?; - let desc: DevDesc = handle - .get_standard_descs() - .context("Failed to get standard descriptors")?; - - log::info!( - "USB HID driver: {:?} serial {:?}", - desc.product_str.as_ref().map(|s| s.as_str()).unwrap_or(""), - desc.serial_str.as_ref().map(|s| s.as_str()).unwrap_or(""), - ); - - log::debug!("{:X?}", desc); - - let mut endp_count = 0; - let (conf_desc, (if_desc, endp_desc_opt, hid_desc)) = desc - .config_descs - .iter() - .find_map(|conf_desc| { - let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { - if if_desc.number == interface_num { - let endp_desc_opt = if_desc.endpoints.iter().find_map(|endp_desc| { - endp_count += 1; - if endp_desc.ty() == EndpointTy::Interrupt - && endp_desc.direction() == EndpDirection::In - { - Some((endp_count, endp_desc.clone())) - } else { - None - } - }); - let hid_desc = if_desc.hid_descs.iter().find_map(|hid_desc| { - //TODO: should we do any filtering? - Some(hid_desc) - })?; - Some((if_desc.clone(), endp_desc_opt, hid_desc)) - } else { - endp_count += if_desc.endpoints.len(); - None - } - })?; - Some((conf_desc.clone(), if_desc)) - }) - .context("Failed to find suitable configuration")?; - - handle - .configure_endpoints(&ConfigureEndpointsReq { - config_desc: conf_desc.configuration_value, - interface_desc: Some(interface_num), - alternate_setting: Some(if_desc.alternate_setting), - hub_ports: None, - }) - .context("Failed to configure endpoints")?; - - //TODO: do we need to set protocol to report? It fails for mice. - - //TODO: dynamically create good values, fix xhcid so it does not block on each request - // This sets all reports to a duration of 4ms - reqs::set_idle(&handle, 1, 0, interface_num as u16).context("Failed to set idle")?; - - let report_desc_len = hid_desc.desc_len; - assert_eq!(hid_desc.desc_ty, REPORT_DESC_TY); - - let mut report_desc_bytes = vec![0u8; report_desc_len as usize]; - handle - .get_descriptor( - PortReqRecipient::Interface, - REPORT_DESC_TY, - 0, - //TODO: should this be an index into interface_descs? - interface_num as u16, - &mut report_desc_bytes, - ) - .context("Failed to retrieve report descriptor")?; - - let mut handler = - ReportHandler::new(&report_desc_bytes).expect("failed to parse report descriptor"); - - let report_len = match endp_desc_opt { - Some((_endp_num, endp_desc)) => endp_desc.max_packet_size as usize, - None => handler.total_byte_length as usize, - }; - let mut report_buffer = vec![0u8; report_len]; - let report_ty = ReportTy::Input; - let report_id = 0; - - let mut display = ProducerHandle::new().context("Failed to open input socket")?; - let mut endpoint_opt = match endp_desc_opt { - Some((endp_num, _endp_desc)) => match handle.open_endpoint(endp_num as u8) { - Ok(ok) => Some(ok), - Err(err) => { - log::warn!("failed to open endpoint {endp_num}: {err}"); - None - } - }, - None => None, - }; - let mut left_shift = false; - let mut right_shift = false; - let mut last_mouse_pos = (0, 0); - let mut last_buttons = [false, false, false]; - loop { - //TODO: get frequency from device - //TODO: use sleeps when accuracy is better: thread::sleep(time::Duration::from_millis(10)); - let timer = time::Instant::now(); - while timer.elapsed() < time::Duration::from_millis(1) { - thread::yield_now(); - } - - if let Some(endpoint) = &mut endpoint_opt { - // interrupt transfer - endpoint - .transfer_read(&mut report_buffer) - .context("failed to get report")?; - } else { - // control transfer - reqs::get_report( - &handle, - report_ty, - report_id, - //TODO: should this be an index into interface_descs? - interface_num as u16, - &mut report_buffer, - ) - .context("failed to get report")?; - } - - let mut mouse_pos = last_mouse_pos; - let mut mouse_dx = 0i32; - let mut mouse_dy = 0i32; - let mut scroll_y = 0i32; - let mut buttons = last_buttons; - for event in handler - .handle(&report_buffer) - .expect("failed to parse report") - { - log::debug!("{}", event); - if event.usage_page == UsagePage::GenericDesktop as u16 { - if event.usage == GenericDesktopUsage::X as u16 { - if event.relative { - mouse_dx += event.value as i32; - } else { - mouse_pos.0 = event.value as i32; - } - } else if event.usage == GenericDesktopUsage::Y as u16 { - if event.relative { - mouse_dy += event.value as i32; - } else { - mouse_pos.1 = event.value as i32; - } - } else if event.usage == GenericDesktopUsage::Wheel as u16 { - //TODO: what is X scroll? - if event.relative { - scroll_y += event.value as i32; - } else { - log::warn!("absolute mouse wheel not supported"); - } - } else { - log::info!( - "unsupported generic desktop usage 0x{:X}:0x{:X} value {}", - event.usage_page, - event.usage, - event.value - ); - } - } else if event.usage_page == UsagePage::KeyboardOrKeypad as u16 { - let (pressed, shift_opt) = if event.value != 0 { - (true, Some(left_shift | right_shift)) - } else { - (false, None) - }; - if event.usage == 0xE1 { - left_shift = pressed; - } else if event.usage == 0xE5 { - right_shift = pressed; - } - send_key_event(&mut display, event.usage_page, event.usage, pressed); - } else if event.usage_page == UsagePage::Button as u16 { - if event.usage > 0 && event.usage as usize <= buttons.len() { - buttons[event.usage as usize - 1] = event.value != 0; - } else { - log::info!( - "unsupported buttons usage 0x{:X}:0x{:X} value {}", - event.usage_page, - event.usage, - event.value - ); - } - } else if event.usage_page >= 0xFF00 { - // Ignore vendor defined event - } else { - log::info!( - "unsupported usage 0x{:X}:0x{:X} value {}", - event.usage_page, - event.usage, - event.value - ); - } - } - - if mouse_pos != last_mouse_pos { - last_mouse_pos = mouse_pos; - - // TODO - // ps2d uses 0..=65535 as range, while usb uses 0..=32767. orbital - // expects the former range, so multiply by two here to temporarily - // align with orbital expectation. This workaround will make cursor - // looks out of sync in QEMU using virtio-vga with usb-tablet. - let mouse_event = orbclient::event::MouseEvent { - x: mouse_pos.0 * 2, - y: mouse_pos.1 * 2, - }; - - match display.write_event(mouse_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send mouse event to orbital: {}", err); - } - } - } - - if mouse_dx != 0 || mouse_dy != 0 { - // TODO: This is a filter to prevent random mouse jumps - if mouse_dx > -127 && mouse_dx < 127 { - let mouse_event = orbclient::event::MouseRelativeEvent { - dx: mouse_dx, - dy: mouse_dy, - }; - - match display.write_event(mouse_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send mouse event to orbital: {}", err); - } - } - } - } - - if scroll_y != 0 { - let scroll_event = orbclient::event::ScrollEvent { x: 0, y: scroll_y }; - - match display.write_event(scroll_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send scroll event to orbital: {}", err); - } - } - } - - if buttons != last_buttons { - last_buttons = buttons; - - let button_event = orbclient::event::ButtonEvent { - left: buttons[0], - right: buttons[1], - middle: buttons[2], - }; - - match display.write_event(button_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send button event to orbital: {}", err); - } - } - } - - // log::trace!("took {}ms", timer.elapsed().as_millis()) - } -} diff --git a/recipes/core/base/drivers/input/usbhidd/src/reqs.rs b/recipes/core/base/drivers/input/usbhidd/src/reqs.rs deleted file mode 100644 index c74281dd3d..0000000000 --- a/recipes/core/base/drivers/input/usbhidd/src/reqs.rs +++ /dev/null @@ -1,109 +0,0 @@ -use std::slice; - -use rehid::report_desc::ReportTy; -use xhcid_interface::{ - DeviceReqData, PortReqRecipient, PortReqTy, XhciClientHandle, XhciClientHandleError, -}; - -const GET_REPORT_REQ: u8 = 0x1; -const SET_REPORT_REQ: u8 = 0x9; -const GET_IDLE_REQ: u8 = 0x2; -const SET_IDLE_REQ: u8 = 0xA; -const GET_PROTOCOL_REQ: u8 = 0x3; -const SET_PROTOCOL_REQ: u8 = 0xB; - -fn concat(hi: u8, lo: u8) -> u16 { - (u16::from(hi) << 8) | u16::from(lo) -} - -pub fn get_report( - handle: &XhciClientHandle, - report_ty: ReportTy, - report_id: u8, - if_num: u16, - buffer: &mut [u8], -) -> Result<(), XhciClientHandleError> { - handle.device_request( - PortReqTy::Class, - PortReqRecipient::Interface, - GET_REPORT_REQ, - concat(report_ty as u8, report_id), - if_num, - DeviceReqData::In(buffer), - ) -} -pub fn set_report( - handle: &XhciClientHandle, - report_ty: ReportTy, - report_id: u8, - if_num: u16, - buffer: &[u8], -) -> Result<(), XhciClientHandleError> { - handle.device_request( - PortReqTy::Class, - PortReqRecipient::Interface, - SET_REPORT_REQ, - concat(report_id, report_ty as u8), - if_num, - DeviceReqData::Out(buffer), - ) -} -pub fn get_idle( - handle: &XhciClientHandle, - report_id: u8, - if_num: u16, -) -> Result { - let mut idle_rate = 0; - let buffer = slice::from_mut(&mut idle_rate); - handle.device_request( - PortReqTy::Class, - PortReqRecipient::Interface, - GET_IDLE_REQ, - u16::from(report_id), - if_num, - DeviceReqData::In(buffer), - )?; - Ok(idle_rate) -} -pub fn set_idle( - handle: &XhciClientHandle, - duration: u8, - report_id: u8, - if_num: u16, -) -> Result<(), XhciClientHandleError> { - handle.device_request( - PortReqTy::Class, - PortReqRecipient::Interface, - SET_IDLE_REQ, - concat(duration, report_id), - if_num, - DeviceReqData::NoData, - ) -} -pub fn get_protocol(handle: &XhciClientHandle, if_num: u16) -> Result { - let mut protocol = 0; - let buffer = slice::from_mut(&mut protocol); - handle.device_request( - PortReqTy::Class, - PortReqRecipient::Interface, - GET_PROTOCOL_REQ, - 0, - if_num, - DeviceReqData::In(buffer), - )?; - Ok(protocol) -} -pub fn set_protocol( - handle: &XhciClientHandle, - protocol: u8, - if_num: u16, -) -> Result<(), XhciClientHandleError> { - handle.device_request( - PortReqTy::Class, - PortReqRecipient::Interface, - SET_PROTOCOL_REQ, - u16::from(protocol), - if_num, - DeviceReqData::NoData, - ) -} diff --git a/recipes/core/base/drivers/inputd/Cargo.toml b/recipes/core/base/drivers/inputd/Cargo.toml deleted file mode 100644 index 8c1b999040..0000000000 --- a/recipes/core/base/drivers/inputd/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "inputd" -description = "Input multiplexer daemon" -version = "0.1.0" -edition = "2021" -authors = ["Anhad Singh "] - -[dependencies] -anyhow.workspace = true -log.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -orbclient.workspace = true -libredox.workspace = true - -common = { path = "../common" } -daemon = { path = "../../daemon" } -redox-scheme.workspace = true -scheme-utils = { path = "../../scheme-utils" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/inputd/src/keymap.rs b/recipes/core/base/drivers/inputd/src/keymap.rs deleted file mode 100644 index ca69e46e90..0000000000 --- a/recipes/core/base/drivers/inputd/src/keymap.rs +++ /dev/null @@ -1,438 +0,0 @@ -use std::collections::HashMap; -use std::fmt::Display; -use std::str::FromStr; - -mod keymaps { - pub static US: [(u8, [char; 2]); 53] = [ - (orbclient::K_ESC, ['\x1B', '\x1B']), - (orbclient::K_1, ['1', '!']), - (orbclient::K_2, ['2', '@']), - (orbclient::K_3, ['3', '#']), - (orbclient::K_4, ['4', '$']), - (orbclient::K_5, ['5', '%']), - (orbclient::K_6, ['6', '^']), - (orbclient::K_7, ['7', '&']), - (orbclient::K_8, ['8', '*']), - (orbclient::K_9, ['9', '(']), - (orbclient::K_0, ['0', ')']), - (orbclient::K_MINUS, ['-', '_']), - (orbclient::K_EQUALS, ['=', '+']), - (orbclient::K_BKSP, ['\x7F', '\x7F']), - (orbclient::K_TAB, ['\t', '\t']), - (orbclient::K_Q, ['q', 'Q']), - (orbclient::K_W, ['w', 'W']), - (orbclient::K_E, ['e', 'E']), - (orbclient::K_R, ['r', 'R']), - (orbclient::K_T, ['t', 'T']), - (orbclient::K_Y, ['y', 'Y']), - (orbclient::K_U, ['u', 'U']), - (orbclient::K_I, ['i', 'I']), - (orbclient::K_O, ['o', 'O']), - (orbclient::K_P, ['p', 'P']), - (orbclient::K_BRACE_OPEN, ['[', '{']), - (orbclient::K_BRACE_CLOSE, [']', '}']), - (orbclient::K_ENTER, ['\n', '\n']), - (orbclient::K_CTRL, ['\0', '\0']), - (orbclient::K_A, ['a', 'A']), - (orbclient::K_S, ['s', 'S']), - (orbclient::K_D, ['d', 'D']), - (orbclient::K_F, ['f', 'F']), - (orbclient::K_G, ['g', 'G']), - (orbclient::K_H, ['h', 'H']), - (orbclient::K_J, ['j', 'J']), - (orbclient::K_K, ['k', 'K']), - (orbclient::K_L, ['l', 'L']), - (orbclient::K_SEMICOLON, [';', ':']), - (orbclient::K_QUOTE, ['\'', '"']), - (orbclient::K_TICK, ['`', '~']), - (orbclient::K_BACKSLASH, ['\\', '|']), - (orbclient::K_Z, ['z', 'Z']), - (orbclient::K_X, ['x', 'X']), - (orbclient::K_C, ['c', 'C']), - (orbclient::K_V, ['v', 'V']), - (orbclient::K_B, ['b', 'B']), - (orbclient::K_N, ['n', 'N']), - (orbclient::K_M, ['m', 'M']), - (orbclient::K_COMMA, [',', '<']), - (orbclient::K_PERIOD, ['.', '>']), - (orbclient::K_SLASH, ['/', '?']), - (orbclient::K_SPACE, [' ', ' ']), - ]; - - pub static GB: [(u8, [char; 2]); 54] = [ - (orbclient::K_ESC, ['\x1B', '\x1B']), - (orbclient::K_1, ['1', '!']), - (orbclient::K_2, ['2', '"']), - (orbclient::K_3, ['3', '£']), - (orbclient::K_4, ['4', '$']), - (orbclient::K_5, ['5', '%']), - (orbclient::K_6, ['6', '^']), - (orbclient::K_7, ['7', '&']), - (orbclient::K_8, ['8', '*']), - (orbclient::K_9, ['9', '(']), - (orbclient::K_0, ['0', ')']), - (orbclient::K_MINUS, ['-', '_']), - (orbclient::K_EQUALS, ['=', '+']), - (orbclient::K_BKSP, ['\x7F', '\x7F']), - (orbclient::K_TAB, ['\t', '\t']), - (orbclient::K_Q, ['q', 'Q']), - (orbclient::K_W, ['w', 'W']), - (orbclient::K_E, ['e', 'E']), - (orbclient::K_R, ['r', 'R']), - (orbclient::K_T, ['t', 'T']), - (orbclient::K_Y, ['y', 'Y']), - (orbclient::K_U, ['u', 'U']), - (orbclient::K_I, ['i', 'I']), - (orbclient::K_O, ['o', 'O']), - (orbclient::K_P, ['p', 'P']), - (orbclient::K_BRACE_OPEN, ['[', '{']), - (orbclient::K_BRACE_CLOSE, [']', '}']), - (orbclient::K_ENTER, ['\n', '\n']), - (orbclient::K_CTRL, ['\0', '\0']), - (orbclient::K_A, ['a', 'A']), - (orbclient::K_S, ['s', 'S']), - (orbclient::K_D, ['d', 'D']), - (orbclient::K_F, ['f', 'F']), - (orbclient::K_G, ['g', 'G']), - (orbclient::K_H, ['h', 'H']), - (orbclient::K_J, ['j', 'J']), - (orbclient::K_K, ['k', 'K']), - (orbclient::K_L, ['l', 'L']), - (orbclient::K_SEMICOLON, [';', ':']), - (orbclient::K_QUOTE, ['\'', '@']), - (orbclient::K_TICK, ['`', '¬']), - (orbclient::K_BACKSLASH, ['#', '~']), - (orbclient::K_Z, ['z', 'Z']), - (orbclient::K_X, ['x', 'X']), - (orbclient::K_C, ['c', 'C']), - (orbclient::K_V, ['v', 'V']), - (orbclient::K_B, ['b', 'B']), - (orbclient::K_N, ['n', 'N']), - (orbclient::K_M, ['m', 'M']), - (orbclient::K_COMMA, [',', '<']), - (orbclient::K_PERIOD, ['.', '>']), - (orbclient::K_SLASH, ['/', '?']), - (orbclient::K_SPACE, [' ', ' ']), - // UK Backslash, doesn't exist on US keyboard - (0x56, ['\\', '|']), - ]; - - pub static DVORAK: [(u8, [char; 2]); 53] = [ - (orbclient::K_ESC, ['\x1B', '\x1B']), - (orbclient::K_1, ['1', '!']), - (orbclient::K_2, ['2', '@']), - (orbclient::K_3, ['3', '#']), - (orbclient::K_4, ['4', '$']), - (orbclient::K_5, ['5', '%']), - (orbclient::K_6, ['6', '^']), - (orbclient::K_7, ['7', '&']), - (orbclient::K_8, ['8', '*']), - (orbclient::K_9, ['9', '(']), - (orbclient::K_0, ['0', ')']), - (orbclient::K_MINUS, ['[', '{']), - (orbclient::K_EQUALS, [']', '}']), - (orbclient::K_BKSP, ['\x7F', '\x7F']), - (orbclient::K_TAB, ['\t', '\t']), - (orbclient::K_Q, ['\'', '"']), - (orbclient::K_W, [',', '<']), - (orbclient::K_E, ['.', '>']), - (orbclient::K_R, ['p', 'P']), - (orbclient::K_T, ['y', 'Y']), - (orbclient::K_Y, ['f', 'F']), - (orbclient::K_U, ['g', 'G']), - (orbclient::K_I, ['c', 'C']), - (orbclient::K_O, ['r', 'R']), - (orbclient::K_P, ['l', 'L']), - (orbclient::K_BRACE_OPEN, ['/', '?']), - (orbclient::K_BRACE_CLOSE, ['=', '+']), - (orbclient::K_ENTER, ['\n', '\n']), - (orbclient::K_CTRL, ['\0', '\0']), - (orbclient::K_A, ['a', 'A']), - (orbclient::K_S, ['o', 'O']), - (orbclient::K_D, ['e', 'E']), - (orbclient::K_F, ['u', 'U']), - (orbclient::K_G, ['i', 'I']), - (orbclient::K_H, ['d', 'D']), - (orbclient::K_J, ['h', 'H']), - (orbclient::K_K, ['t', 'T']), - (orbclient::K_L, ['n', 'N']), - (orbclient::K_SEMICOLON, ['s', 'S']), - (orbclient::K_QUOTE, ['-', '_']), - (orbclient::K_TICK, ['`', '~']), - (orbclient::K_BACKSLASH, ['\\', '|']), - (orbclient::K_Z, [';', ':']), - (orbclient::K_X, ['q', 'Q']), - (orbclient::K_C, ['j', 'J']), - (orbclient::K_V, ['k', 'K']), - (orbclient::K_B, ['x', 'X']), - (orbclient::K_N, ['b', 'B']), - (orbclient::K_M, ['m', 'M']), - (orbclient::K_COMMA, ['w', 'W']), - (orbclient::K_PERIOD, ['v', 'V']), - (orbclient::K_SLASH, ['z', 'Z']), - (orbclient::K_SPACE, [' ', ' ']), - ]; - - pub static AZERTY: [(u8, [char; 2]); 53] = [ - (orbclient::K_ESC, ['\x1B', '\x1B']), - (orbclient::K_1, ['&', '1']), - (orbclient::K_2, ['é', '2']), - (orbclient::K_3, ['"', '3']), - (orbclient::K_4, ['\'', '4']), - (orbclient::K_5, ['(', '5']), - (orbclient::K_6, ['|', '6']), - (orbclient::K_7, ['è', '7']), - (orbclient::K_8, ['_', '8']), - (orbclient::K_9, ['ç', '9']), - (orbclient::K_0, ['à', '0']), - (orbclient::K_MINUS, [')', '°']), - (orbclient::K_EQUALS, ['=', '+']), - (orbclient::K_BKSP, ['\x7F', '\x7F']), - (orbclient::K_TAB, ['\t', '\t']), - (orbclient::K_Q, ['a', 'A']), - (orbclient::K_W, ['z', 'Z']), - (orbclient::K_E, ['e', 'E']), - (orbclient::K_R, ['r', 'R']), - (orbclient::K_T, ['t', 'T']), - (orbclient::K_Y, ['y', 'Y']), - (orbclient::K_U, ['u', 'U']), - (orbclient::K_I, ['i', 'I']), - (orbclient::K_O, ['o', 'O']), - (orbclient::K_P, ['p', 'P']), - (orbclient::K_BRACE_OPEN, ['^', '¨']), - (orbclient::K_BRACE_CLOSE, ['$', '£']), - (orbclient::K_ENTER, ['\n', '\n']), - (orbclient::K_CTRL, ['\0', '\0']), - (orbclient::K_A, ['q', 'Q']), - (orbclient::K_S, ['s', 'S']), - (orbclient::K_D, ['d', 'D']), - (orbclient::K_F, ['f', 'F']), - (orbclient::K_G, ['g', 'G']), - (orbclient::K_H, ['h', 'H']), - (orbclient::K_J, ['j', 'J']), - (orbclient::K_K, ['k', 'K']), - (orbclient::K_L, ['l', 'L']), - (orbclient::K_SEMICOLON, ['m', 'M']), - (orbclient::K_QUOTE, ['ù', '%']), - (orbclient::K_TICK, ['*', 'µ']), - (orbclient::K_BACKSLASH, ['ê', 'Ê']), - (orbclient::K_Z, ['w', 'W']), - (orbclient::K_X, ['x', 'X']), - (orbclient::K_C, ['c', 'C']), - (orbclient::K_V, ['v', 'V']), - (orbclient::K_B, ['b', 'B']), - (orbclient::K_N, ['n', 'N']), - (orbclient::K_M, [',', '?']), - (orbclient::K_COMMA, [';', '.']), - (orbclient::K_PERIOD, [':', '/']), - (orbclient::K_SLASH, ['!', '§']), - (orbclient::K_SPACE, [' ', ' ']), - ]; - - pub static BEPO: [(u8, [char; 2]); 53] = [ - (orbclient::K_ESC, ['\x1B', '\x1B']), - (orbclient::K_1, ['"', '1']), - (orbclient::K_2, ['«', '2']), - (orbclient::K_3, ['»', '3']), - (orbclient::K_4, ['(', '4']), - (orbclient::K_5, [')', '5']), - (orbclient::K_6, ['@', '6']), - (orbclient::K_7, ['+', '7']), - (orbclient::K_8, ['-', '8']), - (orbclient::K_9, ['/', '9']), - (orbclient::K_0, ['*', '0']), - (orbclient::K_MINUS, ['=', '°']), - (orbclient::K_EQUALS, ['%', '`']), - (orbclient::K_BKSP, ['\x7F', '\x7F']), - (orbclient::K_TAB, ['\t', '\t']), - (orbclient::K_Q, ['b', 'B']), - (orbclient::K_W, ['é', 'É']), - (orbclient::K_E, ['p', 'P']), - (orbclient::K_R, ['o', 'O']), - (orbclient::K_T, ['è', 'È']), - (orbclient::K_Y, ['^', '!']), - (orbclient::K_U, ['v', 'V']), - (orbclient::K_I, ['d', 'D']), - (orbclient::K_O, ['l', 'L']), - (orbclient::K_P, ['j', 'J']), - (orbclient::K_BRACE_OPEN, ['z', 'Z']), - (orbclient::K_BRACE_CLOSE, ['w', 'W']), - (orbclient::K_ENTER, ['\n', '\n']), - (orbclient::K_CTRL, ['\0', '\0']), - (orbclient::K_A, ['a', 'A']), - (orbclient::K_S, ['u', 'U']), - (orbclient::K_D, ['i', 'I']), - (orbclient::K_F, ['e', 'E']), - (orbclient::K_G, [',', ';']), - (orbclient::K_H, ['c', 'C']), - (orbclient::K_J, ['t', 'T']), - (orbclient::K_K, ['s', 'S']), - (orbclient::K_L, ['r', 'R']), - (orbclient::K_SEMICOLON, ['n', 'N']), - (orbclient::K_QUOTE, ['m', 'M']), - (orbclient::K_TICK, ['ç', 'Ç']), - (orbclient::K_BACKSLASH, ['ê', 'Ê']), - (orbclient::K_Z, ['à', 'À']), - (orbclient::K_X, ['y', 'Y']), - (orbclient::K_C, ['x', 'X']), - (orbclient::K_V, ['.', ':']), - (orbclient::K_B, ['k', 'K']), - (orbclient::K_N, ['\'', '?']), - (orbclient::K_M, ['q', 'Q']), - (orbclient::K_COMMA, ['g', 'G']), - (orbclient::K_PERIOD, ['h', 'H']), - (orbclient::K_SLASH, ['f', 'F']), - (orbclient::K_SPACE, [' ', ' ']), - ]; - - pub static IT: [(u8, [char; 2]); 53] = [ - (orbclient::K_ESC, ['\x1B', '\x1B']), - (orbclient::K_1, ['1', '!']), - (orbclient::K_2, ['2', '"']), - (orbclient::K_3, ['3', '£']), - (orbclient::K_4, ['4', '$']), - (orbclient::K_5, ['5', '%']), - (orbclient::K_6, ['6', '&']), - (orbclient::K_7, ['7', '/']), - (orbclient::K_8, ['8', '(']), - (orbclient::K_9, ['9', ')']), - (orbclient::K_0, ['0', '=']), - (orbclient::K_MINUS, ['?', '\'']), - (orbclient::K_EQUALS, ['ì', '^']), - (orbclient::K_BKSP, ['\x7F', '\x7F']), - (orbclient::K_TAB, ['\t', '\t']), - (orbclient::K_Q, ['q', 'Q']), - (orbclient::K_W, ['w', 'W']), - (orbclient::K_E, ['e', 'E']), - (orbclient::K_R, ['r', 'R']), - (orbclient::K_T, ['t', 'T']), - (orbclient::K_Y, ['y', 'Y']), - (orbclient::K_U, ['u', 'U']), - (orbclient::K_I, ['i', 'I']), - (orbclient::K_O, ['o', 'O']), - (orbclient::K_P, ['p', 'P']), - (orbclient::K_BRACE_OPEN, ['è', 'é']), - (orbclient::K_BRACE_CLOSE, ['+', '*']), - (orbclient::K_ENTER, ['\n', '\n']), - (orbclient::K_CTRL, ['\x20', '\x20']), - (orbclient::K_A, ['a', 'A']), - (orbclient::K_S, ['s', 'S']), - (orbclient::K_D, ['d', 'D']), - (orbclient::K_F, ['f', 'F']), - (orbclient::K_G, ['g', 'G']), - (orbclient::K_H, ['h', 'H']), - (orbclient::K_J, ['j', 'J']), - (orbclient::K_K, ['k', 'K']), - (orbclient::K_L, ['l', 'L']), - (orbclient::K_SEMICOLON, ['ò', 'ç']), - (orbclient::K_QUOTE, ['à', '°']), - (orbclient::K_TICK, ['ù', '§']), - (orbclient::K_BACKSLASH, ['<', '>']), - (orbclient::K_Z, ['z', 'Z']), - (orbclient::K_X, ['x', 'X']), - (orbclient::K_C, ['c', 'C']), - (orbclient::K_V, ['v', 'V']), - (orbclient::K_B, ['b', 'B']), - (orbclient::K_N, ['n', 'N']), - (orbclient::K_M, ['m', 'M']), - (orbclient::K_COMMA, [',', ';']), - (orbclient::K_PERIOD, ['.', ':']), - (orbclient::K_SLASH, ['-', '_']), - (orbclient::K_SPACE, [' ', ' ']), - ]; -} - -#[derive(Clone, Copy, Debug, PartialEq)] -#[repr(usize)] -pub enum KeymapKind { - US = 0, - GB, - Dvorak, - Azerty, - Bepo, - IT, -} - -impl From for KeymapKind { - fn from(value: usize) -> Self { - if value > (KeymapKind::IT as usize) { - KeymapKind::US - } else { - // SAFETY: Checked above - unsafe { std::mem::transmute(value) } - } - } -} - -#[allow(missing_copy_implementations)] -#[derive(Debug, PartialEq, Eq)] -pub struct ParseKeymapError(()); - -impl FromStr for KeymapKind { - type Err = ParseKeymapError; - - fn from_str(s: &str) -> Result { - let keymap = match s { - "dvorak" => KeymapKind::Dvorak, - "us" => KeymapKind::US, - "gb" => KeymapKind::GB, - "azerty" => KeymapKind::Azerty, - "bepo" => KeymapKind::Bepo, - "it" => KeymapKind::IT, - &_ => return Err(ParseKeymapError(())), - }; - - Ok(keymap) - } -} - -impl Display for KeymapKind { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let s = match *self { - KeymapKind::US => "us", - KeymapKind::GB => "gb", - KeymapKind::Dvorak => "dvorak", - KeymapKind::Azerty => "azerty", - KeymapKind::Bepo => "bepo", - KeymapKind::IT => "it", - }; - f.write_str(s) - } -} - -pub struct KeymapData { - pub keymap_hash: HashMap, - pub kind: KeymapKind, -} - -impl KeymapData { - pub fn new(kind: KeymapKind) -> Self { - let keymap_hash = match kind { - KeymapKind::US => HashMap::from(keymaps::US), - KeymapKind::GB => HashMap::from(keymaps::GB), - KeymapKind::Dvorak => HashMap::from(keymaps::DVORAK), - KeymapKind::Azerty => HashMap::from(keymaps::AZERTY), - KeymapKind::Bepo => HashMap::from(keymaps::BEPO), - KeymapKind::IT => HashMap::from(keymaps::IT), - }; - - Self { keymap_hash, kind } - } - - pub fn get_kind(&self) -> KeymapKind { - self.kind - } - - // TODO: AltGr, Numlock - pub fn get_char(&self, scancode: u8, shift: bool) -> char { - if let Some(c) = self.keymap_hash.get(&scancode) { - if shift { - c[1] - } else { - c[0] - } - } else { - '\0' - } - } -} diff --git a/recipes/core/base/drivers/inputd/src/lib.rs b/recipes/core/base/drivers/inputd/src/lib.rs deleted file mode 100644 index b68e8211f5..0000000000 --- a/recipes/core/base/drivers/inputd/src/lib.rs +++ /dev/null @@ -1,211 +0,0 @@ -use std::fs::{File, OpenOptions}; -use std::io::{self, Read, Write}; -use std::mem::size_of; -use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd}; -use std::os::unix::fs::OpenOptionsExt; -use std::path::PathBuf; -use std::slice; - -use libredox::flag::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; -use orbclient::Event; -use syscall::ESTALE; - -fn read_to_slice( - file: BorrowedFd, - buf: &mut [T], -) -> Result { - unsafe { - libredox::call::read( - file.as_raw_fd() as usize, - slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * size_of::()), - ) - .map(|count| count / size_of::()) - } -} - -pub unsafe fn any_as_u8_slice(p: &T) -> &[u8] { - slice::from_raw_parts((p as *const T) as *const u8, size_of::()) -} - -unsafe fn any_as_u8_slice_mut(p: &mut T) -> &mut [u8] { - slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::()) -} - -pub struct ConsumerHandle(File); - -pub enum ConsumerHandleEvent<'a> { - Events(&'a [Event]), - Handoff, -} - -impl ConsumerHandle { - pub fn new_vt() -> io::Result { - let file = OpenOptions::new() - .read(true) - .custom_flags(O_NONBLOCK as i32) - .open(format!("/scheme/input/consumer"))?; - Ok(Self(file)) - } - - pub fn bootlog_vt() -> io::Result { - let file = OpenOptions::new() - .read(true) - .custom_flags(O_NONBLOCK as i32) - .open(format!("/scheme/input/consumer_bootlog"))?; - Ok(Self(file)) - } - - pub fn event_handle(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } - - pub fn open_display_v2(&self) -> io::Result { - let mut buffer = [0; 1024]; - let fd = self.0.as_raw_fd(); - let written = libredox::call::fpath(fd as usize, &mut buffer)?; - - assert!(written <= buffer.len()); - - let mut display_path = PathBuf::from( - std::str::from_utf8(&buffer[..written]) - .expect("init: display path UTF-8 check failed") - .to_owned(), - ); - display_path.set_file_name(format!( - "v2/{}", - display_path.file_name().unwrap().to_str().unwrap() - )); - let display_path = display_path.to_str().unwrap(); - - let display_file = - libredox::call::open(display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) - .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) - .unwrap_or_else(|err| { - panic!("failed to open display {}: {}", display_path, err); - }); - - Ok(display_file) - } - - pub fn read_events<'a>(&self, events: &'a mut [Event]) -> io::Result> { - match read_to_slice(self.0.as_fd(), events) { - Ok(count) => Ok(ConsumerHandleEvent::Events(&events[..count])), - Err(err) if err.errno() == ESTALE => Ok(ConsumerHandleEvent::Handoff), - Err(err) => Err(err.into()), - } - } -} - -#[derive(Debug, Clone)] -#[repr(C)] -pub struct ControlEvent { - pub kind: usize, - pub data: usize, -} - -impl From for ControlEvent { - fn from(value: VtActivate) -> Self { - ControlEvent { - kind: 1, - data: value.vt, - } - } -} - -impl From for ControlEvent { - fn from(value: KeymapActivate) -> Self { - ControlEvent { - kind: 2, - data: value.keymap, - } - } -} - -pub struct VtActivate { - pub vt: usize, -} - -pub struct KeymapActivate { - pub keymap: usize, -} - -pub struct DisplayHandle(File); - -impl DisplayHandle { - pub fn new>(scheme_name: S) -> io::Result { - let path = format!("/scheme/input/handle/{}", scheme_name.into()); - Ok(Self(File::open(path)?)) - } - - pub fn new_early>(scheme_name: S) -> io::Result { - let path = format!("/scheme/input/handle_early/{}", scheme_name.into()); - Ok(Self(File::open(path)?)) - } - - pub fn read_vt_event(&mut self) -> io::Result> { - let mut event = VtEvent { - kind: VtEventKind::Activate, - vt: usize::MAX, - }; - - let nread = self.0.read(unsafe { any_as_u8_slice_mut(&mut event) })?; - - if nread == 0 { - Ok(None) - } else { - assert_eq!(nread, size_of::()); - Ok(Some(event)) - } - } - - pub fn inner(&self) -> BorrowedFd<'_> { - self.0.as_fd() - } -} - -pub struct ControlHandle(File); - -impl ControlHandle { - pub fn new() -> io::Result { - let path = format!("/scheme/input/control"); - Ok(Self(File::open(path)?)) - } - - /// Sent to Handle::Display - pub fn activate_vt(&mut self, vt: usize) -> io::Result { - let cmd = ControlEvent::from(VtActivate { vt }); - self.0.write(unsafe { any_as_u8_slice(&cmd) }) - } - - /// Sent to Handle::Producer - pub fn activate_keymap(&mut self, keymap: usize) -> io::Result { - let cmd = ControlEvent::from(KeymapActivate { keymap }); - self.0.write(unsafe { any_as_u8_slice(&cmd) }) - } -} - -#[derive(Debug)] -#[repr(usize)] -pub enum VtEventKind { - Activate, -} - -#[derive(Debug)] -#[repr(C)] -pub struct VtEvent { - pub kind: VtEventKind, - pub vt: usize, -} - -pub struct ProducerHandle(File); - -impl ProducerHandle { - pub fn new() -> io::Result { - File::open("/scheme/input/producer").map(ProducerHandle) - } - - pub fn write_event(&mut self, event: orbclient::Event) -> io::Result<()> { - self.0.write(&event)?; - Ok(()) - } -} diff --git a/recipes/core/base/drivers/inputd/src/main.rs b/recipes/core/base/drivers/inputd/src/main.rs deleted file mode 100644 index 9f24080c28..0000000000 --- a/recipes/core/base/drivers/inputd/src/main.rs +++ /dev/null @@ -1,663 +0,0 @@ -//! `:input` -//! -//! A seperate scheme is required since all of the input from different input devices is required -//! to be combined into a single stream which is later going to be processed by the "consumer" -//! which usually is Orbital. -//! -//! ## Input Device ("producer") -//! Write events to `input:producer`. -//! -//! ## Input Consumer ("consumer") -//! Read events from `input:consumer`. Optionally, set the `EVENT_READ` flag to be notified when -//! events are available. - -use core::mem::size_of; -use std::borrow::Cow; -use std::collections::BTreeSet; -use std::mem::transmute; -use std::ops::ControlFlow; -use std::sync::atomic::{AtomicUsize, Ordering}; - -use inputd::{ControlEvent, VtEvent, VtEventKind}; - -use libredox::errno::ESTALE; -use redox_scheme::scheme::SchemeSync; -use redox_scheme::{CallerCtx, OpenResult, Response, SignalBehavior, Socket}; - -use orbclient::{Event, EventOption}; -use scheme_utils::{Blocking, FpathWriter, HandleMap}; -use syscall::schemev2::NewFdFlags; -use syscall::{Error as SysError, EventFlags, EACCES, EBADF, EEXIST, EINVAL}; - -pub mod keymap; - -use keymap::KeymapKind; - -use crate::keymap::KeymapData; - -enum Handle { - Producer, - Consumer { - events: EventFlags, - pending: Vec, - /// We return an ESTALE error once to indicate that a handoff to a different graphics driver - /// is necessary. - needs_handoff: bool, - notified: bool, - vt: usize, - }, - Display { - events: EventFlags, - pending: Vec, - notified: bool, - device: String, - /// Control of all VT's gets handed over from earlyfb devices to the first non-earlyfb device. - is_earlyfb: bool, - }, - Control, - SchemeRoot, -} - -struct InputScheme { - handles: HandleMap, - - next_vt_id: AtomicUsize, - - display: Option, - vts: BTreeSet, - super_key: bool, - active_vt: Option, - active_keymap: KeymapData, - lshift: bool, - rshift: bool, - - has_new_events: bool, -} - -impl InputScheme { - fn new() -> Self { - Self { - handles: HandleMap::new(), - - next_vt_id: AtomicUsize::new(2), // VT 1 is reserved for the bootlog - - display: None, - vts: BTreeSet::new(), - super_key: false, - active_vt: None, - // TODO: configurable init? - active_keymap: KeymapData::new(KeymapKind::US), - lshift: false, - rshift: false, - has_new_events: false, - } - } - - fn switch_vt(&mut self, new_active: usize) { - if let Some(active_vt) = self.active_vt { - if new_active == active_vt { - return; - } - } - - if !self.vts.contains(&new_active) { - log::warn!("switch to non-existent VT #{new_active} was requested"); - return; - } - - log::debug!( - "switching from VT #{} to VT #{new_active}", - self.active_vt.unwrap_or(0) - ); - - for handle in self.handles.values_mut() { - match handle { - Handle::Display { - pending, - notified, - device, - .. - } => { - if self.display.as_deref() == Some(&*device) { - pending.push(VtEvent { - kind: VtEventKind::Activate, - vt: new_active, - }); - *notified = false; - } - } - _ => continue, - } - } - - self.active_vt = Some(new_active); - } - - fn switch_keymap(&mut self, new_active: usize) { - if new_active == self.active_keymap.get_kind() as usize { - return; - } - - log::debug!( - "switching from keymap #{} to keymap #{}", - self.active_keymap.get_kind(), - KeymapKind::from(new_active), - ); - - self.active_keymap = KeymapData::new(new_active.into()); - } -} - -impl SchemeSync for InputScheme { - fn scheme_root(&mut self) -> syscall::Result { - Ok(self.handles.insert(Handle::SchemeRoot)) - } - - fn openat( - &mut self, - dirfd: usize, - path: &str, - _flags: usize, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> syscall::Result { - if !matches!(self.handles.get(dirfd)?, Handle::SchemeRoot) { - return Err(SysError::new(EACCES)); - } - - let mut path_parts = path.split('/'); - - let command = path_parts.next().ok_or(SysError::new(EINVAL))?; - - let handle_ty = match command { - "producer" => Handle::Producer, - "consumer" => { - let vt = self.next_vt_id.fetch_add(1, Ordering::Relaxed); - self.vts.insert(vt); - - if self.active_vt.is_none() { - self.switch_vt(vt); - } - Handle::Consumer { - events: EventFlags::empty(), - pending: Vec::new(), - needs_handoff: false, - notified: false, - vt, - } - } - "consumer_bootlog" => { - if !self.vts.insert(1) { - return Err(SysError::new(EEXIST)); - } - - self.switch_vt(1); - Handle::Consumer { - events: EventFlags::empty(), - pending: Vec::new(), - needs_handoff: false, - notified: false, - vt: 1, - } - } - "handle" | "handle_early" => { - let display = path_parts.next().ok_or(SysError::new(EINVAL))?; - - let needs_handoff = match command { - "handle_early" => self.display.is_none(), - "handle" => self.handles.values().all(|handle| { - !matches!( - handle, - Handle::Display { - is_earlyfb: false, - .. - } - ) - }), - _ => unreachable!(), - }; - - if needs_handoff { - self.has_new_events = true; - self.display = Some(display.to_owned()); - - for handle in self.handles.values_mut() { - match handle { - Handle::Consumer { - needs_handoff, - notified, - .. - } => { - *needs_handoff = true; - *notified = false; - } - _ => continue, - } - } - } - - Handle::Display { - events: EventFlags::empty(), - pending: if let Some(active_vt) = self.active_vt { - vec![VtEvent { - kind: VtEventKind::Activate, - vt: active_vt, - }] - } else { - vec![] - }, - notified: false, - device: display.to_owned(), - is_earlyfb: command == "handle_early", - } - } - "control" => Handle::Control, - - _ => { - log::error!("invalid path '{path}'"); - return Err(SysError::new(EINVAL)); - } - }; - - log::debug!("{path} channel has been opened"); - - let fd = self.handles.insert(handle_ty); - Ok(OpenResult::ThisScheme { - number: fd, - flags: NewFdFlags::empty(), - }) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> syscall::Result { - let display = self.display.as_ref().ok_or(SysError::new(EINVAL))?; - FpathWriter::with(buf, display, |w| { - let handle = self.handles.get(id)?; - - if let Handle::Consumer { vt, .. } = handle { - write!(w, "{vt}").unwrap(); - Ok(()) - } else { - Err(SysError::new(EINVAL)) - } - }) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> syscall::Result { - let handle = self.handles.get_mut(id)?; - - match handle { - Handle::Consumer { - pending, - needs_handoff, - .. - } => { - if *needs_handoff { - *needs_handoff = false; - // Indicates that handoff to a new graphics driver is necessary. - return Err(SysError::new(ESTALE)); - } - - let copy = core::cmp::min(pending.len(), buf.len()); - - for (i, byte) in pending.drain(..copy).enumerate() { - buf[i] = byte; - } - - Ok(copy) - } - - Handle::Display { pending, .. } => { - if buf.len() % size_of::() == 0 { - let copy = core::cmp::min(pending.len(), buf.len() / size_of::()); - - for (i, event) in pending.drain(..copy).enumerate() { - buf[i * size_of::()..(i + 1) * size_of::()] - .copy_from_slice(&unsafe { - transmute::()]>(event) - }); - } - Ok(copy * size_of::()) - } else { - log::error!("display tried to read incorrectly sized event"); - return Err(SysError::new(EINVAL)); - } - } - - Handle::Producer => { - log::error!("producer tried to read"); - return Err(SysError::new(EINVAL)); - } - Handle::Control => { - log::error!("control tried to read"); - return Err(SysError::new(EINVAL)); - } - Handle::SchemeRoot => return Err(SysError::new(EBADF)), - } - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> syscall::Result { - self.has_new_events = true; - - let handle = self.handles.get_mut(id)?; - - match handle { - Handle::Control => { - if buf.len() != size_of::() { - log::error!("control tried to write incorrectly sized command"); - return Err(SysError::new(EINVAL)); - } - - // SAFETY: We have verified the size of the buffer above. - let cmd = unsafe { &*buf.as_ptr().cast::() }; - - match cmd.kind { - 1 => self.switch_vt(cmd.data), - 2 => self.switch_keymap(cmd.data), - k => { - log::warn!("unknown control {}", k); - } - } - - return Ok(buf.len()); - } - - Handle::Consumer { .. } => { - log::error!("consumer tried to write"); - return Err(SysError::new(EINVAL)); - } - Handle::Display { .. } => { - log::error!("display tried to write"); - return Err(SysError::new(EINVAL)); - } - Handle::Producer => {} - Handle::SchemeRoot => return Err(SysError::new(EBADF)), - } - - if buf.len() == 1 && buf[0] > 0xf4 { - return Ok(1); - } - - let mut events = Cow::from(unsafe { - core::slice::from_raw_parts( - buf.as_ptr() as *const Event, - buf.len() / size_of::(), - ) - }); - - for i in 0..events.len() { - let mut new_active_opt = None; - match events[i].to_option() { - EventOption::Key(mut key_event) => match key_event.scancode { - f @ orbclient::K_F1..=orbclient::K_F10 if self.super_key => { - new_active_opt = Some((f - 0x3A) as usize); - } - orbclient::K_F11 if self.super_key => { - new_active_opt = Some(11); - } - orbclient::K_F12 if self.super_key => { - new_active_opt = Some(12); - } - orbclient::K_SUPER => { - self.super_key = key_event.pressed; - } - orbclient::K_LEFT_SHIFT => { - self.lshift = key_event.pressed; - } - orbclient::K_RIGHT_SHIFT => { - self.rshift = key_event.pressed; - } - - key => { - let shift = self.lshift | self.rshift; - let ev = self.active_keymap.get_char(key, shift); - key_event.character = ev; - events.to_mut()[i] = key_event.to_event(); - } - }, - - _ => continue, - } - - if let Some(new_active) = new_active_opt { - self.switch_vt(new_active); - } - } - - let handle = self.handles.get_mut(id)?; - assert!(matches!(handle, Handle::Producer)); - - let buf = unsafe { - core::slice::from_raw_parts( - (events.as_ptr()) as *const u8, - events.len() * size_of::(), - ) - }; - - if let Some(active_vt) = self.active_vt { - for handle in self.handles.values_mut() { - match handle { - Handle::Consumer { - pending, - notified, - vt, - .. - } => { - if *vt != active_vt { - continue; - } - - pending.extend_from_slice(buf); - *notified = false; - } - _ => continue, - } - } - } - - Ok(buf.len()) - } - - fn fevent( - &mut self, - id: usize, - flags: syscall::EventFlags, - _ctx: &CallerCtx, - ) -> syscall::Result { - match self.handles.get_mut(id)? { - Handle::Consumer { - ref mut events, - ref mut notified, - .. - } => { - *events = flags; - *notified = false; - Ok(EventFlags::empty()) - } - Handle::Display { - ref mut events, - ref mut notified, - .. - } => { - *events = flags; - *notified = false; - Ok(EventFlags::empty()) - } - Handle::Producer | Handle::Control => { - log::error!("producer or control tried to use an event queue"); - Err(SysError::new(EINVAL)) - } - Handle::SchemeRoot => Err(SysError::new(EBADF)), - } - } - - fn on_close(&mut self, id: usize) { - match self.handles.remove(id).unwrap() { - Handle::Consumer { vt, .. } => { - self.vts.remove(&vt); - if self.active_vt == Some(vt) { - if let Some(&new_vt) = self.vts.last() { - self.switch_vt(new_vt); - } else { - self.active_vt = None; - } - } - } - _ => {} - } - } -} - -fn daemon(daemon: daemon::SchemeDaemon) -> anyhow::Result<()> { - // Create the ":input" scheme. - let socket_file = Socket::create()?; - let mut scheme = InputScheme::new(); - let mut handler = Blocking::new(&socket_file, 16); - - let _ = daemon.ready_sync_scheme(&socket_file, &mut scheme); - - loop { - scheme.has_new_events = false; - match handler.process_requests_nonblocking(&mut scheme)? { - ControlFlow::Continue(()) => {} - ControlFlow::Break(()) => unreachable!("scheme should be non-blocking"), - } - - if !scheme.has_new_events { - continue; - } - - for (id, handle) in scheme.handles.iter_mut() { - match handle { - Handle::Consumer { - events, - pending, - needs_handoff, - ref mut notified, - .. - } => { - if (!*needs_handoff && pending.is_empty()) - || *notified - || !events.contains(EventFlags::EVENT_READ) - { - continue; - } - - // Notify the consumer that we have some events to read. Yum yum. - socket_file.write_response( - Response::post_fevent(*id, EventFlags::EVENT_READ.bits()), - SignalBehavior::Restart, - )?; - - *notified = true; - } - Handle::Display { - events, - pending, - ref mut notified, - .. - } => { - if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) { - continue; - } - - // Notify the consumer that we have some events to read. Yum yum. - socket_file.write_response( - Response::post_fevent(*id, EventFlags::EVENT_READ.bits()), - SignalBehavior::Restart, - )?; - - *notified = true; - } - _ => {} - } - } - } -} - -fn daemon_runner(redox_daemon: daemon::SchemeDaemon) -> ! { - daemon(redox_daemon).unwrap(); - unreachable!(); -} - -const HELP: &str = r#" -inputd [-K keymap|-A vt|--keymaps] - -A vt : set current virtual display - -K keymap : set keyboard mapping - --keymaps : list available keyboard mappings -"#; - -fn main() { - let mut args = std::env::args().skip(1); - - if let Some(val) = args.next() { - // TODO: Get current VT or keymap - match val.as_ref() { - // Activates a VT. - "-A" => { - let vt = args.next().unwrap().parse::().unwrap(); - - let mut handle = - inputd::ControlHandle::new().expect("inputd: failed to open control handle"); - handle - .activate_vt(vt) - .expect("inputd: failed to activate VT"); - } - // Activates a keymap. - "-K" => { - let arg = if let Some(a) = args.next() { - a - } else { - eprintln!("Error: Option -K requires a layout argument."); - std::process::exit(1); - }; - - let vt: KeymapKind = arg.to_ascii_lowercase().parse().unwrap_or_else(|_| { - eprintln!("inputd: unrecognized keymap code (see: inputd --keymaps)"); - std::process::exit(1); - }); - - let mut handle = - inputd::ControlHandle::new().expect("inputd: failed to open control handle"); - handle - .activate_keymap(vt as usize) - .expect("inputd: failed to activate keymap"); - } - // List available keymaps - "--keymaps" => { - // TODO: configurable KeymapKind using files - for key in vec!["dvorak", "us", "gb", "azerty", "bepo", "it"] { - println!("{}", key); - } - } - "--help" => { - println!("{}", HELP); - } - - _ => panic!("inputd: invalid argument: {}", val), - } - } else { - common::setup_logging( - "input", - "inputd", - "inputd", - common::output_level(), - common::file_level(), - ); - - daemon::SchemeDaemon::new(daemon_runner); - } -} diff --git a/recipes/core/base/drivers/net/driver-network/Cargo.toml b/recipes/core/base/drivers/net/driver-network/Cargo.toml deleted file mode 100644 index fc8179086f..0000000000 --- a/recipes/core/base/drivers/net/driver-network/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "driver-network" -description = "Shared networking code library" -version = "0.1.0" -edition = "2021" - -[dependencies] -libredox.workspace = true -daemon = { path = "../../../daemon" } -redox-scheme.workspace = true -scheme-utils = { path = "../../../scheme-utils" } -redox_syscall = { workspace = true, features = ["std"] } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/net/driver-network/src/lib.rs b/recipes/core/base/drivers/net/driver-network/src/lib.rs deleted file mode 100644 index 39d26d851b..0000000000 --- a/recipes/core/base/drivers/net/driver-network/src/lib.rs +++ /dev/null @@ -1,354 +0,0 @@ -use std::{cmp, io}; - -use libredox::flag::O_NONBLOCK; -use libredox::Fd; -use redox_scheme::{ - scheme::{IntoTag, Op, SchemeResponse, SchemeState, SchemeSync}, - CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket, -}; -use scheme_utils::{FpathWriter, HandleMap}; -use syscall::schemev2::NewFdFlags; -use syscall::{ - Error, EventFlags, Result, Stat, EACCES, EAGAIN, EBADF, EINTR, EINVAL, EWOULDBLOCK, MODE_FILE, -}; - -pub trait NetworkAdapter { - /// The [MAC address](https://en.wikipedia.org/wiki/MAC_address) of this - /// network adapter. - fn mac_address(&mut self) -> [u8; 6]; - - /// The amount of network packets that can be read without blocking. - fn available_for_read(&mut self) -> usize; - - /// Attempt to read a network packet without blocking. - /// - /// Returns `Ok(None)` when there is no pending network packet. - fn read_packet(&mut self, buf: &mut [u8]) -> Result>; - - /// Write a single network packet. - // FIXME support back pressure on writes by returning EWOULDBLOCK or not - // returning from the write syscall until there is room. - fn write_packet(&mut self, buf: &[u8]) -> Result; -} - -pub struct NetworkScheme { - scheme: NetworkSchemeInner, - state: SchemeState, - blocked: Vec<(Op, CallerCtx)>, - socket: Socket, -} - -fn post_fevent(socket: &Socket, id: usize, flags: usize) -> Result<()> { - let fevent_response = Response::post_fevent(id, flags); - match socket.write_response(fevent_response, SignalBehavior::Restart) { - Ok(true) => Ok(()), // Write response success - Ok(false) => Err(Error::new(syscall::EAGAIN)), // Write response failed, retry. - Err(err) => Err(err), // Error writing response - } -} - -impl NetworkScheme { - pub fn new( - adapter_fn: impl FnOnce() -> T, - daemon: daemon::Daemon, - scheme_name: String, - ) -> Self { - assert!(scheme_name.starts_with("network")); - let socket = Socket::nonblock().expect("failed to create network scheme"); - let adapter = adapter_fn(); - let mut scheme = NetworkSchemeInner::new(adapter, scheme_name.clone()); - redox_scheme::scheme::register_sync_scheme(&socket, &scheme_name, &mut scheme) - .expect("failed to regitster network scheme"); - daemon.ready(); - Self { - scheme, - state: SchemeState::new(), - blocked: Vec::new(), - socket, - } - } - - pub fn event_handle(&self) -> &Fd { - self.socket.inner() - } - - pub fn adapter(&self) -> &T { - &self.scheme.adapter - } - - pub fn adapter_mut(&mut self) -> &mut T { - &mut self.scheme.adapter - } - - /// Process pending and new requests. - /// - /// This needs to be called each time there is a new event on the scheme - /// file and each time a new network packet has been received by the - /// driver. - // FIXME maybe split into one method for events on the scheme fd and one - // to call when an irq is received to indicate that blocked requests can - // be processed. - pub fn tick(&mut self) -> io::Result<()> { - // Handle any blocked requests - let mut i = 0; - while i < self.blocked.len() { - let (op, caller) = &mut self.blocked[i]; - let res = op.handle_sync_dont_consume(caller, &mut self.scheme, &mut self.state); - match res { - SchemeResponse::Opened(Err(Error { - errno: syscall::EWOULDBLOCK, - })) - | SchemeResponse::Regular(Err(Error { - errno: syscall::EWOULDBLOCK, - })) if !op.is_explicitly_nonblock() => { - i += 1; - } - SchemeResponse::Regular(r) => { - let (op, _) = self.blocked.remove(i); - let _ = self - .socket - .write_response(Response::new(r, op), SignalBehavior::Restart) - .expect("driver-network: failed to write scheme"); - } - SchemeResponse::Opened(o) => { - let (op, _) = self.blocked.remove(i); - let _ = self - .socket - .write_response(Response::open_dup_like(o, op), SignalBehavior::Restart) - .expect("driver-network: failed to write scheme"); - } - SchemeResponse::RegularAndNotifyOnDetach(status) => { - let (op, _) = self.blocked.remove(i); - let _ = self - .socket - .write_response( - Response::new_notify_on_detach(status, op), - SignalBehavior::Restart, - ) - .expect("driver-network: failed to write scheme"); - } - } - } - - // Handle new scheme requests - loop { - let request = match self.socket.next_request(SignalBehavior::Restart) { - Ok(Some(request)) => request, - Ok(None) => { - // Scheme likely got unmounted - std::process::exit(0); - } - Err(err) if err.errno == EAGAIN => break, - Err(err) => return Err(err.into()), - }; - - let req = match request.kind() { - RequestKind::Call(c) => c, - RequestKind::OnClose { id } => { - self.scheme.on_close(id); - continue; - } - RequestKind::Cancellation(req) => { - if let Some(i) = self.blocked.iter().position(|q| q.0.req_id() == req.id) { - let (blocked_req, _) = self.blocked.remove(i); - let resp = Response::new(Err(Error::new(EINTR)), blocked_req); - self.socket.write_response(resp, SignalBehavior::Restart)?; - } - continue; - } - _ => { - continue; - } - }; - let caller = req.caller(); - let mut op = match req.op() { - Ok(op) => op, - Err(req) => { - self.socket.write_response( - Response::err(syscall::EOPNOTSUPP, req), - SignalBehavior::Restart, - )?; - continue; - } - }; - - let resp = match op.handle_sync_dont_consume(&caller, &mut self.scheme, &mut self.state) - { - SchemeResponse::Opened(Err(Error { - errno: syscall::EWOULDBLOCK, - })) - | SchemeResponse::Regular(Err(Error { - errno: syscall::EWOULDBLOCK, - })) if !op.is_explicitly_nonblock() => { - self.blocked.push((op, caller)); - continue; - } - SchemeResponse::Regular(r) => Response::new(r, op), - SchemeResponse::Opened(o) => Response::open_dup_like(o, op), - SchemeResponse::RegularAndNotifyOnDetach(status) => { - Response::new_notify_on_detach(status, op) - } - }; - let _ = self.socket.write_response(resp, SignalBehavior::Restart)?; - } - - // Notify readers about incoming events - let available_for_read = self.scheme.adapter.available_for_read(); - if available_for_read > 0 { - for &handle_id in self.scheme.handles.keys() { - post_fevent(&self.socket, handle_id, syscall::flag::EVENT_READ.bits())?; - } - return Ok(()); - } - - Ok(()) - } -} - -struct NetworkSchemeInner { - adapter: T, - scheme_name: String, - handles: HandleMap, -} - -enum Handle { - Data, - Mac, - SchemeRoot, -} - -impl NetworkSchemeInner { - pub fn new(adapter: T, scheme_name: String) -> Self { - Self { - adapter, - scheme_name, - handles: HandleMap::new(), - } - } -} - -impl SchemeSync for NetworkSchemeInner { - fn scheme_root(&mut self) -> Result { - Ok(self.handles.insert(Handle::SchemeRoot)) - } - - fn openat( - &mut self, - fd: usize, - path: &str, - _flags: usize, - _fcntl_flags: u32, - ctx: &CallerCtx, - ) -> Result { - if !matches!(self.handles.get(fd)?, Handle::SchemeRoot) { - return Err(Error::new(EACCES)); - } - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - - let (handle, flags) = match path { - "" => (Handle::Data, NewFdFlags::empty()), - "mac" => (Handle::Mac, NewFdFlags::POSITIONED), - _ => return Err(Error::new(EINVAL)), - }; - - let id = self.handles.insert(handle); - Ok(OpenResult::ThisScheme { number: id, flags }) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - let handle = self.handles.get_mut(id)?; - - match *handle { - Handle::Data => {} - Handle::Mac => { - let data = &self.adapter.mac_address()[offset as usize..]; - let i = cmp::min(buf.len(), data.len()); - buf[..i].copy_from_slice(&data[..i]); - return Ok(i); - } - _ => return Err(Error::new(EBADF)), - }; - - match self.adapter.read_packet(buf)? { - Some(count) => Ok(count), - None => { - if fcntl_flags & O_NONBLOCK as u32 != 0 { - Err(Error::new(EAGAIN)) - } else { - Err(Error::new(EWOULDBLOCK)) - } - } - } - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - let handle = self.handles.get(id)?; - - match handle { - Handle::Data => {} - Handle::Mac { .. } => return Err(Error::new(EINVAL)), - _ => return Err(Error::new(EBADF)), - } - - Ok(self.adapter.write_packet(buf)?) - } - - fn fevent(&mut self, id: usize, _flags: EventFlags, _ctx: &CallerCtx) -> Result { - let _handle = self.handles.get(id)?; - Ok(EventFlags::empty()) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with(buf, &self.scheme_name, |w| { - let path = match self.handles.get(id)? { - Handle::Data { .. } => "", - Handle::Mac { .. } => "mac", - _ => "", - }; - write!(w, "{path}").unwrap(); - Ok(()) - }) - } - - fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { - let handle = self.handles.get(id)?; - - match handle { - Handle::Data { .. } => { - stat.st_mode = MODE_FILE | 0o700; - } - Handle::Mac { .. } => { - stat.st_mode = MODE_FILE | 0o400; - stat.st_size = 6; - } - _ => return Err(Error::new(EBADF)), - } - - Ok(()) - } - - fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> { - let _handle = self.handles.get(id)?; - Ok(()) - } - - fn on_close(&mut self, id: usize) { - self.handles.remove(id); - } -} diff --git a/recipes/core/base/drivers/net/e1000d/Cargo.toml b/recipes/core/base/drivers/net/e1000d/Cargo.toml deleted file mode 100644 index 43ef78f4de..0000000000 --- a/recipes/core/base/drivers/net/e1000d/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "e1000d" -description = "Intel Gigabit ethernet driver" -version = "0.1.0" -edition = "2018" - -[dependencies] -bitflags.workspace = true -log.workspace = true -libredox.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-network = { path = "../driver-network" } -pcid = { path = "../../pcid" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/net/e1000d/config.toml b/recipes/core/base/drivers/net/e1000d/config.toml deleted file mode 100644 index 4862da27dc..0000000000 --- a/recipes/core/base/drivers/net/e1000d/config.toml +++ /dev/null @@ -1,5 +0,0 @@ -[[drivers]] -name = "E1000 NIC" -class = 0x02 -ids = { 0x8086 = [0x1004, 0x100e, 0x100f, 0x109a, 0x1503] } -command = ["e1000d"] diff --git a/recipes/core/base/drivers/net/e1000d/src/device.rs b/recipes/core/base/drivers/net/e1000d/src/device.rs deleted file mode 100644 index 4c518f30fc..0000000000 --- a/recipes/core/base/drivers/net/e1000d/src/device.rs +++ /dev/null @@ -1,368 +0,0 @@ -use std::convert::TryInto; -use std::{cmp, mem, ptr, slice, thread, time}; - -use driver_network::NetworkAdapter; - -use syscall::error::Result; - -use common::dma::Dma; - -const CTRL: u32 = 0x00; -const CTRL_LRST: u32 = 1 << 3; -const CTRL_ASDE: u32 = 1 << 5; -const CTRL_SLU: u32 = 1 << 6; -const CTRL_ILOS: u32 = 1 << 7; -const CTRL_RST: u32 = 1 << 26; -const CTRL_VME: u32 = 1 << 30; -const CTRL_PHY_RST: u32 = 1 << 31; - -const STATUS: u32 = 0x08; - -const FCAL: u32 = 0x28; -const FCAH: u32 = 0x2C; -const FCT: u32 = 0x30; -const FCTTV: u32 = 0x170; - -const ICR: u32 = 0xC0; - -const IMS: u32 = 0xD0; -const IMS_TXDW: u32 = 1; -const IMS_TXQE: u32 = 1 << 1; -const IMS_LSC: u32 = 1 << 2; -const IMS_RXSEQ: u32 = 1 << 3; -const IMS_RXDMT: u32 = 1 << 4; -const IMS_RX: u32 = 1 << 6; -const IMS_RXT: u32 = 1 << 7; - -const RCTL: u32 = 0x100; -const RCTL_EN: u32 = 1 << 1; -const RCTL_UPE: u32 = 1 << 3; -const RCTL_MPE: u32 = 1 << 4; -const RCTL_LPE: u32 = 1 << 5; -const RCTL_LBM: u32 = 1 << 6 | 1 << 7; -const RCTL_BAM: u32 = 1 << 15; -const RCTL_BSIZE1: u32 = 1 << 16; -const RCTL_BSIZE2: u32 = 1 << 17; -const RCTL_BSEX: u32 = 1 << 25; -const RCTL_SECRC: u32 = 1 << 26; - -const RDBAL: u32 = 0x2800; -const RDBAH: u32 = 0x2804; -const RDLEN: u32 = 0x2808; -const RDH: u32 = 0x2810; -const RDT: u32 = 0x2818; - -const RAL0: u32 = 0x5400; -const RAH0: u32 = 0x5404; - -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -struct Rd { - buffer: u64, - length: u16, - checksum: u16, - status: u8, - error: u8, - special: u16, -} -const RD_DD: u8 = 1; -const RD_EOP: u8 = 1 << 1; - -const TCTL: u32 = 0x400; -const TCTL_EN: u32 = 1 << 1; -const TCTL_PSP: u32 = 1 << 3; - -const TDBAL: u32 = 0x3800; -const TDBAH: u32 = 0x3804; -const TDLEN: u32 = 0x3808; -const TDH: u32 = 0x3810; -const TDT: u32 = 0x3818; - -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -struct Td { - buffer: u64, - length: u16, - cso: u8, - command: u8, - status: u8, - css: u8, - special: u16, -} -const TD_CMD_EOP: u8 = 1; -const TD_CMD_IFCS: u8 = 1 << 1; -const TD_CMD_RS: u8 = 1 << 3; -const TD_DD: u8 = 1; - -pub struct Intel8254x { - base: usize, - mac_address: [u8; 6], - receive_buffer: [Dma<[u8; 16384]>; 16], - receive_ring: Dma<[Rd; 16]>, - receive_index: usize, - transmit_buffer: [Dma<[u8; 16384]>; 16], - transmit_ring: Dma<[Td; 16]>, - transmit_ring_free: usize, - transmit_index: usize, - transmit_clean_index: usize, -} - -#[derive(Copy, Clone)] -pub enum Handle { - Data { flags: usize }, - Mac { offset: usize }, -} - -fn wrap_ring(index: usize, ring_size: usize) -> usize { - (index + 1) & (ring_size - 1) -} - -impl NetworkAdapter for Intel8254x { - fn mac_address(&mut self) -> [u8; 6] { - self.mac_address - } - - fn available_for_read(&mut self) -> usize { - let desc = unsafe { &*(self.receive_ring.as_ptr().add(self.receive_index) as *const Rd) }; - - if desc.status & RD_DD == RD_DD { - return desc.length as usize; - } - - 0 - } - - fn read_packet(&mut self, buf: &mut [u8]) -> Result> { - let desc = unsafe { &mut *(self.receive_ring.as_ptr().add(self.receive_index) as *mut Rd) }; - - if desc.status & RD_DD == RD_DD { - desc.status = 0; - - let data = &self.receive_buffer[self.receive_index][..desc.length as usize]; - - let i = cmp::min(buf.len(), data.len()); - buf[..i].copy_from_slice(&data[..i]); - - unsafe { self.write_reg(RDT, self.receive_index as u32) }; - self.receive_index = wrap_ring(self.receive_index, self.receive_ring.len()); - - return Ok(Some(i)); - } - - Ok(None) - } - - fn write_packet(&mut self, buf: &[u8]) -> Result { - if self.transmit_ring_free == 0 { - loop { - let desc = unsafe { - &*(self.transmit_ring.as_ptr().add(self.transmit_clean_index) as *const Td) - }; - - if desc.status != 0 { - self.transmit_clean_index = - wrap_ring(self.transmit_clean_index, self.transmit_ring.len()); - self.transmit_ring_free += 1; - } else if self.transmit_ring_free > 0 { - break; - } - - if self.transmit_ring_free >= self.transmit_ring.len() { - break; - } - } - } - - let desc = - unsafe { &mut *(self.transmit_ring.as_ptr().add(self.transmit_index) as *mut Td) }; - - let data = unsafe { - slice::from_raw_parts_mut( - self.transmit_buffer[self.transmit_index].as_ptr() as *mut u8, - cmp::min(buf.len(), self.transmit_buffer[self.transmit_index].len()) as usize, - ) - }; - - let i = cmp::min(buf.len(), data.len()); - data[..i].copy_from_slice(&buf[..i]); - - desc.cso = 0; - desc.command = TD_CMD_EOP | TD_CMD_IFCS | TD_CMD_RS; - desc.status = 0; - desc.css = 0; - desc.special = 0; - - desc.length = (cmp::min( - buf.len(), - self.transmit_buffer[self.transmit_index].len() - 1, - )) as u16; - - self.transmit_index = wrap_ring(self.transmit_index, self.transmit_ring.len()); - self.transmit_ring_free -= 1; - - unsafe { self.write_reg(TDT, self.transmit_index as u32) }; - - Ok(i) - } -} - -fn dma_array() -> Result<[Dma; N]> { - Ok((0..N) - .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) - .collect::>>()? - .try_into() - .unwrap_or_else(|_| unreachable!())) -} -impl Intel8254x { - pub unsafe fn new(base: usize) -> Result { - #[rustfmt::skip] - let mut module = Intel8254x { - base, - mac_address: [0; 6], - receive_buffer: dma_array()?, - receive_ring: Dma::zeroed()?.assume_init(), - transmit_buffer: dma_array()?, - receive_index: 0, - transmit_ring: Dma::zeroed()?.assume_init(), - transmit_ring_free: 16, - transmit_index: 0, - transmit_clean_index: 0, - }; - - module.init(); - - Ok(module) - } - - pub unsafe fn irq(&self) -> bool { - let icr = self.read_reg(ICR); - icr != 0 - } - - pub unsafe fn read_reg(&self, register: u32) -> u32 { - ptr::read_volatile((self.base + register as usize) as *mut u32) - } - - pub unsafe fn write_reg(&self, register: u32, data: u32) -> u32 { - ptr::write_volatile((self.base + register as usize) as *mut u32, data); - ptr::read_volatile((self.base + register as usize) as *mut u32) - } - - pub unsafe fn flag(&self, register: u32, flag: u32, value: bool) { - if value { - self.write_reg(register, self.read_reg(register) | flag); - } else { - self.write_reg(register, self.read_reg(register) & !flag); - } - } - - pub unsafe fn init(&mut self) { - self.flag(CTRL, CTRL_RST, true); - while self.read_reg(CTRL) & CTRL_RST == CTRL_RST { - log::trace!("Waiting for reset: {:X}", self.read_reg(CTRL)); - } - - // Enable auto negotiate, link, clear reset, do not Invert Loss-Of Signal - self.flag(CTRL, CTRL_ASDE | CTRL_SLU, true); - self.flag(CTRL, CTRL_LRST | CTRL_PHY_RST | CTRL_ILOS, false); - - // No flow control - self.write_reg(FCAH, 0); - self.write_reg(FCAL, 0); - self.write_reg(FCT, 0); - self.write_reg(FCTTV, 0); - - // Do not use VLANs - self.flag(CTRL, CTRL_VME, false); - - // TODO: Clear statistical counters - - let mac_low = self.read_reg(RAL0); - let mac_high = self.read_reg(RAH0); - let mac = [ - mac_low as u8, - (mac_low >> 8) as u8, - (mac_low >> 16) as u8, - (mac_low >> 24) as u8, - mac_high as u8, - (mac_high >> 8) as u8, - ]; - log::debug!( - "MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac[0], - mac[1], - mac[2], - mac[3], - mac[4], - mac[5] - ); - self.mac_address = mac; - - // - // MTA => 0; - // - - // Receive Buffer - for i in 0..self.receive_ring.len() { - self.receive_ring[i].buffer = self.receive_buffer[i].physical() as u64; - } - - self.write_reg(RDBAH, ((self.receive_ring.physical() as u64) >> 32) as u32); - self.write_reg(RDBAL, self.receive_ring.physical() as u32); - self.write_reg( - RDLEN, - (self.receive_ring.len() * mem::size_of::()) as u32, - ); - self.write_reg(RDH, 0); - self.write_reg(RDT, self.receive_ring.len() as u32 - 1); - - // Transmit Buffer - for i in 0..self.transmit_ring.len() { - self.transmit_ring[i].buffer = self.transmit_buffer[i].physical() as u64; - } - - self.write_reg(TDBAH, ((self.transmit_ring.physical() as u64) >> 32) as u32); - self.write_reg(TDBAL, self.transmit_ring.physical() as u32); - self.write_reg( - TDLEN, - (self.transmit_ring.len() * mem::size_of::()) as u32, - ); - self.write_reg(TDH, 0); - self.write_reg(TDT, 0); - - self.write_reg(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ); // | IMS_LSC | IMS_TXQE | IMS_TXDW - - self.flag(RCTL, RCTL_EN, true); - self.flag(RCTL, RCTL_UPE, true); - // self.flag(RCTL, RCTL_MPE, true); - self.flag(RCTL, RCTL_LPE, true); - self.flag(RCTL, RCTL_LBM, false); - // RCTL.RDMTS = Minimum threshold size ??? - // RCTL.MO = Multicast offset - self.flag(RCTL, RCTL_BAM, true); - self.flag(RCTL, RCTL_BSIZE1, true); - self.flag(RCTL, RCTL_BSIZE2, false); - self.flag(RCTL, RCTL_BSEX, true); - self.flag(RCTL, RCTL_SECRC, true); - - self.flag(TCTL, TCTL_EN, true); - self.flag(TCTL, TCTL_PSP, true); - // TCTL.CT = Collision threshold - // TCTL.COLD = Collision distance - // TIPG Packet Gap - // TODO ... - - log::debug!("Waiting for link up: {:X}", self.read_reg(STATUS)); - while self.read_reg(STATUS) & 2 != 2 { - thread::sleep(time::Duration::from_millis(100)); - } - log::debug!( - "Link is up with speed {}", - match (self.read_reg(STATUS) >> 6) & 0b11 { - 0b00 => "10 Mb/s", - 0b01 => "100 Mb/s", - _ => "1000 Mb/s", - } - ); - } -} diff --git a/recipes/core/base/drivers/net/e1000d/src/main.rs b/recipes/core/base/drivers/net/e1000d/src/main.rs deleted file mode 100644 index 373ea9b38b..0000000000 --- a/recipes/core/base/drivers/net/e1000d/src/main.rs +++ /dev/null @@ -1,90 +0,0 @@ -use std::io::{Read, Write}; -use std::os::unix::io::AsRawFd; - -use driver_network::NetworkScheme; -use event::{user_data, EventQueue}; -use pcid_interface::PciFunctionHandle; - -pub mod device; - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - let pci_config = pcid_handle.config(); - - let mut name = pci_config.func.name(); - name.push_str("_e1000"); - - common::setup_logging( - "net", - "pci", - &name, - common::output_level(), - common::file_level(), - ); - - let irq = pci_config - .func - .legacy_interrupt_line - .expect("e1000d: no legacy interrupts supported"); - - log::info!("E1000 {}", pci_config.func.display()); - - let mut irq_file = irq.irq_handle("e1000d"); - - let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; - - let mut scheme = NetworkScheme::new( - move || unsafe { - device::Intel8254x::new(address).expect("e1000d: failed to allocate device") - }, - daemon, - format!("network.{name}"), - ); - - user_data! { - enum Source { - Irq, - Scheme, - } - } - - let event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); - - event_queue - .subscribe( - irq_file.as_raw_fd() as usize, - Source::Irq, - event::EventFlags::READ, - ) - .expect("e1000d: failed to subscribe to IRQ fd"); - event_queue - .subscribe( - scheme.event_handle().raw(), - Source::Scheme, - event::EventFlags::READ, - ) - .expect("e1000d: failed to subscribe to scheme fd"); - - libredox::call::setrens(0, 0).expect("e1000d: failed to enter null namespace"); - - scheme.tick().unwrap(); - - for event in event_queue.map(|e| e.expect("e1000d: failed to get event")) { - match event.user_data { - Source::Irq => { - let mut irq = [0; 8]; - irq_file.read(&mut irq).unwrap(); - if unsafe { scheme.adapter().irq() } { - irq_file.write(&mut irq).unwrap(); - - scheme.tick().expect("e1000d: failed to handle IRQ") - } - } - Source::Scheme => scheme.tick().expect("e1000d: failed to handle scheme op"), - } - } - unreachable!() -} diff --git a/recipes/core/base/drivers/net/ixgbed/Cargo.toml b/recipes/core/base/drivers/net/ixgbed/Cargo.toml deleted file mode 100644 index d97ff39874..0000000000 --- a/recipes/core/base/drivers/net/ixgbed/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "ixgbed" -description = "Intel 10 Gigabit ethernet driver" -version = "1.0.0" -edition = "2021" - -[dependencies] -bitflags.workspace = true -libredox.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-network = { path = "../driver-network" } -pcid = { path = "../../pcid" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/net/ixgbed/LICENSE b/recipes/core/base/drivers/net/ixgbed/LICENSE deleted file mode 100644 index 0ad25db4bd..0000000000 --- a/recipes/core/base/drivers/net/ixgbed/LICENSE +++ /dev/null @@ -1,661 +0,0 @@ - GNU AFFERO GENERAL PUBLIC LICENSE - Version 3, 19 November 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU Affero General Public License is a free, copyleft license for -software and other kinds of works, specifically designed to ensure -cooperation with the community in the case of network server software. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -our General Public Licenses are intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - Developers that use our General Public Licenses protect your rights -with two steps: (1) assert copyright on the software, and (2) offer -you this License which gives you legal permission to copy, distribute -and/or modify the software. - - A secondary benefit of defending all users' freedom is that -improvements made in alternate versions of the program, if they -receive widespread use, become available for other developers to -incorporate. Many developers of free software are heartened and -encouraged by the resulting cooperation. However, in the case of -software used on network servers, this result may fail to come about. -The GNU General Public License permits making a modified version and -letting the public access it on a server without ever releasing its -source code to the public. - - The GNU Affero General Public License is designed specifically to -ensure that, in such cases, the modified source code becomes available -to the community. It requires the operator of a network server to -provide the source code of the modified version running there to the -users of that server. Therefore, public use of a modified version, on -a publicly accessible server, gives the public access to the source -code of the modified version. - - An older license, called the Affero General Public License and -published by Affero, was designed to accomplish similar goals. This is -a different license, not a version of the Affero GPL, but Affero has -released a new version of the Affero GPL which permits relicensing under -this license. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU Affero General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Remote Network Interaction; Use with the GNU General Public License. - - Notwithstanding any other provision of this License, if you modify the -Program, your modified version must prominently offer all users -interacting with it remotely through a computer network (if your version -supports such interaction) an opportunity to receive the Corresponding -Source of your version by providing access to the Corresponding Source -from a network server at no charge, through some standard or customary -means of facilitating copying of software. This Corresponding Source -shall include the Corresponding Source for any work covered by version 3 -of the GNU General Public License that is incorporated pursuant to the -following paragraph. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the work with which it is combined will remain governed by version -3 of the GNU General Public License. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU Affero General Public License from time to time. Such new versions -will be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU Affero General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU Affero General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU Affero General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU Affero 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If your software can interact with users remotely through a computer -network, you should also make sure that it provides a way for users to -get its source. For example, if your program is a web application, its -interface could display a "Source" link that leads users to an archive -of the code. There are many ways you could offer source, and different -solutions will be better for different programs; see section 13 for the -specific requirements. - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU AGPL, see -. diff --git a/recipes/core/base/drivers/net/ixgbed/README.md b/recipes/core/base/drivers/net/ixgbed/README.md deleted file mode 100644 index abcd4a2f83..0000000000 --- a/recipes/core/base/drivers/net/ixgbed/README.md +++ /dev/null @@ -1,37 +0,0 @@ -# ixgbed (a.k.a. ixy.rs on Redox) - -ixgbed is the Redox port of [ixy.rs](https://github.com/ixy-languages/ixy.rs), a Rust rewrite of the [ixy](https://github.com/emmericp/ixy) userspace network driver. -It is designed to be readable, idiomatic Rust code. -It supports Intel 82599 10GbE NICs (`ixgbe` family). - -## Features - -* first 10 Gbit/s network driver on Redox -* transmitting 250 times faster than e1000 / rtl8168 driver -* MSI-X interrupts (not supported by Redox yet) -* less than 1000 lines of code for the driver -* documented code - -## Build instructions - -See the [Redox README](https://gitlab.redox-os.org/redox-os/redox/blob/master/README.md) for build instructions. - -To run ixgbed on Redox (in case the driver is not shipped with Redox anymore) - -* clone this project into `cookbook/recipes/drivers/source/` -* create an entry for ixgbed in `cookbook/recipes/drivers/source/Cargo.toml` -* check if your ixgbe device is included in `config.toml` -* touch `filesystem.toml` in Redox's root directory, build Redox and run it - -## Usage - -To test the driver's transmit and forwarding capabilities, have a look at [rheinfall](https://github.com/ackxolotl/rheinfall), a simple packet generator / forwarder application. - -## Docs - -ixgbed contains documentation that can be created and viewed by running - -``` -cargo doc --open -``` - diff --git a/recipes/core/base/drivers/net/ixgbed/config.toml b/recipes/core/base/drivers/net/ixgbed/config.toml deleted file mode 100644 index a10fba5a8f..0000000000 --- a/recipes/core/base/drivers/net/ixgbed/config.toml +++ /dev/null @@ -1,5 +0,0 @@ -[[drivers]] -name = "Intel 10G NIC" -class = 0x02 -ids = { 0x8086 = [0x10F7, 0x1514, 0x1517, 0x151C, 0x10F9, 0x10FB, 0x152a, 0x1529, 0x1507, 0x154D, 0x1557, 0x10FC, 0x10F8, 0x154F, 0x1528, 0x154A, 0x1558, 0x1560, 0x1563, 0x15D1, 0x15AA, 0x15AB, 0x15AC, 0x15AD, 0x15AE, 0x15B0, 0x15C2, 0x15C3, 0x15C4, 0x15C6, 0x15C7, 0x15C8, 0x15CE, 0x15E4, 0x15E5, 0x10ED, 0x1515, 0x1565, 0x15A8, 0x15C5] } -command = ["ixgbed"] diff --git a/recipes/core/base/drivers/net/ixgbed/src/device.rs b/recipes/core/base/drivers/net/ixgbed/src/device.rs deleted file mode 100644 index 0d59b46d34..0000000000 --- a/recipes/core/base/drivers/net/ixgbed/src/device.rs +++ /dev/null @@ -1,579 +0,0 @@ -use std::convert::TryInto; -use std::time::{Duration, Instant}; -use std::{cmp, mem, ptr, slice, thread}; - -use driver_network::NetworkAdapter; -use syscall::error::Result; - -use common::dma::Dma; - -use crate::ixgbe::*; - -pub struct Intel8259x { - base: usize, - size: usize, - receive_buffer: [Dma<[u8; 16384]>; 32], - receive_ring: Dma<[ixgbe_adv_rx_desc; 32]>, - receive_index: usize, - transmit_buffer: [Dma<[u8; 16384]>; 32], - transmit_ring: Dma<[ixgbe_adv_tx_desc; 32]>, - transmit_ring_free: usize, - transmit_index: usize, - transmit_clean_index: usize, - mac_address: [u8; 6], -} - -fn wrap_ring(index: usize, ring_size: usize) -> usize { - (index + 1) & (ring_size - 1) -} - -impl NetworkAdapter for Intel8259x { - fn mac_address(&mut self) -> [u8; 6] { - self.mac_address - } - - fn available_for_read(&mut self) -> usize { - self.next_read() - } - - fn read_packet(&mut self, buf: &mut [u8]) -> Result> { - let desc = unsafe { - &mut *(self.receive_ring.as_ptr().add(self.receive_index) as *mut ixgbe_adv_rx_desc) - }; - - let status = unsafe { desc.wb.upper.status_error }; - - if (status & IXGBE_RXDADV_STAT_DD) != 0 { - if (status & IXGBE_RXDADV_STAT_EOP) == 0 { - panic!("increase buffer size or decrease MTU") - } - - let data = unsafe { - &self.receive_buffer[self.receive_index][..desc.wb.upper.length as usize] - }; - - let i = cmp::min(buf.len(), data.len()); - buf[..i].copy_from_slice(&data[..i]); - - desc.read.pkt_addr = self.receive_buffer[self.receive_index].physical() as u64; - desc.read.hdr_addr = 0; - - self.write_reg(IXGBE_RDT(0), self.receive_index as u32); - self.receive_index = wrap_ring(self.receive_index, self.receive_ring.len()); - - return Ok(Some(i)); - } - - Ok(None) - } - - fn write_packet(&mut self, buf: &[u8]) -> Result { - if self.transmit_ring_free == 0 { - loop { - let desc = unsafe { - &*(self.transmit_ring.as_ptr().add(self.transmit_clean_index) - as *const ixgbe_adv_tx_desc) - }; - - if (unsafe { desc.wb.status } & IXGBE_ADVTXD_STAT_DD) != 0 { - self.transmit_clean_index = - wrap_ring(self.transmit_clean_index, self.transmit_ring.len()); - self.transmit_ring_free += 1; - } else if self.transmit_ring_free > 0 { - break; - } - - if self.transmit_ring_free >= self.transmit_ring.len() { - break; - } - } - } - - let desc = unsafe { - &mut *(self.transmit_ring.as_ptr().add(self.transmit_index) as *mut ixgbe_adv_tx_desc) - }; - - let data = unsafe { - slice::from_raw_parts_mut( - self.transmit_buffer[self.transmit_index].as_ptr() as *mut u8, - cmp::min(buf.len(), self.transmit_buffer[self.transmit_index].len()) as usize, - ) - }; - - let i = cmp::min(buf.len(), data.len()); - data[..i].copy_from_slice(&buf[..i]); - - desc.read.cmd_type_len = IXGBE_ADVTXD_DCMD_EOP - | IXGBE_ADVTXD_DCMD_RS - | IXGBE_ADVTXD_DCMD_IFCS - | IXGBE_ADVTXD_DCMD_DEXT - | IXGBE_ADVTXD_DTYP_DATA - | buf.len() as u32; - - desc.read.olinfo_status = (buf.len() as u32) << IXGBE_ADVTXD_PAYLEN_SHIFT; - - self.transmit_index = wrap_ring(self.transmit_index, self.transmit_ring.len()); - self.transmit_ring_free -= 1; - - self.write_reg(IXGBE_TDT(0), self.transmit_index as u32); - - Ok(i) - } -} - -impl Intel8259x { - /// Returns an initialized `Intel8259x` on success. - pub fn new(base: usize, size: usize) -> Result { - #[rustfmt::skip] - let mut module = Intel8259x { - base, - size, - receive_buffer: (0..32) - .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) - .collect::>>()? - .try_into() - .unwrap_or_else(|_| unreachable!()), - receive_ring: unsafe { Dma::zeroed()?.assume_init() }, - transmit_buffer: (0..32) - .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) - .collect::>>()? - .try_into() - .unwrap_or_else(|_| unreachable!()), - receive_index: 0, - transmit_ring: unsafe { Dma::zeroed()?.assume_init() }, - transmit_ring_free: 32, - transmit_index: 0, - transmit_clean_index: 0, - mac_address: [0; 6], - }; - - module.init(); - - Ok(module) - } - - pub fn irq(&self) -> bool { - let icr = self.read_reg(IXGBE_EICR); - icr != 0 - } - - pub fn next_read(&self) -> usize { - let desc = unsafe { - &*(self.receive_ring.as_ptr().add(self.receive_index) as *const ixgbe_adv_rx_desc) - }; - - let status = unsafe { desc.wb.upper.status_error }; - - if (status & IXGBE_RXDADV_STAT_DD) != 0 { - if (status & IXGBE_RXDADV_STAT_EOP) == 0 { - panic!("increase buffer size or decrease MTU") - } - - return unsafe { desc.wb.upper.length as usize }; - } - - 0 - } - - /// Returns the mac address of this device. - pub fn get_mac_addr(&self) -> [u8; 6] { - let low = self.read_reg(IXGBE_RAL(0)); - let high = self.read_reg(IXGBE_RAH(0)); - - [ - (low & 0xff) as u8, - (low >> 8 & 0xff) as u8, - (low >> 16 & 0xff) as u8, - (low >> 24) as u8, - (high & 0xff) as u8, - (high >> 8 & 0xff) as u8, - ] - } - - /// Sets the mac address of this device. - #[allow(dead_code)] - pub fn set_mac_addr(&mut self, mac: [u8; 6]) { - let low: u32 = u32::from(mac[0]) - + (u32::from(mac[1]) << 8) - + (u32::from(mac[2]) << 16) - + (u32::from(mac[3]) << 24); - let high: u32 = u32::from(mac[4]) + (u32::from(mac[5]) << 8); - - self.write_reg(IXGBE_RAL(0), low); - self.write_reg(IXGBE_RAH(0), high); - - self.mac_address = mac; - } - - /// Returns the register at `self.base` + `register`. - /// - /// # Panics - /// - /// Panics if `self.base` + `register` does not belong to the mapped memory of the PCIe device. - fn read_reg(&self, register: u32) -> u32 { - assert!( - register as usize <= self.size - 4 as usize, - "MMIO access out of bounds" - ); - - unsafe { ptr::read_volatile((self.base + register as usize) as *mut u32) } - } - - /// Sets the register at `self.base` + `register`. - /// - /// # Panics - /// - /// Panics if `self.base` + `register` does not belong to the mapped memory of the PCIe device. - fn write_reg(&self, register: u32, data: u32) -> u32 { - assert!( - register as usize <= self.size - 4 as usize, - "MMIO access out of bounds" - ); - - unsafe { - ptr::write_volatile((self.base + register as usize) as *mut u32, data); - ptr::read_volatile((self.base + register as usize) as *mut u32) - } - } - - fn write_flag(&self, register: u32, flags: u32) { - self.write_reg(register, self.read_reg(register) | flags); - } - - fn clear_flag(&self, register: u32, flags: u32) { - self.write_reg(register, self.read_reg(register) & !flags); - } - - fn wait_clear_reg(&self, register: u32, value: u32) { - loop { - let current = self.read_reg(register); - if (current & value) == 0 { - break; - } - thread::sleep(Duration::from_millis(100)); - } - } - - fn wait_write_reg(&self, register: u32, value: u32) { - loop { - let current = self.read_reg(register); - if (current & value) == value { - break; - } - thread::sleep(Duration::from_millis(100)); - } - } - - /// Resets and initializes an ixgbe device. - fn init(&mut self) { - // section 4.6.3.1 - disable all interrupts - self.write_reg(IXGBE_EIMC, 0x7fff_ffff); - - // section 4.6.3.2 - self.write_reg(IXGBE_CTRL, IXGBE_CTRL_RST_MASK); - self.wait_clear_reg(IXGBE_CTRL, IXGBE_CTRL_RST_MASK); - thread::sleep(Duration::from_millis(10)); - - // section 4.6.3.1 - disable interrupts again after reset - self.write_reg(IXGBE_EIMC, 0x7fff_ffff); - - let mac = self.get_mac_addr(); - - println!( - " - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] - ); - - self.mac_address = mac; - - // section 4.6.3 - wait for EEPROM auto read completion - self.wait_write_reg(IXGBE_EEC, IXGBE_EEC_ARD); - - // section 4.6.3 - wait for dma initialization done - self.wait_write_reg( - IXGBE_RDRXCTL, - IXGBE_RDRXCTL_DMAIDONE | IXGBE_RDRXCTL_RESERVED_BITS, - ); - - // section 4.6.4 - initialize link (auto negotiation) - self.init_link(); - - // section 4.6.5 - statistical counters - // reset-on-read registers, just read them once - self.reset_stats(); - - // section 4.6.7 - init rx - self.init_rx(); - - // section 4.6.8 - init tx - self.init_tx(); - - // start a single receive queue/ring - self.start_rx_queue(0); - - // start a single transmit queue/ring - self.start_tx_queue(0); - - // section 4.6.3.9 - enable interrupts - self.enable_msix_interrupt(0); - - // wait some time for the link to come up - self.wait_for_link(); - } - - /// Resets the stats of this device. - fn reset_stats(&self) { - self.read_reg(IXGBE_GPRC); - self.read_reg(IXGBE_GPTC); - self.read_reg(IXGBE_GORCL); - self.read_reg(IXGBE_GORCH); - self.read_reg(IXGBE_GOTCL); - self.read_reg(IXGBE_GOTCH); - } - - // sections 4.6.7 - /// Initializes the rx queues of this device. - fn init_rx(&mut self) { - // disable rx while re-configuring it - self.clear_flag(IXGBE_RXCTRL, IXGBE_RXCTRL_RXEN); - - // section 4.6.11.3.4 - allocate all queues and traffic to PB0 - self.write_reg(IXGBE_RXPBSIZE(0), IXGBE_RXPBSIZE_128KB); - for i in 1..8 { - self.write_reg(IXGBE_RXPBSIZE(i), 0); - } - - // enable CRC offloading - self.write_flag(IXGBE_HLREG0, IXGBE_HLREG0_RXCRCSTRP); - self.write_flag(IXGBE_RDRXCTL, IXGBE_RDRXCTL_CRCSTRIP); - - // accept broadcast packets - self.write_flag(IXGBE_FCTRL, IXGBE_FCTRL_BAM); - - // configure a single receive queue/ring - let i: u32 = 0; - - // enable advanced rx descriptors - self.write_reg( - IXGBE_SRRCTL(i), - (self.read_reg(IXGBE_SRRCTL(i)) & !IXGBE_SRRCTL_DESCTYPE_MASK) - | IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF, - ); - // let nic drop packets if no rx descriptor is available instead of buffering them - self.write_flag(IXGBE_SRRCTL(i), IXGBE_SRRCTL_DROP_EN); - - self.write_reg(IXGBE_RDBAL(i), self.receive_ring.physical() as u32); - - self.write_reg( - IXGBE_RDBAH(i), - ((self.receive_ring.physical() as u64) >> 32) as u32, - ); - self.write_reg( - IXGBE_RDLEN(i), - (self.receive_ring.len() * mem::size_of::()) as u32, - ); - - // set ring to empty at start - self.write_reg(IXGBE_RDH(i), 0); - self.write_reg(IXGBE_RDT(i), 0); - - // last sentence of section 4.6.7 - set some magic bits - self.write_flag(IXGBE_CTRL_EXT, IXGBE_CTRL_EXT_NS_DIS); - - // probably a broken feature, this flag is initialized with 1 but has to be set to 0 - self.clear_flag(IXGBE_DCA_RXCTRL(i), 1 << 12); - - // enable promisc mode by default to make testing easier - // this has to be done when the rxctrl.rxen bit is not set - self.set_promisc(true); - - // start rx - self.write_flag(IXGBE_RXCTRL, IXGBE_RXCTRL_RXEN); - } - - // section 4.6.8 - /// Initializes the tx queues of this device. - fn init_tx(&mut self) { - // crc offload and small packet padding - self.write_flag(IXGBE_HLREG0, IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN); - - // section 4.6.11.3.4 - set default buffer size allocations - self.write_reg(IXGBE_TXPBSIZE(0), IXGBE_TXPBSIZE_40KB); - for i in 1..8 { - self.write_reg(IXGBE_TXPBSIZE(i), 0); - } - - // required when not using DCB/VTd - self.write_reg(IXGBE_DTXMXSZRQ, 0xfff); - self.clear_flag(IXGBE_RTTDCS, IXGBE_RTTDCS_ARBDIS); - - // configure a single transmit queue/ring - let i: u32 = 0; - - // section 7.1.9 - setup descriptor ring - - self.write_reg(IXGBE_TDBAL(i), self.transmit_ring.physical() as u32); - self.write_reg( - IXGBE_TDBAH(i), - ((self.transmit_ring.physical() as u64) >> 32) as u32, - ); - self.write_reg( - IXGBE_TDLEN(i), - (self.transmit_ring.len() * mem::size_of::()) as u32, - ); - - // descriptor writeback magic values, important to get good performance and low PCIe overhead - // see 7.2.3.4.1 and 7.2.3.5 for an explanation of these values and how to find good ones - // we just use the defaults from DPDK here, but this is a potentially interesting point for optimizations - let mut txdctl = self.read_reg(IXGBE_TXDCTL(i)); - // there are no defines for this in ixgbe.rs for some reason - // pthresh: 6:0, hthresh: 14:8, wthresh: 22:16 - txdctl &= !(0x3F | (0x3F << 8) | (0x3F << 16)); - txdctl |= 36 | (8 << 8) | (4 << 16); - - self.write_reg(IXGBE_TXDCTL(i), txdctl); - - // final step: enable DMA - self.write_reg(IXGBE_DMATXCTL, IXGBE_DMATXCTL_TE); - } - - /// Sets the rx queues` descriptors and enables the queues. - /// - /// # Panics - /// Panics if length of `self.receive_ring` is not a power of 2. - fn start_rx_queue(&mut self, queue_id: u16) { - if self.receive_ring.len() & (self.receive_ring.len() - 1) != 0 { - panic!("number of receive queue entries must be a power of 2"); - } - - for i in 0..self.receive_ring.len() { - self.receive_ring[i].read.pkt_addr = self.receive_buffer[i].physical() as u64; - self.receive_ring[i].read.hdr_addr = 0; - } - - // enable queue and wait if necessary - self.write_flag(IXGBE_RXDCTL(u32::from(queue_id)), IXGBE_RXDCTL_ENABLE); - self.wait_write_reg(IXGBE_RXDCTL(u32::from(queue_id)), IXGBE_RXDCTL_ENABLE); - - // rx queue starts out full - self.write_reg(IXGBE_RDH(u32::from(queue_id)), 0); - - // was set to 0 before in the init function - self.write_reg( - IXGBE_RDT(u32::from(queue_id)), - (self.receive_ring.len() - 1) as u32, - ); - } - - /// Enables the tx queues. - /// - /// # Panics - /// Panics if length of `self.transmit_ring` is not a power of 2. - fn start_tx_queue(&mut self, queue_id: u16) { - if self.transmit_ring.len() & (self.transmit_ring.len() - 1) != 0 { - panic!("number of receive queue entries must be a power of 2"); - } - - for i in 0..self.transmit_ring.len() { - self.transmit_ring[i].read.buffer_addr = self.transmit_buffer[i].physical() as u64; - } - - // tx queue starts out empty - self.write_reg(IXGBE_TDH(u32::from(queue_id)), 0); - self.write_reg(IXGBE_TDT(u32::from(queue_id)), 0); - - // enable queue and wait if necessary - self.write_flag(IXGBE_TXDCTL(u32::from(queue_id)), IXGBE_TXDCTL_ENABLE); - self.wait_write_reg(IXGBE_TXDCTL(u32::from(queue_id)), IXGBE_TXDCTL_ENABLE); - } - - // see section 4.6.4 - /// Initializes the link of this device. - fn init_link(&self) { - // link auto-configuration register should already be set correctly, we're resetting it anyway - self.write_reg( - IXGBE_AUTOC, - (self.read_reg(IXGBE_AUTOC) & !IXGBE_AUTOC_LMS_MASK) | IXGBE_AUTOC_LMS_10G_SERIAL, - ); - self.write_reg( - IXGBE_AUTOC, - (self.read_reg(IXGBE_AUTOC) & !IXGBE_AUTOC_10G_PMA_PMD_MASK) | IXGBE_AUTOC_10G_XAUI, - ); - // negotiate link - self.write_flag(IXGBE_AUTOC, IXGBE_AUTOC_AN_RESTART); - // datasheet wants us to wait for the link here, but we can continue and wait afterwards - } - - /// Waits for the link to come up. - fn wait_for_link(&self) { - println!(" - waiting for link"); - let time = Instant::now(); - let mut speed = self.get_link_speed(); - while speed == 0 && time.elapsed().as_secs() < 10 { - thread::sleep(Duration::from_millis(100)); - speed = self.get_link_speed(); - } - println!(" - link speed is {} Mbit/s", self.get_link_speed()); - } - - /// Enables or disables promisc mode of this device. - fn set_promisc(&self, enabled: bool) { - if enabled { - self.write_flag(IXGBE_FCTRL, IXGBE_FCTRL_MPE | IXGBE_FCTRL_UPE); - } else { - self.clear_flag(IXGBE_FCTRL, IXGBE_FCTRL_MPE | IXGBE_FCTRL_UPE); - } - } - - /// Set the IVAR registers, mapping interrupt causes to vectors. - fn set_ivar(&mut self, direction: i8, queue_id: u16, mut msix_vector: u8) { - let index = ((16 * (queue_id & 1)) as i16 + i16::from(8 * direction)) as u32; - - msix_vector |= IXGBE_IVAR_ALLOC_VAL as u8; - - let mut ivar = self.read_reg(IXGBE_IVAR(u32::from(queue_id >> 1))); - ivar &= !(0xFF << index); - ivar |= u32::from(msix_vector << index); - - self.write_reg(IXGBE_IVAR(u32::from(queue_id >> 1)), ivar); - } - - /// Enable MSI-X interrupt for a queue. - fn enable_msix_interrupt(&mut self, queue_id: u16) { - // Step 1: The software driver associates between interrupt causes and MSI-X vectors and the - //throttling timers EITR[n] by programming the IVAR[n] and IVAR_MISC registers. - self.set_ivar(0, queue_id, queue_id as u8); - - // Step 2: Program SRRCTL[n].RDMTS (per receive queue) if software uses the receive - // descriptor minimum threshold interrupt - - // Step 3: The EIAC[n] registers should be set to auto clear for transmit and receive interrupt - // causes (for best performance). The EIAC bits that control the other and TCP timer - // interrupt causes should be set to 0b (no auto clear). - self.write_reg(IXGBE_EIAC, IXGBE_EICR_RTX_QUEUE); - - // Step 4: Set the auto mask in the EIAM register according to the preferred mode of operation. - - // Step 5: Set the interrupt throttling in EITR[n] and GPIE according to the preferred mode of operation. - - // Step 6: Software enables the required interrupt causes by setting the EIMS register - let mut mask: u32 = self.read_reg(IXGBE_EIMS); - mask |= 1 << queue_id; - - self.write_reg(IXGBE_EIMS, mask); - } - - /// Returns the link speed of this device. - fn get_link_speed(&self) -> u16 { - let speed = self.read_reg(IXGBE_LINKS); - if (speed & IXGBE_LINKS_UP) == 0 { - return 0; - } - match speed & IXGBE_LINKS_SPEED_82599 { - IXGBE_LINKS_SPEED_100_82599 => 100, - IXGBE_LINKS_SPEED_1G_82599 => 1000, - IXGBE_LINKS_SPEED_10G_82599 => 10000, - _ => 0, - } - } -} diff --git a/recipes/core/base/drivers/net/ixgbed/src/ixgbe.rs b/recipes/core/base/drivers/net/ixgbed/src/ixgbe.rs deleted file mode 100644 index 8d77959444..0000000000 --- a/recipes/core/base/drivers/net/ixgbed/src/ixgbe.rs +++ /dev/null @@ -1,315 +0,0 @@ -#![allow(non_snake_case)] -#![allow(non_camel_case_types)] -#![allow(non_upper_case_globals)] -#![allow(clippy::unreadable_literal)] - -pub const IXGBE_EIMC: u32 = 0x00888; - -pub const IXGBE_CTRL: u32 = 0x00000; -pub const IXGBE_CTRL_LNK_RST: u32 = 0x00000008; /* Link Reset. Resets everything. */ -pub const IXGBE_CTRL_RST: u32 = 0x04000000; /* Reset (SW) */ -pub const IXGBE_CTRL_RST_MASK: u32 = IXGBE_CTRL_LNK_RST | IXGBE_CTRL_RST; - -pub const IXGBE_EEC: u32 = 0x10010; -pub const IXGBE_EEC_ARD: u32 = 0x00000200; /* EEPROM Auto Read Done */ - -pub const IXGBE_RDRXCTL: u32 = 0x02F00; -pub const IXGBE_RDRXCTL_RESERVED_BITS: u32 = 1 << 25 | 1 << 26; -pub const IXGBE_RDRXCTL_DMAIDONE: u32 = 0x00000008; /* DMA init cycle done */ - -pub const IXGBE_AUTOC: u32 = 0x042A0; -pub const IXGBE_AUTOC_LMS_SHIFT: u32 = 13; -pub const IXGBE_AUTOC_LMS_MASK: u32 = 0x7 << IXGBE_AUTOC_LMS_SHIFT; -pub const IXGBE_AUTOC_LMS_10G_SERIAL: u32 = 0x3 << IXGBE_AUTOC_LMS_SHIFT; -pub const IXGBE_AUTOC_10G_PMA_PMD_MASK: u32 = 0x00000180; -pub const IXGBE_AUTOC_10G_PMA_PMD_SHIFT: u32 = 7; -pub const IXGBE_AUTOC_10G_XAUI: u32 = 0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT; -pub const IXGBE_AUTOC_AN_RESTART: u32 = 0x00001000; - -pub const IXGBE_GPRC: u32 = 0x04074; -pub const IXGBE_GPTC: u32 = 0x04080; -pub const IXGBE_GORCL: u32 = 0x04088; -pub const IXGBE_GORCH: u32 = 0x0408C; -pub const IXGBE_GOTCL: u32 = 0x04090; -pub const IXGBE_GOTCH: u32 = 0x04094; - -pub const IXGBE_RXCTRL: u32 = 0x03000; -pub const IXGBE_RXCTRL_RXEN: u32 = 0x00000001; /* Enable Receiver */ - -pub fn IXGBE_RXPBSIZE(i: u32) -> u32 { - 0x03C00 + (i * 4) -} - -pub const IXGBE_RXPBSIZE_128KB: u32 = 0x00020000; /* 128KB Packet Buffer */ -pub const IXGBE_HLREG0: u32 = 0x04240; -pub const IXGBE_HLREG0_RXCRCSTRP: u32 = 0x00000002; /* bit 1 */ -pub const IXGBE_RDRXCTL_CRCSTRIP: u32 = 0x00000002; /* CRC Strip */ - -pub const IXGBE_FCTRL: u32 = 0x05080; -pub const IXGBE_FCTRL_BAM: u32 = 0x00000400; /* Broadcast Accept Mode */ - -pub fn IXGBE_SRRCTL(i: u32) -> u32 { - if i <= 15 { - 0x02100 + (i * 4) - } else if i < 64 { - 0x01014 + (i * 0x40) - } else { - 0x0D014 + ((i - 64) * 0x40) - } -} - -pub const IXGBE_SRRCTL_DESCTYPE_MASK: u32 = 0x0E000000; -pub const IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF: u32 = 0x02000000; -pub const IXGBE_SRRCTL_DROP_EN: u32 = 0x10000000; - -pub fn IXGBE_RDBAL(i: u32) -> u32 { - if i < 64 { - 0x01000 + (i * 0x40) - } else { - 0x0D000 + ((i - 64) * 0x40) - } -} -pub fn IXGBE_RDBAH(i: u32) -> u32 { - if i < 64 { - 0x01004 + (i * 0x40) - } else { - 0x0D004 + ((i - 64) * 0x40) - } -} -pub fn IXGBE_RDLEN(i: u32) -> u32 { - if i < 64 { - 0x01008 + (i * 0x40) - } else { - 0x0D008 + ((i - 64) * 0x40) - } -} -pub fn IXGBE_RDH(i: u32) -> u32 { - if i < 64 { - 0x01010 + (i * 0x40) - } else { - 0x0D010 + ((i - 64) * 0x40) - } -} -pub fn IXGBE_RDT(i: u32) -> u32 { - if i < 64 { - 0x01018 + (i * 0x40) - } else { - 0x0D018 + ((i - 64) * 0x40) - } -} - -pub const IXGBE_CTRL_EXT: u32 = 0x00018; -pub const IXGBE_CTRL_EXT_NS_DIS: u32 = 0x00010000; /* No Snoop disable */ - -pub fn IXGBE_DCA_RXCTRL(i: u32) -> u32 { - if i <= 15 { - 0x02200 + (i * 4) - } else if i < 64 { - 0x0100C + (i * 0x40) - } else { - 0x0D00C + ((i - 64) * 0x40) - } -} - -pub const IXGBE_HLREG0_TXCRCEN: u32 = 0x00000001; /* bit 0 */ -pub const IXGBE_HLREG0_TXPADEN: u32 = 0x00000400; /* bit 10 */ - -pub fn IXGBE_TXPBSIZE(i: u32) -> u32 { - 0x0CC00 + (i * 4) -} /* 8 of these */ - -pub const IXGBE_TXPBSIZE_40KB: u32 = 0x0000A000; /* 40KB Packet Buffer */ -pub const IXGBE_DTXMXSZRQ: u32 = 0x08100; -pub const IXGBE_RTTDCS: u32 = 0x04900; -pub const IXGBE_RTTDCS_ARBDIS: u32 = 0x00000040; /* DCB arbiter disable */ - -pub fn IXGBE_TDBAL(i: u32) -> u32 { - 0x06000 + (i * 0x40) -} /* 32 of them (0-31)*/ -pub fn IXGBE_TDBAH(i: u32) -> u32 { - 0x06004 + (i * 0x40) -} -pub fn IXGBE_TDLEN(i: u32) -> u32 { - 0x06008 + (i * 0x40) -} -pub fn IXGBE_TXDCTL(i: u32) -> u32 { - 0x06028 + (i * 0x40) -} - -pub const IXGBE_DMATXCTL: u32 = 0x04A80; -pub const IXGBE_DMATXCTL_TE: u32 = 0x1; /* Transmit Enable */ - -pub fn IXGBE_RXDCTL(i: u32) -> u32 { - if i < 64 { - 0x01028 + (i * 0x40) - } else { - 0x0D028 + ((i - 64) * 0x40) - } -} -pub const IXGBE_RXDCTL_ENABLE: u32 = 0x02000000; /* Ena specific Rx Queue */ -pub const IXGBE_TXDCTL_ENABLE: u32 = 0x02000000; /* Ena specific Tx Queue */ - -pub fn IXGBE_TDH(i: u32) -> u32 { - 0x06010 + (i * 0x40) -} -pub fn IXGBE_TDT(i: u32) -> u32 { - 0x06018 + (i * 0x40) -} - -pub const IXGBE_FCTRL_MPE: u32 = 0x00000100; /* Multicast Promiscuous Ena*/ -pub const IXGBE_FCTRL_UPE: u32 = 0x00000200; /* Unicast Promiscuous Ena */ - -pub const IXGBE_LINKS: u32 = 0x042A4; -pub const IXGBE_LINKS_UP: u32 = 0x40000000; -pub const IXGBE_LINKS_SPEED_82599: u32 = 0x30000000; -pub const IXGBE_LINKS_SPEED_100_82599: u32 = 0x10000000; -pub const IXGBE_LINKS_SPEED_1G_82599: u32 = 0x20000000; -pub const IXGBE_LINKS_SPEED_10G_82599: u32 = 0x30000000; - -pub fn IXGBE_RAL(i: u32) -> u32 { - if i <= 15 { - 0x05400 + (i * 8) - } else { - 0x0A200 + (i * 8) - } -} - -pub fn IXGBE_RAH(i: u32) -> u32 { - if i <= 15 { - 0x05404 + (i * 8) - } else { - 0x0A204 + (i * 8) - } -} - -pub const IXGBE_RXD_STAT_DD: u32 = 0x01; /* Descriptor Done */ -pub const IXGBE_RXD_STAT_EOP: u32 = 0x02; /* End of Packet */ -pub const IXGBE_RXDADV_STAT_DD: u32 = IXGBE_RXD_STAT_DD; /* Done */ -pub const IXGBE_RXDADV_STAT_EOP: u32 = IXGBE_RXD_STAT_EOP; /* End of Packet */ - -pub const IXGBE_ADVTXD_PAYLEN_SHIFT: u32 = 14; /* Adv desc PAYLEN shift */ -pub const IXGBE_TXD_CMD_EOP: u32 = 0x01000000; /* End of Packet */ -pub const IXGBE_ADVTXD_DCMD_EOP: u32 = IXGBE_TXD_CMD_EOP; /* End of Packet */ -pub const IXGBE_TXD_CMD_RS: u32 = 0x08000000; /* Report Status */ -pub const IXGBE_ADVTXD_DCMD_RS: u32 = IXGBE_TXD_CMD_RS; /* Report Status */ -pub const IXGBE_TXD_CMD_IFCS: u32 = 0x02000000; /* Insert FCS (Ethernet CRC) */ -pub const IXGBE_ADVTXD_DCMD_IFCS: u32 = IXGBE_TXD_CMD_IFCS; /* Insert FCS */ -pub const IXGBE_TXD_CMD_DEXT: u32 = 0x20000000; /* Desc extension (0 = legacy) */ -pub const IXGBE_ADVTXD_DTYP_DATA: u32 = 0x00300000; /* Adv Data Descriptor */ -pub const IXGBE_ADVTXD_DCMD_DEXT: u32 = IXGBE_TXD_CMD_DEXT; /* Desc ext 1=Adv */ -pub const IXGBE_TXD_STAT_DD: u32 = 0x00000001; /* Descriptor Done */ -pub const IXGBE_ADVTXD_STAT_DD: u32 = IXGBE_TXD_STAT_DD; /* Descriptor Done */ - -/* Interrupt Registers */ -pub const IXGBE_EICR: u32 = 0x00800; -pub const IXGBE_EIAC: u32 = 0x00810; -pub const IXGBE_EIMS: u32 = 0x00880; -pub const IXGBE_IVAR_ALLOC_VAL: u32 = 0x80; /* Interrupt Allocation valid */ -pub const IXGBE_EICR_RTX_QUEUE: u32 = 0x0000FFFF; /* RTx Queue Interrupt */ - -pub fn IXGBE_IVAR(i: u32) -> u32 { - 0x00900 + (i * 4) -} /* 24 at 0x900-0x960 */ - -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct ixgbe_adv_rx_desc_read { - pub pkt_addr: u64, - /* Packet buffer address */ - pub hdr_addr: u64, - /* Header buffer address */ -} - -/* Receive Descriptor - Advanced */ -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct ixgbe_adv_rx_desc_wb_lower_lo_dword_hs_rss { - pub pkt_info: u16, - /* RSS, Pkt type */ - pub hdr_info: u16, - /* Splithdr, hdrlen */ -} - -#[derive(Copy, Clone)] -#[repr(C, packed)] -pub union ixgbe_adv_rx_desc_wb_lower_lo_dword { - pub data: u32, - pub hs_rss: ixgbe_adv_rx_desc_wb_lower_lo_dword_hs_rss, -} - -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct ixgbe_adv_rx_desc_wb_lower_hi_dword_csum_ip { - pub ip_id: u16, - /* IP id */ - pub csum: u16, - /* Packet Checksum */ -} - -#[derive(Copy, Clone)] -#[repr(C, packed)] -pub union ixgbe_adv_rx_desc_wb_lower_hi_dword { - pub rss: u32, - /* RSS Hash */ - pub csum_ip: ixgbe_adv_rx_desc_wb_lower_hi_dword_csum_ip, -} - -#[derive(Copy, Clone)] -#[repr(C, packed)] -pub struct ixgbe_adv_rx_desc_wb_lower { - pub lo_dword: ixgbe_adv_rx_desc_wb_lower_lo_dword, - pub hi_dword: ixgbe_adv_rx_desc_wb_lower_hi_dword, -} - -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct ixgbe_adv_rx_desc_wb_upper { - pub status_error: u32, - /* ext status/error */ - pub length: u16, - /* Packet length */ - pub vlan: u16, - /* VLAN tag */ -} - -#[derive(Copy, Clone)] -#[repr(C, packed)] -pub struct ixgbe_adv_rx_desc_wb { - pub lower: ixgbe_adv_rx_desc_wb_lower, - pub upper: ixgbe_adv_rx_desc_wb_upper, -} - -#[derive(Copy, Clone)] -#[repr(C, packed)] -pub union ixgbe_adv_rx_desc { - pub read: ixgbe_adv_rx_desc_read, - pub wb: ixgbe_adv_rx_desc_wb, /* writeback */ - _union_align: [u64; 2], -} - -/* Transmit Descriptor - Advanced */ -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct ixgbe_adv_tx_desc_read { - pub buffer_addr: u64, - /* Address of descriptor's data buf */ - pub cmd_type_len: u32, - pub olinfo_status: u32, -} - -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct ixgbe_adv_tx_desc_wb { - pub rsvd: u64, - /* Reserved */ - pub nxtseq_seed: u32, - pub status: u32, -} - -#[derive(Copy, Clone)] -#[repr(C, packed)] -pub union ixgbe_adv_tx_desc { - pub read: ixgbe_adv_tx_desc_read, - pub wb: ixgbe_adv_tx_desc_wb, - _union_align: [u64; 2], -} diff --git a/recipes/core/base/drivers/net/ixgbed/src/main.rs b/recipes/core/base/drivers/net/ixgbed/src/main.rs deleted file mode 100644 index 4a6ce74dcd..0000000000 --- a/recipes/core/base/drivers/net/ixgbed/src/main.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::io::{Read, Write}; -use std::os::unix::io::AsRawFd; - -use driver_network::NetworkScheme; -use event::{user_data, EventQueue}; -use pcid_interface::PciFunctionHandle; - -pub mod device; -#[rustfmt::skip] -mod ixgbe; - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - let pci_config = pcid_handle.config(); - - let mut name = pci_config.func.name(); - name.push_str("_ixgbe"); - - let irq = pci_config - .func - .legacy_interrupt_line - .expect("ixgbed: no legacy interrupts supported"); - - println!(" + IXGBE {}", pci_config.func.display()); - - let mut irq_file = irq.irq_handle("ixgbed"); - - let mapped_bar = unsafe { pcid_handle.map_bar(0) }; - let address = mapped_bar.ptr.as_ptr(); - let size = mapped_bar.bar_size; - - let mut scheme = NetworkScheme::new( - move || { - device::Intel8259x::new(address as usize, size) - .expect("ixgbed: failed to allocate device") - }, - daemon, - format!("network.{name}"), - ); - - user_data! { - enum Source { - Irq, - Scheme, - } - } - - let event_queue = EventQueue::::new().expect("ixgbed: Could not create event queue."); - event_queue - .subscribe( - irq_file.as_raw_fd() as usize, - Source::Irq, - event::EventFlags::READ, - ) - .unwrap(); - event_queue - .subscribe( - scheme.event_handle().raw(), - Source::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - - libredox::call::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); - - scheme.tick().unwrap(); - - for event in event_queue.map(|e| e.expect("ixgbed: failed to get next event")) { - match event.user_data { - Source::Irq => { - let mut irq = [0; 8]; - irq_file.read(&mut irq).unwrap(); - if scheme.adapter().irq() { - irq_file.write(&mut irq).unwrap(); - - scheme.tick().unwrap(); - } - } - Source::Scheme => { - scheme.tick().unwrap(); - } - } - } - unreachable!() -} diff --git a/recipes/core/base/drivers/net/rtl8139d/Cargo.toml b/recipes/core/base/drivers/net/rtl8139d/Cargo.toml deleted file mode 100644 index 8686242a89..0000000000 --- a/recipes/core/base/drivers/net/rtl8139d/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "rtl8139d" -description = "Realtek 8139 ethernet driver" -version = "0.1.0" -edition = "2018" - -[dependencies] -bitflags.workspace = true -libredox.workspace = true -log.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-network = { path = "../driver-network" } -pcid = { path = "../../pcid" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/net/rtl8139d/config.toml b/recipes/core/base/drivers/net/rtl8139d/config.toml deleted file mode 100644 index 05c5322479..0000000000 --- a/recipes/core/base/drivers/net/rtl8139d/config.toml +++ /dev/null @@ -1,5 +0,0 @@ -[[drivers]] -name = "RTL8139 NIC" -class = 0x02 -ids = { 0x10ec = [0x8139] } -command = ["rtl8139d"] diff --git a/recipes/core/base/drivers/net/rtl8139d/src/device.rs b/recipes/core/base/drivers/net/rtl8139d/src/device.rs deleted file mode 100644 index 37167ee2fb..0000000000 --- a/recipes/core/base/drivers/net/rtl8139d/src/device.rs +++ /dev/null @@ -1,309 +0,0 @@ -use std::convert::TryInto; -use std::mem; - -use driver_network::NetworkAdapter; -use syscall::error::{Error, Result, EIO, EMSGSIZE}; - -use common::dma::Dma; -use common::io::{Io, Mmio, ReadOnly}; -use common::timeout::Timeout; - -const RX_BUFFER_SIZE: usize = 64 * 1024; - -const RXSTS_ROK: u16 = 1 << 0; - -const TSD_TOK: u32 = 1 << 15; -const TSD_OWN: u32 = 1 << 13; -const TSD_SIZE_MASK: u32 = 0x1FFF; - -const CR_RST: u8 = 1 << 4; -const CR_RE: u8 = 1 << 3; -const CR_TE: u8 = 1 << 2; -const CR_BUFE: u8 = 1 << 0; - -const IMR_TOK: u16 = 1 << 2; -const IMR_ROK: u16 = 1 << 0; - -const RCR_RBLEN_8K: u32 = 0b00 << 11; -const RCR_RBLEN_16K: u32 = 0b01 << 11; -const RCR_RBLEN_32K: u32 = 0b10 << 11; -const RCR_RBLEN_64K: u32 = 0b11 << 11; -const RCR_RBLEN_MASK: u32 = 0b11 << 11; -const RCR_AER: u32 = 1 << 5; -const RCR_AR: u32 = 1 << 4; -const RCR_AB: u32 = 1 << 3; -const RCR_AM: u32 = 1 << 2; -const RCR_APM: u32 = 1 << 1; -const RCR_AAP: u32 = 1 << 0; - -#[repr(C, packed)] -struct Regs { - mac: [Mmio; 2], - mar: [Mmio; 2], - tsd: [Mmio; 4], - tsad: [Mmio; 4], - rbstart: Mmio, - erbcr: ReadOnly>, - ersr: ReadOnly>, - cr: Mmio, - capr: Mmio, - cbr: ReadOnly>, - imr: Mmio, - isr: Mmio, - tcr: Mmio, - rcr: Mmio, - tctr: Mmio, - mpc: Mmio, - cr_9346: Mmio, - config0: Mmio, - config1: Mmio, - rsvd_53: ReadOnly>, - timer_int: Mmio, - msr: Mmio, - config2: Mmio, - config3: Mmio, - rsvd_5b: ReadOnly>, - mulint: Mmio, - rerid: ReadOnly>, - rsvd_5f: ReadOnly>, - tsts: ReadOnly>, - _todo: [ReadOnly>; 158], -} - -impl Regs { - unsafe fn from_base(base: usize) -> &'static mut Self { - assert_eq!(mem::size_of::(), 256); - - let regs = &mut *(base as *mut Regs); - - assert_eq!(®s.mac[0] as *const _ as usize - base, 0x00); - assert_eq!(®s.mac[1] as *const _ as usize - base, 0x04); - assert_eq!(®s.mar[0] as *const _ as usize - base, 0x08); - assert_eq!(®s.mar[1] as *const _ as usize - base, 0x0C); - assert_eq!(®s.tsd[0] as *const _ as usize - base, 0x10); - assert_eq!(®s.tsd[1] as *const _ as usize - base, 0x14); - assert_eq!(®s.tsd[2] as *const _ as usize - base, 0x18); - assert_eq!(®s.tsd[3] as *const _ as usize - base, 0x1C); - assert_eq!(®s.tsad[0] as *const _ as usize - base, 0x20); - assert_eq!(®s.tsad[1] as *const _ as usize - base, 0x24); - assert_eq!(®s.tsad[2] as *const _ as usize - base, 0x28); - assert_eq!(®s.tsad[3] as *const _ as usize - base, 0x2C); - assert_eq!(®s.rbstart as *const _ as usize - base, 0x30); - assert_eq!(®s.erbcr as *const _ as usize - base, 0x34); - assert_eq!(®s.ersr as *const _ as usize - base, 0x36); - assert_eq!(®s.cr as *const _ as usize - base, 0x37); - assert_eq!(®s.capr as *const _ as usize - base, 0x38); - assert_eq!(®s.cbr as *const _ as usize - base, 0x3A); - assert_eq!(®s.imr as *const _ as usize - base, 0x3C); - assert_eq!(®s.isr as *const _ as usize - base, 0x3E); - assert_eq!(®s.tcr as *const _ as usize - base, 0x40); - assert_eq!(®s.rcr as *const _ as usize - base, 0x44); - assert_eq!(®s.tctr as *const _ as usize - base, 0x48); - assert_eq!(®s.mpc as *const _ as usize - base, 0x4C); - assert_eq!(®s.cr_9346 as *const _ as usize - base, 0x50); - assert_eq!(®s.config0 as *const _ as usize - base, 0x51); - assert_eq!(®s.config1 as *const _ as usize - base, 0x52); - assert_eq!(®s.rsvd_53 as *const _ as usize - base, 0x53); - assert_eq!(®s.timer_int as *const _ as usize - base, 0x54); - assert_eq!(®s.msr as *const _ as usize - base, 0x58); - assert_eq!(®s.config2 as *const _ as usize - base, 0x59); - assert_eq!(®s.config3 as *const _ as usize - base, 0x5A); - assert_eq!(®s.rsvd_5b as *const _ as usize - base, 0x5B); - assert_eq!(®s.mulint as *const _ as usize - base, 0x5C); - assert_eq!(®s.rerid as *const _ as usize - base, 0x5E); - assert_eq!(®s.rsvd_5f as *const _ as usize - base, 0x5F); - assert_eq!(®s.tsts as *const _ as usize - base, 0x60); - - regs - } -} - -pub struct Rtl8139 { - regs: &'static mut Regs, - receive_buffer: Dma<[Mmio; RX_BUFFER_SIZE + 16]>, - receive_i: usize, - transmit_buffer: [Dma<[Mmio; 1792]>; 4], - transmit_i: usize, - mac_address: [u8; 6], -} - -impl NetworkAdapter for Rtl8139 { - fn mac_address(&mut self) -> [u8; 6] { - self.mac_address - } - - fn available_for_read(&mut self) -> usize { - self.next_read() - } - - fn read_packet(&mut self, buf: &mut [u8]) -> Result> { - if !self.regs.cr.readf(CR_BUFE) { - let rxsts = (self.rx(0) as u16) | (self.rx(1) as u16) << 8; - - let size_with_crc = (self.rx(2) as usize) | (self.rx(3) as usize) << 8; - - let res = if (rxsts & RXSTS_ROK) == RXSTS_ROK { - let mut i = 0; - while i < buf.len() && i < size_with_crc.saturating_sub(4) { - buf[i] = self.rx(4 + i as u16); - i += 1; - } - Ok(Some(i)) - } else { - //TODO: better error types - log::error!("invalid receive status 0x{:X}", rxsts); - Err(Error::new(EIO)) - }; - - self.receive_i = - (self.receive_i + 4 + size_with_crc).next_multiple_of(4) % RX_BUFFER_SIZE; - let capr = self.receive_i.wrapping_sub(16) as u16; - self.regs.capr.write(capr); - - res - } else { - Ok(None) - } - } - - fn write_packet(&mut self, buf: &[u8]) -> Result { - loop { - if self.transmit_i >= 4 { - self.transmit_i = 0; - } - - if self.regs.tsd[self.transmit_i].readf(TSD_OWN) { - let data = &mut self.transmit_buffer[self.transmit_i]; - - if buf.len() > data.len() { - return Err(Error::new(EMSGSIZE)); - } - - let mut i = 0; - while i < buf.len() && i < data.len() { - data[i].write(buf[i]); - i += 1; - } - - self.regs.tsad[self.transmit_i].write(data.physical() as u32); - assert_eq!(i as u32, i as u32 & TSD_SIZE_MASK); - self.regs.tsd[self.transmit_i].write(i as u32 & TSD_SIZE_MASK); - - //TODO: wait for TSD_TOK or error - - self.transmit_i += 1; - - return Ok(i); - } - - std::hint::spin_loop(); - } - } -} - -impl Rtl8139 { - pub unsafe fn new(base: usize) -> Result { - let regs = Regs::from_base(base); - - let mut module = Rtl8139 { - regs, - //TODO: limit to 32-bit - receive_buffer: Dma::zeroed().map(|dma| dma.assume_init())?, - receive_i: 0, - //TODO: limit to 32-bit - transmit_buffer: (0..4) - .map(|_| Ok(Dma::zeroed()?.assume_init())) - .collect::>>()? - .try_into() - .unwrap_or_else(|_| unreachable!()), - transmit_i: 0, - mac_address: [0; 6], - }; - - module.init()?; - - Ok(module) - } - - pub unsafe fn irq(&mut self) -> bool { - // Read and then clear the ISR - let isr = self.regs.isr.read(); - self.regs.isr.write(isr); - let imr = self.regs.imr.read(); - (isr & imr) != 0 - } - - fn rx(&self, offset: u16) -> u8 { - let index = (self.receive_i + offset as usize) % RX_BUFFER_SIZE; - self.receive_buffer[index].read() - } - - pub fn next_read(&self) -> usize { - if !self.regs.cr.readf(CR_BUFE) { - let rxsts = (self.rx(0) as u16) | (self.rx(1) as u16) << 8; - - let size_with_crc = (self.rx(2) as usize) | (self.rx(3) as usize) << 8; - - if (rxsts & RXSTS_ROK) == RXSTS_ROK { - size_with_crc.saturating_sub(4) - } else { - 0 - } - } else { - 0 - } - } - - pub unsafe fn init(&mut self) -> Result<()> { - let mac_low = self.regs.mac[0].read(); - let mac_high = self.regs.mac[1].read(); - let mac = [ - mac_low as u8, - (mac_low >> 8) as u8, - (mac_low >> 16) as u8, - (mac_low >> 24) as u8, - mac_high as u8, - (mac_high >> 8) as u8, - ]; - log::debug!( - "MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac[0], - mac[1], - mac[2], - mac[3], - mac[4], - mac[5] - ); - self.mac_address = mac; - - // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value - { - log::debug!("Reset"); - let timeout = Timeout::from_secs(1); - self.regs.cr.writef(CR_RST, true); - while self.regs.cr.readf(CR_RST) { - timeout.run().map_err(|()| Error::new(EIO))?; - } - } - - // Set up rx buffer - log::debug!("Receive buffer"); - self.regs - .rbstart - .write(self.receive_buffer.physical() as u32); - - log::debug!("Interrupt mask"); - self.regs.imr.write(IMR_TOK | IMR_ROK); - - log::debug!("Receive configuration"); - self.regs - .rcr - .write(RCR_RBLEN_64K | RCR_AB | RCR_AM | RCR_APM | RCR_AAP); - - log::debug!("Enable RX and TX"); - self.regs.cr.writef(CR_RE | CR_TE, true); - - log::debug!("Complete!"); - Ok(()) - } -} diff --git a/recipes/core/base/drivers/net/rtl8139d/src/main.rs b/recipes/core/base/drivers/net/rtl8139d/src/main.rs deleted file mode 100644 index d470e814df..0000000000 --- a/recipes/core/base/drivers/net/rtl8139d/src/main.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::io::{Read, Write}; -use std::os::unix::io::AsRawFd; - -use driver_network::NetworkScheme; -use event::{user_data, EventQueue}; -use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; -use pcid_interface::PciFunctionHandle; - -pub mod device; - -use std::ops::{Add, Div, Rem}; -pub fn div_round_up(a: T, b: T) -> T -where - T: Add + Div + Rem + PartialEq + From + Copy, -{ - if a % b != T::from(0u8) { - a / b + T::from(1u8) - } else { - a / b - } -} - -fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { - let config = pcid_handle.config(); - - // RTL8139 uses BAR2, RTL8169 uses BAR1, search in that order - for &barnum in &[2, 1] { - match config.func.bars[usize::from(barnum)] { - pcid_interface::PciBar::Memory32 { .. } | pcid_interface::PciBar::Memory64 { .. } => unsafe { - return pcid_handle.map_bar(barnum).ptr.as_ptr(); - }, - other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), - } - } - panic!("rtl8139d: failed to find BAR"); -} - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - let pci_config = pcid_handle.config(); - - let mut name = pci_config.func.name(); - name.push_str("_rtl8139"); - - common::setup_logging( - "net", - "pci", - &name, - common::output_level(), - common::file_level(), - ); - - log::info!(" + RTL8139 {}", pci_config.func.display()); - - let bar = map_bar(&mut pcid_handle); - - let irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "rtl8139d"); - - let mut scheme = NetworkScheme::new( - move || unsafe { - device::Rtl8139::new(bar as usize).expect("rtl8139d: failed to allocate device") - }, - daemon, - format!("network.{name}"), - ); - - user_data! { - enum Source { - Irq, - Scheme, - } - } - - let event_queue = EventQueue::::new().expect("rtl8139d: Could not create event queue."); - event_queue - .subscribe( - irq_file.irq_handle().as_raw_fd() as usize, - Source::Irq, - event::EventFlags::READ, - ) - .unwrap(); - event_queue - .subscribe( - scheme.event_handle().raw(), - Source::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - - libredox::call::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); - - scheme.tick().unwrap(); - - for event in event_queue.map(|e| e.expect("rtl8139d: failed to get next event")) { - match event.user_data { - Source::Irq => { - let mut irq = [0; 8]; - irq_file.irq_handle().read(&mut irq).unwrap(); - //TODO: This may be causing spurious interrupts - if unsafe { scheme.adapter_mut().irq() } { - irq_file.irq_handle().write(&mut irq).unwrap(); - - scheme.tick().unwrap(); - } - } - Source::Scheme => { - scheme.tick().unwrap(); - } - } - } - unreachable!() -} diff --git a/recipes/core/base/drivers/net/rtl8168d/Cargo.toml b/recipes/core/base/drivers/net/rtl8168d/Cargo.toml deleted file mode 100644 index 35975ed241..0000000000 --- a/recipes/core/base/drivers/net/rtl8168d/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "rtl8168d" -description = "Realtek 8168 ethernet driver" -version = "0.1.0" -edition = "2018" - -[dependencies] -bitflags.workspace = true -libredox.workspace = true -log.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-network = { path = "../driver-network" } -pcid = { path = "../../pcid" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/net/rtl8168d/config.toml b/recipes/core/base/drivers/net/rtl8168d/config.toml deleted file mode 100644 index ee98e345f3..0000000000 --- a/recipes/core/base/drivers/net/rtl8168d/config.toml +++ /dev/null @@ -1,5 +0,0 @@ -[[drivers]] -name = "RTL8168 NIC" -class = 0x02 -ids = { 0x10ec = [0x8168, 0x8169] } -command = ["rtl8168d"] diff --git a/recipes/core/base/drivers/net/rtl8168d/src/device.rs b/recipes/core/base/drivers/net/rtl8168d/src/device.rs deleted file mode 100644 index ae545ec48c..0000000000 --- a/recipes/core/base/drivers/net/rtl8168d/src/device.rs +++ /dev/null @@ -1,345 +0,0 @@ -use std::convert::TryInto; -use std::mem; - -use common::dma::Dma; -use common::io::{Io, Mmio, ReadOnly}; -use common::timeout::Timeout; -use driver_network::NetworkAdapter; -use syscall::error::{Error, Result, EIO, EMSGSIZE}; - -#[repr(C, packed)] -struct Regs { - mac: [Mmio; 2], - _mar: [Mmio; 2], - _dtccr: [Mmio; 2], - _rsv0: [Mmio; 2], - tnpds: [Mmio; 2], - thpds: [Mmio; 2], - _rsv1: [Mmio; 7], - cmd: Mmio, - tppoll: Mmio, - _rsv2: [Mmio; 3], - imr: Mmio, - isr: Mmio, - tcr: Mmio, - rcr: Mmio, - _tctr: Mmio, - _rsv3: Mmio, - cmd_9346: Mmio, - _config: [Mmio; 6], - _rsv4: Mmio, - timer_int: Mmio, - _rsv5: Mmio, - _phys_ar: Mmio, - _rsv6: [Mmio; 2], - phys_sts: ReadOnly>, - _rsv7: [Mmio; 23], - _wakeup: [Mmio; 16], - _crc: [Mmio; 5], - _rsv8: [Mmio; 12], - rms: Mmio, - _rsv9: Mmio, - _c_plus_cr: Mmio, - _rsv10: Mmio, - rdsar: [Mmio; 2], - mtps: Mmio, - _rsv11: [Mmio; 19], -} - -const OWN: u32 = 1 << 31; -const EOR: u32 = 1 << 30; -const FS: u32 = 1 << 29; -const LS: u32 = 1 << 28; - -#[repr(C, packed)] -struct Rd { - ctrl: Mmio, - _vlan: Mmio, - buffer_low: Mmio, - buffer_high: Mmio, -} - -#[repr(C, packed)] -struct Td { - ctrl: Mmio, - _vlan: Mmio, - buffer_low: Mmio, - buffer_high: Mmio, -} - -pub struct Rtl8168 { - regs: &'static mut Regs, - receive_buffer: [Dma<[Mmio; 0x1FF8]>; 64], - receive_ring: Dma<[Rd; 64]>, - receive_i: usize, - transmit_buffer: [Dma<[Mmio; 7552]>; 16], - transmit_ring: Dma<[Td; 16]>, - transmit_i: usize, - transmit_buffer_h: [Dma<[Mmio; 7552]>; 1], - transmit_ring_h: Dma<[Td; 1]>, - mac_address: [u8; 6], -} - -impl NetworkAdapter for Rtl8168 { - fn mac_address(&mut self) -> [u8; 6] { - self.mac_address - } - - fn available_for_read(&mut self) -> usize { - self.next_read() - } - - fn read_packet(&mut self, buf: &mut [u8]) -> Result> { - if self.receive_i >= self.receive_ring.len() { - self.receive_i = 0; - } - - let rd = &mut self.receive_ring[self.receive_i]; - if !rd.ctrl.readf(OWN) { - let rd_len = rd.ctrl.read() & 0x3FFF; - - let data = &self.receive_buffer[self.receive_i]; - - let mut i = 0; - while i < buf.len() && i < rd_len as usize { - buf[i] = data[i].read(); - i += 1; - } - - let eor = rd.ctrl.read() & EOR; - rd.ctrl.write(OWN | eor | data.len() as u32); - - self.receive_i += 1; - - Ok(Some(i)) - } else { - Ok(None) - } - } - - fn write_packet(&mut self, buf: &[u8]) -> Result { - loop { - if self.transmit_i >= self.transmit_ring.len() { - self.transmit_i = 0; - } - - let td = &mut self.transmit_ring[self.transmit_i]; - if !td.ctrl.readf(OWN) { - let data = &mut self.transmit_buffer[self.transmit_i]; - - if buf.len() > data.len() { - return Err(Error::new(EMSGSIZE)); - } - - let mut i = 0; - while i < buf.len() && i < data.len() { - data[i].write(buf[i]); - i += 1; - } - - let eor = td.ctrl.read() & EOR; - td.ctrl.write(OWN | eor | FS | LS | i as u32); - - self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet - - while self.regs.tppoll.readf(1 << 6) { - std::hint::spin_loop(); - } - - self.transmit_i += 1; - - return Ok(i); - } - - std::hint::spin_loop(); - } - } -} - -impl Rtl8168 { - pub unsafe fn new(base: usize) -> Result { - assert_eq!(mem::size_of::(), 256); - - let regs = &mut *(base as *mut Regs); - assert_eq!(®s.tnpds as *const _ as usize - base, 0x20); - assert_eq!(®s.cmd as *const _ as usize - base, 0x37); - assert_eq!(®s.tcr as *const _ as usize - base, 0x40); - assert_eq!(®s.rcr as *const _ as usize - base, 0x44); - assert_eq!(®s.cmd_9346 as *const _ as usize - base, 0x50); - assert_eq!(®s.phys_sts as *const _ as usize - base, 0x6C); - assert_eq!(®s.rms as *const _ as usize - base, 0xDA); - assert_eq!(®s.rdsar as *const _ as usize - base, 0xE4); - assert_eq!(®s.mtps as *const _ as usize - base, 0xEC); - - let mut module = Rtl8168 { - regs, - receive_buffer: (0..64) - .map(|_| Ok(Dma::zeroed()?.assume_init())) - .collect::>>()? - .try_into() - .unwrap_or_else(|_| unreachable!()), - - receive_ring: Dma::zeroed()?.assume_init(), - receive_i: 0, - transmit_buffer: (0..16) - .map(|_| Ok(Dma::zeroed()?.assume_init())) - .collect::>>()? - .try_into() - .unwrap_or_else(|_| unreachable!()), - transmit_ring: Dma::zeroed()?.assume_init(), - transmit_i: 0, - transmit_buffer_h: [Dma::zeroed()?.assume_init()], - transmit_ring_h: Dma::zeroed()?.assume_init(), - mac_address: [0; 6], - }; - - module.init()?; - - Ok(module) - } - - pub unsafe fn irq(&mut self) -> bool { - // Read and then clear the ISR - let isr = self.regs.isr.read(); - self.regs.isr.write(isr); - let imr = self.regs.imr.read(); - (isr & imr) != 0 - } - - pub fn next_read(&self) -> usize { - let mut receive_i = self.receive_i; - if receive_i >= self.receive_ring.len() { - receive_i = 0; - } - - let rd = &self.receive_ring[receive_i]; - if !rd.ctrl.readf(OWN) { - (rd.ctrl.read() & 0x3FFF) as usize - } else { - 0 - } - } - - pub unsafe fn init(&mut self) -> Result<()> { - let mac_low = self.regs.mac[0].read(); - let mac_high = self.regs.mac[1].read(); - let mac = [ - mac_low as u8, - (mac_low >> 8) as u8, - (mac_low >> 16) as u8, - (mac_low >> 24) as u8, - mac_high as u8, - (mac_high >> 8) as u8, - ]; - log::debug!( - "MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac[0], - mac[1], - mac[2], - mac[3], - mac[4], - mac[5] - ); - self.mac_address = mac; - - // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value - { - log::debug!("Reset"); - let timeout = Timeout::from_secs(1); - self.regs.cmd.writef(1 << 4, true); - while self.regs.cmd.readf(1 << 4) { - timeout.run().map_err(|()| Error::new(EIO))?; - } - } - - // Set up rx buffers - log::debug!("Receive buffers"); - for i in 0..self.receive_ring.len() { - let rd = &mut self.receive_ring[i]; - let data = &mut self.receive_buffer[i]; - rd.buffer_low.write(data.physical() as u32); - rd.buffer_high.write((data.physical() as u64 >> 32) as u32); - rd.ctrl.write(OWN | data.len() as u32); - } - if let Some(rd) = self.receive_ring.last_mut() { - rd.ctrl.writef(EOR, true); - } - - // Set up normal priority tx buffers - log::debug!("Transmit buffers (normal priority)"); - for i in 0..self.transmit_ring.len() { - self.transmit_ring[i] - .buffer_low - .write(self.transmit_buffer[i].physical() as u32); - self.transmit_ring[i] - .buffer_high - .write((self.transmit_buffer[i].physical() as u64 >> 32) as u32); - } - if let Some(td) = self.transmit_ring.last_mut() { - td.ctrl.writef(EOR, true); - } - - // Set up high priority tx buffers - log::debug!("Transmit buffers (high priority)"); - for i in 0..self.transmit_ring_h.len() { - self.transmit_ring_h[i] - .buffer_low - .write(self.transmit_buffer_h[i].physical() as u32); - self.transmit_ring_h[i] - .buffer_high - .write((self.transmit_buffer_h[i].physical() as u64 >> 32) as u32); - } - if let Some(td) = self.transmit_ring_h.last_mut() { - td.ctrl.writef(EOR, true); - } - - log::debug!("Set config"); - // Unlock config - self.regs.cmd_9346.write(1 << 7 | 1 << 6); - - // Enable rx (bit 3) and tx (bit 2) - self.regs.cmd.writef(1 << 3 | 1 << 2, true); - - // Max RX packet size - self.regs.rms.write(0x1FF8); - - // Max TX packet size - self.regs.mtps.write(0x3B); - - // Set tx low priority buffer address - self.regs.tnpds[0].write(self.transmit_ring.physical() as u32); - self.regs.tnpds[1].write(((self.transmit_ring.physical() as u64) >> 32) as u32); - - // Set tx high priority buffer address - self.regs.thpds[0].write(self.transmit_ring_h.physical() as u32); - self.regs.thpds[1].write(((self.transmit_ring_h.physical() as u64) >> 32) as u32); - - // Set rx buffer address - self.regs.rdsar[0].write(self.receive_ring.physical() as u32); - self.regs.rdsar[1].write(((self.receive_ring.physical() as u64) >> 32) as u32); - - // Disable timer interrupt - self.regs.timer_int.write(0); - - //Clear ISR - let isr = self.regs.isr.read(); - self.regs.isr.write(isr); - - // Interrupt on tx error (bit 3), tx ok (bit 2), rx error(bit 1), and rx ok (bit 0) - self.regs.imr.write( - 1 << 15 | 1 << 14 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1, - ); - - // Set TX config - self.regs.tcr.write(0b11 << 24 | 0b111 << 8); - - // Set RX config - Accept broadcast (bit 3), multicast (bit 2), and unicast (bit 1) - self.regs.rcr.write(0xE70E); - - // Lock config - self.regs.cmd_9346.write(0); - - log::debug!("Complete!"); - Ok(()) - } -} diff --git a/recipes/core/base/drivers/net/rtl8168d/src/main.rs b/recipes/core/base/drivers/net/rtl8168d/src/main.rs deleted file mode 100644 index 1d9963a3ad..0000000000 --- a/recipes/core/base/drivers/net/rtl8168d/src/main.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::io::{Read, Write}; -use std::os::unix::io::AsRawFd; - -use driver_network::NetworkScheme; -use event::{user_data, EventQueue}; -use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; -use pcid_interface::PciFunctionHandle; - -pub mod device; - -use std::ops::{Add, Div, Rem}; -pub fn div_round_up(a: T, b: T) -> T -where - T: Add + Div + Rem + PartialEq + From + Copy, -{ - if a % b != T::from(0u8) { - a / b + T::from(1u8) - } else { - a / b - } -} - -fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { - let config = pcid_handle.config(); - - // RTL8168 uses BAR2, RTL8169 uses BAR1, search in that order - for &barnum in &[2, 1] { - match config.func.bars[usize::from(barnum)] { - pcid_interface::PciBar::Memory32 { .. } | pcid_interface::PciBar::Memory64 { .. } => unsafe { - return pcid_handle.map_bar(barnum).ptr.as_ptr(); - }, - other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), - } - } - panic!("rtl8168d: failed to find BAR"); -} - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - let pci_config = pcid_handle.config(); - - let mut name = pci_config.func.name(); - name.push_str("_rtl8168"); - - common::setup_logging( - "net", - "pci", - &name, - common::output_level(), - common::file_level(), - ); - - log::info!("RTL8168 {}", pci_config.func.display()); - - let bar = map_bar(&mut pcid_handle); - - let irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "rtl8168d"); - - let mut scheme = NetworkScheme::new( - move || unsafe { - device::Rtl8168::new(bar as usize).expect("rtl8168d: failed to allocate device") - }, - daemon, - format!("network.{name}"), - ); - - user_data! { - enum Source { - Irq, - Scheme, - } - } - - let event_queue = EventQueue::::new().expect("rtl8168d: Could not create event queue."); - event_queue - .subscribe( - irq_file.irq_handle().as_raw_fd() as usize, - Source::Irq, - event::EventFlags::READ, - ) - .unwrap(); - event_queue - .subscribe( - scheme.event_handle().raw(), - Source::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - - libredox::call::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); - - scheme.tick().unwrap(); - - for event in event_queue.map(|e| e.expect("rtl8168d: failed to get next event")) { - match event.user_data { - Source::Irq => { - let mut irq = [0; 8]; - irq_file.irq_handle().read(&mut irq).unwrap(); - //TODO: This may be causing spurious interrupts - if unsafe { scheme.adapter_mut().irq() } { - irq_file.irq_handle().write(&mut irq).unwrap(); - - scheme.tick().unwrap(); - } - } - Source::Scheme => { - scheme.tick().unwrap(); - } - } - } - unreachable!() -} diff --git a/recipes/core/base/drivers/net/virtio-netd/Cargo.toml b/recipes/core/base/drivers/net/virtio-netd/Cargo.toml deleted file mode 100644 index f8e943f3d8..0000000000 --- a/recipes/core/base/drivers/net/virtio-netd/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -name = "virtio-netd" -description = "VirtIO network driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -log.workspace = true -static_assertions.workspace = true -futures = { version = "0.3.28", features = ["executor"] } - -virtio-core = { path = "../../virtio-core" } -pcid = { path = "../../pcid" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-network = { path = "../driver-network" } - -redox_syscall.workspace = true -libredox.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/net/virtio-netd/config.toml b/recipes/core/base/drivers/net/virtio-netd/config.toml deleted file mode 100644 index ebedb9e40c..0000000000 --- a/recipes/core/base/drivers/net/virtio-netd/config.toml +++ /dev/null @@ -1,6 +0,0 @@ -[[drivers]] -name = "virtio-net" -class = 0x02 -vendor = 0x1AF4 -device = 0x1000 -command = ["virtio-netd"] diff --git a/recipes/core/base/drivers/net/virtio-netd/src/main.rs b/recipes/core/base/drivers/net/virtio-netd/src/main.rs deleted file mode 100644 index 1200cec92f..0000000000 --- a/recipes/core/base/drivers/net/virtio-netd/src/main.rs +++ /dev/null @@ -1,137 +0,0 @@ -mod scheme; - -use std::fs::File; -use std::io::{Read, Write}; -use std::mem; - -use driver_network::NetworkScheme; -use pcid_interface::PciFunctionHandle; - -use scheme::VirtioNet; - -pub const VIRTIO_NET_F_MAC: u32 = 5; - -#[derive(Debug)] -#[repr(C)] -pub struct VirtHeader { - pub flags: u8, - pub gso_type: u8, - pub hdr_len: u16, - pub gso_size: u16, - pub csum_start: u16, - pub csum_offset: u16, - pub num_buffers: u16, -} - -static_assertions::const_assert_eq!(core::mem::size_of::(), 12); - -const MAX_BUFFER_LEN: usize = 65535; -fn main() { - pcid_interface::pci_daemon(daemon_runner); -} - -fn daemon_runner(redox_daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! { - daemon(redox_daemon, pcid_handle).unwrap(); - unreachable!(); -} - -fn daemon( - daemon: daemon::Daemon, - mut pcid_handle: PciFunctionHandle, -) -> Result<(), Box> { - common::setup_logging( - "net", - "pci", - "virtio-netd", - common::output_level(), - common::file_level(), - ); - - // Double check that we have the right device. - // - // 0x1000 - virtio-net - let pci_config = pcid_handle.config(); - - assert_eq!(pci_config.func.full_device_id.device_id, 0x1000); - log::info!("virtio-net: initiating startup sequence :^)"); - - let device = virtio_core::probe_device(&mut pcid_handle)?; - let device_space = device.device_space; - - // Negotiate device features: - let mac_address = if device.transport.check_device_feature(VIRTIO_NET_F_MAC) { - let mac = unsafe { - [ - core::ptr::read_volatile(device_space.add(0)), - core::ptr::read_volatile(device_space.add(1)), - core::ptr::read_volatile(device_space.add(2)), - core::ptr::read_volatile(device_space.add(3)), - core::ptr::read_volatile(device_space.add(4)), - core::ptr::read_volatile(device_space.add(5)), - ] - }; - - log::info!( - "virtio-net: device MAC is {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac[0], - mac[1], - mac[2], - mac[3], - mac[4], - mac[5] - ); - - device.transport.ack_driver_feature(VIRTIO_NET_F_MAC); - mac - } else { - unimplemented!() - }; - - device.transport.finalize_features(); - - // Allocate the recieve and transmit queues: - // - // > Empty buffers are placed in one virtqueue for receiving - // > packets, and outgoing packets are enqueued into another - // > for transmission in that order. - // - // TODO(andypython): Should we use the same IRQ vector for both? - let rx_queue = device - .transport - .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR, &device.irq_handle)?; - - let tx_queue = device - .transport - .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR, &device.irq_handle)?; - - device.transport.run_device(); - - let mut name = pci_config.func.name(); - name.push_str("_virtio_net"); - - let device = VirtioNet::new(mac_address, rx_queue, tx_queue); - let mut scheme = NetworkScheme::new( - move || { - //TODO: do device init in this function to prevent hangs - device - }, - daemon, - format!("network.{name}"), - ); - - let mut event_queue = File::open("/scheme/event")?; - event_queue.write(&syscall::Event { - id: scheme.event_handle().raw(), - flags: syscall::EVENT_READ, - data: 0, - })?; - - libredox::call::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); - - scheme.tick()?; - - loop { - event_queue.read(&mut [0; mem::size_of::()])?; // Wait for event - scheme.tick()?; - } -} diff --git a/recipes/core/base/drivers/net/virtio-netd/src/scheme.rs b/recipes/core/base/drivers/net/virtio-netd/src/scheme.rs deleted file mode 100644 index 59b3b93e20..0000000000 --- a/recipes/core/base/drivers/net/virtio-netd/src/scheme.rs +++ /dev/null @@ -1,118 +0,0 @@ -use std::sync::Arc; - -use driver_network::NetworkAdapter; - -use common::dma::Dma; - -use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; -use virtio_core::transport::Queue; - -use crate::{VirtHeader, MAX_BUFFER_LEN}; - -pub struct VirtioNet<'a> { - mac_address: [u8; 6], - - /// Reciever Queue. - rx: Arc>, - rx_buffers: Vec>, - - /// Transmiter Queue. - tx: Arc>, - - recv_head: u16, -} - -impl<'a> VirtioNet<'a> { - pub fn new(mac_address: [u8; 6], rx: Arc>, tx: Arc>) -> Self { - // Populate all of the `rx_queue` with buffers to maximize performence. - let mut rx_buffers = vec![]; - for i in 0..(rx.descriptor_len() as usize) { - rx_buffers.push(unsafe { - Dma::<[u8]>::zeroed_slice(MAX_BUFFER_LEN) - .unwrap() - .assume_init() - }); - - let chain = ChainBuilder::new() - .chain(Buffer::new_unsized(&rx_buffers[i]).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - let _ = rx.send(chain); - } - - Self { - mac_address, - - rx, - rx_buffers, - tx, - - recv_head: 0, - } - } - - /// Returns the number of bytes read. Returns `0` if the operation would block. - fn try_recv(&mut self, target: &mut [u8]) -> usize { - let header_size = core::mem::size_of::(); - - if self.recv_head == self.rx.used.head_index() { - // The read would block. - return 0; - } - - let idx = self.rx.used.head_index() as usize; - let element = self.rx.used.get_element_at(idx - 1); - - let descriptor_idx = element.table_index.get(); - let payload_size = element.written.get() as usize - header_size; - - // XXX: The header and packet are added as one output descriptor to the transmit queue, - // and the device is notified of the new entry (see 5.1.5 Device Initialization). - let buffer = &self.rx_buffers[descriptor_idx as usize]; - // TODO: Check the header. - let _header = unsafe { &*(buffer.as_ptr() as *const VirtHeader) }; - let packet = &buffer[header_size..(header_size + payload_size)]; - - // Copy the packet into the buffer. - target[..payload_size].copy_from_slice(&packet); - - self.recv_head = self.rx.used.head_index(); - payload_size - } -} - -impl<'a> NetworkAdapter for VirtioNet<'a> { - fn mac_address(&mut self) -> [u8; 6] { - self.mac_address - } - - fn available_for_read(&mut self) -> usize { - (self.rx.used.head_index() - self.recv_head).into() - } - - fn read_packet(&mut self, buf: &mut [u8]) -> syscall::Result> { - let bytes = self.try_recv(buf); - - if bytes != 0 { - // We read some bytes. - Ok(Some(bytes)) - } else { - Ok(None) - } - } - - fn write_packet(&mut self, buffer: &[u8]) -> syscall::Result { - let header = unsafe { Dma::::zeroed()?.assume_init() }; - - let mut payload = unsafe { Dma::<[u8]>::zeroed_slice(buffer.len())?.assume_init() }; - payload.copy_from_slice(buffer); - - let chain = ChainBuilder::new() - .chain(Buffer::new(&header)) - .chain(Buffer::new_unsized(&payload)) - .build(); - - futures::executor::block_on(self.tx.send(chain)); - Ok(buffer.len()) - } -} diff --git a/recipes/core/base/drivers/pcid-spawner/Cargo.toml b/recipes/core/base/drivers/pcid-spawner/Cargo.toml deleted file mode 100644 index 8c03f8d33a..0000000000 --- a/recipes/core/base/drivers/pcid-spawner/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "pcid-spawner" -description = "PCI-based device driver spawner daemon" -version = "0.1.0" -authors = ["4lDO2 <4lDO2@protonmail.com>"] -edition = "2021" -license = "MIT" - -[dependencies] -anyhow.workspace = true -log.workspace = true -pico-args.workspace = true -redox_syscall.workspace = true -serde.workspace = true -toml.workspace = true - -config = { path = "../../config" } -common = { path = "../common" } -daemon = { path = "../../daemon" } -pcid = { path = "../pcid" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/pcid-spawner/recipe.toml b/recipes/core/base/drivers/pcid-spawner/recipe.toml deleted file mode 100644 index 61e62e0894..0000000000 --- a/recipes/core/base/drivers/pcid-spawner/recipe.toml +++ /dev/null @@ -1,8 +0,0 @@ -[source] -path = "../../source/drivers/pcid-spawner" - -[build] -template = "cargo" - -[package] -dependencies = ["base"] diff --git a/recipes/core/base/drivers/pcid-spawner/src/main.rs b/recipes/core/base/drivers/pcid-spawner/src/main.rs deleted file mode 100644 index a968f4d494..0000000000 --- a/recipes/core/base/drivers/pcid-spawner/src/main.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::fs; -use std::process::Command; - -use anyhow::{anyhow, Context, Result}; - -use pcid_interface::config::Config; -use pcid_interface::PciFunctionHandle; - -fn main() -> Result<()> { - let mut args = pico_args::Arguments::from_env(); - let initfs = args.contains("--initfs"); - - common::setup_logging( - "bus", - "pci", - "pci-spawner.log", - common::output_level(), - common::file_level(), - ); - - let mut config_data = String::new(); - for path in if initfs { - config::config_for_initfs("pcid")? - } else { - config::config("pcid")? - } { - if let Ok(tmp) = fs::read_to_string(path) { - config_data.push_str(&tmp); - } - } - - let config: Config = toml::from_str(&config_data)?; - - for entry in fs::read_dir("/scheme/pci")? { - let entry = entry.context("failed to get entry")?; - let device_path = entry.path(); - log::trace!("ENTRY: {}", device_path.to_string_lossy()); - - let mut handle = match PciFunctionHandle::connect_by_path(&device_path) { - Ok(handle) => handle, - Err(err) if err.raw_os_error() == Some(syscall::ENOLCK) => { - log::debug!( - "pcid-spawner: {} already in use: {err}", - device_path.display(), - ); - continue; - } - Err(err) => { - log::error!( - "pcid-spawner: failed to open channel for {}: {err}", - device_path.display(), - ); - continue; - } - }; - - let full_device_id = handle.config().func.full_device_id; - - log::debug!( - "pcid-spawner enumerated: PCI {} {}", - handle.config().func.addr, - full_device_id.display() - ); - - let Some(driver) = config - .drivers - .iter() - .find(|driver| driver.match_function(&full_device_id)) - else { - log::debug!("no driver for {}, continuing", handle.config().func.addr); - continue; - }; - - let mut args = driver.command.iter(); - - let program = args - .next() - .ok_or_else(|| anyhow!("driver configuration entry did not have any command!"))?; - let program = if program.starts_with('/') { - program.to_owned() - } else { - "/usr/lib/drivers/".to_owned() + program - }; - - let mut command = Command::new(program); - command.args(args); - - log::info!("pcid-spawner: spawn {:?}", command); - - handle.enable_device(); - - let channel_fd = handle.into_inner_fd(); - command.env("PCID_CLIENT_CHANNEL", channel_fd.to_string()); - - #[allow(deprecated, reason = "we can't yet move this to init")] - daemon::Daemon::spawn(command); - syscall::close(channel_fd as usize).unwrap(); - } - - Ok(()) -} diff --git a/recipes/core/base/drivers/pcid/.gitignore b/recipes/core/base/drivers/pcid/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/recipes/core/base/drivers/pcid/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/recipes/core/base/drivers/pcid/Cargo.toml b/recipes/core/base/drivers/pcid/Cargo.toml deleted file mode 100644 index 6969531136..0000000000 --- a/recipes/core/base/drivers/pcid/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "pcid" -description = "PCI and PCI Express driver" -version = "0.1.0" -edition = "2021" - -[[bin]] -name = "pcid" -path = "src/main.rs" - -[lib] -name = "pcid_interface" -path = "src/lib.rs" - -[dependencies] -bincode = "1.2" -fdt.workspace = true -libc.workspace = true -log.workspace = true -pci_types = "0.10.1" -pico-args = { workspace = true, features = ["combined-flags"] } -plain.workspace = true -redox-scheme.workspace = true -scheme-utils = { path = "../../scheme-utils" } -redox_syscall.workspace = true -serde.workspace = true - -common = { path = "../common" } -daemon = { path = "../../daemon" } -libredox.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/pcid/src/cfg_access/fallback.rs b/recipes/core/base/drivers/pcid/src/cfg_access/fallback.rs deleted file mode 100644 index 671d17f735..0000000000 --- a/recipes/core/base/drivers/pcid/src/cfg_access/fallback.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::cell::Cell; -use std::convert::TryFrom; -use std::sync::Mutex; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use common::io::{Io as _, Pio}; - -use log::info; -use pci_types::{ConfigRegionAccess, PciAddress}; - -pub(crate) struct Pci { - lock: Mutex<()>, -} - -impl Pci { - pub(crate) fn new() -> Self { - Self { - lock: Mutex::new(()), - } - } - - fn set_iopl() { - // The IO privilege level is per-thread, so we need to do the initialization on every thread. - thread_local! { - static IOPL_ONCE: Cell = Cell::new(false); - } - - IOPL_ONCE.with(|iopl_once| { - if !iopl_once.replace(true) { - // make sure that pcid is not granted io port permission unless pcie memory-mapped - // configuration space is not available. - info!( - "PCI: couldn't find or access PCIe extended configuration, \ - and thus falling back to PCI 3.0 io ports" - ); - common::acquire_port_io_rights().expect("pcid: failed to get IO port rights"); - } - }); - } - - fn address(address: PciAddress, offset: u8) -> u32 { - assert_eq!( - address.segment(), - 0, - "usage of multiple segments requires PCIe extended configuration" - ); - - assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); - - 0x80000000 - | (u32::from(address.bus()) << 16) - | (u32::from(address.device()) << 11) - | (u32::from(address.function()) << 8) - | u32::from(offset) - } -} -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -impl ConfigRegionAccess for Pci { - unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { - let _guard = self.lock.lock().unwrap(); - - Self::set_iopl(); - - let offset = - u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); - let address = Self::address(address, offset); - - Pio::::new(0xCF8).write(address); - Pio::::new(0xCFC).read() - } - - unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) { - let _guard = self.lock.lock().unwrap(); - - Self::set_iopl(); - - let offset = - u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); - let address = Self::address(address, offset); - - Pio::::new(0xCF8).write(address); - Pio::::new(0xCFC).write(value); - } -} -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -impl ConfigRegionAccess for Pci { - unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { - let _guard = self.lock.lock().unwrap(); - todo!("Pci::CfgAccess::read on this architecture") - } - - unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32) { - let _guard = self.lock.lock().unwrap(); - todo!("Pci::CfgAccess::write on this architecture") - } -} diff --git a/recipes/core/base/drivers/pcid/src/cfg_access/mod.rs b/recipes/core/base/drivers/pcid/src/cfg_access/mod.rs deleted file mode 100644 index c25524485a..0000000000 --- a/recipes/core/base/drivers/pcid/src/cfg_access/mod.rs +++ /dev/null @@ -1,372 +0,0 @@ -use std::sync::Mutex; -use std::{fs, io, mem}; - -use common::{MemoryType, PhysBorrowed, Prot}; -use fdt::Fdt; -use pci_types::{ConfigRegionAccess, PciAddress}; - -use fallback::Pci; - -mod fallback; - -pub struct InterruptMap { - pub addr: [u32; 3], - pub interrupt: u32, - pub parent_phandle: u32, - pub parent_interrupt: [u32; 3], - pub parent_interrupt_cells: usize, -} - -// https://elinux.org/Device_Tree_Usage has a lot of useful information -fn locate_ecam_dtb( - f: impl FnOnce(PcieAllocs<'_>, Vec, [u32; 4]) -> io::Result, -) -> io::Result { - let dtb = fs::read("/scheme/kernel.dtb")?; - let dt = Fdt::new(&dtb).map_err(|err| { - io::Error::new( - io::ErrorKind::InvalidData, - format!("invalid device tree: {err:?}"), - ) - })?; - - let node = dt - .find_compatible(&["pci-host-ecam-generic"]) - .ok_or_else(|| { - io::Error::new( - io::ErrorKind::NotFound, - "couldn't find pci-host-ecam-generic node in device tree", - ) - })?; - - let address = node.reg().unwrap().next().unwrap().starting_address as u64; - - let bus_range = node.property("bus-range").unwrap(); - assert_eq!(bus_range.value.len(), 8); - let start_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.value[0..4]).unwrap()); - let end_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.value[4..8]).unwrap()); - - // address-cells == 3, size-cells == 2, interrupt-cells == 1 - let mut interrupt_map_data = node - .property("interrupt-map") - .unwrap() - .value - .chunks_exact(4) - .map(|x| u32::from_be_bytes(<[u8; 4]>::try_from(x).unwrap())); - let mut interrupt_map = Vec::::new(); - while let Ok([addr1, addr2, addr3, int1, phandle]) = interrupt_map_data.next_chunk::<5>() { - let parent = dt.find_phandle(phandle).unwrap(); - let parent_address_cells = u32::from_be_bytes( - parent.property("#address-cells").unwrap().value[..4] - .try_into() - .unwrap(), - ); - match parent_address_cells { - 0 => {} - 1 => { - assert_eq!(interrupt_map_data.next().unwrap(), 0); - } - 2 => { - assert_eq!(interrupt_map_data.next_chunk::<2>().unwrap(), [0, 0]); - } - 3 => { - assert_eq!(interrupt_map_data.next_chunk::<3>().unwrap(), [0, 0, 0]); - } - _ => break, - }; - let parent_interrupt_cells = parent.interrupt_cells().unwrap(); - let parent_interrupt = match parent_interrupt_cells { - 1 if let Some(a) = interrupt_map_data.next() => [a, 0, 0], - 2 if let Ok([a, b]) = interrupt_map_data.next_chunk::<2>() => [a, b, 0], - 3 if let Ok([a, b, c]) = interrupt_map_data.next_chunk::<3>() => [a, b, c], - _ => break, - }; - interrupt_map.push(InterruptMap { - addr: [addr1, addr2, addr3], - interrupt: int1, - parent_phandle: phandle, - parent_interrupt, - parent_interrupt_cells, - }); - } - - let interrupt_map_mask = if let Some(interrupt_mask_node) = node.property("interrupt-map-mask") - { - let mut cells = interrupt_mask_node - .value - .chunks_exact(4) - .map(|x| u32::from_be_bytes(<[u8; 4]>::try_from(x).unwrap())); - cells.next_chunk::<4>().unwrap().to_owned() - } else { - [u32::MAX, u32::MAX, u32::MAX, u32::MAX] - }; - - f( - PcieAllocs(&[PcieAlloc { - base_addr: address, - seg_group_num: 0, - start_bus: start_bus.try_into().unwrap(), - end_bus: end_bus.try_into().unwrap(), - _rsvd: [0; 4], - }]), - interrupt_map, - interrupt_map_mask, - ) -} - -pub const MCFG_NAME: [u8; 4] = *b"MCFG"; - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct Mcfg { - // base sdt fields - name: [u8; 4], - length: u32, - revision: u8, - checksum: u8, - oem_id: [u8; 6], - oem_table_id: [u8; 8], - oem_revision: u32, - creator_id: [u8; 4], - creator_revision: u32, - _rsvd: [u8; 8], -} -unsafe impl plain::Plain for Mcfg {} - -/// The "Memory Mapped Enhanced Configuration Space Base Address Allocation Structure" (yes, it's -/// called that). -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct PcieAlloc { - pub base_addr: u64, - pub seg_group_num: u16, - pub start_bus: u8, - pub end_bus: u8, - _rsvd: [u8; 4], -} -unsafe impl plain::Plain for PcieAlloc {} - -#[derive(Debug)] -struct PcieAllocs<'a>(&'a [PcieAlloc]); - -impl Mcfg { - fn with( - f: impl FnOnce(PcieAllocs<'_>, Vec, [u32; 4]) -> io::Result, - ) -> io::Result { - let table_dir = fs::read_dir("/scheme/acpi/tables")?; - - // TODO: validate/print MCFG? - - for table_direntry in table_dir { - let table_path = table_direntry?.path(); - - // Every directory entry has to have a filename unless - // the filesystem (or in this case acpid) misbehaves. - // If it misbehaves we have worse problems than pcid - // crashing. `as_encoded_bytes()` returns some superset - // of ASCII, so directly comparing it with an ASCII name - // is fine. - let table_filename = table_path.file_name().unwrap().as_encoded_bytes(); - if table_filename.get(0..4) == Some(&MCFG_NAME) { - let bytes = fs::read(table_path)?.into_boxed_slice(); - match Mcfg::parse(&*bytes) { - Some((_mcfg, allocs)) => { - log::debug!("MCFG ALLOCS {:?}", allocs.0); - return f(allocs, Vec::new(), [u32::MAX, u32::MAX, u32::MAX, u32::MAX]); - } - None => { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "couldn't find mcfg table", - )); - } - } - } - } - - Err(io::Error::new( - io::ErrorKind::NotFound, - "couldn't find mcfg table", - )) - } - - fn parse<'a>(bytes: &'a [u8]) -> Option<(&'a Mcfg, PcieAllocs<'a>)> { - if bytes.len() < mem::size_of::() { - return None; - } - let (header_bytes, allocs_bytes) = bytes.split_at(mem::size_of::()); - - let mcfg = - plain::from_bytes::(header_bytes).expect("packed -> align 1, checked size"); - if mcfg.length as usize != bytes.len() { - log::warn!("MCFG {mcfg:?} length mismatch, expected {}", bytes.len()); - return None; - } - // TODO: Allow invalid bytes not divisible by PcieAlloc? - - let allocs_len = - allocs_bytes.len() / mem::size_of::() * mem::size_of::(); - - let allocs = plain::slice_from_bytes::(&allocs_bytes[..allocs_len]) - .expect("packed -> align 1, checked size"); - Some((mcfg, PcieAllocs(allocs))) - } -} - -pub struct Pcie { - lock: Mutex<()>, - allocs: Vec, - pub interrupt_map: Vec, - pub interrupt_map_mask: [u32; 4], - fallback: Pci, -} -struct Alloc { - seg: u16, - start_bus: u8, - end_bus: u8, - mem: PhysBorrowed, -} - -unsafe impl Send for Pcie {} -unsafe impl Sync for Pcie {} - -const BYTES_PER_BUS: usize = 1 << 20; - -impl Pcie { - pub fn new() -> Self { - match Mcfg::with(Self::from_allocs) { - Ok(pcie) => pcie, - Err(acpi_error) => match locate_ecam_dtb(Self::from_allocs) { - Ok(pcie) => pcie, - Err(fdt_error) => { - log::warn!( - "Couldn't retrieve PCIe info, perhaps the kernel is not compiled with \ - acpi or device tree support? Using the PCI 3.0 configuration space \ - instead. ACPI error: {:?} FDT error: {:?}", - acpi_error, - fdt_error - ); - Self { - lock: Mutex::new(()), - allocs: Vec::new(), - fallback: Pci::new(), - interrupt_map: Vec::new(), - interrupt_map_mask: [u32::MAX, u32::MAX, u32::MAX, u32::MAX], - } - } - }, - } - } - - fn from_allocs( - allocs: PcieAllocs<'_>, - interrupt_map: Vec, - interrupt_map_mask: [u32; 4], - ) -> Result { - let mut allocs = allocs - .0 - .iter() - .filter_map(|desc| { - Some(Alloc { - seg: desc.seg_group_num, - start_bus: desc.start_bus, - end_bus: desc.end_bus, - mem: PhysBorrowed::map( - desc.base_addr.try_into().ok()?, - BYTES_PER_BUS - * (usize::from(desc.end_bus) - usize::from(desc.start_bus) + 1), - Prot::RW, - MemoryType::Uncacheable, - ) - .inspect_err(|err| { - log::error!( - "failed to map seg {} bus {}..={}: {}", - { desc.seg_group_num }, - { desc.start_bus }, - { desc.end_bus }, - err - ) - }) - .ok()?, - }) - }) - .collect::>(); - - allocs.sort_by_key(|alloc| (alloc.seg, alloc.start_bus)); - - Ok(Self { - lock: Mutex::new(()), - allocs, - interrupt_map, - interrupt_map_mask, - fallback: Pci::new(), - }) - } - - fn bus_addr(&self, seg: u16, bus: u8) -> Option<*mut u32> { - let alloc = match self - .allocs - .binary_search_by_key(&(seg, bus), |alloc| (alloc.seg, alloc.start_bus)) - { - Ok(present_idx) => &self.allocs[present_idx], - Err(0) => return None, - Err(above_idx) => { - let below_alloc = &self.allocs[above_idx - 1]; - if bus > below_alloc.end_bus { - return None; - } - below_alloc - } - }; - let bus_off = bus - alloc.start_bus; - Some(unsafe { - alloc - .mem - .as_ptr() - .cast::() - .add(usize::from(bus_off) * BYTES_PER_BUS) - .cast::() - }) - } - - fn bus_addr_offset_in_dwords(address: PciAddress, offset: u16) -> usize { - assert_eq!(offset & 0xFFFC, offset, "pcie offset not dword-aligned"); - assert_eq!(offset & 0x0FFF, offset, "pcie offset larger than 4095"); - - (((address.device() as usize) << 15) - | ((address.function() as usize) << 12) - | (offset as usize)) - >> 2 - } - // TODO: A safer interface, using e.g. a VolatileCell or Volatile<'a>. The PhysBorrowed wrapper - // can possibly deref to or provide a Volatile. - fn mmio_addr(&self, address: PciAddress, offset: u16) -> Option<*mut u32> { - assert_eq!( - address.segment(), - 0, - "multiple segments not yet implemented" - ); - - let bus_addr = self.bus_addr(address.segment(), address.bus())?; - Some(unsafe { bus_addr.add(Self::bus_addr_offset_in_dwords(address, offset)) }) - } -} - -impl ConfigRegionAccess for Pcie { - unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { - let _guard = self.lock.lock().unwrap(); - - match self.mmio_addr(address, offset) { - Some(addr) => addr.read_volatile(), - None => self.fallback.read(address, offset), - } - } - - unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) { - let _guard = self.lock.lock().unwrap(); - - match self.mmio_addr(address, offset) { - Some(addr) => addr.write_volatile(value), - None => self.fallback.write(address, offset, value), - } - } -} diff --git a/recipes/core/base/drivers/pcid/src/driver_handler.rs b/recipes/core/base/drivers/pcid/src/driver_handler.rs deleted file mode 100644 index f70a7f6da3..0000000000 --- a/recipes/core/base/drivers/pcid/src/driver_handler.rs +++ /dev/null @@ -1,284 +0,0 @@ -use pci_types::capability::{MultipleMessageSupport, PciCapability}; -use pci_types::{ConfigRegionAccess, EndpointHeader}; -use pcid_interface::PciFunction; - -use crate::cfg_access::Pcie; - -pub struct DriverHandler<'a> { - func: PciFunction, - endpoint_header: &'a mut EndpointHeader, - capabilities: &'a mut [PciCapability], - - pcie: &'a Pcie, -} - -impl<'a> DriverHandler<'a> { - pub fn new( - func: PciFunction, - endpoint_header: &'a mut EndpointHeader, - capabilities: &'a mut [PciCapability], - pcie: &'a Pcie, - ) -> Self { - DriverHandler { - func, - endpoint_header, - capabilities, - pcie, - } - } - - pub fn respond( - &mut self, - request: pcid_interface::PcidClientRequest, - ) -> pcid_interface::PcidClientResponse { - use pcid_interface::*; - - #[forbid(non_exhaustive_omitted_patterns)] - match request { - PcidClientRequest::EnableDevice => { - self.func.legacy_interrupt_line = crate::enable_function( - &self.pcie, - &mut self.endpoint_header, - &mut self.capabilities, - ); - - PcidClientResponse::EnabledDevice - } - PcidClientRequest::RequestVendorCapabilities => PcidClientResponse::VendorCapabilities( - self.capabilities - .iter() - .filter_map(|capability| match capability { - PciCapability::Vendor(addr) => unsafe { - Some(VendorSpecificCapability::parse(*addr, self.pcie)) - }, - _ => None, - }) - .collect::>(), - ), - PcidClientRequest::RequestConfig => { - PcidClientResponse::Config(SubdriverArguments { func: self.func }) - } - PcidClientRequest::RequestFeatures => PcidClientResponse::AllFeatures( - self.capabilities - .iter() - .filter_map(|capability| match capability { - PciCapability::Msi(_) => Some(PciFeature::Msi), - PciCapability::MsiX(_) => Some(PciFeature::MsiX), - _ => None, - }) - .collect(), - ), - PcidClientRequest::EnableFeature(feature) => { - match feature { - PciFeature::Msi => { - if let Some(msix_capability) = - self.capabilities - .iter_mut() - .find_map(|capability| match capability { - PciCapability::MsiX(cap) => Some(cap), - _ => None, - }) - { - // If MSI-X is supported disable it before enabling MSI as they can't be - // active at the same time. - msix_capability.set_enabled(false, self.pcie); - } - - let capability = match self.capabilities.iter_mut().find_map(|capability| { - match capability { - PciCapability::Msi(cap) => Some(cap), - _ => None, - } - }) { - Some(capability) => capability, - None => { - return PcidClientResponse::Error( - PcidServerResponseError::NonexistentFeature(feature), - ) - } - }; - capability.set_enabled(true, self.pcie); - PcidClientResponse::FeatureEnabled(feature) - } - PciFeature::MsiX => { - if let Some(msi_capability) = - self.capabilities - .iter_mut() - .find_map(|capability| match capability { - PciCapability::Msi(cap) => Some(cap), - _ => None, - }) - { - // If MSI is supported disable it before enabling MSI-X as they can't be - // active at the same time. - msi_capability.set_enabled(false, self.pcie); - } - - let capability = match self.capabilities.iter_mut().find_map(|capability| { - match capability { - PciCapability::MsiX(cap) => Some(cap), - _ => None, - } - }) { - Some(capability) => capability, - None => { - return PcidClientResponse::Error( - PcidServerResponseError::NonexistentFeature(feature), - ) - } - }; - capability.set_enabled(true, self.pcie); - PcidClientResponse::FeatureEnabled(feature) - } - } - } - PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo( - feature, - match feature { - PciFeature::Msi => { - if let Some(info) = - self.capabilities - .iter() - .find_map(|capability| match capability { - PciCapability::Msi(cap) => Some(cap), - _ => None, - }) - { - PciFeatureInfo::Msi(msi::MsiInfo { - log2_multiple_message_capable: info.multiple_message_capable() - as u8, - is_64bit: info.is_64bit(), - has_per_vector_masking: info.has_per_vector_masking(), - }) - } else { - return PcidClientResponse::Error( - PcidServerResponseError::NonexistentFeature(feature), - ); - } - } - PciFeature::MsiX => { - if let Some(info) = - self.capabilities - .iter() - .find_map(|capability| match capability { - PciCapability::MsiX(cap) => Some(cap), - _ => None, - }) - { - PciFeatureInfo::MsiX(msi::MsixInfo { - table_bar: info.table_bar(), - table_offset: info.table_offset(), - table_size: info.table_size(), - pba_bar: info.pba_bar(), - pba_offset: info.pba_offset(), - }) - } else { - return PcidClientResponse::Error( - PcidServerResponseError::NonexistentFeature(feature), - ); - } - } - }, - ), - PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set { - SetFeatureInfo::Msi(info_to_set) => { - if let Some(info) = - self.capabilities - .iter_mut() - .find_map(|capability| match capability { - PciCapability::Msi(cap) => Some(cap), - _ => None, - }) - { - if let Some(mme) = info_to_set.multi_message_enable { - if (info.multiple_message_capable() as u8) < mme { - return PcidClientResponse::Error( - PcidServerResponseError::InvalidBitPattern, - ); - } - info.set_multiple_message_enable( - match mme { - 0 => MultipleMessageSupport::Int1, - 1 => MultipleMessageSupport::Int2, - 2 => MultipleMessageSupport::Int4, - 3 => MultipleMessageSupport::Int8, - 4 => MultipleMessageSupport::Int16, - 5 => MultipleMessageSupport::Int32, - _ => { - return PcidClientResponse::Error( - PcidServerResponseError::InvalidBitPattern, - ) - } - }, - self.pcie, - ); - } - if let Some(message_addr_and_data) = info_to_set.message_address_and_data { - let message_addr = message_addr_and_data.addr; - if message_addr & 0b11 != 0 { - return PcidClientResponse::Error( - PcidServerResponseError::InvalidBitPattern, - ); - } - if message_addr_and_data.data - & ((1 << info.multiple_message_enable(self.pcie) as u8) - 1) - != 0 - { - return PcidClientResponse::Error( - PcidServerResponseError::InvalidBitPattern, - ); - } - info.set_message_info( - message_addr, - message_addr_and_data - .data - .try_into() - .expect("pcid: MSI message data too big"), - self.pcie, - ); - } - if let Some(mask_bits) = info_to_set.mask_bits { - info.set_message_mask(mask_bits, self.pcie); - } - PcidClientResponse::SetFeatureInfo(PciFeature::Msi) - } else { - return PcidClientResponse::Error( - PcidServerResponseError::NonexistentFeature(PciFeature::Msi), - ); - } - } - SetFeatureInfo::MsiX { function_mask } => { - if let Some(info) = - self.capabilities - .iter_mut() - .find_map(|capability| match capability { - PciCapability::MsiX(cap) => Some(cap), - _ => None, - }) - { - if let Some(mask) = function_mask { - info.set_function_mask(mask, self.pcie); - } - PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) - } else { - return PcidClientResponse::Error( - PcidServerResponseError::NonexistentFeature(PciFeature::MsiX), - ); - } - } - _ => unreachable!(), - }, - PcidClientRequest::ReadConfig(offset) => { - let value = unsafe { self.pcie.read(self.func.addr, offset) }; - return PcidClientResponse::ReadConfig(value); - } - PcidClientRequest::WriteConfig(offset, value) => { - unsafe { - self.pcie.write(self.func.addr, offset, value); - } - return PcidClientResponse::WriteConfig; - } - _ => unreachable!(), - } - } -} diff --git a/recipes/core/base/drivers/pcid/src/driver_interface/bar.rs b/recipes/core/base/drivers/pcid/src/driver_interface/bar.rs deleted file mode 100644 index b2c1d35bbd..0000000000 --- a/recipes/core/base/drivers/pcid/src/driver_interface/bar.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::convert::TryInto; - -use serde::{Deserialize, Serialize}; - -// This type is used instead of [pci_types::Bar] in the driver interface as the -// latter can't be serialized and is missing the convenience functions of [PciBar]. -#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] -pub enum PciBar { - None, - Memory32 { addr: u32, size: u32 }, - Memory64 { addr: u64, size: u64 }, - Port(u16), -} - -impl PciBar { - pub fn display(&self) -> String { - match self { - PciBar::None => format!(""), - PciBar::Memory32 { addr, .. } => format!("{addr:08X}"), - PciBar::Memory64 { addr, .. } => format!("{addr:016X}"), - PciBar::Port(port) => format!("P{port:04X}"), - } - } - - pub fn is_none(&self) -> bool { - match self { - &PciBar::None => true, - _ => false, - } - } - - pub fn expect_port(&self) -> u16 { - match *self { - PciBar::Port(port) => port, - PciBar::Memory32 { .. } | PciBar::Memory64 { .. } => { - panic!("expected port BAR, found memory BAR"); - } - PciBar::None => panic!("expected BAR to exist"), - } - } - - pub fn expect_mem(&self) -> (usize, usize) { - match *self { - PciBar::Memory32 { addr, size } => (addr as usize, size as usize), - PciBar::Memory64 { addr, size } => ( - addr.try_into() - .expect("conversion from 64bit BAR to usize failed"), - size.try_into() - .expect("conversion from 64bit BAR size to usize failed"), - ), - PciBar::Port(_) => panic!("expected memory BAR, found port BAR"), - PciBar::None => panic!("expected BAR to exist"), - } - } -} diff --git a/recipes/core/base/drivers/pcid/src/driver_interface/cap.rs b/recipes/core/base/drivers/pcid/src/driver_interface/cap.rs deleted file mode 100644 index 19521608f8..0000000000 --- a/recipes/core/base/drivers/pcid/src/driver_interface/cap.rs +++ /dev/null @@ -1,38 +0,0 @@ -use pci_types::capability::PciCapabilityAddress; -use pci_types::ConfigRegionAccess; -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub struct VendorSpecificCapability { - pub data: Vec, -} - -impl VendorSpecificCapability { - pub unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { - let dword = access.read(addr.address, addr.offset); - let length = ((dword >> 16) & 0xFF) as u16; - // let next = (dword >> 8) & 0xFF; - // log::trace!( - // "Vendor specific offset: {:#02x} next: {next:#02x} cap len: {length:#02x}", - // addr.offset - // ); - let data = if length > 0 { - assert!( - length > 3 && length % 4 == 0, - "invalid range length: {}", - length - ); - let mut raw_data = { - (addr.offset..addr.offset + length) - .step_by(4) - .flat_map(|offset| access.read(addr.address, offset).to_le_bytes()) - .collect::>() - }; - raw_data.drain(3..).collect() - } else { - log::warn!("Vendor specific capability is invalid"); - Vec::new() - }; - VendorSpecificCapability { data } - } -} diff --git a/recipes/core/base/drivers/pcid/src/driver_interface/config.rs b/recipes/core/base/drivers/pcid/src/driver_interface/config.rs deleted file mode 100644 index e148b26ce6..0000000000 --- a/recipes/core/base/drivers/pcid/src/driver_interface/config.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::collections::BTreeMap; -use std::ops::Range; - -use serde::Deserialize; - -use crate::driver_interface::FullDeviceId; - -#[derive(Clone, Debug, Default, Deserialize)] -pub struct Config { - pub drivers: Vec, -} - -#[derive(Clone, Debug, Default, Deserialize)] -pub struct DriverConfig { - pub name: Option, - pub class: Option, - pub subclass: Option, - pub interface: Option, - pub ids: Option>>, - pub vendor: Option, - pub device: Option, - pub device_id_range: Option>, - pub command: Vec, -} - -impl DriverConfig { - pub fn match_function(&self, id: &FullDeviceId) -> bool { - if let Some(class) = self.class { - if class != id.class { - return false; - } - } - - if let Some(subclass) = self.subclass { - if subclass != id.subclass { - return false; - } - } - - if let Some(interface) = self.interface { - if interface != id.interface { - return false; - } - } - - if let Some(ref ids) = self.ids { - let mut device_found = false; - for (vendor, devices) in ids { - let vendor_without_prefix = vendor.trim_start_matches("0x"); - let vendor = i64::from_str_radix(vendor_without_prefix, 16).unwrap() as u16; - - if vendor != id.vendor_id { - continue; - } - - for device in devices { - if *device == id.device_id { - device_found = true; - break; - } - } - } - if !device_found { - return false; - } - } else { - if let Some(vendor) = self.vendor { - if vendor != id.vendor_id { - return false; - } - } - - if let Some(device) = self.device { - if device != id.device_id { - return false; - } - } - } - - if let Some(ref device_id_range) = self.device_id_range { - if id.device_id < device_id_range.start || device_id_range.end <= id.device_id { - return false; - } - } - - true - } -} diff --git a/recipes/core/base/drivers/pcid/src/driver_interface/id.rs b/recipes/core/base/drivers/pcid/src/driver_interface/id.rs deleted file mode 100644 index 7b4ec84444..0000000000 --- a/recipes/core/base/drivers/pcid/src/driver_interface/id.rs +++ /dev/null @@ -1,48 +0,0 @@ -use pci_types::device_type::DeviceType; -use serde::{Deserialize, Serialize}; - -/// All identifying information of a PCI function. -#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] -pub struct FullDeviceId { - pub vendor_id: u16, - pub device_id: u16, - pub class: u8, - pub subclass: u8, - pub interface: u8, - pub revision: u8, -} - -impl FullDeviceId { - pub fn display(&self) -> String { - let mut string = format!( - "{:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", - self.vendor_id, - self.device_id, - self.class, - self.subclass, - self.interface, - self.revision, - self.class, - ); - let device_type = DeviceType::from((self.class, self.subclass)); - match device_type { - DeviceType::LegacyVgaCompatible => string.push_str(" VGA CTL"), - DeviceType::IdeController => string.push_str(" IDE"), - DeviceType::SataController => match self.interface { - 0 => string.push_str(" SATA VND"), - 1 => string.push_str(" SATA AHCI"), - _ => (), - }, - DeviceType::UsbController => match self.interface { - 0x00 => string.push_str(" UHCI"), - 0x10 => string.push_str(" OHCI"), - 0x20 => string.push_str(" EHCI"), - 0x30 => string.push_str(" XHCI"), - _ => (), - }, - DeviceType::NvmeController => string.push_str(" NVME"), - _ => (), - } - string - } -} diff --git a/recipes/core/base/drivers/pcid/src/driver_interface/irq_helpers.rs b/recipes/core/base/drivers/pcid/src/driver_interface/irq_helpers.rs deleted file mode 100644 index 28ca077a92..0000000000 --- a/recipes/core/base/drivers/pcid/src/driver_interface/irq_helpers.rs +++ /dev/null @@ -1,334 +0,0 @@ -//! IRQ helpers. -//! -//! This module allows easy handling of the `/scheme/irq` scheme, and allocating interrupt vectors -//! for use by INTx#, MSI, or MSI-X. - -use std::convert::TryFrom; -use std::fs::{self, File}; -use std::io::{self, prelude::*}; -use std::num::NonZeroU8; - -use crate::driver_interface::msi::{MsiAddrAndData, MsixTableEntry}; - -/// Read the local APIC ID of the bootstrap processor. -pub fn read_bsp_apic_id() -> io::Result { - let mut buffer = [0u8; 8]; - - let mut file = File::open("/scheme/irq/bsp")?; - let bytes_read = file.read(&mut buffer)?; - - (if bytes_read == 8 { - usize::try_from(u64::from_le_bytes(buffer)) - } else if bytes_read == 4 { - usize::try_from(u32::from_le_bytes([ - buffer[0], buffer[1], buffer[2], buffer[3], - ])) - } else { - panic!( - "`/scheme/irq` scheme responded with {} bytes, expected {}", - bytes_read, - std::mem::size_of::() - ); - }) - .or(Err(io::Error::new( - io::ErrorKind::InvalidData, - "bad BSP int size", - ))) -} - -// TODO: Perhaps read the MADT instead? -/// Obtains an interator over all of the visible CPU ids, for use in IRQ allocation and MSI -/// capability structs or MSI-X tables. -pub fn cpu_ids() -> io::Result> + 'static> { - Ok( - fs::read_dir("/scheme/irq")?.filter_map(|entry| -> Option> { - match entry { - Ok(e) => { - let path = e.path(); - let file_name = path.file_name()?.to_str()?; - // the file name should be in the format `cpu-` - if !file_name.starts_with("cpu-") { - return None; - } - u8::from_str_radix(&file_name[4..], 16) - .map(usize::from) - .map(Ok) - .ok() - } - Err(e) => Some(Err(e)), - } - }), - ) -} - -/// Allocate multiple interrupt vectors, from the IDT of the specified processor, returning the -/// start vector and the IRQ handles. -/// -/// The alignment is a requirement for the allocation range. For example, with an alignment of 8, -/// only ranges that begin with a multiple of eight are accepted. The IRQ handles returned will -/// always correspond to the subsequent IRQ numbers beginning the first value in the return tuple. -/// -/// This function is not actually guaranteed to allocate all of the IRQs specified in `count`, -/// since another process might already have requested one vector in the range. The caller must -/// check that the returned vector have the same length as `count`. In the future this function may -/// perhaps lock the entire directory to prevent this from happening, or maybe find the smallest free -/// range with the minimum alignment, to allow other drivers to obtain their necessary IRQs. -/// -/// Note that this count/alignment restriction is only mandatory for MSI; MSI-X allows for -/// individually allocated vectors that might be spread out, even on multiple CPUs. Thus, multiple -/// invocations with alignment 1 and count 1 are totally acceptable, although allocating in bulk -/// minimizes the initialization overhead. -pub fn allocate_aligned_interrupt_vectors( - cpu_id: usize, - alignment: NonZeroU8, - count: u8, -) -> io::Result)>> { - let cpu_id = u8::try_from(cpu_id).expect("usize cpu ids not implemented yet"); - if count == 0 { - return Ok(None); - } - - let available_irqs = fs::read_dir(format!("/scheme/irq/cpu-{:02x}", cpu_id))?; - let mut available_irq_numbers = available_irqs.filter_map(|entry| -> Option> { - let entry = match entry { - Ok(e) => e, - Err(err) => return Some(Err(err)), - }; - - let path = entry.path(); - - let file_name = match path.file_name() { - Some(f) => f, - None => return None, - }; - - let path_str = match file_name.to_str() { - Some(s) => s, - None => return None, - }; - - match path_str.parse::() { - Ok(p) => Some(Ok(p)), - Err(_) => None, - } - }); - - // TODO: fcntl F_SETLK on `/scheme/irq/`? - - let mut handles = Vec::with_capacity(usize::from(count)); - - let mut index = 0; - let mut first = None; - - while let Some(number) = available_irq_numbers.next() { - let number = number?; - - // Skip until a suitable alignment is found. - if number % u8::from(alignment) != 0 { - continue; - } - let first = *first.get_or_insert(number); - let irq_number = first + index; - - // From the point where the range is aligned, we can start to advance until `count` IRQs - // have been allocated. - if index >= count { - break; - } - - // if found, reserve the irq - let irq_handle = - match File::create(format!("/scheme/irq/cpu-{:02x}/{}", cpu_id, irq_number)) { - Ok(handle) => handle, - - // return early if the entire range couldn't be allocated - Err(err) if err.kind() == io::ErrorKind::NotFound => break, - - Err(err) => return Err(err), - }; - handles.push(irq_handle); - index += 1; - } - if handles.is_empty() { - return Ok(None); - } - let first = match first { - Some(f) => f, - None => return Ok(None), - }; - - Ok(Some((first + 32, handles))) -} - -/// Allocate at most `count` interrupt vectors, which can start at any offset. Unless MSI is used -/// and an entire aligned range of vectors is needed, this function should be used. -pub fn allocate_interrupt_vectors(cpu_id: usize, count: u8) -> io::Result)>> { - allocate_aligned_interrupt_vectors(cpu_id, NonZeroU8::new(1).unwrap(), count) -} - -/// Allocate a single interrupt vector, returning both the vector number (starting from 32 up to -/// 254), and its IRQ handle which is then reserved. Returns Ok(None) if allocation fails due to -/// no available IRQs. -pub fn allocate_single_interrupt_vector(cpu_id: usize) -> io::Result> { - let (base, mut files) = match allocate_interrupt_vectors(cpu_id, 1) { - Ok(Some((base, files))) => (base, files), - Ok(None) => return Ok(None), - Err(err) => return Err(err), - }; - assert_eq!(files.len(), 1); - Ok(Some((base, files.pop().unwrap()))) -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub fn allocate_single_interrupt_vector_for_msi(cpu_id: usize) -> (MsiAddrAndData, File) { - use crate::driver_interface::msi::x86 as x86_msix; - - // FIXME for cpu_id >255 we need to use the IOMMU to use IRQ remapping - let lapic_id = u8::try_from(cpu_id).expect("CPU id couldn't fit inside u8"); - let rh = false; - let dm = false; - let addr = x86_msix::message_address(lapic_id, rh, dm); - - let (vector, interrupt_handle) = allocate_single_interrupt_vector(cpu_id) - .expect("failed to allocate interrupt vector") - .expect("no interrupt vectors left"); - let msg_data = x86_msix::message_data_edge_triggered(x86_msix::DeliveryMode::Fixed, vector); - - ( - MsiAddrAndData { - addr, - data: msg_data, - }, - interrupt_handle, - ) -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub fn allocate_first_msi_interrupt_on_bsp( - pcid_handle: &mut crate::driver_interface::PciFunctionHandle, -) -> File { - use crate::driver_interface::{MsiSetFeatureInfo, PciFeature, SetFeatureInfo}; - - // TODO: Allow allocation of up to 32 vectors. - - let destination_id = read_bsp_apic_id().expect("failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - - let set_feature_info = MsiSetFeatureInfo { - multi_message_enable: Some(0), - message_address_and_data: Some(msg_addr_and_data), - mask_bits: None, - }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - - pcid_handle.enable_feature(PciFeature::Msi); - log::debug!("Enabled MSI"); - - interrupt_handle -} - -pub struct InterruptVector { - irq_handle: File, - vector: u16, - kind: InterruptVectorKind, -} - -enum InterruptVectorKind { - Legacy, - Msi, - MsiX { table_entry: *mut MsixTableEntry }, -} - -impl InterruptVector { - pub fn irq_handle(&self) -> &File { - &self.irq_handle - } - - pub fn vector(&self) -> u16 { - self.vector - } - - pub fn set_masked_if_fast(&mut self, masked: bool) -> bool { - match self.kind { - InterruptVectorKind::Legacy | InterruptVectorKind::Msi => false, - InterruptVectorKind::MsiX { table_entry } => { - unsafe { (*table_entry).set_masked(masked) }; - true - } - } - } -} - -/// Get the most optimal supported interrupt mechanism: either (in the order of preference): -/// MSI-X, MSI, and INTx# pin. Returns both runtime interrupt structures (MSI/MSI-X capability -/// structures), and the handles to the interrupts. -// FIXME allow allocating multiple interrupt vectors -// FIXME move MSI-X IRQ allocation to pcid -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub fn pci_allocate_interrupt_vector( - pcid_handle: &mut crate::driver_interface::PciFunctionHandle, - driver: &str, -) -> InterruptVector { - let features = pcid_handle.fetch_all_features(); - - let has_msi = features.iter().any(|feature| feature.is_msi()); - let has_msix = features.iter().any(|feature| feature.is_msix()); - - if has_msix { - let msix_info = match pcid_handle.feature_info(super::PciFeature::MsiX) { - super::PciFeatureInfo::MsiX(msix) => msix, - _ => unreachable!(), - }; - let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; - - pcid_handle.enable_feature(crate::driver_interface::PciFeature::MsiX); - - let entry = info.table_entry_pointer(0); - - let bsp_cpu_id = read_bsp_apic_id() - .unwrap_or_else(|err| panic!("{driver}: failed to read BSP APIC ID: {err}")); - let (msg_addr_and_data, irq_handle) = allocate_single_interrupt_vector_for_msi(bsp_cpu_id); - entry.write_addr_and_data(msg_addr_and_data); - entry.unmask(); - - InterruptVector { - irq_handle, - vector: 0, - kind: InterruptVectorKind::MsiX { table_entry: entry }, - } - } else if has_msi { - InterruptVector { - irq_handle: allocate_first_msi_interrupt_on_bsp(pcid_handle), - vector: 0, - kind: InterruptVectorKind::Msi, - } - } else if let Some(irq) = pcid_handle.config().func.legacy_interrupt_line { - // INTx# pin based interrupts. - InterruptVector { - irq_handle: irq.irq_handle(driver), - vector: 0, - kind: InterruptVectorKind::Legacy, - } - } else { - panic!("{driver}: no interrupts supported at all") - } -} - -// FIXME support MSI on non-x86 systems -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -pub fn pci_allocate_interrupt_vector( - pcid_handle: &mut crate::driver_interface::PciFunctionHandle, - driver: &str, -) -> InterruptVector { - if let Some(irq) = pcid_handle.config().func.legacy_interrupt_line { - // INTx# pin based interrupts. - InterruptVector { - irq_handle: irq.irq_handle(driver), - vector: 0, - kind: InterruptVectorKind::Legacy, - } - } else { - panic!("{driver}: no interrupts supported at all") - } -} diff --git a/recipes/core/base/drivers/pcid/src/driver_interface/mod.rs b/recipes/core/base/drivers/pcid/src/driver_interface/mod.rs deleted file mode 100644 index bbc7304ee5..0000000000 --- a/recipes/core/base/drivers/pcid/src/driver_interface/mod.rs +++ /dev/null @@ -1,492 +0,0 @@ -use std::fs::File; -use std::io::prelude::*; -use std::os::fd::{FromRawFd, IntoRawFd, RawFd}; -use std::path::Path; -use std::ptr::NonNull; -use std::{env, io}; -use std::{fmt, process}; - -use daemon::Daemon; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; - -pub use bar::PciBar; -pub use cap::VendorSpecificCapability; -pub use id::FullDeviceId; -pub use pci_types::PciAddress; - -mod bar; -pub mod cap; -pub mod config; -mod id; -pub mod irq_helpers; -pub mod msi; - -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct LegacyInterruptLine { - #[doc(hidden)] - pub irq: u8, - pub phandled: Option<(u32, [u32; 3], usize)>, -} - -impl LegacyInterruptLine { - /// Get an IRQ handle for this interrupt line. - pub fn irq_handle(self, driver: &str) -> File { - if let Some((phandle, addr, cells)) = self.phandled { - let path = match cells { - 1 => format!("/scheme/irq/phandle-{}/{}", phandle, addr[0]), - 2 => format!("/scheme/irq/phandle-{}/{},{}", phandle, addr[0], addr[1]), - 3 => format!( - "/scheme/irq/phandle-{}/{},{},{}", - phandle, addr[0], addr[1], addr[2] - ), - _ => panic!( - "unexpected number of IRQ description cells for phandle {phandle}: {cells}" - ), - }; - File::create(path) - .unwrap_or_else(|err| panic!("{driver}: failed to open IRQ file: {err}")) - } else { - File::open(format!("/scheme/irq/{}", self.irq)) - .unwrap_or_else(|err| panic!("{driver}: failed to open IRQ file: {err}")) - } - } -} - -impl fmt::Display for LegacyInterruptLine { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some((phandle, addr, cells)) = self.phandled { - match cells { - 1 => write!(f, "(phandle {}, {:?})", phandle, addr[0]), - 2 => write!(f, "(phandle {}, {:?},{:?})", phandle, addr[0], addr[1]), - 3 => write!(f, "(phandle {}, {:?})", phandle, addr), - _ => panic!( - "unexpected number of IRQ description cells for phandle {phandle}: {cells}" - ), - } - } else { - write!(f, "{}", self.irq) - } - } -} - -#[derive(Serialize, Deserialize)] -#[serde(remote = "PciAddress")] -struct PciAddressDef { - #[serde(getter = "PciAddress::segment")] - segment: u16, - #[serde(getter = "PciAddress::bus")] - bus: u8, - #[serde(getter = "PciAddress::device")] - device: u8, - #[serde(getter = "PciAddress::function")] - function: u8, -} - -impl From for PciAddress { - fn from(value: PciAddressDef) -> Self { - PciAddress::new(value.segment, value.bus, value.device, value.function) - } -} - -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct PciRom { - pub addr: u32, - pub size: u32, - pub enabled: bool, -} - -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct PciFunction { - /// Address of the PCI function. - #[serde(with = "PciAddressDef")] - pub addr: PciAddress, - - /// PCI Base Address Registers - pub bars: [PciBar; 6], - - /// PCI Option ROM - pub rom: Option, - - /// Legacy IRQ line: It's the responsibility of pcid to make sure that it be mapped in either - /// the I/O APIC or the 8259 PIC, so that the subdriver can map the interrupt vector directly. - /// The vector to map is always this field, plus 32. - /// If INTx# interrupts aren't supported at all this is `None`. - pub legacy_interrupt_line: Option, - - /// All identifying information of the PCI function. - pub full_device_id: FullDeviceId, -} -impl PciFunction { - pub fn name(&self) -> String { - // FIXME stop replacing : with - once it is a valid character in scheme names - format!("pci-{}", self.addr).replace(':', "-") - } - - pub fn display(&self) -> String { - let mut string = self.name(); - let mut first = true; - for (i, bar) in self.bars.iter().enumerate() { - if !bar.is_none() { - if first { - first = false; - string.push_str(" on:"); - } - string.push_str(&format!(" {i}={}", bar.display())); - } - } - if let Some(irq) = self.legacy_interrupt_line { - string.push_str(&format!(" IRQ: {irq}")); - } - string - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct SubdriverArguments { - pub func: PciFunction, -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub enum FeatureStatus { - Enabled, - Disabled, -} - -impl FeatureStatus { - pub fn enabled(enabled: bool) -> Self { - if enabled { - Self::Enabled - } else { - Self::Disabled - } - } - pub fn is_enabled(&self) -> bool { - if let &Self::Enabled = self { - true - } else { - false - } - } -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub enum PciFeature { - Msi, - MsiX, -} -impl PciFeature { - pub fn is_msi(self) -> bool { - if let Self::Msi = self { - true - } else { - false - } - } - pub fn is_msix(self) -> bool { - if let Self::MsiX = self { - true - } else { - false - } - } -} -#[derive(Debug, Serialize, Deserialize)] -pub enum PciFeatureInfo { - Msi(msi::MsiInfo), - MsiX(msi::MsixInfo), -} - -// TODO: Remove these "features" and just go strait to the actual thing. - -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct MsiSetFeatureInfo { - /// The Multi Message Enable field of the Message Control in the MSI Capability Structure, - /// is the log2 of the interrupt vectors, minus one. Can only be 0b000..=0b101. - pub multi_message_enable: Option, - - /// The system-specific message address and data. - /// - /// The message address contains things like the CPU that will be targeted, at least on - /// x86_64. The message data contains the actual interrupt vector (lower 8 bits) and - /// the kind of interrupt, at least on x86_64. - pub message_address_and_data: Option, - - /// A bitmap of the vectors that are masked. This field is not guaranteed (and not likely, - /// at least according to the feature flags I got from QEMU), to exist. - pub mask_bits: Option, -} - -/// Some flags that might be set simultaneously, but separately. -#[derive(Debug, Serialize, Deserialize)] -#[non_exhaustive] -pub enum SetFeatureInfo { - Msi(MsiSetFeatureInfo), - - MsiX { - /// Masks the entire function, and all of its vectors. - function_mask: Option, - }, -} - -#[derive(Debug, Serialize, Deserialize)] -#[non_exhaustive] -pub enum PcidClientRequest { - EnableDevice, - RequestConfig, - RequestFeatures, - RequestVendorCapabilities, - EnableFeature(PciFeature), - FeatureInfo(PciFeature), - SetFeatureInfo(SetFeatureInfo), - ReadConfig(u16), - WriteConfig(u16, u32), -} - -#[derive(Debug, Serialize, Deserialize)] -#[non_exhaustive] -pub enum PcidServerResponseError { - NonexistentFeature(PciFeature), - InvalidBitPattern, -} - -#[derive(Debug, Serialize, Deserialize)] -#[non_exhaustive] -pub enum PcidClientResponse { - EnabledDevice, - Config(SubdriverArguments), - AllFeatures(Vec), - VendorCapabilities(Vec), - FeatureEnabled(PciFeature), - FeatureStatus(PciFeature, FeatureStatus), - Error(PcidServerResponseError), - FeatureInfo(PciFeature, PciFeatureInfo), - SetFeatureInfo(PciFeature), - ReadConfig(u32), - WriteConfig, -} - -pub struct MappedBar { - pub ptr: NonNull, - pub bar_size: usize, -} - -/// A handle from a `pcid` client (e.g. `ahcid`) to `pcid`. -pub struct PciFunctionHandle { - channel: File, - config: SubdriverArguments, - mapped_bars: [Option; 6], -} - -fn send(w: &mut File, message: &T) { - let mut data = Vec::new(); - bincode::serialize_into(&mut data, message).expect("couldn't serialize pcid message"); - match w.write(&data) { - Ok(len) => assert_eq!(len, data.len()), - Err(err) => { - log::error!("writing pcid request failed: {err}"); - process::exit(1); - } - } -} -fn recv(r: &mut File) -> T { - let mut length_bytes = [0u8; 8]; - if let Err(err) = r.read_exact(&mut length_bytes) { - log::error!("reading pcid response length failed: {err}"); - process::exit(1); - } - let length = u64::from_le_bytes(length_bytes); - if length > 0x100_000 { - panic!("pcid_interface: buffer too large"); - } - let mut data = vec![0u8; length as usize]; - if let Err(err) = r.read_exact(&mut data) { - log::error!("reading pcid response failed: {err}"); - process::exit(1); - } - - bincode::deserialize_from(&data[..]).expect("couldn't deserialize pcid message") -} - -impl PciFunctionHandle { - fn connect_default() -> Self { - let channel_fd = match env::var("PCID_CLIENT_CHANNEL") { - Ok(channel_fd) => channel_fd, - Err(err) => { - log::error!("PCID_CLIENT_CHANNEL invalid: {err}"); - process::exit(1); - } - }; - let channel_fd = match channel_fd.parse::() { - Ok(channel_fd) => channel_fd, - Err(err) => { - log::error!("PCID_CLIENT_CHANNEL invalid: {err}"); - process::exit(1); - } - }; - Self::connect_common(channel_fd) - } - - pub fn connect_by_path(device_path: &Path) -> io::Result { - let channel_fd = libredox::call::open( - device_path.join("channel").to_str().unwrap(), - libredox::flag::O_RDWR, - 0, - )?; - Ok(Self::connect_common(channel_fd as RawFd)) - } - - fn connect_common(channel_fd: i32) -> PciFunctionHandle { - let mut channel = unsafe { File::from_raw_fd(channel_fd) }; - - send(&mut channel, &PcidClientRequest::RequestConfig); - let config = match recv(&mut channel) { - PcidClientResponse::Config(a) => a, - other => { - log::error!("received wrong pcid response: {other:?}"); - process::exit(1); - } - }; - - Self { - channel, - config, - mapped_bars: [const { None }; 6], - } - } - - pub fn into_inner_fd(self) -> RawFd { - self.channel.into_raw_fd() - } - - fn send(&mut self, req: &PcidClientRequest) { - send(&mut self.channel, req) - } - fn recv(&mut self) -> PcidClientResponse { - recv(&mut self.channel) - } - - pub fn config(&self) -> SubdriverArguments { - self.config.clone() - } - - pub fn enable_device(&mut self) { - self.send(&PcidClientRequest::EnableDevice); - match self.recv() { - PcidClientResponse::EnabledDevice => {} - other => { - log::error!("received wrong pcid response: {other:?}"); - process::exit(1); - } - } - } - - pub fn get_vendor_capabilities(&mut self) -> Vec { - self.send(&PcidClientRequest::RequestVendorCapabilities); - match self.recv() { - PcidClientResponse::VendorCapabilities(a) => a, - other => { - log::error!("received wrong pcid response: {other:?}"); - process::exit(1); - } - } - } - - // FIXME turn into struct with bool fields - pub fn fetch_all_features(&mut self) -> Vec { - self.send(&PcidClientRequest::RequestFeatures); - match self.recv() { - PcidClientResponse::AllFeatures(a) => a, - other => { - log::error!("received wrong pcid response: {other:?}"); - process::exit(1); - } - } - } - pub fn enable_feature(&mut self, feature: PciFeature) { - self.send(&PcidClientRequest::EnableFeature(feature)); - match self.recv() { - PcidClientResponse::FeatureEnabled(feat) if feat == feature => {} - other => { - log::error!("received wrong pcid response: {other:?}"); - process::exit(1); - } - } - } - pub fn feature_info(&mut self, feature: PciFeature) -> PciFeatureInfo { - self.send(&PcidClientRequest::FeatureInfo(feature)); - match self.recv() { - PcidClientResponse::FeatureInfo(feat, info) if feat == feature => info, - other => { - log::error!("received wrong pcid response: {other:?}"); - process::exit(1); - } - } - } - pub fn set_feature_info(&mut self, info: SetFeatureInfo) { - self.send(&PcidClientRequest::SetFeatureInfo(info)); - match self.recv() { - PcidClientResponse::SetFeatureInfo(_) => {} - other => { - log::error!("received wrong pcid response: {other:?}"); - process::exit(1); - } - } - } - pub unsafe fn read_config(&mut self, offset: u16) -> u32 { - self.send(&PcidClientRequest::ReadConfig(offset)); - match self.recv() { - PcidClientResponse::ReadConfig(value) => value, - other => { - log::error!("received wrong pcid response: {other:?}"); - process::exit(1); - } - } - } - pub unsafe fn write_config(&mut self, offset: u16, value: u32) { - self.send(&PcidClientRequest::WriteConfig(offset, value)); - match self.recv() { - PcidClientResponse::WriteConfig => {} - other => { - log::error!("received wrong pcid response: {other:?}"); - process::exit(1); - } - } - } - pub unsafe fn map_bar(&mut self, bir: u8) -> &MappedBar { - let mapped_bar = &mut self.mapped_bars[bir as usize]; - if let Some(mapped_bar) = mapped_bar { - mapped_bar - } else { - let (bar, bar_size) = self.config.func.bars[bir as usize].expect_mem(); - - let ptr = match unsafe { - common::physmap( - bar, - bar_size, - common::Prot::RW, - // FIXME once the kernel supports this use write-through for prefetchable BAR - common::MemoryType::Uncacheable, - ) - } { - Ok(ptr) => ptr, - Err(err) => { - log::error!("failed to map BAR at {bar:016X}: {err}"); - process::exit(1); - } - }; - - mapped_bar.insert(MappedBar { - ptr: NonNull::new(ptr.cast::()).expect("Mapping a BAR resulted in a nullptr"), - bar_size, - }) - } - } -} - -pub fn pci_daemon !>(f: F) -> ! { - Daemon::new(|daemon| { - common::init(); - let pcid_handle = PciFunctionHandle::connect_default(); - f(daemon, pcid_handle) - }) -} diff --git a/recipes/core/base/drivers/pcid/src/driver_interface/msi.rs b/recipes/core/base/drivers/pcid/src/driver_interface/msi.rs deleted file mode 100644 index 0ca68ec556..0000000000 --- a/recipes/core/base/drivers/pcid/src/driver_interface/msi.rs +++ /dev/null @@ -1,257 +0,0 @@ -use std::fmt; -use std::ptr::NonNull; - -use crate::driver_interface::PciBar; -use crate::PciFunctionHandle; - -use common::io::{Io, Mmio}; -use serde::{Deserialize, Serialize}; - -/// The address and data to use for MSI and MSI-X. -/// -/// For MSI using this only works when you need a single interrupt vector. -/// For MSI-X you can have a single [MsiEntry] for each interrupt vector. -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct MsiAddrAndData { - pub addr: u64, - pub data: u32, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct MsiInfo { - pub log2_multiple_message_capable: u8, - pub is_64bit: bool, - pub has_per_vector_masking: bool, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct MsixInfo { - pub table_bar: u8, - pub table_offset: u32, - pub table_size: u16, - pub pba_bar: u8, - pub pba_offset: u32, -} - -impl MsixInfo { - pub unsafe fn map_and_mask_all(self, pcid_handle: &mut PciFunctionHandle) -> MappedMsixRegs { - self.validate(pcid_handle.config().func.bars); - - let virt_table_base = unsafe { - pcid_handle - .map_bar(self.table_bar) - .ptr - .as_ptr() - .byte_add(self.table_offset as usize) - }; - - let mut info = MappedMsixRegs { - virt_table_base: NonNull::new(virt_table_base.cast::()).unwrap(), - info: self, - }; - - // Mask all interrupts in case some earlier driver/os already unmasked them (according to - // the PCI Local Bus spec 3.0, they are masked after system reset). - for i in 0..info.info.table_size { - info.table_entry_pointer(i.into()).mask(); - } - - info - } - - fn validate(&self, bars: [PciBar; 6]) { - if self.table_bar > 5 { - panic!( - "MSI-X Table BIR contained a reserved enum value: {}", - self.table_bar - ); - } - if self.pba_bar > 5 { - panic!( - "MSI-X PBA BIR contained a reserved enum value: {}", - self.pba_bar - ); - } - - let table_size = self.table_size; - let table_offset = self.table_offset as usize; - let table_min_length = table_size * 16; - - let pba_offset = self.pba_offset as usize; - let pba_min_length = table_size.div_ceil(8); - - let (_, table_bar_size) = bars[self.table_bar as usize].expect_mem(); - let (_, pba_bar_size) = bars[self.pba_bar as usize].expect_mem(); - - // Ensure that the table and PBA are within the BAR. - - if !(0..table_bar_size as u64).contains(&(table_offset as u64 + table_min_length as u64)) { - panic!( - "Table {:#x}:{:#x} outside of BAR with length {:#x}", - table_offset, - table_offset + table_min_length as usize, - table_bar_size - ); - } - - if !(0..pba_bar_size as u64).contains(&(pba_offset as u64 + pba_min_length as u64)) { - panic!( - "PBA {:#x}:{:#x} outside of BAR with length {:#x}", - pba_offset, - pba_offset + pba_min_length as usize, - pba_bar_size - ); - } - } -} - -pub struct MappedMsixRegs { - pub virt_table_base: NonNull, - pub info: MsixInfo, -} -impl MappedMsixRegs { - pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { - &mut *self.virt_table_base.as_ptr().add(k) - } - - pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { - assert!(k < self.info.table_size as usize); - unsafe { self.table_entry_pointer_unchecked(k) } - } -} - -#[repr(C, packed)] -pub struct MsixTableEntry { - pub addr_lo: Mmio, - pub addr_hi: Mmio, - pub msg_data: Mmio, - pub vec_ctl: Mmio, -} - -const _: () = { - assert!(size_of::() == 16); -}; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub mod x86 { - #[repr(u8)] - pub enum TriggerMode { - Edge = 0, - Level = 1, - } - - #[repr(u8)] - pub enum LevelTriggerMode { - Deassert = 0, - Assert = 1, - } - - #[repr(u8)] - pub enum DeliveryMode { - Fixed = 0b000, - LowestPriority = 0b001, - Smi = 0b010, - // 0b011 is reserved - Nmi = 0b100, - Init = 0b101, - // 0b110 is reserved - ExtInit = 0b111, - } - - // TODO: should the reserved field be preserved? - pub const fn message_address( - destination_id: u8, - redirect_hint: bool, - dest_mode_logical: bool, - ) -> u64 { - 0x0000_0000_FEE0_0000u64 - | ((destination_id as u64) << 12) - | ((redirect_hint as u64) << 3) - | ((dest_mode_logical as u64) << 2) - } - pub const fn message_data( - trigger_mode: TriggerMode, - level_trigger_mode: LevelTriggerMode, - delivery_mode: DeliveryMode, - vector: u8, - ) -> u32 { - ((trigger_mode as u32) << 15) - | ((level_trigger_mode as u32) << 14) - | ((delivery_mode as u32) << 8) - | vector as u32 - } - pub const fn message_data_level_triggered( - level_trigger_mode: LevelTriggerMode, - delivery_mode: DeliveryMode, - vector: u8, - ) -> u32 { - message_data( - TriggerMode::Level, - level_trigger_mode, - delivery_mode, - vector, - ) - } - pub const fn message_data_edge_triggered(delivery_mode: DeliveryMode, vector: u8) -> u32 { - message_data( - TriggerMode::Edge, - LevelTriggerMode::Deassert, - delivery_mode, - vector, - ) - } -} - -impl MsixTableEntry { - pub fn addr_lo(&self) -> u32 { - self.addr_lo.read() - } - pub fn addr_hi(&self) -> u32 { - self.addr_hi.read() - } - pub fn set_addr_lo(&mut self, value: u32) { - self.addr_lo.write(value); - } - pub fn set_addr_hi(&mut self, value: u32) { - self.addr_hi.write(value); - } - pub fn msg_data(&self) -> u32 { - self.msg_data.read() - } - pub fn vec_ctl(&self) -> u32 { - self.vec_ctl.read() - } - pub fn set_msg_data(&mut self, value: u32) { - self.msg_data.write(value); - } - pub fn addr(&self) -> u64 { - u64::from(self.addr_lo()) | (u64::from(self.addr_hi()) << 32) - } - pub const VEC_CTL_MASK_BIT: u32 = 1; - - pub fn set_masked(&mut self, masked: bool) { - self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, masked) - } - pub fn mask(&mut self) { - self.set_masked(true); - } - pub fn unmask(&mut self) { - self.set_masked(false); - } - - pub fn write_addr_and_data(&mut self, entry: MsiAddrAndData) { - self.set_addr_lo(entry.addr as u32); - self.set_addr_hi((entry.addr >> 32) as u32); - self.set_msg_data(entry.data); - } -} - -impl fmt::Debug for MsixTableEntry { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("MsixTableEntry") - .field("addr", &self.addr()) - .field("msg_data", &self.msg_data()) - .field("vec_ctl", &self.vec_ctl()) - .finish() - } -} diff --git a/recipes/core/base/drivers/pcid/src/lib.rs b/recipes/core/base/drivers/pcid/src/lib.rs deleted file mode 100644 index e8098a1786..0000000000 --- a/recipes/core/base/drivers/pcid/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -//! Interface to `pcid`. - -#![feature(never_type)] - -mod driver_interface; -pub use driver_interface::*; diff --git a/recipes/core/base/drivers/pcid/src/main.rs b/recipes/core/base/drivers/pcid/src/main.rs deleted file mode 100644 index cad33114bc..0000000000 --- a/recipes/core/base/drivers/pcid/src/main.rs +++ /dev/null @@ -1,384 +0,0 @@ -#![feature(iter_next_chunk)] -#![feature(if_let_guard)] -#![feature(non_exhaustive_omitted_patterns_lint)] - -use std::collections::BTreeMap; - -use log::{debug, error, info, trace, warn}; -use pci_types::capability::PciCapability; -use pci_types::{ - Bar as TyBar, CommandRegister, EndpointHeader, HeaderType, PciAddress, - PciHeader as TyPciHeader, PciPciBridgeHeader, -}; -use redox_scheme::scheme::register_sync_scheme; -use scheme_utils::Blocking; - -use crate::cfg_access::Pcie; -use pcid_interface::{FullDeviceId, LegacyInterruptLine, PciBar, PciFunction, PciRom}; - -mod cfg_access; -mod driver_handler; -mod scheme; - -pub struct Func { - inner: PciFunction, - - capabilities: Vec, - endpoint_header: EndpointHeader, - enabled: bool, -} - -fn handle_parsed_header( - pcie: &Pcie, - tree: &mut BTreeMap, - endpoint_header: EndpointHeader, - full_device_id: FullDeviceId, -) { - let mut bars = [PciBar::None; 6]; - let mut skip = false; - for i in 0..6 { - if skip { - skip = false; - continue; - } - match endpoint_header.bar(i, pcie) { - Some(TyBar::Io { port }) => bars[i as usize] = PciBar::Port(port.try_into().unwrap()), - Some(TyBar::Memory32 { - address, - size, - prefetchable: _, - }) => { - bars[i as usize] = PciBar::Memory32 { - addr: address, - size, - } - } - Some(TyBar::Memory64 { - address, - size, - prefetchable: _, - }) => { - bars[i as usize] = PciBar::Memory64 { - addr: address, - size, - }; - skip = true; // Each 64bit memory BAR occupies two slots - } - None => bars[i as usize] = PciBar::None, - } - } - - let mut string = String::new(); - for (i, bar) in bars.iter().enumerate() { - if !bar.is_none() { - string.push_str(&format!(" {i}={}", bar.display())); - } - } - - if !string.is_empty() { - debug!(" BAR{}", string); - } - - //TODO: submit to pci_types - let get_rom = |pci_address, offset| -> Option { - use pci_types::ConfigRegionAccess; - - const ROM_ENABLED: u32 = 1; - const ROM_ADDRESS_MASK: u32 = 0xfffff800; - - let data = unsafe { pcie.read(pci_address, offset) }; - let enabled = (data & ROM_ENABLED) == ROM_ENABLED; - let addr = data & ROM_ADDRESS_MASK; - - let size = unsafe { - pcie.write( - pci_address, - offset, - ROM_ADDRESS_MASK | if enabled { ROM_ENABLED } else { 0 }, - ); - let mut readback = pcie.read(pci_address, offset); - pcie.write(pci_address, offset, data); - - /* - * If the entire readback value is zero, the BAR is not implemented, so we return `None`. - */ - if readback == 0x0 { - return None; - } - - readback &= ROM_ADDRESS_MASK; - 1 << readback.trailing_zeros() - }; - - Some(PciRom { - addr, - size, - enabled, - }) - }; - - let rom = get_rom(endpoint_header.header().address(), 0x30); - if let Some(rom) = rom { - debug!(" ROM={:08X}", rom.addr); - } - - let capabilities = if endpoint_header.status(pcie).has_capability_list() { - endpoint_header.capabilities(pcie).collect::>() - } else { - Vec::new() - }; - debug!( - "PCI DEVICE CAPABILITIES for {}: {:?}", - endpoint_header.header().address(), - capabilities - ); - - let func = Func { - inner: pcid_interface::PciFunction { - addr: endpoint_header.header().address(), - bars, - rom, - legacy_interrupt_line: None, // Will be filled in when enabling the device - full_device_id: full_device_id.clone(), - }, - - capabilities, - endpoint_header, - enabled: false, - }; - - tree.insert(func.inner.addr, func); -} - -fn enable_function( - pcie: &Pcie, - endpoint_header: &mut EndpointHeader, - capabilities: &mut [PciCapability], -) -> Option { - // Enable bus mastering, memory space, and I/O space - endpoint_header.update_command(pcie, |cmd| { - cmd | CommandRegister::BUS_MASTER_ENABLE - | CommandRegister::MEMORY_ENABLE - | CommandRegister::IO_ENABLE - }); - - // Disable MSI and MSI-X in case a previous driver instance enabled them. - for capability in capabilities { - match capability { - PciCapability::Msi(capability) => { - capability.set_enabled(false, pcie); - } - PciCapability::MsiX(capability) => { - capability.set_enabled(false, pcie); - } - _ => {} - } - } - - // Set IRQ line to 9 if not set - let mut irq = 0xFF; - let mut interrupt_pin = 0xFF; - - endpoint_header.update_interrupt(pcie, |(pin, mut line)| { - if line == 0xFF { - line = 9; - } - irq = line; - interrupt_pin = pin; - (pin, line) - }); - - let legacy_interrupt_enabled = match interrupt_pin { - 0 => false, - 1 | 2 | 3 | 4 => true, - - other => { - warn!("pcid: invalid interrupt pin: {}", other); - false - } - }; - - if legacy_interrupt_enabled { - let pci_address = endpoint_header.header().address(); - let dt_address = ((pci_address.bus() as u32) << 16) - | ((pci_address.device() as u32) << 11) - | ((pci_address.function() as u32) << 8); - let addr = [ - dt_address & pcie.interrupt_map_mask[0], - 0u32, - 0u32, - interrupt_pin as u32 & pcie.interrupt_map_mask[3], - ]; - let mapping = pcie - .interrupt_map - .iter() - .find(|x| x.addr == addr[0..3] && x.interrupt == addr[3]); - let phandled = if let Some(mapping) = mapping { - Some(( - mapping.parent_phandle, - mapping.parent_interrupt, - mapping.parent_interrupt_cells, - )) - } else { - None - }; - if mapping.is_some() { - debug!("found mapping: addr={:?} => {:?}", addr, phandled); - } - - Some(LegacyInterruptLine { irq, phandled }) - } else { - None - } -} - -fn main() { - common::init(); - daemon::Daemon::new(daemon); -} - -fn daemon(daemon: daemon::Daemon) -> ! { - common::setup_logging( - "bus", - "pci", - "pcid", - common::output_level(), - common::file_level(), - ); - - let pcie = Pcie::new(); - - info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV"); - - let mut scheme = scheme::PciScheme::new(pcie); - let socket = redox_scheme::Socket::create().expect("failed to open pci scheme socket"); - let handler = Blocking::new(&socket, 16); - - { - match libredox::Fd::open("/scheme/acpi/register_pci", libredox::flag::O_WRONLY, 0) { - Ok(register_pci) => { - let access_id = scheme.access(); - - let access_fd = match socket - .create_this_scheme_fd(0, access_id, syscall::O_RDWR, 0) - { - Ok(fd) => Some(fd), - Err(err) => { - warn!("pcid: failed to issue acpi resource fd: {:?}", err); - None - } - }; - if let Some(access_fd) = access_fd { - let access_bytes = access_fd.to_ne_bytes(); - if let Err(err) = register_pci.call_wo( - &access_bytes, - syscall::CallFlags::WRITE | syscall::CallFlags::FD, - &[], - ) { - warn!("pcid: failed to send pci_fd to acpid: {:?}", err); - } - } - } - Err(err) => { - if err.errno() == libredox::errno::ENODEV { - debug!("pcid: acpid not found. Running without ACPI integration."); - } else { - warn!("pcid: failed to open acpid register_pci (error: {}). Running without ACPI integration.", err); - } - } - } - } - - // FIXME Use full ACPI for enumerating the host bridges. MCFG only describes the first - // host bridge, while multi-processor systems likely have a host bridge for each CPU. - // See also https://www.kernel.org/doc/html/latest/PCI/acpi-info.html - // Bus 0x80 is scanned for compatibility with newer (Arrow Lake) Intel CPUs where PCH devices - // are there. This workaround may not be required if we had ACPI bus enumeration. - let mut bus_nums = vec![0, 0x80]; - let mut bus_i = 0; - while bus_i < bus_nums.len() { - let bus_num = bus_nums[bus_i]; - bus_i += 1; - - for dev_num in 0..32 { - scan_device( - &mut scheme.tree, - &scheme.pcie, - &mut bus_nums, - bus_num, - dev_num, - ); - } - } - debug!("Enumeration complete, now starting pci scheme"); - - if let Err(err) = register_sync_scheme(&socket, "pci", &mut scheme) { - error!("pcid: failed to register pci scheme to namespace: {:?}", err); - std::process::exit(1); - } - - let _ = daemon.ready(); - - handler.process_requests_blocking(scheme).unwrap_or_else(|err| { - error!("pcid: failed to process requests: {:?}", err); - std::process::exit(1); - }); -} - -fn scan_device( - tree: &mut BTreeMap, - pcie: &Pcie, - bus_nums: &mut Vec, - bus_num: u8, - dev_num: u8, -) { - for func_num in 0..8 { - let header = TyPciHeader::new(PciAddress::new(0, bus_num, dev_num, func_num)); - - let (vendor_id, device_id) = header.id(pcie); - if vendor_id == 0xffff && device_id == 0xffff { - if func_num == 0 { - trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); - return; - } - - continue; - } - - let (revision, class, subclass, interface) = header.revision_and_class(pcie); - let full_device_id = FullDeviceId { - vendor_id, - device_id, - class, - subclass, - interface, - revision, - }; - - info!("PCI {} {}", header.address(), full_device_id.display()); - - let has_multiple_functions = header.has_multiple_functions(pcie); - - match header.header_type(pcie) { - HeaderType::Endpoint => { - handle_parsed_header( - pcie, - tree, - EndpointHeader::from_header(header, pcie).unwrap(), - full_device_id, - ); - } - HeaderType::PciPciBridge => { - let bridge_header = PciPciBridgeHeader::from_header(header, pcie).unwrap(); - bus_nums.push(bridge_header.secondary_bus_number(pcie)); - } - ty => { - warn!("pcid: unknown header type: {ty:?}"); - } - } - - if func_num == 0 && !has_multiple_functions { - return; - } - } -} diff --git a/recipes/core/base/drivers/pcid/src/scheme.rs b/recipes/core/base/drivers/pcid/src/scheme.rs deleted file mode 100644 index bb9f39a318..0000000000 --- a/recipes/core/base/drivers/pcid/src/scheme.rs +++ /dev/null @@ -1,428 +0,0 @@ -use std::collections::{BTreeMap, VecDeque}; - -use pci_types::{ConfigRegionAccess, PciAddress}; -use redox_scheme::scheme::SchemeSync; -use redox_scheme::{CallerCtx, OpenResult}; -use scheme_utils::HandleMap; -use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; -use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR}; -use syscall::flag::{MODE_CHR, MODE_DIR, O_DIRECTORY, O_STAT}; -use syscall::schemev2::NewFdFlags; -use syscall::ENOLCK; - -use crate::cfg_access::Pcie; - -pub struct PciScheme { - handles: HandleMap, - pub pcie: Pcie, - pub tree: BTreeMap, -} -enum Handle { - TopLevel { entries: Vec }, - Access, - Device, - Channel { addr: PciAddress, st: ChannelState }, - SchemeRoot, -} -struct HandleWrapper { - inner: Handle, - stat: bool, -} -impl Handle { - fn is_file(&self) -> bool { - matches!(self, Self::Access | Self::Channel { .. }) - } - fn is_dir(&self) -> bool { - !self.is_file() - } - // TODO: capability rather than root - fn requires_root(&self) -> bool { - matches!(self, Self::Access | Self::Channel { .. }) - } - fn is_scheme_root(&self) -> bool { - matches!(self, Self::SchemeRoot) - } -} - -enum ChannelState { - AwaitingData, - AwaitingResponseRead(VecDeque), -} - -const DEVICE_CONTENTS: &[&str] = &["channel"]; - -impl PciScheme { - pub fn access(&mut self) -> usize { - self.handles.insert(HandleWrapper { - inner: Handle::Access, - stat: false, - }) - } -} - -impl SchemeSync for PciScheme { - fn scheme_root(&mut self) -> Result { - Ok(self.handles.insert(HandleWrapper { - inner: Handle::SchemeRoot, - stat: false, - })) - } - fn openat( - &mut self, - dirfd: usize, - path: &str, - flags: usize, - _fcntl_flags: u32, - ctx: &CallerCtx, - ) -> Result { - let handle = self.handles.get(dirfd)?; - if !handle.inner.is_scheme_root() { - return Err(Error::new(EACCES)); - } - - log::trace!("OPEN `{}` flags {}", path, flags); - - // TODO: Check flags are correct - let expects_dir = path.ends_with('/') || flags & O_DIRECTORY != 0; - - let path = path.trim_matches('/'); - - let handle = if path.is_empty() { - Handle::TopLevel { - entries: self - .tree - .iter() - // FIXME remove replacement of : once the old scheme format is no longer supported. - .map(|(addr, _)| format!("{}", addr).replace(':', "--")) - .collect::>(), - } - } else if path == "access" { - Handle::Access - } else { - let idx = path.find('/').unwrap_or(path.len()); - let (addr_str, after) = path.split_at(idx); - let addr = parse_pci_addr(addr_str).ok_or(Error::new(ENOENT))?; - - self.parse_after_pci_addr(addr, after)? - }; - - let stat = flags & O_STAT != 0; - if expects_dir && handle.is_file() && !stat { - return Err(Error::new(ENOTDIR)); - } - if !expects_dir && handle.is_dir() && !stat { - return Err(Error::new(EISDIR)); - } - if ctx.uid != 0 && handle.requires_root() && !stat { - return Err(Error::new(EACCES)); - } - - let id = self.handles.insert(HandleWrapper { - inner: handle, - stat, - }); - Ok(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - }) - } - fn fstat(&mut self, id: usize, stat: &mut syscall::Stat, _ctx: &CallerCtx) -> Result<()> { - let handle = self.handles.get_mut(id)?; - - let (len, mode) = match handle.inner { - Handle::TopLevel { ref entries } => (entries.len(), MODE_DIR | 0o755), - Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755), - Handle::Access | Handle::Channel { .. } => (0, MODE_CHR | 0o600), - Handle::SchemeRoot => return Err(Error::new(EBADF)), - }; - stat.st_size = len as u64; - stat.st_mode = mode; - Ok(()) - } - fn read( - &mut self, - id: usize, - buf: &mut [u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - let handle = self.handles.get_mut(id)?; - - if handle.stat { - return Err(Error::new(EBADF)); - } - - match handle.inner { - Handle::TopLevel { .. } => Err(Error::new(EISDIR)), - Handle::Device => Err(Error::new(EISDIR)), - Handle::Channel { - addr: _, - ref mut st, - } => Self::read_channel(st, buf), - Handle::SchemeRoot => Err(Error::new(EBADF)), - _ => Err(Error::new(EBADF)), - } - } - fn getdents<'buf>( - &mut self, - id: usize, - mut buf: DirentBuf<&'buf mut [u8]>, - opaque_offset: u64, - ) -> Result> { - let Ok(offset) = usize::try_from(opaque_offset) else { - return Ok(buf); - }; - - let handle = self.handles.get_mut(id)?; - - if handle.stat { - return Err(Error::new(EBADF)); - } - - let entries = match handle.inner { - Handle::TopLevel { ref entries } => { - for (i, dent_name) in entries.iter().enumerate().skip(offset) { - buf.entry(DirEntry { - inode: 0, - name: dent_name, - kind: DirentKind::Unspecified, - next_opaque_id: i as u64 + 1, - })?; - } - return Ok(buf); - } - Handle::Device => DEVICE_CONTENTS, - Handle::Access | Handle::Channel { .. } => return Err(Error::new(ENOTDIR)), - Handle::SchemeRoot => return Err(Error::new(EBADF)), - }; - - for (i, dent_name) in entries.iter().enumerate().skip(offset) { - buf.entry(DirEntry { - inode: 0, - name: dent_name, - kind: DirentKind::Unspecified, - next_opaque_id: i as u64 + 1, - })?; - } - Ok(buf) - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - let handle = self.handles.get_mut(id)?; - - if handle.stat { - return Err(Error::new(EBADF)); - } - - match handle.inner { - Handle::Channel { addr, ref mut st } => { - Self::write_channel(&self.pcie, &mut self.tree, addr, st, buf) - } - - _ => Err(Error::new(EBADF)), - } - } - - fn call( - &mut self, - id: usize, - payload: &mut [u8], - metadata: &[u64], - _ctx: &CallerCtx, - ) -> Result { - let handle = self.handles.get_mut(id)?; - - if handle.stat { - return Err(Error::new(EBADF)); - } - - match handle.inner { - Handle::Access => { - let payload_len = u16::try_from(payload.len()).map_err(|_| Error::new(EINVAL))?; - let write = match metadata.get(0) { - Some(1) => false, - Some(2) => true, - _ => return Err(Error::new(EINVAL)), - }; - let (addr, offset) = match metadata.get(1) { - Some(value) => { - // Segment: u16, at 28 bits - // Bus: u8, 8 bits, 256 total, at 20 bits - // Device: u8, 5 bits, 32 total, at 15 bits - // Function: u8, 3 bits, 8 total, at 12 bits - // Offset: u16, 12 bits, 4096 total, at 0 bits - ( - PciAddress::new( - ((value >> 28) & 0xFFFF) as u16, - ((value >> 20) & 0xFF) as u8, - ((value >> 15) & 0x1F) as u8, - ((value >> 12) & 0x7) as u8, - ), - (value & 0xFFF) as u16, - ) - } - None => return Err(Error::new(EINVAL)), - }; - // This handle must allow less than 4 byte access, but the - // lower level only works with 4 byte reads and writes - let unaligned = offset % 4; - let start = offset - unaligned; - let end = offset + payload_len; - let mut i = 0; - while start + i < end { - let mut bytes = unsafe { self.pcie.read(addr, start + i) }.to_le_bytes(); - for j in 0..bytes.len() { - if let Some(payload_i) = i.checked_sub(unaligned) { - if let Some(payload_b) = payload.get_mut(usize::from(payload_i)) { - if write { - bytes[j] = *payload_b; - } else { - *payload_b = bytes[j] - } - } - } - i += 1; - } - if write { - let value = u32::from_le_bytes(bytes); - unsafe { - self.pcie.write(addr, start + i, value); - } - } - } - Ok(payload.len()) - } - - _ => Err(Error::new(EBADF)), - } - } - - fn on_close(&mut self, id: usize) { - match self.handles.remove(id) { - Some(HandleWrapper { - inner: Handle::Channel { addr, .. }, - .. - }) => { - log::trace!("TODO: Support disabling device (called on {})", addr); - if let Some(func) = self.tree.get_mut(&addr) { - func.enabled = false; - } - } - _ => {} - } - } -} - -impl PciScheme { - pub fn new(pcie: Pcie) -> Self { - Self { - handles: HandleMap::new(), - pcie, - tree: BTreeMap::new(), - } - } - fn parse_after_pci_addr(&mut self, addr: PciAddress, after: &str) -> Result { - if after.chars().next().map_or(false, |c| c != '/') { - return Err(Error::new(ENOENT)); - } - let func = self.tree.get_mut(&addr).ok_or(Error::new(ENOENT))?; - - Ok(if after.is_empty() { - Handle::Device - } else { - let path = &after[1..]; - - match path { - "channel" => { - if func.enabled { - return Err(Error::new(ENOLCK)); - } - func.inner.legacy_interrupt_line = crate::enable_function( - &self.pcie, - &mut func.endpoint_header, - &mut func.capabilities, - ); - func.enabled = true; - Handle::Channel { - addr, - st: ChannelState::AwaitingData, - } - } - _ => return Err(Error::new(ENOENT)), - } - }) - } - - fn read_channel(state: &mut ChannelState, buf: &mut [u8]) -> Result { - match *state { - ChannelState::AwaitingResponseRead(ref mut queue) => { - let byte_count = std::cmp::min(queue.len(), buf.len()); - // XXX: Why can't VecDeque support dequeueing into slices? - for (idx, byte) in queue.drain(..byte_count).enumerate() { - buf[idx] = byte; - } - if queue.is_empty() { - *state = ChannelState::AwaitingData; - } - Ok(byte_count) - } - ChannelState::AwaitingData => Err(Error::new(EINVAL)), - } - } - fn write_channel( - pci_state: &Pcie, - tree: &mut BTreeMap, - addr: PciAddress, - state: &mut ChannelState, - buf: &[u8], - ) -> Result { - match *state { - ChannelState::AwaitingResponseRead(_) => return Err(Error::new(EINVAL)), - ChannelState::AwaitingData => { - let func = tree.get_mut(&addr).unwrap(); - - let request = bincode::deserialize_from(buf).map_err(|_| Error::new(EINVAL))?; - let response = crate::driver_handler::DriverHandler::new( - func.inner.clone(), - &mut func.endpoint_header, - &mut func.capabilities, - &*pci_state, - ) - .respond(request); - - let mut output_bytes = vec![0_u8; 8]; - bincode::serialize_into(&mut output_bytes, &response) - .map_err(|_| Error::new(EIO))?; - let len = output_bytes.len() - 8; - output_bytes[..8].copy_from_slice(&u64::to_le_bytes(len as u64)); - *state = ChannelState::AwaitingResponseRead(output_bytes.into()); - - Ok(buf.len()) - } - } - } -} - -fn parse_pci_addr(addr: &str) -> Option { - // FIXME use : instead of -- as separator once the old scheme format is no longer supported. - let (segment, rest) = addr.split_once("--")?; - let segment = u16::from_str_radix(segment, 16).ok()?; - - // FIXME use : instead of -- as separator once the old scheme format is no longer supported. - let (bus, rest) = rest.split_once("--")?; - let bus = u8::from_str_radix(bus, 16).ok()?; - - let (device, function) = rest.split_once('.')?; - let device = u8::from_str_radix(device, 16).ok()?; - let function = u8::from_str_radix(function, 16).ok()?; - - Some(PciAddress::new(segment, bus, device, function)) -} diff --git a/recipes/core/base/drivers/redoxerd/Cargo.toml b/recipes/core/base/drivers/redoxerd/Cargo.toml deleted file mode 100644 index 6214b45a6f..0000000000 --- a/recipes/core/base/drivers/redoxerd/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "redoxerd" -description = "Redoxer QEMU daemon" -version = "0.1.0" -authors = ["Jeremy Soller "] -edition = "2018" - -[dependencies] -anyhow.workspace = true -libredox.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true -redox_termios.workspace = true -common = { path = "../common" } -qemu-exit = "3.0.2" - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/redoxerd/src/main.rs b/recipes/core/base/drivers/redoxerd/src/main.rs deleted file mode 100644 index 5ecd0b4672..0000000000 --- a/recipes/core/base/drivers/redoxerd/src/main.rs +++ /dev/null @@ -1,184 +0,0 @@ -use anyhow::Context; -use std::fs::{self, OpenOptions}; -use std::io; -use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; -use std::process::{Child, Command, ExitStatus, Stdio}; - -mod sys; - -const DEFAULT_COLS: u32 = 80; -const DEFAULT_LINES: u32 = 30; - -event::user_data! { - enum EventData { - Pty, - Timer, - } -} - -fn handle( - event_queue: event::EventQueue, - master_fd: RawFd, - timeout_fd: RawFd, - process: &mut Child, -) -> io::Result { - let handle_event = |event: EventData| -> io::Result { - match event { - EventData::Pty => { - let mut packet = [0; 4096]; - loop { - // Read data from PTY master - let count = match libredox::call::read(master_fd as usize, &mut packet) { - Ok(0) => return Ok(false), - Ok(count) => count, - Err(ref err) if err.errno() == libredox::errno::EAGAIN => return Ok(true), - Err(err) => return Err(err.into()), - }; - - // Write data to stdout - libredox::call::write(1, &packet[1..count])?; - - for i in 1..count { - // Write byte to QEMU debugcon (Bochs compatible) - sys::debug_char(packet[i]); - } - } - } - EventData::Timer => { - let mut timespec = syscall::TimeSpec::default(); - libredox::call::read(timeout_fd as usize, &mut timespec)?; - - timespec.tv_sec += 1; - libredox::call::write(timeout_fd as usize, &mut timespec)?; - - Ok(true) - } - } - }; - - if handle_event(EventData::Pty)? && handle_event(EventData::Timer)? { - 'events: loop { - match process.try_wait() { - Ok(status_opt) => match status_opt { - Some(status) => return Ok(status), - None => (), - }, - Err(err) => match err.kind() { - io::ErrorKind::WouldBlock => (), - _ => return Err(err), - }, - } - - let event = event_queue.next_event()?; - if !handle_event(event.user_data)? { - break 'events; - } - } - } - - let _ = process.kill(); - process.wait() -} - -fn getpty(columns: u32, lines: u32) -> io::Result<(RawFd, String)> { - let master = libredox::call::open( - "/scheme/pty", - libredox::flag::O_CLOEXEC - | libredox::flag::O_RDWR - | libredox::flag::O_CREAT - | libredox::flag::O_NONBLOCK, - 0, - )?; - - if let Ok(winsize_fd) = libredox::call::dup(master, b"winsize") { - let _ = libredox::call::write( - winsize_fd, - &redox_termios::Winsize { - ws_row: lines as u16, - ws_col: columns as u16, - }, - ); - let _ = libredox::call::close(winsize_fd); - } - - let mut buf: [u8; 4096] = [0; 4096]; - let count = libredox::call::fpath(master, &mut buf)?; - Ok((master as RawFd, unsafe { - String::from_utf8_unchecked(Vec::from(&buf[..count])) - })) -} - -fn inner() -> anyhow::Result<()> { - common::acquire_port_io_rights()?; - - let config = fs::read_to_string("/etc/redoxerd").context("Failed to read /etc/redoxerd")?; - let mut config_lines = config.lines(); - - let (columns, lines) = (DEFAULT_COLS, DEFAULT_LINES); - let (master_fd, pty) = getpty(columns, lines)?; - - let timeout_fd = libredox::call::open( - "/scheme/time/4", - libredox::flag::O_CLOEXEC | libredox::flag::O_RDWR | libredox::flag::O_NONBLOCK, - 0, - )? as RawFd; - - let event_queue = event::EventQueue::new()?; - event_queue.subscribe(master_fd as usize, EventData::Pty, event::EventFlags::READ)?; - event_queue.subscribe( - timeout_fd as usize, - EventData::Timer, - event::EventFlags::READ, - )?; - - let slave_stdin = OpenOptions::new().read(true).open(&pty)?; - let slave_stdout = OpenOptions::new().write(true).open(&pty)?; - let slave_stderr = OpenOptions::new().write(true).open(&pty)?; - - let Some(name) = config_lines.next() else { - anyhow::bail!("/etc/redoxerd does not specify command"); - }; - let mut command = Command::new(name); - for arg in config_lines { - command.arg(arg); - } - unsafe { - command - .stdin(Stdio::from_raw_fd(slave_stdin.into_raw_fd())) - .stdout(Stdio::from_raw_fd(slave_stdout.into_raw_fd())) - .stderr(Stdio::from_raw_fd(slave_stderr.into_raw_fd())) - .env("COLUMNS", format!("{}", columns)) - .env("LINES", format!("{}", lines)) - .env("TERM", "xterm-256color") - .env("TTY", &pty); - } - - let mut process = command - .spawn() - .with_context(|| format!("Failed to spawn {command:?}"))?; - let status = handle(event_queue, master_fd, timeout_fd, &mut process) - .with_context(|| format!("Failed to run {name}"))?; - if status.success() { - Ok(()) - } else { - anyhow::bail!("{name} failed with {}", status); - } -} - -fn main() { - match inner() { - Ok(()) => { - // Exit with success using qemu device - sys::exit_success(); - } - Err(err) => { - eprintln!("redoxerd: {:#}", err); - - // Wait a bit for the error message to get flushed through the tty subsystem before exiting. - std::thread::sleep(std::time::Duration::from_millis(100)); - - // Exit with error using qemu device - sys::exit_failure(); - } - } -} diff --git a/recipes/core/base/drivers/redoxerd/src/sys.rs b/recipes/core/base/drivers/redoxerd/src/sys.rs deleted file mode 100644 index 2731eacefb..0000000000 --- a/recipes/core/base/drivers/redoxerd/src/sys.rs +++ /dev/null @@ -1,69 +0,0 @@ -pub fn exit_success() { - imp::exit(true); -} - -pub fn exit_failure() { - imp::exit(false); -} - -pub fn debug_char(b: u8) { - let _ = imp::write_debug(b); -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod imp { - use syscall::Io; - use syscall::Pio; - - pub fn exit(success: bool) { - if success { - Pio::::new(0x604).write(0x2000); - Pio::::new(0x501).write(51 / 2); - } else { - Pio::::new(0x501).write(53 / 2); - } - } - - pub fn write_debug(b: u8) -> syscall::Result<()> { - Pio::::new(0xe9).write(b); - Ok(()) - } -} - -#[cfg(target_arch = "aarch64")] -mod imp { - use qemu_exit::QEMUExit; - - pub fn exit(success: bool) { - let q = qemu_exit::AArch64::new(); - if success { - q.exit(51) - } else { - q.exit(53) - } - } - - pub fn write_debug(b: u8) -> syscall::Result<()> { - // TODO - Ok(()) - } -} - -#[cfg(target_arch = "riscv64")] -mod imp { - - pub fn exit(success: bool) { - todo!() - // let q = qemu_exit::RISCV64::new(addr); - // if success { - // q.exit(51) - // } else { - // q.exit(53) - // } - } - - pub fn write_debug(b: u8) -> syscall::Result<()> { - // TODO - Ok(()) - } -} diff --git a/recipes/core/base/drivers/rtcd/Cargo.toml b/recipes/core/base/drivers/rtcd/Cargo.toml deleted file mode 100644 index 123b04f68c..0000000000 --- a/recipes/core/base/drivers/rtcd/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "rtcd" -description = "x86 Real Time Clock daemon" -version = "0.1.0" -authors = ["4lDO2 <4lDO2@protonmail.com>"] -edition = "2018" -license = "MIT" - - -[dependencies] -anyhow.workspace = true - -common = { path = "../common" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/rtcd/src/main.rs b/recipes/core/base/drivers/rtcd/src/main.rs deleted file mode 100644 index 3e913780ab..0000000000 --- a/recipes/core/base/drivers/rtcd/src/main.rs +++ /dev/null @@ -1,26 +0,0 @@ -use anyhow::{Context, Result}; - -// TODO: Do not use target architecture to distinguish these. -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod x86; - -/// The rtc driver runs only once, being perhaps the first of all processes that init starts (since -/// early logging benefits from knowing the time, even though this can be adjusted later once the -/// time is known). The sole job of `rtcd` is to read from the hardware real-time clock, and then -/// write the offset to the kernel. - -fn main() -> Result<()> { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - common::acquire_port_io_rights().context("failed to set iopl")?; - - let time_s = self::x86::get_time(); - let time_ns = u128::from(time_s) * 1_000_000_000; - - std::fs::write("/scheme/sys/update_time_offset", &time_ns.to_ne_bytes()) - .context("failed to write to time offset")?; - } - // TODO: aarch64 is currently handled in the kernel - - Ok(()) -} diff --git a/recipes/core/base/drivers/rtcd/src/x86.rs b/recipes/core/base/drivers/rtcd/src/x86.rs deleted file mode 100644 index ea2aebcbbf..0000000000 --- a/recipes/core/base/drivers/rtcd/src/x86.rs +++ /dev/null @@ -1,147 +0,0 @@ -// TODO: Get RTC information from acpid. -use common::io::{Io, Pio}; - -pub fn get_time() -> u64 { - Rtc::new().time() -} - -fn cvt_bcd(value: usize) -> usize { - (value & 0xF) + ((value / 16) * 10) -} - -/// RTC -pub struct Rtc { - addr: Pio, - data: Pio, - nmi: bool, -} - -impl Rtc { - /// Create new empty RTC - pub fn new() -> Self { - Rtc { - addr: Pio::::new(0x70), - data: Pio::::new(0x71), - nmi: false, - } - } - - /// Read - unsafe fn read(&mut self, reg: u8) -> u8 { - if self.nmi { - self.addr.write(reg & 0x7F); - } else { - self.addr.write(reg | 0x80); - } - self.data.read() - } - - /// Write - #[allow(dead_code)] - unsafe fn write(&mut self, reg: u8, value: u8) { - if self.nmi { - self.addr.write(reg & 0x7F); - } else { - self.addr.write(reg | 0x80); - } - self.data.write(value); - } - - /// Wait for an update, can take one second if full is specified! - unsafe fn wait(&mut self, full: bool) { - if full { - while self.read(0xA) & 0x80 != 0x80 {} - } - while self.read(0xA) & 0x80 == 0x80 {} - } - - /// Get time without waiting - pub unsafe fn time_no_wait(&mut self) -> u64 { - /*let century_register = if let Some(ref fadt) = acpi::ACPI_TABLE.lock().fadt { - Some(fadt.century) - } else { - None - };*/ - - let mut second = self.read(0) as usize; - let mut minute = self.read(2) as usize; - let mut hour = self.read(4) as usize; - let mut day = self.read(7) as usize; - let mut month = self.read(8) as usize; - let mut year = self.read(9) as usize; - let mut century = /* TODO: Fix invalid value from VirtualBox - if let Some(century_reg) = century_register { - self.read(century_reg) as usize - } else */ { - 20 - }; - let register_b = self.read(0xB); - - if register_b & 4 != 4 { - second = cvt_bcd(second); - minute = cvt_bcd(minute); - hour = cvt_bcd(hour & 0x7F) | (hour & 0x80); - day = cvt_bcd(day); - month = cvt_bcd(month); - year = cvt_bcd(year); - century = /* TODO: Fix invalid value from VirtualBox - if century_register.is_some() { - cvt_bcd(century) - } else */ { - century - }; - } - - if register_b & 2 != 2 || hour & 0x80 == 0x80 { - hour = ((hour & 0x7F) + 12) % 24; - } - - year += century * 100; - - // Unix time from clock - let mut secs: u64 = (year as u64 - 1970) * 31_536_000; - - let mut leap_days = (year as u64 - 1972) / 4 + 1; - if year % 4 == 0 && month <= 2 { - leap_days -= 1; - } - secs += leap_days * 86_400; - - match month { - 2 => secs += 2_678_400, - 3 => secs += 5_097_600, - 4 => secs += 7_776_000, - 5 => secs += 10_368_000, - 6 => secs += 13_046_400, - 7 => secs += 15_638_400, - 8 => secs += 18_316_800, - 9 => secs += 20_995_200, - 10 => secs += 23_587_200, - 11 => secs += 26_265_600, - 12 => secs += 28_857_600, - _ => (), - } - - secs += (day as u64 - 1) * 86_400; - secs += hour as u64 * 3600; - secs += minute as u64 * 60; - secs += second as u64; - - secs - } - - /// Get time - pub fn time(&mut self) -> u64 { - loop { - unsafe { - self.wait(false); - let time = self.time_no_wait(); - self.wait(false); - let next_time = self.time_no_wait(); - if time == next_time { - return time; - } - } - } - } -} diff --git a/recipes/core/base/drivers/storage/ahcid/.gitignore b/recipes/core/base/drivers/storage/ahcid/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/recipes/core/base/drivers/storage/ahcid/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/recipes/core/base/drivers/storage/ahcid/Cargo.toml b/recipes/core/base/drivers/storage/ahcid/Cargo.toml deleted file mode 100644 index 91458cf1d1..0000000000 --- a/recipes/core/base/drivers/storage/ahcid/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "ahcid" -description = "AHCI (SATA standard) driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -byteorder = "1.2" -log.workspace = true -redox_syscall = { workspace = true, features = ["std"] } - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-block = { path = "../driver-block" } -pcid = { path = "../../pcid" } -libredox.workspace = true -redox_event.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/storage/ahcid/src/ahci/disk_ata.rs b/recipes/core/base/drivers/storage/ahcid/src/ahci/disk_ata.rs deleted file mode 100644 index 4f83c51dcf..0000000000 --- a/recipes/core/base/drivers/storage/ahcid/src/ahci/disk_ata.rs +++ /dev/null @@ -1,185 +0,0 @@ -use std::convert::TryInto; -use std::ptr; - -use syscall::error::Result; - -use common::dma::Dma; - -use super::hba::{HbaCmdHeader, HbaCmdTable, HbaPort}; -use super::Disk; - -enum BufferKind<'a> { - Read(&'a mut [u8]), - Write(&'a [u8]), -} - -struct Request { - address: usize, - total_sectors: usize, - sector: usize, - running_opt: Option<(u32, usize)>, -} - -pub struct DiskATA { - id: usize, - port: &'static mut HbaPort, - size: u64, - request_opt: Option, - clb: Dma<[HbaCmdHeader; 32]>, - ctbas: [Dma; 32], - _fb: Dma<[u8; 256]>, - buf: Dma<[u8; 256 * 512]>, -} - -impl DiskATA { - pub fn new(id: usize, port: &'static mut HbaPort) -> Result { - let mut clb = unsafe { Dma::zeroed()?.assume_init() }; - - let mut ctbas: [_; 32] = (0..32) - .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) - .collect::>>()? - .try_into() - .unwrap_or_else(|_| unreachable!()); - - let mut fb = unsafe { Dma::zeroed()?.assume_init() }; - let buf = unsafe { Dma::zeroed()?.assume_init() }; - - port.init(&mut clb, &mut ctbas, &mut fb)?; - - let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) }; - - Ok(DiskATA { - id: id, - port: port, - size: size, - request_opt: None, - clb: clb, - ctbas, - _fb: fb, - buf: buf, - }) - } - - fn request(&mut self, block: u64, mut buffer_kind: BufferKind) -> Result> { - let (write, address, total_sectors) = match buffer_kind { - BufferKind::Read(ref buffer) => (false, buffer.as_ptr() as usize, buffer.len() / 512), - BufferKind::Write(ref buffer) => (true, buffer.as_ptr() as usize, buffer.len() / 512), - }; - - loop { - let mut request = match self.request_opt.take() { - Some(request) => { - if address == request.address && total_sectors == request.total_sectors { - // Keep servicing current request - request - } else { - // Have to wait for another request to finish - self.request_opt = Some(request); - return Ok(None); - } - } - None => { - // Create new request - Request { - address, - total_sectors, - sector: 0, - running_opt: None, - } - } - }; - - // Finish a previously running request - if let Some(running) = request.running_opt.take() { - if self.port.ata_running(running.0) { - // Continue waiting for request - request.running_opt = Some(running); - self.request_opt = Some(request); - return Ok(None); - } - - self.port.ata_stop(running.0)?; - - if let BufferKind::Read(ref mut buffer) = buffer_kind { - unsafe { - ptr::copy( - self.buf.as_ptr(), - buffer.as_mut_ptr().add(request.sector * 512), - running.1 * 512, - ); - } - } - - request.sector += running.1; - } - - if request.sector < request.total_sectors { - // Start a new request - let sectors = if request.total_sectors - request.sector >= 255 { - 255 - } else { - request.total_sectors - request.sector - }; - - if let BufferKind::Write(ref buffer) = buffer_kind { - unsafe { - ptr::copy( - buffer.as_ptr().add(request.sector * 512), - self.buf.as_mut_ptr(), - sectors * 512, - ); - } - } - - if let Some(slot) = self.port.ata_dma( - block + request.sector as u64, - sectors, - write, - &mut self.clb, - &mut self.ctbas, - &mut self.buf, - )? { - request.running_opt = Some((slot, sectors)); - } - - self.request_opt = Some(request); - - // TODO: support async internally - return Ok(None); - } else { - // Done - return Ok(Some(request.sector * 512)); - } - } - } -} - -impl Disk for DiskATA { - fn block_size(&self) -> u32 { - 512 - } - - fn size(&self) -> u64 { - self.size - } - - async fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { - //TODO: FIGURE OUT WHY INTERRUPTS CAUSE HANGS - loop { - match self.request(block, BufferKind::Read(buffer))? { - Some(count) => return Ok(count), - None => std::thread::yield_now(), - } - } - } - - async fn write(&mut self, block: u64, buffer: &[u8]) -> Result { - //TODO: FIGURE OUT WHY INTERRUPTS CAUSE HANGS - loop { - match self.request(block, BufferKind::Write(buffer))? { - Some(count) => return Ok(count), - None => std::thread::yield_now(), - } - } - } -} diff --git a/recipes/core/base/drivers/storage/ahcid/src/ahci/disk_atapi.rs b/recipes/core/base/drivers/storage/ahcid/src/ahci/disk_atapi.rs deleted file mode 100644 index a0e75c0964..0000000000 --- a/recipes/core/base/drivers/storage/ahcid/src/ahci/disk_atapi.rs +++ /dev/null @@ -1,148 +0,0 @@ -#![allow(dead_code)] - -use std::convert::TryInto; -use std::ptr; - -use byteorder::{BigEndian, ByteOrder}; - -use syscall::error::{Error, Result, EBADF}; - -use common::dma::Dma; - -use super::hba::{HbaCmdHeader, HbaCmdTable, HbaPort}; -use super::Disk; - -const SCSI_READ_CAPACITY: u8 = 0x25; -const SCSI_READ10: u8 = 0x28; - -pub struct DiskATAPI { - id: usize, - port: &'static mut HbaPort, - size: u64, - clb: Dma<[HbaCmdHeader; 32]>, - ctbas: [Dma; 32], - _fb: Dma<[u8; 256]>, - // Just using the same buffer size as DiskATA - // Although the sector size is different (and varies) - buf: Dma<[u8; 256 * 512]>, - blk_count: u32, - blk_size: u32, -} - -impl DiskATAPI { - pub fn new(id: usize, port: &'static mut HbaPort) -> Result { - let mut clb = unsafe { Dma::zeroed()?.assume_init() }; - - let mut ctbas: [_; 32] = (0..32) - .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) - .collect::>>()? - .try_into() - .unwrap_or_else(|_| unreachable!()); - - let mut fb = unsafe { Dma::zeroed()?.assume_init() }; - let mut buf = unsafe { Dma::zeroed()?.assume_init() }; - - port.init(&mut clb, &mut ctbas, &mut fb)?; - - let size = unsafe { port.identify_packet(&mut clb, &mut ctbas).unwrap_or(0) }; - - let mut cmd = [0; 16]; - cmd[0] = SCSI_READ_CAPACITY; - port.atapi_dma(&cmd, 8, &mut clb, &mut ctbas, &mut buf)?; - - // Instead of a count, contains number of last LBA, so add 1 - let blk_count = BigEndian::read_u32(&buf[0..4]) + 1; - let blk_size = BigEndian::read_u32(&buf[4..8]); - - Ok(DiskATAPI { - id, - port, - size, - clb, - ctbas, - _fb: fb, - buf, - blk_count, - blk_size, - }) - } -} - -impl Disk for DiskATAPI { - fn block_size(&self) -> u32 { - self.blk_size - } - - fn size(&self) -> u64 { - u64::from(self.blk_count) * u64::from(self.blk_size) - } - - async fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { - // TODO: Handle audio CDs, which use special READ CD command - - let blk_len = self.blk_size; - let sectors = buffer.len() as u32 / blk_len; - - fn read10_cmd(block: u32, count: u16) -> [u8; 16] { - let mut cmd = [0; 16]; - cmd[0] = SCSI_READ10; - BigEndian::write_u32(&mut cmd[2..6], block as u32); - BigEndian::write_u16(&mut cmd[7..9], count as u16); - cmd - } - - let mut sector = 0; - let buf_len = (256 * 512) / blk_len; - let buf_size = buf_len * blk_len; - while sectors - sector >= buf_len { - let cmd = read10_cmd(block as u32 + sector, buf_len as u16); - self.port.atapi_dma( - &cmd, - buf_size, - &mut self.clb, - &mut self.ctbas, - &mut self.buf, - )?; - - unsafe { - ptr::copy( - self.buf.as_ptr(), - buffer - .as_mut_ptr() - .offset(sector as isize * blk_len as isize), - buf_size as usize, - ); - } - - sector += blk_len; - } - if sector < sectors { - let cmd = read10_cmd(block as u32 + sector, (sectors - sector) as u16); - self.port.atapi_dma( - &cmd, - buf_size, - &mut self.clb, - &mut self.ctbas, - &mut self.buf, - )?; - - unsafe { - ptr::copy( - self.buf.as_ptr(), - buffer - .as_mut_ptr() - .offset(sector as isize * blk_len as isize), - ((sectors - sector) * blk_len) as usize, - ); - } - - sector += sectors - sector; - } - - Ok((sector * blk_len) as usize) - } - - async fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result { - Err(Error::new(EBADF)) // TODO: Implement writing - } -} diff --git a/recipes/core/base/drivers/storage/ahcid/src/ahci/fis.rs b/recipes/core/base/drivers/storage/ahcid/src/ahci/fis.rs deleted file mode 100644 index 56dd45b814..0000000000 --- a/recipes/core/base/drivers/storage/ahcid/src/ahci/fis.rs +++ /dev/null @@ -1,157 +0,0 @@ -use common::io::Mmio; - -#[repr(u8)] -pub enum FisType { - /// Register FIS - host to device - RegH2D = 0x27, - /// Register FIS - device to host - RegD2H = 0x34, - /// DMA activate FIS - device to host - DmaAct = 0x39, - /// DMA setup FIS - bidirectional - DmaSetup = 0x41, - /// Data FIS - bidirectional - Data = 0x46, - /// BIST activate FIS - bidirectional - Bist = 0x58, - /// PIO setup FIS - device to host - PioSetup = 0x5F, - /// Set device bits FIS - device to host - DevBits = 0xA1, -} - -#[repr(C, packed)] -pub struct FisRegH2D { - // DWORD 0 - pub fis_type: Mmio, // FIS_TYPE_REG_H2D - - pub pm: Mmio, // Port multiplier, 1: Command, 0: Control - - pub command: Mmio, // Command register - pub featurel: Mmio, // Feature register, 7:0 - - // DWORD 1 - pub lba0: Mmio, // LBA low register, 7:0 - pub lba1: Mmio, // LBA mid register, 15:8 - pub lba2: Mmio, // LBA high register, 23:16 - pub device: Mmio, // Device register - - // DWORD 2 - pub lba3: Mmio, // LBA register, 31:24 - pub lba4: Mmio, // LBA register, 39:32 - pub lba5: Mmio, // LBA register, 47:40 - pub featureh: Mmio, // Feature register, 15:8 - - // DWORD 3 - pub countl: Mmio, // Count register, 7:0 - pub counth: Mmio, // Count register, 15:8 - pub icc: Mmio, // Isochronous command completion - pub control: Mmio, // Control register - - // DWORD 4 - pub rsv1: [Mmio; 4], // Reserved -} - -#[repr(C, packed)] -pub struct FisRegD2H { - // DWORD 0 - pub fis_type: Mmio, // FIS_TYPE_REG_D2H - - pub pm: Mmio, // Port multiplier, Interrupt bit: 2 - - pub status: Mmio, // Status register - pub error: Mmio, // Error register - - // DWORD 1 - pub lba0: Mmio, // LBA low register, 7:0 - pub lba1: Mmio, // LBA mid register, 15:8 - pub lba2: Mmio, // LBA high register, 23:16 - pub device: Mmio, // Device register - - // DWORD 2 - pub lba3: Mmio, // LBA register, 31:24 - pub lba4: Mmio, // LBA register, 39:32 - pub lba5: Mmio, // LBA register, 47:40 - pub rsv2: Mmio, // Reserved - - // DWORD 3 - pub countl: Mmio, // Count register, 7:0 - pub counth: Mmio, // Count register, 15:8 - pub rsv3: [Mmio; 2], // Reserved - - // DWORD 4 - pub rsv4: [Mmio; 4], // Reserved -} - -#[repr(C, packed)] -pub struct FisData { - // DWORD 0 - pub fis_type: Mmio, // FIS_TYPE_DATA - - pub pm: Mmio, // Port multiplier - - pub rsv1: [Mmio; 2], // Reserved - - // DWORD 1 ~ N - pub data: [Mmio; 252], // Payload -} - -#[repr(C, packed)] -pub struct FisPioSetup { - // DWORD 0 - pub fis_type: Mmio, // FIS_TYPE_PIO_SETUP - - pub pm: Mmio, // Port multiplier, direction: 4 - device to host, interrupt: 2 - - pub status: Mmio, // Status register - pub error: Mmio, // Error register - - // DWORD 1 - pub lba0: Mmio, // LBA low register, 7:0 - pub lba1: Mmio, // LBA mid register, 15:8 - pub lba2: Mmio, // LBA high register, 23:16 - pub device: Mmio, // Device register - - // DWORD 2 - pub lba3: Mmio, // LBA register, 31:24 - pub lba4: Mmio, // LBA register, 39:32 - pub lba5: Mmio, // LBA register, 47:40 - pub rsv2: Mmio, // Reserved - - // DWORD 3 - pub countl: Mmio, // Count register, 7:0 - pub counth: Mmio, // Count register, 15:8 - pub rsv3: Mmio, // Reserved - pub e_status: Mmio, // New value of status register - - // DWORD 4 - pub tc: Mmio, // Transfer count - pub rsv4: [Mmio; 2], // Reserved -} - -#[repr(C, packed)] -pub struct FisDmaSetup { - // DWORD 0 - pub fis_type: Mmio, // FIS_TYPE_DMA_SETUP - - pub pm: Mmio, // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1 - - pub rsv1: [Mmio; 2], // Reserved - - // DWORD 1&2 - /* DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work. */ - pub dma_buffer_id_low: Mmio, - pub dma_buffer_id_high: Mmio, - - // DWORD 3 - pub rsv3: Mmio, // More reserved - - // DWORD 4 - pub dma_buffer_offset: Mmio, // Byte offset into buffer. First 2 bits must be 0 - - // DWORD 5 - pub transfer_count: Mmio, // Number of bytes to transfer. Bit 0 must be 0 - - // DWORD 6 - pub rsv6: Mmio, // Reserved -} diff --git a/recipes/core/base/drivers/storage/ahcid/src/ahci/hba.rs b/recipes/core/base/drivers/storage/ahcid/src/ahci/hba.rs deleted file mode 100644 index bea8792c80..0000000000 --- a/recipes/core/base/drivers/storage/ahcid/src/ahci/hba.rs +++ /dev/null @@ -1,549 +0,0 @@ -use log::{debug, error, info, trace}; -use std::mem::size_of; -use std::ops::DerefMut; -use std::time::Duration; -use std::{ptr, u32}; - -use common::dma::Dma; -use common::io::{Io, Mmio}; -use common::timeout::Timeout; -use syscall::error::{Error, Result, EIO}; - -use super::fis::{FisRegH2D, FisType}; - -const ATA_CMD_READ_DMA_EXT: u8 = 0x25; -const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35; -const ATA_CMD_IDENTIFY: u8 = 0xEC; -const ATA_CMD_IDENTIFY_PACKET: u8 = 0xA1; -const ATA_CMD_PACKET: u8 = 0xA0; -const ATA_DEV_BUSY: u8 = 0x80; -const ATA_DEV_DRQ: u8 = 0x08; - -const HBA_PORT_CMD_CR: u32 = 1 << 15; -const HBA_PORT_CMD_FR: u32 = 1 << 14; -const HBA_PORT_CMD_FRE: u32 = 1 << 4; -const HBA_PORT_CMD_ST: u32 = 1; -const HBA_PORT_IS_ERR: u32 = 1 << 30 | 1 << 29 | 1 << 28 | 1 << 27; -const HBA_SSTS_PRESENT: u32 = 0x3; -const HBA_SIG_ATA: u32 = 0x00000101; -const HBA_SIG_ATAPI: u32 = 0xEB140101; -const HBA_SIG_PM: u32 = 0x96690101; -const HBA_SIG_SEMB: u32 = 0xC33C0101; - -const TIMEOUT: Duration = Duration::new(5, 0); - -#[derive(Debug)] -pub enum HbaPortType { - None, - Unknown(u32), - SATA, - SATAPI, - PM, - SEMB, -} - -#[repr(C, packed)] -pub struct HbaPort { - pub clb: [Mmio; 2], // 0x00, command list base address, 1K-byte aligned - pub fb: [Mmio; 2], // 0x08, FIS base address, 256-byte aligned - pub is: Mmio, // 0x10, interrupt status - pub ie: Mmio, // 0x14, interrupt enable - pub cmd: Mmio, // 0x18, command and status - pub _rsv0: Mmio, // 0x1C, Reserved - pub tfd: Mmio, // 0x20, task file data - pub sig: Mmio, // 0x24, signature - pub ssts: Mmio, // 0x28, SATA status (SCR0:SStatus) - pub sctl: Mmio, // 0x2C, SATA control (SCR2:SControl) - pub serr: Mmio, // 0x30, SATA error (SCR1:SError) - pub sact: Mmio, // 0x34, SATA active (SCR3:SActive) - pub ci: Mmio, // 0x38, command issue - pub sntf: Mmio, // 0x3C, SATA notification (SCR4:SNotification) - pub fbs: Mmio, // 0x40, FIS-based switch control - pub _rsv1: [Mmio; 11], // 0x44 ~ 0x6F, Reserved - pub vendor: [Mmio; 4], // 0x70 ~ 0x7F, vendor specific -} - -impl HbaPort { - pub fn probe(&self) -> HbaPortType { - if self.ssts.readf(HBA_SSTS_PRESENT) { - let sig = self.sig.read(); - match sig { - HBA_SIG_ATA => HbaPortType::SATA, - HBA_SIG_ATAPI => HbaPortType::SATAPI, - HBA_SIG_PM => HbaPortType::PM, - HBA_SIG_SEMB => HbaPortType::SEMB, - _ => HbaPortType::Unknown(sig), - } - } else { - HbaPortType::None - } - } - - pub fn start(&mut self) -> Result<()> { - let timeout = Timeout::new(TIMEOUT); - while self.cmd.readf(HBA_PORT_CMD_CR) { - timeout.run().map_err(|()| { - log::error!("HBA start timed out"); - Error::new(EIO) - })?; - } - - self.cmd.writef(HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST, true); - Ok(()) - } - - pub fn stop(&mut self) -> Result<()> { - self.cmd.writef(HBA_PORT_CMD_ST, false); - - let timeout = Timeout::new(TIMEOUT); - while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { - timeout.run().map_err(|()| { - log::error!("HBA stop timed out"); - Error::new(EIO) - })?; - } - - self.cmd.writef(HBA_PORT_CMD_FRE, false); - Ok(()) - } - - pub fn slot(&self) -> Option { - let slots = self.sact.read() | self.ci.read(); - for i in 0..32 { - if slots & 1 << i == 0 { - return Some(i); - } - } - None - } - - pub fn init( - &mut self, - clb: &mut Dma<[HbaCmdHeader; 32]>, - ctbas: &mut [Dma; 32], - fb: &mut Dma<[u8; 256]>, - ) -> Result<()> { - self.stop()?; - - for i in 0..32 { - let cmdheader = &mut clb[i]; - cmdheader.ctba_low.write(ctbas[i].physical() as u32); - cmdheader - .ctba_high - .write((ctbas[i].physical() as u64 >> 32) as u32); - cmdheader.prdtl.write(0); - } - - self.clb[0].write(clb.physical() as u32); - self.clb[1].write(((clb.physical() as u64) >> 32) as u32); - self.fb[0].write(fb.physical() as u32); - self.fb[1].write(((fb.physical() as u64) >> 32) as u32); - let is = self.is.read(); - self.is.write(is); - self.ie.write(0b10111); - let serr = self.serr.read(); - self.serr.write(serr); - - // Disable power management - let sctl = self.sctl.read(); - self.sctl.write(sctl | 7 << 8); - - // Power on and spin up device - self.cmd.writef(1 << 2 | 1 << 1, true); - - debug!("AHCI init {:X}", self.cmd.read()); - Ok(()) - } - - pub unsafe fn identify( - &mut self, - clb: &mut Dma<[HbaCmdHeader; 32]>, - ctbas: &mut [Dma; 32], - ) -> Result { - self.identify_inner(ATA_CMD_IDENTIFY, clb, ctbas) - } - - pub unsafe fn identify_packet( - &mut self, - clb: &mut Dma<[HbaCmdHeader; 32]>, - ctbas: &mut [Dma; 32], - ) -> Result { - self.identify_inner(ATA_CMD_IDENTIFY_PACKET, clb, ctbas) - } - - // Shared between identify() and identify_packet() - unsafe fn identify_inner( - &mut self, - cmd: u8, - clb: &mut Dma<[HbaCmdHeader; 32]>, - ctbas: &mut [Dma; 32], - ) -> Result { - let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); - - let slot = self - .ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { - cmdheader.prdtl.write(1); - - let prdt_entry = &mut prdt_entries[0]; - prdt_entry.dba_low.write(dest.physical() as u32); - prdt_entry - .dba_high - .write((dest.physical() as u64 >> 32) as u32); - prdt_entry.dbc.write(512 | 1); - - cmdfis.pm.write(1 << 7); - cmdfis.command.write(cmd); - cmdfis.device.write(0); - cmdfis.countl.write(1); - cmdfis.counth.write(0); - })? - .ok_or(Error::new(EIO))?; - - self.ata_stop(slot)?; - - let mut serial = String::new(); - for word in 10..20 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - serial.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - serial.push(b); - } - } - - let mut firmware = String::new(); - for word in 23..27 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - firmware.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - firmware.push(b); - } - } - - let mut model = String::new(); - for word in 27..47 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - model.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - model.push(b); - } - } - - let mut sectors = (dest[100] as u64) - | ((dest[101] as u64) << 16) - | ((dest[102] as u64) << 32) - | ((dest[103] as u64) << 48); - - let lba_bits = if sectors == 0 { - sectors = (dest[60] as u64) | ((dest[61] as u64) << 16); - 28 - } else { - 48 - }; - - info!( - "Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", - serial.trim(), - firmware.trim(), - model.trim(), - lba_bits, - sectors / 2048 - ); - - Ok(sectors * 512) - } - - pub fn ata_dma( - &mut self, - block: u64, - sectors: usize, - write: bool, - clb: &mut Dma<[HbaCmdHeader; 32]>, - ctbas: &mut [Dma; 32], - buf: &mut Dma<[u8; 256 * 512]>, - ) -> Result> { - trace!( - "AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}", - (self as *mut HbaPort) as usize, - block, - sectors, - write - ); - - assert!(sectors > 0 && sectors < 256); - - self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { - if write { - let cfl = cmdheader.cfl.read(); - cmdheader.cfl.write(cfl | 1 << 7 | 1 << 6) - } - - cmdheader.prdtl.write(1); - - let prdt_entry = &mut prdt_entries[0]; - prdt_entry.dba_low.write(buf.physical() as u32); - prdt_entry - .dba_high - .write((buf.physical() as u64 >> 32) as u32); - prdt_entry.dbc.write(((sectors * 512) as u32) | 1); - - cmdfis.pm.write(1 << 7); - if write { - cmdfis.command.write(ATA_CMD_WRITE_DMA_EXT); - } else { - cmdfis.command.write(ATA_CMD_READ_DMA_EXT); - } - - cmdfis.lba0.write(block as u8); - cmdfis.lba1.write((block >> 8) as u8); - cmdfis.lba2.write((block >> 16) as u8); - - cmdfis.device.write(1 << 6); - - cmdfis.lba3.write((block >> 24) as u8); - cmdfis.lba4.write((block >> 32) as u8); - cmdfis.lba5.write((block >> 40) as u8); - - cmdfis.countl.write(sectors as u8); - cmdfis.counth.write((sectors >> 8) as u8); - }) - } - - /// Send ATAPI packet - pub fn atapi_dma( - &mut self, - cmd: &[u8; 16], - size: u32, - clb: &mut Dma<[HbaCmdHeader; 32]>, - ctbas: &mut [Dma; 32], - buf: &mut Dma<[u8; 256 * 512]>, - ) -> Result<()> { - let slot = self - .ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, acmd| { - let cfl = cmdheader.cfl.read(); - cmdheader.cfl.write(cfl | 1 << 5); - - cmdheader.prdtl.write(1); - - let prdt_entry = &mut prdt_entries[0]; - prdt_entry.dba_low.write(buf.physical() as u32); - prdt_entry - .dba_high - .write((buf.physical() as u64 >> 32) as u32); - prdt_entry.dbc.write(size - 1); - - cmdfis.pm.write(1 << 7); - cmdfis.command.write(ATA_CMD_PACKET); - cmdfis.device.write(0); - cmdfis.lba1.write(0); - cmdfis.lba2.write(0); - cmdfis.featurel.write(1); - cmdfis.featureh.write(0); - - unsafe { ptr::write_volatile(acmd.as_mut_ptr() as *mut [u8; 16], *cmd) }; - })? - .ok_or(Error::new(EIO))?; - self.ata_stop(slot) - } - - pub fn ata_start( - &mut self, - clb: &mut Dma<[HbaCmdHeader; 32]>, - ctbas: &mut [Dma; 32], - callback: F, - ) -> Result> - where - F: FnOnce( - &mut HbaCmdHeader, - &mut FisRegH2D, - &mut [HbaPrdtEntry; PRDT_ENTRIES], - &mut [Mmio; 16], - ), - { - //TODO: Should probably remove - self.is.write(u32::MAX); - - let Some(slot) = self.slot() else { - return Ok(None); - }; - - { - let cmdheader = &mut clb[slot as usize]; - cmdheader - .cfl - .write((size_of::() / size_of::()) as u8); - - let cmdtbl = &mut ctbas[slot as usize]; - unsafe { - ptr::write_bytes( - cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, - 0, - size_of::(), - ); - } - - let cmdfis = unsafe { &mut *(cmdtbl.cfis.as_mut_ptr() as *mut FisRegH2D) }; - cmdfis.fis_type.write(FisType::RegH2D as u8); - - let prdt_entry = unsafe { &mut *(&mut cmdtbl.prdt_entry as *mut _) }; - let acmd = unsafe { &mut *(&mut cmdtbl.acmd as *mut _) }; - - callback(cmdheader, cmdfis, prdt_entry, acmd) - } - - let timeout = Timeout::new(TIMEOUT); - while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - timeout.run().map_err(|()| { - log::error!("HBA ata_start timeout"); - Error::new(EIO) - })?; - } - - self.ci.writef(1 << slot, true); - - //TODO: Should probably remove - self.start()?; - - Ok(Some(slot)) - } - - pub fn ata_running(&self, slot: u32) -> bool { - (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 - } - - pub fn ata_stop(&mut self, slot: u32) -> Result<()> { - let timeout = Timeout::new(TIMEOUT); - while self.ata_running(slot) { - timeout.run().map_err(|()| { - log::error!("HBA ata_stop timeout"); - Error::new(EIO) - })?; - } - - self.stop()?; - - if self.is.read() & HBA_PORT_IS_ERR != 0 { - let (is, ie, cmd, tfd, ssts, sctl, serr, sact, ci, sntf, fbs) = ( - self.is.read(), - self.ie.read(), - self.cmd.read(), - self.tfd.read(), - self.ssts.read(), - self.sctl.read(), - self.serr.read(), - self.sact.read(), - self.ci.read(), - self.sntf.read(), - self.fbs.read(), - ); - - error!("IS {:X} IE {:X} CMD {:X} TFD {:X}", is, ie, cmd, tfd); - error!( - "SSTS {:X} SCTL {:X} SERR {:X} SACT {:X}", - ssts, sctl, serr, sact - ); - error!("CI {:X} SNTF {:X} FBS {:X}", ci, sntf, fbs); - - self.is.write(u32::MAX); - Err(Error::new(EIO)) - } else { - Ok(()) - } - } -} - -#[repr(C, packed)] -pub struct HbaMem { - pub cap: Mmio, // 0x00, Host capability - pub ghc: Mmio, // 0x04, Global host control - pub is: Mmio, // 0x08, Interrupt status - pub pi: Mmio, // 0x0C, Port implemented - pub vs: Mmio, // 0x10, Version - pub ccc_ctl: Mmio, // 0x14, Command completion coalescing control - pub ccc_pts: Mmio, // 0x18, Command completion coalescing ports - pub em_loc: Mmio, // 0x1C, Enclosure management location - pub em_ctl: Mmio, // 0x20, Enclosure management control - pub cap2: Mmio, // 0x24, Host capabilities extended - pub bohc: Mmio, // 0x28, BIOS/OS handoff control and status - pub _rsv: [Mmio; 116], // 0x2C - 0x9F, Reserved - pub vendor: [Mmio; 96], // 0xA0 - 0xFF, Vendor specific registers - pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers -} - -impl HbaMem { - pub fn init(&mut self) { - /* - self.ghc.writef(1, true); - while self.ghc.readf(1) { - pause(); - } - */ - self.ghc.write(1 << 31 | 1 << 1); - - debug!( - "AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}", - self.cap.read(), - self.ghc.read(), - self.is.read(), - self.pi.read(), - self.vs.read(), - self.cap2.read(), - self.bohc.read() - ); - } -} - -#[repr(C, packed)] -pub struct HbaPrdtEntry { - dba_low: Mmio, // Data base address (low - dba_high: Mmio, // Data base address (high) - _rsv0: Mmio, // Reserved - dbc: Mmio, // Byte count, 4M max, interrupt = 1 -} - -#[repr(C, packed)] -pub struct HbaCmdTable { - // 0x00 - cfis: [Mmio; 64], // Command FIS - - // 0x40 - acmd: [Mmio; 16], // ATAPI command, 12 or 16 bytes - - // 0x50 - _rsv: [Mmio; 48], // Reserved - - // 0x80 - prdt_entry: [HbaPrdtEntry; PRDT_ENTRIES], // Physical region descriptor table entries, 0 ~ 65535 -} -const CMD_TBL_SIZE: usize = 256 * 4096; -const PRDT_ENTRIES: usize = (CMD_TBL_SIZE - 128) / size_of::(); - -#[repr(C, packed)] -pub struct HbaCmdHeader { - // DW0 - cfl: Mmio, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */ - _pm: Mmio, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier - - prdtl: Mmio, // Physical region descriptor table length in entries - - // DW1 - _prdbc: Mmio, // Physical region descriptor byte count transferred - - // DW2, 3 - ctba_low: Mmio, // Command table descriptor base address (low) - ctba_high: Mmio, // Command table descriptor base address (high) - - // DW4 - 7 - _rsv1: [Mmio; 4], // Reserved -} diff --git a/recipes/core/base/drivers/storage/ahcid/src/ahci/mod.rs b/recipes/core/base/drivers/storage/ahcid/src/ahci/mod.rs deleted file mode 100644 index 4d8cc8c040..0000000000 --- a/recipes/core/base/drivers/storage/ahcid/src/ahci/mod.rs +++ /dev/null @@ -1,79 +0,0 @@ -use common::io::Io; -use driver_block::Disk; -use log::{error, info}; - -use self::disk_ata::DiskATA; -use self::disk_atapi::DiskATAPI; -use self::hba::{HbaMem, HbaPortType}; - -pub mod disk_ata; -pub mod disk_atapi; -pub mod fis; -pub mod hba; - -pub enum AnyDisk { - Ata(DiskATA), - Atapi(DiskATAPI), -} -impl Disk for AnyDisk { - fn block_size(&self) -> u32 { - match self { - Self::Ata(a) => a.block_size(), - Self::Atapi(a) => a.block_size(), - } - } - fn size(&self) -> u64 { - match self { - Self::Ata(a) => a.size(), - Self::Atapi(a) => a.size(), - } - } - async fn read(&mut self, base: u64, buffer: &mut [u8]) -> syscall::Result { - match self { - Self::Ata(a) => a.read(base, buffer).await, - Self::Atapi(a) => a.read(base, buffer).await, - } - } - async fn write(&mut self, base: u64, buffer: &[u8]) -> syscall::Result { - match self { - Self::Ata(a) => a.write(base, buffer).await, - Self::Atapi(a) => a.write(base, buffer).await, - } - } -} - -pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec) { - let hba_mem = unsafe { &mut *(base as *mut HbaMem) }; - hba_mem.init(); - let pi = hba_mem.pi.read(); - let disks: Vec = (0..hba_mem.ports.len()) - .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) - .filter_map(|i| { - let port = unsafe { &mut *hba_mem.ports.as_mut_ptr().add(i) }; - let port_type = port.probe(); - info!("{}-{}: {:?}", name, i, port_type); - - let disk: Option = match port_type { - HbaPortType::SATA => match DiskATA::new(i, port) { - Ok(disk) => Some(AnyDisk::Ata(disk)), - Err(err) => { - error!("{}: {}", i, err); - None - } - }, - HbaPortType::SATAPI => match DiskATAPI::new(i, port) { - Ok(disk) => Some(AnyDisk::Atapi(disk)), - Err(err) => { - error!("{}: {}", i, err); - None - } - }, - _ => None, - }; - - disk - }) - .collect(); - - (hba_mem, disks) -} diff --git a/recipes/core/base/drivers/storage/ahcid/src/main.rs b/recipes/core/base/drivers/storage/ahcid/src/main.rs deleted file mode 100644 index 1f130a2974..0000000000 --- a/recipes/core/base/drivers/storage/ahcid/src/main.rs +++ /dev/null @@ -1,109 +0,0 @@ -// #![cfg_attr(target_arch = "aarch64", feature(stdsimd))] // Required for yield instruction - -use std::io::{Read, Write}; -use std::os::fd::AsRawFd; -use std::usize; - -use common::io::Io; -use driver_block::{DiskScheme, ExecutorTrait, FuturesExecutor}; -use event::{EventFlags, RawEventQueue}; -use pcid_interface::PciFunctionHandle; - -use log::{error, info}; - -pub mod ahci; - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - let pci_config = pcid_handle.config(); - - let mut name = pci_config.func.name(); - name.push_str("_ahci"); - - let irq = pci_config - .func - .legacy_interrupt_line - .expect("ahcid: no legacy interrupts supported"); - - common::setup_logging( - "disk", - "pci", - &name, - common::output_level(), - common::file_level(), - ); - - info!("AHCI {}", pci_config.func.display()); - - let address = unsafe { pcid_handle.map_bar(5) }.ptr.as_ptr() as usize; - { - let (hba_mem, disks) = ahci::disks(address as usize, &name); - - let scheme_name = format!("disk.{}", name); - let mut scheme = DiskScheme::new( - Some(daemon), - scheme_name, - disks - .into_iter() - .enumerate() - .map(|(i, disk)| (i as u32, disk)) - .collect(), - &FuturesExecutor, - ); - - let mut irq_file = irq.irq_handle("ahcid"); - let irq_fd = irq_file.as_raw_fd() as usize; - - let event_queue = RawEventQueue::new().expect("ahcid: failed to create event queue"); - - libredox::call::setrens(0, 0).expect("ahcid: failed to enter null namespace"); - - event_queue - .subscribe(scheme.event_handle().raw(), 1, EventFlags::READ) - .expect("ahcid: failed to event scheme socket"); - event_queue - .subscribe(irq_fd, 1, EventFlags::READ) - .expect("ahcid: failed to event irq scheme"); - - for event in event_queue { - let event = event.unwrap(); - if event.fd == scheme.event_handle().raw() { - FuturesExecutor.block_on(scheme.tick()).unwrap(); - } else if event.fd == irq_fd { - let mut irq = [0; 8]; - if irq_file - .read(&mut irq) - .expect("ahcid: failed to read irq file") - >= irq.len() - { - let is = hba_mem.is.read(); - if is > 0 { - let pi = hba_mem.pi.read(); - let pi_is = pi & is; - for i in 0..hba_mem.ports.len() { - if pi_is & 1 << i > 0 { - let port = &mut hba_mem.ports[i]; - let is = port.is.read(); - port.is.write(is); - } - } - hba_mem.is.write(is); - - irq_file - .write(&irq) - .expect("ahcid: failed to write irq file"); - - FuturesExecutor.block_on(scheme.tick()).unwrap(); - } - } - } else { - error!("Unknown event {}", event.fd); - } - } - } - - std::process::exit(0); -} diff --git a/recipes/core/base/drivers/storage/bcm2835-sdhcid/Cargo.toml b/recipes/core/base/drivers/storage/bcm2835-sdhcid/Cargo.toml deleted file mode 100644 index fad2238b7b..0000000000 --- a/recipes/core/base/drivers/storage/bcm2835-sdhcid/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "bcm2835-sdhcid" -description = "BCM2835 storage controller driver" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -fdt = { git = "https://github.com/repnop/fdt.git", rev = "059bb23" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-block = { path = "../driver-block" } - -libredox.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -redox_event.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/storage/bcm2835-sdhcid/src/main.rs b/recipes/core/base/drivers/storage/bcm2835-sdhcid/src/main.rs deleted file mode 100644 index 2241d27c01..0000000000 --- a/recipes/core/base/drivers/storage/bcm2835-sdhcid/src/main.rs +++ /dev/null @@ -1,128 +0,0 @@ -use std::process; - -use driver_block::{DiskScheme, ExecutorTrait, TrivialExecutor}; -use event::{EventFlags, RawEventQueue}; -use fdt::Fdt; - -mod sd; - -#[cfg(target_os = "redox")] -fn get_dtb() -> Vec { - std::fs::read("kernel.dtb:").unwrap() -} - -#[cfg(target_os = "linux")] -fn get_dtb() -> Vec { - use std::env; - if let Some(arg1) = env::args().nth(1) { - std::fs::read(arg1).unwrap() - } else { - Vec::new() - } -} - -fn main() { - daemon::Daemon::new(daemon); -} - -fn daemon(daemon: daemon::Daemon) -> ! { - let dtb_data = get_dtb(); - println!("read from OS, len = {}", dtb_data.len()); - if dtb_data.len() == 0 { - process::exit(0); - } - - let fdt = Fdt::new(&dtb_data).unwrap(); - println!("DTB model = {}", fdt.root().model()); - let with = ["brcm,bcm2835-sdhci"]; - let compat_node = fdt.find_compatible(&with).unwrap(); - let reg = compat_node.reg().unwrap().next().unwrap(); - let reg_size = reg.size.unwrap(); - let mut reg_addr = reg.starting_address as usize; - println!( - "DeviceMemory start = 0x{:08x}, size = 0x{:08x}", - reg_addr, reg_size - ); - if let Some(mut ranges) = fdt.find_node("/soc").and_then(|f| f.ranges()) { - let range = ranges - .find(|f| f.child_bus_address <= reg_addr && reg_addr - f.child_bus_address < f.size) - .expect("Couldn't find device range in /soc/@ranges"); - reg_addr = range.parent_bus_address + (reg_addr - range.child_bus_address); - println!( - "DeviceMemory remapped onto CPU address space: start = 0x{:08x}, size = 0x{:08x}", - reg_addr, reg_size - ); - } - - let addr = unsafe { - common::physmap( - reg_addr, - reg_size, - common::Prot::RW, - common::MemoryType::DeviceMemory, - ) - .expect("bcm2835-sdhcid: failed to map address") as usize - }; - println!( - "ioremap 0x{:08x} to 0x{:08x} 2222", - reg.starting_address as usize, addr - ); - let mut sdhci = sd::SdHostCtrl::new(addr); - unsafe { - sdhci.init(); - /* - let mut buf1 = [0u32; 512]; - sdhci.sd_readblock(1, &mut buf1, 1); - println!("readblock {:?}", buf1); - buf1[0] = 0xdead_0000; - buf1[1] = 0xdead_0000; - buf1[2] = 0x0000_dead; - buf1[3] = 0x0000_dead; - sdhci.sd_writeblock(1, &buf1, 1); - sdhci.sd_readblock(1, &mut buf1, 1); - println!("readblock {:?}", buf1); - */ - /* - let mut buf1 = [0u8; 512]; - sdhci.read(1, &mut buf1); - println!("readblock {:?}", buf1); - buf1[0] = 0xde; - buf1[1] = 0xad; - buf1[2] = 0xde; - buf1[3] = 0xad; - sdhci.write(1, &buf1); - sdhci.read(1, &mut buf1); - println!("readblock {:?}", buf1); - */ - } - - let mut disks = Vec::new(); - disks.push(sdhci); - let mut scheme = DiskScheme::new( - Some(daemon), - "disk.mmc".to_string(), - disks - .into_iter() - .enumerate() - .map(|(i, disk)| (i as u32, disk)) - .collect(), - &TrivialExecutor, // TODO: real executor - ); - - let event_queue = RawEventQueue::new().expect("mmcd: failed to open event file"); - event_queue - .subscribe(scheme.event_handle().raw(), 0, EventFlags::READ) - .expect("mmcd: failed to event disk scheme"); - - libredox::call::setrens(0, 0).expect("mmcd: failed to enter null namespace"); - - for event in event_queue { - let event = event.unwrap(); - if event.fd == scheme.event_handle().raw() { - TrivialExecutor.block_on(scheme.tick()).unwrap(); - } else { - println!("Unknown event {}", event.fd); - } - } - process::exit(0); -} diff --git a/recipes/core/base/drivers/storage/bcm2835-sdhcid/src/sd/mod.rs b/recipes/core/base/drivers/storage/bcm2835-sdhcid/src/sd/mod.rs deleted file mode 100644 index afb568291a..0000000000 --- a/recipes/core/base/drivers/storage/bcm2835-sdhcid/src/sd/mod.rs +++ /dev/null @@ -1,785 +0,0 @@ -use common::io::{Io, Mmio}; -use driver_block::Disk; -use std::{sync::RwLock, thread, time::Duration}; -use syscall::{Error, Result, EINVAL}; - -#[cfg(target_arch = "aarch64")] -#[inline(always)] -pub(crate) unsafe fn wait_cycles(mut n: usize) { - use core::arch::asm; - - while n > 0 { - asm!("nop"); - n -= 1; - } -} - -#[cfg(target_arch = "riscv64")] -#[inline(always)] -pub(crate) unsafe fn wait_msec(mut n: usize) { - todo!() -} - -#[cfg(target_arch = "aarch64")] -#[inline(always)] -pub(crate) unsafe fn wait_msec(mut n: usize) { - use core::arch::asm; - - let mut f: usize; - let mut t: usize; - let mut r: usize; - - asm!("mrs {0}, cntfrq_el0", out(reg) f); - asm!("mrs {0}, cntpct_el0", out(reg) t); - - t += ((f / 1000) * n) / 1000; - - loop { - asm!("mrs {0}, cntpct_el0", out(reg) r); - if r >= t { - break; - } - } -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#[inline(always)] -pub(crate) unsafe fn wait_msec(n: usize) { - thread::sleep(Duration::from_millis(n as u64)); -} - -//cmd Flags -const CMD_NEED_APP: u32 = 0x8000_0000; -const CMD_RSPNS_48: u32 = 0x0002_0000; -const CMD_ERRORS_MASK: u32 = 0xfff9_c004; -const CMD_RCA_MASK: u32 = 0xffff_0000; - -//CMD -const CMD_GO_IDLE: u32 = 0x0000_0000; -const CMD_ALL_SEND_CID: u32 = 0x0201_0000; -const CMD_SEND_CSD: u32 = 0x0901_0000; -const CMD_SEND_REL_ADDR: u32 = 0x0302_0000; -const CMD_CARD_SELECT: u32 = 0x0703_0000; -const CMD_SEND_IF_COND: u32 = 0x0802_0000; -const CMD_STOP_TRANS: u32 = 0x0c03_0000; -const CMD_READ_SINGLE: u32 = 0x1122_0010; -const CMD_READ_MULTI: u32 = 0x1222_0032; -const CMD_SET_BLOCKCNT: u32 = 0x1702_0000; -const CMD_WRITE_SINGLE: u32 = 0x1822_0000; -const CMD_WRITE_MULTI: u32 = 0x1922_0022; - -const CMD_APP_CMD: u32 = 0x3700_0000; -const CMD_SET_BUS_WIDTH: u32 = 0x0602_0000 | CMD_NEED_APP; -const CMD_SEND_OP_COND: u32 = 0x2902_0000 | CMD_NEED_APP; -const CMD_SEND_SCR: u32 = 0x3322_0010 | CMD_NEED_APP; - -//STATUS register settings -const SR_READ_AVAILABLE: u32 = 0x0000_0800; -const SR_WRITE_AVAILABLE: u32 = 0x0000_0400; -const SR_DAT_INHIBIT: u32 = 0x0000_0002; -const SR_CMD_INHIBIT: u32 = 0x0000_0001; -const SR_APP_CMD: u32 = 0x0000_0020; - -//CONTROL register settings - -const C0_SPI_MODE_EN: u32 = 0x0010_0000; -const C0_HCTL_HS_EN: u32 = 0x0000_0004; -const C0_HCTL_DWITDH: u32 = 0x0000_0002; - -const C1_SRST_DATA: u32 = 0x0400_0000; -const C1_SRST_CMD: u32 = 0x0200_0000; -const C1_SRST_HC: u32 = 0x0100_0000; -const C1_TOUNIT_DIS: u32 = 0x000f_0000; -const C1_TOUNIT_MAX: u32 = 0x000e_0000; -const C1_CLK_GENSEL: u32 = 0x0000_0020; -const C1_CLK_EN: u32 = 0x0000_0004; -const C1_CLK_STABLE: u32 = 0x0000_0002; -const C1_CLK_INTLEN: u32 = 0x0000_0001; - -//INTERRUPT register settings -const INT_DATA_TIMEOUT: u32 = 0x0010_0000; -const INT_CMD_TIMEOUT: u32 = 0x0001_0000; -const INT_READ_RDY: u32 = 0x0000_0020; -const INT_WRITE_RDY: u32 = 0x0000_0010; -const INT_DATA_DONE: u32 = 0x0000_0002; -const INT_CMD_DONE: u32 = 0x0000_0001; -const INT_ERROR_MASK: u32 = 0x017e_8000; - -const HOST_SPEC_VERSION_OFFSET: u32 = 16; -const HOST_SPEC_VERSION_MASK: u32 = 0x00ff_0000; -const HOST_SPEC_V3: u32 = 2; -const HOST_SPEC_V2: u32 = 1; -const HOST_SPEC_V1: u32 = 0; - -const ACMD41_VOLTAGE: u32 = 0x00ff_8000; -const ACMD41_CMD_COMPLETE: u32 = 0x8000_0000; -const ACMD41_CMD_CCS: u32 = 0x4000_0000; -const ACMD41_ARG_HC: u32 = 0x51ff_8000; - -const SCR_SD_BUS_WIDTH_4: u32 = 0x0000_0400; -const SCR_SUPP_SET_BLKCNT: u32 = 0x0200_0000; -//added by bztsrc driver -const SCR_SUPP_CCS: u32 = 0x0000_0001; - -#[repr(C, packed)] -pub struct SdHostCtrlRegs { - //LSB - - //ACMD23 Argument - _arg2: Mmio, - - //Block Size and Count - blksizecnt: Mmio, - - //Argument - arg1: Mmio, - - //Command and Transfer Mode - cmdtm: Mmio, - - //Response bit 0-127 - resp0: Mmio, - resp1: Mmio, - resp2: Mmio, - resp3: Mmio, - - //Data - data: Mmio, - - //Status - status: Mmio, - - //Host Configuration bits - control0: Mmio, - - //Host Configuration bits - control1: Mmio, - - //Interrupt Flags - interrupt: Mmio, - - //Interrupt Flag Enable - irpt_mask: Mmio, - - //Interrupt Generation Enable - irpt_en: Mmio, - - //Host Configuration bits - _control2: Mmio, - - _rsvd: [Mmio; 47], - - //Slot Interrupt Status and Version - slotisr_ver: Mmio, -} - -//TODO: refactor, sd/sdhci/bcmh2835-sdhci three different modules. -pub struct SdHostCtrl { - regs: RwLock<&'static mut SdHostCtrlRegs>, - host_spec_ver: u32, - cid: [u32; 4], - csd: [u32; 4], - rca: u32, //relative card address - scr: [u32; 2], - ocr: u32, - size: u64, -} - -impl SdHostCtrl { - pub fn new(address: usize) -> Self { - SdHostCtrl { - regs: RwLock::new(unsafe { &mut *(address as *mut SdHostCtrlRegs) }), - host_spec_ver: 0, - cid: [0; 4], - csd: [0; 4], - rca: 0, - scr: [0; 2], - ocr: 0, - size: 0, - } - } - - pub unsafe fn init(&mut self) { - let regs = self.regs.get_mut().unwrap(); - - let mut reg_val = regs.slotisr_ver.read(); - self.host_spec_ver = (reg_val & HOST_SPEC_VERSION_MASK) >> HOST_SPEC_VERSION_OFFSET; - - regs.control0.write(0x0); - reg_val = regs.control1.read(); - regs.control1.write(reg_val | C1_SRST_HC); - let mut cnt = 1000; - while (cnt >= 0) && ((regs.control1.read() & C1_SRST_HC) == C1_SRST_HC) { - cnt -= 1; - wait_msec(10); - } - - if cnt < 0 { - println!("ERROR: failed to reset EMMC"); - return; - } - println!("EMMC: reset OK"); - reg_val = regs.control1.read(); - regs.control1.write(reg_val | C1_CLK_INTLEN | C1_TOUNIT_MAX); - - wait_msec(10); - - { - if let Err(_) = self.set_clock(40_0000) { - println!("ERROR: failed to set clock {}", 40_0000); - return; - } - } - - let regs = self.regs.get_mut().unwrap(); - regs.irpt_en.write(0xffff_ffff); - regs.irpt_mask.write(0xffff_ffff); - - if let Err(_) = self.sd_cmd(CMD_GO_IDLE, 0) { - println!("failed to go idle"); - return; - } - - if let Err(_) = self.sd_cmd(CMD_SEND_IF_COND, 0x0000_01aa) { - println!("failed to send if cond"); - return; - } - - cnt = 6; - reg_val = 0; - - while ((reg_val & ACMD41_CMD_COMPLETE) == 0) && cnt > 0 { - wait_msec(10); - cnt -= 1; - - if let Ok(val) = self.sd_cmd(CMD_SEND_OP_COND, ACMD41_ARG_HC) { - reg_val = val; - self.ocr = reg_val; - print!("EMMC: CMD_SEND_OP_COND returned 0x{:08x} = ", reg_val); - - if (reg_val & ACMD41_CMD_COMPLETE) != 0 { - print!("COMPLETE "); - } - if (reg_val & ACMD41_VOLTAGE) != 0 { - print!("VOLTAGE "); - } - if (reg_val & ACMD41_CMD_CCS) != 0 { - print!("CCS "); - } - print!("\n"); - } else { - println!("ERROR: EMMC ACMD41 returned error"); - return; - } - } - - if (reg_val & ACMD41_CMD_COMPLETE) == 0 || cnt <= 0 { - println!("ACMD41 TIMEOUT"); - return; - } - - if (reg_val & ACMD41_VOLTAGE) == 0 { - println!("ACMD41 VOLTAGE NOT FOUND!"); - return; - } - - let ccs = if (reg_val & ACMD41_CMD_CCS) != 0 { - SCR_SUPP_CCS - } else { - 0 - }; - - if let Err(_) = self.sd_cmd(CMD_ALL_SEND_CID, 0) { - println!("CMD_ALL_SEND_CID ERROR, IGNORE!"); - } - - let sd_rca = self.sd_cmd(CMD_SEND_REL_ADDR, 0x0).unwrap(); - println!("CMD_SEND_REL_ADDR = 0x{:08x}", sd_rca); - self.rca = sd_rca; - - if let Err(_) = self.sd_cmd(CMD_SEND_CSD, sd_rca) { - println!("failed to get csd"); - return; - } - - let (csize, cmult) = if (self.ocr & ACMD41_CMD_CCS) != 0 { - let csize = (self.csd[1] & 0x3f) << 16 | (self.csd[2] & 0xffff_0000) >> 16; - let cmult = 8; - (csize as u64, cmult as u64) - } else { - let csize = (self.csd[1] & 0x3ff) << 2 | (self.csd[2] & 0xc000_0000) >> 30; - let cmult = (self.csd[2] & 0x0003_8000) >> 15; - (csize as u64, cmult as u64) - }; - self.size = ((csize + 1) << (cmult + 2)) * 512; - println!("mmc size = 0x{:08x}", self.size); - - if let Err(_) = self.set_clock(2500_0000) { - println!("failed to set clock 2500_0000 Hz"); - return; - } - - if let Err(_) = self.sd_cmd(CMD_CARD_SELECT, sd_rca) { - println!("failed to CMD_CARD_SELECT 0x{:08x}", sd_rca); - return; - } - - if let Err(_) = self.sd_status(SR_DAT_INHIBIT) { - println!("SR_DAT_INHIBIT return"); - return; - } - - let regs = self.regs.get_mut().unwrap(); - regs.blksizecnt.write(1 << 16 | 8); - - if let Err(_) = self.sd_cmd(CMD_SEND_SCR, 0) { - println!("failed to CMD_SEND_SCR"); - return; - } - - if let Err(_) = self.sd_int(INT_READ_RDY) { - println!("failed to INT_READ_RDY"); - return; - } - - cnt = 10000; - let mut i = 0; - let regs = self.regs.get_mut().unwrap(); - while i < 2 && cnt > 0 { - reg_val = regs.status.read(); - cnt -= 1; - if (reg_val & SR_READ_AVAILABLE) != 0 { - self.scr[i] = regs.data.read(); - i += 1; - } else { - wait_msec(10); - cnt -= 1; - } - } - if i != 2 { - println!("SD TIMEOUT FOR SCR[; 2]"); - return; - } - - if (self.scr[0] & SCR_SD_BUS_WIDTH_4) != 0 { - if let Err(_) = self.sd_cmd(CMD_SET_BUS_WIDTH, sd_rca | 2) { - println!("failed to set bus width, {}", sd_rca | 2); - return; - } - let regs = self.regs.get_mut().unwrap(); - regs.control0.write(C0_HCTL_DWITDH); - } - - print!("EMMC: supports "); - - if (self.scr[0] & SCR_SUPP_SET_BLKCNT) != 0 { - print!("SET_BLKCNT "); - } - - if ccs != 0 { - print!("CCS "); - } - - print!("\n"); - - self.scr[0] &= !SCR_SUPP_CCS; - self.scr[0] |= ccs; - } - - pub unsafe fn set_clock(&mut self, freq: u32) -> Result<()> { - let regs = self.regs.get_mut().unwrap(); - - let mut reg_val = regs.status.read() & (SR_CMD_INHIBIT | SR_DAT_INHIBIT); - let mut cnt = 10_0000; - while (cnt > 0) && reg_val != 0 { - wait_msec(1); - cnt -= 1; - reg_val = regs.status.read() & (SR_CMD_INHIBIT | SR_DAT_INHIBIT); - } - - if cnt <= 0 { - println!("ERROR: TIMEOUT WAITING FOR INHIBIT FLAG"); - return Err(Error::new(EINVAL)); - } - - reg_val = regs.control1.read(); - reg_val &= !C1_CLK_EN; - regs.control1.write(reg_val); - wait_msec(10); - - let c = 4166_6666 / freq; - let mut x: u32 = c - 1; - let mut s: u32 = 32; - - if x == 0 { - s = 0; - } else { - if (x & 0xffff_0000) == 0 { - x <<= 16; - s -= 16; - } - if (x & 0xff00_0000) == 0 { - x <<= 8; - s -= 8; - } - if (x & 0xf000_0000) == 0 { - x <<= 4; - s -= 4; - } - if (x & 0xc000_0000) == 0 { - x <<= 2; - s -= 2; - } - if (x & 0x8000_0000) == 0 { - x <<= 1; - s -= 1; - } - if s > 0 { - s -= 1; - } - if s > 7 { - s = 7; - } - } - let mut d; - if self.host_spec_ver > HOST_SPEC_V2 { - d = c; - } else { - d = 1 << s; - } - - if d <= 2 { - d = 2; - s = 0; - } - println!("sd clk divisor: 0x{:08x}, shift: 0x{:08x}", d, s); - - let mut h = 0; - if self.host_spec_ver > HOST_SPEC_V2 { - h = (d & 0x300) >> 2; - } - - d = ((d & 0xff) << 8) | h; - reg_val = regs.control1.read() & 0xffff_003f; - regs.control1.write(reg_val | d); - wait_msec(10); - reg_val = regs.control1.read(); - regs.control1.write(reg_val | C1_CLK_EN); - wait_msec(10); - - reg_val = regs.control1.read() & C1_CLK_STABLE; - cnt = 10000; - while cnt > 0 && reg_val == 0 { - wait_msec(10); - cnt -= 1; - reg_val = regs.control1.read() & C1_CLK_STABLE; - } - - if cnt <= 0 { - println!("ERROR: failed to get stable clock"); - return Err(Error::new(EINVAL)); - } - - Ok(()) - } - - pub unsafe fn sd_cmd(&mut self, mut code: u32, arg: u32) -> Result { - if (code & CMD_NEED_APP) != 0 { - let pre_cmd = CMD_APP_CMD | if self.rca != 0 { CMD_RSPNS_48 } else { 0 }; - match self.sd_cmd(pre_cmd, self.rca) { - Err(_) => { - println!("ERROR: failed to send SD APP command"); - return Err(Error::new(EINVAL)); - } - Ok(_) => { - code &= !CMD_NEED_APP; - } - } - } - - if let Err(_) = self.sd_status(SR_CMD_INHIBIT) { - println!("ERROR: Emmc busy"); - return Err(Error::new(EINVAL)); - } - - //println!("EMMC: Sending command 0x{:08x}, arg 0x{:08x}", code, arg); - - let regs = self.regs.get_mut().unwrap(); - let mut reg_val = regs.interrupt.read(); - regs.interrupt.write(reg_val); - regs.arg1.write(arg); - regs.cmdtm.write(code); - - if code == CMD_SEND_OP_COND { - wait_msec(1000); - } else if code == CMD_SEND_IF_COND || code == CMD_APP_CMD { - wait_msec(200); - } - - if let Err(_) = self.sd_int(INT_CMD_DONE) { - println!("ERROR: failed to send EMMC command"); - return Err(Error::new(EINVAL)); - } - - let regs = self.regs.get_mut().unwrap(); - reg_val = regs.resp0.read(); - - if code == CMD_GO_IDLE || code == CMD_APP_CMD { - return Ok(0); - } else if code == (CMD_APP_CMD | CMD_RSPNS_48) { - return Ok(reg_val & SR_APP_CMD); - } else if code == CMD_SEND_OP_COND { - return Ok(reg_val); - } else if code == CMD_SEND_IF_COND { - if reg_val == arg { - return Ok(0); - } else { - return Err(Error::new(EINVAL)); - } - } else if code == CMD_ALL_SEND_CID { - self.cid[0] = reg_val; - self.cid[1] = regs.resp1.read(); - self.cid[2] = regs.resp2.read(); - self.cid[3] = regs.resp3.read(); - - //FIXME: wrong implement, see CMD_SEND_CSD for detail - return Ok(reg_val); - } else if code == CMD_SEND_CSD { - let tmp0 = reg_val; - let tmp1 = regs.resp1.read(); - let tmp2 = regs.resp2.read(); - let tmp3 = regs.resp3.read(); - - self.csd[0] = tmp3 << 8 | tmp2 >> 24; - self.csd[1] = tmp2 << 8 | tmp1 >> 24; - self.csd[2] = tmp1 << 8 | tmp0 >> 24; - self.csd[3] = tmp0 << 8; - - //FIXME: support variable length of result. - return Ok(reg_val); - } else if code == CMD_SEND_REL_ADDR { - let mut err = reg_val & 0x1fff; - err |= (reg_val & 0x2000) << 6; - err |= (reg_val & 0x4000) << 8; - err |= (reg_val & 0x8000) << 8; - err &= CMD_ERRORS_MASK; - - if err != 0 { - return Err(Error::new(EINVAL)); - } else { - return Ok(reg_val & CMD_RCA_MASK); - } - } else { - return Ok(reg_val & CMD_ERRORS_MASK); - } - } - - pub unsafe fn sd_status(&mut self, mask: u32) -> Result<()> { - let regs = self.regs.get_mut().unwrap(); - let mut cnt = 500000; - - let mut reg_val = regs.status.read() & mask; - let mut reg_val1 = regs.interrupt.read() & INT_ERROR_MASK; - - while cnt > 0 && reg_val != 0 && reg_val1 == 0 { - wait_msec(1); - cnt -= 1; - reg_val = regs.status.read() & mask; - reg_val1 = regs.interrupt.read() & INT_ERROR_MASK; - } - reg_val1 = regs.interrupt.read() & INT_ERROR_MASK; - - if cnt <= 0 || reg_val1 != 0 { - return Err(Error::new(EINVAL)); - } else { - return Ok(()); - } - } - pub unsafe fn sd_int(&mut self, mask: u32) -> Result<()> { - let regs = self.regs.get_mut().unwrap(); - let mut cnt = 100_0000; - let m = mask | INT_ERROR_MASK; - - let mut reg_val = regs.interrupt.read() & m; - - while cnt > 0 && reg_val == 0 { - wait_msec(1); - cnt -= 1; - reg_val = regs.interrupt.read() & m; - } - reg_val = regs.interrupt.read(); - let err = reg_val & (INT_CMD_TIMEOUT | INT_DATA_TIMEOUT | INT_ERROR_MASK); - - if cnt <= 0 || err != 0 { - regs.interrupt.write(reg_val); - return Err(Error::new(EINVAL)); - } else { - regs.interrupt.write(mask); - return Ok(()); - } - } - - pub unsafe fn sd_readblock(&mut self, lba: u32, buf: &mut [u32], num: u32) -> Result { - let num = if num < 1 { 1 } else { num }; - - //println!("sd_readblock lba 0x{:x}, num 0x{:x}", lba, num); - - if let Err(_) = self.sd_status(SR_DAT_INHIBIT) { - println!("SR_DAT_INHIBIT TIMEOUT"); - return Err(Error::new(EINVAL)); - } - - if (self.scr[0] & SCR_SUPP_CCS) != 0 { - if num > 1 && ((self.scr[0] & SCR_SUPP_SET_BLKCNT) != 0) { - if let Err(_) = self.sd_cmd(CMD_SET_BLOCKCNT, num) { - println!("CMD_SET_BLOCKCNT ERROR"); - return Err(Error::new(EINVAL)); - } - } - let regs = self.regs.get_mut().unwrap(); - regs.blksizecnt.write((num) << 16 | 512); - if num == 1 { - self.sd_cmd(CMD_READ_SINGLE, lba).unwrap(); - } else { - self.sd_cmd(CMD_READ_MULTI, lba).unwrap(); - } - } else { - let regs = self.regs.get_mut().unwrap(); - regs.blksizecnt.write(1 << 16 | 512); - } - - let mut cnt = 0; - while cnt < num { - if (self.scr[0] & SCR_SUPP_CCS) == 0 { - self.sd_cmd(CMD_READ_SINGLE, (lba + cnt) * 512).unwrap(); - } - - if let Err(_) = self.sd_int(INT_READ_RDY) { - println!("ERROR: Timeout waiting for ready to read"); - return Err(Error::new(EINVAL)); - } - - let regs = self.regs.get_mut().unwrap(); - regs.blksizecnt.write(1 << 16 | 512); - for d in 0..128 { - buf[(128 * cnt + d) as usize] = regs.data.read(); - } - cnt += 1; - } - - if num > 1 && (self.scr[0] & SCR_SUPP_SET_BLKCNT) == 0 && (self.scr[0] & SCR_SUPP_CCS) != 0 - { - self.sd_cmd(CMD_STOP_TRANS, 0).unwrap(); - } - Ok((num * 512) as usize) - } - - pub unsafe fn sd_writeblock(&mut self, lba: u32, buf: &[u32], num: u32) -> Result { - let num = if num < 1 { 1 } else { num }; - - //println!("sd_writelock lba 0x{:x}, num 0x{:x}", lba, num); - - if let Err(_) = self.sd_status(SR_DAT_INHIBIT | SR_WRITE_AVAILABLE) { - println!("SR_DAT_INHIBIT TIMEOUT"); - return Err(Error::new(EINVAL)); - } - - if (self.scr[0] & SCR_SUPP_CCS) != 0 { - if num > 1 && ((self.scr[0] & SCR_SUPP_SET_BLKCNT) != 0) { - if let Err(_) = self.sd_cmd(CMD_SET_BLOCKCNT, num) { - println!("CMD_SET_BLOCKCNT ERROR"); - return Err(Error::new(EINVAL)); - } - } - let regs = self.regs.get_mut().unwrap(); - regs.blksizecnt.write((num) << 16 | 512); - if num == 1 { - self.sd_cmd(CMD_WRITE_SINGLE, lba).unwrap(); - } else { - self.sd_cmd(CMD_WRITE_MULTI, lba).unwrap(); - } - } else { - let regs = self.regs.get_mut().unwrap(); - regs.blksizecnt.write(1 << 16 | 512); - } - - let mut cnt = 0; - while cnt < num { - if (self.scr[0] & SCR_SUPP_CCS) == 0 { - self.sd_cmd(CMD_WRITE_SINGLE, (lba + cnt) * 512).unwrap(); - } - - if let Err(_) = self.sd_int(INT_WRITE_RDY) { - println!("ERROR: Timeout waiting for ready to write"); - return Err(Error::new(EINVAL)); - } - - let regs = self.regs.get_mut().unwrap(); - regs.blksizecnt.write(1 << 16 | 512); - for d in 0..128 { - regs.data.write(buf[(128 * cnt + d) as usize]); - } - cnt += 1; - } - - if let Err(_) = self.sd_int(INT_DATA_DONE) { - println!("ERROR: Timeout waiting for data done"); - return Err(Error::new(EINVAL)); - } - - if num > 1 && (self.scr[0] & SCR_SUPP_SET_BLKCNT) == 0 && (self.scr[0] & SCR_SUPP_CCS) != 0 - { - self.sd_cmd(CMD_STOP_TRANS, 0).unwrap(); - } - Ok((num * 512) as usize) - } -} - -impl Disk for SdHostCtrl { - fn block_size(&self) -> u32 { - 512 - } - - fn size(&self) -> u64 { - //assert 512MiB - self.size - } - - // TODO: real async? - async fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { - if (buffer.len() % 512) != 0 { - println!("buffer.len {} should be aligned to {}", buffer.len(), 512); - return Err(Error::new(EINVAL)); - } - let u32_len = buffer.len() / core::mem::size_of::(); - let num = buffer.len() / 512; - let u8_ptr = buffer.as_mut_ptr(); - let ret = unsafe { - let u32_buffer = core::slice::from_raw_parts_mut(u8_ptr as *mut u32, u32_len); - self.sd_readblock(block as u32, u32_buffer, num as u32) - }; - match ret { - Ok(cnt) => Ok(cnt), - Err(err) => Err(err), - } - } - - // TODO: real async? - async fn write(&mut self, block: u64, buffer: &[u8]) -> Result { - if (buffer.len() % 512) != 0 { - println!("buffer.len {} should be aligned to {}", buffer.len(), 512); - return Err(Error::new(EINVAL)); - } - let u32_len = buffer.len() / core::mem::size_of::(); - let num = buffer.len() / 512; - let u8_ptr = buffer.as_ptr(); - let ret = unsafe { - let u32_buffer = core::slice::from_raw_parts(u8_ptr as *const u32, u32_len); - self.sd_writeblock(block as u32, u32_buffer, num as u32) - }; - match ret { - Ok(cnt) => Ok(cnt), - Err(err) => Err(err), - } - } -} diff --git a/recipes/core/base/drivers/storage/driver-block/Cargo.toml b/recipes/core/base/drivers/storage/driver-block/Cargo.toml deleted file mode 100644 index ec34dd9cdc..0000000000 --- a/recipes/core/base/drivers/storage/driver-block/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "driver-block" -description = "Shared storage driver code" -version = "0.1.0" -edition = "2021" - -[dependencies] -daemon = { path = "../../../daemon" } -executor = { path = "../../executor" } -partitionlib = { path = "../partitionlib" } - -libredox.workspace = true -log.workspace = true - -# TODO: migrate virtio to our executor -futures = { version = "0.3.28", features = ["executor"] } - -redox_syscall = { workspace = true, features = ["std"] } -redox-scheme.workspace = true -scheme-utils = { path = "../../../scheme-utils" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/storage/driver-block/src/lib.rs b/recipes/core/base/drivers/storage/driver-block/src/lib.rs deleted file mode 100644 index 315aa659d1..0000000000 --- a/recipes/core/base/drivers/storage/driver-block/src/lib.rs +++ /dev/null @@ -1,661 +0,0 @@ -use std::cmp; -use std::future::{Future, IntoFuture}; -use std::io::{self, Read, Seek, SeekFrom}; - -use std::collections::BTreeMap; -use std::convert::TryFrom; -use std::fmt::Write; -use std::str; -use std::task::Poll; - -use executor::LocalExecutor; -use libredox::Fd; -use partitionlib::{LogicalBlockSize, PartitionTable}; -use redox_scheme::scheme::{register_scheme_inner, SchemeAsync, SchemeState}; -use redox_scheme::{CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket}; -use scheme_utils::{FpathWriter, HandleMap}; -use syscall::dirent::DirentBuf; -use syscall::schemev2::NewFdFlags; -use syscall::{ - Error, Result, Stat, EACCES, EAGAIN, EBADF, EINTR, EINVAL, EISDIR, ENOENT, ENOLCK, EOPNOTSUPP, - EOVERFLOW, EWOULDBLOCK, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, -}; - -/// Split the read operation into a series of block reads. -/// `read_fn` will be called with a block number to be read, and a buffer to be filled. -/// `read_fn` must return a full block of data. -/// Result will be the number of bytes read. -fn block_read( - offset: u64, - blksize: u32, - buf: &mut [u8], - mut read_fn: impl FnMut(u64, &mut [u8]) -> io::Result<()>, -) -> io::Result { - // TODO: Yield sometimes, perhaps after a few blocks or something. - - if buf.len() == 0 { - return Ok(0); - } - let to_copy = usize::try_from( - offset.saturating_add(u64::try_from(buf.len()).expect("buf.len() larger than u64")) - - offset, - ) - .expect("bytes to copy larger than usize"); - let mut curr_buf = &mut buf[..to_copy]; - let mut curr_offset = offset; - let blk_size = usize::try_from(blksize).expect("blksize larger than usize"); - let mut total_read = 0; - - let mut block_bytes = [0u8; 4096]; - let block_bytes = &mut block_bytes[..blk_size]; - - while curr_buf.len() > 0 { - // TODO: Async/await? I mean, shouldn't AHCI be async? - - let blk_offset = - usize::try_from(curr_offset % u64::from(blksize)).expect("usize smaller than blksize"); - let to_copy = cmp::min(curr_buf.len(), blk_size - blk_offset); - assert!(blk_offset + to_copy <= blk_size); - - read_fn(curr_offset / u64::from(blksize), block_bytes)?; - - let src_buf = &block_bytes[blk_offset..]; - - curr_buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); - curr_buf = &mut curr_buf[to_copy..]; - curr_offset += u64::try_from(to_copy).expect("bytes to copy larger than u64"); - total_read += to_copy; - } - Ok(total_read) -} - -pub trait Disk { - fn block_size(&self) -> u32; - fn size(&self) -> u64; - - // These operate on a whole multiple of the block size - // FIXME maybe only operate on a single block worth of data? - async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result; - async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result; -} - -impl Disk for Box { - fn block_size(&self) -> u32 { - (**self).block_size() - } - - fn size(&self) -> u64 { - (**self).size() - } - - async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { - (**self).read(block, buffer).await - } - - async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { - (**self).write(block, buffer).await - } -} - -pub struct DiskWrapper { - pub disk: T, - pub pt: Option, -} - -impl DiskWrapper { - pub fn pt(disk: &mut T, executor: &impl ExecutorTrait) -> Option { - let bs = match disk.block_size() { - 512 => LogicalBlockSize::Lb512, - 4096 => LogicalBlockSize::Lb4096, - _ => return None, - }; - struct Device<'a, D: Disk, E: ExecutorTrait> { - disk: &'a mut D, - executor: &'a E, - offset: u64, - } - - impl<'a, D: Disk, E: ExecutorTrait> Seek for Device<'a, D, E> { - fn seek(&mut self, from: SeekFrom) -> io::Result { - let size = i64::try_from(self.disk.size()).or(Err(io::Error::new( - io::ErrorKind::Other, - "Disk larger than 2^63 - 1 bytes", - )))?; - - self.offset = match from { - SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos), - SeekFrom::Current(new_pos) => { - cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64 - } - SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64, - }; - - Ok(self.offset) - } - } - // TODO: Perhaps this impl should be used in the rest of the scheme. - impl<'a, D: Disk, E: ExecutorTrait> Read for Device<'a, D, E> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let blksize = self.disk.block_size(); - let size_in_blocks = self.disk.size() / u64::from(blksize); - - let disk = &mut self.disk; - - let read_block = |block: u64, block_bytes: &mut [u8]| { - if block >= size_in_blocks { - return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); - } - - let bytes = self.executor.block_on(disk.read(block, block_bytes))?; - assert_eq!(bytes, block_bytes.len()); - Ok(()) - }; - let bytes_read = block_read(self.offset, blksize, buf, read_block)?; - - self.offset += bytes_read as u64; - Ok(bytes_read) - } - } - - partitionlib::get_partitions( - &mut Device { - disk, - offset: 0, - executor, - }, - bs, - ) - .ok() - .flatten() - } - - pub fn new(mut disk: T, executor: &impl ExecutorTrait) -> Self { - Self { - pt: Self::pt(&mut disk, executor), - disk, - } - } - - pub fn disk(&self) -> &T { - &self.disk - } - - pub fn disk_mut(&mut self) -> &mut T { - &mut self.disk - } - - pub fn block_size(&self) -> u32 { - self.disk.block_size() - } - - pub fn size(&self) -> u64 { - self.disk.size() - } - - pub async fn read( - &mut self, - part_num: Option, - block: u64, - buf: &mut [u8], - ) -> syscall::Result { - if buf.len() as u64 % u64::from(self.disk.block_size()) != 0 { - return Err(Error::new(EINVAL)); - } - - if let Some(part_num) = part_num { - let part = self - .pt - .as_ref() - .ok_or(syscall::Error::new(EBADF))? - .partitions - .get(part_num) - .ok_or(syscall::Error::new(EBADF))?; - - if block >= part.size { - return Err(syscall::Error::new(EOVERFLOW)); - } - - let abs_block = part.start_lba + block; - - self.disk.read(abs_block, buf).await - } else { - self.disk.read(block, buf).await - } - } - - pub async fn write( - &mut self, - part_num: Option, - block: u64, - buf: &[u8], - ) -> syscall::Result { - if buf.len() as u64 % u64::from(self.disk.block_size()) != 0 { - return Err(Error::new(EINVAL)); - } - - if let Some(part_num) = part_num { - let part = self - .pt - .as_ref() - .ok_or(syscall::Error::new(EBADF))? - .partitions - .get(part_num) - .ok_or(syscall::Error::new(EBADF))?; - - if block >= part.size { - return Err(syscall::Error::new(EOVERFLOW)); - } - - let abs_block = part.start_lba + block; - - self.disk.write(abs_block, buf).await - } else { - self.disk.write(block, buf).await - } - } -} - -pub struct DiskScheme { - inner: DiskSchemeInner, - state: SchemeState, -} - -impl DiskScheme { - pub fn new( - daemon: Option, - scheme_name: String, - disks: BTreeMap, - executor: &impl ExecutorTrait, - ) -> Self { - assert!(scheme_name.starts_with("disk")); - let socket = Socket::nonblock().expect("failed to create disk scheme"); - - let mut inner = DiskSchemeInner { - scheme_name: scheme_name, - socket, - disks: disks - .into_iter() - .map(|(k, disk)| (k, DiskWrapper::new(disk, executor))) - .collect(), - handles: HandleMap::new(), - }; - - let cap_id = inner.scheme_root().expect("failed to get this scheme root"); - register_scheme_inner(&inner.socket, &inner.scheme_name, cap_id) - .expect("failed to register disk scheme root"); - - if let Some(daemon) = daemon { - daemon.ready(); - } - - Self { - inner, - state: SchemeState::new(), - } - } - - pub fn event_handle(&self) -> &Fd { - self.inner.socket.inner() - } - - /// Process pending and new requests. - /// - /// This needs to be called each time there is a new event on the scheme. - pub async fn tick(&mut self) -> io::Result<()> { - // Handle new scheme requests - loop { - let request = match self.inner.socket.next_request(SignalBehavior::Interrupt) { - Ok(Some(request)) => request, - Ok(None) => { - // Scheme likely got unmounted - // TODO: return this to caller instead - std::process::exit(0); - } - Err(error) if error.errno == EWOULDBLOCK || error.errno == EAGAIN => break, - Err(err) if err.errno == EINTR => continue, - Err(err) => return Err(err.into()), - }; - - let response = match request.kind() { - RequestKind::Call(call_request) => { - // TODO: Spawn a separate task for each scheme call. This would however require the - // use of a smarter buffer pool (or direct IO, or a buffer per fd) in order to do - // parallel IO. It might also require async-aware locks so that a close() is - // correctly ordered wrt IO on the same fd. - call_request - .handle_async(&mut self.inner, &mut self.state) - .await - } - RequestKind::SendFd(request) => Response::err(EOPNOTSUPP, request), - RequestKind::RecvFd(request) => Response::err(EOPNOTSUPP, request), - RequestKind::Cancellation(_cancellation_request) => { - // FIXME implement cancellation - continue; - } - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { - unreachable!() - } - RequestKind::OnClose { id } => { - self.inner.on_close(id); - continue; - } - RequestKind::OnDetach { .. } => continue, - }; - self.inner - .socket - .write_response(response, SignalBehavior::Restart)?; - } - - Ok(()) - } -} - -enum Handle { - List(Vec), // entries - Disk(u32), // disk num - Partition(u32, u32), // disk num, part num - SchemeRoot, -} - -struct DiskSchemeInner { - scheme_name: String, - socket: Socket, - disks: BTreeMap>, - handles: HandleMap, -} - -pub trait ExecutorTrait { - fn block_on<'a, O: 'a>(&self, fut: impl IntoFuture + 'a) -> O; -} -impl ExecutorTrait for LocalExecutor { - fn block_on<'a, O: 'a>(&self, fut: impl IntoFuture + 'a) -> O { - LocalExecutor::block_on(self, fut) - } -} -#[deprecated = "use custom executor"] -pub struct FuturesExecutor; - -#[allow(deprecated)] -impl ExecutorTrait for FuturesExecutor { - fn block_on<'a, O: 'a>(&self, fut: impl IntoFuture + 'a) -> O { - futures::executor::block_on(fut.into_future()) - } -} -pub struct TrivialExecutor; -impl ExecutorTrait for TrivialExecutor { - fn block_on<'a, O: 'a>(&self, fut: impl IntoFuture + 'a) -> O { - let mut fut = std::pin::pin!(fut.into_future()); - let mut cx = std::task::Context::from_waker(std::task::Waker::noop()); - loop { - match fut.as_mut().poll(&mut cx) { - Poll::Ready(v) => return v, - Poll::Pending => { - log::warn!("TrivialExecutor: future wasn't trivial"); - continue; - } - } - } - } -} - -impl DiskSchemeInner { - // Checks if any conflicting handles already exist - fn check_locks(&self, disk_i: u32, part_i_opt: Option) -> Result<()> { - for (_, handle) in self.handles.iter() { - match handle { - Handle::Disk(i) => { - if disk_i == *i { - return Err(Error::new(ENOLCK)); - } - } - Handle::Partition(i, p) => { - if disk_i == *i { - match part_i_opt { - Some(part_i) => { - if part_i == *p { - return Err(Error::new(ENOLCK)); - } - } - None => { - return Err(Error::new(ENOLCK)); - } - } - } - } - _ => (), - } - } - Ok(()) - } -} - -impl SchemeAsync for DiskSchemeInner { - fn scheme_root(&mut self) -> Result { - Ok(self.handles.insert(Handle::SchemeRoot)) - } - async fn openat( - &mut self, - dirfd: usize, - path_str: &str, - flags: usize, - _fcntl_flags: u32, - ctx: &CallerCtx, - ) -> Result { - if !matches!(self.handles.get(dirfd)?, Handle::SchemeRoot) { - return Err(Error::new(EACCES)); - } - - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - let path_str = path_str.trim_matches('/'); - - let handle = if path_str.is_empty() { - if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { - let mut list = String::new(); - - for (nsid, disk) in self.disks.iter() { - write!(list, "{}\n", nsid).unwrap(); - - if disk.pt.is_none() { - continue; - } - for part_num in 0..disk.pt.as_ref().unwrap().partitions.len() { - write!(list, "{}p{}\n", nsid, part_num).unwrap(); - } - } - - Handle::List(list.into_bytes()) - } else { - return Err(Error::new(EISDIR)); - } - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let nsid_str = &path_str[..p_pos]; - - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_num_str = &path_str[p_pos + 1..]; - - let nsid = nsid_str.parse::().or(Err(Error::new(ENOENT)))?; - let part_num = part_num_str.parse::().or(Err(Error::new(ENOENT)))?; - - if let Some(disk) = self.disks.get(&nsid) { - if disk - .pt - .as_ref() - .ok_or(Error::new(ENOENT))? - .partitions - .get(part_num as usize) - .is_some() - { - self.check_locks(nsid, Some(part_num))?; - - Handle::Partition(nsid, part_num) - } else { - return Err(Error::new(ENOENT)); - } - } else { - return Err(Error::new(ENOENT)); - } - } else { - let nsid = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if self.disks.contains_key(&nsid) { - self.check_locks(nsid, None)?; - Handle::Disk(nsid) - } else { - return Err(Error::new(ENOENT)); - } - }; - let id = self.handles.insert(handle); - Ok(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - }) - } - async fn getdents<'buf>( - &mut self, - _id: usize, - _buf: DirentBuf<&'buf mut [u8]>, - _opaque_offset: u64, - ) -> Result> { - // TODO - Err(Error::new(EOPNOTSUPP)) - } - - async fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { - match *self.handles.get(id)? { - Handle::List(ref data) => { - stat.st_mode = MODE_DIR; - stat.st_size = data.len() as u64; - Ok(()) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_blocks = disk.disk().size() / u64::from(disk.block_size()); - stat.st_blksize = disk.block_size(); - stat.st_size = disk.size(); - Ok(()) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_size = part.size * u64::from(disk.block_size()); - stat.st_blocks = part.size; - stat.st_blksize = disk.block_size(); - Ok(()) - } - Handle::SchemeRoot => Err(Error::new(EBADF)), - } - } - - async fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with_legacy(buf, &self.scheme_name, |w| { - match *self.handles.get(id)? { - Handle::List(_) => (), - Handle::Disk(number) => { - write!(w, "{number}").unwrap(); - } - Handle::Partition(disk_num, part_num) => { - write!(w, "{disk_num}p{part_num}").unwrap(); - } - Handle::SchemeRoot => return Err(Error::new(EBADF)), - } - Ok(()) - }) - } - - async fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - match *self.handles.get_mut(id)? { - Handle::List(ref handle) => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| handle.get(o..)) - .unwrap_or(&[]); - let count = core::cmp::min(src.len(), buf.len()); - buf[..count].copy_from_slice(&src[..count]); - Ok(count) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(None, block, buf).await - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(Some(part_num as usize), block, buf).await - } - Handle::SchemeRoot => Err(Error::new(EBADF)), - } - } - - async fn write( - &mut self, - id: usize, - buf: &[u8], - offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - match *self.handles.get_mut(id)? { - Handle::List(_) => Err(Error::new(EBADF)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(None, block, buf).await - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(Some(part_num as usize), block, buf).await - } - Handle::SchemeRoot => Err(Error::new(EBADF)), - } - } - - async fn fsize(&mut self, id: usize, _ctx: &CallerCtx) -> Result { - Ok(match *self.handles.get_mut(id)? { - Handle::List(ref handle) => handle.len() as u64, - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - disk.size() - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - - part.size * u64::from(disk.block_size()) - } - Handle::SchemeRoot => return Err(Error::new(EBADF)), - }) - } -} - -impl DiskSchemeInner { - pub fn on_close(&mut self, id: usize) { - let _ = self.handles.remove(id); - } -} diff --git a/recipes/core/base/drivers/storage/ided/.gitignore b/recipes/core/base/drivers/storage/ided/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/recipes/core/base/drivers/storage/ided/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/recipes/core/base/drivers/storage/ided/Cargo.toml b/recipes/core/base/drivers/storage/ided/Cargo.toml deleted file mode 100644 index addcfafd8f..0000000000 --- a/recipes/core/base/drivers/storage/ided/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "ided" -description = "PATA (IDE) driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -common = { path = "../../common" } -driver-block = { path = "../driver-block" } -libredox.workspace = true -log.workspace = true -pcid = { path = "../../pcid" } -daemon = { path = "../../../daemon" } -redox_syscall = { workspace = true, features = ["std"] } -redox_event.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/storage/ided/src/ide.rs b/recipes/core/base/drivers/storage/ided/src/ide.rs deleted file mode 100644 index 5faf3250d4..0000000000 --- a/recipes/core/base/drivers/storage/ided/src/ide.rs +++ /dev/null @@ -1,469 +0,0 @@ -use std::{ - convert::TryInto, - sync::{Arc, Mutex}, - thread, - time::{Duration, Instant}, -}; - -use driver_block::Disk; -use syscall::error::{Error, Result, EIO}; - -use common::dma::Dma; -use common::io::{Io, Pio, ReadOnly, WriteOnly}; - -const TIMEOUT: Duration = Duration::new(5, 0); - -#[repr(u8)] -pub enum AtaCommand { - ReadPio = 0x20, - ReadPioExt = 0x24, - ReadDma = 0xC8, - ReadDmaExt = 0x25, - WritePio = 0x30, - WritePioExt = 0x34, - WriteDma = 0xCA, - WriteDmaExt = 0x35, - CacheFlush = 0xE7, - CacheFlushExt = 0xEA, - Packet = 0xA0, - IdentifyPacket = 0xA1, - Identify = 0xEC, -} - -#[repr(C, packed)] -struct PrdtEntry { - phys: u32, - size: u16, - flags: u16, -} - -pub struct Channel { - pub data8: Pio, - pub data32: Pio, - pub error: ReadOnly>, - pub features: WriteOnly>, - pub sector_count: Pio, - pub lba_0: Pio, - pub lba_1: Pio, - pub lba_2: Pio, - pub device_select: Pio, - pub status: ReadOnly>, - pub command: WriteOnly>, - pub alt_status: ReadOnly>, - pub control: WriteOnly>, - pub busmaster_command: Pio, - pub busmaster_status: Pio, - pub busmaster_prdt: Pio, - prdt: Dma<[PrdtEntry; 128]>, - buf: Dma<[u8; 128 * 512]>, -} - -impl Channel { - pub fn new(base: u16, control_base: u16, busmaster_base: u16) -> Result { - Ok(Self { - data8: Pio::new(base + 0), - data32: Pio::new(base + 0), - error: ReadOnly::new(Pio::new(base + 1)), - features: WriteOnly::new(Pio::new(base + 1)), - sector_count: Pio::new(base + 2), - lba_0: Pio::new(base + 3), - lba_1: Pio::new(base + 4), - lba_2: Pio::new(base + 5), - device_select: Pio::new(base + 6), - status: ReadOnly::new(Pio::new(base + 7)), - command: WriteOnly::new(Pio::new(base + 7)), - alt_status: ReadOnly::new(Pio::new(control_base)), - control: WriteOnly::new(Pio::new(control_base)), - busmaster_command: Pio::new(busmaster_base), - busmaster_status: Pio::new(busmaster_base + 2), - busmaster_prdt: Pio::new(busmaster_base + 4), - prdt: unsafe { - Dma::zeroed( - //TODO: PhysBox::new_in_32bit_space(4096)? - )? - .assume_init() - }, - buf: unsafe { - Dma::zeroed( - //TODO: PhysBox::new_in_32bit_space(16 * 4096)? - )? - .assume_init() - }, - }) - } - - pub fn primary_compat(busmaster_base: u16) -> Result { - Self::new(0x1F0, 0x3F6, busmaster_base) - } - - pub fn secondary_compat(busmaster_base: u16) -> Result { - Self::new(0x170, 0x376, busmaster_base) - } - - fn check_status(&mut self) -> Result { - let status = self.status.read(); - - if status & 0x01 != 0 { - log::error!("IDE error: {:#x}", self.error.read()); - return Err(Error::new(EIO)); - } - - if status & 0x20 != 0 { - log::error!("IDE device write fault"); - return Err(Error::new(EIO)); - } - - Ok(status) - } - - fn polling(&mut self, read: bool, line: u32) -> Result<()> { - /* - #define ATA_SR_BSY 0x80 // Busy - #define ATA_SR_DRDY 0x40 // Drive ready - #define ATA_SR_DF 0x20 // Drive write fault - #define ATA_SR_DSC 0x10 // Drive seek complete - #define ATA_SR_DRQ 0x08 // Data request ready - #define ATA_SR_CORR 0x04 // Corrected data - #define ATA_SR_IDX 0x02 // Index - #define ATA_SR_ERR 0x01 // Error - */ - - for _ in 0..4 { - // Doing this 4 times creates a 400ns delay - self.alt_status.read(); - } - - let start = Instant::now(); - loop { - let status = self.check_status()?; - if status & 0x80 == 0 { - if read && status & 0x08 == 0 { - log::error!("IDE read data not ready"); - return Err(Error::new(EIO)); - } - break; - } - if start.elapsed() >= TIMEOUT { - log::error!( - "line {} polling {} timeout with status 0x{:02X}", - line, - if read { "read" } else { "write" }, - status - ); - return Err(Error::new(EIO)); - } - thread::yield_now(); - } - - Ok(()) - } -} - -pub struct AtaDisk { - pub chan: Arc>, - pub chan_i: usize, - pub dev: u8, - pub size: u64, - pub dma: bool, - pub lba_48: bool, -} - -impl Disk for AtaDisk { - fn block_size(&self) -> u32 { - 512 - } - - fn size(&self) -> u64 { - self.size - } - - // NOTE: not async - async fn read(&mut self, start_block: u64, buffer: &mut [u8]) -> Result { - let mut count = 0; - for chunk in buffer.chunks_mut(65536) { - let block = start_block + (count as u64) / 512; - - //TODO: support other LBA modes - assert!(block < 0x1_0000_0000_0000); - - let sectors = (chunk.len() + 511) / 512; - assert!(sectors <= 128); - - log::trace!( - "IDE read chan {} dev {} block {:#x} count {:#x}", - self.chan_i, - self.dev, - block, - sectors - ); - - let mut chan = self.chan.lock().unwrap(); - - if self.dma { - // Stop bus master - chan.busmaster_command.writef(1, false); - // Make PRDT EOT match chunk size - for i in 0..sectors { - chan.prdt[i] = PrdtEntry { - phys: (chan.buf.physical() + i * 512).try_into().unwrap(), - size: 512, - flags: if i + 1 == sectors { - 1 << 15 // End of table - } else { - 0 - }, - }; - } - // Set PRDT - let prdt = chan.prdt.physical(); - chan.busmaster_prdt.write(prdt.try_into().unwrap()); - // Set to read - chan.busmaster_command.writef(1 << 3, true); - // Clear interrupt and error bits - chan.busmaster_status.write(0b110); - } - - // Select drive - //TODO: upper part of LBA 28 - chan.device_select.write(0xE0 | (self.dev << 4)); - - if self.lba_48 { - // Set high sector count and LBA - chan.control.write(0x80); - chan.sector_count.write((sectors >> 8) as u8); - chan.lba_0.write((block >> 24) as u8); - chan.lba_1.write((block >> 32) as u8); - chan.lba_2.write((block >> 40) as u8); - chan.control.write(0x00); - } - - // Set low sector count and LBA - chan.sector_count.write(sectors as u8); - chan.lba_0.write(block as u8); - chan.lba_1.write((block >> 8) as u8); - chan.lba_2.write((block >> 16) as u8); - - // Send command - chan.command.write(if self.dma { - if self.lba_48 { - AtaCommand::ReadDmaExt as u8 - } else { - AtaCommand::ReadDma as u8 - } - } else { - if self.lba_48 { - AtaCommand::ReadPioExt as u8 - } else { - AtaCommand::ReadPio as u8 - } - }); - - // Read data - if self.dma { - // Start bus master - chan.busmaster_command.writef(1, true); - - // Wait for transaction to finish - chan.polling(false, line!())?; - - // Wait for bus master to finish - let start = Instant::now(); - let error = loop { - let status = chan.busmaster_status.read(); - if status & 1 << 1 != 0 { - // Break with error status - break true; - } - if status & 1 == 0 { - // Break when not busy and no error - break false; - } - if start.elapsed() >= TIMEOUT { - log::error!("busmaster read timeout with status 0x{:02X}", status); - return Err(Error::new(EIO)); - } - thread::yield_now(); - }; - - // Stop bus master - chan.busmaster_command.writef(1, false); - - // Clear bus master error and interrupt - chan.busmaster_status.write(0b110); - - if error { - log::error!("IDE bus master error"); - return Err(Error::new(EIO)); - } - - // Read buffer - chunk.copy_from_slice(&chan.buf[..chunk.len()]); - } else { - for sector in 0..sectors { - chan.polling(true, line!())?; - - for i in 0..128 { - let data = chan.data32.read(); - chunk[sector * 512 + i * 4 + 0] = (data >> 0) as u8; - chunk[sector * 512 + i * 4 + 1] = (data >> 8) as u8; - chunk[sector * 512 + i * 4 + 2] = (data >> 16) as u8; - chunk[sector * 512 + i * 4 + 3] = (data >> 24) as u8; - } - } - } - - count += chunk.len(); - } - - Ok(count) - } - - // NOTE: not async - async fn write(&mut self, start_block: u64, buffer: &[u8]) -> Result { - let mut count = 0; - for chunk in buffer.chunks(65536) { - let block = start_block + (count as u64) / 512; - - //TODO: support other LBA modes - assert!(block < 0x1_0000_0000_0000); - - let sectors = (chunk.len() + 511) / 512; - assert!(sectors <= 128); - - log::trace!( - "IDE write chan {} dev {} block {:#x} count {:#x}", - self.chan_i, - self.dev, - block, - sectors - ); - - let mut chan = self.chan.lock().unwrap(); - - if self.dma { - // Stop bus master - chan.busmaster_command.writef(1, false); - // Make PRDT EOT match chunk size - for i in 0..sectors { - chan.prdt[i] = PrdtEntry { - phys: (chan.buf.physical() + i * 512).try_into().unwrap(), - size: 512, - flags: if i + 1 == sectors { - 1 << 15 // End of table - } else { - 0 - }, - }; - } - // Set PRDT - let prdt = chan.prdt.physical(); - chan.busmaster_prdt.write(prdt.try_into().unwrap()); - // Set to write - chan.busmaster_command.writef(1 << 3, false); - // Clear interrupt and error bits - chan.busmaster_status.write(0b110); - - // Write buffer - chan.buf[..chunk.len()].copy_from_slice(chunk); - } - - // Select drive - //TODO: upper part of LBA 28 - chan.device_select.write(0xE0 | (self.dev << 4)); - - if self.lba_48 { - // Set high sector count and LBA - chan.control.write(0x80); - chan.sector_count.write((sectors >> 8) as u8); - chan.lba_0.write((block >> 24) as u8); - chan.lba_1.write((block >> 32) as u8); - chan.lba_2.write((block >> 40) as u8); - chan.control.write(0x00); - } - - // Set low sector count and LBA - chan.sector_count.write(sectors as u8); - chan.lba_0.write(block as u8); - chan.lba_1.write((block >> 8) as u8); - chan.lba_2.write((block >> 16) as u8); - - // Send command - chan.command.write(if self.dma { - if self.lba_48 { - AtaCommand::WriteDmaExt as u8 - } else { - AtaCommand::WriteDma as u8 - } - } else { - if self.lba_48 { - AtaCommand::WritePioExt as u8 - } else { - AtaCommand::WritePio as u8 - } - }); - - // Write data - if self.dma { - // Start bus master - chan.busmaster_command.writef(1, true); - - // Wait for transaction to finish - chan.polling(false, line!())?; - - // Wait for bus master to finish - let start = Instant::now(); - let error = loop { - let status = chan.busmaster_status.read(); - if status & 1 << 1 != 0 { - // Break with error status - break true; - } - if status & 1 == 0 { - // Break when not busy and no error - break false; - } - if start.elapsed() >= TIMEOUT { - log::error!("busmaster write timeout with status 0x{:02X}", status); - return Err(Error::new(EIO)); - } - thread::yield_now(); - }; - - // Stop bus master - chan.busmaster_command.writef(1, false); - - // Clear bus master error and interrupt - chan.busmaster_status.write(0b110); - - if error { - log::error!("IDE bus master error"); - return Err(Error::new(EIO)); - } - } else { - for sector in 0..sectors { - chan.polling(false, line!())?; - - for i in 0..128 { - chan.data32.write( - ((chunk[sector * 512 + i * 4 + 0] as u32) << 0) - | ((chunk[sector * 512 + i * 4 + 1] as u32) << 8) - | ((chunk[sector * 512 + i * 4 + 2] as u32) << 16) - | ((chunk[sector * 512 + i * 4 + 3] as u32) << 24), - ); - } - } - } - - chan.command.write(if self.lba_48 { - AtaCommand::CacheFlushExt as u8 - } else { - AtaCommand::CacheFlush as u8 - }); - chan.polling(false, line!())?; - - count += chunk.len(); - } - - Ok(count) - } -} diff --git a/recipes/core/base/drivers/storage/ided/src/main.rs b/recipes/core/base/drivers/storage/ided/src/main.rs deleted file mode 100644 index 4197217dcd..0000000000 --- a/recipes/core/base/drivers/storage/ided/src/main.rs +++ /dev/null @@ -1,304 +0,0 @@ -use common::io::Io as _; -use driver_block::{Disk, DiskScheme, ExecutorTrait, FuturesExecutor}; -use event::{EventFlags, RawEventQueue}; -use libredox::flag; -use log::{error, info}; -use pcid_interface::PciFunctionHandle; -use std::{ - fs::File, - io::{Read, Write}, - os::unix::io::{FromRawFd, RawFd}, - sync::{Arc, Mutex}, - thread::{self, sleep}, - time::Duration, -}; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use crate::ide::{AtaCommand, AtaDisk, Channel}; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub mod ide; - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! { - let pci_config = pcid_handle.config(); - - let mut name = pci_config.func.name(); - name.push_str("_ide"); - - common::setup_logging( - "disk", - "pci", - &name, - common::output_level(), - common::file_level(), - ); - - info!("IDE PCI CONFIG: {:?}", pci_config); - - // Get controller DMA capable - let dma = pci_config.func.full_device_id.interface & 0x80 != 0; - - let busmaster_base = pci_config.func.bars[4].expect_port(); - let (primary, primary_irq) = if pci_config.func.full_device_id.interface & 1 != 0 { - panic!("TODO: IDE primary channel is PCI native"); - } else { - (Channel::primary_compat(busmaster_base).unwrap(), 14) - }; - let (secondary, secondary_irq) = if pci_config.func.full_device_id.interface & 1 != 0 { - panic!("TODO: IDE secondary channel is PCI native"); - } else { - (Channel::secondary_compat(busmaster_base + 8).unwrap(), 15) - }; - - common::acquire_port_io_rights().expect("ided: failed to get I/O privilege"); - - //TODO: move this to ide.rs? - let chans = vec![ - Arc::new(Mutex::new(primary)), - Arc::new(Mutex::new(secondary)), - ]; - enum AnyDisk { - Ata(AtaDisk), - } - impl Disk for AnyDisk { - fn block_size(&self) -> u32 { - let AnyDisk::Ata(a) = self; - a.block_size() - } - fn size(&self) -> u64 { - let AnyDisk::Ata(a) = self; - a.size() - } - async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { - let AnyDisk::Ata(a) = self; - a.write(block, buffer).await - } - async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { - let AnyDisk::Ata(a) = self; - a.read(block, buffer).await - } - } - let mut disks: Vec = Vec::new(); - for (chan_i, chan_lock) in chans.iter().enumerate() { - let mut chan = chan_lock.lock().unwrap(); - - println!(" - channel {}", chan_i); - - // Disable IRQs - chan.control.write(2); - - for dev in 0..=1 { - println!(" - device {}", dev); - - // Select device - chan.device_select.write(0xA0 | (dev << 4)); - sleep(Duration::from_millis(1)); - - // ATA identify command - chan.command.write(AtaCommand::Identify as u8); - sleep(Duration::from_millis(1)); - - // Check if device exists - if chan.status.read() == 0 { - println!(" not found"); - continue; - } - - // Poll for status - let error = loop { - let status = chan.status.read(); - if status & 1 != 0 { - // Error - break true; - } - if status & 0x80 == 0 && status & 0x08 != 0 { - // Not busy and data ready - break false; - } - thread::yield_now(); - }; - - //TODO: probe ATAPI - if error { - println!(" error"); - continue; - } - - // Read and print identity - { - let mut dest = [0u16; 256]; - for chunk in dest.chunks_mut(2) { - let data = chan.data32.read(); - chunk[0] = data as u16; - chunk[1] = (data >> 16) as u16; - } - - let mut serial = String::new(); - for word in 10..20 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - serial.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - serial.push(b); - } - } - - let mut firmware = String::new(); - for word in 23..27 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - firmware.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - firmware.push(b); - } - } - - let mut model = String::new(); - for word in 27..47 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - model.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - model.push(b); - } - } - - let mut sectors = (dest[100] as u64) - | ((dest[101] as u64) << 16) - | ((dest[102] as u64) << 32) - | ((dest[103] as u64) << 48); - - let lba_bits = if sectors == 0 { - sectors = (dest[60] as u64) | ((dest[61] as u64) << 16); - 28 - } else { - 48 - }; - - println!(" Serial: {}", serial.trim()); - println!(" Firmware: {}", firmware.trim()); - println!(" Model: {}", model.trim()); - println!(" Size: {} MB", sectors / 2048); - println!(" DMA: {}", dma); - println!(" {}-bit LBA", lba_bits); - - disks.push(AnyDisk::Ata(AtaDisk { - chan: chan_lock.clone(), - chan_i, - dev, - size: sectors * 512, - dma, - lba_48: lba_bits == 48, - })); - } - } - } - - let scheme_name = format!("disk.{}", name); - let mut scheme = DiskScheme::new( - Some(daemon), - scheme_name, - disks - .into_iter() - .enumerate() - .map(|(i, disk)| (i as u32, disk)) - .collect(), - // TODO: Should ided just use TrivialExecutor or would it be valuable to actually use a - // real executor? - &FuturesExecutor, - ); - - let primary_irq_fd = libredox::call::open( - &format!("/scheme/irq/{}", primary_irq), - flag::O_RDWR | flag::O_NONBLOCK, - 0, - ) - .expect("ided: failed to open irq file"); - let mut primary_irq_file = unsafe { File::from_raw_fd(primary_irq_fd as RawFd) }; - - let secondary_irq_fd = libredox::call::open( - &format!("/scheme/irq/{}", secondary_irq), - flag::O_RDWR | flag::O_NONBLOCK, - 0, - ) - .expect("ided: failed to open irq file"); - let mut secondary_irq_file = unsafe { File::from_raw_fd(secondary_irq_fd as RawFd) }; - - let event_queue = RawEventQueue::new().expect("ided: failed to open event file"); - - libredox::call::setrens(0, 0).expect("ided: failed to enter null namespace"); - - event_queue - .subscribe(scheme.event_handle().raw(), 0, EventFlags::READ) - .expect("ided: failed to event disk scheme"); - - event_queue - .subscribe(primary_irq_fd, 0, EventFlags::READ) - .expect("ided: failed to event irq scheme"); - - event_queue - .subscribe(secondary_irq_fd, 0, EventFlags::READ) - .expect("ided: failed to event irq scheme"); - - for event in event_queue { - let event = event.unwrap(); - if event.fd == scheme.event_handle().raw() { - FuturesExecutor.block_on(scheme.tick()).unwrap(); - } else if event.fd == primary_irq_fd { - let mut irq = [0; 8]; - if primary_irq_file - .read(&mut irq) - .expect("ided: failed to read irq file") - >= irq.len() - { - let _chan = chans[0].lock().unwrap(); - //TODO: check chan for irq - - primary_irq_file - .write(&irq) - .expect("ided: failed to write irq file"); - - FuturesExecutor.block_on(scheme.tick()).unwrap(); - } - } else if event.fd == secondary_irq_fd { - let mut irq = [0; 8]; - if secondary_irq_file - .read(&mut irq) - .expect("ided: failed to read irq file") - >= irq.len() - { - let _chan = chans[1].lock().unwrap(); - //TODO: check chan for irq - - secondary_irq_file - .write(&irq) - .expect("ided: failed to write irq file"); - - FuturesExecutor.block_on(scheme.tick()).unwrap(); - } - } else { - error!("Unknown event {}", event.fd); - } - } - - std::process::exit(0); -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! { - unimplemented!() -} diff --git a/recipes/core/base/drivers/storage/lived/Cargo.toml b/recipes/core/base/drivers/storage/lived/Cargo.toml deleted file mode 100644 index 72ccae96c4..0000000000 --- a/recipes/core/base/drivers/storage/lived/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "lived" -description = "Live disk daemon" -authors = ["4lDO2 <4lDO2@protonmail.com>"] -version = "0.1.0" -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -anyhow.workspace = true -libredox.workspace = true -daemon = { path = "../../../daemon" } -redox_syscall = { workspace = true, features = ["std"] } -redox_event.workspace = true -driver-block = { path = "../driver-block" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/storage/lived/src/main.rs b/recipes/core/base/drivers/storage/lived/src/main.rs deleted file mode 100644 index 2ca1ff27e5..0000000000 --- a/recipes/core/base/drivers/storage/lived/src/main.rs +++ /dev/null @@ -1,177 +0,0 @@ -//! Disk scheme replacement when making live disk - -#![feature(int_roundings)] - -use std::collections::{BTreeMap, HashMap}; -use std::fs::File; - -use std::os::fd::AsRawFd; - -use driver_block::{Disk, DiskScheme}; -use driver_block::{ExecutorTrait, TrivialExecutor}; -use libredox::call::MmapArgs; -use libredox::flag; - -use syscall::error::*; -use syscall::PAGE_SIZE; - -use anyhow::{anyhow, Context}; - -struct LiveDisk { - original: &'static [u8], - //TODO: drop overlay blocks if they match the original - overlay: HashMap>, -} - -impl LiveDisk { - fn new(phys: usize, size: usize) -> anyhow::Result { - let start = phys.div_floor(PAGE_SIZE) * PAGE_SIZE; - let end = phys - .checked_add(size) - .context("phys + size overflow")? - .next_multiple_of(PAGE_SIZE); - let size = end - start; - - let original = unsafe { - let file = File::open("/scheme/memory/physical")?; - let base = libredox::call::mmap(MmapArgs { - fd: file.as_raw_fd() as usize, - addr: core::ptr::null_mut(), - offset: start as u64, - length: size, - prot: flag::PROT_READ, - flags: flag::MAP_SHARED, - }) - .map_err(|err| anyhow!("failed to mmap livedisk: {}", err))?; - - std::slice::from_raw_parts_mut(base as *mut u8, size) - }; - - Ok(LiveDisk { - original, - overlay: HashMap::new(), - }) - } -} - -impl Disk for LiveDisk { - fn block_size(&self) -> u32 { - PAGE_SIZE as u32 - } - - fn size(&self) -> u64 { - self.original.len() as u64 - } - - async fn read(&mut self, mut block: u64, buffer: &mut [u8]) -> syscall::Result { - let mut offset = (block as usize) * PAGE_SIZE; - if offset + buffer.len() > self.original.len() { - return Err(syscall::Error::new(EINVAL)); - } - for chunk in buffer.chunks_mut(PAGE_SIZE) { - match self.overlay.get(&block) { - Some(overlay) => { - chunk.copy_from_slice(&overlay[..chunk.len()]); - } - None => { - chunk.copy_from_slice(&self.original[offset..offset + chunk.len()]); - } - } - block += 1; - offset += PAGE_SIZE; - } - Ok(buffer.len()) - } - - async fn write(&mut self, mut block: u64, buffer: &[u8]) -> syscall::Result { - let mut offset = (block as usize) * PAGE_SIZE; - if offset + buffer.len() > self.original.len() { - return Err(syscall::Error::new(EINVAL)); - } - for chunk in buffer.chunks(PAGE_SIZE) { - self.overlay.entry(block).or_insert_with(|| { - let offset = (block as usize) * PAGE_SIZE; - self.original[offset..offset + PAGE_SIZE] - .to_vec() - .into_boxed_slice() - })[..chunk.len()] - .copy_from_slice(chunk); - block += 1; - offset += PAGE_SIZE; - } - Ok(buffer.len()) - } -} - -fn main() { - daemon::Daemon::new(daemon); -} - -fn daemon(daemon: daemon::Daemon) -> ! { - let mut phys = 0; - let mut size = 0; - - // TODO: handle error - for line in std::fs::read_to_string("/scheme/sys/env") - .context("failed to read env") - .unwrap() - .lines() - { - let mut parts = line.splitn(2, '='); - let name = parts.next().unwrap_or(""); - let value = parts.next().unwrap_or(""); - - if name == "DISK_LIVE_ADDR" { - phys = usize::from_str_radix(value, 16).unwrap_or(0); - } - - if name == "DISK_LIVE_SIZE" { - size = usize::from_str_radix(value, 16).unwrap_or(0); - } - } - - if phys == 0 || size == 0 { - // No live disk data, no need to say anything or exit with - daemon.ready(); - std::process::exit(0); - } - - let event_queue = event::EventQueue::new().unwrap(); - - event::user_data! { - enum Event { - Scheme, - } - }; - - let mut scheme = DiskScheme::new( - Some(daemon), - "disk.live".to_owned(), - BTreeMap::from([( - 0, - LiveDisk::new(phys, size).unwrap_or_else(|err| { - eprintln!("failed to initialize livedisk scheme: {}", err); - std::process::exit(1) - }), - )]), - &TrivialExecutor, - ); - - libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - - event_queue - .subscribe( - scheme.event_handle().raw(), - Event::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - - for event in event_queue { - match event.unwrap().user_data { - Event::Scheme => TrivialExecutor.block_on(scheme.tick()).unwrap(), - } - } - - std::process::exit(0); -} diff --git a/recipes/core/base/drivers/storage/nvmed/.gitignore b/recipes/core/base/drivers/storage/nvmed/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/recipes/core/base/drivers/storage/nvmed/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/recipes/core/base/drivers/storage/nvmed/Cargo.toml b/recipes/core/base/drivers/storage/nvmed/Cargo.toml deleted file mode 100644 index 69e8438133..0000000000 --- a/recipes/core/base/drivers/storage/nvmed/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -name = "nvmed" -description = "NVM Express (NVMe) driver" -version = "0.1.0" -edition = "2021" - -[dependencies] -bitflags.workspace = true -futures = "0.3" -libredox.workspace = true -log.workspace = true -parking_lot.workspace = true -redox_event.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -smallvec.workspace = true - -executor = { path = "../../executor" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-block = { path = "../driver-block" } -partitionlib = { path = "../partitionlib" } -pcid = { path = "../../pcid" } - -[features] -default = [] - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/storage/nvmed/src/main.rs b/recipes/core/base/drivers/storage/nvmed/src/main.rs deleted file mode 100644 index beb1b68940..0000000000 --- a/recipes/core/base/drivers/storage/nvmed/src/main.rs +++ /dev/null @@ -1,154 +0,0 @@ -use std::cell::RefCell; -use std::fs::File; -use std::io::{self, Read, Write}; -use std::os::fd::AsRawFd; -use std::rc::Rc; -use std::sync::Arc; -use std::usize; - -use driver_block::{Disk, DiskScheme}; -use pcid_interface::{irq_helpers, PciFunctionHandle}; - -use crate::nvme::NvmeNamespace; - -use self::nvme::Nvme; - -mod nvme; - -struct NvmeDisk { - nvme: Arc, - ns: NvmeNamespace, -} - -impl Disk for NvmeDisk { - fn block_size(&self) -> u32 { - self.ns.block_size.try_into().unwrap() - } - - fn size(&self) -> u64 { - self.ns.blocks * self.ns.block_size - } - - async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { - self.nvme.namespace_read(&self.ns, block, buffer).await - } - - async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { - self.nvme.namespace_write(&self.ns, block, buffer).await - } -} - -fn time_arm(time_handle: &mut File, secs: i64) -> io::Result<()> { - let mut time_buf = [0_u8; core::mem::size_of::()]; - if time_handle.read(&mut time_buf)? < time_buf.len() { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "time read too small", - )); - } - - match libredox::data::timespec_from_mut_bytes(&mut time_buf) { - time => { - time.tv_sec += secs; - } - } - time_handle.write(&time_buf)?; - Ok(()) -} - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - let pci_config = pcid_handle.config(); - - let scheme_name = format!("disk.{}-nvme", pci_config.func.name()); - - common::setup_logging( - "disk", - "pci", - &scheme_name, - common::output_level(), - common::file_level(), - ); - - log::debug!("NVME PCI CONFIG: {:?}", pci_config); - - let address = unsafe { pcid_handle.map_bar(0).ptr }; - - let interrupt_vector = irq_helpers::pci_allocate_interrupt_vector(&mut pcid_handle, "nvmed"); - let iv = interrupt_vector.vector(); - let irq_handle = interrupt_vector.irq_handle().try_clone().unwrap(); - - let mut nvme = Nvme::new(address.as_ptr() as usize, interrupt_vector, pcid_handle) - .expect("nvmed: failed to allocate driver data"); - - unsafe { nvme.init().expect("nvmed: failed to init") } - log::debug!("Finished base initialization"); - let nvme = Arc::new(nvme); - - let executor = nvme::executor::init(Arc::clone(&nvme), iv, false /* FIXME */, irq_handle); - - let mut time_handle = File::open(&format!("/scheme/time/{}", libredox::flag::CLOCK_MONOTONIC)) - .expect("failed to open time handle"); - - let mut time_events = Box::pin( - executor.register_external_event(time_handle.as_raw_fd() as usize, event::EventFlags::READ), - ); - - // Try to init namespaces for 5 seconds - time_arm(&mut time_handle, 5).expect("failed to arm timer"); - let namespaces = executor.block_on(async { - let namespaces_future = nvme.init_with_queues(); - let time_future = time_events.as_mut().next(); - futures::pin_mut!(namespaces_future); - futures::pin_mut!(time_future); - match futures::future::select(namespaces_future, time_future).await { - futures::future::Either::Left((namespaces, _)) => namespaces, - futures::future::Either::Right(_) => panic!("timeout on init"), - } - }); - log::debug!("Initialized!"); - - let scheme = Rc::new(RefCell::new(DiskScheme::new( - Some(daemon), - scheme_name, - namespaces - .into_iter() - .map(|(k, ns)| { - ( - k, - NvmeDisk { - nvme: nvme.clone(), - ns, - }, - ) - }) - .collect(), - &*executor, - ))); - - let mut scheme_events = Box::pin(executor.register_external_event( - scheme.borrow().event_handle().raw(), - event::EventFlags::READ, - )); - - libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - - log::debug!("Starting to listen for scheme events"); - - executor.block_on(async { - loop { - log::trace!("new event iteration"); - if let Err(err) = scheme.borrow_mut().tick().await { - log::error!("scheme error: {err}"); - } - let _ = scheme_events.as_mut().next().await; - } - }); - - //TODO: destroy NVMe stuff - - std::process::exit(0); -} diff --git a/recipes/core/base/drivers/storage/nvmed/src/nvme/cmd.rs b/recipes/core/base/drivers/storage/nvmed/src/nvme/cmd.rs deleted file mode 100644 index b3567d9923..0000000000 --- a/recipes/core/base/drivers/storage/nvmed/src/nvme/cmd.rs +++ /dev/null @@ -1,162 +0,0 @@ -use super::NvmeCmd; - -impl NvmeCmd { - pub fn create_io_completion_queue( - cid: u16, - qid: u16, - ptr: usize, - size: u16, - iv: Option, - ) -> Self { - const DW11_PHYSICALLY_CONTIGUOUS_BIT: u32 = 0x0000_0001; - const DW11_ENABLE_INTERRUPTS_BIT: u32 = 0x0000_0002; - const DW11_INTERRUPT_VECTOR_SHIFT: u8 = 16; - - Self { - opcode: 5, - flags: 0, - cid, - nsid: 0, - _rsvd: 0, - mptr: 0, - dptr: [ptr as u64, 0], - cdw10: ((size as u32) << 16) | (qid as u32), - - cdw11: DW11_PHYSICALLY_CONTIGUOUS_BIT - | if let Some(iv) = iv { - // enable interrupts if a vector is present - DW11_ENABLE_INTERRUPTS_BIT | (u32::from(iv) << DW11_INTERRUPT_VECTOR_SHIFT) - } else { - 0 - }, - - cdw12: 0, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - - pub fn create_io_submission_queue( - cid: u16, - qid: u16, - ptr: usize, - size: u16, - cqid: u16, - ) -> Self { - Self { - opcode: 1, - flags: 0, - cid, - nsid: 0, - _rsvd: 0, - mptr: 0, - dptr: [ptr as u64, 0], - cdw10: ((size as u32) << 16) | (qid as u32), - cdw11: ((cqid as u32) << 16) | 1, /* Physically Contiguous */ - //TODO: QPRIO - cdw12: 0, //TODO: NVMSETID - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - - pub fn identify_namespace(cid: u16, ptr: usize, nsid: u32) -> Self { - Self { - opcode: 6, - flags: 0, - cid, - nsid, - _rsvd: 0, - mptr: 0, - dptr: [ptr as u64, 0], - cdw10: 0, - cdw11: 0, - cdw12: 0, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - - pub fn identify_controller(cid: u16, ptr: usize) -> Self { - Self { - opcode: 6, - flags: 0, - cid, - nsid: 0, - _rsvd: 0, - mptr: 0, - dptr: [ptr as u64, 0], - cdw10: 1, - cdw11: 0, - cdw12: 0, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - - pub fn identify_namespace_list(cid: u16, ptr: usize, base: u32) -> Self { - Self { - opcode: 6, - flags: 0, - cid, - nsid: base, - _rsvd: 0, - mptr: 0, - dptr: [ptr as u64, 0], - cdw10: 2, - cdw11: 0, - cdw12: 0, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - pub fn get_features(cid: u16, ptr: usize, fid: u8) -> Self { - Self { - opcode: 0xA, - dptr: [ptr as u64, 0], - cdw10: u32::from(fid), // TODO: SEL - ..Default::default() - } - } - - pub fn io_read(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { - Self { - opcode: 2, - flags: 0, - cid, - nsid, - _rsvd: 0, - mptr: 0, - dptr: [ptr0, ptr1], - cdw10: lba as u32, - cdw11: (lba >> 32) as u32, - cdw12: blocks_1 as u32, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - - pub fn io_write(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { - Self { - opcode: 1, - flags: 0, - cid, - nsid, - _rsvd: 0, - mptr: 0, - dptr: [ptr0, ptr1], - cdw10: lba as u32, - cdw11: (lba >> 32) as u32, - cdw12: blocks_1 as u32, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } -} diff --git a/recipes/core/base/drivers/storage/nvmed/src/nvme/executor.rs b/recipes/core/base/drivers/storage/nvmed/src/nvme/executor.rs deleted file mode 100644 index 6242fa98cb..0000000000 --- a/recipes/core/base/drivers/storage/nvmed/src/nvme/executor.rs +++ /dev/null @@ -1,82 +0,0 @@ -use std::cell::RefCell; -use std::fs::File; -use std::rc::Rc; -use std::sync::Arc; - -use executor::{Hardware, LocalExecutor}; - -use super::{CmdId, CqId, Nvme, NvmeCmd, NvmeComp, SqId}; - -pub struct NvmeHw; - -impl Hardware for NvmeHw { - type Iv = u16; - type Sqe = NvmeCmd; - type Cqe = NvmeComp; - type CmdId = CmdId; - type CqId = CqId; - type SqId = SqId; - type GlobalCtxt = Arc; - - fn mask_vector(ctxt: &Arc, iv: Self::Iv) { - ctxt.set_vector_masked(iv, true) - } - fn unmask_vector(ctxt: &Arc, iv: Self::Iv) { - ctxt.set_vector_masked(iv, false) - } - fn set_sqe_cmdid(sqe: &mut NvmeCmd, id: CmdId) { - sqe.cid = id; - } - fn get_cqe_cmdid(cqe: &Self::Cqe) -> Self::CmdId { - cqe.cid - } - fn vtable() -> &'static std::task::RawWakerVTable { - &VTABLE - } - fn current() -> std::rc::Rc> { - THE_EXECUTOR.with(|exec| Rc::clone(exec.borrow().as_ref().unwrap())) - } - fn try_submit( - nvme: &Arc, - sq_id: Self::SqId, - success: impl FnOnce(Self::CmdId) -> Self::Sqe, - fail: impl FnOnce(), - ) -> Option<(Self::CqId, Self::CmdId)> { - let ctxt = nvme.cur_thread_ctxt(); - let ctxt = ctxt.lock(); - - nvme.try_submit_raw(&*ctxt, sq_id, success, fail) - } - fn poll_cqes(nvme: &Arc, mut handle: impl FnMut(Self::CqId, Self::Cqe)) { - let ctxt = nvme.cur_thread_ctxt(); - let ctxt = ctxt.lock(); - - for (sq_cq_id, (sq, cq)) in ctxt.queues.borrow_mut().iter_mut() { - while let Some((new_head, cqe)) = cq.complete() { - unsafe { - nvme.completion_queue_head(*sq_cq_id, new_head); - } - sq.head = cqe.sq_head; - log::trace!("new head {new_head} cqe {cqe:?}"); - handle(*sq_cq_id, cqe); - } - } - } - fn sq_cq(_ctxt: &Arc, id: Self::CqId) -> Self::SqId { - id - } -} - -static VTABLE: std::task::RawWakerVTable = executor::vtable::(); - -thread_local! { - static THE_EXECUTOR: RefCell>>> = RefCell::new(None); -} - -pub type NvmeExecutor = LocalExecutor; - -pub fn init(nvme: Arc, iv: u16, intx: bool, irq_handle: File) -> Rc> { - let this = Rc::new(executor::init_raw(nvme, iv, intx, irq_handle)); - THE_EXECUTOR.with(|exec| *exec.borrow_mut() = Some(Rc::clone(&this))); - this -} diff --git a/recipes/core/base/drivers/storage/nvmed/src/nvme/identify.rs b/recipes/core/base/drivers/storage/nvmed/src/nvme/identify.rs deleted file mode 100644 index 05e5b9b2b6..0000000000 --- a/recipes/core/base/drivers/storage/nvmed/src/nvme/identify.rs +++ /dev/null @@ -1,228 +0,0 @@ -use super::{Nvme, NvmeCmd, NvmeNamespace}; - -use common::dma::Dma; - -/// See NVME spec section 5.15.2.2. -#[derive(Clone, Copy)] -#[repr(C, packed)] -pub struct IdentifyControllerData { - /// PCI vendor ID, always the same as in the PCI function header. - pub vid: u16, - /// PCI subsystem vendor ID. - pub ssvid: u16, - /// ASCII - pub serial_no: [u8; 20], - /// ASCII - pub model_no: [u8; 48], - /// ASCII - pub firmware_rev: [u8; 8], - // TODO: Lots of fields - pub _4k_pad: [u8; 4096 - 72], -} - -/// See NVME spec section 5.15.2.1. -#[derive(Clone, Copy)] -#[repr(C, packed)] -pub struct IdentifyNamespaceData { - pub nsze: u64, - pub ncap: u64, - pub nuse: u64, - - pub nsfeat: u8, - pub nlbaf: u8, - pub flbas: u8, - pub mc: u8, - - pub dpc: u8, - pub dps: u8, - pub nmic: u8, - pub rescap: u8, - // 32 - pub fpi: u8, - pub dlfeat: u8, - pub nawun: u16, - - pub nawupf: u16, - pub nacwu: u16, - // 40 - pub nabsn: u16, - pub nabo: u16, - - pub nabspf: u16, - pub noiob: u16, - // 48 - pub nvmcap: u128, - // 64 - pub npwg: u16, - pub npwa: u16, - pub npdg: u16, - pub npda: u16, - // 72 - pub nows: u16, - pub _rsvd1: [u8; 18], - // 92 - pub anagrpid: u32, - pub _rsvd2: [u8; 3], - pub nsattr: u8, - - // 100 - pub nvmsetid: u16, - pub endgid: u16, - pub nguid: [u8; 16], - pub eui64: u64, - - pub lba_format_support: [LbaFormat; 16], - pub _rsvd3: [u8; 192], - pub vendor_specific: [u8; 3712], -} - -impl IdentifyNamespaceData { - pub fn size_in_blocks(&self) -> u64 { - self.nsze - } - pub fn capacity_in_blocks(&self) -> u64 { - self.ncap - } - /// Guaranteed to be within 0..=15 - pub fn formatted_lba_size_idx(&self) -> usize { - (self.flbas & 0xF) as usize - } - pub fn formatted_lba_size(&self) -> &LbaFormat { - &self.lba_format_support[self.formatted_lba_size_idx()] - } - pub fn has_metadata_after_data(&self) -> bool { - (self.flbas & (1 << 4)) != 0 - } -} - -#[derive(Clone, Copy)] -#[repr(C, packed)] -pub struct LbaFormat(pub u32); - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum RelativePerformance { - Best = 0b00, - Better, - Good, - Degraded, -} -impl Ord for RelativePerformance { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - // higher performance is better, hence reversed - Ord::cmp(&(*self as u8), &(*other as u8)).reverse() - } -} -impl PartialOrd for RelativePerformance { - fn partial_cmp(&self, other: &Self) -> Option { - Some(Ord::cmp(self, other)) - } -} - -impl LbaFormat { - pub fn relative_performance(&self) -> RelativePerformance { - match ((self.0 >> 24) & 0b11) { - 0b00 => RelativePerformance::Best, - 0b01 => RelativePerformance::Better, - 0b10 => RelativePerformance::Good, - 0b11 => RelativePerformance::Degraded, - _ => unreachable!(), - } - } - pub fn is_available(&self) -> bool { - self.log_lba_data_size() != 0 - } - pub fn log_lba_data_size(&self) -> u8 { - ((self.0 >> 16) & 0xFF) as u8 - } - pub fn lba_data_size(&self) -> Option { - if self.log_lba_data_size() < 9 { - return None; - } - if self.log_lba_data_size() >= 32 { - return None; - } - Some(1u64 << self.log_lba_data_size()) - } - pub fn metadata_size(&self) -> u16 { - (self.0 & 0xFFFF) as u16 - } -} - -impl Nvme { - /// Returns the serial number, model, and firmware, in that order. - pub async fn identify_controller(&self) { - // TODO: Use same buffer - let data: Dma = unsafe { Dma::zeroed().unwrap().assume_init() }; - - // println!(" - Attempting to identify controller"); - let comp = self - .submit_and_complete_admin_command(|cid| { - NvmeCmd::identify_controller(cid, data.physical()) - }) - .await; - log::trace!("Completion: {:?}", comp); - - // println!(" - Dumping identify controller"); - - let model_cow = String::from_utf8_lossy(&data.model_no); - let serial_cow = String::from_utf8_lossy(&data.serial_no); - let fw_cow = String::from_utf8_lossy(&data.firmware_rev); - - let model = model_cow.trim(); - let serial = serial_cow.trim(); - let firmware = fw_cow.trim(); - - log::info!( - " - Model: {} Serial: {} Firmware: {}", - model, - serial, - firmware, - ); - } - pub async fn identify_namespace_list(&self, base: u32) -> Vec { - // TODO: Use buffer - let data: Dma<[u32; 1024]> = unsafe { Dma::zeroed().unwrap().assume_init() }; - - // println!(" - Attempting to retrieve namespace ID list"); - let comp = self - .submit_and_complete_admin_command(|cid| { - NvmeCmd::identify_namespace_list(cid, data.physical(), base) - }) - .await; - - log::trace!("Completion2: {:?}", comp); - - // println!(" - Dumping namespace ID list"); - data.iter().copied().take_while(|&nsid| nsid != 0).collect() - } - pub async fn identify_namespace(&self, nsid: u32) -> NvmeNamespace { - //TODO: Use buffer - let data: Dma = unsafe { Dma::zeroed().unwrap().assume_init() }; - - log::debug!("Attempting to identify namespace {nsid}"); - let comp = self - .submit_and_complete_admin_command(|cid| { - NvmeCmd::identify_namespace(cid, data.physical(), nsid) - }) - .await; - - log::debug!("Dumping identify namespace"); - - let size = data.size_in_blocks(); - let capacity = data.capacity_in_blocks(); - log::info!("NSID: {} Size: {} Capacity: {}", nsid, size, capacity); - - let block_size = data - .formatted_lba_size() - .lba_data_size() - .expect("nvmed: error: size outside 512-2^64 range"); - log::debug!("NVME block size: {}", block_size); - - NvmeNamespace { - id: nsid, - blocks: size, - block_size, - } - } -} diff --git a/recipes/core/base/drivers/storage/nvmed/src/nvme/mod.rs b/recipes/core/base/drivers/storage/nvmed/src/nvme/mod.rs deleted file mode 100644 index 682ee93329..0000000000 --- a/recipes/core/base/drivers/storage/nvmed/src/nvme/mod.rs +++ /dev/null @@ -1,541 +0,0 @@ -use std::cell::RefCell; -use std::collections::{BTreeMap, HashMap}; -use std::convert::TryFrom; -use std::iter; -use std::sync::atomic::AtomicU16; -use std::sync::Arc; - -use parking_lot::{Mutex, ReentrantMutex, RwLock}; -use pcid_interface::irq_helpers::InterruptVector; - -use common::io::{Io, Mmio}; -use common::timeout::Timeout; -use syscall::error::{Error, Result, EIO}; - -use common::dma::Dma; - -pub mod cmd; -pub mod executor; -pub mod identify; -pub mod queues; - -use self::executor::NvmeExecutor; -pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue}; - -use pcid_interface::PciFunctionHandle; - -#[repr(C, packed)] -pub struct NvmeRegs { - /// Controller Capabilities - cap_low: Mmio, - cap_high: Mmio, - /// Version - vs: Mmio, - /// Interrupt mask set - intms: Mmio, - /// Interrupt mask clear - intmc: Mmio, - /// Controller configuration - cc: Mmio, - /// Reserved - _rsvd: Mmio, - /// Controller status - csts: Mmio, - /// NVM subsystem reset - nssr: Mmio, - /// Admin queue attributes - aqa: Mmio, - /// Admin submission queue base address - asq_low: Mmio, - asq_high: Mmio, - /// Admin completion queue base address - acq_low: Mmio, - acq_high: Mmio, - /// Controller memory buffer location - cmbloc: Mmio, - /// Controller memory buffer size - cmbsz: Mmio, -} - -#[derive(Copy, Clone, Debug)] -pub struct NvmeNamespace { - pub id: u32, - pub blocks: u64, - pub block_size: u64, -} - -pub type CqId = u16; -pub type SqId = u16; -pub type CmdId = u16; -pub type AtomicCqId = AtomicU16; -pub type AtomicSqId = AtomicU16; -pub type AtomicCmdId = AtomicU16; -pub type Iv = u16; - -pub struct Nvme { - interrupt_vector: Mutex, - pcid_interface: Mutex, - regs: RwLock<&'static mut NvmeRegs>, - - sq_ivs: RwLock>, - cq_ivs: RwLock>, - - // maps interrupt vectors with the completion queues they have - thread_ctxts: RwLock>>>, - - next_sqid: AtomicSqId, - next_cqid: AtomicCqId, -} - -pub struct ThreadCtxt { - buffer: RefCell>, // 2MB of buffer - buffer_prp: RefCell>, // 4KB of PRP for the buffer - - // Yes, technically NVME allows multiple submission queues to be mapped to the same completion - // queue, but we don't use that feature. - queues: RefCell>, -} - -unsafe impl Send for Nvme {} -unsafe impl Sync for Nvme {} - -/// How to handle full submission queues. -pub enum FullSqHandling { - /// Return an error immediately prior to posting the command. - ErrorDirectly, - - /// Tell the executor that we want to be notified when a command on the same submission queue - /// has been completed. - Wait, -} - -impl Nvme { - pub fn new( - address: usize, - interrupt_vector: InterruptVector, - pcid_interface: PciFunctionHandle, - ) -> Result { - Ok(Nvme { - regs: RwLock::new(unsafe { &mut *(address as *mut NvmeRegs) }), - thread_ctxts: RwLock::new( - iter::once(( - 0_u16, - Arc::new(ReentrantMutex::new(ThreadCtxt { - buffer: RefCell::new(unsafe { Dma::zeroed()?.assume_init() }), - buffer_prp: RefCell::new(unsafe { Dma::zeroed()?.assume_init() }), - - queues: RefCell::new( - iter::once((0, (NvmeCmdQueue::new()?, NvmeCompQueue::new()?))) - .collect(), - ), - })), - )) - .collect(), - ), - - cq_ivs: RwLock::new(iter::once((0, 0)).collect()), - sq_ivs: RwLock::new(iter::once((0, 0)).collect()), - - interrupt_vector: Mutex::new(interrupt_vector), - pcid_interface: Mutex::new(pcid_interface), - - // TODO - next_sqid: AtomicSqId::new(2), - next_cqid: AtomicCqId::new(2), - }) - } - /// Write to a doorbell register. - /// - /// # Locking - /// Locks `regs`. - unsafe fn doorbell_write(&self, index: usize, value: u32) { - use std::ops::DerefMut; - - let mut regs_guard = self.regs.write(); - let regs: &mut NvmeRegs = regs_guard.deref_mut(); - - let dstrd = (regs.cap_high.read() & 0b1111) as usize; - let addr = (regs as *mut NvmeRegs as usize) + 0x1000 + index * (4 << dstrd); - (&mut *(addr as *mut Mmio)).write(value); - } - fn cur_thread_ctxt(&self) -> Arc> { - // TODO: multi-threading - Arc::clone(self.thread_ctxts.read().get(&0).unwrap()) - } - - pub unsafe fn submission_queue_tail(&self, qid: u16, tail: u16) { - self.doorbell_write(2 * (qid as usize), u32::from(tail)); - } - - pub unsafe fn completion_queue_head(&self, qid: u16, head: u16) { - self.doorbell_write(2 * (qid as usize) + 1, u32::from(head)); - } - - pub unsafe fn init(&mut self) -> Result<()> { - let thread_ctxts = self.thread_ctxts.get_mut(); - { - let regs = self.regs.read(); - log::debug!("CAP_LOW: {:X}", regs.cap_low.read()); - log::debug!("CAP_HIGH: {:X}", regs.cap_high.read()); - log::debug!("VS: {:X}", regs.vs.read()); - log::debug!("CC: {:X}", regs.cc.read()); - log::debug!("CSTS: {:X}", regs.csts.read()); - } - - log::debug!("Disabling controller."); - self.regs.get_mut().cc.writef(1, false); - - { - log::trace!("Waiting for not ready."); - let timeout = Timeout::from_secs(1); - loop { - let csts = self.regs.get_mut().csts.read(); - log::trace!("CSTS: {:X}", csts); - if csts & 1 == 1 { - timeout.run().map_err(|()| { - log::error!("failed to wait for not ready"); - Error::new(EIO) - })?; - } else { - break; - } - } - } - - if !self.interrupt_vector.get_mut().set_masked_if_fast(false) { - self.regs.get_mut().intms.write(0xFFFF_FFFF); - self.regs.get_mut().intmc.write(0x0000_0001); - } - - for (qid, iv) in self.cq_ivs.get_mut().iter_mut() { - let ctxt = thread_ctxts.get(&0).unwrap().lock(); - let queues = ctxt.queues.borrow(); - - let &(ref cq, ref sq) = queues.get(qid).unwrap(); - log::debug!( - "iv {iv} [cq {qid}: {:X}, {}] [sq {qid}: {:X}, {}]", - cq.data.physical(), - cq.data.len(), - sq.data.physical(), - sq.data.len() - ); - } - - { - let main_ctxt = thread_ctxts.get(&0).unwrap().lock(); - - for (i, prp) in main_ctxt.buffer_prp.borrow_mut().iter_mut().enumerate() { - *prp = (main_ctxt.buffer.borrow_mut().physical() + i * 4096) as u64; - } - - let regs = self.regs.get_mut(); - - let mut queues = main_ctxt.queues.borrow_mut(); - let (asq, acq) = queues.get_mut(&0).unwrap(); - regs.aqa - .write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1)); - regs.asq_low.write(asq.data.physical() as u32); - regs.asq_high - .write((asq.data.physical() as u64 >> 32) as u32); - regs.acq_low.write(acq.data.physical() as u32); - regs.acq_high - .write((acq.data.physical() as u64 >> 32) as u32); - - // Set IOCQES, IOSQES, AMS, MPS, and CSS - let mut cc = regs.cc.read(); - cc &= 0xFF00000F; - cc |= (4 << 20) | (6 << 16); - regs.cc.write(cc); - } - - log::debug!("Enabling controller."); - self.regs.get_mut().cc.writef(1, true); - - { - log::debug!("Waiting for ready"); - let timeout = Timeout::from_secs(1); - loop { - let csts = self.regs.get_mut().csts.read(); - log::debug!("CSTS: {:X}", csts); - if csts & 1 == 0 { - timeout.run().map_err(|()| { - log::error!("failed to wait for ready"); - Error::new(EIO) - })?; - } else { - break; - } - } - } - - Ok(()) - } - - pub fn set_vector_masked(&self, vector: u16, masked: bool) { - let mut interrupt_vector_guard = (&self).interrupt_vector.lock(); - - if !interrupt_vector_guard.set_masked_if_fast(masked) { - let mut to_mask = 0x0000_0000; - let mut to_clear = 0x0000_0000; - - let vector = vector as u8; - - if masked { - assert_ne!( - to_clear & (1 << vector), - (1 << vector), - "nvmed: internal error: cannot both mask and set" - ); - to_mask |= 1 << vector; - } else { - assert_ne!( - to_mask & (1 << vector), - (1 << vector), - "nvmed: internal error: cannot both mask and set" - ); - to_clear |= 1 << vector; - } - - if to_mask != 0 { - (&self).regs.write().intms.write(to_mask); - } - if to_clear != 0 { - (&self).regs.write().intmc.write(to_clear); - } - } - } - - pub async fn submit_and_complete_command( - &self, - sq_id: SqId, - cmd_init: impl FnOnce(CmdId) -> NvmeCmd, - ) -> NvmeComp { - NvmeExecutor::current().submit(sq_id, cmd_init(0)).await - } - - pub async fn submit_and_complete_admin_command( - &self, - cmd_init: impl FnOnce(CmdId) -> NvmeCmd, - ) -> NvmeComp { - self.submit_and_complete_command(0, cmd_init).await - } - pub fn try_submit_raw( - &self, - ctxt: &ThreadCtxt, - sq_id: SqId, - cmd_init: impl FnOnce(CmdId) -> NvmeCmd, - fail: impl FnOnce(), - ) -> Option<(CqId, CmdId)> { - match ctxt.queues.borrow_mut().get_mut(&sq_id).unwrap() { - (sq, _cq) => { - if sq.is_full() { - fail(); - return None; - } - let cmd_id = sq.tail; - let tail = sq.submit_unchecked(cmd_init(cmd_id)); - - // TODO: Submit in bulk - unsafe { - self.submission_queue_tail(sq_id, tail); - } - Some((sq_id, cmd_id)) - } - } - } - - pub async fn create_io_completion_queue( - &self, - io_cq_id: CqId, - vector: Option, - ) -> NvmeCompQueue { - let queue = NvmeCompQueue::new().expect("nvmed: failed to allocate I/O completion queue"); - - let len = u16::try_from(queue.data.len()) - .expect("nvmed: internal error: I/O CQ longer than 2^16 entries"); - let raw_len = len - .checked_sub(1) - .expect("nvmed: internal error: CQID 0 for I/O CQ"); - - let comp = self - .submit_and_complete_admin_command(|cid| { - NvmeCmd::create_io_completion_queue( - cid, - io_cq_id, - queue.data.physical(), - raw_len, - vector, - ) - }) - .await; - - /*match comp.status.specific { - 1 => panic!("invalid queue identifier"), - 2 => panic!("invalid queue size"), - 8 => panic!("invalid interrupt vector"), - _ => (), - }*/ - - queue - } - pub async fn create_io_submission_queue(&self, io_sq_id: SqId, io_cq_id: CqId) -> NvmeCmdQueue { - let q = NvmeCmdQueue::new().expect("failed to create submission queue"); - - let len = u16::try_from(q.data.len()) - .expect("nvmed: internal error: I/O SQ longer than 2^16 entries"); - let raw_len = len - .checked_sub(1) - .expect("nvmed: internal error: SQID 0 for I/O SQ"); - - let comp = self - .submit_and_complete_admin_command(|cid| { - NvmeCmd::create_io_submission_queue( - cid, - io_sq_id, - q.data.physical(), - raw_len, - io_cq_id, - ) - }) - .await; - /*match comp.status.specific { - 0 => panic!("completion queue invalid"), - 1 => panic!("invalid queue identifier"), - 2 => panic!("invalid queue size"), - _ => (), - }*/ - - q - } - - pub async fn init_with_queues(&self) -> BTreeMap { - log::trace!("preinit"); - - self.identify_controller().await; - - let nsids = self.identify_namespace_list(0).await; - - log::debug!("first commands"); - - let mut namespaces = BTreeMap::new(); - - for nsid in nsids.iter().copied() { - namespaces.insert(nsid, self.identify_namespace(nsid).await); - } - - // TODO: Multiple queues - let cq = self.create_io_completion_queue(1, Some(0)).await; - log::trace!("created compq"); - let sq = self.create_io_submission_queue(1, 1).await; - log::trace!("created subq"); - self.thread_ctxts - .read() - .get(&0) - .unwrap() - .lock() - .queues - .borrow_mut() - .insert(1, (sq, cq)); - self.sq_ivs.write().insert(1, 0); - self.cq_ivs.write().insert(1, 0); - - namespaces - } - - async fn namespace_rw( - &self, - ctxt: &ThreadCtxt, - namespace: &NvmeNamespace, - lba: u64, - blocks_1: u16, - write: bool, - ) -> Result<()> { - let block_size = namespace.block_size; - - let prp = ctxt.buffer_prp.borrow_mut(); - let bytes = ((blocks_1 as u64) + 1) * block_size; - let (ptr0, ptr1) = if bytes <= 4096 { - (prp[0], 0) - } else if bytes <= 8192 { - (prp[0], prp[1]) - } else { - (prp[0], (prp.physical() + 8) as u64) - }; - - let mut cmd = NvmeCmd::default(); - let comp = self - .submit_and_complete_command(1, |cid| { - cmd = if write { - NvmeCmd::io_write(cid, namespace.id, lba, blocks_1, ptr0, ptr1) - } else { - NvmeCmd::io_read(cid, namespace.id, lba, blocks_1, ptr0, ptr1) - }; - cmd.clone() - }) - .await; - - let status = comp.status >> 1; - if status == 0 { - Ok(()) - } else { - log::error!("command {:#x?} failed with status {:#x}", cmd, status); - Err(Error::new(EIO)) - } - } - - pub async fn namespace_read( - &self, - namespace: &NvmeNamespace, - mut lba: u64, - buf: &mut [u8], - ) -> Result { - let ctxt = self.cur_thread_ctxt(); - let ctxt = ctxt.lock(); - - let block_size = namespace.block_size as usize; - - for chunk in buf.chunks_mut(/* TODO: buf len */ 8192) { - let blocks = (chunk.len() + block_size - 1) / block_size; - - assert!(blocks > 0); - assert!(blocks <= 0x1_0000); - - self.namespace_rw(&*ctxt, namespace, lba, (blocks - 1) as u16, false) - .await?; - - chunk.copy_from_slice(&ctxt.buffer.borrow()[..chunk.len()]); - - lba += blocks as u64; - } - - Ok(buf.len()) - } - - pub async fn namespace_write( - &self, - namespace: &NvmeNamespace, - mut lba: u64, - buf: &[u8], - ) -> Result { - let ctxt = self.cur_thread_ctxt(); - let ctxt = ctxt.lock(); - - let block_size = namespace.block_size as usize; - - for chunk in buf.chunks(/* TODO: buf len */ 8192) { - let blocks = (chunk.len() + block_size - 1) / block_size; - - assert!(blocks > 0); - assert!(blocks <= 0x1_0000); - - ctxt.buffer.borrow_mut()[..chunk.len()].copy_from_slice(chunk); - - self.namespace_rw(&*ctxt, namespace, lba, (blocks - 1) as u16, true) - .await?; - - lba += blocks as u64; - } - - Ok(buf.len()) - } -} diff --git a/recipes/core/base/drivers/storage/nvmed/src/nvme/queues.rs b/recipes/core/base/drivers/storage/nvmed/src/nvme/queues.rs deleted file mode 100644 index a3712aeb74..0000000000 --- a/recipes/core/base/drivers/storage/nvmed/src/nvme/queues.rs +++ /dev/null @@ -1,151 +0,0 @@ -use std::cell::UnsafeCell; -use std::ptr; -use syscall::Result; - -use common::dma::Dma; - -/// A submission queue entry. -#[derive(Clone, Copy, Debug, Default)] -#[repr(C, packed)] -pub struct NvmeCmd { - /// Opcode - pub opcode: u8, - /// Flags - pub flags: u8, - /// Command ID - pub cid: u16, - /// Namespace identifier - pub nsid: u32, - /// Reserved - pub _rsvd: u64, - /// Metadata pointer - pub mptr: u64, - /// Data pointer - pub dptr: [u64; 2], - /// Command dword 10 - pub cdw10: u32, - /// Command dword 11 - pub cdw11: u32, - /// Command dword 12 - pub cdw12: u32, - /// Command dword 13 - pub cdw13: u32, - /// Command dword 14 - pub cdw14: u32, - /// Command dword 15 - pub cdw15: u32, -} - -/// A completion queue entry. -#[derive(Clone, Copy, Debug)] -#[repr(C, packed)] -pub struct NvmeComp { - pub command_specific: u32, - pub _rsvd: u32, - pub sq_head: u16, - pub sq_id: u16, - pub cid: u16, - pub status: u16, -} - -/// Completion queue -pub struct NvmeCompQueue { - pub data: Dma<[UnsafeCell]>, - pub head: u16, - pub phase: bool, -} - -impl NvmeCompQueue { - pub fn new() -> Result { - Ok(Self { - data: unsafe { Dma::zeroed_slice(256)?.assume_init() }, - head: 0, - phase: true, - }) - } - - /// Get a new completion queue entry, or return None if no entry is available yet. - pub(crate) fn complete(&mut self) -> Option<(u16, NvmeComp)> { - let entry = unsafe { ptr::read_volatile(self.data[usize::from(self.head)].get()) }; - - if ((entry.status & 1) == 1) == self.phase { - self.head = (self.head + 1) % (self.data.len() as u16); - if self.head == 0 { - self.phase = !self.phase; - } - Some((self.head, entry)) - } else { - None - } - } - - /// Get a new CQ entry, busy waiting until an entry appears. - pub fn complete_spin(&mut self) -> (u16, NvmeComp) { - log::debug!("Waiting for new CQ entry"); - loop { - if let Some(some) = self.complete() { - return some; - } else { - unsafe { - std::hint::spin_loop(); - } - } - } - } -} - -/// Submission queue -pub struct NvmeCmdQueue { - pub data: Dma<[UnsafeCell]>, - pub tail: u16, - pub head: u16, -} - -impl NvmeCmdQueue { - pub fn new() -> Result { - Ok(Self { - data: unsafe { Dma::zeroed_slice(64)?.assume_init() }, - tail: 0, - head: 0, - }) - } - - pub fn is_empty(&self) -> bool { - self.head == self.tail - } - pub fn is_full(&self) -> bool { - self.head == self.tail + 1 - } - - /// Add a new submission command entry to the queue. The caller must ensure that the queue have free - /// entries; this can be checked using `is_full`. - pub fn submit_unchecked(&mut self, entry: NvmeCmd) -> u16 { - unsafe { ptr::write_volatile(self.data[usize::from(self.tail)].get(), entry) } - self.tail = (self.tail + 1) % (self.data.len() as u16); - self.tail - } -} - -#[derive(Debug)] -pub enum Status { - GenericCmdStatus(u8), - CommandSpecificStatus(u8), - IntegrityError(u8), - PathRelatedStatus(u8), - Rsvd(u8), - Vendor(u8), -} -impl Status { - pub fn parse(raw: u16) -> Self { - let code = (raw >> 1) as u8; - match (raw >> 9) & 0b111 { - 0 => Self::GenericCmdStatus(code), - 1 => Self::CommandSpecificStatus(code), - 2 => Self::IntegrityError(code), - 3 => Self::PathRelatedStatus(code), - 4..=6 => Self::Rsvd(code), - 7 => Self::Vendor(code), - _ => unreachable!(), - } - } -} diff --git a/recipes/core/base/drivers/storage/partitionlib/Cargo.toml b/recipes/core/base/drivers/storage/partitionlib/Cargo.toml deleted file mode 100644 index d9c95c985a..0000000000 --- a/recipes/core/base/drivers/storage/partitionlib/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "partitionlib" -description = "GPT and MBR partition table library" -version = "0.1.0" -authors = ["Deepak Sirone "] -edition = "2021" -license = "MIT" - -[dependencies] -gpt = { version = "3.0.1" } -scroll = { version = "0.10", features = ["derive"] } -uuid = { version = "1.0", features = ["v4"] } diff --git a/recipes/core/base/drivers/storage/partitionlib/resources/disk.img b/recipes/core/base/drivers/storage/partitionlib/resources/disk.img deleted file mode 100644 index 76913628c2..0000000000 Binary files a/recipes/core/base/drivers/storage/partitionlib/resources/disk.img and /dev/null differ diff --git a/recipes/core/base/drivers/storage/partitionlib/resources/disk_mbr.img b/recipes/core/base/drivers/storage/partitionlib/resources/disk_mbr.img deleted file mode 100644 index 429d41ca6b..0000000000 Binary files a/recipes/core/base/drivers/storage/partitionlib/resources/disk_mbr.img and /dev/null differ diff --git a/recipes/core/base/drivers/storage/partitionlib/src/lib.rs b/recipes/core/base/drivers/storage/partitionlib/src/lib.rs deleted file mode 100644 index be369ce64e..0000000000 --- a/recipes/core/base/drivers/storage/partitionlib/src/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod mbr; -mod partition; -pub use self::partition::*; diff --git a/recipes/core/base/drivers/storage/partitionlib/src/mbr.rs b/recipes/core/base/drivers/storage/partitionlib/src/mbr.rs deleted file mode 100644 index 67ae5a6dad..0000000000 --- a/recipes/core/base/drivers/storage/partitionlib/src/mbr.rs +++ /dev/null @@ -1,57 +0,0 @@ -use scroll::{Pread, Pwrite}; -use std::io::{self, Read, Seek}; - -#[derive(Clone, Copy, Debug, Pread, Pwrite)] -pub(crate) struct Entry { - pub(crate) drive_attrs: u8, - pub(crate) start_head: u8, - pub(crate) start_cs: u16, - pub(crate) sys_id: u8, - pub(crate) end_head: u8, - pub(crate) end_cs: u16, - pub(crate) rel_sector: u32, - pub(crate) len: u32, -} - -#[derive(Pread, Pwrite)] -pub(crate) struct Header { - pub(crate) bootstrap: [u8; 446], - pub(crate) first_entry: Entry, - pub(crate) second_entry: Entry, - pub(crate) third_entry: Entry, - pub(crate) fourth_entry: Entry, - pub(crate) last_signature: u16, // 0xAA55 -} - -pub(crate) fn read_header(device: &mut D) -> io::Result> { - device.seek(io::SeekFrom::Start(0))?; - - let mut bytes = [0u8; 512]; - device.read_exact(&mut bytes)?; - - let header: Header = bytes.pread_with(0, scroll::LE).unwrap(); - - if header.last_signature != 0xAA55 { - return Ok(None); - } - - Ok(Some(header)) -} - -impl Header { - pub(crate) fn partitions(&self) -> impl Iterator { - [ - self.first_entry, - self.second_entry, - self.third_entry, - self.fourth_entry, - ] - .into_iter() - .filter(Entry::is_valid) - } -} -impl Entry { - fn is_valid(&self) -> bool { - (self.drive_attrs == 0 || self.drive_attrs == 0x80) && self.len != 0 - } -} diff --git a/recipes/core/base/drivers/storage/partitionlib/src/partition.rs b/recipes/core/base/drivers/storage/partitionlib/src/partition.rs deleted file mode 100644 index 949171511b..0000000000 --- a/recipes/core/base/drivers/storage/partitionlib/src/partition.rs +++ /dev/null @@ -1,84 +0,0 @@ -pub use gpt::disk::LogicalBlockSize; -use std::io::{self, Read, Seek}; -use uuid::Uuid; - -/// A union of the MBR and GPT partition entry -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct Partition { - /// The starting logical block number - pub start_lba: u64, - /// The size of the partition in sectors - pub size: u64, - pub flags: Option, - pub name: Option, - pub uuid: Option, -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum PartitionTableKind { - Mbr, - Gpt, -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct PartitionTable { - pub partitions: Vec, - pub kind: PartitionTableKind, -} - -fn get_gpt_partitions( - device: &mut D, - sector_size: LogicalBlockSize, -) -> io::Result { - let header = gpt::header::read_header_from_arbitrary_device(device, sector_size)?; - Ok(PartitionTable { - partitions: gpt::partition::file_read_partitions(device, &header, sector_size).map( - |btree| { - btree - .into_iter() - .map(|(_, part)| Partition { - flags: Some(part.flags), - size: part.last_lba - part.first_lba + 1, - name: Some(part.name.clone()), - uuid: Some(part.part_guid), - start_lba: part.first_lba, - }) - .collect() - }, - )?, - kind: PartitionTableKind::Gpt, - }) -} -fn get_mbr_partitions(device: &mut D) -> io::Result> { - let Some(header) = crate::mbr::read_header(device)? else { - return Ok(None); - }; - Ok(Some(PartitionTable { - kind: PartitionTableKind::Mbr, - partitions: header - .partitions() - .map(|partition: crate::mbr::Entry| Partition { - name: None, - uuid: None, // TODO: Some kind of one-way conversion should be possible - flags: None, // TODO - size: partition.len.into(), - start_lba: partition.rel_sector.into(), - }) - .collect(), - })) -} -pub fn get_partitions( - device: &mut D, - sector_size: LogicalBlockSize, -) -> io::Result> { - get_gpt_partitions(device, sector_size) - .map(Some) - .or_else(|_| get_mbr_partitions(device)) -} - -impl Partition { - pub fn to_offset(&self, sector_size: LogicalBlockSize) -> u64 { - let blksize: u64 = sector_size.into(); - self.start_lba * blksize - } -} diff --git a/recipes/core/base/drivers/storage/partitionlib/tests/test.rs b/recipes/core/base/drivers/storage/partitionlib/tests/test.rs deleted file mode 100644 index c4ef93220e..0000000000 --- a/recipes/core/base/drivers/storage/partitionlib/tests/test.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::fs::File; - -use partitionlib::{ - get_partitions, LogicalBlockSize, Partition, PartitionTable, PartitionTableKind, -}; - -fn get_partitions_from_file(path: &str) -> PartitionTable { - let mut file = File::open(path).unwrap(); - get_partitions(&mut file, LogicalBlockSize::Lb512) - .unwrap() - .unwrap() -} - -// NOTE: The following tests rely on outside resource files being correct. -#[test] -fn gpt() { - let table = get_partitions_from_file("./resources/disk.img"); - assert_eq!(table.kind, PartitionTableKind::Gpt); - assert_eq!( - &table.partitions, - &[Partition { - flags: Some(0), - name: Some("bug".to_owned()), - uuid: Some(uuid::Uuid::parse_str("b665fba9-74d5-4069-a6b9-5ba3a164fdfe").unwrap()), // Microsoft basic data - size: 957, - start_lba: 34, - }] - ); -} - -#[test] -fn mbr() { - let table = get_partitions_from_file("./resources/disk_mbr.img"); - assert_eq!(table.kind, PartitionTableKind::Mbr); - assert_eq!( - &table.partitions, - &[Partition { - flags: None, - name: None, - uuid: None, - size: 3, - start_lba: 1, - }] - ); -} diff --git a/recipes/core/base/drivers/storage/usbscsid/.gitignore b/recipes/core/base/drivers/storage/usbscsid/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/recipes/core/base/drivers/storage/usbscsid/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/recipes/core/base/drivers/storage/usbscsid/Cargo.toml b/recipes/core/base/drivers/storage/usbscsid/Cargo.toml deleted file mode 100644 index 4a36934ebb..0000000000 --- a/recipes/core/base/drivers/storage/usbscsid/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "usbscsid" -description = "USB SCSI driver" -version = "0.1.0" -authors = ["4lDO2 <4lDO2@protonmail.com>"] -edition = "2021" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -base64 = "0.11" # Only for debugging -libredox.workspace = true -plain.workspace = true -driver-block = { path = "../driver-block" } -daemon = { path = "../../../daemon" } -redox_event.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -thiserror.workspace = true -xhcid = { path = "../../usb/xhcid" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/storage/usbscsid/src/main.rs b/recipes/core/base/drivers/storage/usbscsid/src/main.rs deleted file mode 100644 index 5382d118e3..0000000000 --- a/recipes/core/base/drivers/storage/usbscsid/src/main.rs +++ /dev/null @@ -1,168 +0,0 @@ -use std::collections::BTreeMap; -use std::env; - -use driver_block::{Disk, DiskScheme, ExecutorTrait}; -use syscall::{Error, EIO}; -use xhcid_interface::{ConfigureEndpointsReq, PortId, XhciClientHandle}; - -pub mod protocol; -pub mod scsi; - -use crate::protocol::Protocol; -use crate::scsi::Scsi; - -fn main() { - daemon::Daemon::new(daemon); -} -fn daemon(daemon: daemon::Daemon) -> ! { - let mut args = env::args().skip(1); - - const USAGE: &'static str = "usbscsid "; - - let scheme = args.next().expect(USAGE); - let port = args - .next() - .expect(USAGE) - .parse::() - .expect("Expected port ID"); - let protocol = args - .next() - .expect(USAGE) - .parse::() - .expect("protocol has to be a number 0-255"); - - println!( - "USB SCSI driver spawned with scheme `{}`, port {}, protocol {}", - scheme, port, protocol - ); - - let disk_scheme_name = format!("disk.usb-{scheme}+{port}-scsi"); - - // TODO: Use eventfds. - let handle = - XhciClientHandle::new(scheme.to_owned(), port).expect("Failed to open XhciClientHandle"); - - let desc = handle - .get_standard_descs() - .expect("Failed to get standard descriptors"); - - // TODO: Perhaps the drivers should just be given the config, interface, and alternate setting - // from xhcid. - let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting)) = desc - .config_descs - .iter() - .find_map(|config_desc| { - let interface_desc = config_desc.interface_descs.iter().find_map(|if_desc| { - if if_desc.class == 8 && if_desc.sub_class == 6 && if_desc.protocol == 0x50 { - Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting)) - } else { - None - } - })?; - Some(( - config_desc.clone(), - config_desc.configuration_value, - interface_desc, - )) - }) - .expect("Failed to find suitable configuration"); - - handle - .configure_endpoints(&ConfigureEndpointsReq { - config_desc: configuration_value, - interface_desc: Some(interface_num), - alternate_setting: Some(alternate_setting), - hub_ports: None, - }) - .expect("Failed to configure endpoints"); - - let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc) - .expect("Failed to setup protocol"); - - // TODO: Let all of the USB drivers fork or be managed externally, and xhcid won't have to keep - // track of all the drivers. - let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI"); - println!("SCSI initialized"); - let mut buffer = [0u8; 512]; - scsi.read(&mut *protocol, 0, &mut buffer).unwrap(); - println!("DISK CONTENT: {}", base64::encode(&buffer[..])); - - let event_queue = event::EventQueue::new().unwrap(); - - event::user_data! { - enum Event { - Scheme, - } - }; - - let mut scheme = DiskScheme::new( - None, - disk_scheme_name, - BTreeMap::from([( - 0, - UsbDisk { - scsi: &mut scsi, - protocol: &mut *protocol, - }, - )]), - &driver_block::FuturesExecutor, - ); - - // FIXME should this wait notifying readiness until the disk scheme is created? - daemon.ready(); - - //libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - - event_queue - .subscribe( - scheme.event_handle().raw(), - Event::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - - for event in event_queue { - match event.unwrap().user_data { - Event::Scheme => driver_block::FuturesExecutor - .block_on(scheme.tick()) - .unwrap(), - } - } - - std::process::exit(0); -} - -struct UsbDisk<'a> { - scsi: &'a mut Scsi, - protocol: &'a mut dyn Protocol, -} - -impl Disk for UsbDisk<'_> { - fn block_size(&self) -> u32 { - self.scsi.block_size - } - - fn size(&self) -> u64 { - self.scsi.get_disk_size() - } - - async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { - match self.scsi.read(self.protocol, block, buffer) { - Ok(bytes_read) => Ok(bytes_read as usize), - Err(err) => { - eprintln!("usbscsid: READ IO ERROR: {err}"); - Err(Error::new(EIO)) - } - } - } - - async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { - match self.scsi.write(self.protocol, block, buffer) { - Ok(bytes_written) => Ok(bytes_written as usize), - Err(err) => { - eprintln!("usbscsid: WRITE IO ERROR: {err}"); - Err(Error::new(EIO)) - } - } - } -} diff --git a/recipes/core/base/drivers/storage/usbscsid/src/protocol/bot.rs b/recipes/core/base/drivers/storage/usbscsid/src/protocol/bot.rs deleted file mode 100644 index b751d51ad6..0000000000 --- a/recipes/core/base/drivers/storage/usbscsid/src/protocol/bot.rs +++ /dev/null @@ -1,363 +0,0 @@ -use std::num::NonZeroU32; -use std::slice; - -use xhcid_interface::{ - ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, - PortReqRecipient, PortReqTy, PortTransferStatus, PortTransferStatusKind, XhciClientHandle, - XhciClientHandleError, XhciEndpHandle, -}; - -use super::{Protocol, ProtocolError, SendCommandStatus, SendCommandStatusKind}; - -pub const CBW_SIGNATURE: u32 = 0x43425355; - -/// 0 means host to dev, 1 means dev to host -pub const CBW_FLAGS_DIRECTION_BIT: u8 = 1 << CBW_FLAGS_DIRECTION_SHIFT; -pub const CBW_FLAGS_DIRECTION_SHIFT: u8 = 7; - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct CommandBlockWrapper { - pub signature: u32, - pub tag: u32, - pub data_transfer_len: u32, - pub flags: u8, // upper nibble reserved - pub lun: u8, // bits 7:5 reserved - pub cb_len: u8, - pub command_block: [u8; 16], -} -impl CommandBlockWrapper { - pub fn new( - tag: u32, - data_transfer_len: u32, - direction: EndpBinaryDirection, - lun: u8, - cb: &[u8], - ) -> Result { - let mut command_block = [0u8; 16]; - if cb.len() > 16 { - return Err(ProtocolError::TooLargeCommandBlock(cb.len())); - } - - command_block[..cb.len()].copy_from_slice(&cb); - Ok(Self { - signature: CBW_SIGNATURE, - tag, - data_transfer_len, - flags: match direction { - EndpBinaryDirection::Out => 0, - EndpBinaryDirection::In => 1, - } << CBW_FLAGS_DIRECTION_SHIFT, - lun, - cb_len: cb.len() as u8, - command_block, - }) - } -} -unsafe impl plain::Plain for CommandBlockWrapper {} - -pub const CSW_SIGNATURE: u32 = 0x53425355; - -#[repr(u8)] -pub enum CswStatus { - Passed = 0, - Failed = 1, - PhaseError = 2, - // the rest are reserved -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct CommandStatusWrapper { - pub signature: u32, - pub tag: u32, - pub data_residue: u32, - pub status: u8, -} -unsafe impl plain::Plain for CommandStatusWrapper {} - -impl CommandStatusWrapper { - pub fn is_valid(&self) -> bool { - self.signature == CSW_SIGNATURE - } -} - -pub struct BulkOnlyTransport<'a> { - handle: &'a XhciClientHandle, - bulk_in: XhciEndpHandle, - bulk_out: XhciEndpHandle, - bulk_in_num: u8, - bulk_out_num: u8, - max_lun: u8, - current_tag: u32, - interface_num: u8, -} - -pub const FEATURE_ENDPOINT_HALT: u16 = 0; - -impl<'a> BulkOnlyTransport<'a> { - pub fn init( - handle: &'a XhciClientHandle, - config_desc: &ConfDesc, - if_desc: &IfDesc, - ) -> Result { - let endpoints = &if_desc.endpoints; - - let bulk_in_num = (endpoints - .iter() - .position(|endpoint| endpoint.direction() == EndpDirection::In) - .unwrap() - + 1) as u8; - let bulk_out_num = (endpoints - .iter() - .position(|endpoint| endpoint.direction() == EndpDirection::Out) - .unwrap() - + 1) as u8; - - let max_lun = get_max_lun(handle, 0)?; - println!("BOT_MAX_LUN {}", max_lun); - - Ok(Self { - bulk_in: handle.open_endpoint(bulk_in_num)?, - bulk_out: handle.open_endpoint(bulk_out_num)?, - bulk_in_num, - bulk_out_num, - handle, - max_lun, - current_tag: 0, - interface_num: if_desc.number, - }) - } - fn clear_stall_in(&mut self) -> Result<(), XhciClientHandleError> { - if self.bulk_in.status()? == EndpointStatus::Halted { - self.bulk_in.reset(false)?; - self.handle.clear_feature( - PortReqRecipient::Endpoint, - u16::from(self.bulk_in_num), - FEATURE_ENDPOINT_HALT, - )?; - } - Ok(()) - } - fn clear_stall_out(&mut self) -> Result<(), XhciClientHandleError> { - if self.bulk_out.status()? == EndpointStatus::Halted { - self.bulk_out.reset(false)?; - self.handle.clear_feature( - PortReqRecipient::Endpoint, - u16::from(self.bulk_out_num), - FEATURE_ENDPOINT_HALT, - )?; - } - Ok(()) - } - fn reset_recovery(&mut self) -> Result<(), ProtocolError> { - bulk_only_mass_storage_reset(self.handle, self.interface_num.into())?; - self.clear_stall_in()?; - self.clear_stall_out()?; - - if self.bulk_in.status()? == EndpointStatus::Halted - || self.bulk_out.status()? == EndpointStatus::Halted - { - return Err(ProtocolError::RecoveryFailed); - } - Ok(()) - } - fn read_csw_raw( - &mut self, - csw_buffer: &mut [u8; 13], - already: bool, - ) -> Result<(), ProtocolError> { - match self.bulk_in.transfer_read(&mut csw_buffer[..])? { - PortTransferStatus { - kind: PortTransferStatusKind::Stalled, - .. - } => { - if already { - self.reset_recovery()?; - } - println!("bulk in endpoint stalled when reading CSW"); - self.clear_stall_in()?; - self.read_csw_raw(csw_buffer, true)?; - } - PortTransferStatus { - kind: PortTransferStatusKind::ShortPacket, - bytes_transferred, - } if bytes_transferred != 13 => { - panic!( - "received a short packet when reading CSW ({} != 13)", - bytes_transferred - ) - } - _ => (), - } - Ok(()) - } - fn read_csw(&mut self, csw_buffer: &mut [u8; 13]) -> Result<(), ProtocolError> { - self.read_csw_raw(csw_buffer, false) - } -} - -impl<'a> Protocol for BulkOnlyTransport<'a> { - fn send_command( - &mut self, - cb: &[u8], - data: DeviceReqData, - ) -> Result { - self.current_tag += 1; - let tag = self.current_tag; - - let mut cbw_bytes = [0u8; 31]; - let cbw = plain::from_mut_bytes::(&mut cbw_bytes).unwrap(); - *cbw = CommandBlockWrapper::new(tag, data.len() as u32, data.direction().into(), 0, cb)?; - let cbw = *cbw; - - match self.bulk_out.transfer_write(&cbw_bytes)? { - PortTransferStatus { - kind: PortTransferStatusKind::Stalled, - .. - } => { - // TODO: Error handling - panic!("bulk out endpoint stalled when sending CBW {:?}", cbw); - //self.clear_stall_out()?; - //dbg!(self.bulk_in.status()?, self.bulk_out.status()?); - } - PortTransferStatus { - bytes_transferred, .. - } if bytes_transferred != 31 => { - panic!( - "received short packet when sending CBW ({} != 31)", - bytes_transferred - ); - } - _ => (), - } - - let early_residue: Option = match data { - DeviceReqData::In(buffer) => match self.bulk_in.transfer_read(buffer)? { - PortTransferStatus { - kind, - bytes_transferred, - } => match kind { - PortTransferStatusKind::Success => None, - PortTransferStatusKind::ShortPacket => { - println!( - "received short packet (len {}) when transferring data", - bytes_transferred - ); - NonZeroU32::new(bytes_transferred) - } - PortTransferStatusKind::Stalled => { - panic!("bulk in endpoint stalled when reading data"); - //self.clear_stall_in()?; - } - PortTransferStatusKind::Unknown => { - return Err(ProtocolError::XhciError( - XhciClientHandleError::InvalidResponse(Invalid( - "unknown transfer status", - )), - )); - } - }, - }, - DeviceReqData::Out(buffer) => match self.bulk_out.transfer_write(buffer)? { - PortTransferStatus { - kind, - bytes_transferred, - } => match kind { - PortTransferStatusKind::Success => None, - PortTransferStatusKind::ShortPacket => { - println!( - "received short packet (len {}) when transferring data", - bytes_transferred - ); - NonZeroU32::new(bytes_transferred) - } - PortTransferStatusKind::Stalled => { - panic!("bulk out endpoint stalled when reading data"); - //self.clear_stall_out()?; - } - PortTransferStatusKind::Unknown => { - return Err(ProtocolError::XhciError( - XhciClientHandleError::InvalidResponse(Invalid( - "unknown transfer status", - )), - )); - } - }, - }, - DeviceReqData::NoData => None, - }; - - let mut csw_buffer = [0u8; 13]; - self.read_csw(&mut csw_buffer)?; - let csw = plain::from_bytes::(&csw_buffer).unwrap(); - - let residue = early_residue.or(NonZeroU32::new(csw.data_residue)); - - if csw.status == CswStatus::Failed as u8 { - println!("CSW indicated failure (CSW {:?}, CBW {:?})", csw, cbw); - } - - if !csw.is_valid() || csw.tag != cbw.tag { - println!("Invald CSW {:?} (for CBW {:?})", csw, cbw); - self.reset_recovery()?; - if self.bulk_in.status()? == EndpointStatus::Halted - || self.bulk_out.status()? == EndpointStatus::Halted - { - return Err(ProtocolError::ProtocolError( - "Reset Recovery didn't reset endpoints", - )); - } - return Err(ProtocolError::ProtocolError( - "CSW invalid, but a recover was successful", - )); - } - - /*if self.bulk_in.status()? == EndpointStatus::Halted - || self.bulk_out.status()? == EndpointStatus::Halted - { - println!("Trying to recover from stall"); - dbg!(self.bulk_in.status()?, self.bulk_out.status()?); - }*/ - - Ok(SendCommandStatus { - kind: if csw.status == CswStatus::Passed as u8 { - SendCommandStatusKind::Success - } else if csw.status == CswStatus::Failed as u8 { - SendCommandStatusKind::Failed - } else { - return Err(ProtocolError::ProtocolError( - "bulk-only transport phase error, or other", - )); - }, - residue, - }) - } -} - -pub fn bulk_only_mass_storage_reset( - handle: &XhciClientHandle, - if_num: u16, -) -> Result<(), XhciClientHandleError> { - handle.device_request( - PortReqTy::Class, - PortReqRecipient::Interface, - 0xFF, - 0, - if_num, - DeviceReqData::NoData, - ) -} -pub fn get_max_lun(handle: &XhciClientHandle, if_num: u16) -> Result { - let mut lun = 0u8; - let buffer = slice::from_mut(&mut lun); - handle.device_request( - PortReqTy::Class, - PortReqRecipient::Interface, - 0xFE, - 0, - if_num, - DeviceReqData::In(buffer), - )?; - Ok(lun) -} diff --git a/recipes/core/base/drivers/storage/usbscsid/src/protocol/mod.rs b/recipes/core/base/drivers/storage/usbscsid/src/protocol/mod.rs deleted file mode 100644 index a580765f1d..0000000000 --- a/recipes/core/base/drivers/storage/usbscsid/src/protocol/mod.rs +++ /dev/null @@ -1,81 +0,0 @@ -use std::io; -use std::num::NonZeroU32; - -use thiserror::Error; -use xhcid_interface::{ - ConfDesc, DevDesc, DeviceReqData, IfDesc, XhciClientHandle, XhciClientHandleError, -}; - -#[derive(Debug, Error)] -pub enum ProtocolError { - #[error("Too large command block ({0} > 16)")] - TooLargeCommandBlock(usize), - - #[error("xhcid connection error: {0}")] - XhciError(#[from] XhciClientHandleError), - - #[error("i/o error")] - IoError(#[from] io::Error), - - #[error("attempted recovery failed")] - RecoveryFailed, - - #[error("protocol error")] - ProtocolError(&'static str), -} - -#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] -pub struct SendCommandStatus { - pub residue: Option, - pub kind: SendCommandStatusKind, -} - -impl SendCommandStatus { - pub fn bytes_transferred(&self, transfer_len: u32) -> u32 { - transfer_len - self.residue.map(u32::from).unwrap_or(0) - } -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum SendCommandStatusKind { - Success, - Failed, -} - -impl Default for SendCommandStatusKind { - fn default() -> Self { - Self::Success - } -} - -pub trait Protocol { - fn send_command( - &mut self, - command: &[u8], - data: DeviceReqData, - ) -> Result; -} - -/// Bulk-only transport -pub mod bot; - -mod uas { - // TODO -} - -use bot::BulkOnlyTransport; - -pub fn setup<'a>( - handle: &'a XhciClientHandle, - protocol: u8, - dev_desc: &DevDesc, - conf_desc: &ConfDesc, - if_desc: &IfDesc, -) -> Option> { - match protocol { - 0x50 => Some(Box::new( - BulkOnlyTransport::init(handle, conf_desc, if_desc).unwrap(), - )), - _ => None, - } -} diff --git a/recipes/core/base/drivers/storage/usbscsid/src/scsi/cmds.rs b/recipes/core/base/drivers/storage/usbscsid/src/scsi/cmds.rs deleted file mode 100644 index ab02525e93..0000000000 --- a/recipes/core/base/drivers/storage/usbscsid/src/scsi/cmds.rs +++ /dev/null @@ -1,559 +0,0 @@ -use super::opcodes::Opcode; -use std::convert::TryInto; -use std::{fmt, mem, slice}; - -#[repr(C, packed)] -pub struct Inquiry { - pub opcode: u8, - /// bits 7:2 are reserved, bit 1 (CMDDT) is obsolete, bit 0 is EVPD - pub evpd: u8, - pub page_code: u8, - /// big endian - pub alloc_len: u16, - pub control: u8, -} -unsafe impl plain::Plain for Inquiry {} - -impl Inquiry { - pub const fn new(evpd: bool, page_code: u8, alloc_len: u16, control: u8) -> Self { - Self { - opcode: Opcode::Inquiry as u8, - evpd: evpd as u8, - page_code, - alloc_len: u16::to_be(alloc_len), - control, - } - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct StandardInquiryData { - /// Peripheral device type (bits 4:0), and peripheral device qualifier (bits 7:5). - pub a: u8, - /// Removable media bit (bit 7, bits 6:0 are reserved). - pub rmb: u8, - /// Version of the SCSI command set. - pub version: u8, - pub b: u8, - pub additional_len: u8, - pub c: u8, - pub d: u8, - pub e: u8, - pub t10_vendor_info: u64, - pub product_ident: [u8; 16], - pub product_rev_label: u32, - pub driver_serial_no: [u8; 8], - pub vendor_uniq: [u8; 12], - _rsvd1: [u8; 2], - pub version_descs: [u16; 8], - _rsvd2: [u8; 22], -} -unsafe impl plain::Plain for StandardInquiryData {} -impl StandardInquiryData { - pub const fn periph_dev_ty(&self) -> u8 { - self.a & 0x1F - } - pub const fn periph_dev_qual(&self) -> u8 { - (self.a & 0xE0) >> 5 - } - pub const fn version(&self) -> u8 { - self.version - } -} - -#[repr(u8)] -pub enum PeriphDeviceType { - DirectAccess, - SeqAccess, - // there are more -} -#[repr(u8)] -pub enum InquiryVersion { - NoConformance, - Spc, - Spc2, - Spc3, - Spc4, - Spc5, -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct RequestSense { - pub opcode: u8, - pub desc: u8, // bits 7:1 reserved - _rsvd: u16, - pub alloc_len: u8, - pub control: u8, -} -unsafe impl plain::Plain for RequestSense {} - -impl RequestSense { - pub const MINIMAL_ALLOC_LEN: u8 = 252; - - pub const fn new(desc: bool, alloc_len: u8, control: u8) -> Self { - Self { - opcode: Opcode::RequestSense as u8, - desc: desc as u8, - _rsvd: 0, - alloc_len, - control, - } - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct FixedFormatSenseData { - pub a: u8, - _obsolete: u8, - pub b: u8, - pub info: u32, - pub add_sense_len: u8, - pub command_specific_info: u32, - pub add_sense_code: u8, - pub add_sense_code_qual: u8, - pub field_replacable_unit_code: u8, - pub sense_key_specific: [u8; 3], // big endian - pub add_sense_bytes: [u8; 0], -} -unsafe impl plain::Plain for FixedFormatSenseData {} - -impl FixedFormatSenseData { - pub const fn additional_len(&self) -> u16 { - self.add_sense_len as u16 + 7 - } - pub unsafe fn add_sense_bytes(&self) -> &[u8] { - slice::from_raw_parts( - &self.add_sense_len as *const u8, - self.add_sense_len as usize - 18, - ) - } - pub fn sense_key(&self) -> SenseKey { - let sense_key_raw = self.b & 0b1111; - // Safe because all possible values (0-15) are used by the enum. - unsafe { mem::transmute(sense_key_raw) } - } -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum SenseKey { - NoSense = 0x00, - RecoveredError = 0x01, - NotReady = 0x02, - MediumError = 0x03, - HardwareError = 0x04, - IllegalRequest = 0x05, - UnitAttention = 0x06, - DataProtect = 0x07, - BlankCheck = 0x08, - VendorSpecific = 0x09, - CopyAborted = 0x0A, - AbortedCommand = 0x0B, - Reserved = 0x0C, - VolumeOverflow = 0x0D, - Miscompare = 0x0E, - Completed = 0x0F, -} -impl Default for SenseKey { - fn default() -> Self { - Self::NoSense - } -} - -pub const ADD_SENSE_CODE05_INVAL_CDB_FIELD: u8 = 0x24; - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct Read16 { - pub opcode: u8, - pub a: u8, - pub lba: u64, - pub transfer_len: u32, - pub b: u8, - pub control: u8, -} -unsafe impl plain::Plain for Read16 {} - -impl Read16 { - pub const fn new(lba: u64, transfer_len: u32, control: u8) -> Self { - // TODO: RDPROTECT, DPO, FUA, RARC - // TODO: DLD - // TODO: Group number - Self { - opcode: Opcode::Read16 as u8, - a: 0, - lba: u64::to_be(lba), - transfer_len: u32::to_be(transfer_len), - b: 0, - control, - } - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct Write16 { - pub opcode: u8, - pub a: u8, - pub lba: u64, // big endian - pub transfer_len: u32, - pub b: u8, - pub control: u8, -} -unsafe impl plain::Plain for Write16 {} - -impl Write16 { - pub const fn new(lba: u64, transfer_len: u32, control: u8) -> Self { - Self { - // TODO - opcode: Opcode::Write16 as u8, - a: 0, - lba, - transfer_len, - b: 0, - control, - } - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct ModeSense6 { - pub opcode: u8, - pub a: u8, - pub b: u8, - pub subpage_code: u8, - pub alloc_len: u8, - pub control: u8, -} -unsafe impl plain::Plain for ModeSense6 {} - -impl ModeSense6 { - pub const fn new( - dbd: bool, - page_code: u8, - pc: u8, - subpage_code: u8, - alloc_len: u8, - control: u8, - ) -> Self { - Self { - opcode: Opcode::ModeSense6 as u8, - a: (dbd as u8) << 3, - b: page_code | (pc << 6), - subpage_code, - alloc_len, - control, - } - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct ModeSense10 { - pub opcode: u8, - pub a: u8, - pub b: u8, - pub subpage_code: u8, - pub _rsvd: [u8; 3], - pub alloc_len: u16, - pub control: u8, -} -unsafe impl plain::Plain for ModeSense10 {} - -impl ModeSense10 { - pub const fn new( - dbd: bool, - llbaa: bool, - page_code: u8, - pc: ModePageControl, - subpage_code: u8, - alloc_len: u16, - control: u8, - ) -> Self { - Self { - opcode: Opcode::ModeSense10 as u8, - a: ((dbd as u8) << 3) | ((llbaa as u8) << 4), - b: page_code | ((pc as u8) << 6), - subpage_code, - _rsvd: [0u8; 3], - alloc_len: u16::from_be(alloc_len), - control, - } - } - pub const fn get_block_desc(alloc_len: u16, control: u8) -> Self { - Self::new( - false, - true, - 0x3F, - ModePageControl::CurrentValues, - 0x00, - alloc_len, - control, - ) - } -} - -#[repr(u8)] -pub enum ModePageControl { - CurrentValues, - ChangeableChanges, - DefaultValues, - SavedValue, -} - -#[repr(C, packed)] -#[derive(Clone, Copy)] -pub struct ShortLbaModeParamBlkDesc { - pub block_count: u32, - _rsvd: u8, - pub logical_block_len: [u8; 3], -} -unsafe impl plain::Plain for ShortLbaModeParamBlkDesc {} - -impl ShortLbaModeParamBlkDesc { - pub const fn block_count(&self) -> u32 { - u32::from_be(self.block_count) - } - pub const fn logical_block_len(&self) -> u32 { - u24_be_to_u32(self.logical_block_len) - } -} -impl fmt::Debug for ShortLbaModeParamBlkDesc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("ShortLbaModeParamBlkDesc") - .field("block_count", &self.block_count()) - .field("logical_block_len", &self.logical_block_len()) - .finish() - } -} - -const fn u24_be_to_u32(u24: [u8; 3]) -> u32 { - ((u24[0] as u32) << 16) | ((u24[1] as u32) << 8) | (u24[2] as u32) -} - -/// From SPC-3, when LONGLBA is not set, and the peripheral device type of the INQUIRY data indicates that the device is not a direct access device. Otherwise, `ShortLbaModeParamBlkDesc` is used instead. -#[repr(C, packed)] -#[derive(Clone, Copy)] -pub struct GeneralModeParamBlkDesc { - pub density_code: u8, - pub block_count: [u8; 3], - _rsvd: u8, - pub block_length: [u8; 3], -} -unsafe impl plain::Plain for GeneralModeParamBlkDesc {} - -impl GeneralModeParamBlkDesc { - pub fn block_count(&self) -> u32 { - u24_be_to_u32(self.block_count) - } - pub fn logical_block_len(&self) -> u32 { - u24_be_to_u32(self.block_length) - } -} - -impl fmt::Debug for GeneralModeParamBlkDesc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("GeneralModeParamBlkDesc") - .field("density_code", &self.density_code) - .field("block_count", &u24_be_to_u32(self.block_count)) - .field("block_length", &u24_be_to_u32(self.block_length)) - .finish() - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct LongLbaModeParamBlkDesc { - pub block_count: u64, - _rsvd: u32, - pub logical_block_len: u32, -} -unsafe impl plain::Plain for LongLbaModeParamBlkDesc {} - -impl LongLbaModeParamBlkDesc { - pub const fn block_count(&self) -> u64 { - u64::from_be(self.block_count) - } - pub const fn logical_block_len(&self) -> u32 { - u32::from_be(self.logical_block_len) - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct ModeParamHeader6 { - pub mode_data_len: u8, - pub medium_ty: u8, - pub a: u8, - pub block_desc_len: u8, -} -unsafe impl plain::Plain for ModeParamHeader6 {} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct ModeParamHeader10 { - pub mode_data_len: u16, - pub medium_ty: u8, - pub a: u8, - pub b: u8, - _rsvd: u8, - pub block_desc_len: u16, -} -unsafe impl plain::Plain for ModeParamHeader10 {} -impl ModeParamHeader10 { - pub const fn mode_data_len(&self) -> u16 { - u16::from_be(self.mode_data_len) - } - pub const fn block_desc_len(&self) -> u16 { - u16::from_be(self.block_desc_len) - } - pub const fn longlba(&self) -> bool { - (self.b & 0x01) != 0 - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct ReadCapacity10 { - pub opcode: u8, - _rsvd1: u8, - obsolete_lba: u32, - _rsvd2: [u8; 3], - pub control: u8, -} -unsafe impl plain::Plain for ReadCapacity10 {} - -impl ReadCapacity10 { - pub const fn new(control: u8) -> Self { - Self { - opcode: Opcode::ReadCapacity10 as u8, - _rsvd1: 0, - obsolete_lba: 0, - _rsvd2: [0; 3], - control, - } - } -} -// TODO: ReadCapacity16 - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct ReadCapacity10ParamData { - pub max_lba: u32, - pub block_len: u32, -} -unsafe impl plain::Plain for ReadCapacity10ParamData {} - -impl ReadCapacity10ParamData { - pub const fn block_count(&self) -> u32 { - u32::from_be(self.max_lba) - } - pub const fn logical_block_len(&self) -> u32 { - u32::from_be(self.block_len) - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct RwErrorRecoveryPage { - pub a: u8, - pub page_length: u8, - pub b: u8, - pub read_retry_count: u8, - _obsolete: [u8; 3], - _rsvd: u8, - pub recovery_time_limit: u16, -} -unsafe impl plain::Plain for RwErrorRecoveryPage {} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct CachingModePage { - pub a: u8, - pub page_length: u8, - // TODO: more -} -unsafe impl plain::Plain for CachingModePage {} - -pub(crate) struct ModePageIterRaw<'a> { - buffer: &'a [u8], -} - -impl<'a> Iterator for ModePageIterRaw<'a> { - type Item = &'a [u8]; - - fn next(&mut self) -> Option { - if self.buffer.len() < 2 { - return None; - } - - let a = self.buffer[0]; - let page_len = if a & (1 << 6) == 0 { - // item is page_0 mode - self.buffer[1] as usize + 1 - } else { - // item is sub_page mode - u16::from_be_bytes((&self.buffer[2..3]).try_into().ok()?) as usize + 3 - }; - if self.buffer.len() < page_len { - return None; - } - let buffer = &self.buffer[..page_len]; - - self.buffer = if page_len == self.buffer.len() { - &[] - } else { - &self.buffer[page_len..] - }; - - Some(buffer) - } -} - -#[derive(Clone, Copy, Debug)] -pub enum AnyModePage<'a> { - RwErrorRecovery(&'a RwErrorRecoveryPage), - Caching(&'a CachingModePage), -} - -struct ModePageIter<'a> { - raw: ModePageIterRaw<'a>, -} - -impl<'a> Iterator for ModePageIter<'a> { - type Item = AnyModePage<'a>; - - fn next(&mut self) -> Option { - let next_buf = self.raw.next()?; - let a = next_buf[0]; - - let page_code = a & 0x1F; - let spf = a & (1 << 6) != 0; - - if !spf { - if page_code == 0x01 { - Some(AnyModePage::RwErrorRecovery( - plain::from_bytes(next_buf).ok()?, - )) - } else if page_code == 0x08 { - Some(AnyModePage::Caching(plain::from_bytes(next_buf).ok()?)) - } else { - println!("Unimplemented sub_page {}", base64::encode(next_buf)); - None - } - } else { - println!("Unimplemented page_0 {}", base64::encode(next_buf)); - None - } - } -} - -pub fn mode_page_iter(buffer: &[u8]) -> impl Iterator> { - ModePageIter { - raw: ModePageIterRaw { buffer }, - } -} diff --git a/recipes/core/base/drivers/storage/usbscsid/src/scsi/mod.rs b/recipes/core/base/drivers/storage/usbscsid/src/scsi/mod.rs deleted file mode 100644 index 790abea68c..0000000000 --- a/recipes/core/base/drivers/storage/usbscsid/src/scsi/mod.rs +++ /dev/null @@ -1,339 +0,0 @@ -use std::convert::TryFrom; -use std::mem; - -pub mod cmds; -pub mod opcodes; - -use thiserror::Error; -use xhcid_interface::DeviceReqData; - -use crate::protocol::{Protocol, ProtocolError, SendCommandStatus, SendCommandStatusKind}; -use cmds::StandardInquiryData; - -pub struct Scsi { - command_buffer: [u8; 16], - inquiry_buffer: [u8; 259], - data_buffer: Vec, - pub block_size: u32, - pub block_count: u64, -} - -const INQUIRY_CMD_LEN: u8 = 6; -const REPORT_SUPP_OPCODES_CMD_LEN: u8 = 12; -const REQUEST_SENSE_CMD_LEN: u8 = 6; -const MIN_INQUIRY_ALLOC_LEN: u16 = 5; -const MIN_REPORT_SUPP_OPCODES_ALLOC_LEN: u32 = 4; - -type Result = std::result::Result; - -#[derive(Debug, Error)] -pub enum ScsiError { - // TODO: Add some kind of context here, since it's very useful indeed to be able to see which - // command returned the protocol error. - #[error("protocol error when sending command: {0}")] - ProtocolError(#[from] ProtocolError), - - #[error("overflow")] - Overflow(&'static str), -} - -impl Scsi { - pub fn new(protocol: &mut dyn Protocol) -> Result { - assert_eq!(std::mem::size_of::(), 96); - - let mut this = Self { - command_buffer: [0u8; 16], - // separate buffer since the inquiry data is most likely going to be used in the - // future. - inquiry_buffer: [0u8; 259], // additional_len = 255 max - data_buffer: Vec::new(), - block_size: 0, - block_count: 0, - }; - - // Get the max length that the device supports, of the Standard Inquiry Data. - let max_inquiry_len = this.get_inquiry_alloc_len(protocol)?; - // Get the Standard Inquiry Data. - this.get_standard_inquiry_data(protocol, max_inquiry_len)?; - - let version = this.res_standard_inquiry_data().version(); - println!("Inquiry version: {}", version); - - let (block_size, block_count) = { - let (_, blkdescs, mode_page_iter) = this.get_mode_sense10(protocol)?; - - for page in mode_page_iter { - println!("PAGE: {:?}", page); - } - - // TODO: Can there be multiple disks at all? - if let Some(only_blkdesc) = blkdescs.get(0) { - println!("Found block desc: {:?}", only_blkdesc); - (only_blkdesc.block_size(), only_blkdesc.block_count()) - } else { - println!("read_capacity10"); - let r = this.read_capacity(protocol)?; - println!("read_capacity10 result: {:?}", r); - (r.logical_block_len(), r.block_count().into()) - } - }; - - this.block_size = block_size; - this.block_count = block_count; - - Ok(this) - } - pub fn get_inquiry_alloc_len(&mut self, protocol: &mut dyn Protocol) -> Result { - self.get_standard_inquiry_data(protocol, MIN_INQUIRY_ALLOC_LEN)?; - let standard_inquiry_data = self.res_standard_inquiry_data(); - Ok(4 + u16::from(standard_inquiry_data.additional_len)) - } - pub fn get_standard_inquiry_data( - &mut self, - protocol: &mut dyn Protocol, - max_inquiry_len: u16, - ) -> Result<()> { - let inquiry = self.cmd_inquiry(); - *inquiry = cmds::Inquiry::new(false, 0, max_inquiry_len, 0); - - protocol.send_command( - &self.command_buffer[..INQUIRY_CMD_LEN as usize], - DeviceReqData::In(&mut self.inquiry_buffer[..max_inquiry_len as usize]), - )?; - Ok(()) - } - pub fn get_ff_sense(&mut self, protocol: &mut dyn Protocol, alloc_len: u8) -> Result<()> { - let request_sense = self.cmd_request_sense(); - *request_sense = cmds::RequestSense::new(false, alloc_len, 0); - self.data_buffer.resize(alloc_len.into(), 0); - protocol.send_command( - &self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize], - DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize]), - )?; - Ok(()) - } - pub fn read_capacity( - &mut self, - protocol: &mut dyn Protocol, - ) -> Result<&cmds::ReadCapacity10ParamData> { - // The spec explicitly states that the allocation length is 8 bytes. - let read_capacity10 = self.cmd_read_capacity10(); - *read_capacity10 = cmds::ReadCapacity10::new(0); - self.data_buffer.resize(10usize, 0u8); - protocol.send_command( - &self.command_buffer[..10], - DeviceReqData::In(&mut self.data_buffer[..8]), - )?; - Ok(self.res_read_capacity10()) - } - pub fn get_mode_sense10( - &mut self, - protocol: &mut dyn Protocol, - ) -> Result<( - &cmds::ModeParamHeader10, - BlkDescSlice<'_>, - impl Iterator>, - )> { - let initial_alloc_len = mem::size_of::() as u16; // covers both mode_data_len and blk_desc_len. - let mode_sense10 = self.cmd_mode_sense10(); - *mode_sense10 = cmds::ModeSense10::get_block_desc(initial_alloc_len, 0); - self.data_buffer - .resize(mem::size_of::(), 0); - if let SendCommandStatus { - kind: SendCommandStatusKind::Failed, - .. - } = protocol.send_command( - &self.command_buffer[..10], - DeviceReqData::In(&mut self.data_buffer[..initial_alloc_len as usize]), - )? { - self.get_ff_sense(protocol, 252)?; - panic!("{:?}", self.res_ff_sense_data()); - } - - let optimal_alloc_len = self.res_mode_param_header10().mode_data_len() + 2; // the length of the mode data field itself - - let mode_sense10 = self.cmd_mode_sense10(); - *mode_sense10 = cmds::ModeSense10::get_block_desc(optimal_alloc_len, 0); - self.data_buffer.resize(optimal_alloc_len as usize, 0); - protocol.send_command( - &self.command_buffer[..10], - DeviceReqData::In(&mut self.data_buffer[..optimal_alloc_len as usize]), - )?; - Ok(( - self.res_mode_param_header10(), - self.res_blkdesc_mode10(), - self.res_mode_pages10(), - )) - } - - pub fn cmd_inquiry(&mut self) -> &mut cmds::Inquiry { - plain::from_mut_bytes(&mut self.command_buffer).unwrap() - } - pub fn cmd_mode_sense6(&mut self) -> &mut cmds::ModeSense6 { - plain::from_mut_bytes(&mut self.command_buffer).unwrap() - } - pub fn cmd_mode_sense10(&mut self) -> &mut cmds::ModeSense10 { - plain::from_mut_bytes(&mut self.command_buffer).unwrap() - } - pub fn cmd_request_sense(&mut self) -> &mut cmds::RequestSense { - plain::from_mut_bytes(&mut self.command_buffer).unwrap() - } - pub fn cmd_read_capacity10(&mut self) -> &mut cmds::ReadCapacity10 { - plain::from_mut_bytes(&mut self.command_buffer).unwrap() - } - pub fn cmd_read16(&mut self) -> &mut cmds::Read16 { - plain::from_mut_bytes(&mut self.command_buffer).unwrap() - } - pub fn cmd_write16(&mut self) -> &mut cmds::Write16 { - plain::from_mut_bytes(&mut self.command_buffer).unwrap() - } - pub fn res_standard_inquiry_data(&self) -> &StandardInquiryData { - plain::from_bytes(&self.inquiry_buffer).unwrap() - } - pub fn res_ff_sense_data(&self) -> &cmds::FixedFormatSenseData { - plain::from_bytes(&self.data_buffer).unwrap() - } - pub fn res_mode_param_header6(&self) -> &cmds::ModeParamHeader6 { - plain::from_bytes(&self.data_buffer).unwrap() - } - pub fn res_mode_param_header10(&self) -> &cmds::ModeParamHeader10 { - plain::from_bytes(&self.data_buffer).unwrap() - } - pub fn res_blkdesc_mode6(&self) -> &[cmds::ShortLbaModeParamBlkDesc] { - let header = self.res_mode_param_header6(); - let descs_start = mem::size_of::(); - plain::slice_from_bytes( - &self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)], - ) - .unwrap() - } - pub fn res_blkdesc_mode10(&self) -> BlkDescSlice<'_> { - let header = self.res_mode_param_header10(); - let descs_start = mem::size_of::(); - if header.longlba() { - BlkDescSlice::Long( - plain::slice_from_bytes( - &self.data_buffer - [descs_start..descs_start + usize::from(header.block_desc_len())], - ) - .unwrap(), - ) - } else if self.res_standard_inquiry_data().periph_dev_ty() - != cmds::PeriphDeviceType::DirectAccess as u8 - && self.res_standard_inquiry_data().version() == cmds::InquiryVersion::Spc3 as u8 - { - BlkDescSlice::General( - plain::slice_from_bytes( - &self.data_buffer - [descs_start..descs_start + usize::from(header.block_desc_len())], - ) - .unwrap(), - ) - } else { - BlkDescSlice::Short( - plain::slice_from_bytes( - &self.data_buffer - [descs_start..descs_start + usize::from(header.block_desc_len())], - ) - .unwrap(), - ) - } - } - - pub fn res_mode_pages10(&self) -> impl Iterator> { - let header = self.res_mode_param_header10(); - let descs_start = mem::size_of::(); - let buffer = &self.data_buffer[descs_start + header.block_desc_len() as usize..]; - cmds::mode_page_iter(buffer) - } - pub fn res_read_capacity10(&self) -> &cmds::ReadCapacity10ParamData { - plain::from_bytes(&self.data_buffer).unwrap() - } - pub fn get_disk_size(&self) -> u64 { - self.block_count * u64::from(self.block_size) - } - pub fn read( - &mut self, - protocol: &mut dyn Protocol, - lba: u64, - buffer: &mut [u8], - ) -> Result { - let blocks_to_read = buffer.len() as u64 / u64::from(self.block_size); - let bytes_to_read = blocks_to_read as usize * self.block_size as usize; - let transfer_len = u32::try_from(blocks_to_read).or(Err(ScsiError::Overflow( - "number of blocks to read couldn't fit inside a u32", - )))?; - { - let read = self.cmd_read16(); - *read = cmds::Read16::new(lba, transfer_len, 0); - } - // TODO: Use the to-be-written TransferReadStream instead of relying on everything being - // able to fit within a single buffer. - self.data_buffer.resize(bytes_to_read, 0u8); - let status = protocol.send_command( - &self.command_buffer[..16], - DeviceReqData::In(&mut self.data_buffer[..bytes_to_read]), - )?; - buffer[..bytes_to_read].copy_from_slice(&self.data_buffer[..bytes_to_read]); - Ok(status.bytes_transferred(bytes_to_read as u32)) - } - pub fn write(&mut self, protocol: &mut dyn Protocol, lba: u64, buffer: &[u8]) -> Result { - let blocks_to_write = buffer.len() as u64 / u64::from(self.block_size); - let bytes_to_write = blocks_to_write as usize * self.block_size as usize; - let transfer_len = u32::try_from(blocks_to_write).or(Err(ScsiError::Overflow( - "number of blocks to write couldn't fit inside a u32", - )))?; - { - let read = self.cmd_write16(); - *read = cmds::Write16::new(lba, transfer_len, 0); - } - // TODO: Use the to-be-written TransferReadStream instead of relying on everything being - // able to fit within a single buffer. - self.data_buffer.resize(bytes_to_write, 0u8); - self.data_buffer[..bytes_to_write].copy_from_slice(&buffer[..bytes_to_write]); - let status = protocol.send_command( - &self.command_buffer[..16], - DeviceReqData::Out(&buffer[..bytes_to_write]), - )?; - Ok(status.bytes_transferred(bytes_to_write as u32)) - } -} -#[derive(Debug)] -pub enum BlkDescSlice<'a> { - Short(&'a [cmds::ShortLbaModeParamBlkDesc]), - General(&'a [cmds::GeneralModeParamBlkDesc]), - Long(&'a [cmds::LongLbaModeParamBlkDesc]), -} - -#[derive(Debug)] -pub enum BlkDesc<'a> { - Short(&'a cmds::ShortLbaModeParamBlkDesc), - General(&'a cmds::GeneralModeParamBlkDesc), - Long(&'a cmds::LongLbaModeParamBlkDesc), -} -impl<'a> BlkDesc<'a> { - fn block_size(&self) -> u32 { - match self { - Self::Short(s) => s.logical_block_len(), - Self::General(g) => g.logical_block_len(), - Self::Long(l) => l.logical_block_len(), - } - } - fn block_count(&self) -> u64 { - match self { - Self::Short(s) => s.block_count().into(), - Self::General(g) => g.block_count().into(), - Self::Long(l) => l.block_count(), - } - } -} - -impl<'a> BlkDescSlice<'a> { - fn get(&self, idx: usize) -> Option> { - match self { - Self::Short(s) => s.get(idx).map(BlkDesc::Short), - Self::Long(l) => l.get(idx).map(BlkDesc::Long), - Self::General(g) => g.get(idx).map(BlkDesc::General), - } - } -} diff --git a/recipes/core/base/drivers/storage/usbscsid/src/scsi/opcodes.rs b/recipes/core/base/drivers/storage/usbscsid/src/scsi/opcodes.rs deleted file mode 100644 index d146238297..0000000000 --- a/recipes/core/base/drivers/storage/usbscsid/src/scsi/opcodes.rs +++ /dev/null @@ -1,112 +0,0 @@ -#[repr(u8)] -pub enum Opcode { - TestUnitReady = 0x00, - /// obsolete - RezeroUnit = 0x01, - RequestSense = 0x03, - FormatUnit = 0x04, - ReassignBlocks = 0x07, - /// obsolete - Read6 = 0x08, - /// obsolete - Write6 = 0x0A, - /// obsolete - Seek = 0x0B, - Inquiry = 0x12, - ModeSelect6 = 0x15, - /// obsolete - Reserve6 = 0x16, - /// obsolete - Release6 = 0x17, - ModeSense6 = 0x1A, - StartStopUnit = 0x1B, - RecvDiagnosticRes = 0x1C, - SendDiagnostic = 0x1D, - ReadCapacity10 = 0x25, - Read10 = 0x28, - Write10 = 0x2A, - /// obsolete - SeekExt = 0x2B, - WriteAndVerify10 = 0x2E, - Verify10 = 0x2F, - SyncCache10 = 0x35, - ReadDefectData10 = 0x37, - WriteBuf10 = 0x3B, - ReadBuf10 = 0x3C, - /// obsolete - ReadLong10 = 0x3E, - WriteLong10 = 0x3F, - /// obsolete - ChangeDef = 0x40, - WriteSame10 = 0x41, - Unmap = 0x42, - Sanitize = 0x48, - LogSelect = 0x4C, - LogSense = 0x4D, - ModeSelect10 = 0x55, - /// obsolete - Reserve10 = 0x56, - /// obsolete - Release10 = 0x57, - ModeSense10 = 0x5A, - PersistentResvIn = 0x5E, - PersistentResvOut = 0x5F, - ServiceAction7F = 0x7F, - Read16 = 0x88, - Write16 = 0x8A, - WriteAndVerify16 = 0x8E, - Verify16 = 0x8F, - SyncCache16 = 0x91, - WriteSame16 = 0x93, - WriteStream16 = 0x9A, - ReadBuf16 = 0x9B, - WriteAtomic16 = 0x9C, - ServiceAction9E = 0x9E, - ServiceAction9F, - ReportLuns = 0xA0, - SecurityProtoIn = 0xA2, - ServiceActionA3 = 0xA3, - ServiceActionA4 = 0xA4, - Read12 = 0xA8, - Write12 = 0xAA, - WriteAndVerify12 = 0xAE, - Verify12 = 0xAF, - SecurityProtoOut = 0xB5, - ReadDefectData12 = 0xB7, -} - -#[repr(u8)] -pub enum ServiceAction7F { - Read32 = 0x09, - Verify32 = 0x0A, - Write32 = 0x0B, - WriteAndVerify32 = 0x0C, - WriteSame32 = 0x0D, - WriteAtomic32 = 0x18, -} - -#[repr(u8)] -pub enum ServiceAction9E { - ReadCapacity16 = 0x10, - ReadLong16 = 0x11, - GetLbaStatus = 0x12, - StreamControl = 0x14, - BackgroundControl = 0x15, - GetStreamStatus = 0x16, -} -#[repr(u8)] -pub enum ServiceAction9F { - WriteLong16 = 0x11, -} -#[repr(u8)] -pub enum ServiceActionA3 { - ReportIdentInfo = 0x05, - ReportSuppOpcodes = 0x0C, - ReportSuppTaskManFuncs = 0x0D, - ReportTimestamp = 0x0F, -} -#[repr(u8)] -pub enum ServiceActionA4 { - SetIdentInfo = 0x06, - SetTimestamp = 0x0F, -} diff --git a/recipes/core/base/drivers/storage/virtio-blkd/Cargo.toml b/recipes/core/base/drivers/storage/virtio-blkd/Cargo.toml deleted file mode 100644 index cd8fc6d2de..0000000000 --- a/recipes/core/base/drivers/storage/virtio-blkd/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -name = "virtio-blkd" -description = "VirtIO block (storage) driver" -version = "0.1.0" -edition = "2021" -authors = ["Anhad Singh "] - -[dependencies] -anyhow.workspace = true -log.workspace = true -thiserror.workspace = true -static_assertions.workspace = true -futures = { version = "0.3.28", features = ["executor"] } -spin.workspace = true - -redox_event.workspace = true -redox_syscall = { workspace = true, features = ["std"] } - -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -driver-block = { path = "../driver-block" } -pcid = { path = "../../pcid" } -virtio-core = { path = "../../virtio-core" } -libredox.workspace = true - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/storage/virtio-blkd/src/main.rs b/recipes/core/base/drivers/storage/virtio-blkd/src/main.rs deleted file mode 100644 index d21236b377..0000000000 --- a/recipes/core/base/drivers/storage/virtio-blkd/src/main.rs +++ /dev/null @@ -1,182 +0,0 @@ -#![deny(trivial_numeric_casts, unused_allocation)] - -use std::collections::BTreeMap; -use std::sync::{Arc, Weak}; - -use driver_block::DiskScheme; -use static_assertions::const_assert_eq; - -use pcid_interface::*; -use virtio_core::spec::*; - -use virtio_core::transport::Transport; -use virtio_core::utils::VolatileCell; - -mod scheme; - -use thiserror::Error; - -use crate::scheme::VirtioDisk; - -#[derive(Debug, Error)] -pub enum Error { - #[error("capability {0:?} not found")] - InCapable(CfgType), - #[error("failed to map memory")] - Physmap, - #[error("failed to allocate an interrupt vector")] - ExhaustedInt, - #[error("syscall error")] - SyscallError(syscall::Error), -} - -#[repr(C)] -pub struct BlockGeometry { - pub cylinders: VolatileCell, - pub heads: VolatileCell, - pub sectors: VolatileCell, -} - -#[repr(u8)] -pub enum DeviceConfigTy { - Capacity = 0, - SizeMax = 0x8, - SeqMax = 0xc, - Geometry = 0x10, - BlkSize = 0x14, -} - -pub struct BlockDeviceConfig(Weak); - -impl BlockDeviceConfig { - #[inline] - fn new(tranport: &Arc) -> Self { - Self(Arc::downgrade(&tranport)) - } - - pub fn load_config(&self, ty: DeviceConfigTy) -> T - where - T: Sized + TryFrom, - >::Error: std::fmt::Debug, - { - let transport = self.0.upgrade().unwrap(); - - let size = core::mem::size_of::() - .try_into() - .expect("load_config: invalid size"); - - let value = transport.load_config(ty as u8, size); - T::try_from(value).unwrap() - } - - /// Returns the capacity of the block device in bytes. - #[inline] - pub fn capacity(&self) -> u64 { - self.load_config(DeviceConfigTy::Capacity) - } - - #[inline] - pub fn block_size(&self) -> u32 { - self.load_config(DeviceConfigTy::BlkSize) - } -} - -#[repr(u32)] -pub enum BlockRequestTy { - In = 0, - Out = 1, -} - -const_assert_eq!(core::mem::size_of::(), 4); - -#[repr(C)] -pub struct BlockVirtRequest { - pub ty: BlockRequestTy, - pub reserved: u32, - pub sector: u64, -} - -const_assert_eq!(core::mem::size_of::(), 16); - -fn main() { - pcid_interface::pci_daemon(daemon_runner); -} - -fn daemon_runner(redox_daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! { - daemon(redox_daemon, pcid_handle).unwrap(); - unreachable!(); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow::Result<()> { - common::setup_logging( - "disk", - "pci", - "virtio-blkd", - common::output_level(), - common::file_level(), - ); - - // Double check that we have the right device. - // - // 0x1001 - virtio-blk - let pci_config = pcid_handle.config(); - - assert_eq!(pci_config.func.full_device_id.device_id, 0x1001); - log::info!("virtio-blk: initiating startup sequence :^)"); - - let device = virtio_core::probe_device(&mut pcid_handle)?; - device.transport.finalize_features(); - - let queue = device - .transport - .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR, &device.irq_handle)?; - - let device_space = BlockDeviceConfig::new(&device.transport); - - // At this point the device is alive! - device.transport.run_device(); - - log::info!( - "virtio-blk: disk size: {} sectors and block size of {} bytes", - device_space.capacity(), - device_space.block_size() - ); - - let mut name = pci_config.func.name(); - name.push_str("_virtio_blk"); - - let scheme_name = format!("disk.{}", name); - - let event_queue = event::EventQueue::new().unwrap(); - - event::user_data! { - enum Event { - Scheme, - } - }; - - let mut scheme = DiskScheme::new( - Some(daemon), - scheme_name, - BTreeMap::from([(0, VirtioDisk::new(queue, device_space))]), - &driver_block::FuturesExecutor, - ); - - libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - - event_queue - .subscribe( - scheme.event_handle().raw(), - Event::Scheme, - event::EventFlags::READ, - ) - .unwrap(); - - for event in event_queue { - match event.unwrap().user_data { - Event::Scheme => futures::executor::block_on(scheme.tick()).unwrap(), - } - } - - Ok(()) -} diff --git a/recipes/core/base/drivers/storage/virtio-blkd/src/scheme.rs b/recipes/core/base/drivers/storage/virtio-blkd/src/scheme.rs deleted file mode 100644 index ec4ecf732d..0000000000 --- a/recipes/core/base/drivers/storage/virtio-blkd/src/scheme.rs +++ /dev/null @@ -1,103 +0,0 @@ -use std::sync::Arc; - -use common::dma::Dma; -use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; -use virtio_core::transport::Queue; - -use crate::BlockDeviceConfig; -use crate::BlockRequestTy; -use crate::BlockVirtRequest; - -trait BlkExtension { - async fn read(&self, block: u64, target: &mut [u8]) -> usize; - async fn write(&self, block: u64, target: &[u8]) -> usize; -} - -impl BlkExtension for Queue<'_> { - async fn read(&self, block: u64, target: &mut [u8]) -> usize { - let req = Dma::new(BlockVirtRequest { - ty: BlockRequestTy::In, - reserved: 0, - sector: block, - }) - .unwrap(); - - let result = unsafe { - Dma::<[u8]>::zeroed_slice(target.len()) - .unwrap() - .assume_init() - }; - let status = Dma::new(u8::MAX).unwrap(); - - let chain = ChainBuilder::new() - .chain(Buffer::new(&req)) - .chain(Buffer::new_unsized(&result).flags(DescriptorFlags::WRITE_ONLY)) - .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - // XXX: Subtract 1 because the of status byte. - let written = self.send(chain).await as usize - 1; - assert_eq!(*status, 0); - - target[..written].copy_from_slice(&result); - written - } - - async fn write(&self, block: u64, target: &[u8]) -> usize { - let req = Dma::new(BlockVirtRequest { - ty: BlockRequestTy::Out, - reserved: 0, - sector: block, - }) - .unwrap(); - - let mut result = unsafe { - Dma::<[u8]>::zeroed_slice(target.len()) - .unwrap() - .assume_init() - }; - result.copy_from_slice(target.as_ref()); - - let status = Dma::new(u8::MAX).unwrap(); - - let chain = ChainBuilder::new() - .chain(Buffer::new(&req)) - .chain(Buffer::new_sized(&result, target.len())) - .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - self.send(chain).await as usize; - assert_eq!(*status, 0); - - target.len() - } -} - -pub(crate) struct VirtioDisk<'a> { - queue: Arc>, - cfg: BlockDeviceConfig, -} - -impl<'a> VirtioDisk<'a> { - pub(crate) fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { - Self { queue, cfg } - } -} - -impl driver_block::Disk for VirtioDisk<'_> { - fn block_size(&self) -> u32 { - self.cfg.block_size() - } - - fn size(&self) -> u64 { - self.cfg.capacity() * u64::from(self.cfg.block_size()) - } - - async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { - Ok(self.queue.read(block, buffer).await) - } - - async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { - Ok(self.queue.write(block, buffer).await) - } -} diff --git a/recipes/core/base/drivers/thermald/Cargo.toml b/recipes/core/base/drivers/thermald/Cargo.toml deleted file mode 100644 index 65255ebaa0..0000000000 --- a/recipes/core/base/drivers/thermald/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "thermald" -version = "0.1.0" -edition = "2021" - -[dependencies] -log.workspace = true -anyhow.workspace = true -common = { path = "../common" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/thermald/src/main.rs b/recipes/core/base/drivers/thermald/src/main.rs deleted file mode 100644 index 3db4dd55ba..0000000000 --- a/recipes/core/base/drivers/thermald/src/main.rs +++ /dev/null @@ -1,30 +0,0 @@ -use anyhow::{Context, Result}; -use std::{thread, time}; - -fn read_temp() -> Option { - for zone in 0..4 { - let path = format!("/scheme/acpi/thermal_zone/{}/temperature", zone); - if let Ok(data) = std::fs::read_to_string(&path) { - if let Ok(mv) = data.trim().parse::() { - return Some(mv as f32 / 1000.0); - } - } - } - None -} - -fn main() -> Result<()> { - common::setup_logging("system", "thermald", "thermald", - common::output_level(), common::file_level()); - log::info!("thermald: started"); - loop { - if let Some(temp) = read_temp() { - if temp > 85.0 { - log::error!("thermald: CRITICAL {:.1}C", temp); - } else if temp > 70.0 { - log::warn!("thermald: WARNING {:.1}C", temp); - } - } - thread::sleep(time::Duration::from_secs(5)); - } -} diff --git a/recipes/core/base/drivers/usb/ucsid/Cargo.toml b/recipes/core/base/drivers/usb/ucsid/Cargo.toml deleted file mode 100644 index 1a6833e500..0000000000 --- a/recipes/core/base/drivers/usb/ucsid/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "ucsid" -description = "USB-C UCSI topology daemon" -version = "0.1.0" -edition = "2021" - -[dependencies] -anyhow.workspace = true -log.workspace = true -redox_syscall = { workspace = true, features = ["std"] } -libredox.workspace = true -redox-scheme.workspace = true -serde.workspace = true -ron.workspace = true - -acpi-resource = { path = "../../acpi-resource" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -i2c-interface = { path = "../../i2c/i2c-interface" } -scheme-utils = { path = "../../../scheme-utils" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/usb/ucsid/src/main.rs b/recipes/core/base/drivers/usb/ucsid/src/main.rs deleted file mode 100644 index d00cfbcfe1..0000000000 --- a/recipes/core/base/drivers/usb/ucsid/src/main.rs +++ /dev/null @@ -1,839 +0,0 @@ -use std::collections::BTreeMap; -use std::fs::{self, File, OpenOptions}; -use std::io::{Read, Write}; -use std::path::Path; -use std::process; - -use acpi_resource::{ - AddressResourceType, FixedMemory32Descriptor, I2cSerialBusDescriptor, Memory32RangeDescriptor, - ResourceDescriptor, -}; -use anyhow::{bail, Context, Result}; -use i2c_interface::{ - I2cAdapterInfo, I2cControlRequest, I2cControlResponse, I2cTransferRequest, - I2cTransferSegment, -}; -use libredox::flag::{O_CLOEXEC, O_RDWR}; -use redox_scheme::scheme::SchemeSync; -use redox_scheme::{CallerCtx, OpenResult, Socket}; -use scheme_utils::{Blocking, HandleMap}; -use serde::{Deserialize, Serialize}; -use syscall::schemev2::NewFdFlags; -use syscall::{Error as SysError, EACCES, EBADF, EINVAL, ENOENT}; - -const SUPPORTED_IDS: &[&str] = &["PNP0CA0", "AMDI0042"]; -const GET_CAPABILITY: u8 = 0x01; -const GET_CONNECTOR_STATUS: u8 = 0x10; -const UCSI_RESPONSE_HEADER_LEN: usize = 4; -const UCSI_CAPABILITY_READ_LEN: usize = 20; -const UCSI_CONNECTOR_STATUS_READ_LEN: usize = 20; -const MAX_CONNECTOR_PROBE: u8 = 8; - -#[derive(Debug, Deserialize)] -struct AmlSymbol { - name: String, - value: AmlValue, -} - -#[derive(Debug, Deserialize)] -enum AmlValue { - Integer(u64), - String(String), -} - -#[derive(Clone, Copy, Debug)] -struct UcsiCommand { - command: u8, - data_length: u8, - specific_data: [u8; 6], -} - -impl UcsiCommand { - fn new(command: u8, data_length: u8, specific_data: [u8; 6]) -> Self { - Self { - command, - data_length, - specific_data, - } - } - - fn as_bytes(self) -> [u8; 8] { - let mut bytes = [0_u8; 8]; - bytes[0] = self.command; - bytes[1] = self.data_length; - bytes[2..].copy_from_slice(&self.specific_data); - bytes - } -} - -#[derive(Clone, Copy, Debug)] -struct UcsiResponseHeader { - _status: u16, - data_length: u16, -} - -impl UcsiResponseHeader { - fn parse(bytes: &[u8]) -> Option { - let header = bytes.get(..UCSI_RESPONSE_HEADER_LEN)?; - Some(Self { - _status: u16::from_le_bytes([header[0], header[1]]), - data_length: u16::from_le_bytes([header[2], header[3]]), - }) - } -} - -#[derive(Clone, Debug)] -struct DiscoveredUcsiDevice { - name: String, - hid: String, - transport: UcsiTransport, - dsm_probe: bool, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -enum UcsiTransport { - I2c { - adapter: String, - address: u16, - ten_bit_address: bool, - }, - Mmio { - base: usize, - len: usize, - }, - Unknown, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -struct UcsiCapability { - connector_count: u8, - supports_usb_pd: bool, - supports_alt_modes: bool, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -struct UcsiConnectorSummary { - device: String, - connector_number: u8, - connected: bool, - data_role: String, - power_direction: String, - input_critical: bool, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -struct UcsiDeviceSummary { - name: String, - hid: String, - transport: UcsiTransport, - capability: Option, - connectors: Vec, - dsm_probe: bool, - issues: Vec, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -struct UcsiSummary { - schema_version: u32, - device_count: usize, - connector_count: usize, - input_critical_ports: usize, - devices: Vec, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -struct UcsiHealth { - healthy: bool, - scanned_devices: usize, - responsive_devices: usize, - issues: Vec, -} - -struct UcsiState { - summary: UcsiSummary, - connectors: Vec, - health: UcsiHealth, -} - -enum Handle { - SchemeRoot, - Summary { pending: Vec }, - Connectors { pending: Vec }, - Health { pending: Vec }, -} - -struct UcsiScheme { - handles: HandleMap, - state: UcsiState, -} - -impl UcsiScheme { - fn new(state: UcsiState) -> Self { - Self { - handles: HandleMap::new(), - state, - } - } - - fn serialize_payload(value: &T) -> syscall::Result> { - ron::ser::to_string(value) - .map(|text| text.into_bytes()) - .map_err(|err| { - log::error!("ucsid: failed to serialize scheme payload: {err}"); - SysError::new(EINVAL) - }) - } - - fn set_pending(handle: &mut Handle, pending: Vec) -> syscall::Result<()> { - match handle { - Handle::Summary { pending: slot } - | Handle::Connectors { pending: slot } - | Handle::Health { pending: slot } => { - *slot = pending; - Ok(()) - } - Handle::SchemeRoot => Err(SysError::new(EBADF)), - } - } - - fn copy_pending(handle: &mut Handle, buf: &mut [u8], offset: u64) -> syscall::Result { - let pending = match handle { - Handle::Summary { pending } - | Handle::Connectors { pending } - | Handle::Health { pending } => pending, - Handle::SchemeRoot => return Err(SysError::new(EBADF)), - }; - - let offset = usize::try_from(offset).map_err(|_| SysError::new(EINVAL))?; - if offset >= pending.len() { - return Ok(0); - } - - let copy_len = buf.len().min(pending.len() - offset); - buf[..copy_len].copy_from_slice(&pending[offset..offset + copy_len]); - Ok(copy_len) - } -} - -impl SchemeSync for UcsiScheme { - fn scheme_root(&mut self) -> syscall::Result { - Ok(self.handles.insert(Handle::SchemeRoot)) - } - - fn openat( - &mut self, - dirfd: usize, - path: &str, - _flags: usize, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> syscall::Result { - if !matches!(self.handles.get(dirfd)?, Handle::SchemeRoot) { - return Err(SysError::new(EACCES)); - } - - let handle = match path.trim_matches('/') { - "summary" => Handle::Summary { - pending: Vec::new(), - }, - "connectors" => Handle::Connectors { - pending: Vec::new(), - }, - "health" => Handle::Health { - pending: Vec::new(), - }, - "" => return Err(SysError::new(EINVAL)), - _ => return Err(SysError::new(ENOENT)), - }; - - let fd = self.handles.insert(handle); - Ok(OpenResult::ThisScheme { - number: fd, - flags: NewFdFlags::empty(), - }) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> syscall::Result { - let payload = match self.handles.get(id)? { - Handle::Summary { pending } if pending.is_empty() => { - Some(Self::serialize_payload(&self.state.summary)?) - } - Handle::Connectors { pending } if pending.is_empty() => { - Some(Self::serialize_payload(&self.state.connectors)?) - } - Handle::Health { pending } if pending.is_empty() => { - log::info!( - "RB_UCSID_HEALTH healthy={} scanned_devices={} responsive_devices={} issues={}", - self.state.health.healthy, - self.state.health.scanned_devices, - self.state.health.responsive_devices, - self.state.health.issues.len(), - ); - Some(Self::serialize_payload(&self.state.health)?) - } - _ => None, - }; - - let handle = self.handles.get_mut(id)?; - if let Some(payload) = payload { - Self::set_pending(handle, payload)?; - } - Self::copy_pending(handle, buf, offset) - } -} - -fn main() { - common::setup_logging( - "usb", - "ucsi", - "ucsid", - common::output_level(), - common::file_level(), - ); - - daemon::SchemeDaemon::new(daemon_runner); -} - -fn daemon_runner(daemon: daemon::SchemeDaemon) -> ! { - if let Err(err) = run_daemon(daemon) { - log::error!("ucsid: {err:#}"); - process::exit(1); - } - - process::exit(0); -} - -fn run_daemon(daemon: daemon::SchemeDaemon) -> Result<()> { - log::info!("RB_UCSID_SCHEMA version=1"); - - let state = build_state().context("failed to build UCSI device snapshot")?; - let socket = Socket::create().context("failed to create ucsi scheme socket")?; - let mut scheme = UcsiScheme::new(state); - let handler = Blocking::new(&socket, 16); - - daemon - .ready_sync_scheme(&socket, &mut scheme) - .context("failed to publish ucsi scheme root")?; - - libredox::call::setrens(0, 0).context("failed to enter null namespace")?; - - handler - .process_requests_blocking(scheme) - .context("failed to process ucsid requests")?; -} - -fn build_state() -> Result { - let adapters = list_i2c_adapters().unwrap_or_else(|err| { - log::warn!("ucsid: failed to query i2cd adapters: {err:#}"); - Vec::new() - }); - let devices = discover_ucsi_devices().context("failed to discover ACPI UCSI devices")?; - - let mut summaries = Vec::new(); - let mut connectors = Vec::new(); - let mut issues = Vec::new(); - let mut responsive_devices = 0usize; - - for device in devices { - log::info!( - "RB_UCSID_DEVICE name={} hid={} transport={:?} dsm_probe={}", - device.name, - device.hid, - device.transport, - device.dsm_probe, - ); - let summary = summarize_device(device, &adapters) - .context("failed to summarize discovered UCSI device")?; - if summary.capability.is_some() { - responsive_devices += 1; - } - issues.extend(summary.issues.iter().cloned()); - connectors.extend(summary.connectors.iter().cloned()); - summaries.push(summary); - } - - let summary = UcsiSummary { - schema_version: 1, - device_count: summaries.len(), - connector_count: connectors.len(), - input_critical_ports: connectors.iter().filter(|connector| connector.input_critical).count(), - devices: summaries, - }; - let health = UcsiHealth { - healthy: issues.is_empty(), - scanned_devices: summary.device_count, - responsive_devices, - issues, - }; - - log::info!( - "RB_UCSID_SUMMARY devices={} connectors={} input_critical_ports={} healthy={}", - summary.device_count, - summary.connector_count, - summary.input_critical_ports, - health.healthy, - ); - - Ok(UcsiState { - summary, - connectors, - health, - }) -} - -fn discover_ucsi_devices() -> Result> { - let mut matched = BTreeMap::new(); - - let entries = match fs::read_dir("/scheme/acpi/symbols") { - Ok(entries) => entries, - Err(err) if err.kind() == std::io::ErrorKind::WouldBlock || err.raw_os_error() == Some(11) => { - log::debug!("ucsid: ACPI symbols are not ready yet"); - return Ok(Vec::new()); - } - Err(err) => return Err(err).context("failed to read /scheme/acpi/symbols"), - }; - - for entry in entries { - let entry = entry.context("failed to read ACPI symbol directory entry")?; - let Some(file_name) = entry.file_name().to_str().map(str::to_owned) else { - continue; - }; - if !file_name.ends_with("_HID") && !file_name.ends_with("_CID") { - continue; - } - - let Some(id) = read_symbol_id(&entry.path())? else { - continue; - }; - if !SUPPORTED_IDS.iter().any(|candidate| *candidate == id) { - continue; - } - - let Some(device) = file_name - .strip_suffix("_HID") - .or_else(|| file_name.strip_suffix("_CID")) - .map(str::to_owned) - else { - continue; - }; - matched.entry(device).or_insert(id); - } - - let mut devices = Vec::new(); - for (device, hid) in matched { - let transport = read_ucsi_transport(&device) - .with_context(|| format!("failed to decode transport resources for {device}"))?; - let dsm_probe = bounded_dsm_probe(&device).unwrap_or_else(|err| { - log::debug!("ucsid: bounded _DSM probe failed for {device}: {err:#}"); - false - }); - devices.push(DiscoveredUcsiDevice { - name: device, - hid, - transport, - dsm_probe, - }); - } - - Ok(devices) -} - -fn summarize_device(device: DiscoveredUcsiDevice, adapters: &[I2cAdapterInfo]) -> Result { - let mut issues = Vec::new(); - let capability = match &device.transport { - UcsiTransport::I2c { - adapter, - address, - ten_bit_address, - } => match match_i2c_adapter(adapters, adapter) { - Some(adapter_info) => match execute_ucsi_i2c_command( - adapter_info, - adapter, - *address, - *ten_bit_address, - UcsiCommand::new(GET_CAPABILITY, 0, [0; 6]), - UCSI_CAPABILITY_READ_LEN, - ) { - Ok(bytes) => parse_ucsi_payload(&bytes) - .and_then(|(_header, payload)| parse_capability(payload)) - .or_else(|| { - issues.push(format!( - "{}: GET_CAPABILITY returned an unexpected payload", - device.name - )); - None - }), - Err(err) => { - issues.push(format!("{}: GET_CAPABILITY failed: {err:#}", device.name)); - None - } - }, - None => { - issues.push(format!( - "{}: no i2cd adapter matched ACPI source {}", - device.name, adapter - )); - None - } - }, - UcsiTransport::Mmio { base, len } => { - issues.push(format!( - "{}: MMIO UCSI transport discovered at {base:#x}+{len:#x} but command execution is not implemented yet", - device.name, - )); - None - } - UcsiTransport::Unknown => { - issues.push(format!( - "{}: no supported UCSI transport was decoded from ACPI resources", - device.name, - )); - None - } - }; - - let connector_count = capability - .as_ref() - .map(|capability| capability.connector_count.min(MAX_CONNECTOR_PROBE)) - .unwrap_or(0); - let mut connectors = Vec::new(); - for connector in 1..=connector_count { - match query_connector_status(&device, adapters, connector) { - Ok(connector_summary) => connectors.push(connector_summary), - Err(err) => issues.push(format!( - "{}: GET_CONNECTOR_STATUS({connector}) failed: {err:#}", - device.name, - )), - } - } - - Ok(UcsiDeviceSummary { - name: device.name, - hid: device.hid, - transport: device.transport, - capability, - connectors, - dsm_probe: device.dsm_probe, - issues, - }) -} - -fn read_ucsi_transport(device: &str) -> Result { - let contents = fs::read_to_string(format!("/scheme/acpi/resources/{device}")) - .with_context(|| format!("failed to read /scheme/acpi/resources/{device}"))?; - let resources = ron::from_str::>(&contents) - .with_context(|| format!("failed to decode RON resources for {device}"))?; - - let mut i2c = None::; - let mut mmio = None::<(usize, usize)>; - - for resource in resources { - match resource { - ResourceDescriptor::I2cSerialBus(bus) if i2c.is_none() => i2c = Some(bus), - ResourceDescriptor::FixedMemory32(FixedMemory32Descriptor { - address, - address_length, - .. - }) if mmio.is_none() => { - mmio = Some((address as usize, address_length as usize)); - } - ResourceDescriptor::Memory32Range(Memory32RangeDescriptor { - minimum, - maximum, - address_length, - .. - }) if mmio.is_none() && maximum >= minimum => { - let span = maximum.saturating_sub(minimum).saturating_add(1) as usize; - mmio = Some((minimum as usize, span.max(address_length as usize))); - } - ResourceDescriptor::Address32(descriptor) - if mmio.is_none() - && matches!(descriptor.resource_type, AddressResourceType::MemoryRange) => - { - mmio = Some((descriptor.minimum as usize, descriptor.address_length as usize)); - } - ResourceDescriptor::Address64(descriptor) - if mmio.is_none() - && matches!(descriptor.resource_type, AddressResourceType::MemoryRange) => - { - let base = usize::try_from(descriptor.minimum) - .context("64-bit MMIO base does not fit in usize")?; - let len = usize::try_from(descriptor.address_length) - .context("64-bit MMIO length does not fit in usize")?; - mmio = Some((base, len)); - } - _ => {} - } - } - - if let Some(bus) = i2c { - let adapter = bus - .resource_source - .as_ref() - .map(|source| source.source.clone()) - .filter(|source| !source.is_empty()) - .unwrap_or_else(|| String::from("ACPI-I2C")); - return Ok(UcsiTransport::I2c { - adapter, - address: bus.slave_address, - ten_bit_address: bus.access_mode_10bit, - }); - } - if let Some((base, len)) = mmio { - return Ok(UcsiTransport::Mmio { base, len }); - } - Ok(UcsiTransport::Unknown) -} - -fn bounded_dsm_probe(device: &str) -> Result { - let symbol_name = format!("{}.{}", normalize_device_path(device), "_DSM"); - let symbol_path = format!("/scheme/acpi/symbols/{symbol_name}"); - let fd = match libredox::Fd::open(&symbol_path, O_RDWR | O_CLOEXEC, 0) { - Ok(fd) => fd, - Err(err) => { - log::debug!("ucsid: {} has no callable _DSM: {err}", device); - return Ok(false); - } - }; - - let mut payload = ron::to_string(&Vec::::new()) - .context("failed to serialize bounded _DSM probe arguments")? - .into_bytes(); - payload.resize(payload.len() + 1024, 0); - match libredox::call::call_ro(fd.raw(), &mut payload, syscall::CallFlags::empty(), &[]) { - Ok(_) => Ok(true), - Err(err) => { - log::debug!("ucsid: bounded _DSM probe for {} failed: {err}", device); - Ok(false) - } - } -} - -fn parse_capability(payload: &[u8]) -> Option { - let connector_count = *payload.first()?; - let flags = payload.get(1).copied().unwrap_or(0); - Some(UcsiCapability { - connector_count, - supports_usb_pd: flags & 0x01 != 0, - supports_alt_modes: flags & 0x02 != 0, - }) -} - -fn query_connector_status( - device: &DiscoveredUcsiDevice, - adapters: &[I2cAdapterInfo], - connector: u8, -) -> Result { - match &device.transport { - UcsiTransport::I2c { - adapter, - address, - ten_bit_address, - } => { - let adapter_info = match_i2c_adapter(adapters, adapter).with_context(|| { - format!("no i2cd adapter matched ACPI source {} for {}", adapter, device.name) - })?; - let bytes = execute_ucsi_i2c_command( - adapter_info, - adapter, - *address, - *ten_bit_address, - UcsiCommand::new(GET_CONNECTOR_STATUS, 1, [connector, 0, 0, 0, 0, 0]), - UCSI_CONNECTOR_STATUS_READ_LEN, - )?; - let (_header, payload) = parse_ucsi_payload(&bytes) - .with_context(|| format!("{}: malformed connector-status response", device.name))?; - Ok(parse_connector_summary(&device.name, connector, payload)) - } - UcsiTransport::Mmio { base, len } => bail!( - "MMIO connector-status transport is not implemented yet for {:#x}+{:#x}", - base, - len, - ), - UcsiTransport::Unknown => bail!("unknown UCSI transport"), - } -} - -fn parse_connector_summary(device_name: &str, connector: u8, payload: &[u8]) -> UcsiConnectorSummary { - let state = payload.first().copied().unwrap_or(0); - let connected = state & 0x01 != 0; - let power_direction = if state & 0x02 != 0 { "source" } else { "sink" }; - let data_role = if state & 0x04 != 0 { "dfp" } else { "ufp" }; - UcsiConnectorSummary { - device: device_name.to_string(), - connector_number: connector, - connected, - data_role: data_role.to_string(), - power_direction: power_direction.to_string(), - input_critical: classify_input_critical(device_name), - } -} - -fn classify_input_critical(device_name: &str) -> bool { - let normalized = device_name.to_ascii_lowercase(); - normalized.contains("kbd") - || normalized.contains("key") - || normalized.contains("touch") - || normalized.contains("thc") -} - -fn parse_ucsi_payload(bytes: &[u8]) -> Option<(UcsiResponseHeader, &[u8])> { - let header = UcsiResponseHeader::parse(bytes)?; - let body = bytes.get(UCSI_RESPONSE_HEADER_LEN..)?; - let body_len = usize::from(header.data_length).min(body.len()); - Some((header, &body[..body_len])) -} - -fn execute_ucsi_i2c_command( - adapter: &I2cAdapterInfo, - adapter_name: &str, - address: u16, - ten_bit_address: bool, - command: UcsiCommand, - read_len: usize, -) -> Result> { - let request = I2cTransferRequest { - adapter: adapter_name.to_string(), - segments: vec![ - I2cTransferSegment { - address, - ten_bit_address, - op: i2c_interface::I2cTransferOp::Write(command.as_bytes().to_vec()), - }, - I2cTransferSegment { - address, - ten_bit_address, - op: i2c_interface::I2cTransferOp::Read(read_len), - }, - ], - stop: true, - }; - - let mut file = OpenOptions::new() - .read(true) - .write(true) - .open("/scheme/i2c/transfer") - .context("failed to open /scheme/i2c/transfer")?; - let payload = ron::ser::to_string(&I2cControlRequest::Transfer { - adapter_id: adapter.id, - request, - }) - .context("failed to encode UCSI I2C transfer request")?; - file.write_all(payload.as_bytes()) - .context("failed to send UCSI I2C transfer request")?; - - let response = read_i2c_control_response(&mut file)?; - match response { - I2cControlResponse::TransferResult(result) => { - if !result.ok { - let detail = result - .error - .clone() - .unwrap_or_else(|| String::from("unknown I2C transfer failure")); - bail!("UCSI I2C transfer failed: {detail}"); - } - result - .read_data - .into_iter() - .next() - .context("UCSI I2C transfer returned no response payload") - } - I2cControlResponse::Error(message) => bail!("i2cd returned an error: {message}"), - other => bail!("unexpected i2cd transfer response: {other:?}"), - } -} - -fn list_i2c_adapters() -> Result> { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .open("/scheme/i2c/adapters") - .context("failed to open /scheme/i2c/adapters")?; - - let payload = ron::ser::to_string(&I2cControlRequest::ListAdapters) - .context("failed to encode I2C list-adapters request")?; - file.write_all(payload.as_bytes()) - .context("failed to request I2C adapter list")?; - - let response = read_i2c_control_response(&mut file)?; - match response { - I2cControlResponse::AdapterList(adapters) => Ok(adapters), - I2cControlResponse::Error(message) => bail!("i2cd returned an error: {message}"), - other => bail!("unexpected i2cd list-adapters response: {other:?}"), - } -} - -fn match_i2c_adapter<'a>(adapters: &'a [I2cAdapterInfo], wanted: &str) -> Option<&'a I2cAdapterInfo> { - adapters - .iter() - .find(|adapter| adapter.name == wanted) - .or_else(|| adapters.iter().find(|adapter| adapter.name.ends_with(wanted))) - .or_else(|| adapters.iter().find(|adapter| wanted.ends_with(&adapter.name))) -} - -fn read_i2c_control_response(file: &mut File) -> Result { - let mut buffer = vec![0_u8; 4096]; - let count = file - .read(&mut buffer) - .context("failed to read I2C control response")?; - buffer.truncate(count); - let text = std::str::from_utf8(&buffer).context("I2C control response was not UTF-8")?; - let trimmed = text.trim(); - if trimmed.is_empty() { - return Ok(I2cControlResponse::AdapterList(Vec::new())); - } - ron::from_str(trimmed).context("failed to decode I2C control response") -} - -fn read_symbol_id(path: &Path) -> Result> { - let contents = fs::read_to_string(path) - .with_context(|| format!("failed to read ACPI symbol {}", path.display()))?; - let symbol = match ron::from_str::(&contents) { - Ok(symbol) => symbol, - Err(err) => { - log::debug!( - "ucsid: skipping {} because the symbol payload was not a scalar ID: {err}", - path.display(), - ); - return Ok(None); - } - }; - - let id = match symbol.value { - AmlValue::Integer(integer) => eisa_id_from_integer(integer), - AmlValue::String(string) => string, - }; - - log::debug!("ucsid: {} -> {id}", symbol.name); - Ok(Some(id)) -} - -fn normalize_device_path(path: &str) -> String { - path.trim_start_matches('\\') - .trim_matches('/') - .replace('/', ".") -} - -fn eisa_id_from_integer(integer: u64) -> String { - let vendor = integer & 0xFFFF; - let device = (integer >> 16) & 0xFFFF; - let vendor_rev = ((vendor & 0xFF) << 8) | (vendor >> 8); - let vendor_1 = (((vendor_rev >> 10) & 0x1F) as u8 + 64) as char; - let vendor_2 = (((vendor_rev >> 5) & 0x1F) as u8 + 64) as char; - let vendor_3 = (((vendor_rev >> 0) & 0x1F) as u8 + 64) as char; - let device_1 = (device >> 4) & 0xF; - let device_2 = (device >> 0) & 0xF; - let device_3 = (device >> 12) & 0xF; - let device_4 = (device >> 8) & 0xF; - - format!( - "{vendor_1}{vendor_2}{vendor_3}{device_1:01X}{device_2:01X}{device_3:01X}{device_4:01X}" - ) -} diff --git a/recipes/core/base/drivers/usb/usbctl/.gitignore b/recipes/core/base/drivers/usb/usbctl/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/recipes/core/base/drivers/usb/usbctl/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/recipes/core/base/drivers/usb/usbctl/Cargo.toml b/recipes/core/base/drivers/usb/usbctl/Cargo.toml deleted file mode 100644 index 5cc99f43e4..0000000000 --- a/recipes/core/base/drivers/usb/usbctl/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "usbctl" -version = "0.1.0" -authors = ["4lDO2 <4lDO2@protonmail.com>"] -edition = "2018" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -clap.workspace = true -xhcid = { path = "../xhcid" } -common = { path = "../../common" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/usb/usbctl/src/main.rs b/recipes/core/base/drivers/usb/usbctl/src/main.rs deleted file mode 100644 index 9b5773d901..0000000000 --- a/recipes/core/base/drivers/usb/usbctl/src/main.rs +++ /dev/null @@ -1,54 +0,0 @@ -use clap::{Arg, Command}; -use xhcid_interface::{PortId, XhciClientHandle}; - -fn main() { - common::init(); - let matches = Command::new("usbctl") - .arg( - Arg::new("SCHEME") - .num_args(1) - .required(true) - .long("scheme") - .short('s'), - ) - .subcommand( - Command::new("port") - .arg(Arg::new("PORT").num_args(1).required(true)) - .subcommand(Command::new("status")) - .subcommand( - Command::new("endpoint") - .arg(Arg::new("ENDPOINT_NUM").num_args(1).required(true)) - .subcommand(Command::new("status")), - ), - ) - .get_matches(); - - let scheme = matches.get_one::("SCHEME").expect("no scheme"); - - if let Some(port_scmd_matches) = matches.subcommand_matches("port") { - let port = port_scmd_matches - .get_one::("PORT") - .expect("invalid utf-8 for PORT argument") - .parse::() - .expect("expected PORT ID"); - - let handle = XhciClientHandle::new(scheme.to_owned(), port) - .expect("Failed to open XhciClientHandle"); - - if let Some(_status_scmd_matches) = port_scmd_matches.subcommand_matches("status") { - let state = handle.port_state().expect("Failed to get port state"); - println!("{}", state.as_str()); - } else if let Some(endp_scmd_matches) = port_scmd_matches.subcommand_matches("endpoint") { - let endp_num = endp_scmd_matches - .get_one::("ENDPOINT_NUM") - .expect("no valid ENDPOINT_NUM") - .parse::() - .expect("expected ENDPOINT_NUM to be an 8-bit integer"); - let mut endp_handle = handle - .open_endpoint(endp_num) - .expect("Failed to open endpoint"); - let state = endp_handle.status().expect("Failed to get endpoint state"); - println!("{}", state.as_str()); - } - } -} diff --git a/recipes/core/base/drivers/usb/usbhubd/.gitignore b/recipes/core/base/drivers/usb/usbhubd/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/recipes/core/base/drivers/usb/usbhubd/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/recipes/core/base/drivers/usb/usbhubd/Cargo.toml b/recipes/core/base/drivers/usb/usbhubd/Cargo.toml deleted file mode 100644 index e64355c56a..0000000000 --- a/recipes/core/base/drivers/usb/usbhubd/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "usbhubd" -description = "USB Hub driver" -version = "0.1.0" -edition = "2018" -license = "MIT" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -log.workspace = true -redox_syscall.workspace = true -xhcid = { path = "../xhcid" } - -common = { path = "../../common" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/usb/usbhubd/src/main.rs b/recipes/core/base/drivers/usb/usbhubd/src/main.rs deleted file mode 100644 index 2c8b9876a6..0000000000 --- a/recipes/core/base/drivers/usb/usbhubd/src/main.rs +++ /dev/null @@ -1,249 +0,0 @@ -use std::{env, thread, time}; - -use xhcid_interface::{ - plain, usb, ConfigureEndpointsReq, DevDesc, DeviceReqData, PortId, PortReqRecipient, PortReqTy, - XhciClientHandle, -}; - -fn main() { - common::init(); - let mut args = env::args().skip(1); - - const USAGE: &'static str = "usbhubd "; - - let scheme = args.next().expect(USAGE); - let port_id = args - .next() - .expect(USAGE) - .parse::() - .expect("Expected port ID"); - let interface_num = args - .next() - .expect(USAGE) - .parse::() - .expect("Expected integer as input of interface"); - - log::info!( - "USB HUB driver spawned with scheme `{}`, port {}, interface {}", - scheme, - port_id, - interface_num - ); - - let name = format!("{}_{}_{}_hub", scheme, port_id, interface_num); - common::setup_logging( - "usb", - "device", - &name, - common::output_level(), - common::file_level(), - ); - - let handle = - XhciClientHandle::new(scheme.clone(), port_id).expect("Failed to open XhciClientHandle"); - let desc: DevDesc = handle - .get_standard_descs() - .expect("Failed to get standard descriptors"); - - let (conf_desc, if_desc) = desc - .config_descs - .iter() - .find_map(|conf_desc| { - let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { - if if_desc.number == interface_num { - Some(if_desc.clone()) - } else { - None - } - })?; - Some((conf_desc.clone(), if_desc)) - }) - .expect("Failed to find suitable configuration"); - - // Read hub descriptor - let (ports, usb_3) = if desc.major_version() >= 3 { - // USB 3.0 hubs - let mut hub_desc = usb::HubDescriptorV3::default(); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Device, - usb::SetupReq::GetDescriptor as u8, - u16::from(usb::HubDescriptorV3::DESCRIPTOR_KIND) << 8, - 0, - DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), - ) - .expect("Failed to read hub descriptor"); - (hub_desc.ports, true) - } else { - // USB 2.0 and earlier hubs - let mut hub_desc = usb::HubDescriptorV2::default(); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Device, - usb::SetupReq::GetDescriptor as u8, - u16::from(usb::HubDescriptorV2::DESCRIPTOR_KIND) << 8, - 0, - DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), - ) - .expect("Failed to read hub descriptor"); - (hub_desc.ports, false) - }; - - // Configure as hub device - handle - .configure_endpoints(&ConfigureEndpointsReq { - config_desc: conf_desc.configuration_value, - interface_desc: None, //TODO: stalls on USB 3 hub: Some(interface_num), - alternate_setting: None, //TODO: stalls on USB 3 hub: Some(if_desc.alternate_setting), - hub_ports: Some(ports), - }) - .expect("Failed to configure endpoints after reading hub descriptor"); - - if usb_3 { - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Device, - 0x0c, // SET_HUB_DEPTH - port_id.hub_depth().into(), - 0, - DeviceReqData::NoData, - ) - .expect("Failed to set hub depth"); - } - - // Initialize states - struct PortState { - port_id: PortId, - port_sts: usb::HubPortStatus, - handle: XhciClientHandle, - attached: bool, - } - - impl PortState { - pub fn ensure_attached(&mut self, attached: bool) { - if attached == self.attached { - return; - } - - if attached { - self.handle.attach().expect("Failed to attach"); - } else { - self.handle.detach().expect("Failed to detach"); - } - - self.attached = attached; - } - } - - let mut states = Vec::new(); - for port in 1..=ports { - let child_port_id = port_id.child(port).expect("Cannot get child port ID"); - states.push(PortState { - port_id: child_port_id, - port_sts: if usb_3 { - usb::HubPortStatus::V3(usb::HubPortStatusV3::default()) - } else { - usb::HubPortStatus::V2(usb::HubPortStatusV2::default()) - }, - handle: XhciClientHandle::new(scheme.clone(), child_port_id) - .expect("Failed to open XhciClientHandle"), - attached: false, - }); - } - - //TODO: use change flags? - loop { - for port in 1..=ports { - let port_idx: usize = port.checked_sub(1).unwrap().into(); - let state = states.get_mut(port_idx).unwrap(); - - let port_sts = if usb_3 { - let mut port_sts = usb::HubPortStatusV3::default(); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Other, - usb::SetupReq::GetStatus as u8, - 0, - port as u16, - DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut port_sts) }), - ) - .expect("Failed to retrieve port status"); - usb::HubPortStatus::V3(port_sts) - } else { - let mut port_sts = usb::HubPortStatusV2::default(); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Other, - usb::SetupReq::GetStatus as u8, - 0, - port as u16, - DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut port_sts) }), - ) - .expect("Failed to retrieve port status"); - usb::HubPortStatus::V2(port_sts) - }; - if state.port_sts != port_sts { - state.port_sts = port_sts; - log::info!("port {} status {:X?}", port, port_sts); - } - - // Ensure port is powered on - if !port_sts.is_powered() { - log::info!("power on port {port}"); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Other, - usb::SetupReq::SetFeature as u8, - usb::HubPortFeature::PortPower as u16, - port as u16, - DeviceReqData::NoData, - ) - .expect("Failed to set port power"); - state.ensure_attached(false); - continue; - } - - // Ignore disconnected port - if !port_sts.is_connected() { - state.ensure_attached(false); - continue; - } - - // Ignore port in reset - if port_sts.is_resetting() { - state.ensure_attached(false); - continue; - } - - // Ensure port is enabled - if !port_sts.is_enabled() { - log::info!("reset port {port}"); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Other, - usb::SetupReq::SetFeature as u8, - usb::HubPortFeature::PortReset as u16, - port as u16, - DeviceReqData::NoData, - ) - .expect("Failed to set port enable"); - state.ensure_attached(false); - continue; - } - - state.ensure_attached(true); - } - - //TODO: use interrupts or poll faster? - thread::sleep(time::Duration::new(1, 0)); - } - - //TODO: read interrupt port for changes -} diff --git a/recipes/core/base/drivers/usb/xhcid/.gitignore b/recipes/core/base/drivers/usb/xhcid/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/recipes/core/base/drivers/usb/xhcid/Cargo.toml b/recipes/core/base/drivers/usb/xhcid/Cargo.toml deleted file mode 100644 index 6353ea5d69..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "xhcid" -description = "xHCI controller driver" -version = "0.1.0" -edition = "2018" - -[[bin]] -name = "xhcid" -path = "src/main.rs" - -[lib] -name = "xhcid_interface" -path = "src/lib.rs" - -[dependencies] -bitflags.workspace = true -chashmap = "2.2.2" -crossbeam-channel = "0.4" -futures = "0.3" -plain.workspace = true -lazy_static = "1.4" -log.workspace = true -redox_event.workspace = true -redox-scheme.workspace = true -scheme-utils = { path = "../../../scheme-utils" } -redox_syscall.workspace = true -serde.workspace = true -serde_json.workspace = true -smallvec = { workspace = true, features = ["serde"] } -thiserror.workspace = true -toml.workspace = true - -config = { path = "../../../config" } -common = { path = "../../common" } -daemon = { path = "../../../daemon" } -pcid = { path = "../../pcid" } -libredox.workspace = true -regex = "1.10.6" - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/usb/xhcid/config.toml b/recipes/core/base/drivers/usb/xhcid/config.toml deleted file mode 100644 index 80e781c52a..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/config.toml +++ /dev/null @@ -1,7 +0,0 @@ -[[drivers]] -name = "XHCI" -class = 0x0C -subclass = 0x03 -interface = 0x30 -command = ["xhcid"] -use_channel = true diff --git a/recipes/core/base/drivers/usb/xhcid/drivers.toml b/recipes/core/base/drivers/usb/xhcid/drivers.toml deleted file mode 100644 index 83c90e2385..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/drivers.toml +++ /dev/null @@ -1,18 +0,0 @@ -#TODO: causes XHCI errors -#[[drivers]] -#name = "SCSI over USB" -#class = 8 # Mass Storage class -#subclass = 6 # SCSI transparent command set -#command = ["usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"] - -[[drivers]] -name = "USB HUB" -class = 9 # HUB class -subclass = -1 -command = ["usbhubd", "$SCHEME", "$PORT", "$IF_NUM"] - -[[drivers]] -name = "USB HID" -class = 3 # HID class -subclass = -1 -command = ["usbhidd", "$SCHEME", "$PORT", "$IF_NUM"] diff --git a/recipes/core/base/drivers/usb/xhcid/src/driver_interface.rs b/recipes/core/base/drivers/usb/xhcid/src/driver_interface.rs deleted file mode 100644 index 727f8d7e99..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/driver_interface.rs +++ /dev/null @@ -1,889 +0,0 @@ -pub extern crate serde; -pub extern crate smallvec; - -use std::convert::TryFrom; -use std::fs::File; -use std::io::prelude::*; -use std::num::NonZeroU8; -use std::os::fd::{FromRawFd, RawFd}; -use std::string::FromUtf8Error; -use std::{fmt, io, result, str}; - -use serde::{Deserialize, Serialize}; -use smallvec::SmallVec; -use syscall::{Error, Result, EINVAL}; -use thiserror::Error; - -pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK}; - -#[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct ConfigureEndpointsReq { - /// Index into the configuration descriptors of the device descriptor. - pub config_desc: u8, - pub interface_desc: Option, - pub alternate_setting: Option, - pub hub_ports: Option, -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct DevDesc { - pub kind: u8, - pub usb: u16, - pub class: u8, - pub sub_class: u8, - pub protocol: u8, - pub packet_size: u8, - pub vendor: u16, - pub product: u16, - pub release: u16, - pub manufacturer_str: Option, - pub product_str: Option, - pub serial_str: Option, - pub config_descs: SmallVec<[ConfDesc; 1]>, -} - -impl DevDesc { - pub fn major_version(&self) -> u8 { - ((self.usb & 0xFF00) >> 8) as u8 - } - pub fn minor_version(&self) -> u8 { - self.usb as u8 - } -} - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct ConfDesc { - pub kind: u8, - pub configuration_value: u8, - pub configuration: Option, - pub attributes: u8, - pub max_power: u8, - pub interface_descs: SmallVec<[IfDesc; 1]>, -} - -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct EndpDesc { - pub kind: u8, - pub address: u8, - pub attributes: u8, - pub max_packet_size: u16, - pub interval: u8, - pub ssc: Option, - pub sspc: Option, -} -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum EndpDirection { - Out, - In, - Bidirectional, -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum EndpBinaryDirection { - Out, - In, -} - -impl From for EndpBinaryDirection { - fn from(d: PortReqDirection) -> Self { - match d { - PortReqDirection::DeviceToHost => Self::In, - PortReqDirection::HostToDevice => Self::Out, - } - } -} - -impl From for EndpDirection { - fn from(b: EndpBinaryDirection) -> Self { - match b { - EndpBinaryDirection::In => Self::In, - EndpBinaryDirection::Out => Self::Out, - } - } -} - -impl From for EndpDirection { - fn from(d: PortReqDirection) -> Self { - match d { - PortReqDirection::HostToDevice => Self::Out, - PortReqDirection::DeviceToHost => Self::In, - } - } -} - -impl EndpDesc { - pub fn ty(self) -> EndpointTy { - match self.attributes & ENDP_ATTR_TY_MASK { - 0 => EndpointTy::Ctrl, - 1 => EndpointTy::Isoch, - 2 => EndpointTy::Bulk, - 3 => EndpointTy::Interrupt, - _ => unreachable!(), - } - } - pub fn is_control(&self) -> bool { - self.ty() == EndpointTy::Ctrl - } - pub fn is_interrupt(&self) -> bool { - self.ty() == EndpointTy::Interrupt - } - pub fn is_bulk(&self) -> bool { - self.ty() == EndpointTy::Bulk - } - pub fn is_isoch(&self) -> bool { - self.ty() == EndpointTy::Isoch - } - pub fn direction(&self) -> EndpDirection { - if self.is_control() { - return EndpDirection::Bidirectional; - } - if self.address & 0x80 != 0 { - EndpDirection::In - } else { - EndpDirection::Out - } - } - pub fn xhci_ep_type(&self) -> Result { - Ok(match self.direction() { - EndpDirection::Out if self.is_isoch() => 1, - EndpDirection::Out if self.is_bulk() => 2, - EndpDirection::Out if self.is_interrupt() => 3, - EndpDirection::Bidirectional if self.is_control() => 4, - EndpDirection::In if self.is_isoch() => 5, - EndpDirection::In if self.is_bulk() => 6, - EndpDirection::In if self.is_interrupt() => 7, - _ => return Err(Error::new(EINVAL)), - }) - } - pub fn is_superspeed(&self) -> bool { - self.ssc.is_some() - } - pub fn is_superspeedplus(&self) -> bool { - self.sspc.is_some() - } - fn interrupt_usage_bits(&self) -> u8 { - assert!(self.is_interrupt()); - (self.attributes & 0x20) >> 4 - } - pub fn is_periodic(&self) -> bool { - #[repr(u8)] - enum InterruptUsageBits { - Periodic, - Notification, - Rsvd2, - Rsvd3, - } - - if self.is_interrupt() { - self.interrupt_usage_bits() == InterruptUsageBits::Periodic as u8 - } else { - self.is_isoch() - } - } - pub fn log_max_streams(&self) -> Option { - self.ssc - .as_ref() - .map(|ssc| { - if self.is_bulk() { - let raw = ssc.attributes & 0x1F; - NonZeroU8::new(raw) - } else { - None - } - }) - .flatten() - } - pub fn isoch_mult(&self, lec: bool) -> u8 { - if !lec && self.is_isoch() { - if self.is_superspeedplus() { - return 0; - } - self.ssc - .as_ref() - .map(|ssc| ssc.attributes & 0x3) - .unwrap_or(0) - } else { - 0 - } - } - pub fn max_burst(&self) -> u8 { - self.ssc.map(|ssc| ssc.max_burst).unwrap_or(0) - } - pub fn has_ssp_companion(&self) -> bool { - self.ssc - .map(|ssc| ssc.attributes & (1 << 7) != 0) - .unwrap_or(false) - } -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct IfDesc { - pub kind: u8, - pub number: u8, - pub alternate_setting: u8, - pub class: u8, - pub sub_class: u8, - pub protocol: u8, - pub interface_str: Option, - pub endpoints: SmallVec<[EndpDesc; 4]>, - pub hid_descs: SmallVec<[HidDesc; 1]>, -} - -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct SuperSpeedCmp { - pub kind: u8, - pub max_burst: u8, - pub attributes: u8, - pub bytes_per_interval: u16, -} -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct SuperSpeedPlusIsochCmp { - pub kind: u8, - pub bytes_per_interval: u32, -} -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct HidDesc { - pub kind: u8, - pub hid_spec_release: u16, - pub country: u8, - pub desc_count: u8, - pub desc_ty: u8, - pub desc_len: u16, - pub optional_desc_ty: u8, - pub optional_desc_len: u16, -} -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct PortReq { - pub direction: PortReqDirection, - pub req_type: PortReqTy, - pub req_recipient: PortReqRecipient, - pub request: u8, - pub value: u16, - pub index: u16, - pub length: u16, - pub transfers_data: bool, -} -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub enum PortReqDirection { - HostToDevice, - DeviceToHost, -} -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub enum PortReqTy { - Class, - Vendor, - Standard, -} -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub enum PortReqRecipient { - Device, - Interface, - Endpoint, - Other, - VendorSpecific, -} - -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct PortId { - pub root_hub_port_num: u8, - pub route_string: u32, -} - -impl PortId { - pub fn root_hub_port_index(&self) -> usize { - self.root_hub_port_num.checked_sub(1).unwrap().into() - } - - pub fn hub_depth(&self) -> u8 { - let mut hub_depth = 0; - let mut route_string = self.route_string; - while route_string != 0 { - route_string >>= 4; - hub_depth += 1; - } - hub_depth - } - - pub fn child(&self, value: u8) -> Result { - let depth = self.hub_depth(); - if depth >= 5 { - return Err(format!("too many route string components")); - } - if value & 0xF0 != 0 { - return Err(format!( - "value {:?} is too large for route string component", - value - )); - } - Ok(Self { - root_hub_port_num: self.root_hub_port_num, - route_string: self.route_string | u32::from(value) << (depth * 4), - }) - } - - pub fn parent(&self) -> Option<(Self, u8)> { - let depth = self.hub_depth(); - let parent_depth = depth.checked_sub(1)?; - let parent_shift = parent_depth * 4; - let parent_mask = 0xF << parent_shift; - Some(( - Self { - root_hub_port_num: self.root_hub_port_num, - route_string: self.route_string & !parent_mask, - }, - u8::try_from((self.route_string & parent_mask) >> parent_shift).unwrap(), - )) - } -} - -impl fmt::Display for PortId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.root_hub_port_num)?; - // USB 3.1 Revision 1.1 Specification Section 8.9 Route String Field - // The Route String is a 20-bit field in downstream directed packets that the hub uses to route - // each packet to the designated downstream port. It is composed of a concatenation of the - // downstream port numbers (4 bits per hub) for each hub traversed to reach a device. - let mut route_string = self.route_string; - while route_string != 0 { - write!(f, ".{}", route_string & 0xF)?; - route_string >>= 4; - } - Ok(()) - } -} - -impl str::FromStr for PortId { - type Err = String; - - fn from_str(s: &str) -> Result { - let mut root_hub_port_num = 0; - let mut route_string = 0; - for (i, part) in s.split('.').enumerate() { - let value: u8 = part - .parse() - .map_err(|e| format!("failed to parse {:?}: {}", part, e))?; - - // Neither root hub port number nor route string support 0 components - // to identify downstream ports - if value == 0 { - return Err(format!("zero is not a valid port ID component")); - } - - // Parse root hub port number - if i == 0 { - root_hub_port_num = value; - continue; - } - - // Parse route string component - let depth = i - 1; - if depth >= 5 { - return Err(format!("too many route string components")); - } - if value & 0xF0 != 0 { - return Err(format!( - "value {:?} is too large for route string component", - value - )); - } - route_string |= u32::from(value) << (depth * 4); - } - Ok(Self { - root_hub_port_num, - route_string, - }) - } -} - -pub struct XhciClientHandle { - fd: libredox::Fd, - scheme: String, - port: PortId, -} -impl fmt::Debug for XhciClientHandle { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("XhciClientHandle") - .field("scheme", &self.scheme) - .field("port", &self.port) - .field("fd", &"libredox::Fd") - .finish() - } -} -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum PortState { - EnabledOrDisabled, - Default, - Addressed, - Configured, -} -impl PortState { - pub fn as_str(&self) -> &'static str { - match self { - Self::EnabledOrDisabled => "enabled_or_disabled", - Self::Default => "default", - Self::Addressed => "addressed", - Self::Configured => "configured", - } - } -} -#[derive(Debug, Error)] -#[error("invalid input")] -pub struct Invalid(pub &'static str); - -impl str::FromStr for PortState { - type Err = Invalid; - - fn from_str(s: &str) -> result::Result { - Ok(match s { - "enabled_or_disabled" | "enabled/disabled" => Self::EnabledOrDisabled, - "default" => Self::Default, - "addressed" => Self::Addressed, - "configured" => Self::Configured, - _ => return Err(Invalid("read reserved port state")), - }) - } -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub enum EndpointStatus { - Disabled, - Enabled, - Halted, - Stopped, - Error, -} - -#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub struct PortTransferStatus { - pub kind: PortTransferStatusKind, - pub bytes_transferred: u32, -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub enum PortTransferStatusKind { - Success, - ShortPacket, - Stalled, - Unknown, -} -impl Default for PortTransferStatusKind { - fn default() -> Self { - Self::Success - } -} - -impl EndpointStatus { - pub fn as_str(&self) -> &'static str { - match self { - Self::Disabled => "disabled", - Self::Enabled => "enabled", - Self::Halted => "halted", - Self::Stopped => "stopped", - Self::Error => "error", - } - } -} - -impl str::FromStr for EndpointStatus { - type Err = Invalid; - - fn from_str(s: &str) -> result::Result { - Ok(match s { - "disabled" => Self::Disabled, - "enabled" => Self::Enabled, - "halted" => Self::Halted, - "stopped" => Self::Stopped, - "error" => Self::Error, - _ => return Err(Invalid("read reserved endpoint state")), - }) - } -} - -pub enum DeviceReqData<'a> { - In(&'a mut [u8]), - Out(&'a [u8]), - NoData, -} -impl DeviceReqData<'_> { - pub fn len(&self) -> usize { - match self { - Self::In(buf) => buf.len(), - Self::Out(buf) => buf.len(), - Self::NoData => 0, - } - } - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - pub fn map_buf T>(&self, f: F) -> Option { - match self { - Self::In(sbuf) => Some(f(sbuf)), - Self::Out(dbuf) => Some(f(dbuf)), - _ => None, - } - } - pub fn direction(&self) -> PortReqDirection { - match self { - DeviceReqData::Out(_) => PortReqDirection::HostToDevice, - DeviceReqData::NoData => PortReqDirection::HostToDevice, - DeviceReqData::In(_) => PortReqDirection::DeviceToHost, - } - } -} - -impl XhciClientHandle { - pub fn new(scheme: String, port: PortId) -> result::Result { - let path = format!("/scheme/{}/port{}", scheme, port); - let fd = libredox::Fd::open(&path, libredox::flag::O_DIRECTORY, 0)?; - Ok(Self { fd, scheme, port }) - } - fn read(&self, path: &str) -> result::Result, XhciClientHandleError> { - let target_fd = self.fd.openat(path, libredox::flag::O_RDONLY, 0)?; - let stat = target_fd.stat()?; - let mut buf: Vec = vec![0u8; stat.st_size as usize]; - let count = target_fd.read(&mut buf)?; - buf.truncate(count); - Ok(buf) - } - fn read_to_string(&self, path: &str) -> result::Result { - let buf = self.read(path)?; - Ok(String::from_utf8(buf)?) - } - pub fn attach(&self) -> result::Result<(), XhciClientHandleError> { - let file = self.fd.openat("attach", libredox::flag::O_WRONLY, 0)?; - let _bytes_written = file.write(&[])?; - Ok(()) - } - pub fn detach(&self) -> result::Result<(), XhciClientHandleError> { - let file = self.fd.openat("detach", libredox::flag::O_WRONLY, 0)?; - let _bytes_written = file.write(&[])?; - Ok(()) - } - pub fn get_standard_descs(&self) -> result::Result { - let json = self.read("descriptors")?; - Ok(serde_json::from_slice(&json)?) - } - pub fn configure_endpoints( - &self, - req: &ConfigureEndpointsReq, - ) -> result::Result<(), XhciClientHandleError> { - let json = serde_json::to_vec(req)?; - let file = self.fd.openat("configure", libredox::flag::O_WRONLY, 0)?; - let json_bytes_written = file.write(&json)?; - if json_bytes_written != json.len() { - return Err(XhciClientHandleError::InvalidResponse(Invalid( - "configure_endpoints didn't read as many bytes as were requested", - ))); - } - Ok(()) - } - pub fn port_state(&self) -> result::Result { - let string = self.read_to_string("state")?; - Ok(string.parse()?) - } - pub fn open_endpoint_ctl(&self, num: u8) -> result::Result { - let path = format!("endpoints/{}/ctl", num); - let fd = self.fd.openat(&path, libredox::flag::O_RDWR, 0)?; - Ok(unsafe { File::from_raw_fd(fd.into_raw() as RawFd) }) - } - pub fn open_endpoint_data(&self, num: u8) -> result::Result { - let path = format!("endpoints/{}/data", num); - let fd = self.fd.openat(&path, libredox::flag::O_RDWR, 0)?; - Ok(unsafe { File::from_raw_fd(fd.into_raw() as RawFd) }) - } - pub fn open_endpoint(&self, num: u8) -> result::Result { - Ok(XhciEndpHandle { - ctl: self.open_endpoint_ctl(num)?, - data: self.open_endpoint_data(num)?, - }) - } - pub fn device_request<'a>( - &self, - req_type: PortReqTy, - req_recipient: PortReqRecipient, - request: u8, - value: u16, - index: u16, - data: DeviceReqData<'a>, - ) -> result::Result<(), XhciClientHandleError> { - let length = u16::try_from(data.len()) - .or(Err(XhciClientHandleError::TransferBufTooLarge(data.len())))?; - - let req = PortReq { - direction: data.direction(), - req_type, - req_recipient, - request, - value, - index, - length, - transfers_data: !matches!(data, DeviceReqData::NoData), - }; - let json = serde_json::to_vec(&req)?; - - let file = self.fd.openat("request", libredox::flag::O_RDWR, 0)?; - - let json_bytes_written = file.write(&json)?; - if json_bytes_written != json.len() { - return Err(XhciClientHandleError::InvalidResponse(Invalid( - "device_request didn't return the same number of bytes as were written", - ))); - } - - match data { - DeviceReqData::In(buf) => { - let bytes_read = file.read(buf)?; - - if bytes_read != buf.len() { - return Err(XhciClientHandleError::InvalidResponse(Invalid( - "device_request didn't transfer (host2dev) all bytes", - ))); - } - } - DeviceReqData::Out(buf) => { - let bytes_read = file.write(&buf)?; - - if bytes_read != buf.len() { - return Err(XhciClientHandleError::InvalidResponse(Invalid( - "device_request didn't transfer (dev2host) all bytes", - ))); - } - } - DeviceReqData::NoData => (), - } - Ok(()) - } - pub fn get_descriptor( - &self, - recipient: PortReqRecipient, - ty: u8, - idx: u8, - windex: u16, - buffer: &mut [u8], - ) -> result::Result<(), XhciClientHandleError> { - self.device_request( - PortReqTy::Standard, - recipient, - 0x06, - (u16::from(ty) << 8) | u16::from(idx), - windex, - DeviceReqData::In(buffer), - ) - } - pub fn clear_feature( - &self, - recipient: PortReqRecipient, - index: u16, - feature_sel: u16, - ) -> result::Result<(), XhciClientHandleError> { - self.device_request( - PortReqTy::Standard, - recipient, - 0x01, - feature_sel, - index, - DeviceReqData::NoData, - ) - } -} - -#[derive(Debug)] -pub struct XhciEndpHandle { - data: File, - ctl: File, -} - -/// The direction of a transfer. -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub enum XhciEndpCtlDirection { - /// Host to device - Out, - /// Device to host - In, - /// No data, and hence no I/O on the Data interface file at all. - NoData, -} - -/// A request to an endpoint Ctl interface file. Currently serialized with JSON. -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -#[non_exhaustive] -pub enum XhciEndpCtlReq { - // TODO: Reduce the number of direction enums from 5 to perhaps 2. - // TODO: Allow to send multiple buffers in one transfer. - /// Tells xhcid that a buffer is about to be sent from the Data interface file, to the - /// endpoint. - Transfer { - /// The direction of the transfer. If the direction is `XhciEndpCtlDirection::NoData`, no - /// bytes will be transferred, and therefore no reads or writes shall be done to the Data - /// driver interface file. - direction: XhciEndpCtlDirection, - - /// The number of bytes to be read or written. This field must be set to zero if the - /// direction is `XhciEndpCtlDirection::NoData`. When all bytes have been read or written, - /// the transfer will be considered complete by xhcid, and a non-pending status will be - /// returned. - count: u32, - }, - // TODO: Allow clients to specify what to reset. - /// Tells xhcid that the endpoint is going to be reset. - Reset { - /// Only issue the Reset Endpoint and Set TR Dequeue Pointer commands, and let the client - /// itself send a potential ClearFeature(ENDPOINT_HALT). - no_clear_feature: bool, - }, - - /// Tells xhcid that the endpoint status is going to be retrieved from the Ctl interface file. - Status, -} -/// A response from an endpoint Ctl interface file. Currently serialized with JSON. -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] -#[non_exhaustive] -pub enum XhciEndpCtlRes { - /// Xhcid responded with the current state of an endpoint. - Status(EndpointStatus), - - /// Xhci sent the result of a transfer. - TransferResult(PortTransferStatus), - - /// Xhcid is waiting for data to be sent or received on the Data interface file. - Pending, - - /// No Ctl request is currently being processed by xhcid. - Idle, -} - -impl XhciEndpHandle { - fn ctl_req(&mut self, ctl_req: &XhciEndpCtlReq) -> result::Result<(), XhciClientHandleError> { - let ctl_buffer = serde_json::to_vec(ctl_req)?; - - let ctl_bytes_written = self.ctl.write(&ctl_buffer)?; - if ctl_bytes_written != ctl_buffer.len() { - return Err(Invalid("xhcid didn't process all of the ctl bytes").into()); - } - - Ok(()) - } - fn ctl_res(&mut self) -> result::Result { - // a response must never exceed 256 bytes - let mut ctl_buffer = [0u8; 256]; - let ctl_bytes_read = self.ctl.read(&mut ctl_buffer)?; - - let ctl_res = serde_json::from_slice(&ctl_buffer[..ctl_bytes_read as usize])?; - Ok(ctl_res) - } - pub fn reset(&mut self, no_clear_feature: bool) -> result::Result<(), XhciClientHandleError> { - self.ctl_req(&XhciEndpCtlReq::Reset { no_clear_feature }) - } - pub fn status(&mut self) -> result::Result { - self.ctl_req(&XhciEndpCtlReq::Status)?; - match self.ctl_res()? { - XhciEndpCtlRes::Status(s) => Ok(s), - _ => Err(Invalid("expected status response").into()), - } - } - fn generic_transfer io::Result>( - &mut self, - direction: XhciEndpCtlDirection, - f: F, - expected_len: u32, - ) -> result::Result { - let req = XhciEndpCtlReq::Transfer { - direction, - count: expected_len, - }; - self.ctl_req(&req)?; - - let bytes_read = f(&mut self.data)?; - let res = self.ctl_res()?; - - match res { - XhciEndpCtlRes::TransferResult(PortTransferStatus { - kind: PortTransferStatusKind::Success, - .. - }) if bytes_read != expected_len as usize => { - Err(Invalid("no short packet, but fewer bytes were read/written").into()) - } - XhciEndpCtlRes::TransferResult(r) => Ok(r), - _ => Err(Invalid("expected transfer result").into()), - } - } - pub fn transfer_write( - &mut self, - buf: &[u8], - ) -> result::Result { - self.generic_transfer( - XhciEndpCtlDirection::Out, - |data| data.write(buf), - buf.len() as u32, - ) - } - pub fn transfer_read( - &mut self, - buf: &mut [u8], - ) -> result::Result { - let len = buf.len() as u32; - self.generic_transfer(XhciEndpCtlDirection::In, |data| data.read(buf), len) - } - pub fn transfer_nodata(&mut self) -> result::Result { - self.generic_transfer(XhciEndpCtlDirection::NoData, |_| Ok(0), 0) - } - fn transfer_stream(&mut self, total_len: u32) -> TransferStream<'_> { - TransferStream { - bytes_to_transfer: total_len, - bytes_transferred: 0, - bytes_per_transfer: 32768, // TODO - endp_handle: self, - } - } - pub fn transfer_write_stream(&mut self, total_len: u32) -> TransferWriteStream<'_> { - TransferWriteStream { - inner: self.transfer_stream(total_len), - } - } - pub fn transfer_read_stream(&mut self, total_len: u32) -> TransferReadStream<'_> { - TransferReadStream { - inner: self.transfer_stream(total_len), - } - } -} - -pub struct TransferWriteStream<'a> { - inner: TransferStream<'a>, -} -pub struct TransferReadStream<'a> { - inner: TransferStream<'a>, -} -struct TransferStream<'a> { - bytes_to_transfer: u32, - bytes_transferred: u32, - bytes_per_transfer: u32, - endp_handle: &'a mut XhciEndpHandle, -} - -#[derive(Debug, Error)] -pub enum XhciClientHandleError { - #[error("i/o error: {0}")] - IoError(#[from] io::Error), - - #[error("serialization error: {0}")] - SerializationError(#[from] serde_json::Error), - - #[error("invalid response")] - InvalidResponse(#[from] Invalid), - - #[error("transfer buffer too large ({0} > 65536)")] - TransferBufTooLarge(usize), - - #[error("unexpected short packet of size {0}")] - UnexpectedShortPacket(usize), - - #[error("utf8 error: {0}")] - Utf8Error(#[from] FromUtf8Error), -} - -impl From for XhciClientHandleError { - fn from(error: libredox::error::Error) -> Self { - Self::IoError(error.into()) - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/lib.rs b/recipes/core/base/drivers/usb/xhcid/src/lib.rs deleted file mode 100644 index 771958a18d..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/lib.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! The eXtensible Host Controller Interface (XHCI) Daemon Interface -//! -//! This crate implements the driver interface for interacting with the Redox xhcid daemon from -//! another userspace process. -//! -//! XHCI is a standard for the USB Host Controller interface specified by Intel that provides a -//! common register interface for systems to use to interact with the Universal Serial Bus (USB) -//! subsystem. -//! -//! USB consists of three types of devices: The Host Controller/Root Hub, USB Hubs, and Endpoints. -//! Endpoints represent actual devices connected to the USB fabric. USB Hubs are intermediaries -//! between the Host Controller and the endpoints that report when devices have been connected/disconnected. -//! The Host Controller provides the interface to the USB subsystem that software running on the -//! system's CPU can interact with. It's a tree-like structure, which the Host Controller enumerating -//! and addressing all the hubs and endpoints in the tree. Data then flows through the fabric -//! using the USB protocol (2.0 or 3.2) as packets. Hubs have multiple ports that endpoints can -//! connect to, and they notify the Host Controller/Root Hub when devices are hot plugged or removed. -//! -//! This documentation will refer directly to the relevant standards, which are as follows: -//! -//! - XHCI - [eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf) -//! - USB2 - [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification) -//! - USB32 - [Universal Serial Bus 3.2 Specification Revision 1.1](https://usb.org/document-library/usb-32-revision-11-june-2022) -//! -pub extern crate plain; - -mod driver_interface; -pub mod usb; - -pub use driver_interface::*; diff --git a/recipes/core/base/drivers/usb/xhcid/src/main.rs b/recipes/core/base/drivers/usb/xhcid/src/main.rs deleted file mode 100644 index d345a52fc4..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/main.rs +++ /dev/null @@ -1,181 +0,0 @@ -//! The eXtensible Host Controller Interface (XHCI) Daemon -//! -//! This crate provides the executable xhcid daemon that implements the driver for interacting with -//! a PCIe XHCI device -//! -//! XHCI is a standard for the USB Host Controller interface specified by Intel that provides a -//! common register interface for systems to use to interact with the Universal Serial Bus (USB) -//! subsystem. -//! -//! USB consists of three types of devices: The Host Controller/Root Hub, USB Hubs, and Endpoints. -//! Endpoints represent actual devices connected to the USB fabric. USB Hubs are intermediaries -//! between the Host Controller and the endpoints that report when devices have been connected/disconnected. -//! The Host Controller provides the interface to the USB subsystem that software running on the -//! system's CPU can interact with. It's a tree-like structure, which the Host Controller enumerating -//! and addressing all the hubs and endpoints in the tree. Data then flows through the fabric -//! using the USB protocol (2.0 or 3.2) as packets. Hubs have multiple ports that endpoints can -//! connect to, and they notify the Host Controller/Root Hub when devices are hot plugged or removed. -//! -//! This documentation will refer directly to the relevant standards, which are as follows: -//! -//! - XHCI - [eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf) -//! - USB2 - [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification) -//! - USB32 - [Universal Serial Bus 3.2 Specification Revision 1.1](https://usb.org/document-library/usb-32-revision-11-june-2022) -//! -#![allow(warnings)] - -#[macro_use] -extern crate bitflags; - -use std::fs::File; -use std::sync::Arc; - -use pcid_interface::irq_helpers::read_bsp_apic_id; -#[cfg(target_arch = "x86_64")] -use pcid_interface::irq_helpers::{ - allocate_first_msi_interrupt_on_bsp, allocate_single_interrupt_vector_for_msi, -}; -use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle}; - -use redox_scheme::{scheme::register_sync_scheme, Socket}; -use scheme_utils::Blocking; - -use crate::xhci::{InterruptMethod, Xhci}; - -// Declare as pub so that no warnings appear due to parts of the interface code not being used by -// the driver. Since there's also a dedicated crate for the driver interface, those warnings don't -// mean anything. -pub mod driver_interface; - -mod usb; -mod xhci; - -#[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> (Option, InterruptMethod) { - let pci_config = pcid_handle.config(); - - let all_pci_features = pcid_handle.fetch_all_features(); - log::debug!("XHCI PCI FEATURES: {:?}", all_pci_features); - - let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); - let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - - if has_msix { - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { - PciFeatureInfo::Msi(_) => panic!(), - PciFeatureInfo::MsiX(s) => s, - }; - let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; - - // Allocate one msi vector. - - let method = { - // primary interrupter - let k = 0; - - let table_entry_pointer = info.table_entry_pointer(k); - - let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - table_entry_pointer.write_addr_and_data(msg_addr_and_data); - table_entry_pointer.unmask(); - - (Some(interrupt_handle), InterruptMethod::Msi) - }; - - pcid_handle.enable_feature(PciFeature::MsiX); - log::debug!("Enabled MSI-X"); - - method - } else if has_msi { - let interrupt_handle = allocate_first_msi_interrupt_on_bsp(pcid_handle); - (Some(interrupt_handle), InterruptMethod::Msi) - } else if let Some(irq) = pci_config.func.legacy_interrupt_line { - log::debug!("Legacy IRQ {}", irq); - - // legacy INTx# interrupt pins. - (Some(irq.irq_handle("xhcid")), InterruptMethod::Intx) - } else { - // no interrupts at all - (None, InterruptMethod::Polling) - } -} - -//TODO: MSI on non-x86_64? -#[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> (Option, InterruptMethod) { - let pci_config = pcid_handle.config(); - - if let Some(irq) = pci_config.func.legacy_interrupt_line { - // legacy INTx# interrupt pins. - (Some(irq.irq_handle("xhcid")), InterruptMethod::Intx) - } else { - // no interrupts at all - (None, InterruptMethod::Polling) - } -} - -//TODO: cleanup CSZ support -fn daemon_with_context_size( - daemon: daemon::Daemon, - mut pcid_handle: PciFunctionHandle, -) -> ! { - let pci_config = pcid_handle.config(); - - let mut name = pci_config.func.name(); - name.push_str("_xhci"); - - common::setup_logging( - "usb", - "host", - &name, - common::output_level(), - common::file_level(), - ); - - log::debug!("XHCI PCI CONFIG: {:?}", pci_config); - - let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; - - let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle); - //TODO: Fix interrupts. - - log::info!("XHCI {}", pci_config.func.display()); - - let scheme_name = format!("usb.{}", name); - let socket = Socket::create().expect("xhcid: failed to create usb scheme"); - let handler = Blocking::new(&socket, 16); - - let hci = Arc::new( - Xhci::::new(scheme_name.clone(), address, interrupt_method, pcid_handle) - .expect("xhcid: failed to allocate device"), - ); - register_sync_scheme(&socket, &scheme_name, &mut &*hci) - .expect("xhcid: failed to regsiter scheme to namespace"); - - daemon.ready(); - - xhci::start_irq_reactor(&hci, irq_file); - xhci::start_device_enumerator(&hci); - - hci.poll(); - - handler - .process_requests_blocking(&*hci) - .expect("xhcid: failed to process requests"); -} - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; - let cap = unsafe { &mut *(address as *mut xhci::CapabilityRegs) }; - if cap.csz() { - daemon_with_context_size::<{ xhci::CONTEXT_64 }>(daemon, pcid_handle) - } else { - daemon_with_context_size::<{ xhci::CONTEXT_32 }>(daemon, pcid_handle) - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/usb/bos.rs b/recipes/core/base/drivers/usb/xhcid/src/usb/bos.rs deleted file mode 100644 index f6a095712d..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/usb/bos.rs +++ /dev/null @@ -1,182 +0,0 @@ -use std::slice; - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct BosDescriptor { - pub len: u8, - pub kind: u8, - pub total_len: u16, - pub cap_count: u8, -} - -unsafe impl plain::Plain for BosDescriptor {} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct BosDevDescriptorBase { - pub len: u8, - pub kind: u8, - pub cap_ty: u8, -} - -unsafe impl plain::Plain for BosDevDescriptorBase {} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct BosSuperSpeedDesc { - pub len: u8, - pub kind: u8, - pub cap_ty: u8, - - pub attrs: u8, - pub speed_supp: u16, - pub func_supp: u8, - pub u1_dev_exit_lat: u8, - pub u2_dev_exit_lat: u16, -} -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct BosSuperSpeedPlusDesc { - pub len: u8, - pub kind: u8, - pub cap_ty: u8, - pub _rsvd0: u8, - pub attrs: u32, - pub func_supp: u32, - pub _rsvd1: u16, -} - -unsafe impl plain::Plain for BosSuperSpeedPlusDesc {} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct BosUsb2ExtDesc { - pub len: u8, - pub kind: u8, - pub cap_ty: u8, - - pub attrs: u32, -} - -unsafe impl plain::Plain for BosUsb2ExtDesc {} - -#[repr(u8)] -pub enum DeviceCapability { - Usb2Ext = 0x02, - SuperSpeed, - SuperSpeedPlus = 0x0A, -} - -unsafe impl plain::Plain for BosSuperSpeedDesc {} - -impl BosSuperSpeedPlusDesc { - pub fn ssac(&self) -> u8 { - (self.attrs & 0x0000_000F) as u8 - } - pub fn sublink_speed_attr(&self) -> &[u32] { - unsafe { - slice::from_raw_parts( - (self as *const Self).add(1) as *const u32, - self.ssac() as usize + 1, - ) - } - } -} - -pub struct BosDevDescIter<'a> { - bytes: &'a [u8], -} -impl<'a> BosDevDescIter<'a> { - pub fn new(bytes: &'a [u8]) -> Self { - Self { bytes } - } -} -impl<'a> From<&'a [u8]> for BosDevDescIter<'a> { - fn from(slice: &'a [u8]) -> Self { - Self::new(slice) - } -} -impl<'a> Iterator for BosDevDescIter<'a> { - type Item = (BosDevDescriptorBase, &'a [u8]); - - fn next(&mut self) -> Option { - if let Some(desc) = plain::from_bytes::(self.bytes).ok() { - if desc.len as usize > self.bytes.len() { - return None; - }; - let bytes_ret = &self.bytes[..desc.len as usize]; - self.bytes = &self.bytes[desc.len as usize..]; - Some((*desc, bytes_ret)) - } else { - return None; - } - } -} - -#[derive(Clone, Copy, Debug)] -pub enum BosAnyDevDesc { - Usb2Ext(BosUsb2ExtDesc), - SuperSpeed(BosSuperSpeedDesc), - SuperSpeedPlus(BosSuperSpeedPlusDesc), - Unknown, -} - -impl BosAnyDevDesc { - pub fn is_superspeed(&self) -> bool { - match self { - Self::SuperSpeed(_) => true, - _ => false, - } - } - pub fn is_superspeedplus(&self) -> bool { - match self { - Self::SuperSpeedPlus(_) => true, - _ => false, - } - } -} - -pub struct BosAnyDevDescIter<'a> { - inner: BosDevDescIter<'a>, -} -impl<'a> From> for BosAnyDevDescIter<'a> { - fn from(ll: BosDevDescIter<'a>) -> Self { - Self { inner: ll } - } -} -impl<'a> From<&'a [u8]> for BosAnyDevDescIter<'a> { - fn from(slice: &'a [u8]) -> Self { - Self::from(BosDevDescIter::from(slice)) - } -} -impl<'a> Iterator for BosAnyDevDescIter<'a> { - type Item = BosAnyDevDesc; - - fn next(&mut self) -> Option { - let (base, slice) = self.inner.next()?; - - if base.cap_ty == DeviceCapability::Usb2Ext as u8 { - Some(BosAnyDevDesc::Usb2Ext(*plain::from_bytes(slice).ok()?)) - } else if base.cap_ty == DeviceCapability::SuperSpeed as u8 { - Some(BosAnyDevDesc::SuperSpeed(*plain::from_bytes(slice).ok()?)) - } else if base.cap_ty == DeviceCapability::SuperSpeedPlus as u8 { - Some(BosAnyDevDesc::SuperSpeedPlus( - *plain::from_bytes(slice).ok()?, - )) - } else if base.cap_ty == 0 { - // TODO - return None; - } else { - log::warn!("unknown USB device capability of type: {:#x}", base.cap_ty); - Some(BosAnyDevDesc::Unknown) - } - } -} - -pub fn bos_capability_descs<'a>( - desc: BosDescriptor, - data: &'a [u8], -) -> impl Iterator + 'a { - BosAnyDevDescIter::from(&data[..desc.total_len as usize - std::mem::size_of_val(&desc)]) - .take(desc.cap_count as usize) -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/usb/config.rs b/recipes/core/base/drivers/usb/xhcid/src/usb/config.rs deleted file mode 100644 index 5d4a23bca7..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/usb/config.rs +++ /dev/null @@ -1,27 +0,0 @@ -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct ConfigDescriptor { - pub length: u8, - pub kind: u8, - pub total_length: u16, - pub interfaces: u8, - pub configuration_value: u8, - pub configuration_str: u8, - pub attributes: u8, - pub max_power: u8, -} - -unsafe impl plain::Plain for ConfigDescriptor {} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct OtherSpeedConfig { - pub length: u8, - pub kind: u8, - pub total_length: u16, - pub interfaces: u8, - pub configuration_value: u8, - pub configuration_str: u8, - pub attributes: u8, - pub max_power: u8, -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/usb/device.rs b/recipes/core/base/drivers/usb/xhcid/src/usb/device.rs deleted file mode 100644 index accac1c316..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/usb/device.rs +++ /dev/null @@ -1,191 +0,0 @@ -//! Implements the "Device" USB Descriptor. -//! -//! This descriptor is described in USB32 section 9.6.1 - -/// A USB Device Descriptor. -/// -/// This is common to all USB standards, and "provides information that applies globally to the -/// device and all the device's configurations" (USB32 9.6.1) -/// -/// A given device will only have one device descriptor. -/// -/// USB32 Table 9-11 describes the USB packet offsets of the fields described by this structure. -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct DeviceDescriptor { - /// The length of this descriptor in bytes. - /// The bLength field in USB32 Table 9-11 - pub length: u8, - /// The descriptor type. See [DescriptorKind] - /// The bDescriptorType field in USB32 Table 9-11. - pub kind: u8, - /// The USB standard version in binary-coded decimal. - /// - /// USB 2.1 would be encoded as 210H, 3.2 would be 320H. - /// The bcdUSB field in USB32 Table 9-11 - pub usb: u16, - /// The USB Class Code. - /// - /// bDeviceClass in USB32 Table 9-11. - /// - /// These are values assigned by USB-IF that describes the type of device connected via USB. - /// - /// A value of FF indicates a vendor-specific class. A value of 0 indicates that all the - /// interfaces in a configuration will provide their own class information. - pub class: u8, - /// The USB Sub Device Class Code. - /// - /// bDeviceSubClass in USB32 Table 9-11 - /// - /// These specify subclasses of a device class specified by the 'class' field. - pub sub_class: u8, - /// The USB Protocol code. - /// - /// bDeviceProtocol in USB32 Table 9-11 - /// - /// This qualified by the class and sub_class fields, and specifies the application-layer protocol - /// (the protocol encapsulated by USB) of this device. - pub protocol: u8, - /// The maximum packet size for endpoint 0. - /// - /// bMaxPacketSize0 in USB32 Table 9-11 - pub packet_size: u8, - /// The USB Vendor ID - /// - /// idVendor in USB32 Table 9-11 - pub vendor: u16, - /// The USB Product ID - /// - /// idProduct in USB32 Table 9-11 - pub product: u16, - /// The device release number in binary-coded decimal. - /// - /// bcdDevice in USB32 Table 9-11 - pub release: u16, - /// Index of the String Descriptor describing the device manufacturer - /// - /// iManufacturer in USB32 Table 9-11 - pub manufacturer_str: u8, - /// Index of the String Descriptor describing the product - /// - /// iProduct in Table 9-11 - pub product_str: u8, - /// Index of the string descriptor describing the device's serial number - /// - /// iSerialNumber in USB32 Table 9-11 - pub serial_str: u8, - /// The number of possible configurations (Configuration Descriptors) for this device. - /// - /// bNumConfigurations in USB32 Table 9-11 - pub configurations: u8, -} - -unsafe impl plain::Plain for DeviceDescriptor {} - -impl DeviceDescriptor { - /// Gets the USB Minor Version - pub fn minor_usb_vers(&self) -> u8 { - (self.usb & 0xFF) as u8 - } - /// Gets the USB Major Version - pub fn major_usb_vers(&self) -> u8 { - ((self.usb >> 8) & 0xFF) as u8 - } -} - -/// The 8-byte version of the Device Descriptor -/// -/// This is a subset of the full Device Descriptor. When the system is first performing device -/// enumeration, it will request only the first eight bytes of the DeviceDescriptor from each -/// device as this contains the crucial information, and then it will request the full descriptor -/// at a later point. -/// -/// See [DeviceDescriptor] -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct DeviceDescriptor8Byte { - /// See [DeviceDescriptor] - pub length: u8, - /// See [DeviceDescriptor] - pub kind: u8, - /// See [DeviceDescriptor] - pub usb: u16, - /// See [DeviceDescriptor] - pub class: u8, - /// See [DeviceDescriptor] - pub sub_class: u8, - /// See [DeviceDescriptor] - pub protocol: u8, - /// See [DeviceDescriptor] - pub packet_size: u8, -} - -unsafe impl plain::Plain for DeviceDescriptor8Byte {} - -impl DeviceDescriptor8Byte { - /// Gets the USB Minor Version - pub fn minor_usb_vers(&self) -> u8 { - (self.usb & 0xFF) as u8 - } - - /// Gets the USB Major Version - pub fn major_usb_vers(&self) -> u8 { - ((self.usb >> 8) & 0xFF) as u8 - } -} - -/// A Device Qualifier Descriptor -/// -/// This is a descriptor specific to the USB2 standard, and was deprecated in USB3. USB2 devices -/// will still provide this value. -/// -/// A Device Qualifier is sent by a high-speed capable USB2 device to describe information in its -/// descriptor that would change if it was operating at the other speed. If it was at low speed, -/// the qualifier would describe the device at high speed. If it was at high speed, the qualifier -/// would describe the device at low speed. -/// -/// See USB2 section 9.6.2 -/// -/// The packet offsets are described in USB2 Table 9-9 -#[repr(C, packed)] -pub struct DeviceQualifier { - /// The size of the descriptor. - /// - /// bLength in USB2 Table 9-9 - pub length: u8, - /// The Device Descriptor Type (see [xhci_interface::usb::DescriptorKind]) - /// - /// bDescriptorType in USB2 Table 9-9 - pub kind: u8, - /// The USB specification version number in binary-coded decimal - /// - /// bDeviceClass in USB2 Table 9-9 - pub usb: u16, - /// The USB Device Class Code - /// - /// bDeviceClass in USB2 Table 9-9 - pub class: u8, - /// The USB Device Sub Class Code - /// - /// bDeviceSubClass in USB2 Table 9-9 - pub sub_class: u8, - /// The USB Device Protocol Code - /// - /// bDeviceProtocol in USB2 Table 9-9 - pub protocol: u8, - /// The maximum packet size for the other speed\ - /// - /// bMaxPacketSize0 in USB2 Table9-9 - pub pkgsz_other_speed: u8, - /// The number of device configurations for the other speed - /// - /// bNumConfiguration in USB2 Table 9-9 - pub num_other_speed_cfgs: u8, - /// Reserved for future use by the USB2 standard - /// - /// (DeviceQualifier was dropped in USB3, so it was never used!) - /// bReserved in USB2 Table 9-9 - pub _rsvd: u8, -} - -unsafe impl plain::Plain for DeviceQualifier {} diff --git a/recipes/core/base/drivers/usb/xhcid/src/usb/endpoint.rs b/recipes/core/base/drivers/usb/xhcid/src/usb/endpoint.rs deleted file mode 100644 index e0f3510a7d..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/usb/endpoint.rs +++ /dev/null @@ -1,86 +0,0 @@ -use plain::Plain; - -/// The descriptor for a USB Endpoint. -/// -/// Each endpoint for a particular interface has its own descriptor. The information in this -/// structure is used by the host to determine the bandwidth requirements of the endpoint. -/// -/// This is returned automatically when you send a request for a ConfigurationDescriptor, -/// and cannot be requested individually. -/// -/// See USB32 9.6.6 -/// -/// The offsets for the fields in the packet are described in USB32 Table 9-26 -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct EndpointDescriptor { - pub length: u8, - pub kind: u8, - pub address: u8, - pub attributes: u8, - pub max_packet_size: u16, - pub interval: u8, -} - -/// Mask that is ANDed to the [EndpointDescriptor].attributes buffer to get the endpoint type. -pub const ENDP_ATTR_TY_MASK: u8 = 0x3; - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum EndpointTy { - Ctrl = 0, - Isoch = 1, - Bulk = 2, - Interrupt = 3, -} - -impl EndpointDescriptor { - fn ty(self) -> EndpointTy { - match self.attributes & ENDP_ATTR_TY_MASK { - 0 => EndpointTy::Ctrl, - 1 => EndpointTy::Isoch, - 2 => EndpointTy::Bulk, - 3 => EndpointTy::Interrupt, - _ => unreachable!(), - } - } -} - -unsafe impl Plain for EndpointDescriptor {} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct SuperSpeedCompanionDescriptor { - pub length: u8, - pub kind: u8, - pub max_burst: u8, - pub attributes: u8, - pub bytes_per_interval: u16, -} -unsafe impl Plain for SuperSpeedCompanionDescriptor {} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct SuperSpeedPlusIsochCmpDescriptor { - pub length: u8, - pub kind: u8, - pub reserved: u16, - pub bytes_per_interval: u32, -} -unsafe impl Plain for SuperSpeedPlusIsochCmpDescriptor {} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct HidDescriptor { - pub length: u8, - pub kind: u8, - pub hid_spec_release: u16, - pub country_code: u8, - pub num_descriptors: u8, - pub report_desc_ty: u8, - pub report_desc_len: u16, - pub optional_desc_ty: u8, - pub optional_desc_len: u16, -} - -unsafe impl Plain for HidDescriptor {} diff --git a/recipes/core/base/drivers/usb/xhcid/src/usb/hub.rs b/recipes/core/base/drivers/usb/xhcid/src/usb/hub.rs deleted file mode 100644 index 9dab55e85a..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/usb/hub.rs +++ /dev/null @@ -1,187 +0,0 @@ -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct HubDescriptorV2 { - pub length: u8, - pub kind: u8, - pub ports: u8, - pub characteristics: u16, - pub power_on_good: u8, - pub current: u8, - /*TODO: USB 2 and 3 disagree on the descriptor, so some fields are disabled - // device_removable: bitmap of ports, maximum of 256 bits (32 bytes) - // power_control_mask: bitmap of ports, maximum of 256 bits (32 bytes) - bitmaps: [u8; 64], - */ -} - -unsafe impl plain::Plain for HubDescriptorV2 {} - -impl HubDescriptorV2 { - pub const DESCRIPTOR_KIND: u8 = 0x29; -} - -impl Default for HubDescriptorV2 { - fn default() -> Self { - Self { - length: 0, - kind: 0, - ports: 0, - characteristics: 0, - power_on_good: 0, - current: 0, - /* - bitmaps: [0; 64], - */ - } - } -} - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug)] -pub struct HubDescriptorV3 { - pub length: u8, - pub kind: u8, - pub ports: u8, - pub characteristics: u16, - pub power_on_good: u8, - pub current: u8, - pub decode_latency: u8, - pub delay: u16, - /*TODO: USB 2 and 3 disagree on the descriptor, so some fields are disabled - // device_removable: bitmap of ports, maximum of 256 bits (32 bytes) - // power_control_mask: bitmap of ports, maximum of 256 bits (32 bytes) - bitmaps: [u8; 64], - */ -} - -unsafe impl plain::Plain for HubDescriptorV3 {} - -impl HubDescriptorV3 { - pub const DESCRIPTOR_KIND: u8 = 0x2A; -} - -impl Default for HubDescriptorV3 { - fn default() -> Self { - Self { - length: 0, - kind: 0, - ports: 0, - characteristics: 0, - power_on_good: 0, - current: 0, - decode_latency: 0, - delay: 0, - /* - bitmaps: [0; 64], - */ - } - } -} - -// This only includes matching features from both USB 2.0 and 3.0 specs -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -pub enum HubPortFeature { - PortConnection = 0, - PortOverCurrent = 3, - PortReset = 4, - PortLinkState = 5, - PortPower = 8, - CPortConnection = 16, - CPortOverCurrent = 19, - CPortReset = 20, -} - -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] - #[repr(transparent)] - pub struct HubPortStatusV2: u32 { - const CONNECTION = 1 << 0; - const ENABLE = 1 << 1; - const SUSPEND = 1 << 2; - const OVER_CURRENT = 1 << 3; - const RESET = 1 << 4; - // bits 5-7 reserved - const POWER = 1 << 8; - const LOW_SPEED = 1 << 9; - const HIGH_SPEED = 1 << 10; - const TEST = 1 << 11; - const INDICATOR = 1 << 12; - // bits 13-15 reserved - const CONNECTION_CHANGED = 1 << 16; - const ENABLE_CHANGED = 1 << 17; - const SUSPEND_CHANGED = 1 << 18; - const OVER_CURRENT_CHANGED = 1 << 19; - const RESET_CHANGED = 1 << 20; - // bits 21 - 31 reserved - } -} - -unsafe impl plain::Plain for HubPortStatusV2 {} - -bitflags::bitflags! { - #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] - #[repr(transparent)] - pub struct HubPortStatusV3: u32 { - const CONNECTION = 1 << 0; - const ENABLE = 1 << 1; - // bit 2 reserved - const OVER_CURRENT = 1 << 3; - const RESET = 1 << 4; - const LINK_STATE_0 = 1 << 5; - const LINK_STATE_1 = 1 << 6; - const LINK_STATE_2 = 1 << 7; - const LINK_STATE_3 = 1 << 8; - const POWER = 1 << 9; - const SPEED_0 = 1 << 10; - const SPEED_1 = 1 << 11; - const SPEED_2 = 1 << 12; - // bits 13 - 15 reserved - const CONNECTION_CHANGED = 1 << 16; - // bits 17-18 - const OVER_CURRENT_CHANGED = 1 << 19; - const RESET_CHANGED = 1 << 20; - const BH_RESET_CHANGED = 1 << 21; - const LINK_STATE_CHANGED = 1 << 22; - const CONFIG_ERROR = 1 << 23; - // bits 24 - 31 reserved - } -} - -unsafe impl plain::Plain for HubPortStatusV3 {} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum HubPortStatus { - V2(HubPortStatusV2), - V3(HubPortStatusV3), -} - -impl HubPortStatus { - pub fn is_powered(&self) -> bool { - match self { - Self::V2(x) => x.contains(HubPortStatusV2::POWER), - Self::V3(x) => x.contains(HubPortStatusV3::POWER), - } - } - - pub fn is_connected(&self) -> bool { - match self { - Self::V2(x) => x.contains(HubPortStatusV2::CONNECTION), - Self::V3(x) => x.contains(HubPortStatusV3::CONNECTION), - } - } - - pub fn is_resetting(&self) -> bool { - match self { - Self::V2(x) => x.contains(HubPortStatusV2::RESET), - Self::V3(x) => x.contains(HubPortStatusV3::RESET), - } - } - - pub fn is_enabled(&self) -> bool { - match self { - Self::V2(x) => x.contains(HubPortStatusV2::ENABLE), - Self::V3(x) => x.contains(HubPortStatusV3::ENABLE), - } - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/usb/interface.rs b/recipes/core/base/drivers/usb/xhcid/src/usb/interface.rs deleted file mode 100644 index 4b60e06cf0..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/usb/interface.rs +++ /dev/null @@ -1,18 +0,0 @@ -use plain::Plain; - -/// -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct InterfaceDescriptor { - pub length: u8, - pub kind: u8, - pub number: u8, - pub alternate_setting: u8, - pub endpoints: u8, - pub class: u8, - pub sub_class: u8, - pub protocol: u8, - pub interface_str: u8, -} - -unsafe impl Plain for InterfaceDescriptor {} diff --git a/recipes/core/base/drivers/usb/xhcid/src/usb/mod.rs b/recipes/core/base/drivers/usb/xhcid/src/usb/mod.rs deleted file mode 100644 index d0d659882a..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/usb/mod.rs +++ /dev/null @@ -1,63 +0,0 @@ -//! The Universal Serial Bus (USB) Module -//! -//! The implementations in this module are common to all USB interfaces (though individual elements -//! may be specific to only 2.0 or 3.2), and are used by specialized driver components like [xhci] -//! to implement the driver interface. -//! -//! The [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification) and the [Universal Serial Bus 3.2 Specification](https://usb.org/document-library/usb-32-revision-11-june-2022) are -//! the documents that inform this implementation. -//! -//! See the crate-level documentation for the acronyms used to refer to specific documents. -pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuperSpeedDesc}; -pub use self::config::ConfigDescriptor; -pub use self::device::{DeviceDescriptor, DeviceDescriptor8Byte}; -pub use self::endpoint::{ - EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, - SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK, -}; -pub use self::hub::*; -pub use self::interface::InterfaceDescriptor; -pub use self::setup::{Setup, SetupReq}; - -/// Enumerates the list of descriptor kinds that can be reported by a USB device to report its -/// attributes to the system. (See USB32 Sections 9.5 and 9.6) -#[derive(Clone, Copy, Debug)] -#[repr(u8)] -pub enum DescriptorKind { - /// No Descriptor TODO: Determine why this state exists, and what it does in the code. - None = 0, - /// A Device Descriptor. See [DeviceDescriptor] - Device = 1, - /// A Configuration Descriptor. See [ConfigDescriptor] - Configuration = 2, - /// A String Descriptor. See (USB32 Section 9.6.9). - String = 3, - /// An Interface Descriptor. See [InterfaceDescriptor] - Interface = 4, - /// An Endpoint Descriptor. See [EndpointDescriptor] - Endpoint = 5, - /// A Device Qualifier. USB2-specific. See [DeviceQualifier] - DeviceQualifier = 6, - /// The "Other Speed Configuration" descriptor. USB2-specific. See (USB2 9.6.4] - OtherSpeedConfiguration = 7, - /// TODO: Determine the standard that specifies this - InterfacePower = 8, - /// TODO: Determine the standard that specifies this (Possibly USB-C?) - OnTheGo = 9, - /// A Binary Device Object Store Descriptor. See [BosDescriptor] - BinaryObjectStorage = 15, - /// TODO: Track down the HID standard for references - Hid = 33, - /// A USB Hub Device Descriptor. See [HubDescriptor] - Hub = 41, - /// A Super Speed Endpoint Companion Descriptor. See [SuperSpeedCompanionDescriptor] - SuperSpeedCompanion = 48, -} - -pub(crate) mod bos; -pub(crate) mod config; -pub(crate) mod device; -pub(crate) mod endpoint; -pub(crate) mod hub; -pub(crate) mod interface; -pub(crate) mod setup; diff --git a/recipes/core/base/drivers/usb/xhcid/src/usb/setup.rs b/recipes/core/base/drivers/usb/xhcid/src/usb/setup.rs deleted file mode 100644 index dc315ac502..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/usb/setup.rs +++ /dev/null @@ -1,209 +0,0 @@ -use super::DescriptorKind; -use crate::driver_interface::*; - -#[repr(C, packed)] -#[derive(Clone, Copy, Debug, Default)] -pub struct Setup { - pub kind: u8, - pub request: u8, - pub value: u16, - pub index: u16, - pub length: u16, -} - -#[repr(u8)] -pub enum ReqDirection { - HostToDevice = 0, - DeviceToHost = 1, -} -impl From for ReqDirection { - fn from(d: PortReqDirection) -> Self { - match d { - PortReqDirection::DeviceToHost => Self::DeviceToHost, - PortReqDirection::HostToDevice => Self::HostToDevice, - } - } -} - -#[repr(u8)] -pub enum ReqType { - /// Standard device requests, such as SET_ADDRESS and SET_CONFIGURATION. These aren't directly - /// accessible using the API, but are sent from xhcid when required. - Standard = 0, - - /// Class specific requests that are directly accessible from the API. - Class = 1, - - /// Vendor specific requests that are accessible using the API. - Vendor = 2, - - /// Reserved - Reserved = 3, -} -impl From for ReqType { - fn from(d: PortReqTy) -> Self { - match d { - PortReqTy::Standard => Self::Standard, - PortReqTy::Class => Self::Class, - PortReqTy::Vendor => Self::Vendor, - } - } -} - -#[repr(u8)] -pub enum ReqRecipient { - Device = 0, - Interface = 1, - Endpoint = 2, - Other = 3, - // 4..=30 are reserved - VendorSpecific = 31, -} -impl From for ReqRecipient { - fn from(d: PortReqRecipient) -> Self { - match d { - PortReqRecipient::Device => Self::Device, - PortReqRecipient::Interface => Self::Interface, - PortReqRecipient::Endpoint => Self::Endpoint, - PortReqRecipient::Other => Self::Other, - PortReqRecipient::VendorSpecific => Self::VendorSpecific, - } - } -} - -#[repr(u8)] -pub enum SetupReq { - GetStatus = 0x00, - ClearFeature = 0x01, - SetFeature = 0x03, - SetAddress = 0x05, - GetDescriptor = 0x06, - SetDescriptor = 0x07, - GetConfiguration = 0x08, - SetConfiguration = 0x09, - GetInterface = 0x0A, - SetInterface = 0x0B, - SynchFrame = 0x0C, -} - -pub const USB_SETUP_DIR_BIT: u8 = 1 << 7; -pub const USB_SETUP_DIR_SHIFT: u8 = 7; -pub const USB_SETUP_REQ_TY_MASK: u8 = 0x60; -pub const USB_SETUP_REQ_TY_SHIFT: u8 = 5; -pub const USB_SETUP_RECIPIENT_MASK: u8 = 0x1F; -pub const USB_SETUP_RECIPIENT_SHIFT: u8 = 0; - -impl Setup { - pub fn direction(&self) -> ReqDirection { - if self.kind & USB_SETUP_DIR_BIT == 0 { - ReqDirection::HostToDevice - } else { - ReqDirection::DeviceToHost - } - } - pub const fn req_ty(&self) -> u8 { - (self.kind & USB_SETUP_REQ_TY_MASK) >> USB_SETUP_REQ_TY_SHIFT - } - - pub const fn req_recipient(&self) -> u8 { - (self.kind & USB_SETUP_RECIPIENT_MASK) >> USB_SETUP_RECIPIENT_SHIFT - } - pub fn is_allowed_from_api(&self) -> bool { - self.req_ty() == ReqType::Class as u8 || self.req_ty() == ReqType::Vendor as u8 - } - - pub const fn get_status() -> Self { - Self { - kind: 0b1000_0000, - request: 0x00, - value: 0, - index: 0, - length: 2, - } - } - - pub const fn clear_feature(feature: u16) -> Self { - Self { - kind: 0b0000_0000, - request: 0x01, - value: feature, - index: 0, - length: 0, - } - } - - pub const fn set_feature(feature: u16) -> Self { - Self { - kind: 0b0000_0000, - request: 0x03, - value: feature, - index: 0, - length: 0, - } - } - - pub const fn set_address(address: u16) -> Self { - Self { - kind: 0b0000_0000, - request: 0x05, - value: address, - index: 0, - length: 0, - } - } - - pub const fn get_descriptor( - kind: DescriptorKind, - index: u8, - language: u16, - length: u16, - ) -> Self { - Self { - kind: 0b1000_0000, - request: 0x06, - value: ((kind as u16) << 8) | (index as u16), - index: language, - length: length, - } - } - - pub const fn set_descriptor(kind: u8, index: u8, language: u16, length: u16) -> Self { - Self { - kind: 0b0000_0000, - request: 0x07, - value: ((kind as u16) << 8) | (index as u16), - index: language, - length: length, - } - } - - pub const fn get_configuration() -> Self { - Self { - kind: 0b1000_0000, - request: 0x08, - value: 0, - index: 0, - length: 1, - } - } - - pub const fn set_configuration(value: u8) -> Self { - Self { - kind: 0b0000_0000, - request: 0x09, - value: value as u16, - index: 0, - length: 0, - } - } - - pub const fn set_interface(interface: u8, alternate_setting: u8) -> Self { - Self { - kind: 0b0000_0001, - request: 0x0B, - value: alternate_setting as u16, - index: interface as u16, - length: 0, - } - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/capability.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/capability.rs deleted file mode 100644 index 2ad4ad1aa0..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/capability.rs +++ /dev/null @@ -1,225 +0,0 @@ -use common::io::{Io, Mmio}; - -/// Represents the memory-mapped Capability Registers of the XHCI -/// -/// These are read-only registers that specify the capabilities -/// of the host controller implementation. -/// -/// They are used by the driver to determine what subsystems to -/// configure during initialization. -/// -/// See XHCI Section 5.3. Table 5-9 describes the offsets of the registers -/// in memory. -#[repr(C, packed)] -pub struct CapabilityRegs { - /// The length of the Capability Registers data structure in XHCI memory. - /// - /// While only the registers in this structure are defined by the XHCI standard, - /// the standard defines an arbitrary amount of space following those registers that - /// are reserved for the standard. As such, you need to know the offset to the operational - /// registers, which immediately follow. - /// - /// CAPLENGTH in XHC Table 5-9. See XHC 5.3.1 - pub len: Mmio, - /// Reserved byte - /// - /// Rsvd in XHC Table 5-9 - _rsvd: Mmio, - /// The XHCI interface version number in Binary-Encoded Decimal. - /// - /// This specifies the version of the XHCI specification that is supported by this controller. - /// HCIVERSION in XHC Table 5-9 - pub hci_ver: Mmio, - /// The HCI Structural Parameters 1 Register. - /// - /// -Bits 0 - 7 describe the number of device slots supported by this controller - /// -Bits 8 - 18 describe the number of interrupters supported by this controller - /// -Bits 19-23 are reserved - /// -Bits 24-31 specify the maximum number of ports supported by this controller. - /// - /// HCPARAMS1 in XHC Table 5-9. See 5.3.3 - pub hcs_params1: Mmio, - /// The HCI Structural Parameters 2 Register. - /// - /// - Bits 0-3 describe the Isochronus Scheduling Threshold (IST) - /// - Bits 4-7 describe the Event Ring Segment Table Max (ERST Max). The maximum number of event - /// ring segment table entries is 2^(ERST Max) - /// - Bits 8-20 are reserved - /// - Bits 25-21 describe the high order five bits of the maximum number of scratchpad buffers - /// - Bit 26 is the Scratchpad Restore Buffer (SPR). (See XHC 4.23.2) - /// - Bits 26-31 describe the low order five bits of the maximum number of scratchpad buffers - /// - /// HCPARAMS2 in XHC Table 5-9. See 5.3.4 - pub hcs_params2: Mmio, - /// The HCI Structural Parameters 3 Register. - /// - /// - Bits 0-7 describes the worst-case U1 Device Exit Latency. Values are in microseconds, from 00h to 0Ah. 0B-FFh are reserved - /// - Bits 8-15 are reserved - /// - Bits 16-31 describe the worst-case U2 Device Exit Latency. Values are in microseconds, from 0000h to 07FFh. 0800-FFFFh are reserved - /// - /// HCPARAMS3 in XHC Table 5-9. See XHC 5.3.5 - pub hcs_params3: Mmio, - /// The HCI Capability Parameters 1 Register. - /// - /// This register defines optional capabilities supported by the xHCI - /// - /// - Bit 0 is the 64-bit Address Capability Flag (AC64). 0 = 32-bit pointers, 1 = 64-bit pointers. - /// - Bit 1 is the Bandwidth Negotation Capability Flag (BNC) - /// - Bit 2 is the Context Size Flag (CSZ). 0 = 32-byte, 1 = 64-byte Context Data Structures - /// - Bit 3 is the Port Power Control Flag (PPC). Indicates whether the implementation supports port power control. - /// - Bit 4 is the Port Indicators Flag (PIND). Indicates whether the XHC root hub supports port indicator control - /// - Bit 5 is the Light Host Controller Reset Capability Flag (LHRC). Indicates whether the implementation supports a light reset - /// - Bit 6 is the Latency Tolerance Messaging Capability Flag (LTC). Indicates whether the implementation supports Latency Tolerance Messaging - /// - Bit 7 is the no Secondary SID Support Flag (NSS). Indicates whether secondary stream ids is supported. 1 = NO, 0 = YES - /// - Bit 8 is the Parse All Event Data Flag (PAE). (See XHC Table 5-13) - /// - Bit 9 is the Stopped - Short Packet Capability Flag (SPC). (See XHC 4.6.9) - /// - Bit 10 is the Stopped EDTLA Capability Flag (SEC). (See XHC 4.6.9, 4.12, and 6.4.4.1) - /// - Bit 11 is the Contiguous Frame ID Capability Flag (CFC). (See XHC 4.11.2.5) - /// - Bits 12-15 are the Maximum Primary Stream Array Size (MaxPSASize). Identifies the maximum size of PSA that the implementation supports. - /// - Bits 16-31 The xHCI Extended Capabilities Pointer (xECP). Points to an extended capabilities list. (See XHC Table 5-13 to see how to process this value) - /// - /// HCCPARAMS1 in XHC Table 5-9. See XHC 5.3.6 - pub hcc_params1: Mmio, - /// The Doorbell Offset Register - /// - /// This register defines the offset of the Doorbell Array base address from the Base. - /// - /// Bits 0-1 are reserved. - /// Bits 2-31 contain the offset. - /// - /// DBOFF in XHC Table 5-9. See XHC 5.3.7 - pub db_offset: Mmio, - /// The Runtime Register Space Offset - /// - /// The offset of the xHCI Runtime Registers from the Base. - /// - /// - Bits 0-4 are reserved. - /// - Bits 5-31 contain the offset. - /// - /// RTSOFF in XHC Table 5-9. See XHC 5.3.8 - pub rts_offset: Mmio, - /// The HC Capability Parameters 2 Register - /// - /// This register defines optional capabilities supported by the xHCI - /// - /// - Bit 0 is the UC3 Entry Capability Flag (U3C). See XHC 4.15.1 - /// - Bit 1 is the Configure Endpoint Command Max Latency Too Large Capability Flag (CMC). See XHC 4.23.5.2 and 5.4.1 - /// - Bit 2 is the Force Save Context Capability (FCS). See XHC 4.23.2 and 5.4.1 - /// - Bit 3 is the Compliance Transition Capability (CTC). See XHC 4.19.2.4.1 - /// - Bit 4 is the Large ESIT Payload Capability (LEC). See XHC 6.2.3.8 - /// - Bit 5 is the Configuration Information Capability (CIC). See XHC 6.2.5.1 - /// - Bit 6 is the Extended TBC Capability (ETC). See XHC 4.11.2.3 - /// - Bit 7 is the Extended TBC TRB Status Capability (ETC_TSC). See XHC 4.11.2.3 - /// - Bit 8 is the Get/Set Extended Property Capability (GSC). See Sections XHC 4.6.17 and 4.6.18 - /// - Bits 10-31 are reserved. - pub hcc_params2: Mmio, - //TODO: VTIOSOFF register for I/O virtualization -} - -/// The mask to use to get the AC64 bit from HCCPARAMS1. See [CapabilityRegs] -pub const HCC_PARAMS1_AC64_BIT: u32 = 1 << HCC_PARAMS1_AC64_SHIFT; -/// The shift to use to get the AC64 bit from HCCParams1. See [CapabilityRegs] -pub const HCC_PARAMS1_AC64_SHIFT: u8 = 0; -/// The mask to use to get the CSZ bit from HCCPARAMS1. See [CapabilityRegs] -pub const HCC_PARAMS1_CSZ_BIT: u32 = 1 << HCC_PARAMS1_CSZ_SHIFT; -/// The shift to use to get the CSZ bit from HCCParams1. See [CapabilityRegs] -pub const HCC_PARAMS1_CSZ_SHIFT: u8 = 2; -/// The Mask to use to get the MAXPSASIZE value from HCCParams1. See [CapabilityRegs] -pub const HCC_PARAMS1_MAXPSASIZE_MASK: u32 = 0xF000; // 15:12 -/// The shift to use to get the MAXPSASIZE value from HCCParams1. See [CapabilityRegs] -pub const HCC_PARAMS1_MAXPSASIZE_SHIFT: u8 = 12; -/// The mask to use to get the XECP value from HCCParams1. See [CapabilityRegs] -pub const HCC_PARAMS1_XECP_MASK: u32 = 0xFFFF_0000; -/// The shift to use to get the XECP value from HCCParams1. See [CapabilityRegs] -pub const HCC_PARAMS1_XECP_SHIFT: u8 = 16; - -/// The mask to use to get the LEC bit from HCCParams2. See [CapabilityRegs] -pub const HCC_PARAMS2_LEC_BIT: u32 = 1 << 4; -/// The mask to use to get the CIC bit from HCCParams2. See [CapabilityRegs] -pub const HCC_PARAMS2_CIC_BIT: u32 = 1 << 5; -/// The mask to use to get MAXPORTS from HCSParams1. See [CapabilityRegs] -pub const HCS_PARAMS1_MAX_PORTS_MASK: u32 = 0xFF00_0000; -/// The shift to use to get MAXPORTS from HCSParams1. See [CapabilityRegs] -pub const HCS_PARAMS1_MAX_PORTS_SHIFT: u8 = 24; -/// The shift to use to get MAXSLOTS from HCSParams1. See [CapabilityRegs] -pub const HCS_PARAMS1_MAX_SLOTS_MASK: u32 = 0x0000_00FF; -/// The shift to use to get MAXSLOTS from HCSParams1. See [CapabilityRegs] -pub const HCS_PARAMS1_MAX_SLOTS_SHIFT: u8 = 0; -/// The mask to use to get MAXSCRATPADBUFS_LO from HCSParams2. See [CapabilityRegs] -pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK: u32 = 0xF800_0000; -/// The shift to use to get MAXSCRATCHPADBUFS_LO from HCSParams2. See [CapabilityRegs] -pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT: u8 = 27; -/// The mask to use to get the SPR bit from HCSParams2. See [CapabilityRegs] -pub const HCS_PARAMS2_SPR_BIT: u32 = 1 << HCS_PARAMS2_SPR_SHIFT; -/// The shift to use to get the SPR bit from HCSParams2. See [CapabilityRegs] -pub const HCS_PARAMS2_SPR_SHIFT: u8 = 26; -/// The mask to use to get MAXSCRATCHPADBUFS_HI from HCSParams2. See [CapabilityRegs] -pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK: u32 = 0x03E0_0000; -/// The shift to use to get MAXSCRATCHPADBUFS_HI from HCSParams2. See [CapabilityRegs] - -pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT: u8 = 21; - -impl CapabilityRegs { - /// Gets the ACS64 bit from HCCParams1. - pub fn ac64(&self) -> bool { - self.hcc_params1.readf(HCC_PARAMS1_AC64_BIT) - } - - /// Gets the context size (CSZ) bit from HCCParams1. - pub fn csz(&self) -> bool { - self.hcc_params1.readf(HCC_PARAMS1_CSZ_BIT) - } - - /// Gets the LEC bit from HCCParams2. - pub fn lec(&self) -> bool { - self.hcc_params2.readf(HCC_PARAMS2_LEC_BIT) - } - /// Gets the CIC bit from HCCParams2. - pub fn cic(&self) -> bool { - self.hcc_params2.readf(HCC_PARAMS2_CIC_BIT) - } - - /// Gets the Max PSA Size from HCCParams1 - pub fn max_psa_size(&self) -> u8 { - ((self.hcc_params1.read() & HCC_PARAMS1_MAXPSASIZE_MASK) >> HCC_PARAMS1_MAXPSASIZE_SHIFT) - as u8 - } - - /// Gets the maximum number of ports from HCCParams1 - pub fn max_ports(&self) -> u8 { - ((self.hcs_params1.read() & HCS_PARAMS1_MAX_PORTS_MASK) >> HCS_PARAMS1_MAX_PORTS_SHIFT) - as u8 - } - - /// Gets the maximum number of ports from HCCParams 2 - pub fn max_slots(&self) -> u8 { - (self.hcs_params1.read() & HCS_PARAMS1_MAX_SLOTS_MASK) as u8 - } - - /// Gets the extended capability pointer from HCCParams1 in DWORDs. - pub fn ext_caps_ptr_in_dwords(&self) -> u16 { - ((self.hcc_params1.read() & HCC_PARAMS1_XECP_MASK) >> HCC_PARAMS1_XECP_SHIFT) as u16 - } - - /// Gets the lower five bits from the Max Scratchpad Buffer Lo Register in HCSParams2 - pub fn max_scratchpad_bufs_lo(&self) -> u8 { - ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) - >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) as u8 - } - - /// Gets the SPR register from HCSParams2 - pub fn spr(&self) -> bool { - self.hcs_params2.readf(HCS_PARAMS2_SPR_BIT) - } - - /// Gets the higher five bits from the Max Scratchpad Buffer Hi Register in HCSParams2 - pub fn max_scratchpad_bufs_hi(&self) -> u8 { - ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) - >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) as u8 - } - - /// Gets the maximum number of scratchpad buffers supported by this implementation. - pub fn max_scratchpad_bufs(&self) -> u16 { - u16::from(self.max_scratchpad_bufs_lo()) | (u16::from(self.max_scratchpad_bufs_hi()) << 5) - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/context.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/context.rs deleted file mode 100644 index b8f2f45a95..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/context.rs +++ /dev/null @@ -1,228 +0,0 @@ -use std::collections::BTreeMap; - -use common::io::{Io, Mmio}; -use log::debug; -use syscall::error::Result; -use syscall::PAGE_SIZE; - -use common::dma::Dma; - -use super::ring::Ring; -use super::Xhci; - -pub const CONTEXT_32: usize = 0; -pub const CONTEXT_64: usize = 1; - -#[repr(C, packed)] -struct Rsvd64([[Mmio; 8]; N]); - -#[repr(C, packed)] -pub struct SlotContext { - pub a: Mmio, - pub b: Mmio, - pub c: Mmio, - pub d: Mmio, - _rsvd: [Mmio; 4], - _rsvd64: Rsvd64, -} - -pub const SLOT_CONTEXT_STATE_MASK: u32 = 0xF800_0000; -pub const SLOT_CONTEXT_STATE_SHIFT: u8 = 27; - -#[repr(u8)] -pub enum SlotState { - EnabledOrDisabled = 0, - Default = 1, - Addressed = 2, - Configured = 3, -} - -#[repr(C, packed)] -pub struct EndpointContext { - pub a: Mmio, - pub b: Mmio, - pub trl: Mmio, - pub trh: Mmio, - pub c: Mmio, - _rsvd: [Mmio; 3], - _rsvd64: Rsvd64, -} - -pub const ENDPOINT_CONTEXT_STATUS_MASK: u32 = 0x7; - -#[repr(C, packed)] -pub struct DeviceContext { - pub slot: SlotContext, - pub endpoints: [EndpointContext; 31], -} - -#[repr(C, packed)] -pub struct InputContext { - pub drop_context: Mmio, - pub add_context: Mmio, - _rsvd: [Mmio; 5], - pub control: Mmio, - _rsvd64: Rsvd64, - pub device: DeviceContext, -} -impl InputContext { - pub fn dump_control(&self) { - debug!( - "INPUT CONTEXT: {} {} [{} {} {} {} {}] {}", - self.drop_context.read(), - self.add_context.read(), - self._rsvd[0].read(), - self._rsvd[1].read(), - self._rsvd[2].read(), - self._rsvd[3].read(), - self._rsvd[4].read(), - self.control.read() - ); - } -} - -pub struct DeviceContextList { - pub dcbaa: Dma<[u64; 256]>, - pub contexts: Box<[Dma>]>, -} - -impl DeviceContextList { - pub fn new(ac64: bool, max_slots: u8) -> Result { - let mut dcbaa = unsafe { Xhci::::alloc_dma_zeroed_raw::<[u64; 256]>(ac64)? }; - let mut contexts = vec![]; - - // Create device context buffers for each slot - for i in 0..max_slots as usize { - let context: Dma> = unsafe { Xhci::::alloc_dma_zeroed_raw(ac64) }?; - dcbaa[i] = context.physical() as u64; - contexts.push(context); - } - - Ok(DeviceContextList { - dcbaa, - contexts: contexts.into_boxed_slice(), - }) - } - - pub fn dcbaap(&self) -> u64 { - self.dcbaa.physical() as u64 - } -} - -#[repr(C, packed)] -pub struct StreamContext { - trl: Mmio, - trh: Mmio, - edtla: Mmio, - rsvd: Mmio, -} - -unsafe impl plain::Plain for StreamContext {} - -#[repr(u8)] -pub enum StreamContextType { - SecondaryRing, - PrimaryRing, - PrimarySsa8, - PrimarySsa16, - PrimarySsa32, - PrimarySsa64, - PrimarySsa128, - PrimarySsa256, -} - -pub struct StreamContextArray { - pub contexts: Dma<[StreamContext]>, - pub rings: BTreeMap, -} - -impl StreamContextArray { - pub fn new(ac64: bool, count: usize) -> Result { - unsafe { - Ok(Self { - contexts: Xhci::::alloc_dma_zeroed_unsized_raw(ac64, count)?, - rings: BTreeMap::new(), - }) - } - } - pub fn add_ring( - &mut self, - ac64: bool, - stream_id: u16, - link: bool, - ) -> Result<()> { - // NOTE: stream_id 0 is reserved - assert_ne!(stream_id, 0); - - let ring = Ring::new::(ac64, 16, link)?; - let pointer = ring.register(); - let sct = StreamContextType::PrimaryRing; - - assert_eq!(pointer & (!0xE), pointer); - { - let context = &mut self.contexts[stream_id as usize]; - context.trl.write((pointer as u32) | ((sct as u32) << 1)); - context.trh.write((pointer >> 32) as u32); - // TODO: stopped edtla - } - self.rings.insert(stream_id, ring); - Ok(()) - } - pub fn register(&self) -> u64 { - self.contexts.physical() as u64 - } -} - -#[repr(C, packed)] -pub struct ScratchpadBufferEntry { - pub value_low: Mmio, - pub value_high: Mmio, -} -impl ScratchpadBufferEntry { - pub fn set_addr(&mut self, addr: u64) { - self.value_low.write(addr as u32); - self.value_high.write((addr >> 32) as u32); - } -} - -pub struct ScratchpadBufferArray { - pub entries: Dma<[ScratchpadBufferEntry]>, - pub pages: Vec>, -} -impl ScratchpadBufferArray { - pub fn new(ac64: bool, entries: u16) -> Result { - let mut entries = - unsafe { Xhci::::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? }; - - let pages = entries - .iter_mut() - .map( - |entry: &mut ScratchpadBufferEntry| -> Result<_, syscall::Error> { - let dma = unsafe { Dma::<[u8; PAGE_SIZE]>::zeroed()?.assume_init() }; - assert_eq!(dma.physical() % PAGE_SIZE, 0); - entry.set_addr(dma.physical() as u64); - Ok(dma) - }, - ) - .collect::, _>>()?; - - Ok(Self { entries, pages }) - } - pub fn register(&self) -> usize { - self.entries.physical() - } -} - -#[cfg(test)] -mod test { - use super::*; - use core::mem; - - #[test] - fn context_size() { - assert_eq!(mem::size_of::>(), 32); - assert_eq!(mem::size_of::>(), 64); - assert_eq!(mem::size_of::>(), 32); - assert_eq!(mem::size_of::>(), 64); - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/device_enumerator.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/device_enumerator.rs deleted file mode 100644 index 74b9f73251..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/device_enumerator.rs +++ /dev/null @@ -1,143 +0,0 @@ -use crate::xhci::port::PortFlags; -use crate::xhci::{PortId, Xhci}; -use common::io::Io; -use crossbeam_channel; -use log::{debug, info, warn}; -use std::sync::Arc; -use std::time::Duration; -use syscall::EAGAIN; - -pub struct DeviceEnumerationRequest { - pub port_id: PortId, -} - -pub struct DeviceEnumerator { - hci: Arc>, - request_queue: crossbeam_channel::Receiver, -} - -impl DeviceEnumerator { - pub fn new(hci: Arc>) -> Self { - let request_queue = hci.device_enumerator_receiver.clone(); - DeviceEnumerator { hci, request_queue } - } - - pub fn run(&mut self) { - loop { - debug!("Start Device Enumerator Loop"); - let request = match self.request_queue.recv() { - Ok(req) => req, - Err(err) => { - panic!("Failed to received an enumeration request! error: {}", err) - } - }; - - let port_id = request.port_id; - let port_array_index = port_id.root_hub_port_index(); - - debug!("Device Enumerator request for port {}", port_id); - - let (len, flags) = { - let ports = self.hci.ports.lock().unwrap(); - - let len = ports.len(); - - if port_array_index >= len { - warn!( - "Received out of bounds Device Enumeration request for port {}", - port_id - ); - continue; - } - - (len, ports[port_array_index].flags()) - }; - - if flags.contains(PortFlags::CCS) { - debug!( - "Received Device Connect Port Status Change Event with port flags {:?}", - flags - ); - //If the port isn't enabled (i.e. it's a USB2 port), we need to reset it if it isn't resetting already - //A USB3 port won't generate a Connect Status Change until it's already enabled, so this check - //will always be skipped for USB3 ports - if !flags.contains(PortFlags::PED) { - let disabled_state = flags.contains(PortFlags::PP) - && flags.contains(PortFlags::CCS) - && !flags.contains(PortFlags::PED) - && !flags.contains(PortFlags::PR); - - if !disabled_state { - panic!( - "Port {} isn't in the disabled state! Current flags: {:?}", - port_id, flags - ); - } else { - debug!("Port {} has entered the disabled state.", port_id); - } - - //THIS LOCKS THE PORTS. DO NOT LOCK PORTS BEFORE THIS POINT - debug!("Received a device connect on port {}, but it's not enabled. Resetting the port.", port_id); - let _ = self.hci.reset_port(port_id); - - let mut ports = self.hci.ports.lock().unwrap(); - let port = &mut ports[port_array_index]; - - port.clear_prc(); - - std::thread::sleep(Duration::from_millis(16)); //Some controllers need some extra time to make the transition. - - let flags = port.flags(); - - let enabled_state = flags.contains(PortFlags::PP) - && flags.contains(PortFlags::CCS) - && flags.contains(PortFlags::PED) - && !flags.contains(PortFlags::PR); - - if !enabled_state { - warn!( - "Port {} isn't in the enabled state! Current flags: {:?}", - port_id, flags - ); - } else { - debug!( - "Port {} is in the enabled state. Proceeding with enumeration", - port_id - ); - } - } - - let result = futures::executor::block_on(self.hci.attach_device(port_id)); - match result { - Ok(_) => { - info!("Device on port {} was attached", port_id); - } - Err(err) => { - if err.errno == EAGAIN { - debug!("Received a device connect notification for an already connected device. Ignoring...") - } else { - warn!("processing of device attach request failed! Error: {}", err); - } - } - } - } else { - debug!( - "Device Enumerator received Detach request on port {} which is in state {}", - port_id, - self.hci.get_pls(port_id) - ); - let result = futures::executor::block_on(self.hci.detach_device(port_id)); - match result { - Ok(was_connected) => { - if was_connected { - info!("Device on port {} was detached", port_id); - } - } - Err(err) => { - warn!("processing of device attach request failed! Error: {}", err); - } - } - } - } - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/doorbell.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/doorbell.rs deleted file mode 100644 index f65db206aa..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/doorbell.rs +++ /dev/null @@ -1,14 +0,0 @@ -use common::io::{Io, Mmio}; - -#[repr(C, packed)] -pub struct Doorbell(Mmio); - -impl Doorbell { - pub fn read(&self) -> u32 { - self.0.read() - } - - pub fn write(&mut self, data: u32) { - self.0.write(data); - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/event.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/event.rs deleted file mode 100644 index 83af1209af..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/event.rs +++ /dev/null @@ -1,52 +0,0 @@ -use common::io::{Io, Mmio}; -use syscall::error::Result; - -use common::dma::Dma; - -use super::ring::Ring; -use super::trb::Trb; -use super::Xhci; - -#[repr(C, packed)] -pub struct EventRingSte { - pub address_low: Mmio, - pub address_high: Mmio, - pub size: Mmio, - _rsvd: Mmio, - _rsvd2: Mmio, -} - -// TODO: Use atomic operations, and perhaps an occasional lock for reallocating. -pub struct EventRing { - pub ste: Dma<[EventRingSte]>, - pub ring: Ring, -} - -impl EventRing { - pub fn new(ac64: bool) -> Result { - let mut ring = EventRing { - ste: unsafe { Xhci::::alloc_dma_zeroed_unsized_raw(ac64, 1)? }, - ring: Ring::new::(ac64, 256, false)?, - }; - - ring.ste[0] - .address_low - .write(ring.ring.trbs.physical() as u32); - ring.ste[0] - .address_high - .write((ring.ring.trbs.physical() as u64 >> 32) as u32); - ring.ste[0].size.write(ring.ring.trbs.len() as u16); - - Ok(ring) - } - - pub fn next(&mut self) -> &mut Trb { - self.ring.next().0 - } - pub fn erdp(&self) -> u64 { - self.ring.register() & 0xFFFF_FFFF_FFFF_FFF0 - } - pub fn erstba(&self) -> u64 { - self.ste.physical() as u64 - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/extended.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/extended.rs deleted file mode 100644 index 00ab6f2f1b..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/extended.rs +++ /dev/null @@ -1,287 +0,0 @@ -use common::io::{Io, Mmio}; -use std::ops::Range; -use std::ptr::NonNull; -use std::{fmt, mem, ptr, slice}; - -pub struct ExtendedCapabilitiesIter { - base: *const u8, -} -impl ExtendedCapabilitiesIter { - pub unsafe fn new(base: *const u8) -> Self { - Self { base } - } -} -impl Iterator for ExtendedCapabilitiesIter { - type Item = (NonNull, u8); // pointer, capability id - - fn next(&mut self) -> Option { - unsafe { - let current = NonNull::new(self.base as *mut _)?; - - let reg = current.cast::>().as_ref().read(); - let capability_id = (reg & 0xFF) as u8; - let next_rel_in_dwords = ((reg & 0xFF00) >> 8) as u8; - - let next_rel = u16::from(next_rel_in_dwords) << 2; - - self.base = if next_rel != 0 { - self.base.offset(next_rel as isize) - } else { - ptr::null() - }; - - Some((current, capability_id)) - } - } -} - -#[repr(u8)] -pub enum CapabilityId { - // bit 0 is reserved - UsbLegacySupport = 1, - SupportedProtocol, - ExtendedPowerManagement, - IoVirtualization, - MessageInterrupt, - LocalMem, - // bits 7-9 are reserved - UsbDebugCapability = 10, - // bits 11-16 are reserved - ExtendedMessageInterrupt = 17, - // bits 18-191 are reserved - // bits 192-255 are vendor-defined -} - -#[repr(C, packed)] -pub struct SupportedProtoCap { - a: Mmio, - b: Mmio, - c: Mmio, - d: Mmio, - protocol_speeds: [u8; 0], -} - -#[repr(C, packed)] -pub struct ProtocolSpeed { - a: Mmio, -} - -pub const PROTO_SPEED_PSIV_MASK: u32 = 0x0000_000F; -pub const PROTO_SPEED_PSIV_SHIFT: u8 = 0; - -pub const PROTO_SPEED_PSIE_MASK: u32 = 0x0000_0030; -pub const PROTO_SPEED_PSIE_SHIFT: u8 = 4; - -pub const PROTO_SPEED_PLT_MASK: u32 = 0x0000_00C0; -pub const PROTO_SPEED_PLT_SHIFT: u8 = 6; - -pub const PROTO_SPEED_PFD_BIT: u32 = 1 << PROTO_SPEED_PFD_SHIFT; -pub const PROTO_SPEED_PFD_SHIFT: u8 = 8; - -pub const PROTO_SPEED_LP_MASK: u32 = 0x0000_C000; -pub const PROTO_SPEED_LP_SHIFT: u8 = 14; - -pub const PROTO_SPEED_PSIM_MASK: u32 = 0xFFFF_0000; -pub const PROTO_SPEED_PSIM_SHIFT: u8 = 16; - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub enum Psie { - Bps, - Kbps, - Mbps, - Gbps, -} -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum Plt { - Symmetric, - Reserved, - AsymmetricRx, - AsymmetricTx, -} -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum Lp { - SuperSpeed, - SuperSpeedPlus, - Rsvd2, - Rsvd3, -} - -impl ProtocolSpeed { - pub const fn from_raw(raw: u32) -> Self { - Self { a: Mmio::new(raw) } - } - pub fn is_lowspeed(&self) -> bool { - self.psim() == 1500 && self.psie() == Psie::Kbps && !self.pfd() - } - pub fn is_fullspeed(&self) -> bool { - self.psim() == 12 && self.psie() == Psie::Mbps && !self.pfd() - } - pub fn is_highspeed(&self) -> bool { - self.psim() == 480 && self.psie() == Psie::Mbps && !self.pfd() - } - pub fn is_superspeed_gen1x1(&self) -> bool { - self.psim() == 5 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeed - } - pub fn is_superspeedplus_gen2x1(&self) -> bool { - self.psim() == 10 - && self.psie() == Psie::Gbps - && self.pfd() - && self.lp() == Lp::SuperSpeedPlus - } - pub fn is_superspeedplus_gen1x2(&self) -> bool { - self.psim() == 10 - && self.psie() == Psie::Gbps - && self.pfd() - && self.lp() == Lp::SuperSpeedPlus - } - pub fn is_superspeedplus_gen2x2(&self) -> bool { - self.psim() == 20 - && self.psie() == Psie::Gbps - && self.pfd() - && self.lp() == Lp::SuperSpeedPlus - } - pub fn is_superspeed_gen_x(&self) -> bool { - self.is_superspeed_gen1x1() - || self.is_superspeedplus_gen2x1() - || self.is_superspeedplus_gen1x2() - || self.is_superspeedplus_gen2x2() - } - /// Protocol speed ID value - pub fn psiv(&self) -> u8 { - ((self.a.read() & PROTO_SPEED_PSIV_MASK) >> PROTO_SPEED_PSIV_SHIFT) as u8 - } - pub fn psie_raw(&self) -> u8 { - ((self.a.read() & PROTO_SPEED_PSIE_MASK) >> PROTO_SPEED_PSIE_SHIFT) as u8 - } - /// Protocol speed ID exponent - pub fn psie(&self) -> Psie { - // safe because psie_raw can only return values in 0..=3 - unsafe { mem::transmute(self.psie_raw()) } - } - pub fn plt_raw(&self) -> u8 { - ((self.a.read() & PROTO_SPEED_PLT_MASK) >> PROTO_SPEED_PLT_SHIFT) as u8 - } - /// PSI type - pub fn plt(&self) -> Plt { - // safe because plt_raw can only return values in 0..=3 - unsafe { mem::transmute(self.plt_raw()) } - } - /// PSI Full-duplex - pub fn pfd(&self) -> bool { - self.a.readf(PROTO_SPEED_PFD_BIT) - } - pub fn lp_raw(&self) -> u8 { - ((self.a.read() & PROTO_SPEED_LP_MASK) >> PROTO_SPEED_LP_SHIFT) as u8 - } - /// Link protocol - pub fn lp(&self) -> Lp { - // safe because lp_raw can only return values in 0..=3 - unsafe { mem::transmute(self.lp_raw()) } - } - /// Protocol speed ID mantissa - pub fn psim(&self) -> u16 { - ((self.a.read() & PROTO_SPEED_PSIM_MASK) >> PROTO_SPEED_PSIM_SHIFT) as u16 - } -} - -impl fmt::Debug for ProtocolSpeed { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("ProtocolSpeed") - .field("psiv", &self.psiv()) - .field("psie", &self.psie()) - .field("plt", &self.plt()) - .field("pfd", &self.pfd()) - .field("lp", &self.lp()) - .field("psim", &self.psim()) - .finish() - } -} - -pub const SUPP_PROTO_CAP_REV_MIN_MASK: u32 = 0x00FF_0000; -pub const SUPP_PROTO_CAP_REV_MIN_SHIFT: u8 = 16; - -pub const SUPP_PROTO_CAP_REV_MAJ_MASK: u32 = 0xFF00_0000; -pub const SUPP_PROTO_CAP_REV_MAJ_SHIFT: u8 = 24; - -pub const SUPP_PROTO_CAP_COMPAT_PORT_OFF_MASK: u32 = 0x0000_00FF; -pub const SUPP_PROTO_CAP_COMPAT_PORT_OFF_SHIFT: u8 = 0; - -pub const SUPP_PROTO_CAP_COMPAT_PORT_CNT_MASK: u32 = 0x0000_FF00; -pub const SUPP_PROTO_CAP_COMPAT_PORT_CNT_SHIFT: u8 = 8; - -pub const SUPP_PROTO_CAP_PROTO_DEF_MASK: u32 = 0x0FFF_0000; -pub const SUPP_PROTO_CAP_PROTO_DEF_SHIFT: u8 = 16; - -pub const SUPP_PROTO_CAP_PSIC_MASK: u32 = 0xF000_0000; -pub const SUPP_PROTO_CAP_PSIC_SHIFT: u8 = 28; - -pub const SUPP_PROTO_CAP_PORT_SLOT_TYPE_MASK: u32 = 0x0000_001F; -pub const SUPP_PROTO_CAP_PORT_SLOT_TYPE_SHIFT: u8 = 0; - -impl SupportedProtoCap { - pub unsafe fn protocol_speeds(&self) -> &[ProtocolSpeed] { - slice::from_raw_parts( - &self.protocol_speeds as *const u8 as *const _, - self.psic() as usize, - ) - } - pub unsafe fn protocol_speeds_mut(&mut self) -> &mut [ProtocolSpeed] { - // XXX: Variance really is annoying sometimes. - slice::from_raw_parts_mut( - &self.protocol_speeds as *const u8 as *mut u8 as *mut _, - self.psic() as usize, - ) - } - pub fn rev_minor(&self) -> u8 { - ((self.a.read() & SUPP_PROTO_CAP_REV_MIN_MASK) >> SUPP_PROTO_CAP_REV_MIN_SHIFT) as u8 - } - pub fn rev_major(&self) -> u8 { - ((self.a.read() & SUPP_PROTO_CAP_REV_MAJ_MASK) >> SUPP_PROTO_CAP_REV_MAJ_SHIFT) as u8 - } - pub fn name_string(&self) -> [u8; 4] { - // TODO: Little endian, right? - u32::to_le_bytes(self.b.read()) - } - pub fn compat_port_offset(&self) -> u8 { - ((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_OFF_MASK) - >> SUPP_PROTO_CAP_COMPAT_PORT_OFF_SHIFT) as u8 - } - pub fn compat_port_count(&self) -> u8 { - ((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_CNT_MASK) - >> SUPP_PROTO_CAP_COMPAT_PORT_CNT_SHIFT) as u8 - } - pub fn compat_port_range(&self) -> Range { - self.compat_port_offset()..self.compat_port_offset() + self.compat_port_count() - } - - pub fn proto_defined(&self) -> u16 { - ((self.c.read() & SUPP_PROTO_CAP_PROTO_DEF_MASK) >> SUPP_PROTO_CAP_PROTO_DEF_SHIFT) as u16 - } - pub fn psic(&self) -> u8 { - ((self.c.read() & SUPP_PROTO_CAP_PSIC_MASK) >> SUPP_PROTO_CAP_PSIC_SHIFT) as u8 - } - pub fn proto_slot_ty(&self) -> u8 { - ((self.d.read() & SUPP_PROTO_CAP_PORT_SLOT_TYPE_MASK) - >> SUPP_PROTO_CAP_PORT_SLOT_TYPE_SHIFT) as u8 - } -} -impl fmt::Debug for SupportedProtoCap { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SupportedProtoCap") - .field("rev_minor", &self.rev_minor()) - .field("rev_major", &self.rev_major()) - .field("name_string", &String::from_utf8_lossy(&self.name_string())) - .field("compat_port_offset", &self.compat_port_count()) - .field("compat_port_count", &self.compat_port_offset()) - .field("proto_defined", &self.proto_defined()) - .field("psic", &self.psic()) - .field("proto_slot_ty", &self.proto_slot_ty()) - .field("proto_speeds", unsafe { - &self.protocol_speeds().to_owned() - }) - .finish() - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/irq_reactor.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/irq_reactor.rs deleted file mode 100644 index ac492d5bc1..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/irq_reactor.rs +++ /dev/null @@ -1,743 +0,0 @@ -use std::fs::File; -use std::future::Future; -use std::io::prelude::*; -use std::pin::Pin; -use std::sync::{Arc, Mutex}; -use std::task; - -use std::os::unix::io::AsRawFd; - -use crossbeam_channel::{Receiver, Sender}; -use log::{debug, error, info, trace, warn}; - -use super::doorbell::Doorbell; -use super::event::EventRing; -use super::ring::Ring; -use super::trb::{Trb, TrbCompletionCode, TrbType}; -use super::{PortId, Xhci}; -use crate::xhci::device_enumerator::DeviceEnumerationRequest; -use crate::xhci::port::PortFlags; -use common::io::Io as _; -use event::RawEventQueue; - -/// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back -/// by the future unless it completed). -#[derive(Debug)] -pub struct State { - waker: task::Waker, - kind: StateKind, - message: Arc>>, - is_isoch_or_vf: bool, -} - -impl State { - fn finish(self, message: Option) { - *self.message.lock().unwrap() = message; - trace!("Waking up future with waker: {:?}", self.waker); - self.waker.wake(); - } -} - -#[derive(Debug)] -pub struct NextEventTrb { - pub event_trb: Trb, - pub src_trb: Option, -} - -// TODO: Perhaps all of the transfer rings used by the xHC should be stored linearly, and then -// indexed using this struct instead. -#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct RingId { - pub port: PortId, - pub endpoint_num: u8, - pub stream_id: u16, -} -impl RingId { - pub const fn default_control_pipe(port: PortId) -> Self { - Self { - port, - endpoint_num: 0, - stream_id: 0, - } - } -} - -/// The state specific to a TRB-type. Since some of the event TDs may asynchronously appear, for -/// example the Command Completion Event and the Transfer Event TDs, they have to be -/// distinguishable. Luckily, the xHC also gives us the actual (physical) pointer to the source -/// TRB, from the command ring, unless the event TD has one the completion codes Ring Underrun, -/// Ring Overrun, or VF Event Ring Full Error. When these errors are encountered, it simply -/// indicates that the commands causing the errors continue to be pending, and thus no information -/// is lost. -#[derive(Clone, Copy, Debug)] -pub enum StateKind { - CommandCompletion { - phys_ptr: u64, - }, - Transfer { - first_phys_ptr: u64, - last_phys_ptr: u64, - ring_id: RingId, - }, - Other(TrbType), -} - -impl StateKind { - pub fn trb_type(&self) -> TrbType { - match self { - &Self::CommandCompletion { .. } => TrbType::CommandCompletion, - &Self::Transfer { .. } => TrbType::Transfer, - &Self::Other(ty) => ty, - } - } -} - -pub struct IrqReactor { - hci: Arc>, - irq_file: Option, - irq_receiver: Receiver, - device_enumerator_sender: Sender, - states: Vec, - // TODO: Since the IRQ reactor is the only part of this driver that gets event TRBs, perhaps - // the event ring should be owned here? -} - -pub type NewPendingTrb = State; - -impl IrqReactor { - pub fn new(hci: Arc>, irq_file: Option) -> Self { - let device_enumerator_sender = hci.device_enumerator_sender.clone(); - let irq_receiver = hci.irq_reactor_receiver.clone(); - - Self { - hci, - irq_file, - irq_receiver, - device_enumerator_sender, - states: Vec::new(), - } - } - // TODO: Configure the amount of time wait when no more work can be done (for IRQ-less polling). - fn pause(&self) { - std::thread::sleep(std::time::Duration::from_millis(2)); - } - fn run_polling(mut self) -> ! { - debug!("Running IRQ reactor in polling mode."); - let hci_clone = Arc::clone(&self.hci); - - let mut event_trb_index = { - hci_clone - .primary_event_ring - .lock() - .unwrap() - .ring - .next_index() - }; - - 'trb_loop: loop { - self.pause(); - - let mut event_ring = hci_clone.primary_event_ring.lock().unwrap(); - - let event_trb = &mut event_ring.ring.trbs[event_trb_index]; - - if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { - continue 'trb_loop; - } - - trace!( - "Found event TRB at index {} with type {} and cycle bit {}: {:?}", - event_trb_index, - event_trb.trb_type(), - event_trb.cycle() as u8, - event_trb - ); - - if self.check_event_ring_full(event_trb.clone()) { - info!("Had to resize event TRB, retrying..."); - continue 'trb_loop; - } - - trace!("Handling requests"); - self.handle_requests(); - trace!("Requests handled"); - - match event_trb.trb_type() { - _ if event_trb.trb_type() == TrbType::PortStatusChange as u8 => { - trace!("Received a port status change!"); - self.handle_port_status_change(event_trb.clone()) - } //TODO Handle the other unprompted events - _ => { - self.acknowledge(event_trb.clone()); - } - } - - event_trb.reserved(false); - - self.update_erdp(&*event_ring); - hci_clone.event_handler_finished(); - - event_trb_index = event_ring.ring.next_index(); - } - } - - fn mask_interrupts(&mut self) { - let mut run = self.hci.run.lock().unwrap(); - - debug!("Masking interrupts!"); - - if !run.ints[0].iman.readf(1 << 1) { - warn!("Attempted to mask interrupts when they were already disabled!") - } - - run.ints[0].iman.writef(1 << 1, false); - } - - fn unmask_interrupts(&mut self) { - let mut run = self.hci.run.lock().unwrap(); - - debug!("unmasking interrupts!"); - if run.ints[0].iman.readf(1 << 1) { - warn!("Attempted to unmask interrupts when they were already enabled!") - } - - run.ints[0].iman.writef(1 << 1, true); - } - - fn run_with_irq_file(mut self) -> ! { - debug!("Running IRQ reactor with IRQ file and event queue"); - - let hci_clone = Arc::clone(&self.hci); - let event_queue = - RawEventQueue::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); - let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); - event_queue - .subscribe(irq_fd as usize, 0, event::EventFlags::READ) - .unwrap(); - - trace!("IRQ Reactor has created its event queue."); - let mut event_trb_index = { - hci_clone - .primary_event_ring - .lock() - .unwrap() - .ring - .next_index() - }; - - trace!("IRQ reactor has grabbed the next index in the event ring."); - 'trb_loop: loop { - let _event = event_queue.next_event().unwrap(); - trace!("IRQ event queue notified"); - let mut buffer = [0u8; 8]; - - let _ = self - .irq_file - .as_mut() - .unwrap() - .read(&mut buffer) - .expect("Failed to read from irq scheme"); - - if !self.hci.received_irq() { - // continue only when an IRQ to this device was received - trace!("no interrupt pending"); - continue 'trb_loop; - } - - self.mask_interrupts(); - - trace!("IRQ reactor received an IRQ"); - - let _ = self.irq_file.as_mut().unwrap().write(&buffer); - - // TODO: More event rings, probably even with different IRQs. - - let mut event_ring = hci_clone.primary_event_ring.lock().unwrap(); - - let mut count = 0; - - loop { - trace!("count: {}", count); - let event_trb = &mut event_ring.ring.trbs[event_trb_index]; - - if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { - if count == 0 { - warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") - } - //hci_clone.event_handler_finished(); - self.unmask_interrupts(); - continue 'trb_loop; - } else { - count += 1 - } - - info!( - "Found event TRB at index {} with type {} and cycle bit {}: {:?}", - event_trb_index, - event_trb.trb_type(), - event_trb.cycle() as u8, - event_trb - ); - - if self.check_event_ring_full(event_trb.clone()) { - info!("Had to resize event TRB, retrying..."); - //hci_clone.event_handler_finished(); - if self.hci.interrupt_is_pending(0) { - warn!("After incrementing the dequeue pointer, the interrupt bit is still pending.") - } else { - debug!("The interrupt bit is no longer pending."); - } - self.unmask_interrupts(); - continue 'trb_loop; - } - self.handle_requests(); - - match event_trb.trb_type() { - _ if event_trb.trb_type() == TrbType::PortStatusChange as u8 => { - trace!("Received a port status change!"); - self.handle_port_status_change(event_trb.clone()) - } //TODO Handle the other unprompted events - _ => { - trace!("Received a non-status trb"); - self.acknowledge(event_trb.clone()); - } - } - - event_trb.reserved(false); - - self.update_erdp(&*event_ring); - self.hci.event_handler_finished(); - - event_trb_index = event_ring.ring.next_index(); - } - } - } - - /// Handles device attach/detach events as indicated by a PortStatusChange - fn handle_port_status_change(&mut self, trb: Trb) { - if let Some(root_hub_port_num) = trb.port_status_change_port_id() { - let port_id = PortId { - root_hub_port_num, - route_string: 0, - }; - trace!("Received Port Status Change Request on port {}", port_id); - self.device_enumerator_sender - .send(DeviceEnumerationRequest { port_id }) - .expect( - format!( - "Failed to transmit device numeration request on port {}", - port_id - ) - .as_str(), - ); - { - let mut ports = self.hci.ports.lock().unwrap(); - let root_port_index = port_id.root_hub_port_index(); - if root_port_index >= ports.len() { - warn!( - "Received out of bounds transmit device numeration request on root index {} at port {} [port len was: {}]", - root_port_index, port_id, ports.len() - ); - return; - } - - let port = &mut ports[root_port_index]; - port.clear_csc(); - } - } else { - warn!( - "Received a TRB of type {}, which was unexpected", - trb.trb_type() - ) - } - } - - fn update_erdp(&self, event_ring: &EventRing) { - let dequeue_pointer_and_dcs = event_ring.erdp(); - let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; - assert_eq!( - dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, - dequeue_pointer, - "unaligned ERDP received from primary event ring" - ); - - trace!("Updated ERDP to {:#0x}", dequeue_pointer); - - self.hci.run.lock().unwrap().ints[0] - .erdp_low - .write(dequeue_pointer as u32); - self.hci.run.lock().unwrap().ints[0] - .erdp_high - .write((dequeue_pointer >> 32) as u32); - } - fn handle_requests(&mut self) { - self.states.extend( - self.irq_receiver - .try_iter() - .inspect(|req| trace!("Received request: {:X?}", req)), - ); - } - fn acknowledge(&mut self, trb: Trb) { - //TODO: handle TRBs without an attached state - - trace!("ACK TRB {:X?}", trb); - - let mut index = 0; - while index < self.states.len() { - trace!("ACK STATE {}: {:X?}", index, self.states[index].kind); - - match self.states[index].kind { - StateKind::CommandCompletion { phys_ptr } - if trb.trb_type() == TrbType::CommandCompletion as u8 => - { - if trb.completion_trb_pointer() == Some(phys_ptr) { - trace!("Found matching command completion future"); - let state = self.states.remove(index); - - // Before waking, it's crucial that the command TRB that generated this event - // is fetched before removing this event TRB from the queue. - let command_trb = match self - .hci - .cmd - .lock() - .unwrap() - .phys_addr_to_entry_mut(self.hci.cap.ac64(), phys_ptr) - { - Some(command_trb) => { - let t = command_trb.clone(); - command_trb.reserved(false); - t - } - None => { - warn!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb); - continue; - } - }; - - // TODO: Validate the command TRB. - state.finish(Some(NextEventTrb { - src_trb: Some(command_trb.clone()), - event_trb: trb.clone(), - })); - - return; - } else if trb.completion_trb_pointer().is_none() { - warn!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); - } - } - - StateKind::Transfer { - first_phys_ptr, - last_phys_ptr, - ring_id, - } => { - // Check if the TRB matches the transfer - if trb.trb_type() == TrbType::Transfer as u8 { - match trb.transfer_event_trb_pointer() { - Some(phys_ptr) => { - let matches = if first_phys_ptr <= last_phys_ptr { - phys_ptr >= first_phys_ptr && phys_ptr <= last_phys_ptr - } else { - // Handle ring buffer wrap - phys_ptr >= first_phys_ptr || phys_ptr <= last_phys_ptr - }; - if matches { - let src_trb = self.hci.get_transfer_trb(phys_ptr, ring_id); - // Give the source transfer TRB together with the event TRB, to the future. - let state = self.states.remove(index); - state.finish(Some(NextEventTrb { - src_trb: src_trb, - event_trb: trb.clone(), - })); - return; - } - } - None => { - // Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full. - // - // These errors are caused when either an isoch transfer that shall write data, doesn't - // have any data since the ring is empty, or if an isoch receive is impossible due to a - // full ring. The Virtual Function Event Ring Full is only for Virtual Machine - // Managers, and since this isn't implemented yet, they are irrelevant. - // - // The best solution here is to differentiate between isoch transfers (and - // virtual function event rings when virtualization gets implemented), with - // regular commands and transfers, and send the error TRB to all of them, or - // possibly an error code wrapped in a Result. - self.acknowledge_failed_transfer_trbs(trb); - return; - } - } - } - - // Also check if the transfer is on a dead ring - if self.hci.with_ring(ring_id, |_ring| ()).is_none() { - log::debug!("State {} is a dead transfer", index); - let state = self.states.remove(index); - state.finish(Some(NextEventTrb { - src_trb: None, - //TODO: don't send this TRB as it may not be related - event_trb: trb.clone(), - })); - continue; - } - } - - StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => { - let state = self.states.remove(index); - state.finish(None); - return; - } - - _ => (), - } - - index += 1; - } - warn!( - "Lost event TRB type {}, completion code: {}: {:X?}", - trb.trb_type(), - trb.completion_code(), - trb - ); - } - fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { - let mut index = 0; - - loop { - if !self.states[index].is_isoch_or_vf { - index += 1; - if index >= self.states.len() { - break; - } - continue; - } - let state = self.states.remove(index); - state.finish(Some(NextEventTrb { - event_trb: trb.clone(), - src_trb: None, - })); - } - } - /// Checks if an event TRB is a Host Controller Event, with the completion code Event Ring - /// Full. If so, it grows the event ring. The return value is whether the event ring was full, - /// and then grown. - fn check_event_ring_full(&mut self, event_trb: Trb) -> bool { - let had_event_ring_full_error = event_trb.trb_type() == TrbType::HostController as u8 - && event_trb.completion_code() == TrbCompletionCode::EventRingFull as u8; - - if had_event_ring_full_error { - self.grow_event_ring(); - } - had_event_ring_full_error - } - /// Grows the event ring - fn grow_event_ring(&mut self) { - // TODO - error!("TODO: grow event ring"); - } - - pub fn run(self) -> ! { - if self.irq_file.is_some() { - self.run_with_irq_file(); - } else { - self.run_polling(); - } - } -} - -struct FutureState { - message: Arc>>, - is_isoch_or_vf: bool, - state_kind: StateKind, -} - -pub struct EventDoorbell { - dbs: Arc>, - index: usize, - data: u32, -} - -impl EventDoorbell { - pub fn new(hci: &Xhci, index: usize, data: u32) -> Self { - Self { - //TODO: simplify this logic, maybe just use a raw pointer? - dbs: hci.dbs.clone(), - index, - data, - } - } - - pub fn ring(self) { - trace!("Ring doorbell {} with data {}", self.index, self.data); - self.dbs.lock().unwrap()[self.index].write(self.data); - trace!("Doorbell was rung."); - } -} - -enum EventTrbFuture { - Pending { - state: FutureState, - sender: Sender, - doorbell_opt: Option, - }, - Finished, -} - -impl Future for EventTrbFuture { - type Output = NextEventTrb; - - fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { - let this = self.get_mut(); - trace!("Start poll!"); - let message = match this { - &mut Self::Pending { - ref state, - ref sender, - ref mut doorbell_opt, - } => match state.message.lock().unwrap().take() { - Some(message) => message, - - None => { - // Register state with IRQ reactor - trace!("Send state {:X?}", state.state_kind); - sender - .send(State { - message: Arc::clone(&state.message), - is_isoch_or_vf: state.is_isoch_or_vf, - kind: state.state_kind, - waker: context.waker().clone(), - }) - .expect("IRQ reactor thread unexpectedly stopped"); - - // Doorbell must be rung after sending state - if let Some(doorbell) = doorbell_opt.take() { - doorbell.ring(); - } - return task::Poll::Pending; - } - }, - &mut Self::Finished => panic!("Polling finished EventTrbFuture again."), - }; - trace!("finished!"); - *this = Self::Finished; - task::Poll::Ready(message) - } -} - -impl Xhci { - pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option { - self.with_ring(id, |ring| ring.phys_addr_to_entry(self.cap.ac64(), paddr)) - .flatten() - } - pub fn with_ring T>(&self, id: RingId, function: F) -> Option { - use super::RingOrStreams; - - let slot_state = self.port_states.get(&id.port)?; - let endpoint_state = slot_state.endpoint_states.get(&id.endpoint_num)?; - - let ring_ref = match endpoint_state.transfer { - RingOrStreams::Ring(ref ring) => ring, - RingOrStreams::Streams(ref ctx_arr) => ctx_arr.rings.get(&id.stream_id)?, - }; - - Some(function(ring_ref)) - } - pub fn with_ring_mut T>( - &self, - id: RingId, - function: F, - ) -> Option { - use super::RingOrStreams; - - let mut slot_state = self.port_states.get_mut(&id.port)?; - let mut endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?; - - let ring_ref = match endpoint_state.transfer { - RingOrStreams::Ring(ref mut ring) => ring, - RingOrStreams::Streams(ref mut ctx_arr) => ctx_arr.rings.get_mut(&id.stream_id)?, - }; - - Some(function(ring_ref)) - } - pub fn next_transfer_event_trb( - &self, - ring_id: RingId, - ring: &Ring, - first_trb: &Trb, - last_trb: &Trb, - doorbell: EventDoorbell, - ) -> impl Future + Send + Sync + 'static { - if !last_trb.is_transfer_trb() { - panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", last_trb.trb_type(), last_trb) - } - - let is_isoch_or_vf = last_trb.trb_type() == TrbType::Isoch as u8; - let first_phys_ptr = ring.trb_phys_ptr(self.cap.ac64(), first_trb); - let last_phys_ptr = ring.trb_phys_ptr(self.cap.ac64(), last_trb); - EventTrbFuture::Pending { - state: FutureState { - is_isoch_or_vf, - state_kind: StateKind::Transfer { - ring_id, - first_phys_ptr, - last_phys_ptr, - }, - message: Arc::new(Mutex::new(None)), - }, - sender: self.irq_reactor_sender.clone(), - doorbell_opt: Some(doorbell), - } - } - pub fn next_command_completion_event_trb( - &self, - command_ring: &Ring, - trb: &Trb, - doorbell: EventDoorbell, - ) -> impl Future + Send + Sync + 'static { - trace!( - "Sending command at phys_ptr {:X}", - command_ring.trb_phys_ptr(self.cap.ac64(), trb) - ); - if !trb.is_command_trb() { - panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb) - } - EventTrbFuture::Pending { - state: FutureState { - // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). - is_isoch_or_vf: false, - state_kind: StateKind::CommandCompletion { - phys_ptr: command_ring.trb_phys_ptr(self.cap.ac64(), trb), - }, - message: Arc::new(Mutex::new(None)), - }, - sender: self.irq_reactor_sender.clone(), - doorbell_opt: Some(doorbell), - } - } - pub fn next_misc_event_trb( - &self, - trb_type: TrbType, - ) -> impl Future + Send + Sync + 'static { - let valid_trb_types = [ - TrbType::PortStatusChange as u8, - TrbType::BandwidthRequest as u8, - TrbType::Doorbell as u8, - TrbType::HostController as u8, - TrbType::DeviceNotification as u8, - TrbType::MfindexWrap as u8, - ]; - if !valid_trb_types.contains(&(trb_type as u8)) { - panic!("Invalid TRB type given to next_misc_event_trb(): {:?}. Only event TRB types that are neither transfer events or command completion events can be used.", trb_type) - } - EventTrbFuture::Pending { - state: FutureState { - is_isoch_or_vf: false, - state_kind: StateKind::Other(trb_type), - message: Arc::new(Mutex::new(None)), - }, - sender: self.irq_reactor_sender.clone(), - doorbell_opt: None, - } - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/mod.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/mod.rs deleted file mode 100644 index 73d9d90b2a..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/mod.rs +++ /dev/null @@ -1,1498 +0,0 @@ -//! The eXtensible Host Controller Interface (XHCI) Module -//! -//! This module implements the XHCI functionality of Redox's USB driver daemon. -//! -//! XHCI is a standard for the USB Host Controller interface specified by Intel that provides a -//! common register interface for systems to use to interact with the Universal Serial Bus (USB) -//! subsystem. -//! -//! The standard can be found [here](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf). -//! The standard is referenced frequently throughout this documentation. The acronyms used for specific -//! documents are specified in the crate-level documentation. -use std::collections::BTreeMap; -use std::convert::TryFrom; -use std::fs::{self, File}; -use std::sync::atomic::AtomicUsize; -use std::sync::{Arc, Mutex}; - -use std::{mem, process, slice, thread}; -use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT}; -use syscall::{EAGAIN, PAGE_SIZE}; - -use chashmap::CHashMap; -use common::{dma::Dma, io::Io, timeout::Timeout}; -use crossbeam_channel::{Receiver, Sender}; -use log::{debug, error, info, trace, warn}; -use serde::Deserialize; - -use crate::usb; - -use pcid_interface::PciFunctionHandle; - -mod capability; -mod context; -mod device_enumerator; -mod doorbell; -mod event; -mod extended; -pub mod irq_reactor; -mod operational; -mod port; -mod ring; -mod runtime; -pub mod scheme; -mod trb; - -pub use self::capability::CapabilityRegs; -use self::context::{ - DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray, - SLOT_CONTEXT_STATE_MASK, SLOT_CONTEXT_STATE_SHIFT, -}; -pub use self::context::{CONTEXT_32, CONTEXT_64}; -use self::doorbell::Doorbell; -use self::event::EventRing; -use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap}; -use self::irq_reactor::{EventDoorbell, IrqReactor, NewPendingTrb, RingId}; -use self::operational::*; -use self::port::Port; -use self::ring::Ring; -use self::runtime::RuntimeRegs; -use self::trb::{TransferKind, Trb, TrbCompletionCode}; - -use self::scheme::EndpIfState; - -pub use crate::driver_interface::PortId; -use crate::driver_interface::*; -use crate::xhci::device_enumerator::{DeviceEnumerationRequest, DeviceEnumerator}; -use crate::xhci::port::PortFlags; - -/// Specifies the configurable interrupt mechanism used by the xhci subsystem for registering -/// device state change notifications. -pub enum InterruptMethod { - /// No interrupts whatsoever; the driver will instead rely on polling event rings. - Polling, - - /// Legacy PCI INTx# interrupt pin. - Intx, - - /// (Extended) Message signaled interrupts. - Msi, -} - -impl Xhci { - /// Gets descriptors, before the port state is initiated. - async fn get_desc_raw( - &self, - port: PortId, - slot: u8, - kind: usb::DescriptorKind, - value: u8, - index: u16, - desc: &mut Dma, - ) -> Result<()> { - if self.interrupt_is_pending(0) { - debug!("EHB is already set!"); - self.force_clear_interrupt(0); - } - let len = mem::size_of::(); - log::debug!( - "get_desc_raw port {} slot {} kind {:?} value {} index {} len {}", - port, - slot, - kind, - value, - index, - len - ); - - let future = { - let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; - let ring = port_state - .endpoint_states - .get_mut(&0) - .ok_or(Error::new(EIO))? - .ring() - .expect("no ring for the default control pipe"); - - let first_index = ring.next_index(); - let (cmd, cycle) = (&mut ring.trbs[first_index], ring.cycle); - cmd.setup( - usb::Setup::get_descriptor(kind, value, index, len as u16), - TransferKind::In, - cycle, - ); - - let (cmd, cycle) = ring.next(); - cmd.data(desc.physical(), len as u16, true, cycle); - - let last_index = ring.next_index(); - let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle); - - let interrupter = 0; - // When the data stage is in, the status stage must be out - let input = false; - let ioc = true; - let ch = false; - let ent = false; - cmd.status(interrupter, input, ioc, ch, ent, cycle); - - self.next_transfer_event_trb( - RingId::default_control_pipe(port), - &ring, - &ring.trbs[first_index], - &ring.trbs[last_index], - EventDoorbell::new(self, usize::from(slot), Self::def_control_endp_doorbell()), - ) - }; - - debug!("Waiting for the next transfer event TRB..."); - let trbs = future.await; - let event_trb = trbs.event_trb; - let status_trb = trbs.src_trb.ok_or(Error::new(EIO))?; - trace!("Handling the transfer event TRB!"); - self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?; - - //self.event_handler_finished(); - Ok(()) - } - - async fn fetch_dev_desc_8_byte( - &self, - port: PortId, - slot: u8, - ) -> Result { - let mut desc = unsafe { self.alloc_dma_zeroed::()? }; - self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, 0, &mut desc) - .await?; - Ok(*desc) - } - - async fn fetch_dev_desc(&self, port: PortId, slot: u8) -> Result { - let mut desc = unsafe { self.alloc_dma_zeroed::()? }; - self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, 0, &mut desc) - .await?; - Ok(*desc) - } - - async fn fetch_config_desc( - &self, - port: PortId, - slot: u8, - config: u8, - ) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { - let mut desc = unsafe { self.alloc_dma_zeroed::<(usb::ConfigDescriptor, [u8; 4087])>()? }; - self.get_desc_raw( - port, - slot, - usb::DescriptorKind::Configuration, - config, - 0, - &mut desc, - ) - .await?; - Ok(*desc) - } - - async fn fetch_bos_desc( - &self, - port: PortId, - slot: u8, - ) -> Result<(usb::BosDescriptor, [u8; 4087])> { - let mut desc = unsafe { self.alloc_dma_zeroed::<(usb::BosDescriptor, [u8; 4087])>()? }; - self.get_desc_raw( - port, - slot, - usb::DescriptorKind::BinaryObjectStorage, - 0, - 0, - &mut desc, - ) - .await?; - Ok(*desc) - } - - async fn fetch_lang_ids_desc(&self, port: PortId, slot: u8) -> Result> { - let mut sdesc = unsafe { self.alloc_dma_zeroed::<(u8, u8, [u16; 127])>()? }; - self.get_desc_raw(port, slot, usb::DescriptorKind::String, 0, 0, &mut sdesc) - .await?; - - let len = sdesc.0 as usize; - if len > 2 { - Ok(sdesc.2[..(len - 2) / 2].to_vec()) - } else { - Ok(Vec::new()) - } - } - - async fn fetch_string_desc( - &self, - port: PortId, - slot: u8, - value: u8, - lang_id: u16, - ) -> Result { - let mut sdesc = unsafe { self.alloc_dma_zeroed::<(u8, u8, [u16; 127])>()? }; - self.get_desc_raw( - port, - slot, - usb::DescriptorKind::String, - value, - lang_id, - &mut sdesc, - ) - .await?; - - let len = sdesc.0 as usize; - if len > 2 { - Ok(String::from_utf16(&sdesc.2[..(len - 2) / 2]).unwrap_or(String::new())) - } else { - Ok(String::new()) - } - } -} - -/// The eXtensible Host Controller Interface (XHCI) data structure -pub struct Xhci { - // immutable - /// The Host Controller Interface Capability Registers. These read-only registers specify the - /// limits and capabilities of the host controller implementation (See XHCI section 5.3) - cap: &'static CapabilityRegs, - //page_size: usize, - - // XXX: It would be really useful to be able to mutably access individual elements of a slice, - // without having to wrap every element in a lock (which wouldn't work since they're packed). - /// The Host Controller Interface Operational Registers. These registers provide the software - /// interface to configure and monitor the state of the XHCI (See XHCI section 5.4) - op: Mutex<&'static mut OperationalRegs>, - ports: Mutex<&'static mut [Port]>, - /// The Host Controller Interface Doorbell Registers. There is one register per device slot, - /// and these registers are used by system software to notify the XHC that it has work to perform - /// for a specific device slot. (See XHCI sections 4.7 and 5.6) - dbs: Arc>, - /// The Host Controller Interface Runtime Registers. These handle interrupt and event processing, - /// and provide time-sensitive information such as the current microframe. (See XHCI section 5.5) - run: Mutex<&'static mut RuntimeRegs>, - cmd: Mutex, - primary_event_ring: Mutex, - - // immutable - dev_ctx: DeviceContextList, - scratchpad_buf_arr: Option, - - // used for the extended capabilities, and so far none of them are mutated, and thus no lock. - base: *const u8, - - drivers_config: DriversConfig, - handles: CHashMap, - next_handle: AtomicUsize, - port_states: CHashMap>, - drivers: CHashMap>, - scheme_name: String, - - interrupt_method: InterruptMethod, - pcid_handle: Mutex, - - irq_reactor: Mutex>>, - - irq_reactor_sender: Sender, - - // not used, but still stored so that the thread, when created, can get the channel without the - // channel being in a mutex. - irq_reactor_receiver: Receiver, - device_enumerator: Mutex>>, - device_enumerator_sender: Sender, - device_enumerator_receiver: Receiver, -} - -unsafe impl Send for Xhci {} -unsafe impl Sync for Xhci {} - -struct PortState { - slot: u8, - protocol_speed: &'static ProtocolSpeed, - cfg_idx: Option, - input_context: Mutex>>, - dev_desc: Option, - endpoint_states: BTreeMap, -} - -impl PortState { - //TODO: fetch using endpoint number instead - fn get_endp_desc(&self, endp_idx: u8) -> Option<&EndpDesc> { - let cfg_idx = self.cfg_idx?; - let config_desc = self - .dev_desc - .as_ref()? - .config_descs - .iter() - .find(|desc| desc.configuration_value == cfg_idx)?; - let mut endp_count = 0; - for if_desc in config_desc.interface_descs.iter() { - for endp_desc in if_desc.endpoints.iter() { - if endp_idx == endp_count { - return Some(endp_desc); - } - endp_count += 1; - } - } - None - } -} - -pub(crate) enum RingOrStreams { - Ring(Ring), - Streams(StreamContextArray), -} - -pub(crate) struct EndpointState { - pub transfer: RingOrStreams, - pub driver_if_state: EndpIfState, -} -impl EndpointState { - fn ring(&mut self) -> Option<&mut Ring> { - match self.transfer { - RingOrStreams::Ring(ref mut ring) => Some(ring), - _ => None, - } - } -} - -impl Xhci { - pub fn new( - scheme_name: String, - address: usize, - interrupt_method: InterruptMethod, - pcid_handle: PciFunctionHandle, - ) -> Result { - //Locate the capability registers from the mapped PCI Bar - let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; - debug!("CAP REGS BASE {:X}", address); - - //let page_size = ... - - //The operational registers appear immediately after the capability registers. - let op_base = address + cap.len.read() as usize; - let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; - debug!("OP REGS BASE {:X}", op_base); - - //Reset the XHCI device - let (max_slots, max_ports) = { - { - debug!("Waiting for xHC becoming ready."); - let timeout = Timeout::from_secs(1); - while op.usb_sts.readf(USB_STS_CNR) { - timeout.run().map_err(|()| { - log::error!("timeout on USB_STS_CNR"); - Error::new(EIO) - })?; - } - } - - debug!("Stopping the xHC"); - // Set run/stop to 0 - op.usb_cmd.writef(USB_CMD_RS, false); - - { - debug!("Waiting for the xHC to stop."); - let timeout = Timeout::from_secs(1); - while !op.usb_sts.readf(USB_STS_HCH) { - timeout.run().map_err(|()| { - log::error!("timeout on USB_STS_HCH"); - Error::new(EIO) - })?; - } - } - - { - debug!("Resetting the xHC."); - op.usb_cmd.writef(USB_CMD_HCRST, true); - let timeout = Timeout::from_secs(1); - while op.usb_cmd.readf(USB_CMD_HCRST) { - timeout.run().map_err(|()| { - log::error!("timeout on USB_CMD_HCRST"); - Error::new(EIO) - })?; - } - } - - debug!("Reading max slots."); - - let max_slots = cap.max_slots(); - let max_ports = cap.max_ports(); - - debug!("xHC max slots: {}, max ports: {}", max_slots, max_ports); - (max_slots, max_ports) - }; - - //Get the address of the port register table - let port_base = op_base + 0x400; - let ports = - unsafe { slice::from_raw_parts_mut(port_base as *mut Port, max_ports as usize) }; - debug!("PORT BASE {:X}", port_base); - - //Get the address of the dorbell register table - let db_base = address + cap.db_offset.read() as usize; - let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut Doorbell, 256) }; - debug!("DOORBELL REGS BASE {:X}", db_base); - - let run_base = address + cap.rts_offset.read() as usize; - let run = unsafe { &mut *(run_base as *mut RuntimeRegs) }; - debug!("RUNTIME REGS BASE {:X}", run_base); - - // Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the - // DMA allocation (which is at least a 4k page). - let entries_per_page = PAGE_SIZE / mem::size_of::(); - let cmd = Ring::new::(cap.ac64(), entries_per_page, true)?; - - let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded(); - - let (device_enumerator_sender, device_enumerator_receiver) = crossbeam_channel::unbounded(); - - let mut drivers_config = DriversConfig { drivers: vec![] }; - for file in config::config("xhcid").expect("xhcid: Failed to read driver configs") { - let config = match fs::read(&file) { - Ok(config) => config, - Err(err) => { - println!("xhcid: Failed to read config {}: {err}", file.display()); - continue; - } - }; - let config = match toml::from_slice::(&config) { - Ok(config) => config, - Err(err) => { - println!("xhcid: Failed to parse config {}: {err}", file.display()); - continue; - } - }; - drivers_config.drivers.extend(config.drivers); - } - - let mut xhci = Self { - base: address as *const u8, - - cap, - //page_size, - op: Mutex::new(op), - ports: Mutex::new(ports), - dbs: Arc::new(Mutex::new(dbs)), - run: Mutex::new(run), - - dev_ctx: DeviceContextList::new(cap.ac64(), max_slots)?, - scratchpad_buf_arr: None, // initialized in init() - - cmd: Mutex::new(cmd), - primary_event_ring: Mutex::new(EventRing::new::(cap.ac64())?), - drivers_config, - handles: CHashMap::new(), - next_handle: AtomicUsize::new(0), - port_states: CHashMap::new(), - drivers: CHashMap::new(), - scheme_name, - - interrupt_method, - pcid_handle: Mutex::new(pcid_handle), - - irq_reactor: Mutex::new(None), - irq_reactor_sender, - irq_reactor_receiver, - device_enumerator: Mutex::new(None), - device_enumerator_sender, - device_enumerator_receiver, - }; - - xhci.init(max_slots)?; - - Ok(xhci) - } - - pub fn init(&mut self, max_slots: u8) -> Result<()> { - // Set run/stop to 0 - debug!("Stopping xHC."); - self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, false); - - // Warm reset - { - debug!("Reset xHC"); - let timeout = Timeout::from_secs(1); - self.op - .get_mut() - .unwrap() - .usb_cmd - .writef(USB_CMD_HCRST, true); - while self.op.get_mut().unwrap().usb_cmd.readf(USB_CMD_HCRST) { - timeout.run().map_err(|()| { - log::error!("timeout on USB_CMD_HCRST"); - Error::new(EIO) - })?; - } - } - - // Set enabled slots - debug!("Setting enabled slots to {}.", max_slots); - self.op.get_mut().unwrap().config.write(max_slots as u32); - debug!( - "Enabled Slots: {}", - self.op.get_mut().unwrap().config.read() & 0xFF - ); - - // Set device context address array pointer - let dcbaap = self.dev_ctx.dcbaap(); - debug!("Writing DCBAAP: {:X}", dcbaap); - self.op.get_mut().unwrap().dcbaap_low.write(dcbaap as u32); - self.op - .get_mut() - .unwrap() - .dcbaap_high - .write((dcbaap as u64 >> 32) as u32); - - // Set command ring control register - let crcr = self.cmd.get_mut().unwrap().register(); - assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR"); - debug!("Writing CRCR: {:X}", crcr); - self.op.get_mut().unwrap().crcr_low.write(crcr as u32); - self.op - .get_mut() - .unwrap() - .crcr_high - .write((crcr as u64 >> 32) as u32); - - // Set event ring segment table registers - debug!( - "Interrupter 0: {:p}", - self.run.get_mut().unwrap().ints.as_ptr() - ); - { - let int = &mut self.run.get_mut().unwrap().ints[0]; - - let erstz = 1; - debug!("Writing ERSTZ: {}", erstz); - int.erstsz.write(erstz); - - let erdp = self.primary_event_ring.get_mut().unwrap().erdp(); - debug!("Writing ERDP: {:X}", erdp); - int.erdp_low.write(erdp as u32 | (1 << 3)); - int.erdp_high.write((erdp as u64 >> 32) as u32); - - let erstba = self.primary_event_ring.get_mut().unwrap().erstba(); - debug!("Writing ERSTBA: {:X}", erstba); - int.erstba_low.write(erstba as u32); - int.erstba_high.write((erstba as u64 >> 32) as u32); - - debug!("Writing IMODC and IMODI: {} and {}", 0, 0); - int.imod.write(0); - - debug!("Enabling Primary Interrupter."); - int.iman.writef(1 << 1 | 1, true); - } - self.op - .get_mut() - .unwrap() - .usb_cmd - .writef(USB_CMD_INTE, true); - - // Setup the scratchpad buffers that are required for the xHC to function. - self.setup_scratchpads()?; - - // Set run/stop to 1 - debug!("Starting xHC."); - self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, true); - - { - debug!("Waiting for start request to complete."); - let timeout = Timeout::from_secs(1); - while self.op.get_mut().unwrap().usb_sts.readf(USB_STS_HCH) { - timeout.run().map_err(|()| { - log::error!("timeout on USB_STS_HCH"); - Error::new(EIO) - })?; - } - } - - // Ring command doorbell - debug!("Ringing command doorbell."); - self.dbs.lock().unwrap()[0].write(0); - - debug!("XHCI initialized."); - - self.op.get_mut().unwrap().set_cie(self.cap.cic()); - - self.print_port_capabilities(); - - Ok(()) - } - - pub fn get_pls(&self, port_id: PortId) -> u8 { - let mut ports = self.ports.lock().unwrap(); - let port = ports.get_mut(port_id.root_hub_port_index()).unwrap(); - port.state() - } - - pub fn poll(&self) { - debug!("Polling Initial Devices!"); - - let len = self.ports.lock().unwrap().len(); - - for root_hub_port_num in 1..=(len as u8) { - let port_id = PortId { - root_hub_port_num, - route_string: 0, - }; - - //Get the CCS and CSC flags - let (ccs, csc, flags) = { - let mut ports = self.ports.lock().unwrap(); - let port = &mut ports[port_id.root_hub_port_index()]; - let flags = port.flags(); - let ccs = flags.contains(PortFlags::CCS); - let csc = flags.contains(PortFlags::CSC); - - (ccs, csc, flags) - }; - - debug!("Port {} has flags {:?}", port_id, flags); - - match (ccs, csc) { - (false, false) => { // Nothing is connected, and there was no port status change - //Do nothing - } - _ => { - //Either something is connected, or nothing is connected and a port status change was asserted. - self.device_enumerator_sender - .send(DeviceEnumerationRequest { port_id }) - .expect("Failed to generate the port enumeration request!"); - } - } - } - } - - pub fn print_port_capabilities(&self) { - let len; - { - let mut ports = self.ports.lock().unwrap(); - len = ports.len(); - } - - for root_hub_port_num in 1..=(len as u8) { - let port_id = PortId { - root_hub_port_num, - route_string: 0, - }; - - let state = self.get_pls(port_id); - let mut flags; - { - let mut ports = self.ports.lock().unwrap(); - - flags = ports[port_id.root_hub_port_index()].flags(); - } - - match self.supported_protocol(port_id) { - None => { - warn!("No detected supported protocol for port {}", port_id); - } - Some(protocol) => { - debug!( - "Port {} is a USB {}.{} port with slot type {} and in current state {}: {:?}", - port_id, - protocol.rev_major(), - protocol.rev_minor(), - protocol.proto_slot_ty(), - state, - flags - ); - } - }; - } - } - pub fn reset_port(&self, port_id: PortId) -> Result<()> { - debug!("XHCI Port {} reset", port_id); - - //TODO handle the second unwrap - let mut ports = self.ports.lock().unwrap(); - let port = ports.get_mut(port_id.root_hub_port_index()).unwrap(); - let instant = std::time::Instant::now(); - - debug!("Port {} Link State: {}", port_id, port.state()); - - { - port.set_pr(); - debug!( - "Flags after setting port {} reset: {:?}", - port_id, - port.flags() - ); - let timeout = Timeout::from_secs(1); - while !port.flags().contains(port::PortFlags::PRC) { - timeout.run().map_err(|()| { - log::error!("timeout on port {} PRC", port_id); - Error::new(EIO) - })?; - } - } - Ok(()) - } - - pub fn setup_scratchpads(&mut self) -> Result<()> { - let buf_count = self.cap.max_scratchpad_bufs(); - - if buf_count == 0 { - return Ok(()); - } - let scratchpad_buf_arr = ScratchpadBufferArray::new::(self.cap.ac64(), buf_count)?; - self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; - debug!( - "Setting up {} scratchpads, at {:#0x}", - buf_count, - scratchpad_buf_arr.register() - ); - self.scratchpad_buf_arr = Some(scratchpad_buf_arr); - - Ok(()) - } - - pub fn force_clear_interrupt(&self, index: usize) { - { - // If ERDP EHB bit is set, clear it before sending command - //TODO: find out why this bit is set earlier! - let mut run = self.run.lock().unwrap(); - let mut int = &mut run.ints[index]; - - if int.erdp_low.readf(1 << 3) { - int.erdp_low.writef(1 << 3, true); - } else { - warn!("Attempted to clear the interrupt bit when no interrupt was pending"); - } - } - } - - pub fn interrupt_is_pending(&self, index: usize) -> bool { - let mut run = self.run.lock().unwrap(); - let mut int = &mut run.ints[index]; - int.erdp_low.readf(1 << 3) - } - - pub async fn enable_port_slot(&self, slot_ty: u8) -> Result { - assert_eq!(slot_ty & 0x1F, slot_ty); - - let (event_trb, command_trb) = self - .execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)) - .await; - - trace!("Slot is enabled!"); - self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb)?; - //self.event_handler_finished(); - - Ok(event_trb.event_slot()) - } - pub async fn disable_port_slot(&self, slot: u8) -> Result<()> { - trace!("Disable slot {}", slot); - let (event_trb, command_trb) = self - .execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)) - .await; - - self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb)?; - //self.event_handler_finished(); - - Ok(()) - } - - pub fn slot_state(&self, slot: usize) -> u8 { - ((self.dev_ctx.contexts[slot].slot.d.read() & SLOT_CONTEXT_STATE_MASK) - >> SLOT_CONTEXT_STATE_SHIFT) as u8 - } - pub unsafe fn alloc_dma_zeroed_raw(_ac64: bool) -> Result> { - // TODO: ac64 - Ok(Dma::zeroed()?.assume_init()) - } - pub unsafe fn alloc_dma_zeroed(&self) -> Result> { - Self::alloc_dma_zeroed_raw(self.cap.ac64()) - } - pub unsafe fn alloc_dma_zeroed_unsized_raw(_ac64: bool, count: usize) -> Result> { - // TODO: ac64 - Ok(Dma::zeroed_slice(count)?.assume_init()) - } - pub unsafe fn alloc_dma_zeroed_unsized(&self, count: usize) -> Result> { - Self::alloc_dma_zeroed_unsized_raw(self.cap.ac64(), count) - } - - pub async fn attach_device(&self, port_id: PortId) -> syscall::Result<()> { - if self.port_states.contains_key(&port_id) { - debug!("Already contains port {}", port_id); - return Err(syscall::Error::new(EAGAIN)); - } - - let (data, state, speed, flags) = { - let port = &self.ports.lock().unwrap()[port_id.root_hub_port_index()]; - (port.read(), port.state(), port.speed(), port.flags()) - }; - - debug!( - "XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", - port_id, data, state, speed, flags - ); - - if flags.contains(port::PortFlags::CCS) { - let slot_ty = match self.supported_protocol(port_id) { - Some(protocol) => protocol.proto_slot_ty(), - None => { - warn!("Failed to find supported protocol information for port"); - 0 - } - }; - - debug!("Slot type: {}", slot_ty); - debug!("Enabling slot."); - let slot = match self.enable_port_slot(slot_ty).await { - Ok(ok) => ok, - Err(err) => { - error!("Failed to enable slot for port {}: {}", port_id, err); - return Err(err); - } - }; - - debug!("Enabled port {}, which the xHC mapped to {}", port_id, slot); - - //TODO: get correct speed for child devices - let protocol_speed = self - .lookup_psiv(port_id, speed) - .expect("Failed to retrieve speed ID"); - - let mut input = unsafe { self.alloc_dma_zeroed::>()? }; - - debug!("Attempting to address the device"); - let mut ring = match self - .address_device(&mut input, port_id, slot_ty, slot, protocol_speed, speed) - .await - { - Ok(device_ring) => device_ring, - Err(err) => { - error!("Failed to address device for port {}: `{}`", port_id, err); - return Err(err); - } - }; - - debug!("Addressed device"); - - // TODO: Should the descriptors be cached in PortState, or refetched? - - let mut port_state = PortState { - slot, - protocol_speed, - input_context: Mutex::new(input), - dev_desc: None, - cfg_idx: None, - endpoint_states: std::iter::once(( - 0, - EndpointState { - transfer: RingOrStreams::Ring(ring), - driver_if_state: EndpIfState::Init, - }, - )) - .collect::>(), - }; - self.port_states.insert(port_id, port_state); - debug!("Got port states!"); - - // Ensure correct packet size is used - let dev_desc_8_byte = self.fetch_dev_desc_8_byte(port_id, slot).await?; - { - let mut port_state = self.port_states.get_mut(&port_id).unwrap(); - - let mut input = port_state.input_context.lock().unwrap(); - - self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte) - .await?; - } - - debug!("Got the 8 byte dev descriptor: {:X?}", dev_desc_8_byte); - - let dev_desc = self.get_desc(port_id, slot).await?; - debug!("Got the full device descriptor!"); - self.port_states.get_mut(&port_id).unwrap().dev_desc = Some(dev_desc); - - debug!("Got the port states again!"); - { - let mut port_state = self.port_states.get_mut(&port_id).unwrap(); - - let mut input = port_state.input_context.lock().unwrap(); - debug!("Got the input context!"); - let dev_desc = port_state.dev_desc.as_ref().unwrap(); - - self.update_default_control_pipe(&mut *input, slot, dev_desc) - .await?; - } - - debug!("Updated the default control pipe"); - - match self.spawn_drivers(port_id) { - Ok(()) => (), - Err(err) => { - error!("Failed to spawn driver for port {}: `{}`", port_id, err) - } - } - } else { - warn!("Attempted to attach a device that didnt have CCS=1"); - } - - Ok(()) - } - - pub async fn detach_device(&self, port_id: PortId) -> Result { - if let Some(children) = self.drivers.remove(&port_id) { - for mut child in children { - info!("killing driver process {} for port {}", child.id(), port_id); - match child.kill() { - Ok(()) => { - info!("killed driver process {} for port {}", child.id(), port_id); - match child.try_wait() { - Ok(status_opt) => match status_opt { - Some(status) => { - debug!( - "driver process {} for port {} exited with status {}", - child.id(), - port_id, - status - ); - } - None => { - //TODO: kill harder - warn!( - "driver process {} for port {} still running", - child.id(), - port_id - ); - } - }, - Err(err) => { - warn!( - "failed to wait for the driver process {} for port {}: {}", - child.id(), - port_id, - err - ); - } - } - } - Err(err) => { - warn!( - "failed to kill the driver process {} for port {}: {}", - child.id(), - port_id, - err - ); - } - } - } - } - - if let Some(state) = self.port_states.remove(&port_id) { - debug!("disabling port slot {} for port {}", state.slot, port_id); - let result = self.disable_port_slot(state.slot).await.and(Ok(true)); - debug!( - "disabled port slot {} for port {} with result: {:?}", - state.slot, port_id, result - ); - result - } else { - debug!( - "Attempted to detach from port {}, which wasn't previously attached.", - port_id - ); - Ok(false) - } - } - - pub async fn update_max_packet_size( - &self, - input_context: &mut Dma>, - slot_id: u8, - dev_desc: usb::DeviceDescriptor8Byte, - ) -> Result<()> { - let new_max_packet_size = if dev_desc.major_usb_vers() <= 2 { - // For USB 2.0 and below, packet_size is in bytes - u32::from(dev_desc.packet_size) - } else { - // For later USB versions, packet_size is the shift - 1u32 << dev_desc.packet_size - }; - let mut b = input_context.device.endpoints[0].b.read(); - b &= 0x0000_FFFF; - b |= (new_max_packet_size) << 16; - input_context.device.endpoints[0].b.write(b); - - let (event_trb, command_trb) = self - .execute_command(|trb, cycle| { - trb.evaluate_context(slot_id, input_context.physical(), false, cycle) - }) - .await; - - self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; - //self.event_handler_finished(); - - Ok(()) - } - - pub async fn update_default_control_pipe( - &self, - input_context: &mut Dma>, - slot_id: u8, - dev_desc: &DevDesc, - ) -> Result<()> { - debug!("Updating default control pipe!"); - input_context.add_context.write(1 << 1); - input_context.drop_context.write(0); - - let new_max_packet_size = if dev_desc.major_version() <= 2 { - // For USB 2.0 and below, packet_size is in bytes - u32::from(dev_desc.packet_size) - } else { - // For later USB versions, packet_size is the shift - 1u32 << dev_desc.packet_size - }; - let mut b = input_context.device.endpoints[0].b.read(); - b &= 0x0000_FFFF; - b |= (new_max_packet_size) << 16; - input_context.device.endpoints[0].b.write(b); - - let (event_trb, command_trb) = self - .execute_command(|trb, cycle| { - trb.evaluate_context(slot_id, input_context.physical(), false, cycle) - }) - .await; - debug!("Completed the command to update the default control pipe"); - - self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; - //self.event_handler_finished(); - - Ok(()) - } - - pub async fn address_device( - &self, - input_context: &mut Dma>, - port: PortId, - slot_ty: u8, - slot: u8, - protocol_speed: &ProtocolSpeed, - speed: u8, - ) -> Result { - // Collect MTT, parent port number, parent slot ID - let mut mtt = false; - let mut parent_hub_slot_id = 0u8; - let mut parent_port_num = 0u8; - if let Some((parent_port, port_num)) = port.parent() { - match self.port_states.get(&parent_port) { - Some(parent_state) => { - // parent info must be supplied if: - let mut needs_parent_info = false; - // 1. the device is low or full speed and connected through a high speed hub - //TODO: determine device speed (speed is not accurate as it comes from the port) - // 2. the device is superspeed and connected through a higher rank hub - //TODO: determine device speed (speed is not accurate as it comes from the port) - // For now, this is just set to true to force things to work - needs_parent_info = true; - if needs_parent_info { - parent_hub_slot_id = parent_state.slot; - parent_port_num = port_num; - } - info!( - "port {} parent_hub_slot_id {} parent_port_num {}", - port, parent_hub_slot_id, parent_port_num - ); - } - None => { - warn!("port {} missing parent port {} state", port, parent_port); - } - } - } - - let mut ring = Ring::new::(self.cap.ac64(), 16, true)?; - - { - input_context.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit). - - let route_string = port.route_string; - let context_entries = 1u8; - let hub = false; - - assert_eq!(route_string & 0x000F_FFFF, route_string); - input_context.device.slot.a.write( - route_string - | (u32::from(speed) << 20) - | (u32::from(mtt) << 25) - | (u32::from(hub) << 26) - | (u32::from(context_entries) << 27), - ); - - let max_exit_latency = 0u16; - let root_hub_port_num = port.root_hub_port_num; - let number_of_ports = 0u8; - input_context.device.slot.b.write( - u32::from(max_exit_latency) - | (u32::from(root_hub_port_num) << 16) - | (u32::from(number_of_ports) << 24), - ); - - // TODO - let ttt = 0u8; - let interrupter = 0u8; - - assert_eq!(ttt & 0b11, ttt); - input_context.device.slot.c.write( - u32::from(parent_hub_slot_id) - | (u32::from(parent_port_num) << 8) - | (u32::from(ttt) << 16) - | (u32::from(interrupter) << 22), - ); - - let max_error_count = 3u8; // recommended value according to the XHCI spec - let ep_ty = 4u8; // control endpoint, bidirectional - let max_packet_size: u32 = - if protocol_speed.is_lowspeed() || protocol_speed.is_fullspeed() { - 8 - } else if protocol_speed.is_highspeed() { - 64 - } else { - 512 - }; - let host_initiate_disable = false; // only applies to streams - let max_burst_size = 0u8; // TODO - - assert_eq!(max_error_count & 0b11, max_error_count); - input_context.device.endpoints[0].b.write( - (u32::from(max_error_count) << 1) - | (u32::from(ep_ty) << 3) - | (u32::from(host_initiate_disable) << 7) - | (u32::from(max_burst_size) << 8) - | (u32::from(max_packet_size) << 16), - ); - - let dequeue_cycle_state = true; - let tr = ring.register(); - input_context.device.endpoints[0] - .trh - .write((tr >> 32) as u32); - input_context.device.endpoints[0] - .trl - .write((tr as u32) | u32::from(dequeue_cycle_state)); - - // The default control pipe can always use 8 bytes - let avg_trb_len = 8u8; - input_context.device.endpoints[0] - .c - .write(u32::from(avg_trb_len)); - } - - let input_context_physical = input_context.physical(); - - let (event_trb, _) = self - .execute_command(|trb, cycle| { - trb.address_device(slot, input_context_physical, false, cycle) - }) - .await; - - if event_trb.completion_code() != TrbCompletionCode::Success as u8 { - error!( - "Failed to address device at slot {} (port {}), completion code 0x{:X}", - slot, - port, - event_trb.completion_code() - ); - //self.event_handler_finished(); - return Err(Error::new(EIO)); - } - //self.event_handler_finished(); - - Ok(ring) - } - - fn uses_msi_interrupts(&self) -> bool { - matches!(self.interrupt_method, InterruptMethod::Msi) - } - - /// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always - /// true when using MSI/MSI-X. - pub fn received_irq(&self) -> bool { - let mut runtime_regs = self.run.lock().unwrap(); - - if self.uses_msi_interrupts() { - // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit - // doesn't have to be touched. - trace!( - "Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", - runtime_regs.ints[0].iman.readf(1), - runtime_regs.ints[0].erdp_low.readf(1 << 3) - ); - true - } else if runtime_regs.ints[0].iman.readf(1) { - trace!( - "Successfully received INTx# interrupt, IP={}, EHB={}", - runtime_regs.ints[0].iman.readf(1), - runtime_regs.ints[0].erdp_low.readf(1 << 3) - ); - // If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is - // a special register to specify whether the IRQ actually came from the xHC. - runtime_regs.ints[0].iman.writef(1, true); - - // The interrupt came from the xHC. - true - } else { - // The interrupt came from a different device. - false - } - } - fn spawn_drivers(&self, port: PortId) -> Result<()> { - // TODO: There should probably be a way to select alternate interfaces, and not just the - // first one. - // TODO: Now that there are some good error crates, I don't think errno.h error codes are - // suitable here. - - let ps = self.port_states.get(&port).unwrap(); - trace!("Spawning driver on port: {}", port); - - //TODO: support choosing config? - let config_desc = &ps - .dev_desc - .as_ref() - .ok_or_else(|| { - log::warn!("Missing device descriptor"); - Error::new(EBADF) - })? - .config_descs - .first() - .ok_or_else(|| { - log::warn!("Missing config descriptor"); - Error::new(EBADF) - })?; - - trace!("Got config and device descriptors on port {}", port); - - for ifdesc in config_desc.interface_descs.iter() { - //TODO: support alternate settings - // This is difficult because the device driver must know which alternate - // to use, but if alternates can have different classes, then a different - // device driver may be required for each alternate. For now, we will use - // only the default alternate setting (0) - if ifdesc.alternate_setting != 0 { - warn!( - "ignoring port {} iface {} alternate {} class {}.{} proto {}", - port, - ifdesc.number, - ifdesc.alternate_setting, - ifdesc.class, - ifdesc.sub_class, - ifdesc.protocol - ); - continue; - } - - if let Some(driver) = self.drivers_config.drivers.iter().find(|driver| { - driver.class == ifdesc.class - && driver - .subclass() - .map(|subclass| subclass == ifdesc.sub_class) - .unwrap_or(true) - }) { - info!( - "Loading subdriver \"{}\" for port {} iface {} alternate {} class {}.{} proto {}", - driver.name, - port, - ifdesc.number, - ifdesc.alternate_setting, - ifdesc.class, - ifdesc.sub_class, - ifdesc.protocol, - ); - let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; - - let command = if command.starts_with('/') { - command.to_owned() - } else { - "/usr/lib/drivers/".to_owned() + command - }; - let process = process::Command::new(command) - .args( - args.into_iter() - .map(|arg| { - arg.replace("$SCHEME", &self.scheme_name) - .replace("$PORT", &format!("{}", port)) - .replace("$IF_NUM", &format!("{}", ifdesc.number)) - .replace("$IF_PROTO", &format!("{}", ifdesc.protocol)) - }) - .collect::>(), - ) - .stdin(process::Stdio::null()) - .spawn() - .or(Err(Error::new(ENOENT)))?; - self.drivers.alter(port, |children_opt| { - let mut children = children_opt.unwrap_or_else(|| Vec::new()); - children.push(process); - Some(children) - }); - } else { - warn!( - "No driver for port {} iface {} alternate {} class {}.{} proto {}", - port, - ifdesc.number, - ifdesc.alternate_setting, - ifdesc.class, - ifdesc.sub_class, - ifdesc.protocol - ); - } - } - - Ok(()) - } - pub fn capabilities_iter(&self) -> ExtendedCapabilitiesIter { - unsafe { - ExtendedCapabilitiesIter::new( - (self.base as *mut u8).offset((self.cap.ext_caps_ptr_in_dwords() << 2) as isize), - ) - } - } - pub fn supported_protocols_iter(&self) -> impl Iterator { - self.capabilities_iter() - .filter_map(|(pointer, cap_num)| unsafe { - if cap_num == CapabilityId::SupportedProtocol as u8 { - Some(&*pointer.cast::().as_ptr()) - } else { - None - } - }) - } - pub fn supported_protocol(&self, port: PortId) -> Option<&'static SupportedProtoCap> { - self.supported_protocols_iter().find(|supp_proto| { - supp_proto - .compat_port_range() - .contains(&port.root_hub_port_num) - }) - } - pub fn supported_protocol_speeds( - &self, - port: PortId, - ) -> impl Iterator { - use extended::*; - const DEFAULT_SUPP_PROTO_SPEEDS: [ProtocolSpeed; 7] = [ - // Full-speed - ProtocolSpeed::from_raw( - (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT - | (false as u32) << PROTO_SPEED_PFD_SHIFT - | (Psie::Mbps as u32) << PROTO_SPEED_PSIE_SHIFT - | 12 << PROTO_SPEED_PSIM_SHIFT - | 1 << PROTO_SPEED_PSIV_SHIFT, - ), - // Low-speed - ProtocolSpeed::from_raw( - (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT - | (false as u32) << PROTO_SPEED_PFD_SHIFT - | (Psie::Kbps as u32) << PROTO_SPEED_PSIE_SHIFT - | 1500 << PROTO_SPEED_PSIM_SHIFT - | 2 << PROTO_SPEED_PSIV_SHIFT, - ), - // High-speed - ProtocolSpeed::from_raw( - (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT - | (false as u32) << PROTO_SPEED_PFD_SHIFT - | (Psie::Mbps as u32) << PROTO_SPEED_PSIE_SHIFT - | 480 << PROTO_SPEED_PSIM_SHIFT - | 3 << PROTO_SPEED_PSIV_SHIFT, - ), - // SuperSpeed Gen1 x1 - ProtocolSpeed::from_raw( - (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT - | (true as u32) << PROTO_SPEED_PFD_SHIFT - | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT - | 5 << PROTO_SPEED_PSIM_SHIFT - | (Lp::SuperSpeed as u32) << PROTO_SPEED_LP_SHIFT - | 4 << PROTO_SPEED_PSIV_SHIFT, - ), - // SuperSpeedPlus Gen2 x1 - ProtocolSpeed::from_raw( - (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT - | (true as u32) << PROTO_SPEED_PFD_SHIFT - | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT - | 10 << PROTO_SPEED_PSIM_SHIFT - | (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT - | 5 << PROTO_SPEED_PSIV_SHIFT, - ), - // SuperSpeedPlus Gen1 x2 - ProtocolSpeed::from_raw( - (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT - | (true as u32) << PROTO_SPEED_PFD_SHIFT - | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT - | 10 << PROTO_SPEED_PSIM_SHIFT - | (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT - | 6 << PROTO_SPEED_PSIV_SHIFT, - ), - // SuperSpeedPlus Gen2 x2 - ProtocolSpeed::from_raw( - (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT - | (true as u32) << PROTO_SPEED_PFD_SHIFT - | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT - | 20 << PROTO_SPEED_PSIM_SHIFT - | (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT - | 7 << PROTO_SPEED_PSIV_SHIFT, - ), - ]; - - match self.supported_protocol(port) { - Some(supp_proto) => { - if supp_proto.psic() != 0 { - unsafe { supp_proto.protocol_speeds().iter() } - } else { - DEFAULT_SUPP_PROTO_SPEEDS.iter() - } - } - None => { - log::warn!( - "falling back to default supported protocol speeds for port {}", - port - ); - DEFAULT_SUPP_PROTO_SPEEDS.iter() - } - } - } - pub fn lookup_psiv(&self, port: PortId, psiv: u8) -> Option<&'static ProtocolSpeed> { - self.supported_protocol_speeds(port) - .find(|speed| speed.psiv() == psiv) - } -} -pub fn start_irq_reactor(hci: &Arc>, irq_file: Option) { - let hci_clone = Arc::clone(&hci); - - debug!("About to start IRQ reactor"); - - *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { - debug!("Started IRQ reactor thread"); - IrqReactor::new(hci_clone, irq_file).run() - })); -} - -pub fn start_device_enumerator(hci: &Arc>) { - let hci_clone = Arc::clone(&hci); - - debug!("About to start Device Enumerator"); - - *hci.device_enumerator.lock().unwrap() = Some(thread::spawn(move || { - debug!("Started Device Enumerator"); - DeviceEnumerator::new(hci_clone).run(); - })); -} - -#[derive(Deserialize)] -struct DriverConfig { - name: String, - class: u8, - subclass: i16, // The subclass may be meaningless for some drivers, hence negative values (and values above 255) mean "undefined". - command: Vec, -} -impl DriverConfig { - fn subclass(&self) -> Option { - u8::try_from(self.subclass).ok() - } -} -#[derive(Deserialize)] -struct DriversConfig { - drivers: Vec, -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/operational.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/operational.rs deleted file mode 100644 index 12be477296..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/operational.rs +++ /dev/null @@ -1,101 +0,0 @@ -use common::io::{Io, Mmio}; - -/// The XHCI Operational Registers -/// -/// These registers specify the operational state of the XHCI device, and are used to receive status -/// messages and transmit commands. These registers are offset from the XHCI base address by the -/// "length" field of the [CapabilityRegs] -/// -/// See XHCI section 5.4. Table 5-18 describes the offset of these registers in memory. -#[repr(C, packed)] -pub struct OperationalRegs { - /// The USB Command Register (USBCMD) - /// - /// Describes the command to be executed by the XHCI. Writes to this register case a command - /// to be executed. - /// - /// - Bit 0 is the Run/Stop bit (R/S). Writing a value of 1 stops the xHC from executing the schedule, 1 resumes. Latency is ~16ms at worst. (See XHCI Table 5-20) - /// - Bit 1 is the Host Controller Reset Bit (HCRST). Used by software to reset the host controller (See XHCI Table 5-20) - /// - Bit 2 is the Interrupter Enable Bit (INTE). Enables interrupting the host system. - /// - Bit 3 is the Host System Error Enable Bit (HSEE). Enables out-of-band error signalling to the host. - /// - Bits 4-6 are reserved. - /// - Bit 7 is the Light Host Controller Reset Bit (LHCRST). Resets the driver without affecting the state of the ports. Affected by [CapabilityRegs] - /// - Bit 8 is the Controller Save State Bit (CSS). See XHCI Table 5-20 - /// - Bit 9 is the Controller Restore State Bit (CRS). See XHCI Table 5-20 - /// - Bit 10 is the Enable Wrap Event Bit (EWE). See XHCI Table 5-20 - /// - Bit 11 is the Enable U3 MFINDEX Stop Bit (EU3S). See XHCI Table 5-20 - /// - Bit 12 is reserved. - /// - Bit 13 is the CEM Enable Bit (CME). See XHCI Table 5-20 - /// - Bit 14 is the Extended TBC Enable Bit (ETE). See XHCI Table 5-20 - /// - Bit 15 is the Extended TBC TRB Status Enable Bit (TSC_En). See XHCI Table 5-20 - /// - Bit 16 is the VTIO Enable Bit (VTIOE). Controls the enable state of the VTIO capability. - /// - Bits 17-31 are reserved. - /// - pub usb_cmd: Mmio, - /// The USB Status Register (USBSTS) - /// - /// This register indicates pending interrupts and various states of the host controller. - /// - /// Software sets a bit to '0' in this register by writing a 1 to it. - /// - /// - pub usb_sts: Mmio, - /// The PAGESIZE Register (PAGESIZE) - /// - /// - pub page_size: Mmio, - /// Reserved bits (RsvdZ) - _rsvd: [Mmio; 2], - /// The Device Notification Control Register (DNCTRL) - /// - /// - pub dn_ctrl: Mmio, - /// The Command Ring Control Register Lower 32 bits (CRCR) - /// - /// - pub crcr_low: Mmio, - /// The Command Ring Control Register Upper 32 bits (CRCR) - /// - /// - pub crcr_high: Mmio, - /// Reserved bits (RsvdZ) - _rsvd2: [Mmio; 4], - /// Device Context Base Address Array Pointer Lower 32 bits (DCBAAP) - /// - /// - pub dcbaap_low: Mmio, - /// Device Context Base Address Array Pointer Upper 32 bits (DCBAAP) - /// - /// - pub dcbaap_high: Mmio, - /// The Configure Register (CONFIG) - /// - /// - pub config: Mmio, - // The standard has another set of reserved bits from 3C-3FFh here - // The standard has 400-13FFh has a Port Register Set here (likely defined in port.rs). -} - -// Run/stop -pub const USB_CMD_RS: u32 = 1 << 0; -/// Host controller reset -pub const USB_CMD_HCRST: u32 = 1 << 1; -// Interrupter enable -pub const USB_CMD_INTE: u32 = 1 << 2; - -/// Host controller halted -pub const USB_STS_HCH: u32 = 1 << 0; -/// Host controller not ready -pub const USB_STS_CNR: u32 = 1 << 11; - -/// The mask to get the CIE bit from the Config register. See [OperationalRegs] -pub const OP_CONFIG_CIE_BIT: u32 = 1 << 9; - -impl OperationalRegs { - pub fn cie(&self) -> bool { - self.config.readf(OP_CONFIG_CIE_BIT) - } - pub fn set_cie(&mut self, value: bool) { - self.config.writef(OP_CONFIG_CIE_BIT, value) - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/port.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/port.rs deleted file mode 100644 index 0654ccc3a7..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/port.rs +++ /dev/null @@ -1,114 +0,0 @@ -use common::io::{Io, Mmio}; - -// RO - read-only -// ROS - read-only sticky -// RW - read/write -// RWS - read/write sticky -// RW1CS - read/write-1-to-clear sticky -// RW1S - read/write-1-to-set -// Sticky register values may preserve values through chip hardware reset - -bitflags! { - #[derive(Debug)] - pub struct PortFlags: u32 { - const CCS = 1 << 0; // ROS - const PED = 1 << 1; // RW1CS - const RSVD_2 = 1 << 2; // RsvdZ - const OCA = 1 << 3; // RO - const PR = 1 << 4; // RW1S - const PLS_0 = 1 << 5; // RWS - const PLS_1 = 1 << 6; // RWS - const PLS_2 = 1 << 7; // RWS - const PLS_3 = 1 << 8; // RWS - const PP = 1 << 9; // RWS - const SPEED_0 = 1 << 10; // ROS - const SPEED_1 = 1 << 11; // ROS - const SPEED_2 = 1 << 12; // ROS - const SPEED_3 = 1 << 13; // ROS - const PIC_AMB = 1 << 14; // RWS - const PIC_GRN = 1 << 15; // RWS - const LWS = 1 << 16; // RW - const CSC = 1 << 17; // RW1CS - const PEC = 1 << 18; // RW1CS - const WRC = 1 << 19; // RW1CS - const OCC = 1 << 20; // RW1CS - const PRC = 1 << 21; // RW1CS - const PLC = 1 << 22; // RW1CS - const CEC = 1 << 23; // RW1CS - const CAS = 1 << 24; // RO - const WCE = 1 << 25; // RWS - const WDE = 1 << 26; // RWS - const WOE = 1 << 27; // RWS - const RSVD_28 = 1 << 28; // RsvdZ - const RSVD_29 = 1 << 29; // RsvdZ - const DR = 1 << 30; // RO - const WPR = 1 << 31; // RW1S - } -} - -#[repr(C, packed)] -pub struct Port { - // This has write one to clear fields, do not expose it, handle writes carefully! - portsc: Mmio, - pub portpmsc: Mmio, - pub portli: Mmio, - pub porthlpmc: Mmio, -} - -impl Port { - pub fn read(&self) -> u32 { - self.portsc.read() - } - - pub fn clear_csc(&mut self) { - self.portsc - .write((self.flags_preserved() | PortFlags::CSC).bits()); - } - - pub fn clear_prc(&mut self) { - self.portsc - .write((self.flags_preserved() | PortFlags::PRC).bits()); - } - - pub fn set_pr(&mut self) { - self.portsc - .write((self.flags_preserved() | PortFlags::PR).bits()); - } - - pub fn state(&self) -> u8 { - ((self.read() & (0b1111 << 5)) >> 5) as u8 - } - - pub fn speed(&self) -> u8 { - ((self.read() & (0b1111 << 10)) >> 10) as u8 - } - - pub fn flags(&self) -> PortFlags { - PortFlags::from_bits_truncate(self.read()) - } - - // Read only preserved flags - pub fn flags_preserved(&self) -> PortFlags { - // RO(S) and RW(S) bits should be preserved - // RW1S and RW1CS bits should not - let preserved = PortFlags::CCS - | PortFlags::OCA - | PortFlags::PLS_0 - | PortFlags::PLS_1 - | PortFlags::PLS_2 - | PortFlags::PLS_3 - | PortFlags::PP - | PortFlags::SPEED_0 - | PortFlags::SPEED_1 - | PortFlags::SPEED_2 - | PortFlags::SPEED_3 - | PortFlags::PIC_AMB - | PortFlags::PIC_GRN - | PortFlags::WCE - | PortFlags::WDE - | PortFlags::WOE - | PortFlags::DR; - - self.flags() & preserved - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/ring.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/ring.rs deleted file mode 100644 index 8e187ebea4..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/ring.rs +++ /dev/null @@ -1,164 +0,0 @@ -use std::mem; - -use syscall::error::Result; - -use common::dma::Dma; - -use super::trb::Trb; -use super::Xhci; - -pub struct Ring { - pub link: bool, - pub trbs: Dma<[Trb]>, - pub i: usize, - pub cycle: bool, -} - -impl Ring { - pub fn new(ac64: bool, length: usize, link: bool) -> Result { - Ok(Ring { - link, - trbs: unsafe { Xhci::::alloc_dma_zeroed_unsized_raw(ac64, length)? }, - i: 0, - cycle: link, - }) - } - - pub fn register(&self) -> u64 { - let base = self.trbs.physical() as *const Trb; - let addr = unsafe { base.offset(self.i as isize) }; - addr as u64 | self.cycle as u64 - } - - pub fn next_index(&mut self) -> usize { - let mut i; - loop { - i = self.i; - self.i += 1; - if self.i >= self.trbs.len() { - self.i = 0; - - if self.link { - let address = self.trbs.physical(); - self.trbs[i].link(address, true, self.cycle); - self.cycle = !self.cycle; - } else { - break; - } - } else { - break; - } - } - i - } - - pub fn next(&mut self) -> (&mut Trb, bool) { - let i = self.next_index(); - (&mut self.trbs[i], self.cycle) - } - /// Endless iterator that iterates through the ring items, over and over again. The iterator - /// doesn't enqueue or dequeue anything. - pub fn iter(&self) -> impl Iterator + '_ { - Iter { - ring: self, - i: self.i, - } - } - /// Takes a physical address and returns the index into this ring, that the index represents. - /// Returns `None` if the address is outside the bounds of this ring. - /// - /// # Panics - /// Panics if paddr is not a multiple of 16 bytes, i.e. the size of a TRB. - pub fn phys_addr_to_index(&self, ac64: bool, paddr: u64) -> Option { - let base = (self.trbs.physical() as u64) - & if ac64 { - 0xFFFF_FFFF_FFFF_FFFF - } else { - 0xFFFF_FFFF - }; - let offset = paddr.checked_sub(base)? as usize; - - assert_eq!( - offset % mem::size_of::(), - 0, - "unaligned TRB physical address" - ); - - let index = offset / mem::size_of::(); - - if index > self.trbs.len() { - return None; - } - - Some(index) - } - pub fn phys_addr_to_entry_ref(&self, ac64: bool, paddr: u64) -> Option<&Trb> { - Some(&self.trbs[self.phys_addr_to_index(ac64, paddr)?]) - } - pub fn phys_addr_to_entry_mut(&mut self, ac64: bool, paddr: u64) -> Option<&mut Trb> { - let index = self.phys_addr_to_index(ac64, paddr)?; - Some(&mut self.trbs[index]) - } - pub fn phys_addr_to_entry(&self, ac64: bool, paddr: u64) -> Option { - Some(self.trbs[self.phys_addr_to_index(ac64, paddr)?].clone()) - } - pub(crate) fn start_virt_addr(&self) -> *const Trb { - self.trbs.as_ptr() - } - pub(crate) fn end_virt_addr(&self) -> *const Trb { - unsafe { self.start_virt_addr().offset(self.trbs.len() as isize) } - } - pub fn trb_phys_ptr(&self, ac64: bool, trb: &Trb) -> u64 { - let trb_virt_pointer = trb as *const Trb; - let trbs_base_virt_pointer = self.trbs.as_ptr(); - - if (trb_virt_pointer as usize) < (trbs_base_virt_pointer as usize) - || (trb_virt_pointer as usize) - > (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::() - { - panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb); - } - let trb_offset_from_base = trb_virt_pointer as u64 - trbs_base_virt_pointer as u64; - - let trbs_base_phys_ptr = (self.trbs.physical() as u64) - & if ac64 { - 0xFFFF_FFFF_FFFF_FFFF - } else { - 0xFFFF_FFFF - }; - let trb_phys_ptr = trbs_base_phys_ptr + trb_offset_from_base; - trb_phys_ptr - } - /* - /// Endless mutable iterator that iterates through the ring items, over and over again. The - /// iterator doesn't enqueue or dequeue anything, but the trbs are mutably borrowed. - pub fn iter_mut(&mut self) -> impl Iterator + '_ { - IterMut { ring: self, i: self.i } - }*/ -} -struct Iter<'ring> { - ring: &'ring Ring, - i: usize, -} -impl<'ring> Iterator for Iter<'ring> { - type Item = &'ring Trb; - - fn next(&mut self) -> Option { - let i = self.i; - self.i = (self.i + 1) % self.ring.trbs.len(); - Some(&self.ring.trbs[i]) - } -} -/*struct IterMut<'ring> { - ring: &'ring mut Ring, - i: usize, -} -impl<'ring> Iterator for IterMut<'ring> { - type Item = &'ring mut Trb; - - fn next(&mut self) -> Option { - let i = self.i; - self.i = (self.i + 1) % self.ring.trbs.len(); - Some(&mut self.ring.trbs[i]) - } -}*/ diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/runtime.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/runtime.rs deleted file mode 100644 index 55d54d4472..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/runtime.rs +++ /dev/null @@ -1,20 +0,0 @@ -use common::io::Mmio; - -#[repr(C, packed)] -pub struct Interrupter { - pub iman: Mmio, - pub imod: Mmio, - pub erstsz: Mmio, - _rsvd: Mmio, - pub erstba_low: Mmio, - pub erstba_high: Mmio, - pub erdp_low: Mmio, - pub erdp_high: Mmio, -} - -#[repr(C, packed)] -pub struct RuntimeRegs { - pub mfindex: Mmio, - _rsvd: [Mmio; 7], - pub ints: [Interrupter; 1024], -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/scheme.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/scheme.rs deleted file mode 100644 index ca27b3fec7..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/scheme.rs +++ /dev/null @@ -1,2839 +0,0 @@ -//! Provides the File Descriptor Scheme Interface to the XHCI. -//! -//! This file implements the basic unix file operations that are used to interface with the XHCI -//! driver. While an external program could interact with the driver using this interface, a -//! higher-level abstraction can be found in driver_interface.rs. It is recommended that you use -//! the functions in that module to interact with the driver. -//! -//! The XHCI driver has the following set of schemes: -//! -//! port -//! port/configure -//! port/request -//! port/endpoints -//! port/descriptors -//! port/state -//! port/endpoints/ -//! port/endpoints//ctl -//! port/endpoints//data -use std::convert::TryFrom; -use std::io::prelude::*; -use std::ops::Deref; -use std::sync::atomic; -use std::{cmp, fmt, io, mem, str}; - -use common::dma::Dma; -use futures::executor::block_on; -use log::{debug, error, info, trace, warn}; -use redox_scheme::scheme::SchemeSync; -use scheme_utils::FpathWriter; -use smallvec::SmallVec; - -use common::io::Io; -use redox_scheme::{CallerCtx, OpenResult}; -use syscall::schemev2::NewFdFlags; -use syscall::{ - Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, - ENOTDIR, EOPNOTSUPP, EPROTO, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_DIRECTORY, O_RDWR, - O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, -}; - -use super::{port, usb}; -use super::{EndpointState, PortId, Xhci}; - -use super::context::{ - SlotState, StreamContextArray, StreamContextType, CONTEXT_32, CONTEXT_64, - SLOT_CONTEXT_STATE_MASK, SLOT_CONTEXT_STATE_SHIFT, -}; -use super::extended::ProtocolSpeed; -use super::irq_reactor::{EventDoorbell, RingId}; -use super::ring::Ring; -use super::trb::{TransferKind, Trb, TrbCompletionCode, TrbType}; -use super::usb::endpoint::EndpointTy; - -use crate::driver_interface::*; -use regex::Regex; - -lazy_static! { - static ref REGEX_PORT_CONFIGURE: Regex = Regex::new(r"^port([\d\.]+)/configure$") - .expect("Failed to create the regex for the port/configure scheme."); - static ref REGEX_PORT_ATTACH: Regex = Regex::new(r"^port([\d\.]+)/attach$") - .expect("Failed to create the regex for the port/attach scheme."); - static ref REGEX_PORT_DETACH: Regex = Regex::new(r"^port([\d\.]+)/detach$") - .expect("Failed to create the regex for the port/detach scheme."); - static ref REGEX_PORT_DESCRIPTORS: Regex = Regex::new(r"^port([\d\.]+)/descriptors$") - .expect("Failed to create the regex for the port/descriptors"); - static ref REGEX_PORT_STATE: Regex = Regex::new(r"^port([\d\.]+)/state$") - .expect("Failed to create the regex for the port/state scheme"); - static ref REGEX_PORT_REQUEST: Regex = Regex::new(r"^port([\d\.]+)/request$") - .expect("Failed to create the regex for the port/request scheme"); - static ref REGEX_PORT_ENDPOINTS: Regex = Regex::new(r"^port([\d\.]+)/endpoints$") - .expect("Failed to create the regex for the port/endpoints scheme"); - static ref REGEX_PORT_SPECIFIC_ENDPOINT: Regex = - Regex::new(r"^port([\d\.]+)/endpoints/(\d{1,3})$") - .expect("Failed to create the regex for the port/endpoints/ scheme"); - static ref REGEX_PORT_SUB_ENDPOINT: Regex = Regex::new( - r"port([\d\.]+)/endpoints/(\d{1,3})/(ctl|data)$" - ) - .expect("Failed to create the regex for the port/endpoints// scheme"); - static ref REGEX_PORT_ROOT: Regex = - Regex::new(r"^port([\d\.]+)$").expect("Failed to create the regex for the port scheme."); - static ref REGEX_TOP_LEVEL: Regex = - Regex::new(r"^$").expect("Failed to create the regex for the top-level scheme"); -} - -pub enum ControlFlow { - Continue, - Break, -} - -#[derive(Clone, Copy, Debug)] -pub enum EndpIfState { - Init, - WaitingForDataPipe { - direction: XhciEndpCtlDirection, - bytes_transferred: u32, - bytes_to_transfer: u32, - }, - WaitingForStatus, - WaitingForTransferResult(PortTransferStatus), -} - -/// Subdirs of an endpoint -#[derive(Debug)] -pub enum EndpointHandleTy { - /// portX/endpoints/Y/data. Allows clients to read and write data associated with ctl requests. - Data, - - /// portX/endpoints/Y/status - Ctl, - - /// portX/endpoints/Y/ - Root(Vec), // content -} - -#[derive(Clone, Copy, Debug)] -pub enum PortTransferState { - /// Ready to read or write to do another transfer - Ready, - - /// Transfer has completed, and the status has to be read. - WaitingForStatusReq(PortTransferStatus), -} - -pub enum PortReqState { - Init, - WaitingForDeviceBytes(Dma<[u8]>, usb::Setup), // buffer, setup params - WaitingForHostBytes(Dma<[u8]>, usb::Setup), // buffer, setup params - TmpSetup(usb::Setup), - Tmp, -} - -/// The Handle to a specific scheme that is returned by an open() operation. -/// -/// Contains some information about the data requested via the handle. -#[derive(Debug)] -pub enum Handle { - TopLevel(Vec), // contents (ports) - Port(PortId, Vec), // port, contents - PortDesc(PortId, Vec), // port, contents - PortState(PortId), // port - PortReq(PortId, PortReqState), // port, state - Endpoints(PortId, Vec), // port, contents - Endpoint(PortId, u8, EndpointHandleTy), // port, endpoint, state - ConfigureEndpoints(PortId), // port - AttachDevice(PortId), // port - DetachDevice(PortId), // port - SchemeRoot, -} - -/// The type of handle. -/// -/// This is used by fstat() to determine whether to return a: -/// - MODE_DIR -/// - MODE_FILE -/// - MODE_CHR -pub(crate) enum HandleType { - Directory, - File, - Character, -} - -/// Parameters to a handle that were extracted from a scheme. -/// -/// This structure is used to easily convert a scheme filesystem path to -/// the parameters that we care about when constructing a handle. -#[derive(Debug)] -enum SchemeParameters { - /// The scheme references the top-level XHCI driver endpoint - TopLevel, - /// /port - Port(PortId), // port number - /// /port/descriptors - PortDesc(PortId), // port number - /// /port/state - PortState(PortId), // port number - /// /port/request - PortReq(PortId), // port number - /// /port/endpoints - Endpoints(PortId), // port number - /// /port/endpoints//(data|ctl) - /// - /// This can also represent - /// /port/endpoints/ - Endpoint(PortId, u8, String), // port number, endpoint number, handle type - /// /port/configure - ConfigureEndpoints(PortId), // port number - /// /port/attach - AttachDevice(PortId), // port number - /// /port/detach - DetachDevice(PortId), // port number -} - -impl Handle { - /// Converts a handle back into the scheme that generated it. - /// - /// This is useful for implementing fpath, as the input parameters for our existing schemes - /// are generally static for the lifetime of the driver and can easily be retrieved. - /// - /// # Returns - /// - A [String] containing the scheme path that the handle is associated with. - pub(crate) fn to_path(&self) -> String { - match self { - Handle::TopLevel(_) => String::from(""), - Handle::Port(port_num, _) => { - format!("port{}", port_num) - } - Handle::PortDesc(port_num, _) => { - format!("port{}/descriptors", port_num) - } - Handle::PortState(port_num) => { - format!("port{}/state", port_num) - } - Handle::PortReq(port_num, _) => { - format!("port{}/request", port_num) - } - Handle::Endpoints(port_num, _) => { - format!("port{}/endpoints", port_num) - } - Handle::Endpoint(port_num, endpoint_num, handle_type) => match handle_type { - EndpointHandleTy::Data => { - format!("port{}/endpoints/{}/data", port_num, endpoint_num) - } - EndpointHandleTy::Ctl => { - format!("port{}/endpoints/{}/ctl", port_num, endpoint_num) - } - EndpointHandleTy::Root(_) => { - format!("port{}/endpoints/{}", port_num, endpoint_num) - } - }, - Handle::ConfigureEndpoints(port_num) => { - format!("port{}/configure", port_num) - } - Handle::AttachDevice(port_num) => { - format!("port{}/attach", port_num) - } - Handle::DetachDevice(port_num) => { - format!("port{}/detach", port_num) - } - Handle::SchemeRoot => String::from(""), - } - } - - /// Gets the access mode for this handle - /// - /// Handles can be a file, a directory, or a character interface. The mode that we use is - /// entirely dependent upon the functionality of the scheme endpoint, so this returns the value - /// that should be associated with that endpoint. - /// - /// # Returns - /// - [HandleType] - The access mode associated with the handle. - pub(crate) fn get_handle_type(&self) -> HandleType { - match self { - &Handle::TopLevel(_) => HandleType::Directory, - &Handle::Port(_, _) => HandleType::Directory, - &Handle::Endpoints(_, _) => HandleType::Directory, - &Handle::PortDesc(_, _) => HandleType::File, - &Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(_, _)) => HandleType::Character, - &Handle::PortReq(_, PortReqState::WaitingForHostBytes(_, _)) => HandleType::Character, - &Handle::PortReq(_, PortReqState::Tmp) => unreachable!(), - &Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(), - &Handle::PortState(_) => HandleType::Character, - &Handle::PortReq(_, _) => HandleType::Character, - &Handle::ConfigureEndpoints(_) => HandleType::Character, - &Handle::AttachDevice(_) => HandleType::Character, - &Handle::DetachDevice(_) => HandleType::Character, - &Handle::Endpoint(_, _, ref st) => match st { - EndpointHandleTy::Data => HandleType::Character, - EndpointHandleTy::Ctl => HandleType::Character, - EndpointHandleTy::Root(_) => HandleType::Directory, - }, - &Handle::SchemeRoot => HandleType::Directory, - } - } - - /// Gets the length of the file buffer as returned by fstat in Stat.st_size - /// - /// As some of these endpoints did not return a length in the origin code, this - /// provides an Option - /// - /// # Returns - /// Either the size of the buffer, or [Option::None] if the buffer does not exist. - pub(crate) fn get_buf_len(&self) -> Option { - match self { - &Handle::TopLevel(ref buf) => Some(buf.len()), - &Handle::Port(_, ref buf) => Some(buf.len()), - &Handle::Endpoints(_, ref buf) => Some(buf.len()), - &Handle::PortDesc(_, ref buf) => Some(buf.len()), - &Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) => Some(buf.len()), - &Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => Some(buf.len()), - &Handle::PortReq(_, PortReqState::Tmp) => None, - &Handle::PortReq(_, PortReqState::TmpSetup(_)) => None, - &Handle::PortState(_) => None, - &Handle::PortReq(_, _) => None, - &Handle::ConfigureEndpoints(_) => None, - &Handle::AttachDevice(_) => None, - &Handle::DetachDevice(_) => None, - &Handle::Endpoint(_, _, ref st) => match st { - EndpointHandleTy::Data => None, - EndpointHandleTy::Ctl => None, - EndpointHandleTy::Root(ref buf) => Some(buf.len()), - }, - &Handle::SchemeRoot => None, - } - } -} - -impl SchemeParameters { - /// This function gets a partially populated handle from a scheme string. - /// - /// This function is intended to be used by the driver's 'open' filesystem - /// hook to determine if the given string value represents a valid scheme - /// - /// # Arguments - /// 'scheme: &[str]' - A scheme in string format. - /// - /// # Returns - /// A [Result] containing: - /// - A [SchemeParameters] object representing the scheme that was passed, populated with the input parameters - /// - [ENOENT] if the passed scheme path is not valid for this driver. - /// - /// # Notes - /// ENOENT is returned so that it can easily be forwarded to the caller of open(). It cleans - /// up the function considerably to be able to use the ? syntax. - pub fn from_scheme(scheme: &str) -> Result { - fn get_string_from_regex( - rgx: &Regex, - scheme: &str, - capture_idx: usize, - ) -> syscall::Result { - if let Some(capture_list) = rgx.captures(scheme) { - if let Some(value) = capture_list.get(capture_idx + 1) { - return Ok(value.as_str().to_string()); - } - } - - Err(Error::new(ENOENT)) - }; - - fn get_port_id_from_regex( - rgx: &Regex, - scheme: &str, - capture_idx: usize, - ) -> syscall::Result { - if let Some(capture_list) = rgx.captures(scheme) { - if let Some(value) = capture_list.get(capture_idx + 1) { - if let Ok(port_id) = value.as_str().parse::() { - return Ok(port_id); - } - } - } - - Err(Error::new(ENOENT)) - }; - - fn get_u8_from_regex(rgx: &Regex, scheme: &str, capture_idx: usize) -> syscall::Result { - if let Some(capture_list) = rgx.captures(scheme) { - if let Some(value) = capture_list.get(capture_idx + 1) { - if let Ok(integer) = value.as_str().parse::() { - return Ok(integer); - } - } - } - - Err(Error::new(ENOENT)) - }; - - //We don't implement From::<&path::Path> because we don't want to make this a part of - //the public interface. This function does not guarantee that the handle is VALID, only - //that the scheme is valid. open() will validate the contents of the enumeration instance, - //and store it if it's valid. - - //Generate the regular expressions for all of our valid schemes. - - //Check if we have a match and either return a partially initialized scheme, OR ENOENT - if REGEX_PORT_CONFIGURE.is_match(scheme) { - let port_num = get_port_id_from_regex(®EX_PORT_CONFIGURE, scheme, 0)?; - - Ok(Self::ConfigureEndpoints(port_num)) - } else if REGEX_PORT_ATTACH.is_match(scheme) { - let port_num = get_port_id_from_regex(®EX_PORT_ATTACH, scheme, 0)?; - - Ok(Self::AttachDevice(port_num)) - } else if REGEX_PORT_DETACH.is_match(scheme) { - let port_num = get_port_id_from_regex(®EX_PORT_DETACH, scheme, 0)?; - - Ok(Self::DetachDevice(port_num)) - } else if REGEX_PORT_DESCRIPTORS.is_match(scheme) { - let port_num = get_port_id_from_regex(®EX_PORT_DESCRIPTORS, scheme, 0)?; - - Ok(Self::PortDesc(port_num)) - } else if REGEX_PORT_STATE.is_match(scheme) { - let port_num = get_port_id_from_regex(®EX_PORT_STATE, scheme, 0)?; - - Ok(Self::PortState(port_num)) - } else if REGEX_PORT_REQUEST.is_match(scheme) { - let port_num = get_port_id_from_regex(®EX_PORT_REQUEST, scheme, 0)?; - - Ok(Self::PortReq(port_num)) - } else if REGEX_PORT_ENDPOINTS.is_match(scheme) { - let port_num = get_port_id_from_regex(®EX_PORT_ENDPOINTS, scheme, 0)?; - - Ok(Self::Endpoints(port_num)) - } else if REGEX_PORT_SPECIFIC_ENDPOINT.is_match(scheme) { - let port_num = get_port_id_from_regex(®EX_PORT_SPECIFIC_ENDPOINT, scheme, 0)?; - let endpoint_num = get_u8_from_regex(®EX_PORT_SPECIFIC_ENDPOINT, scheme, 1)?; - - Ok(Self::Endpoint(port_num, endpoint_num, String::from("root"))) - } else if REGEX_PORT_SUB_ENDPOINT.is_match(scheme) { - let port_num = get_port_id_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 0)?; - let endpoint_num = get_u8_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 1)?; - let handle_type = get_string_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 2)?; - - Ok(Self::Endpoint(port_num, endpoint_num, handle_type)) - } else if REGEX_PORT_ROOT.is_match(scheme) { - let port_num = get_port_id_from_regex(®EX_PORT_ROOT, scheme, 0)?; - Ok(Self::Port(port_num)) - } else if REGEX_TOP_LEVEL.is_match(scheme) { - Ok(Self::TopLevel) - } else { - Err(Error::new(ENOENT)) - } - } -} - -#[derive(Clone, Copy)] -struct DmaSliceDbg<'a, T>(&'a Dma<[T]>); - -impl<'a, T> fmt::Debug for DmaSliceDbg<'a, T> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let DmaSliceDbg(dma) = self; - - f.debug_struct("Dma") - .field("phys_ptr", &(dma.physical() as *const u8)) - .field("virt_ptr", &(dma.deref().as_ptr() as *const u8)) - .field("length", &(dma.len() * mem::size_of::())) - .finish() - } -} - -impl fmt::Debug for PortReqState { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Init => f.debug_struct("PortReqState::Init").finish(), - Self::WaitingForDeviceBytes(ref dma, setup) => f - .debug_tuple("PortReqState::WaitingForDeviceBytes") - .field(&DmaSliceDbg(dma)) - .field(&setup) - .finish(), - Self::WaitingForHostBytes(ref dma, setup) => f - .debug_tuple("PortReqState::WaitingForHostBytes") - .field(&DmaSliceDbg(dma)) - .field(&setup) - .finish(), - Self::TmpSetup(setup) => f - .debug_tuple("PortReqState::TmpSetup") - .field(&setup) - .finish(), - Self::Tmp => f.debug_struct("PortReqState::Init").finish(), - } - } -} - -// TODO: Even though the driver interface descriptors are originally intended for JSON, they should suffice... for -// now. - -impl From for EndpDesc { - fn from(d: usb::EndpointDescriptor) -> Self { - Self { - kind: d.kind, - address: d.address, - attributes: d.attributes, - interval: d.interval, - max_packet_size: d.max_packet_size, - ssc: None, - sspc: None, - } - } -} - -impl From for HidDesc { - fn from(d: usb::HidDescriptor) -> Self { - Self { - kind: d.kind, - hid_spec_release: d.hid_spec_release, - country: d.country_code, - desc_count: d.num_descriptors, - desc_ty: d.report_desc_ty, - desc_len: d.report_desc_len, - optional_desc_ty: d.optional_desc_ty, - optional_desc_len: d.optional_desc_len, - } - } -} - -impl From for SuperSpeedCmp { - fn from(d: usb::SuperSpeedCompanionDescriptor) -> Self { - Self { - kind: d.kind, - attributes: d.attributes, - bytes_per_interval: d.bytes_per_interval, - max_burst: d.max_burst, - } - } -} -impl From for SuperSpeedPlusIsochCmp { - fn from(r: usb::SuperSpeedPlusIsochCmpDescriptor) -> Self { - Self { - kind: r.kind, - bytes_per_interval: r.bytes_per_interval, - } - } -} - -/// Any descriptor that can be stored in the config desc "data" area. -#[derive(Debug)] -pub enum AnyDescriptor { - // These are the ones that I have found, but there are more. - Device(usb::DeviceDescriptor), - Config(usb::ConfigDescriptor), - Interface(usb::InterfaceDescriptor), - Endpoint(usb::EndpointDescriptor), - Hid(usb::HidDescriptor), - SuperSpeedCompanion(usb::SuperSpeedCompanionDescriptor), - SuperSpeedPlusCompanion(usb::SuperSpeedPlusIsochCmpDescriptor), -} - -impl AnyDescriptor { - fn parse(bytes: &[u8]) -> Option<(Self, usize)> { - if bytes.len() < 2 { - return None; - } - - let len = bytes[0]; - let kind = bytes[1]; - - if bytes.len() < len.into() { - return None; - } - - Some(( - match kind { - 1 => Self::Device(*plain::from_bytes(bytes).ok()?), - 2 => Self::Config(*plain::from_bytes(bytes).ok()?), - 4 => Self::Interface(*plain::from_bytes(bytes).ok()?), - 5 => Self::Endpoint(*plain::from_bytes(bytes).ok()?), - 33 => Self::Hid(*plain::from_bytes(bytes).ok()?), - 48 => Self::SuperSpeedCompanion(*plain::from_bytes(bytes).ok()?), - 49 => Self::SuperSpeedPlusCompanion(*plain::from_bytes(bytes).ok()?), - _ => { - //panic!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes); - return None; - } - }, - len.into(), - )) - } -} - -impl Xhci { - async fn new_if_desc( - &self, - port_id: PortId, - slot: u8, - desc: usb::InterfaceDescriptor, - endps: impl IntoIterator, - hid_descs: impl IntoIterator, - lang_id: u16, - ) -> Result { - Ok(IfDesc { - alternate_setting: desc.alternate_setting, - class: desc.class, - interface_str: if desc.interface_str > 0 { - Some( - self.fetch_string_desc(port_id, slot, desc.interface_str, lang_id) - .await?, - ) - } else { - None - }, - kind: desc.kind, - number: desc.number, - protocol: desc.protocol, - sub_class: desc.sub_class, - endpoints: endps.into_iter().collect(), - hid_descs: hid_descs.into_iter().collect(), - }) - } - /// Pushes a command TRB to the command ring, rings the doorbell, and then awaits its Command - /// Completion Event. - /// - /// # Locking - /// This function will lock `Xhci::cmd` and `Xhci::dbs`. - pub async fn execute_command(&self, f: F) -> (Trb, Trb) { - //TODO: find out why this bit is set earlier! - if self.interrupt_is_pending(0) { - debug!("The EHB bit is already set!"); - //self.force_clear_interrupt(0); - } - - let next_event = { - let mut command_ring = self.cmd.lock().unwrap(); - let (cmd_index, cycle) = (command_ring.next_index(), command_ring.cycle); - - debug!("Sending command with cycle bit {}", cycle as u8); - - { - let command_trb = &mut command_ring.trbs[cmd_index]; - f(command_trb, cycle); - } - - // get the future here before awaiting, to destroy the lock before deadlock - let command_trb = &command_ring.trbs[cmd_index]; - self.next_command_completion_event_trb( - &*command_ring, - command_trb, - EventDoorbell::new(self, 0, 0), - ) - }; - - let trbs = next_event.await; - let event_trb = trbs.event_trb; - let command_trb = trbs.src_trb.expect("Command completion event TRBs shall always have a valid pointer to a valid source command TRB"); - - assert_eq!( - event_trb.trb_type(), - TrbType::CommandCompletion as u8, - "The IRQ reactor (or the xHC) gave an invalid event TRB" - ); - - (event_trb, command_trb) - } - pub async fn execute_control_transfer( - &self, - port_num: PortId, - setup: usb::Setup, - tk: TransferKind, - name: &str, - mut d: D, - ) -> Result - where - D: FnMut(&mut Trb, bool) -> ControlFlow, - { - let future = { - let mut port_state = self.port_state_mut(port_num)?; - let slot = port_state.slot; - - let mut endpoint_state = port_state - .endpoint_states - .get_mut(&0) - .ok_or(Error::new(EIO))?; - - let ring = endpoint_state.ring().ok_or(Error::new(EIO))?; - - let first_index = ring.next_index(); - let (cmd, cycle) = (&mut ring.trbs[first_index], ring.cycle); - cmd.setup(setup, tk, cycle); - - if tk != TransferKind::NoData { - loop { - let (trb, cycle) = ring.next(); - match d(trb, cycle) { - ControlFlow::Break => break, - ControlFlow::Continue => continue, - } - } - } - - let last_index = ring.next_index(); - let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle); - - let interrupter = 0; - // When the data stage is in, the status stage must be out - let input = tk != TransferKind::In; - let ioc = true; - let ch = false; - let ent = false; - cmd.status(interrupter, input, ioc, ch, ent, cycle); - - self.next_transfer_event_trb( - RingId::default_control_pipe(port_num), - ring, - &ring.trbs[first_index], - &ring.trbs[last_index], - EventDoorbell::new(self, usize::from(slot), Self::def_control_endp_doorbell()), - ) - }; - - let trbs = future.await; - let event_trb = trbs.event_trb; - let status_trb = trbs.src_trb.ok_or(Error::new(EIO))?; - - handle_transfer_event_trb("CONTROL_TRANSFER", &event_trb, &status_trb)?; - - //self.event_handler_finished(); - - Ok(event_trb) - } - /// NOTE: There has to be AT LEAST one successful invocation of `d`, that actually updates the - /// TRB (it could be a NO-OP in the worst case). - /// The function is also required to set the Interrupt on Completion flag, or this function - /// will never complete. - pub async fn execute_transfer( - &self, - port_num: PortId, - endp_num: u8, - stream_id: u16, - name: &str, - mut d: D, - ) -> Result - where - D: FnMut(&mut Trb, bool) -> ControlFlow, - { - let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?; - let mut port_state = self.port_state_mut(port_num)?; - - let slot = port_state.slot; - - let (doorbell_data_stream, doorbell_data_no_stream) = { - let endp_desc = port_state - .get_endp_desc(endp_idx) - .ok_or(Error::new(EBADFD))?; - - //TODO: clean this up - ( - Self::endp_doorbell(endp_num, endp_desc, stream_id), - Self::endp_doorbell(endp_num, endp_desc, 0), - ) - }; - - let endp_state = port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADF))?; - - let (has_streams, ring) = match endp_state { - EndpointState { - transfer: super::RingOrStreams::Ring(ref mut ring), - .. - } => (false, ring), - EndpointState { - transfer: super::RingOrStreams::Streams(stream_ctx_array), - .. - } => ( - true, - stream_ctx_array - .rings - .get_mut(&1) - .ok_or(Error::new(EBADF))?, - ), - }; - - let future = loop { - let last_index = ring.next_index(); - let (trb, cycle) = (&mut ring.trbs[last_index], ring.cycle); - - match d(trb, cycle) { - ControlFlow::Break => { - break self.next_transfer_event_trb( - super::irq_reactor::RingId { - port: port_num, - endpoint_num: endp_num, - stream_id, - }, - ring, - //TODO: find first TRB - &ring.trbs[last_index], - &ring.trbs[last_index], - EventDoorbell::new( - self, - usize::from(slot), - if has_streams { - doorbell_data_stream - } else { - doorbell_data_no_stream - }, - ), - ); - } - ControlFlow::Continue => continue, - } - }; - - drop(port_state); - - let trbs = future.await; - let event_trb = trbs.event_trb; - let transfer_trb = trbs.src_trb.ok_or(Error::new(EIO))?; - - handle_transfer_event_trb("EXECUTE_TRANSFER", &event_trb, &transfer_trb)?; - - // FIXME: EDTLA if event data was set - if event_trb.completion_code() != TrbCompletionCode::ShortPacket as u8 - && event_trb.transfer_length() != 0 - { - error!("Event trb didn't yield a short packet, but some bytes were not transferred"); - return Err(Error::new(EIO)); - } - - // TODO: Handle event data - trace!("EVENT DATA: {:?}", event_trb.event_data()); - - Ok(event_trb) - } - async fn device_req_no_data(&self, port: PortId, req: usb::Setup) -> Result<()> { - trace!("DEVICE_REQ_NO_DATA port {}, req: {:?}", port, req); - - self.execute_control_transfer( - port, - req, - TransferKind::NoData, - "DEVICE_REQ_NO_DATA", - |_, _| ControlFlow::Break, - ) - .await?; - Ok(()) - } - - async fn set_configuration(&self, port: PortId, config: u8) -> Result<()> { - debug!("Setting configuration value {} to port {}", config, port); - self.device_req_no_data(port, usb::Setup::set_configuration(config)) - .await - } - - async fn set_interface( - &self, - port: PortId, - interface_num: u8, - alternate_setting: u8, - ) -> Result<()> { - debug!( - "Setting interface value {} (alternate setting {}) to port {}", - interface_num, alternate_setting, port - ); - self.device_req_no_data( - port, - usb::Setup::set_interface(interface_num, alternate_setting), - ) - .await - } - - async fn reset_endpoint(&self, port_num: PortId, endp_num: u8, tsp: bool) -> Result<()> { - let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?; - let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; - - let endp_desc = port_state - .get_endp_desc(endp_idx) - .ok_or(Error::new(EBADFD))?; - let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); - - let slot = self - .port_states - .get(&port_num) - .ok_or(Error::new(EBADF))? - .slot; - - let (event_trb, command_trb) = self - .execute_command(|trb, cycle| { - trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle); - }) - .await; - //self.event_handler_finished(); - - handle_event_trb("RESET_ENDPOINT", &event_trb, &command_trb) - } - - fn endp_ctx_interval(speed_id: &ProtocolSpeed, endp_desc: &EndpDesc) -> u8 { - /// Logarithmic (base 2) 125 µs periods per millisecond. - const MILLISEC_PERIODS: u8 = 3; - - // TODO: Also check the Speed ID for superspeed(plus). - if (speed_id.is_lowspeed() || speed_id.is_fullspeed()) && endp_desc.is_interrupt() { - // The interval field has values 1-255, ranging from 1 ms to 255 ms. - // TODO: This is correct, right? - let last_power_of_two = 8 - endp_desc.interval.leading_zeros() as u8; - last_power_of_two - 1 + MILLISEC_PERIODS - } else if speed_id.is_fullspeed() && endp_desc.is_isoch() { - // bInterval has values 1-16, ranging from 1 ms to 32,768 ms. - endp_desc.interval - 1 + MILLISEC_PERIODS - } else if (speed_id.is_fullspeed() - || endp_desc.is_superspeed() - || endp_desc.is_superspeedplus()) - && (endp_desc.is_interrupt() || endp_desc.is_isoch()) - { - // bInterval has values 1-16, but ranging from 125 µs to 4096 ms. - endp_desc.interval - 1 - } else { - // This includes superspeed(plus) control and bulk endpoints in particular. - 0 - } - } - fn endp_ctx_max_burst( - speed_id: &ProtocolSpeed, - dev_desc: &DevDesc, - endp_desc: &EndpDesc, - ) -> u8 { - if speed_id.is_highspeed() && (endp_desc.is_interrupt() || endp_desc.is_isoch()) { - assert_eq!(dev_desc.major_version(), 2); - ((endp_desc.max_packet_size & 0x0C00) >> 11) as u8 - } else if endp_desc.is_superspeed() { - endp_desc.max_burst() - } else { - 0 - } - } - fn endp_ctx_max_packet_size(endp_desc: &EndpDesc) -> u16 { - // TODO: Control endpoint? Encoding? - endp_desc.max_packet_size & 0x07FF - } - fn endp_ctx_max_esit_payload( - speed_id: &ProtocolSpeed, - dev_desc: &DevDesc, - endp_desc: &EndpDesc, - max_packet_size: u16, - max_burst_size: u8, - ) -> u32 { - const KIB: u32 = 1024; - - if dev_desc.major_version() == 2 && endp_desc.is_periodic() { - u32::from(max_packet_size) * (u32::from(max_burst_size) + 1) - } else if endp_desc.has_ssp_companion() { - endp_desc.sspc.as_ref().unwrap().bytes_per_interval - } else if endp_desc.ssc.is_some() { - u32::from(endp_desc.ssc.as_ref().unwrap().bytes_per_interval) - } else if speed_id.is_fullspeed() && endp_desc.is_interrupt() { - 64 - } else if speed_id.is_fullspeed() && endp_desc.is_isoch() { - 1 * KIB - } else if (speed_id.is_highspeed() && (endp_desc.is_interrupt() || endp_desc.is_isoch())) - || endp_desc.is_superspeed() && endp_desc.is_interrupt() - { - 3 * KIB - } else if endp_desc.is_superspeed() && endp_desc.is_isoch() { - 48 * KIB - } else { - // TODO: Is "maximum allowed" ESIT payload, the same as "maximum" ESIT payload. - 0 - } - } - - fn port_state( - &self, - port: PortId, - ) -> Result>> { - self.port_states.get(&port).ok_or(Error::new(EBADF)) - } - fn port_state_mut( - &self, - port: PortId, - ) -> Result>> { - self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) - } - - async fn configure_endpoints_once( - &self, - port: PortId, - req: &ConfigureEndpointsReq, - ) -> Result<()> { - let (endp_desc_count, new_context_entries, configuration_value) = { - let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; - - port_state.cfg_idx = Some(req.config_desc); - - let config_desc = port_state - .dev_desc - .as_ref() - .unwrap() - .config_descs - .iter() - .find(|desc| desc.configuration_value == req.config_desc) - .ok_or(Error::new(EBADFD))?; - - //TODO: USE ENDPOINTS FROM ALL INTERFACES - let mut endp_desc_count = 0; - let mut new_context_entries = 1; - for if_desc in config_desc.interface_descs.iter() { - for endpoint in if_desc.endpoints.iter() { - endp_desc_count += 1; - let entry = Self::endp_num_to_dci(endp_desc_count, endpoint); - if entry > new_context_entries { - new_context_entries = entry; - } - } - } - new_context_entries += 1; - - if endp_desc_count >= 31 { - warn!("endpoints length {} >= 31", endp_desc_count); - return Err(Error::new(EIO)); - } - - ( - endp_desc_count, - new_context_entries, - config_desc.configuration_value, - ) - }; - let lec = self.cap.lec(); - let log_max_psa_size = self.cap.max_psa_size(); - - let port_speed_id = self.ports.lock().unwrap()[port.root_hub_port_index()].speed(); - let speed_id: &ProtocolSpeed = self.lookup_psiv(port, port_speed_id).ok_or_else(|| { - warn!("no speed_id"); - Error::new(EIO) - })?; - - { - let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let mut input_context = port_state.input_context.lock().unwrap(); - - // Configure the slot context as well, which holds the last index of the endp descs. - input_context.add_context.write(1); - input_context.drop_context.write(0); - - const CONTEXT_ENTRIES_MASK: u32 = 0xF800_0000; - const CONTEXT_ENTRIES_SHIFT: u8 = 27; - - const HUB_PORTS_MASK: u32 = 0xFF00_0000; - const HUB_PORTS_SHIFT: u8 = 24; - - let mut current_slot_a = input_context.device.slot.a.read(); - let mut current_slot_b = input_context.device.slot.b.read(); - - // Set context entries - current_slot_a &= !CONTEXT_ENTRIES_MASK; - current_slot_a |= - (u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT) & CONTEXT_ENTRIES_MASK; - - // Set hub data - current_slot_a &= !(1 << 26); - current_slot_b &= !HUB_PORTS_MASK; - if let Some(hub_ports) = req.hub_ports { - current_slot_a |= 1 << 26; - current_slot_b |= (u32::from(hub_ports) << HUB_PORTS_SHIFT) & HUB_PORTS_MASK; - } - - input_context.device.slot.a.write(current_slot_a); - input_context.device.slot.b.write(current_slot_b); - - let control = if self.op.lock().unwrap().cie() { - (u32::from(req.alternate_setting.unwrap_or(0)) << 16) - | (u32::from(req.interface_desc.unwrap_or(0)) << 8) - | u32::from(configuration_value) - } else { - 0 - }; - input_context.control.write(control); - } - - for endp_idx in 0..endp_desc_count as u8 { - let endp_num = endp_idx + 1; - - let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; - let dev_desc = port_state.dev_desc.as_ref().unwrap(); - let endp_desc = port_state.get_endp_desc(endp_idx).ok_or_else(|| { - warn!("failed to find endpoint {}", endp_idx); - Error::new(EIO) - })?; - - let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); - - let usb_log_max_streams = endp_desc.log_max_streams(); - - // TODO: Secondary streams. - let primary_streams = if let Some(log_max_streams) = usb_log_max_streams { - // TODO: Can streams-capable be configured to not use streams? - if log_max_psa_size != 0 { - cmp::min(u8::from(log_max_streams), log_max_psa_size + 1) - 1 - } else { - 0 - } - } else { - 0 - }; - let linear_stream_array = if primary_streams != 0 { true } else { false }; - - // TODO: Interval related fields - // TODO: Max ESIT payload size. - - let mult = endp_desc.isoch_mult(lec); - - let max_packet_size = Self::endp_ctx_max_packet_size(endp_desc); - let max_burst_size = Self::endp_ctx_max_burst(speed_id, dev_desc, endp_desc); - - let max_esit_payload = Self::endp_ctx_max_esit_payload( - speed_id, - dev_desc, - endp_desc, - max_packet_size, - max_burst_size, - ); - let max_esit_payload_lo = max_esit_payload as u16; - let max_esit_payload_hi = ((max_esit_payload & 0x00FF_0000) >> 16) as u8; - - let interval = Self::endp_ctx_interval(speed_id, endp_desc); - - let max_error_count = 3; - let ep_ty = endp_desc.xhci_ep_type()?; - let host_initiate_disable = false; - - // TODO: Maybe this value is out of scope for xhcid, because the actual usb device - // driver probably knows better. The spec says that the initial value should be 8 bytes - // for control, 1KiB for interrupt and 3KiB for bulk and isoch. - let avg_trb_len: u16 = match endp_desc.ty() { - EndpointTy::Ctrl => { - warn!("trying to use control endpoint"); - return Err(Error::new(EIO)); // only endpoint zero is of type control, and is configured separately with the address device command. - } - EndpointTy::Bulk | EndpointTy::Isoch => 3072, // 3 KiB - EndpointTy::Interrupt => 1024, // 1 KiB - }; - - assert_eq!(ep_ty & 0x7, ep_ty); - assert_eq!(mult & 0x3, mult); - assert_eq!(max_error_count & 0x3, max_error_count); - assert_ne!(ep_ty, 0); // 0 means invalid. - - let ring_ptr = if usb_log_max_streams.is_some() { - let mut array = - StreamContextArray::new::(self.cap.ac64(), 1 << (primary_streams + 1))?; - - // TODO: Use as many stream rings as needed. - array.add_ring::(self.cap.ac64(), 1, true)?; - let array_ptr = array.register(); - - assert_eq!( - array_ptr & 0xFFFF_FFFF_FFFF_FF81, - array_ptr, - "stream ctx ptr not aligned to 16 bytes" - ); - port_state.endpoint_states.insert( - endp_num, - EndpointState { - transfer: super::RingOrStreams::Streams(array), - driver_if_state: EndpIfState::Init, - }, - ); - - array_ptr - } else { - let ring = Ring::new::(self.cap.ac64(), 16, true)?; - let ring_ptr = ring.register(); - - assert_eq!( - ring_ptr & 0xFFFF_FFFF_FFFF_FF81, - ring_ptr, - "ring pointer not aligned to 16 bytes" - ); - port_state.endpoint_states.insert( - endp_num, - EndpointState { - transfer: super::RingOrStreams::Ring(ring), - driver_if_state: EndpIfState::Init, - }, - ); - ring_ptr - }; - assert_eq!(primary_streams & 0x1F, primary_streams); - - let mut input_context = port_state.input_context.lock().unwrap(); - input_context.add_context.writef(1 << endp_num_xhc, true); - - let endp_i = endp_num_xhc as usize - 1; - input_context.device.endpoints[endp_i].a.write( - u32::from(mult) << 8 - | u32::from(primary_streams) << 10 - | u32::from(linear_stream_array) << 15 - | u32::from(interval) << 16 - | u32::from(max_esit_payload_hi) << 24, - ); - input_context.device.endpoints[endp_i].b.write( - max_error_count << 1 - | u32::from(ep_ty) << 3 - | u32::from(host_initiate_disable) << 7 - | u32::from(max_burst_size) << 8 - | u32::from(max_packet_size) << 16, - ); - - input_context.device.endpoints[endp_i] - .trl - .write(ring_ptr as u32); - input_context.device.endpoints[endp_i] - .trh - .write((ring_ptr >> 32) as u32); - - input_context.device.endpoints[endp_i] - .c - .write(u32::from(avg_trb_len) | (u32::from(max_esit_payload_lo) << 16)); - - log::debug!("initialized endpoint {}", endp_num); - } - - { - let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let slot = port_state.slot; - let input_context_physical = port_state.input_context.lock().unwrap().physical(); - - let (event_trb, command_trb) = self - .execute_command(|trb, cycle| { - trb.configure_endpoint(slot, input_context_physical, cycle) - }) - .await; - - //self.event_handler_finished(); - - handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; - } - - // Tell the device about this configuration. - self.set_configuration(port, configuration_value).await?; - - Ok(()) - } - - async fn configure_endpoints(&self, port: PortId, json_buf: &[u8]) -> Result<()> { - let mut req: ConfigureEndpointsReq = - serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; - - debug!( - "Running configure endpoints command, at port {}, request: {:?}", - port, req - ); - - if req.interface_desc.is_some() != req.alternate_setting.is_some() { - return Err(Error::new(EBADMSG)); - } - - let already_configured = { - let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - port_state.cfg_idx == Some(req.config_desc) - }; - - if !already_configured { - self.configure_endpoints_once(port, &req).await?; - } - - if let Some(interface_num) = req.interface_desc { - if let Some(alternate_setting) = req.alternate_setting { - self.set_interface(port, interface_num, alternate_setting) - .await?; - } - } - - Ok(()) - } - async fn transfer_read( - &self, - port_num: PortId, - endp_idx: u8, - buf: &mut [u8], - ) -> Result<(u8, u32)> { - if buf.is_empty() { - return Err(Error::new(EINVAL)); - } - let dma_buffer = unsafe { self.alloc_dma_zeroed_unsized(buf.len())? }; - - let (completion_code, bytes_transferred, dma_buffer) = self - .transfer( - port_num, - endp_idx, - Some(dma_buffer), - PortReqDirection::DeviceToHost, - ) - .await?; - - buf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); - Ok((completion_code, bytes_transferred)) - } - async fn transfer_write( - &self, - port_num: PortId, - endp_idx: u8, - sbuf: &[u8], - ) -> Result<(u8, u32)> { - if sbuf.is_empty() { - return Err(Error::new(EINVAL)); - } - let mut dma_buffer = unsafe { self.alloc_dma_zeroed_unsized(sbuf.len()) }?; - dma_buffer.copy_from_slice(sbuf); - - trace!( - "TRANSFER_WRITE port {} ep {}, buffer at {:p}, size {}, dma buffer {:?}", - port_num, - endp_idx + 1, - sbuf.as_ptr(), - sbuf.len(), - DmaSliceDbg(&dma_buffer) - ); - - let (completion_code, bytes_transferred, _) = self - .transfer( - port_num, - endp_idx, - Some(dma_buffer), - PortReqDirection::HostToDevice, - ) - .await?; - Ok((completion_code, bytes_transferred)) - } - pub const fn def_control_endp_doorbell() -> u32 { - 1 - } - // TODO: Wrap DCIs and driver-level endp_num into distinct types, due to the high chance of - // mixing the two up. - fn endp_num_to_dci(endp_num: u8, desc: &EndpDesc) -> u8 { - if endp_num == 0 { - unreachable!("EndpDesc cannot be obtained from the default control endpoint") - } - - if desc.is_control() || desc.direction() == EndpDirection::In { - endp_num * 2 + 1 - } else if desc.direction() == EndpDirection::Out { - endp_num * 2 - } else { - unreachable!() - } - } - fn endp_doorbell(endp_num: u8, desc: &EndpDesc, stream_id: u16) -> u32 { - let db_target = Self::endp_num_to_dci(endp_num, desc); - let db_task_id: u16 = stream_id; - - (u32::from(db_task_id) << 16) | u32::from(db_target) - } - // TODO: Rename DeviceReqData to something more general. - async fn transfer( - &self, - port_num: PortId, - endp_idx: u8, - dma_buf: Option>, - direction: PortReqDirection, - ) -> Result<(u8, u32, Option>)> { - // TODO: Check that only readable enpoints are read, etc. - let endp_num = endp_idx + 1; - - let mut port_state = self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(EBADFD))?; - - let endp_desc: &EndpDesc = port_state - .get_endp_desc(endp_idx) - .ok_or(Error::new(EBADFD))?; - - let direction = endp_desc.direction(); - - if endp_desc.is_isoch() { - return Err(Error::new(ENOSYS)); - } - - if EndpDirection::from(direction) != endp_desc.direction() { - return Err(Error::new(EBADF)); - } - - let max_packet_size = endp_desc.max_packet_size; - let max_transfer_size = 65536u32; - - let (buffer, idt, estimated_td_size) = { - let (buffer, idt) = if dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0) <= 8 - && max_packet_size >= 8 - && direction != EndpDirection::In - { - dma_buf - .as_ref() - .map(|sbuf| { - let mut bytes = [0u8; 8]; - bytes[..sbuf.len()].copy_from_slice(&sbuf); - (u64::from_le_bytes(bytes), true) - }) - .unwrap_or((0, false)) - } else { - ( - dma_buf.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, - false, - ) - }; - let estimated_td_size = cmp::min( - u8::try_from( - div_round_up( - dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0), - max_transfer_size as usize, - ) * mem::size_of::(), - ) - .ok() - .unwrap_or(0x1F), - 0x1F, - ); // one trb per td - (buffer, idt, estimated_td_size) - }; - - let stream_id = 1u16; - - let mut bytes_left = dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0); - - drop(port_state); - - let event = self - .execute_transfer( - port_num, - endp_num, - stream_id, - "CUSTOM_TRANSFER", - |trb, cycle| { - let len = cmp::min(bytes_left, max_transfer_size as usize) as u32; - - // set the interrupt on completion (IOC) flag for the last trb. - let ioc = bytes_left <= max_transfer_size as usize; - let chain = !ioc; - - let interrupter = 0; - let ent = false; - let isp = true; - let bei = false; - trb.normal( - buffer, - len, - cycle, - estimated_td_size, - interrupter, - ent, - isp, - chain, - ioc, - idt, - bei, - ); - - bytes_left -= len as usize; - - if bytes_left != 0 { - ControlFlow::Continue - } else { - ControlFlow::Break - } - }, - ) - .await?; - //self.event_handler_finished(); - - let bytes_transferred = dma_buf - .as_ref() - .map(|buf| buf.len() as u32 - event.transfer_length()) - .unwrap_or(0); - - Ok((event.completion_code(), bytes_transferred, dma_buf)) - } - pub async fn get_desc(&self, port_id: PortId, slot: u8) -> Result { - let ports = self.ports.lock().unwrap(); - let port = ports - .get(port_id.root_hub_port_index()) - .ok_or(Error::new(ENOENT))?; - if !port.flags().contains(port::PortFlags::CCS) { - return Err(Error::new(ENOENT)); - } - - let raw_dd = self.fetch_dev_desc(port_id, slot).await?; - log::debug!("port {} slot {} desc {:X?}", port_id, slot, raw_dd); - - // Only fetch language IDs if we need to. Some devices will fail to return this descriptor - //TODO: also check configurations and interfaces for defined strings? - let lang_id = - if raw_dd.manufacturer_str > 0 || raw_dd.product_str > 0 || raw_dd.serial_str > 0 { - let lang_ids = self.fetch_lang_ids_desc(port_id, slot).await?; - // Prefer US English, but fall back to first language ID, or zero - let en_us_id = 0x409; - if lang_ids.contains(&en_us_id) { - en_us_id - } else { - match lang_ids.first() { - Some(some) => *some, - None => 0, - } - } - } else { - 0 - }; - log::debug!("port {} using language ID 0x{:04x}", port_id, lang_id); - - let (manufacturer_str, product_str, serial_str) = ( - if raw_dd.manufacturer_str > 0 { - Some( - self.fetch_string_desc(port_id, slot, raw_dd.manufacturer_str, lang_id) - .await?, - ) - } else { - None - }, - if raw_dd.product_str > 0 { - Some( - self.fetch_string_desc(port_id, slot, raw_dd.product_str, lang_id) - .await?, - ) - } else { - None - }, - if raw_dd.serial_str > 0 { - Some( - self.fetch_string_desc(port_id, slot, raw_dd.serial_str, lang_id) - .await?, - ) - } else { - None - }, - ); - log::debug!( - "manufacturer {:?} product {:?} serial {:?}", - manufacturer_str, - product_str, - serial_str - ); - - //TODO let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot).await?; - - let supports_superspeed = false; - //TODO usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); - let supports_superspeedplus = false; - //TODO usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus()); - - let mut config_descs = SmallVec::new(); - - for index in 0..raw_dd.configurations { - debug!("Fetching the config descriptor at index {}", index); - let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?; - log::debug!( - "port {} slot {} config {} desc {:X?}", - port_id, - slot, - index, - desc - ); - - let extra_length = desc.total_length as usize - mem::size_of_val(&desc); - let data = &data[..extra_length]; - - let mut i = 0; - let mut descriptors = Vec::new(); - - while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) { - descriptors.push(descriptor); - i += len; - } - - let mut interface_descs = SmallVec::new(); - let mut iter = descriptors.into_iter().peekable(); - - while let Some(item) = iter.next() { - if let AnyDescriptor::Interface(idesc) = item { - let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); - let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); - - while endpoints.len() < idesc.endpoints as usize { - let next = match iter.next() { - Some(AnyDescriptor::Endpoint(n)) => n, - Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { - hid_descs.push(h.into()); - continue; - } - Some(unexpected) => { - log::warn!("expected endpoint, got {:X?}", unexpected); - break; - } - None => break, - }; - let mut endp = EndpDesc::from(next); - - loop { - match iter.peek() { - Some(AnyDescriptor::SuperSpeedCompanion(n)) => { - endp.ssc = Some(SuperSpeedCmp::from(n.clone())); - iter.next().unwrap(); - } - Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => { - endp.sspc = Some(SuperSpeedPlusIsochCmp::from(n.clone())); - iter.next().unwrap(); - } - _ => break, - } - } - - endpoints.push(endp); - } - - interface_descs.push( - self.new_if_desc(port_id, slot, idesc, endpoints, hid_descs, lang_id) - .await?, - ); - } else { - log::warn!("expected interface, got {:?}", item); - // TODO - //break; - } - } - - config_descs.push(ConfDesc { - kind: desc.kind, - configuration: if desc.configuration_str > 0 { - Some( - self.fetch_string_desc(port_id, slot, desc.configuration_str, lang_id) - .await?, - ) - } else { - None - }, - configuration_value: desc.configuration_value, - attributes: desc.attributes, - max_power: desc.max_power, - interface_descs, - }); - } - - Ok(DevDesc { - kind: raw_dd.kind, - usb: raw_dd.usb, - class: raw_dd.class, - sub_class: raw_dd.sub_class, - protocol: raw_dd.protocol, - packet_size: raw_dd.packet_size, - vendor: raw_dd.vendor, - product: raw_dd.product, - release: raw_dd.release, - manufacturer_str, - product_str, - serial_str, - config_descs, - }) - } - fn port_desc_json(&self, port_id: PortId) -> Result> { - let dev_desc = &self - .port_states - .get(&port_id) - .ok_or(Error::new(ENOENT))? - .dev_desc; - serde_json::to_vec(dev_desc).or(Err(Error::new(EIO))) - } - fn write_dyn_string(string: &[u8], buf: &mut [u8], offset: usize) -> usize { - let max_bytes_to_read = cmp::min(string.len(), buf.len()); - let bytes_to_read = cmp::max(offset, max_bytes_to_read) - offset; - buf[..bytes_to_read].copy_from_slice(&string[..bytes_to_read]); - - bytes_to_read - } - async fn port_req_transfer( - &self, - port_num: PortId, - data_buffer: Option<&mut Dma<[u8]>>, - setup: usb::Setup, - transfer_kind: TransferKind, - ) -> Result<()> { - self.execute_control_transfer( - port_num, - setup, - transfer_kind, - "CUSTOM_DEVICE_REQ", - |trb, cycle| { - trb.data( - data_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0), - setup.length, - transfer_kind == TransferKind::In, - cycle, - ); - ControlFlow::Break - }, - ) - .await?; - Ok(()) - } - fn port_req_init_st(&self, port_num: PortId, req: &PortReq) -> Result { - use usb::setup::*; - - let direction = ReqDirection::from(req.direction); - let ty = ReqType::from(req.req_type) as u8; - let recipient = ReqRecipient::from(req.req_recipient) as u8; - - let transfer_kind = match direction { - _ if !req.transfers_data => TransferKind::NoData, - ReqDirection::DeviceToHost => TransferKind::In, - ReqDirection::HostToDevice => TransferKind::Out, - }; - - let setup = Setup { - kind: ((direction as u8) << USB_SETUP_DIR_SHIFT) - | (ty << USB_SETUP_REQ_TY_SHIFT) - | (recipient << USB_SETUP_RECIPIENT_SHIFT), - request: req.request, - value: req.value, - index: req.index, - length: req.length, - }; - // TODO: Reuse buffers, or something. - // TODO: Validate the size. - // TODO: Sizes above 65536, *perhaps*. - let data_buffer_opt = if req.transfers_data { - let data_buffer = unsafe { self.alloc_dma_zeroed_unsized(req.length as usize)? }; - assert_eq!(data_buffer.len(), req.length as usize); - Some(data_buffer) - } else { - None - }; - - Ok(match transfer_kind { - TransferKind::In => PortReqState::WaitingForDeviceBytes( - data_buffer_opt.ok_or(Error::new(EINVAL))?, - setup, - ), - TransferKind::Out => { - PortReqState::WaitingForHostBytes(data_buffer_opt.ok_or(Error::new(EINVAL))?, setup) - } - TransferKind::NoData => PortReqState::TmpSetup(setup), - _ => unreachable!(), - }) - // FIXME: Make sure there aren't any other PortReq handles, perhaps by storing the state in - // PortState? - } - async fn handle_port_req_write( - &self, - fd: usize, - port_num: PortId, - mut st: PortReqState, - buf: &[u8], - ) -> Result { - let bytes_written = match st { - PortReqState::Init => { - let req = serde_json::from_slice::(buf).or(Err(Error::new(EBADMSG)))?; - - st = self.port_req_init_st(port_num, &req)?; - - if let PortReqState::TmpSetup(setup) = st { - // No need for any additional reads or writes, before completing. - self.port_req_transfer(port_num, None, setup, TransferKind::NoData) - .await?; - st = PortReqState::Init; - } - - buf.len() - } - PortReqState::WaitingForHostBytes(mut dma_buffer, setup) => { - if buf.len() != dma_buffer.len() { - return Err(Error::new(EINVAL)); - } - dma_buffer.copy_from_slice(buf); - - self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::Out) - .await?; - st = PortReqState::Init; - - buf.len() - } - PortReqState::WaitingForDeviceBytes(_, _) => return Err(Error::new(EBADF)), - PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), - }; - let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; - match &mut *guard { - Handle::PortReq(_, ref mut state) => *state = st, - _ => unreachable!(), - } - Ok(bytes_written) - } - async fn handle_port_req_read( - &self, - fd: usize, - port_num: PortId, - mut st: PortReqState, - buf: &mut [u8], - ) -> Result { - let bytes_read = match st { - PortReqState::WaitingForDeviceBytes(mut dma_buffer, setup) => { - if buf.len() != dma_buffer.len() { - return Err(Error::new(EINVAL)); - } - self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::In) - .await?; - buf.copy_from_slice(&dma_buffer); - - st = PortReqState::Init; - - buf.len() - } - PortReqState::Init | PortReqState::WaitingForHostBytes(_, _) => { - return Err(Error::new(EBADF)) - } - PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), - }; - - let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; - match &mut *guard { - Handle::PortReq(_, ref mut state) => *state = st, - _ => unreachable!(), - } - Ok(bytes_read) - } - - /// Implements open() for the root level scheme - /// - /// # Arguments - /// - 'flags: [usize]' - The flags parameter passed to open() - /// - /// # Returns - /// This function returns a [Result] containing either - /// - /// - Handle::TopLevel - The file was opened. - /// - EISDIR - This is a directory endpoint, but neither O_DIRECTORY nor O_STAT were passed. - /// - fn open_handle_top_level(&self, flags: usize) -> Result { - if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { - let mut contents = Vec::new(); - - let ports_guard = self.ports.lock().unwrap(); - - for (index, _) in ports_guard - .iter() - .enumerate() - .filter(|(_, port)| port.flags().contains(port::PortFlags::CCS)) - { - write!(contents, "port{}\n", index).unwrap(); - } - - Ok(Handle::TopLevel(contents)) - } else { - Err(Error::new(EISDIR)) - } - } - - /// implements open() for /port/descriptors - /// - /// # Arguments - /// - 'port_num: [PortId]' - The port number specified in the scheme path - /// - 'flags: [usize]' - The flags parameter passed to open() - /// - /// # Returns - /// This function returns a [Result] containing either: - /// - /// - [Handle::PortDesc] - The handle was opened successfully - /// - [ENOTDIR] - Directory-specific flags were passed to open(), but this endpoint is not a directory. - fn open_handle_port_descriptors(&self, port_num: PortId, flags: usize) -> Result { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - - let contents = self.port_desc_json(port_num)?; - Ok(Handle::PortDesc(port_num, contents)) - } - - /// implements open() for /port - /// - /// # Arguments - /// - 'port_num: [PortId]' - The port number specified in the scheme path - /// - 'flags: [usize]' - The flags parameter passed to open() - /// - /// # Returns - /// This function returns a [Result] containing either: - /// - /// - [Handle::Port] - The handle was opened successfully - /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num - /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open - fn open_handle_port(&self, port_num: PortId, flags: usize) -> Result { - // The != here is unintuitive. You would assume that you could do - // flags & O_DIRECTORY || flags & O_STAT, but rust doesn't allow - // you to cast integers to booleans. - if (flags & O_DIRECTORY != 0) || (flags & O_STAT != 0) { - let mut contents = Vec::new(); - - write!(contents, "descriptors\nendpoints\n").unwrap(); - - if self.slot_state( - self.port_states - .get(&port_num) - .ok_or(Error::new(ENOENT))? - .slot as usize, - ) != SlotState::Configured as u8 - { - write!(contents, "configure\n").unwrap(); - } - - Ok(Handle::Port(port_num, contents)) - } else { - Err(Error::new(EISDIR)) - } - } - - /// implements open() for /port/state - /// - /// # Arguments - /// - 'port_num: [PortId]' - The port number specified in the scheme path - /// - 'flags: [usize]' - The flags parameter passed to open() - /// - /// # Returns - /// This function returns a [Result] containing either: - /// - /// - [Handle::Port] - The handle was opened successfully - /// - [ENOTDIR] - open() was called on this scheme endpoint, but directory-specific flags were passed to open - fn open_handle_port_state(&self, port_num: PortId, flags: usize) -> Result { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - - Ok(Handle::PortState(port_num)) - } - - /// implements open() for /port/endpoints - /// - /// # Arguments - /// - 'port_num: [PortId]' - The port number specified in the scheme path - /// - 'flags: [usize]' - The flags parameter passed to open() - /// - /// # Returns - /// This function returns a [Result] containing either: - /// - /// - [Handle::Port] - The handle was opened successfully - /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open - fn open_handle_port_endpoints(&self, port_num: PortId, flags: usize) -> Result { - if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { - return Err(Error::new(EISDIR)); - }; - let mut contents = Vec::new(); - let ps = self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?; - - /*for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { - write!(contents, "{}\n", ep_num).unwrap(); - }*/ - - for ep_num in ps.endpoint_states.keys() { - write!(contents, "{}\n", ep_num).unwrap(); - } - - Ok(Handle::Endpoints(port_num, contents)) - } - - /// implements open() for /port/endpoints/ - /// - /// # Arguments - /// - 'port_num: [PortId]' - The port number specified in the scheme path - /// - 'endpoint_num: [u8]' - The endpoint number to access - /// - 'flags: [usize]' - The flags parameter passed to open() - /// - /// # Returns - /// This function returns a [Result] containing either: - /// - /// - [Handle::Port] - The handle was opened successfully - /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open - /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num - fn open_handle_endpoint_root( - &self, - port_num: PortId, - endpoint_num: u8, - flags: usize, - ) -> Result { - if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { - return Err(Error::new(EISDIR)); - } - - let port_state = self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(ENOENT))?; - - /*if self.dev_ctx.contexts[port_state.slot as usize].endpoints.get(endpoint_num as usize).ok_or(Error::new(ENOENT))?.a.read() & 0b111 != 1 { - return Err(Error::new(ENXIO)); // TODO: Find a proper error code for "endpoint not initialized". - }*/ - - if !port_state.endpoint_states.contains_key(&endpoint_num) { - return Err(Error::new(ENOENT)); - } - let contents = "ctl\ndata\n".as_bytes().to_owned(); - - Ok(Handle::Endpoint( - port_num, - endpoint_num, - EndpointHandleTy::Root(contents), - )) - } - - /// implements open() for /port/endpoints//data and /port/endpoints//ctl - /// - /// # Arguments - /// - 'port_num: [PortId]' - The port number specified in the scheme path - /// - 'endpoint_num: [u8]' - The endpoint number to access - /// - 'handle_type: [String]' - The type of the handle - /// - 'flags: [usize]' - The flags parameter passed to open() - /// - /// # Returns - /// This function returns a [Result] containing either: - /// - /// - [Handle::Port] - The handle was opened successfully - /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open - /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num, or no endpoint with the given endpoint_num - fn open_handle_single_endpoint( - &self, - port_num: PortId, - endpoint_num: u8, - handle_type: String, - flags: usize, - ) -> Result { - match handle_type.as_str() { - "root" => self.open_handle_endpoint_root(port_num, endpoint_num, flags), - "ctl" | "data" => { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(EISDIR)); - } - - let port_state = self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?; - - if port_state.endpoint_states.get(&endpoint_num).is_none() { - return Err(Error::new(ENOENT)); - } - - let st = match handle_type.as_str() { - "ctl" => EndpointHandleTy::Ctl, - "data" => EndpointHandleTy::Data, - _ => return Err(Error::new(ENOENT)), - }; - Ok(Handle::Endpoint(port_num, endpoint_num, st)) - } - _ => panic!( - "Scheme parser returned an invalid string '{}' for the endpoint handle type", - handle_type - ), - } - } - - /// implements open() for /port/configure - /// - /// # Arguments - /// - 'port_num: [PortId]' - The port number specified in the scheme path - /// - 'endpoint_num: [u8]' - The endpoint number to access - /// - 'flags: [usize]' - The flags parameter passed to open() - /// - /// # Returns - /// This function returns a [Result] containing either: - /// - /// - [Handle::Port] - The handle was opened successfully - /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open - /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num, or no endpoint with the given endpoint_num - fn open_handle_configure_endpoints(&self, port_num: PortId, flags: usize) -> Result { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - - if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { - return Err(Error::new(EACCES)); - } - - Ok(Handle::ConfigureEndpoints(port_num)) - } - - /// implements open() for /port/attach - /// - /// # Arguments - /// - 'port_num: [PortId]' - The port number specified in the scheme path - /// - 'flags: [usize]' - The flags parameter passed to open() - /// - /// # Returns - /// This function returns a [Result] containing either: - /// - /// - [Handle::Port] - The handle was opened successfully - /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open - /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num, or no endpoint with the given endpoint_num - fn open_handle_attach_device(&self, port_num: PortId, flags: usize) -> Result { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - - if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { - return Err(Error::new(EACCES)); - } - - Ok(Handle::AttachDevice(port_num)) - } - - /// implements open() for /port/detach - /// - /// # Arguments - /// - 'port_num: [PortId]' - The port number specified in the scheme path - /// - 'flags: [usize]' - The flags parameter passed to open() - /// - /// # Returns - /// This function returns a [Result] containing either: - /// - /// - [Handle::Port] - The handle was opened successfully - /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open - /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num, or no endpoint with the given endpoint_num - fn open_handle_detach_device(&self, port_num: PortId, flags: usize) -> Result { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - - if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { - return Err(Error::new(EACCES)); - } - - Ok(Handle::DetachDevice(port_num)) - } - - /// implements open() for /port/request - /// - /// # Arguments - /// - 'port_num: [PortId]' - The port number specified in the scheme path - /// - 'flags: [usize]' - The flags parameter passed to open() - /// - /// # Returns - /// This function returns a [Result] containing either: - /// - /// - [Handle::Port] - The handle was opened successfully - /// - [ENOTDIR] - open() was called on this scheme endpoint, but directory-specific flags were passed to open - fn open_handle_port_request(&self, port_num: PortId, flags: usize) -> Result { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - - Ok(Handle::PortReq(port_num, PortReqState::Init)) - } -} - -impl SchemeSync for &Xhci { - fn scheme_root(&mut self) -> Result { - let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed); - self.handles.insert(fd, Handle::SchemeRoot); - Ok(fd) - } - fn openat( - &mut self, - dirfd: usize, - path_str: &str, - mut flags: usize, - fcntl_flags: u32, - ctx: &CallerCtx, - ) -> Result { - let full_path = match *self.handles.get(&dirfd).ok_or(Error::new(EBADF))? { - Handle::SchemeRoot => path_str.trim_start_matches('/').to_string(), - Handle::Port(port_num, _) => { - let clean_path = path_str.trim_start_matches('/'); - if clean_path.is_empty() { - format!("port{}", port_num) - } else { - format!("port{}/{}", port_num, clean_path) - } - } - _ => return Err(Error::new(EACCES)), - }; - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - - //Parse the scheme, determine if it's in the valid format, return an error if not. - //This doesn't guarantee that the parameters themselves are valid (i.e. bounded correctly) - //only that the scheme itself was parseable. - let scheme_parameters = SchemeParameters::from_scheme(&full_path)?; - - flags |= fcntl_flags as usize; - - //Once we have our scheme parsed into parameters, we can match on those parameters to - //find the correct routine to open a handle - let handle = match scheme_parameters { - SchemeParameters::TopLevel => self.open_handle_top_level(flags)?, - SchemeParameters::Port(port_number) => self.open_handle_port(port_number, flags)?, - SchemeParameters::PortDesc(port_number) => { - self.open_handle_port_descriptors(port_number, flags)? - } - SchemeParameters::PortState(port_number) => { - self.open_handle_port_state(port_number, flags)? - } - SchemeParameters::PortReq(port_number) => { - self.open_handle_port_request(port_number, flags)? - } - SchemeParameters::Endpoints(port_number) => { - self.open_handle_port_endpoints(port_number, flags)? - } - SchemeParameters::Endpoint(port_number, endpoint_number, handle_type) => { - self.open_handle_single_endpoint(port_number, endpoint_number, handle_type, flags)? - } - SchemeParameters::ConfigureEndpoints(port_number) => { - self.open_handle_configure_endpoints(port_number, flags)? - } - SchemeParameters::AttachDevice(port_number) => { - self.open_handle_attach_device(port_number, flags)? - } - SchemeParameters::DetachDevice(port_number) => { - self.open_handle_detach_device(port_number, flags)? - } - }; - - let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed); - - trace!("OPENED {} to FD={}, handle: {:?}", full_path, fd, handle); - - self.handles.insert(fd, handle); - - Ok(OpenResult::ThisScheme { - number: fd, - flags: NewFdFlags::POSITIONED, - }) - } - - fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { - let guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - stat.st_mode = match (&*guard).get_handle_type() { - HandleType::Directory => MODE_DIR, - HandleType::File => MODE_FILE, - HandleType::Character => MODE_CHR, - }; - - stat.st_size = match (&*guard).get_buf_len() { - None => stat.st_size, - Some(size) => size as u64, - }; - - //If we have a handle to the configure scheme, we need to mark it as write only. - match &*guard { - Handle::ConfigureEndpoints(_) | Handle::AttachDevice(_) | Handle::DetachDevice(_) => { - stat.st_mode = stat.st_mode | 0o200; - } - _ => {} - } - - Ok(()) - } - - fn fpath(&mut self, fd: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { - FpathWriter::with(buf, "xhci", |w| { - let handle = self.handles.get(&fd).ok_or(Error::new(EBADF))?; - write!(w, "{}", handle.to_path()).unwrap(); - Ok(()) - }) - } - - fn read( - &mut self, - fd: usize, - buf: &mut [u8], - offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - let offset = offset as usize; - let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; - trace!( - "READ fd={}, handle={:?}, buf=(addr {:p}, length {})", - fd, - guard, - buf.as_ptr(), - buf.len() - ); - match &mut *guard { - Handle::TopLevel(ref src_buf) - | Handle::Port(_, ref src_buf) - | Handle::PortDesc(_, ref src_buf) - | Handle::Endpoints(_, ref src_buf) - | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref src_buf)) => { - let max_bytes_to_read = cmp::min(src_buf.len(), buf.len()); - let bytes_to_read = cmp::max(max_bytes_to_read, offset) - offset; - - buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]); - - Ok(bytes_to_read) - } - Handle::ConfigureEndpoints(_) => Err(Error::new(EBADF)), - Handle::AttachDevice(_) => Err(Error::new(EBADF)), - Handle::DetachDevice(_) => Err(Error::new(EBADF)), - Handle::SchemeRoot => Err(Error::new(EBADF)), - - &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { - EndpointHandleTy::Ctl => self.on_read_endp_ctl(port_num, endp_num, buf), - EndpointHandleTy::Data => block_on(self.on_read_endp_data(port_num, endp_num, buf)), - EndpointHandleTy::Root(_) => Err(Error::new(EBADF)), - }, - &mut Handle::PortState(port_num) => { - let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?; - let ctx = self - .dev_ctx - .contexts - .get(ps.slot as usize) - .ok_or(Error::new(EBADF))?; - let state = ((ctx.slot.d.read() & SLOT_CONTEXT_STATE_MASK) - >> SLOT_CONTEXT_STATE_SHIFT) as u8; - - let string = match state { - 0 => Some(PortState::EnabledOrDisabled), - 1 => Some(PortState::Default), - 2 => Some(PortState::Addressed), - 3 => Some(PortState::Configured), - _ => None, - } - .as_ref() - .map(PortState::as_str) - .unwrap_or("unknown") - .as_bytes(); - - Ok(Xhci::::write_dyn_string(string, buf, offset)) - } - &mut Handle::PortReq(port_num, ref mut st) => { - let state = std::mem::replace(st, PortReqState::Tmp); - drop(guard); // release the lock - block_on(self.handle_port_req_read(fd, port_num, state, buf)) - } - } - } - fn write( - &mut self, - fd: usize, - buf: &[u8], - _offset: u64, - _fcntl_flags: u32, - _ctx: &CallerCtx, - ) -> Result { - let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; - trace!( - "WRITE fd={}, handle={:?}, buf=(addr {:p}, length {})", - fd, - guard, - buf.as_ptr(), - buf.len() - ); - - match &mut *guard { - &mut Handle::ConfigureEndpoints(port_num) => { - block_on(self.configure_endpoints(port_num, buf))?; - Ok(buf.len()) - } - &mut Handle::AttachDevice(port_num) => { - //TODO: accept some arguments in buffer? - block_on(self.attach_device(port_num))?; - Ok(buf.len()) - } - &mut Handle::DetachDevice(port_num) => { - //TODO: accept some arguments in buffer? - block_on(self.detach_device(port_num))?; - Ok(buf.len()) - } - &mut Handle::Endpoint(port_num, endp_num, ref ep_file_ty) => match ep_file_ty { - EndpointHandleTy::Ctl => block_on(self.on_write_endp_ctl(port_num, endp_num, buf)), - EndpointHandleTy::Data => { - block_on(self.on_write_endp_data(port_num, endp_num, buf)) - } - EndpointHandleTy::Root(_) => return Err(Error::new(EBADF)), - }, - &mut Handle::PortReq(port_num, ref mut st) => { - let state = std::mem::replace(st, PortReqState::Tmp); - drop(guard); // release the lock - block_on(self.handle_port_req_write(fd, port_num, state, buf)) - } - // TODO: Introduce PortReqState::Waiting, which this write call changes to - // PortReqState::ReadyToWrite when all bytes are written. - _ => Err(Error::new(EBADF)), - } - } - - fn on_close(&mut self, fd: usize) { - self.handles.remove(&fd); - } -} - -impl Xhci { - pub fn get_endp_status(&self, port_num: PortId, endp_num: u8) -> Result { - let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; - - let slot = port_state.slot; - - let endp_desc = port_state - .dev_desc - .as_ref() - .unwrap() - .config_descs - .get(0) - .ok_or(Error::new(EIO))? - .interface_descs - .get(0) - .ok_or(Error::new(EIO))? - .endpoints - .get(endp_num as usize - 1) - .ok_or(Error::new(EBADFD))?; - - let endp_num_xhc = if endp_num != 0 { - Self::endp_num_to_dci(endp_num, endp_desc) - } else { - 1 - }; - - let raw = self - .dev_ctx - .contexts - .get(slot as usize) - .ok_or(Error::new(EBADFD))? - .endpoints[endp_num_xhc as usize - 1] - .a - .read() - & super::context::ENDPOINT_CONTEXT_STATUS_MASK; - - Ok(match raw { - 0 => EndpointStatus::Disabled, - 1 => EndpointStatus::Enabled, - 2 => EndpointStatus::Halted, - 3 => EndpointStatus::Stopped, - 4 => EndpointStatus::Error, - _ => return Err(Error::new(EIO)), - }) - } - pub async fn on_req_reset_device( - &self, - port_num: PortId, - endp_num: u8, - clear_feature: bool, - ) -> Result<()> { - if self.get_endp_status(port_num, endp_num)? != EndpointStatus::Halted { - return Err(Error::new(EPROTO)); - } - // Change the endpoint state from anything, but most likely HALTED (otherwise resetting - // would be quite meaningless), to stopped. - self.reset_endpoint(port_num, endp_num, false).await?; - self.restart_endpoint(port_num, endp_num).await?; - - if clear_feature { - self.device_req_no_data( - port_num, - usb::Setup { - kind: 0b0000_0010, // endpoint recipient - request: 0x01, // CLEAR_FEATURE - value: 0x00, // ENDPOINT_HALT - index: 0, // TODO: interface num - length: 0, - }, - ) - .await?; - } - Ok(()) - } - pub async fn restart_endpoint(&self, port_num: PortId, endp_num: u8) -> Result<()> { - let mut port_state = self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(EBADFD))?; - let slot = port_state.slot; - - let mut endpoint_state = port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADFD))?; - - let (has_streams, ring) = match &mut endpoint_state.transfer { - &mut super::RingOrStreams::Ring(ref mut ring) => (false, ring), - &mut super::RingOrStreams::Streams(ref mut arr) => { - (true, arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?) - } - }; - - let (cmd, cycle) = ring.next(); - cmd.transfer_no_op(0, false, false, false, cycle); - - let deque_ptr_and_cycle = ring.register(); - - let endp_desc = port_state - .dev_desc - .as_ref() - .unwrap() - .config_descs - .get(0) - .ok_or(Error::new(EIO))? - .interface_descs - .get(0) - .ok_or(Error::new(EIO))? - .endpoints - .get(endp_num as usize - 1) - .ok_or(Error::new(EBADFD))?; - - let doorbell = if endp_num != 0 { - let stream_id = 1u16; - - Self::endp_doorbell(endp_num, endp_desc, if has_streams { stream_id } else { 0 }) - } else { - Self::def_control_endp_doorbell() - }; - - self.dbs.lock().unwrap()[slot as usize].write(doorbell); - - self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle) - .await?; - - Ok(()) - } - pub fn endp_direction(&self, port_num: PortId, endp_num: u8) -> Result { - Ok(self - .port_states - .get(&port_num) - .ok_or(Error::new(EIO))? - .dev_desc - .as_ref() - .unwrap() - .config_descs - .first() - .ok_or(Error::new(EIO))? - .interface_descs - .first() - .ok_or(Error::new(EIO))? - .endpoints - .get(endp_num as usize) - .ok_or(Error::new(EIO))? - .direction()) - } - pub fn slot(&self, port_num: PortId) -> Result { - Ok(self.port_states.get(&port_num).ok_or(Error::new(EIO))?.slot) - } - pub async fn set_tr_deque_ptr( - &self, - port_num: PortId, - endp_num: u8, - deque_ptr_and_cycle: u64, - ) -> Result<()> { - let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?; - let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; - let slot = port_state.slot; - - let endp_desc = port_state - .get_endp_desc(endp_idx) - .ok_or(Error::new(EBADFD))?; - let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); - - let (event_trb, command_trb) = self - .execute_command(|trb, cycle| { - trb.set_tr_deque_ptr( - deque_ptr_and_cycle, - cycle, - StreamContextType::PrimaryRing, - 1, - endp_num_xhc, - slot, - ) - }) - .await; - //self.event_handler_finished(); - - handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb) - } - pub async fn on_write_endp_ctl( - &self, - port_num: PortId, - endp_num: u8, - buf: &[u8], - ) -> Result { - let mut port_state = self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(EBADF))?; - - let ep_if_state = &mut port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADF))? - .driver_if_state; - - let req = serde_json::from_slice::(buf).or(Err(Error::new(EBADMSG)))?; - match req { - XhciEndpCtlReq::Status => match ep_if_state { - state @ EndpIfState::Init => *state = EndpIfState::WaitingForStatus, - other => { - return Err(Error::new(EBADF)); - } - }, - XhciEndpCtlReq::Reset { no_clear_feature } => match ep_if_state { - EndpIfState::Init => { - self.on_req_reset_device(port_num, endp_num, !no_clear_feature) - .await? - } - other => { - return Err(Error::new(EBADF)); - } - }, - XhciEndpCtlReq::Transfer { direction, count } => match ep_if_state { - state @ EndpIfState::Init => { - if direction == XhciEndpCtlDirection::NoData { - // Yield the result directly because no bytes have to be sent or received - // beforehand. - let (completion_code, bytes_transferred, _) = self - .transfer(port_num, endp_num - 1, None, PortReqDirection::DeviceToHost) - .await?; - if bytes_transferred > 0 { - return Err(Error::new(EIO)); - } - let result = Self::transfer_result(completion_code, 0); - - let mut port_state = self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(EBADF))?; - let new_state = &mut port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADF))? - .driver_if_state; - *new_state = EndpIfState::WaitingForTransferResult(result) - } else { - *state = EndpIfState::WaitingForDataPipe { - direction, - bytes_to_transfer: count, - bytes_transferred: 0, - }; - } - } - other => { - return Err(Error::new(EBADF)); - } - }, - other => { - return Err(Error::new(EBADF)); - } - } - Ok(buf.len()) - } - fn transfer_result(completion_code: u8, bytes_transferred: u32) -> PortTransferStatus { - let kind = if completion_code == TrbCompletionCode::Success as u8 { - PortTransferStatusKind::Success - } else if completion_code == TrbCompletionCode::ShortPacket as u8 { - PortTransferStatusKind::ShortPacket - } else if completion_code == TrbCompletionCode::Stall as u8 { - PortTransferStatusKind::Stalled - } else { - PortTransferStatusKind::Unknown - }; - PortTransferStatus { - kind, - bytes_transferred, - } - } - pub async fn on_write_endp_data( - &self, - port_num: PortId, - endp_num: u8, - buf: &[u8], - ) -> Result { - let mut port_state = self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(EBADFD))?; - let mut endpoint_state = port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADFD))?; - - let ep_if_state = &mut endpoint_state.driver_if_state; - - match ep_if_state { - &mut EndpIfState::WaitingForDataPipe { - direction: XhciEndpCtlDirection::Out, - bytes_to_transfer: total_bytes_to_transfer, - bytes_transferred, - } => { - if buf.len() > total_bytes_to_transfer as usize - bytes_transferred as usize { - return Err(Error::new(EINVAL)); - } - drop(port_state); - let (completion_code, some_bytes_transferred) = - self.transfer_write(port_num, endp_num - 1, buf).await?; - let result = Self::transfer_result(completion_code, some_bytes_transferred); - - // To avoid having to read from the Ctl interface file, the client should stop - // invoking further data transfer calls if any single transfer returns fewer bytes - // than requested. - - let mut port_state = self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(EBADFD))?; - let mut endpoint_state = port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADFD))?; - let ep_if_state = &mut endpoint_state.driver_if_state; - - if let &mut EndpIfState::WaitingForDataPipe { - direction: XhciEndpCtlDirection::Out, - bytes_to_transfer, - ref mut bytes_transferred, - } = ep_if_state - { - if *bytes_transferred + some_bytes_transferred == bytes_to_transfer - || completion_code != TrbCompletionCode::Success as u8 - { - *ep_if_state = EndpIfState::WaitingForTransferResult(result); - } else { - *bytes_transferred += some_bytes_transferred; - } - } else { - unreachable!() - } - Ok(some_bytes_transferred as usize) - } - _ => return Err(Error::new(EBADF)), - } - } - pub fn on_read_endp_ctl( - &self, - port_num: PortId, - endp_num: u8, - buf: &mut [u8], - ) -> Result { - let port_state = &mut self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(EBADF))?; - - let ep_if_state = &mut port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADF))? - .driver_if_state; - - let res: XhciEndpCtlRes = match ep_if_state { - &mut EndpIfState::Init => XhciEndpCtlRes::Idle, - - state @ &mut EndpIfState::WaitingForStatus => { - *state = EndpIfState::Init; - XhciEndpCtlRes::Status(self.get_endp_status(port_num, endp_num)?) - } - &mut EndpIfState::WaitingForDataPipe { .. } => XhciEndpCtlRes::Pending, - &mut EndpIfState::WaitingForTransferResult(status) => { - *ep_if_state = EndpIfState::Init; - XhciEndpCtlRes::TransferResult(status) - } - }; - - let mut cursor = io::Cursor::new(buf); - serde_json::to_writer(&mut cursor, &res).or(Err(Error::new(EIO)))?; - Ok(cursor.seek(io::SeekFrom::Current(0)).unwrap() as usize) - } - pub async fn on_read_endp_data( - &self, - port_num: PortId, - endp_num: u8, - buf: &mut [u8], - ) -> Result { - let mut port_state = self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(EBADF))?; - - let mut ep_if_state = &mut port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADF))? - .driver_if_state; - - match ep_if_state { - &mut EndpIfState::WaitingForDataPipe { - direction: XhciEndpCtlDirection::In, - bytes_transferred, - bytes_to_transfer: total_bytes_to_transfer, - } => { - if buf.len() > total_bytes_to_transfer as usize - bytes_transferred as usize { - return Err(Error::new(EINVAL)); - } - - drop(port_state); - let (completion_code, some_bytes_transferred) = - self.transfer_read(port_num, endp_num - 1, buf).await?; - - // Just as with on_write_endp_data, a client issuing multiple reads must always - // stop reading if one read returns fewer bytes than expected. - - let result = Self::transfer_result(completion_code, some_bytes_transferred); - - let mut port_state = self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(EBADF))?; - - let mut ep_state = port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADF))?; - - let ep_if_state = &mut ep_state.driver_if_state; - - if let &mut EndpIfState::WaitingForDataPipe { - direction: XhciEndpCtlDirection::In, - bytes_to_transfer, - ref mut bytes_transferred, - } = ep_if_state - { - if *bytes_transferred + some_bytes_transferred == bytes_to_transfer - || completion_code != TrbCompletionCode::Success as u8 - { - *ep_if_state = EndpIfState::WaitingForTransferResult(result); - } else { - *bytes_transferred += some_bytes_transferred; - } - } else { - unreachable!() - } - Ok(some_bytes_transferred as usize) - } - _ => return Err(Error::new(EBADF)), - } - } - /// Notifies the xHC that the current event handler has finished, so that new interrupts can be - /// sent. This is required after each invocation of `Self::execute_command`. - /// - /// # Locking - /// This function locks `Xhci::run`. - pub fn event_handler_finished(&self) { - trace!("Event handler finished"); - // write 1 to EHB to clear it - self.run.lock().unwrap().ints[0] - .erdp_low - .writef(1 << 3, true); - } -} -pub fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()> { - if event_trb.completion_code() == TrbCompletionCode::Success as u8 { - Ok(()) - } else { - error!( - "{} command (TRB {:?}) failed with event trb {:?}", - name, command_trb, event_trb - ); - Err(Error::new(EIO)) - } -} -pub fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb) -> Result<()> { - if event_trb.completion_code() == TrbCompletionCode::Success as u8 - || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 - { - Ok(()) - } else { - error!( - "{} transfer {:?} failed with event {:?}", - name, transfer_trb, event_trb - ); - Err(Error::new(EIO)) - } -} -use lazy_static::lazy_static; -use std::ops::{Add, Div, Rem}; - -pub fn div_round_up(a: T, b: T) -> T -where - T: Add + Div + Rem + PartialEq + From + Copy, -{ - if a % b != T::from(0u8) { - a / b + T::from(1u8) - } else { - a / b - } -} diff --git a/recipes/core/base/drivers/usb/xhcid/src/xhci/trb.rs b/recipes/core/base/drivers/usb/xhcid/src/xhci/trb.rs deleted file mode 100644 index e0e5dc79fe..0000000000 --- a/recipes/core/base/drivers/usb/xhcid/src/xhci/trb.rs +++ /dev/null @@ -1,510 +0,0 @@ -use super::context::StreamContextType; -use crate::usb; -use common::io::{Io, Mmio}; -use log::trace; -use std::{fmt, mem}; - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum TrbType { - Reserved, - /* Transfer */ - Normal, - SetupStage, - DataStage, - StatusStage, - Isoch, - Link, - EventData, - NoOp, - /* Command */ - EnableSlot, - DisableSlot, - AddressDevice, - ConfigureEndpoint, - EvaluateContext, - ResetEndpoint, - StopEndpoint, - SetTrDequeuePointer, - ResetDevice, - ForceEvent, - NegotiateBandwidth, - SetLatencyToleranceValue, - GetPortBandwidth, - ForceHeader, - NoOpCmd, - /* Reserved */ - GetExtendedProperty, - SetExtendedProperty, - Rsv26, - Rsv27, - Rsv28, - Rsv29, - Rsv30, - Rsv31, - /* Events */ - Transfer, - CommandCompletion, - PortStatusChange, - BandwidthRequest, - Doorbell, - HostController, - DeviceNotification, - MfindexWrap, - /* Reserved from 40 to 47, vendor devined from 48 to 63 */ -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum TrbCompletionCode { - Invalid = 0x00, - Success = 0x01, - DataBuffer = 0x02, - BabbleDetected = 0x03, - UsbTransaction = 0x04, - Trb = 0x05, - Stall = 0x06, - Resource = 0x07, - Bandwidth = 0x08, - NoSlotsAvailable = 0x09, - InvalidStreamType = 0x0A, - SlotNotEnabled = 0x0B, - EndpointNotEnabled = 0x0C, - ShortPacket = 0x0D, - RingUnderrun = 0x0E, - RingOverrun = 0x0F, - VfEventRingFull = 0x10, - Parameter = 0x11, - BandwidthOverrun = 0x12, - ContextState = 0x13, - NoPingResponse = 0x14, - EventRingFull = 0x15, - IncompatibleDevice = 0x16, - MissedService = 0x17, - CommandRingStopped = 0x18, - CommandAborted = 0x19, - Stopped = 0x1A, - StoppedLengthInvalid = 0x1B, - StoppedShortPacket = 0x1C, - MaxExitLatencyTooLarge = 0x1D, - Rsv30 = 0x1E, - IsochBuffer = 0x1F, - EventLost = 0x20, - Undefined = 0x21, - InvalidStreamId = 0x22, - SecondaryBandwidth = 0x23, - SplitTransaction = 0x24, - /* Values from 37 to 191 are reserved */ - /* 192 to 223 are vendor defined errors */ - /* 224 to 255 are vendor defined information */ -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum TransferKind { - NoData, - Reserved, - Out, - In, -} - -#[repr(C, packed)] -pub struct Trb { - pub data_low: Mmio, - pub data_high: Mmio, - pub status: Mmio, - pub control: Mmio, -} -impl Clone for Trb { - fn clone(&self) -> Self { - Self { - data_low: Mmio::new(self.data_low.read()), - data_high: Mmio::new(self.data_high.read()), - status: Mmio::new(self.status.read()), - control: Mmio::new(self.control.read()), - } - } -} - -pub const TRB_STATUS_COMPLETION_CODE_SHIFT: u8 = 24; -pub const TRB_STATUS_COMPLETION_CODE_MASK: u32 = 0xFF00_0000; - -pub const TRB_STATUS_COMPLETION_PARAM_SHIFT: u8 = 0; -pub const TRB_STATUS_COMPLETION_PARAM_MASK: u32 = 0x00FF_FFFF; - -pub const TRB_STATUS_TRANSFER_LENGTH_SHIFT: u8 = 0; -pub const TRB_STATUS_TRANSFER_LENGTH_MASK: u32 = 0x00FF_FFFF; - -pub const TRB_CONTROL_TRB_TYPE_SHIFT: u8 = 10; -pub const TRB_CONTROL_TRB_TYPE_MASK: u32 = 0x0000_FC00; - -pub const TRB_CONTROL_EVENT_DATA_SHIFT: u8 = 2; -pub const TRB_CONTROL_EVENT_DATA_BIT: u32 = 1 << TRB_CONTROL_EVENT_DATA_SHIFT; - -pub const TRB_CONTROL_ENDPOINT_ID_MASK: u32 = 0x001F_0000; -pub const TRB_CONTROL_ENDPOINT_ID_SHIFT: u8 = 16; - -impl Trb { - pub fn set(&mut self, data: u64, status: u32, control: u32) { - self.data_low.write(data as u32); - self.data_high.write((data >> 32) as u32); - self.status.write(status); - self.control.write(control); - } - - pub fn reserved(&mut self, cycle: bool) { - self.set(0, 0, ((TrbType::Reserved as u32) << 10) | (cycle as u32)); - } - - pub fn read_data(&self) -> u64 { - (self.data_low.read() as u64) | ((self.data_high.read() as u64) << 32) - } - - pub fn completion_code(&self) -> u8 { - (self.status.read() >> TRB_STATUS_COMPLETION_CODE_SHIFT) as u8 - } - pub fn completion_param(&self) -> u32 { - self.status.read() & TRB_STATUS_COMPLETION_PARAM_MASK - } - fn has_completion_trb_pointer(&self) -> bool { - if self.completion_code() == TrbCompletionCode::RingUnderrun as u8 - || self.completion_code() == TrbCompletionCode::RingOverrun as u8 - { - false - } else if self.completion_code() == TrbCompletionCode::VfEventRingFull as u8 { - false - } else { - true - } - } - pub fn completion_trb_pointer(&self) -> Option { - debug_assert_eq!(self.trb_type(), TrbType::CommandCompletion as u8); - - if self.has_completion_trb_pointer() { - Some(self.read_data()) - } else { - None - } - } - pub fn transfer_event_trb_pointer(&self) -> Option { - debug_assert_eq!(self.trb_type(), TrbType::Transfer as u8); - - if self.has_completion_trb_pointer() { - Some(self.read_data()) - } else { - None - } - } - - pub fn port_status_change_port_id(&self) -> Option { - debug_assert_eq!(self.trb_type(), TrbType::PortStatusChange as u8); - - if self.has_completion_trb_pointer() { - let data = self.read_data(); - Some(((data >> 24) & 0xFF) as u8) - } else { - None - } - } - - pub fn event_slot(&self) -> u8 { - (self.control.read() >> 24) as u8 - } - /// Returns the number of bytes that should have been transmitten, but weren't. - pub fn transfer_length(&self) -> u32 { - self.status.read() & TRB_STATUS_TRANSFER_LENGTH_MASK - } - pub fn event_data_bit(&self) -> bool { - self.control.readf(TRB_CONTROL_EVENT_DATA_BIT) - } - pub fn event_data(&self) -> Option { - if self.event_data_bit() { - Some(self.read_data()) - } else { - None - } - } - pub fn endpoint_id(&self) -> u8 { - ((self.control.read() & TRB_CONTROL_ENDPOINT_ID_MASK) >> TRB_CONTROL_ENDPOINT_ID_SHIFT) - as u8 - } - pub fn trb_type(&self) -> u8 { - ((self.control.read() & TRB_CONTROL_TRB_TYPE_MASK) >> TRB_CONTROL_TRB_TYPE_SHIFT) as u8 - } - - pub fn link(&mut self, address: usize, toggle: bool, cycle: bool) { - self.set( - address as u64, - 0, - ((TrbType::Link as u32) << 10) | ((toggle as u32) << 1) | (cycle as u32), - ); - } - - pub fn no_op_cmd(&mut self, cycle: bool) { - self.set(0, 0, ((TrbType::NoOpCmd as u32) << 10) | (cycle as u32)); - } - - pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) { - trace!("Enabling slot with type {}", slot_type); - self.set( - 0, - 0, - (((slot_type as u32) & 0x1F) << 16) - | ((TrbType::EnableSlot as u32) << 10) - | (cycle as u32), - ); - } - pub fn disable_slot(&mut self, slot: u8, cycle: bool) { - self.set( - 0, - 0, - (u32::from(slot) << 24) | ((TrbType::DisableSlot as u32) << 10) | u32::from(cycle), - ); - } - - pub fn address_device(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) { - assert_eq!( - (input_ctx_ptr as u64) & 0xFFFF_FFFF_FFFF_FFF0, - input_ctx_ptr as u64, - "unaligned input context ptr" - ); - self.set( - input_ctx_ptr as u64, - 0, - (u32::from(slot_id) << 24) - | ((TrbType::AddressDevice as u32) << 10) - | (u32::from(bsr) << 9) - | u32::from(cycle), - ); - } - // Synchronizes the input context endpoints with the device context endpoints, I think. - pub fn configure_endpoint(&mut self, slot_id: u8, input_ctx_ptr: usize, cycle: bool) { - assert_eq!( - (input_ctx_ptr as u64) & 0xFFFF_FFFF_FFFF_FFF0, - input_ctx_ptr as u64, - "unaligned input context ptr" - ); - - self.set( - input_ctx_ptr as u64, - 0, - (u32::from(slot_id) << 24) - | ((TrbType::ConfigureEndpoint as u32) << 10) - | u32::from(cycle), - ); - } - pub fn evaluate_context(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) { - assert_eq!( - (input_ctx_ptr as u64) & 0xFFFF_FFFF_FFFF_FFF0, - input_ctx_ptr as u64, - "unaligned input context ptr" - ); - self.set( - input_ctx_ptr as u64, - 0, - (u32::from(slot_id) << 24) - | ((TrbType::EvaluateContext as u32) << 10) - | (u32::from(bsr) << 9) - | u32::from(cycle), - ); - } - pub fn reset_endpoint(&mut self, slot_id: u8, endp_num_xhc: u8, tsp: bool, cycle: bool) { - assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc); - self.set( - 0, - 0, - (u32::from(slot_id) << 24) - | (u32::from(endp_num_xhc) << 16) - | ((TrbType::ResetEndpoint as u32) << 10) - | (u32::from(tsp) << 9) - | u32::from(cycle), - ); - } - /// The deque_ptr has to contain the DCS bit (bit 0). - pub fn set_tr_deque_ptr( - &mut self, - deque_ptr: u64, - cycle: bool, - sct: StreamContextType, - stream_id: u16, - endp_num_xhc: u8, - slot: u8, - ) { - assert_eq!(deque_ptr & 0xFFFF_FFFF_FFFF_FFF1, deque_ptr); - assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc); - - self.set( - deque_ptr | ((sct as u64) << 1), - u32::from(stream_id) << 16, - (u32::from(slot) << 24) - | (u32::from(endp_num_xhc) << 16) - | ((TrbType::SetTrDequeuePointer as u32) << 10) - | u32::from(cycle), - ) - } - pub fn stop_endpoint(&mut self, slot_id: u8, endp_num_xhc: u8, suspend: bool, cycle: bool) { - assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc); - self.set( - 0, - 0, - (u32::from(slot_id) << 24) - | (u32::from(suspend) << 23) - | (u32::from(endp_num_xhc) << 16) - | ((TrbType::StopEndpoint as u32) << 10) - | u32::from(cycle), - ); - } - pub fn reset_device(&mut self, slot_id: u8, cycle: bool) { - self.set( - 0, - 0, - (u32::from(slot_id) << 24) | ((TrbType::ResetDevice as u32) << 10) | u32::from(cycle), - ); - } - - pub fn transfer_no_op(&mut self, interrupter: u8, ent: bool, ch: bool, ioc: bool, cycle: bool) { - self.set( - 0, - u32::from(interrupter) << 22, - ((TrbType::NoOp as u32) << 10) - | (u32::from(ioc) << 5) - | (u32::from(ch) << 4) - | (u32::from(ent) << 1) - | u32::from(cycle), - ); - } - - pub fn setup(&mut self, setup: usb::Setup, transfer: TransferKind, cycle: bool) { - self.set( - unsafe { mem::transmute(setup) }, - 8, - ((transfer as u32) << 16) - | ((TrbType::SetupStage as u32) << 10) - | (1 << 6) - | (cycle as u32), - ); - } - - pub fn data(&mut self, buffer: usize, length: u16, input: bool, cycle: bool) { - self.set( - buffer as u64, - length as u32, - ((input as u32) << 16) | ((TrbType::DataStage as u32) << 10) | (cycle as u32), - ); - } - - pub fn cycle(&self) -> bool { - self.control.readf(0x01) - } - - pub fn status( - &mut self, - interrupter: u16, - input: bool, - ioc: bool, - ch: bool, - ent: bool, - cycle: bool, - ) { - self.set( - 0, - u32::from(interrupter) << 22, - (u32::from(input) << 16) - | ((TrbType::StatusStage as u32) << 10) - | (u32::from(ioc) << 5) - | (u32::from(ch) << 4) - | (u32::from(ent) << 1) - | (cycle as u32), - ); - } - pub fn normal( - &mut self, - buffer: u64, - len: u32, - cycle: bool, - estimated_td_size: u8, - interrupter: u8, - ent: bool, - isp: bool, - chain: bool, - ioc: bool, - idt: bool, - bei: bool, - ) { - assert_eq!(estimated_td_size & 0x1F, estimated_td_size); - // NOTE: The interrupter target and no snoop flags have been omitted. - self.set( - buffer, - len | (u32::from(estimated_td_size) << 17) | (u32::from(interrupter) << 22), - u32::from(cycle) - | (u32::from(ent) << 1) - | (u32::from(isp) << 2) - | (u32::from(chain) << 4) - | (u32::from(ioc) << 5) - | (u32::from(idt) << 6) - | (u32::from(bei) << 9) - | ((TrbType::Normal as u32) << 10), - ) - } - pub fn is_command_trb(&self) -> bool { - let valid_trb_types = [ - TrbType::NoOpCmd as u8, - TrbType::EnableSlot as u8, - TrbType::DisableSlot as u8, - TrbType::AddressDevice as u8, - TrbType::ConfigureEndpoint as u8, - TrbType::EvaluateContext as u8, - TrbType::ResetEndpoint as u8, - TrbType::StopEndpoint as u8, - TrbType::SetTrDequeuePointer as u8, - TrbType::ResetDevice as u8, - TrbType::ForceEvent as u8, - TrbType::NegotiateBandwidth as u8, - TrbType::SetLatencyToleranceValue as u8, - TrbType::GetPortBandwidth as u8, - TrbType::ForceHeader as u8, - TrbType::GetExtendedProperty as u8, - TrbType::SetExtendedProperty as u8, - ]; - valid_trb_types.contains(&self.trb_type()) - } - pub fn is_transfer_trb(&self) -> bool { - // XXX: Unfortunately, the only way to use match statements with integer constants, is to - // precast them into valid enum values, which either requires a derive macro such as - // num_traits's #[derive(FromPrimitive)], or manually writing the reverse match statement - // first. - let valid_trb_types = [ - TrbType::Normal as u8, - TrbType::SetupStage as u8, - TrbType::DataStage as u8, - TrbType::StatusStage as u8, - TrbType::Isoch as u8, - TrbType::NoOp as u8, - ]; - valid_trb_types.contains(&self.trb_type()) - } -} - -impl fmt::Debug for Trb { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "Trb {{ data: {:>016X}, status: {:>08X}, control: {:>08X} }}", - self.read_data(), - self.status.read(), - self.control.read() - ) - } -} - -impl fmt::Display for Trb { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "({:>016X}, {:>08X}, {:>08X})", - self.read_data(), - self.status.read(), - self.control.read() - ) - } -} diff --git a/recipes/core/base/drivers/vboxd/Cargo.toml b/recipes/core/base/drivers/vboxd/Cargo.toml deleted file mode 100644 index 814eeeab11..0000000000 --- a/recipes/core/base/drivers/vboxd/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -name = "vboxd" -description = "VirtualBox driver" -version = "0.1.0" -edition = "2018" - -[dependencies] -libredox.workspace = true -orbclient.workspace = true -redox_event.workspace = true -redox_syscall.workspace = true - -common = { path = "../common" } -daemon = { path = "../../daemon" } -pcid = { path = "../pcid" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/vboxd/config.toml b/recipes/core/base/drivers/vboxd/config.toml deleted file mode 100644 index 1216625579..0000000000 --- a/recipes/core/base/drivers/vboxd/config.toml +++ /dev/null @@ -1,6 +0,0 @@ -[[drivers]] -name = "VirtualBox Guest Device" -class = 0x08 -vendor = 0x80EE -device = 0xCAFE -command = ["vboxd"] diff --git a/recipes/core/base/drivers/vboxd/src/bga.rs b/recipes/core/base/drivers/vboxd/src/bga.rs deleted file mode 100644 index 264c9c568c..0000000000 --- a/recipes/core/base/drivers/vboxd/src/bga.rs +++ /dev/null @@ -1,46 +0,0 @@ -use common::io::{Io, Pio}; - -const BGA_INDEX_XRES: u16 = 1; -const BGA_INDEX_YRES: u16 = 2; -const BGA_INDEX_BPP: u16 = 3; -const BGA_INDEX_ENABLE: u16 = 4; - -pub struct Bga { - index: Pio, - data: Pio, -} - -impl Bga { - pub fn new() -> Bga { - Bga { - index: Pio::new(0x1CE), - data: Pio::new(0x1CF), - } - } - - fn read(&mut self, index: u16) -> u16 { - self.index.write(index); - self.data.read() - } - - fn write(&mut self, index: u16, data: u16) { - self.index.write(index); - self.data.write(data); - } - - pub fn width(&mut self) -> u16 { - self.read(BGA_INDEX_XRES) - } - - pub fn height(&mut self) -> u16 { - self.read(BGA_INDEX_YRES) - } - - pub fn set_size(&mut self, width: u16, height: u16) { - self.write(BGA_INDEX_ENABLE, 0); - self.write(BGA_INDEX_XRES, width); - self.write(BGA_INDEX_YRES, height); - self.write(BGA_INDEX_BPP, 32); - self.write(BGA_INDEX_ENABLE, 0x41); - } -} diff --git a/recipes/core/base/drivers/vboxd/src/main.rs b/recipes/core/base/drivers/vboxd/src/main.rs deleted file mode 100644 index bcb9bb157d..0000000000 --- a/recipes/core/base/drivers/vboxd/src/main.rs +++ /dev/null @@ -1,333 +0,0 @@ -//#![deny(warnings)] - -use event::{user_data, EventQueue}; -use std::fs::File; -use std::io::{Read, Write}; -use std::os::unix::io::AsRawFd; -use std::{iter, mem}; - -use common::io::{Io, Mmio}; -use pcid_interface::PciFunctionHandle; - -use common::dma::Dma; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod bga; - -const VBOX_REQUEST_HEADER_VERSION: u32 = 0x10001; -const VBOX_VMMDEV_VERSION: u32 = 0x00010003; - -const VBOX_EVENT_DISPLAY: u32 = 1 << 2; -const VBOX_EVENT_MOUSE: u32 = 1 << 9; - -/// VBox VMMDevMemory -#[repr(C, packed)] -struct VboxVmmDev { - size: Mmio, - version: Mmio, - host_events: Mmio, - guest_events: Mmio, -} - -/// VBox Guest packet header -#[repr(C, packed)] -struct VboxHeader { - /// Size of the entire packet (including this header) - size: Mmio, - /// Version; always VBOX_REQUEST_HEADER_VERSION - version: Mmio, - /// Request type - request: Mmio, - /// Return code - result: Mmio, - _reserved1: Mmio, - _reserved2: Mmio, -} - -/// VBox Get Mouse -#[repr(C, packed)] -struct VboxGetMouse { - header: VboxHeader, - features: Mmio, - x: Mmio, - y: Mmio, -} - -impl VboxGetMouse { - fn request() -> u32 { - 1 - } - - fn new() -> syscall::Result> { - let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; - - packet.header.size.write(mem::size_of::() as u32); - packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); - packet.header.request.write(Self::request()); - - Ok(packet) - } -} - -/// VBox Set Mouse -#[repr(C, packed)] -struct VboxSetMouse { - header: VboxHeader, - features: Mmio, - x: Mmio, - y: Mmio, -} - -impl VboxSetMouse { - fn request() -> u32 { - 2 - } - - fn new() -> syscall::Result> { - let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; - - packet.header.size.write(mem::size_of::() as u32); - packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); - packet.header.request.write(Self::request()); - - Ok(packet) - } -} - -/// VBox Acknowledge Events packet -#[repr(C, packed)] -struct VboxAckEvents { - header: VboxHeader, - events: Mmio, -} - -impl VboxAckEvents { - fn request() -> u32 { - 41 - } - - fn new() -> syscall::Result> { - let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; - - packet.header.size.write(mem::size_of::() as u32); - packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); - packet.header.request.write(Self::request()); - - Ok(packet) - } -} - -/// VBox Guest Capabilities packet -#[repr(C, packed)] -struct VboxGuestCaps { - header: VboxHeader, - caps: Mmio, -} - -impl VboxGuestCaps { - fn request() -> u32 { - 55 - } - - fn new() -> syscall::Result> { - let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; - - packet.header.size.write(mem::size_of::() as u32); - packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); - packet.header.request.write(Self::request()); - - Ok(packet) - } -} - -/* VBox GetDisplayChange packet */ -struct VboxDisplayChange { - header: VboxHeader, - xres: Mmio, - yres: Mmio, - bpp: Mmio, - eventack: Mmio, -} - -impl VboxDisplayChange { - fn request() -> u32 { - 51 - } - - fn new() -> syscall::Result> { - let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; - - packet.header.size.write(mem::size_of::() as u32); - packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); - packet.header.request.write(Self::request()); - - Ok(packet) - } -} - -/// VBox Guest Info packet (legacy) -#[repr(C, packed)] -struct VboxGuestInfo { - header: VboxHeader, - version: Mmio, - ostype: Mmio, -} - -impl VboxGuestInfo { - fn request() -> u32 { - 50 - } - - fn new() -> syscall::Result> { - let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; - - packet.header.size.write(mem::size_of::() as u32); - packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); - packet.header.request.write(Self::request()); - - Ok(packet) - } -} - -fn main() { - pcid_interface::pci_daemon(daemon); -} - -fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! { - let pci_config = pcid_handle.config(); - - let mut name = pci_config.func.name(); - name.push_str("_vbox"); - - let bar0 = pci_config.func.bars[0].expect_port(); - - let irq = pci_config - .func - .legacy_interrupt_line - .expect("vboxd: no legacy interrupts supported"); - - println!(" + VirtualBox {}", pci_config.func.display()); - - common::acquire_port_io_rights().expect("vboxd: failed to get I/O permission"); - - let mut width = 0; - let mut height = 0; - let mut display_opt = File::open("inputd:producer").ok(); - if let Some(ref display) = display_opt { - let mut buf: [u8; 4096] = [0; 4096]; - if let Ok(count) = libredox::call::fpath(display.as_raw_fd() as usize, &mut buf) { - let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; - let res = path.split(":").nth(1).unwrap_or(""); - width = res - .split("/") - .nth(1) - .unwrap_or("") - .parse::() - .unwrap_or(0); - height = res - .split("/") - .nth(2) - .unwrap_or("") - .parse::() - .unwrap_or(0); - } - } - - let mut irq_file = irq.irq_handle("vboxd"); - - let address = unsafe { pcid_handle.map_bar(1) }.ptr.as_ptr(); - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - let mut port = common::io::Pio::::new(bar0 as u16); - - let vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; - - let mut guest_info = VboxGuestInfo::new().expect("vboxd: failed to map GuestInfo"); - guest_info.version.write(VBOX_VMMDEV_VERSION); - guest_info.ostype.write(0x100); - port.write(guest_info.physical() as u32); - - let mut guest_caps = VboxGuestCaps::new().expect("vboxd: failed to map GuestCaps"); - guest_caps.caps.write(1 << 2); - port.write(guest_caps.physical() as u32); - - let mut set_mouse = VboxSetMouse::new().expect("vboxd: failed to map SetMouse"); - set_mouse.features.write(1 << 4 | 1); - port.write(set_mouse.physical() as u32); - - vmmdev - .guest_events - .write(VBOX_EVENT_DISPLAY | VBOX_EVENT_MOUSE); - - user_data! { - enum Source { - Irq, - } - } - - let event_queue = - EventQueue::::new().expect("vboxd: Could not create event queue."); - event_queue - .subscribe( - irq_file.as_raw_fd() as usize, - Source::Irq, - event::EventFlags::READ, - ) - .unwrap(); - - daemon.ready(); - - libredox::call::setrens(0, 0).expect("vboxd: failed to enter null namespace"); - - let mut bga = crate::bga::Bga::new(); - let get_mouse = VboxGetMouse::new().expect("vboxd: failed to map GetMouse"); - let display_change = VboxDisplayChange::new().expect("vboxd: failed to map DisplayChange"); - let ack_events = VboxAckEvents::new().expect("vboxd: failed to map AckEvents"); - - for Source::Irq in iter::once(Source::Irq) - .chain(event_queue.map(|e| e.expect("vboxd: failed to get next event").user_data)) - { - let mut irq = [0; 8]; - if irq_file.read(&mut irq).unwrap() >= irq.len() { - let host_events = vmmdev.host_events.read(); - if host_events != 0 { - port.write(ack_events.physical() as u32); - irq_file.write(&irq).unwrap(); - - if host_events & VBOX_EVENT_DISPLAY == VBOX_EVENT_DISPLAY { - port.write(display_change.physical() as u32); - if let Some(ref mut display) = display_opt { - let new_width = display_change.xres.read(); - let new_height = display_change.yres.read(); - if width != new_width || height != new_height { - width = new_width; - height = new_height; - println!("Display {}, {}", width, height); - bga.set_size(width as u16, height as u16); - let _ = display - .write(&orbclient::ResizeEvent { width, height }.to_event()); - } - } - } - - if host_events & VBOX_EVENT_MOUSE == VBOX_EVENT_MOUSE { - port.write(get_mouse.physical() as u32); - if let Some(ref mut display) = display_opt { - let x = get_mouse.x.read() * width / 0x10000; - let y = get_mouse.y.read() * height / 0x10000; - let _ = display.write( - &orbclient::MouseEvent { - x: x as i32, - y: y as i32, - } - .to_event(), - ); - } - } - } - } - } - } - - std::process::exit(0); -} diff --git a/recipes/core/base/drivers/virtio-core/Cargo.toml b/recipes/core/base/drivers/virtio-core/Cargo.toml deleted file mode 100644 index 0f37be583f..0000000000 --- a/recipes/core/base/drivers/virtio-core/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "virtio-core" -description = "VirtIO driver library" -version = "0.1.0" -edition = "2021" -authors = ["Anhad Singh "] - -[dependencies] -static_assertions.workspace = true -bitflags.workspace = true -redox_syscall.workspace = true -libredox.workspace = true -log.workspace = true -thiserror.workspace = true -futures = { version = "0.3.28", features = ["executor"] } -crossbeam-queue = "0.3.8" - -redox_event.workspace = true - -common = { path = "../common" } -pcid = { path = "../pcid" } - -[lints] -workspace = true diff --git a/recipes/core/base/drivers/virtio-core/src/arch/aarch64.rs b/recipes/core/base/drivers/virtio-core/src/arch/aarch64.rs deleted file mode 100644 index 4801a1f25d..0000000000 --- a/recipes/core/base/drivers/virtio-core/src/arch/aarch64.rs +++ /dev/null @@ -1,9 +0,0 @@ -use std::fs::File; - -use pcid_interface::*; - -use crate::{transport::Error, Device}; - -pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { - unimplemented!("virtio_core: aarch64 enable_msix") -} diff --git a/recipes/core/base/drivers/virtio-core/src/arch/riscv64.rs b/recipes/core/base/drivers/virtio-core/src/arch/riscv64.rs deleted file mode 100644 index 2551479f52..0000000000 --- a/recipes/core/base/drivers/virtio-core/src/arch/riscv64.rs +++ /dev/null @@ -1,9 +0,0 @@ -use std::fs::File; - -use pcid_interface::*; - -use crate::{transport::Error, Device}; - -pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { - unimplemented!("virtio_core: enable_msix") -} diff --git a/recipes/core/base/drivers/virtio-core/src/arch/x86.rs b/recipes/core/base/drivers/virtio-core/src/arch/x86.rs deleted file mode 100644 index aea86c4ad5..0000000000 --- a/recipes/core/base/drivers/virtio-core/src/arch/x86.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::transport::Error; - -use pcid_interface::irq_helpers::{allocate_single_interrupt_vector_for_msi, read_bsp_apic_id}; -use std::fs::File; - -use crate::MSIX_PRIMARY_VECTOR; - -use pcid_interface::*; - -pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { - // Extended message signaled interrupts. - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { - PciFeatureInfo::MsiX(capability) => capability, - _ => unreachable!(), - }; - let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; - - // Allocate the primary MSI vector. - // FIXME allow the driver to register multiple MSI-X vectors - // FIXME move this MSI-X registering code into pcid_interface or pcid itself - let interrupt_handle = { - let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize); - - let destination_id = read_bsp_apic_id().expect("virtio_core: `read_bsp_apic_id()` failed"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - table_entry_pointer.write_addr_and_data(msg_addr_and_data); - table_entry_pointer.unmask(); - - interrupt_handle - }; - - pcid_handle.enable_feature(PciFeature::MsiX); - - log::debug!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})"); - Ok(interrupt_handle) -} diff --git a/recipes/core/base/drivers/virtio-core/src/lib.rs b/recipes/core/base/drivers/virtio-core/src/lib.rs deleted file mode 100644 index 2557d0b78e..0000000000 --- a/recipes/core/base/drivers/virtio-core/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -pub mod spec; -pub mod transport; -pub mod utils; - -mod probe; - -#[cfg(target_arch = "aarch64")] -#[path = "arch/aarch64.rs"] -mod arch; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#[path = "arch/x86.rs"] -mod arch; - -#[cfg(target_arch = "riscv64")] -#[path = "arch/riscv64.rs"] -mod arch; - -pub use probe::{probe_device, reinit, Device, MSIX_PRIMARY_VECTOR}; diff --git a/recipes/core/base/drivers/virtio-core/src/probe.rs b/recipes/core/base/drivers/virtio-core/src/probe.rs deleted file mode 100644 index 5631ef676c..0000000000 --- a/recipes/core/base/drivers/virtio-core/src/probe.rs +++ /dev/null @@ -1,158 +0,0 @@ -use std::fs::File; -use std::sync::Arc; - -use pcid_interface::*; - -use crate::spec::*; -use crate::transport::{Error, StandardTransport, Transport}; -use crate::utils::align_down; - -pub struct Device { - pub transport: Arc, - pub device_space: *const u8, - pub irq_handle: File, -} - -// FIXME(andypython): `device_space` should not be `Send` nor `Sync`. Take -// it out of `Device`. -unsafe impl Send for Device {} -unsafe impl Sync for Device {} - -pub const MSIX_PRIMARY_VECTOR: u16 = 0; - -/// VirtIO Device Probe -/// -/// ## Device State -/// After this function, the device will have been successfully reseted and is ready for use. -/// -/// The caller is required to do the following: -/// * Negotiate the device and driver supported features (finialize via [`StandardTransport::finalize_features`]) -/// * Create the device specific virtio queues (via [`StandardTransport::setup_queue`]). This is *required* to be done -/// before starting the device. -/// * Finally start the device (via [`StandardTransport::run_device`]). At this point, the device -/// is alive. -/// -/// ## Panics -/// This function panics if the device is not a virtio device. -pub fn probe_device(pcid_handle: &mut PciFunctionHandle) -> Result { - let pci_config = pcid_handle.config(); - - assert_eq!( - pci_config.func.full_device_id.vendor_id, 6900, - "virtio_core::probe_device: not a virtio device" - ); - - let mut common_addr = None; - let mut notify_addr = None; - let mut device_addr = None; - - for raw_capability in pcid_handle.get_vendor_capabilities() { - // SAFETY: We have verified that the length of the data is correct. - let capability = unsafe { &*(raw_capability.data.as_ptr() as *const PciCapability) }; - - match capability.cfg_type { - CfgType::Common | CfgType::Notify | CfgType::Device => {} - _ => continue, - } - - let (addr, _) = pci_config.func.bars[capability.bar as usize].expect_mem(); - - let address = unsafe { - let addr = addr + capability.offset as usize; - - // XXX: physmap() requires the address to be page aligned. - let aligned_addr = align_down(addr); - let offset = addr - aligned_addr; - - let size = offset + capability.length as usize; - - let addr = common::physmap( - aligned_addr, - size, - common::Prot::RW, - common::MemoryType::Uncacheable, - )? as usize; - - addr + offset - }; - - match capability.cfg_type { - CfgType::Common => { - debug_assert!(common_addr.is_none()); - common_addr = Some(address); - } - - CfgType::Notify => { - debug_assert!(notify_addr.is_none()); - - // SAFETY: The capability type is `Notify`, so its safe to access - // the `notify_multiplier` field. - let multiplier = unsafe { - (&*(raw_capability.data.as_ptr() as *const PciCapability - as *const PciCapabilityNotify)) - .notify_off_multiplier() - }; - notify_addr = Some((address, multiplier)); - } - - CfgType::Device => { - debug_assert!(device_addr.is_none()); - device_addr = Some(address); - } - - _ => unreachable!(), - } - } - - let common_addr = common_addr.expect("virtio common capability missing"); - let device_addr = device_addr.expect("virtio device capability missing"); - let (notify_addr, notify_multiplier) = notify_addr.expect("virtio notify capability missing"); - - // FIXME this is explicitly allowed by the virtio specification to happen - assert!( - notify_multiplier != 0, - "virtio-core::device_probe: device uses the same Queue Notify addresses for all queues" - ); - - let common = unsafe { &mut *(common_addr as *mut CommonCfg) }; - let device_space = unsafe { &mut *(device_addr as *mut u8) }; - - let transport = StandardTransport::new( - common, - notify_addr as *const u8, - notify_multiplier, - device_space, - ); - - // Setup interrupts. - let all_pci_features = pcid_handle.fetch_all_features(); - let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - - // According to the virtio specification, the device REQUIRED to support MSI-X. - assert!(has_msix, "virtio: device does not support MSI-X"); - let irq_handle = crate::arch::enable_msix(pcid_handle)?; - - log::debug!("virtio: using standard PCI transport"); - - let device = Device { - transport, - device_space, - irq_handle, - }; - - device.transport.reset(); - reinit(&device)?; - - Ok(device) -} - -pub fn reinit(device: &Device) -> Result<(), Error> { - // XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits - // in `device_status` is required to be done in two steps. - device - .transport - .insert_status(DeviceStatusFlags::ACKNOWLEDGE); - - device.transport.insert_status(DeviceStatusFlags::DRIVER); - Ok(()) -} diff --git a/recipes/core/base/drivers/virtio-core/src/spec/mod.rs b/recipes/core/base/drivers/virtio-core/src/spec/mod.rs deleted file mode 100644 index b78931d2cb..0000000000 --- a/recipes/core/base/drivers/virtio-core/src/spec/mod.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html -//! -//! This file contains comments copied from the VirtIO specification which are -//! licensed under the following conditions: -//! -//! Copyright © OASIS Open 2022. All Rights Reserved. -//! -//! All capitalized terms in the following text have the meanings assigned to them -//! in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The -//! full Policy may be found at the OASIS website. -//! -//! This document and translations of it may be copied and furnished to others, -//! and derivative works that comment on or otherwise explain it or assist in its -//! implementation may be prepared, copied, published, and distributed, in whole -//! or in part, without restriction of any kind, provided that the above copyright -//! notice and this section are included on all such copies and derivative works. -//! However, this document itself may not be modified in any way, including by -//! removing the copyright notice or references to OASIS, except as needed for the -//! purpose of developing any document or deliverable produced by an OASIS Technical -//! Committee (in which case the rules applicable to copyrights, as set forth in the -//! OASIS IPR Policy, must be followed) or as required to translate it into languages -//! other than English. - -bitflags::bitflags! { - /// [2.1 Device Status Field](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-110001) - #[derive(Debug, Copy, Clone, PartialEq)] - #[repr(transparent)] - pub struct DeviceStatusFlags: u8 { - /// Indicates that the guest OS has found the device and recognized it as a - /// valid device. - const ACKNOWLEDGE = 1; - /// Indicates that the guest OS knows how to drive the device. - const DRIVER = 2; - /// Indicates that something went wrong in the guest and it has given up on - /// the device. - const FAILED = 128; - /// Indicates that the driver has acknowledged all the features it understands - /// and feature negotiation is complete. - const FEATURES_OK = 8; - /// Indicates that the driver is set up and ready to drive the device. - const DRIVER_OK = 4; - /// Indicates that the device has experienced an error from which it can’t recover. - const DEVICE_NEEDS_RESET = 64; - } -} - -mod split_virtqueue; -pub use split_virtqueue::*; - -// FIXME add [2.8 Packed Virtqueues](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-720008) - -mod transport_pci; -pub use transport_pci::*; - -mod reserved_features; -pub use reserved_features::*; diff --git a/recipes/core/base/drivers/virtio-core/src/spec/reserved_features.rs b/recipes/core/base/drivers/virtio-core/src/spec/reserved_features.rs deleted file mode 100644 index 9f88676767..0000000000 --- a/recipes/core/base/drivers/virtio-core/src/spec/reserved_features.rs +++ /dev/null @@ -1,100 +0,0 @@ -//! [6 Reserved Feature Bits](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-6600006) -//! -//! This file contains comments copied from the VirtIO specification which are -//! licensed under the following conditions: -//! -//! Copyright © OASIS Open 2022. All Rights Reserved. -//! -//! All capitalized terms in the following text have the meanings assigned to them -//! in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The -//! full Policy may be found at the OASIS website. -//! -//! This document and translations of it may be copied and furnished to others, -//! and derivative works that comment on or otherwise explain it or assist in its -//! implementation may be prepared, copied, published, and distributed, in whole -//! or in part, without restriction of any kind, provided that the above copyright -//! notice and this section are included on all such copies and derivative works. -//! However, this document itself may not be modified in any way, including by -//! removing the copyright notice or references to OASIS, except as needed for the -//! purpose of developing any document or deliverable produced by an OASIS Technical -//! Committee (in which case the rules applicable to copyrights, as set forth in the -//! OASIS IPR Policy, must be followed) or as required to translate it into languages -//! other than English. - -/// Negotiating this feature indicates that the driver can use descriptors -/// with the VIRTQ_DESC_F_INDIRECT flag set as described in 2.7.5.3 Indirect -/// Descriptors and 2.8.7 Indirect Flag: Scatter-Gather Support. -pub const VIRTIO_F_INDIRECT_DESC: u32 = 28; - -/// This feature enables the used_event and the avail_event fields as -/// described in 2.7.7, 2.7.8 and 2.8.10. -pub const VIRTIO_F_EVENT_IDX: u32 = 29; - -/// This indicates compliance with this specification, giving a simple way -/// to detect legacy devices or drivers. -pub const VIRTIO_F_VERSION_1: u32 = 32; - -/// This feature indicates that the device can be used on a platform where device -/// access to data in memory is limited and/or translated. E.g. this is the case -/// if the device can be located behind an IOMMU that translates bus addresses -/// from the device into physical addresses in memory, if the device can be limited -/// to only access certain memory addresses or if special commands such as a cache -/// flush can be needed to synchronise data in memory with the device. Whether -/// accesses are actually limited or translated is described by platform-specific -/// means. If this feature bit is set to 0, then the device has same access to -/// memory addresses supplied to it as the driver has. In particular, the device -/// will always use physical addresses matching addresses used by the driver -/// (typically meaning physical addresses used by the CPU) and not translated -/// further, and can access any address supplied to it by the driver. When clear, -/// this overrides any platform-specific description of whether device access is -/// limited or translated in any way, e.g. whether an IOMMU may be present. -pub const VIRTIO_F_ACCESS_PLATFORM: u32 = 33; - -/// This feature indicates support for the packed virtqueue layout as described -/// in 2.8 Packed Virtqueues. -pub const VIRTIO_F_RING_PACKED: u32 = 34; - -/// This feature indicates that all buffers are used by the device in the same order -/// in which they have been made available. -pub const VIRTIO_F_IN_ORDER: u32 = 35; - -/// This feature indicates that memory accesses by the driver and the device are -/// ordered in a way described by the platform. -/// If this feature bit is negotiated, the ordering in effect for any memory -/// accesses by the driver that need to be ordered in a specific way with respect -/// to accesses by the device is the one suitable for devices described by the -/// platform. This implies that the driver needs to use memory barriers suitable -/// for devices described by the platform; e.g. for the PCI transport in the case -/// of hardware PCI devices. -/// -/// If this feature bit is not negotiated, then the device and driver are assumed -/// to be implemented in software, that is they can be assumed to run on identical -/// CPUs in an SMP configuration. Thus a weaker form of memory barriers is sufficient -/// to yield better performance. -pub const VIRTIO_F_ORDER_PLATFORM: u32 = 36; - -/// This feature indicates that the device supports Single Root I/O Virtualization. -/// Currently only PCI devices support this feature. -pub const VIRTIO_F_SR_IOV: u32 = 37; - -/// This feature indicates that the driver passes extra data (besides identifying -/// the virtqueue) in its device notifications. See 2.9 Driver Notifications. -pub const VIRTIO_F_NOTIFICATION_DATA: u32 = 38; - -/// This feature indicates that the driver uses the data provided by the device as -/// a virtqueue identifier in available buffer notifications. As mentioned in section -/// 2.9, when the driver is required to send an available buffer notification to the -/// device, it sends the virtqueue number to be notified. The method of delivering -/// notifications is transport specific. With the PCI transport, the device can -/// optionally provide a per-virtqueue value for the driver to use in driver -/// notifications, instead of the virtqueue number. Some devices may benefit from this -/// flexibility by providing, for example, an internal virtqueue identifier, or an -/// internal offset related to the virtqueue number. -/// -/// This feature indicates the availability of such value. The definition of the data -/// to be provided in driver notification and the delivery method is transport -/// specific. For more details about driver notifications over PCI see 4.1.5.2. -pub const VIRTIO_F_NOTIF_CONFIG_DATA: u32 = 39; - -/// This feature indicates that the driver can reset a queue individually. See 2.6.1. -pub const VIRTIO_F_RING_RESET: u32 = 40; diff --git a/recipes/core/base/drivers/virtio-core/src/spec/split_virtqueue.rs b/recipes/core/base/drivers/virtio-core/src/spec/split_virtqueue.rs deleted file mode 100644 index b96367111f..0000000000 --- a/recipes/core/base/drivers/virtio-core/src/spec/split_virtqueue.rs +++ /dev/null @@ -1,205 +0,0 @@ -//! [2.7 Split Virtqueues](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-350007) -//! -//! This file contains comments copied from the VirtIO specification which are -//! licensed under the following conditions: -//! -//! Copyright © OASIS Open 2022. All Rights Reserved. -//! -//! All capitalized terms in the following text have the meanings assigned to them -//! in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The -//! full Policy may be found at the OASIS website. -//! -//! This document and translations of it may be copied and furnished to others, -//! and derivative works that comment on or otherwise explain it or assist in its -//! implementation may be prepared, copied, published, and distributed, in whole -//! or in part, without restriction of any kind, provided that the above copyright -//! notice and this section are included on all such copies and derivative works. -//! However, this document itself may not be modified in any way, including by -//! removing the copyright notice or references to OASIS, except as needed for the -//! purpose of developing any document or deliverable produced by an OASIS Technical -//! Committee (in which case the rules applicable to copyrights, as set forth in the -//! OASIS IPR Policy, must be followed) or as required to translate it into languages -//! other than English. - -use std::sync::atomic::{AtomicU16, AtomicU32, AtomicU64, Ordering}; - -use crate::utils::{IncompleteArrayField, VolatileCell}; -use static_assertions::const_assert_eq; - -/// [2.7.5 The Virtqueue Descriptor table](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-430005) -#[repr(C, align(16))] -pub struct Descriptor { - /// Address (guest-physical). - address: AtomicU64, - /// Size of the descriptor. - size: AtomicU32, - flags: AtomicU16, - /// Next field if flags & NEXT - next: AtomicU16, -} - -const_assert_eq!(core::mem::size_of::(), 16); - -bitflags::bitflags! { - #[derive(Debug, Copy, Clone)] - #[repr(transparent)] - pub struct DescriptorFlags: u16 { - /// This marks a buffer as continuing via the next field. - const NEXT = 1 << 0; - /// This marks a buffer as device write-only (otherwise device read-only). - const WRITE_ONLY = 1 << 1; - /// This means the buffer contains a list of buffer descriptors. - const INDIRECT = 1 << 2; - } -} - -impl Descriptor { - pub fn set_addr(&self, addr: u64) { - self.address.store(addr, Ordering::SeqCst) - } - - pub fn set_size(&self, size: u32) { - self.size.store(size, Ordering::SeqCst) - } - - pub fn set_next(&self, next: Option) { - self.next.store(next.unwrap_or_default(), Ordering::SeqCst) - } - - pub fn set_flags(&self, flags: DescriptorFlags) { - self.flags.store(flags.bits(), Ordering::SeqCst) - } - - pub fn next(&self) -> u16 { - self.next.load(Ordering::SeqCst) - } - - pub fn flags(&self) -> DescriptorFlags { - DescriptorFlags::from_bits_truncate(self.flags.load(Ordering::SeqCst)) - } -} - -// ======== Available Ring ======== -// -// XXX: The driver uses the available ring to offer buffers to the -// device. Each ring entry refers to the head of a descriptor -// chain. - -/// [2.7.6 The Virtqueue Available Ring](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-490006) -#[repr(C, align(2))] -pub struct AvailableRing { - pub flags: VolatileCell, - pub head_index: AtomicU16, - pub elements: IncompleteArrayField, -} - -const_assert_eq!(core::mem::size_of::(), 4); - -#[repr(C)] -pub struct AvailableRingElement { - pub table_index: AtomicU16, -} - -impl AvailableRingElement { - pub fn set_table_index(&self, index: u16) { - self.table_index.store(index, Ordering::SeqCst) - } -} - -const_assert_eq!(core::mem::size_of::(), 2); - -#[repr(C)] -pub struct AvailableRingExtra { - pub avail_event: VolatileCell, // Only if `VIRTIO_F_EVENT_IDX` -} - -const_assert_eq!(core::mem::size_of::(), 2); - -// ======== Used Ring ======== - -/// [2.7.8 The Virtqueue Used Ring](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-540008) -#[repr(C, align(4))] -pub struct UsedRing { - pub flags: VolatileCell, - pub head_index: VolatileCell, - pub elements: IncompleteArrayField, -} - -const_assert_eq!(core::mem::size_of::(), 4); - -#[repr(C)] -pub struct UsedRingElement { - pub table_index: VolatileCell, - pub written: VolatileCell, -} - -const_assert_eq!(core::mem::size_of::(), 8); - -#[repr(C)] -pub struct UsedRingExtra { - pub event_index: VolatileCell, -} - -// ======== Utils ======== -pub struct Buffer { - pub(crate) buffer: usize, - pub(crate) size: usize, - pub(crate) flags: DescriptorFlags, -} - -impl Buffer { - pub fn new(val: &common::dma::Dma) -> Self { - Self { - buffer: val.physical(), - size: core::mem::size_of::(), - flags: DescriptorFlags::empty(), - } - } - - pub fn new_unsized(val: &common::dma::Dma<[T]>) -> Self { - Self { - buffer: val.physical(), - size: core::mem::size_of::() * val.len(), - flags: DescriptorFlags::empty(), - } - } - - pub fn new_sized(val: &common::dma::Dma<[T]>, size: usize) -> Self { - Self { - buffer: val.physical(), - size, - flags: DescriptorFlags::empty(), - } - } - - pub fn flags(mut self, flags: DescriptorFlags) -> Self { - self.flags = flags; - self - } -} - -/// XXX: The [`DescriptorFlags::NEXT`] flag is set automatically. -pub struct ChainBuilder { - buffers: Vec, -} - -impl ChainBuilder { - pub fn new() -> Self { - Self { - buffers: Vec::new(), - } - } - - pub fn chain(mut self, mut buffer: Buffer) -> Self { - buffer.flags |= DescriptorFlags::NEXT; - self.buffers.push(buffer); - self - } - - pub fn build(mut self) -> Vec { - let last_buffer = self.buffers.last_mut().expect("virtio-core: empty chain"); - last_buffer.flags.remove(DescriptorFlags::NEXT); - - self.buffers - } -} diff --git a/recipes/core/base/drivers/virtio-core/src/spec/transport_pci.rs b/recipes/core/base/drivers/virtio-core/src/spec/transport_pci.rs deleted file mode 100644 index c6cb4a8af4..0000000000 --- a/recipes/core/base/drivers/virtio-core/src/spec/transport_pci.rs +++ /dev/null @@ -1,176 +0,0 @@ -//! [4.1 Virtio Over PCI Bus](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-1150001) -//! -//! This file contains comments copied from the VirtIO specification which are -//! licensed under the following conditions: -//! -//! Copyright © OASIS Open 2022. All Rights Reserved. -//! -//! All capitalized terms in the following text have the meanings assigned to them -//! in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The -//! full Policy may be found at the OASIS website. -//! -//! This document and translations of it may be copied and furnished to others, -//! and derivative works that comment on or otherwise explain it or assist in its -//! implementation may be prepared, copied, published, and distributed, in whole -//! or in part, without restriction of any kind, provided that the above copyright -//! notice and this section are included on all such copies and derivative works. -//! However, this document itself may not be modified in any way, including by -//! removing the copyright notice or references to OASIS, except as needed for the -//! purpose of developing any document or deliverable produced by an OASIS Technical -//! Committee (in which case the rules applicable to copyrights, as set forth in the -//! OASIS IPR Policy, must be followed) or as required to translate it into languages -//! other than English. - -use super::DeviceStatusFlags; -use crate::utils::VolatileCell; -use static_assertions::const_assert_eq; - -/// [4.1.4 Virtio Structure PCI Capabilities](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-1240004) -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct PciCapability { - /// Identifies the structure. - pub cfg_type: CfgType, - /// Where to find it. - pub bar: u8, - /// Multiple capabilities of the same type. - pub id: u8, - /// Pad to a full dword. - pub padding: [u8; 2], - /// Offset within the bar. - pub offset: u32, - /// Length of the structure, in bytes. - pub length: u32, -} - -// The size of `PciCapability` is 13 bytes since the generic -// PCI fields are *not* included. -const_assert_eq!(core::mem::size_of::(), 13); - -#[derive(Debug, Copy, Clone)] -#[repr(u8)] -pub enum CfgType { - /// Common Configuration. - Common = 1, - /// Notifications. - Notify = 2, - /// ISR Status. - Isr = 3, - /// Device specific configuration. - Device = 4, - /// PCI configuration access. - PciConfig = 5, - /// Shared memory region. - SharedMemory = 8, - /// Vendor-specific data. - Vendor = 9, -} - -const_assert_eq!(core::mem::size_of::(), 1); - -#[derive(Debug)] -#[repr(C)] -pub struct CommonCfg { - // About the whole device. - /// The driver uses this to select which feature bits device_feature shows. - /// Value 0x0 selects Feature Bits 0 to 31, 0x1 selects Feature Bits 32 to 63, etc. - /// read-write - pub device_feature_select: VolatileCell, - /// The device uses this to report which feature bits it is offering to the driver: - /// the driver writes to device_feature_select to select which feature bits are presented. - /// read-only for driver - pub device_feature: VolatileCell, - /// The driver uses this to select which feature bits driver_feature shows. - /// Value 0x0 selects Feature Bits 0 to 31, 0x1 selects Feature Bits 32 to 63, etc. - /// read-write - pub driver_feature_select: VolatileCell, - /// The driver writes this to accept feature bits offered by the device. - /// Driver Feature Bits selected by driver_feature_select. - /// read-write - pub driver_feature: VolatileCell, - /// The driver sets the Configuration Vector for MSI-X. - /// read-write - pub config_msix_vector: VolatileCell, - /// The device specifies the maximum number of virtqueues supported here. - /// read-only for driver - pub num_queues: VolatileCell, - /// The driver writes the device status here (see 2.1). - /// Writing 0 into this field resets the device. - /// read-write - pub device_status: VolatileCell, - /// Configuration atomicity value. The device changes this every time the - /// configuration noticeably changes. - /// read-only for driver - pub config_generation: VolatileCell, - - // About a specific virtqueue. - /// Queue Select. The driver selects which virtqueue the following fields refer to. - /// read-write - pub queue_select: VolatileCell, - /// Queue Size. On reset, specifies the maximum queue size supported by the device. - /// This can be modified by the driver to reduce memory requirements. - /// A 0 means the queue is unavailable. - /// read-write - pub queue_size: VolatileCell, - /// The driver uses this to specify the queue vector for MSI-X. - /// read-write - pub queue_msix_vector: VolatileCell, - /// The driver uses this to selectively prevent the device from executing - /// requests from this virtqueue. 1 - enabled; 0 - disabled. - /// read-write - pub queue_enable: VolatileCell, - /// The driver reads this to calculate the offset from start of Notification - /// structure at which this virtqueue is located. Note: this is not an offset - /// in bytes. See 4.1.4.4 below. - /// read-only for driver - pub queue_notify_off: VolatileCell, - /// The driver writes the physical address of Descriptor Area here. - /// See section 2.6. - /// read-write - pub queue_desc: VolatileCell, - /// The driver writes the physical address of Driver Area here. - /// See section 2.6. - /// read-write - pub queue_driver: VolatileCell, - /// The driver writes the physical address of Device Area here. - /// See section 2.6. - /// read-write - pub queue_device: VolatileCell, - /// This field exists only if VIRTIO_F_NOTIF_CONFIG_DATA has been negotiated. - /// The driver will use this value to put it in the ’virtqueue number’ field - /// in the available buffer notification structure. See section 4.1.5.2. Note: - /// This field provides the device with flexibility to determine how virtqueues - /// will be referred to in available buffer notifications. In a trivial case the - /// device can set queue_notify_data=vqn. Some devices may benefit from providing - /// another value, for example an internal virtqueue identifier, or an internal - /// offset related to the virtqueue number. - /// read-only for driver - pub queue_notify_data: VolatileCell, - /// The driver uses this to selectively reset the queue. This field exists - /// only if VIRTIO_F_RING_RESET has been negotiated. (see 2.6.1). - /// read-write - pub queue_reset: VolatileCell, -} - -//TODO: why does this fail on x86? -#[cfg(not(target_arch = "x86"))] -const_assert_eq!(core::mem::size_of::(), 64); - -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct PciCapabilityNotify { - pub cap: PciCapability, - /// Multiplier for queue_notify_off. - notify_off_multiplier: u32, -} - -impl PciCapabilityNotify { - pub fn notify_off_multiplier(&self) -> u32 { - self.notify_off_multiplier - } -} - -const_assert_eq!(core::mem::size_of::(), 17); - -/// Vector value used to disable MSI for queue -pub const VIRTIO_MSI_NO_VECTOR: u16 = 0xffff; diff --git a/recipes/core/base/drivers/virtio-core/src/transport.rs b/recipes/core/base/drivers/virtio-core/src/transport.rs deleted file mode 100644 index d3445d2d81..0000000000 --- a/recipes/core/base/drivers/virtio-core/src/transport.rs +++ /dev/null @@ -1,696 +0,0 @@ -use crate::spec::*; -use crate::utils::align; - -use common::dma::Dma; -use event::RawEventQueue; - -use core::mem::size_of; -use core::sync::atomic::{AtomicU16, Ordering}; - -use std::fs::File; -use std::future::Future; -use std::os::fd::AsRawFd; -use std::sync::{Arc, Mutex, Weak}; -use std::task::{Poll, Waker}; - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("syscall failed")] - SyscallError(#[from] libredox::error::Error), - #[error("the device is incapable of {0:?}")] - InCapable(CfgType), -} - -/// Returns the queue part sizes in bytes. -/// -/// ## Reference -/// Section 2.7 Split Virtqueues of the specfication v1.2 describes the alignment -/// and size of the queue parts. -/// -/// ## Panics -/// If `queue_size` is not a power of two or is zero. -pub const fn queue_part_sizes(queue_size: usize) -> (usize, usize, usize) { - assert!(queue_size.is_power_of_two() && queue_size != 0); - - const DESCRIPTOR_ALIGN: usize = 16; - const AVAILABLE_ALIGN: usize = 2; - const USED_ALIGN: usize = 4; - - let queue_size = queue_size as usize; - let desc = size_of::() * queue_size; - - // `avail_header`: Size of the available ring header and the footer. - let avail_header = size_of::() + size_of::(); - let avail = avail_header + size_of::() * queue_size; - - // `used_header`: Size of the used ring header and the footer. - let used_header = size_of::() + size_of::(); - let used = used_header + size_of::() * queue_size; - - ( - align(desc, DESCRIPTOR_ALIGN).next_multiple_of(syscall::PAGE_SIZE), - align(avail, AVAILABLE_ALIGN).next_multiple_of(syscall::PAGE_SIZE), - align(used, USED_ALIGN).next_multiple_of(syscall::PAGE_SIZE), - ) -} - -pub fn spawn_irq_thread(irq_handle: &File, queue: &Arc>) { - let irq_fd = irq_handle.as_raw_fd(); - let queue_copy = queue.clone(); - - std::thread::spawn(move || { - let event_queue = RawEventQueue::new().unwrap(); - - event_queue - .subscribe(irq_fd as usize, 0, event::EventFlags::READ) - .unwrap(); - - for _ in event_queue.map(Result::unwrap) { - // Wake up the tasks waiting on the queue. - for (_, task) in queue_copy.waker.lock().unwrap().iter() { - task.wake_by_ref(); - } - } - }); -} - -pub trait NotifyBell { - fn ring(&self, queue_index: u16); -} - -pub struct PendingRequest<'a> { - queue: Arc>, - first_descriptor: u32, -} - -impl<'a> Future for PendingRequest<'a> { - type Output = u32; - - fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { - // XXX: Register the waker before checking the queue to avoid the race condition - // where you lose a notification. - self.queue - .waker - .lock() - .unwrap() - .insert(self.first_descriptor, cx.waker().clone()); - - let used_head = self.queue.used.head_index(); - - if used_head == self.queue.used_head.load(Ordering::SeqCst) { - // No new requests have been completed. - return Poll::Pending; - } - - let used_element = self.queue.used.get_element_at((used_head - 1) as usize); - let written = used_element.written.get(); - - let mut table_index = used_element.table_index.get(); - - if table_index == self.first_descriptor { - // The request has been completed; recycle the descriptors used. - while self.queue.descriptor[table_index as usize] - .flags() - .contains(DescriptorFlags::NEXT) - { - let next_index = self.queue.descriptor[table_index as usize].next(); - self.queue.descriptor_stack.push(table_index as u16); - table_index = next_index.into(); - } - - // Push the last descriptor. - self.queue.descriptor_stack.push(table_index as u16); - self.queue - .waker - .lock() - .unwrap() - .remove(&self.first_descriptor); - - self.queue.used_head.store(used_head, Ordering::SeqCst); - return Poll::Ready(written); - } else { - return Poll::Pending; - } - } -} - -pub struct Queue<'a> { - pub queue_index: u16, - pub waker: Mutex>, - pub used: Used<'a>, - pub descriptor: Dma<[Descriptor]>, - pub available: Available<'a>, - pub used_head: AtomicU16, - vector: u16, - - notification_bell: Box, - descriptor_stack: crossbeam_queue::SegQueue, - sref: Weak, -} - -impl<'a> Queue<'a> { - pub fn new( - descriptor: Dma<[Descriptor]>, - available: Available<'a>, - used: Used<'a>, - - notification_bell: N, - queue_index: u16, - vector: u16, - ) -> Arc - where - N: NotifyBell + 'static, - { - let descriptor_stack = crossbeam_queue::SegQueue::new(); - (0..descriptor.len() as u16).for_each(|i| descriptor_stack.push(i)); - - Arc::new_cyclic(|sref| Self { - notification_bell: Box::new(notification_bell), - available, - descriptor, - used, - waker: Mutex::new(std::collections::HashMap::new()), - queue_index, - descriptor_stack, - used_head: AtomicU16::new(0), - sref: sref.clone(), - vector, - }) - } - - fn reinit(&self) { - self.used_head.store(0, Ordering::SeqCst); - self.available.set_head_idx(0); - - // Drain all of the available descriptors. - while let Some(_) = self.descriptor_stack.pop() {} - - // Refill the descriptor stack. - (0..self.descriptor.len() as u16).for_each(|i| self.descriptor_stack.push(i)); - } - - #[must_use = "The function returns a future that must be awaited to ensure the sent request is completed."] - pub fn send(&self, chain: Vec) -> PendingRequest<'a> { - let mut first_descriptor: Option = None; - let mut last_descriptor: Option = None; - - for buffer in chain.iter() { - let descriptor = self.descriptor_stack.pop().unwrap() as usize; - - if first_descriptor.is_none() { - first_descriptor = Some(descriptor); - } - - self.descriptor[descriptor].set_addr(buffer.buffer as u64); - self.descriptor[descriptor].set_flags(buffer.flags); - self.descriptor[descriptor].set_size(buffer.size as u32); - - if let Some(index) = last_descriptor { - self.descriptor[index].set_next(Some(descriptor as u16)); - } - - last_descriptor = Some(descriptor); - } - - let last_descriptor = last_descriptor.unwrap(); - let first_descriptor = first_descriptor.unwrap(); - - self.descriptor[last_descriptor].set_next(None); - - let index = self.available.head_index() as usize; - - self.available - .get_element_at(index) - .set_table_index(first_descriptor as u16); - - self.available.set_head_idx(index as u16 + 1); - self.notification_bell.ring(self.queue_index); - - PendingRequest { - queue: self.sref.upgrade().unwrap(), - first_descriptor: first_descriptor as u32, - } - } - - /// Returns the number of descriptors in the descriptor table of this queue. - pub fn descriptor_len(&self) -> usize { - self.descriptor.len() - } -} - -unsafe impl Sync for Queue<'_> {} -unsafe impl Send for Queue<'_> {} - -pub struct Available<'a> { - mem: Mem<'a>, - queue_size: usize, -} -pub struct Borrowed<'a> { - phys: usize, - virt: usize, - size: usize, - _unused: &'a (), -} -pub enum Mem<'a> { - Owned(Dma<[u8]>), - Borrowed(Borrowed<'a>), -} -impl Borrowed<'_> { - pub unsafe fn new(phys: usize, virt: usize, size: usize) -> Self { - Self { - phys, - virt, - size, - _unused: &(), - } - } -} -impl<'a> Mem<'a> { - pub fn as_ptr(&self) -> *const T { - match *self { - Self::Owned(ref dma) => dma.as_ptr().cast(), - Self::Borrowed(Borrowed { - phys: _, - virt, - size: _, - _unused, - }) => virt as *const T, - } - } - pub fn as_mut_ptr(&mut self) -> *mut T { - match *self { - Self::Owned(ref mut dma) => dma.as_mut_ptr().cast(), - Self::Borrowed(Borrowed { - phys: _, - virt, - size: _, - _unused, - }) => virt as *mut T, - } - } - pub fn physical(&self) -> usize { - match self { - Self::Owned(dma) => dma.physical(), - Self::Borrowed(borrowed) => borrowed.phys, - } - } -} - -impl<'a> Available<'a> { - pub fn ring(&self) -> &AvailableRing { - unsafe { &*self.mem.as_ptr() } - } - pub fn ring_mut(&mut self) -> &mut AvailableRing { - unsafe { &mut *self.mem.as_mut_ptr() } - } - pub fn new(queue_size: usize) -> Result { - let (_, _, size) = queue_part_sizes(queue_size); - let mem = unsafe { - Dma::zeroed_slice(size) - .map_err(Error::SyscallError)? - .assume_init() - }; - - unsafe { Self::from_raw(Mem::Owned(mem), queue_size) } - } - - /// `addr` is the physical address of the ring. - pub unsafe fn from_raw(mem: Mem<'a>, queue_size: usize) -> Result { - let ring = Self { mem, queue_size }; - - for i in 0..queue_size { - // Setting them to `u16::MAX` helps with debugging since qemu reports them - // as illegal values. - ring.get_element_at(i) - .table_index - .store(u16::MAX, Ordering::SeqCst); - } - - Ok(ring) - } - - /// ## Panics - /// This function panics if the index is out of bounds. - pub fn get_element_at(&self, index: usize) -> &AvailableRingElement { - // SAFETY: We have exclusive access to the elements and the number of elements - // is correct; same as the queue size. - unsafe { - self.ring() - .elements - .as_slice(self.queue_size) - .get(index % self.queue_size) - .expect("virtio-core::available: index out of bounds") - } - } - - pub fn head_index(&self) -> u16 { - self.ring().head_index.load(Ordering::SeqCst) - } - - pub fn set_head_idx(&self, index: u16) { - self.ring().head_index.store(index, Ordering::SeqCst); - } - - pub fn phys_addr(&self) -> usize { - self.mem.physical() - } -} - -impl<'a> Drop for Available<'a> { - fn drop(&mut self) { - log::warn!( - "virtio-core: dropping 'available' ring at {:#x}", - self.phys_addr() - ); - } -} - -pub struct Used<'a> { - mem: Mem<'a>, - queue_size: usize, - _unused: &'a (), -} - -impl<'a> Used<'a> { - fn ring(&self) -> &UsedRing { - unsafe { &*self.mem.as_ptr() } - } - fn ring_mut(&mut self) -> &mut UsedRing { - unsafe { &mut *self.mem.as_mut_ptr() } - } - - pub fn new(queue_size: usize) -> Result { - let (_, _, size) = queue_part_sizes(queue_size); - let mem = unsafe { - Dma::zeroed_slice(size) - .map_err(Error::SyscallError)? - .assume_init() - }; - - unsafe { Self::from_raw(Mem::Owned(mem), queue_size) } - } - - /// `addr` is the physical address of the ring. - pub unsafe fn from_raw(mem: Mem<'a>, queue_size: usize) -> Result { - let mut ring = Self { - mem, - queue_size, - _unused: &(), - }; - - for i in 0..queue_size { - // Setting them to `u32::MAX` helps with debugging since qemu reports them - // as illegal values. - ring.get_mut_element_at(i).table_index.set(u32::MAX); - } - - Ok(ring) - } - - /// ## Panics - /// This function panics if the index is out of bounds. - pub fn get_element_at(&self, index: usize) -> &UsedRingElement { - // SAFETY: We have exclusive access to the elements and the number of elements - // is correct; same as the queue size. - unsafe { - self.ring() - .elements - .as_slice(self.queue_size) - .get(index % self.queue_size) - .expect("virtio-core::used: index out of bounds") - } - } - - /// ## Panics - /// This function panics if the index is out of bounds. - pub fn get_mut_element_at(&mut self, index: usize) -> &mut UsedRingElement { - // SAFETY: We have exclusive access to the elements and the number of elements - // is correct; same as the queue size. - let queue_size = self.queue_size; - unsafe { - self.ring_mut() - .elements - .as_mut_slice(queue_size) - .get_mut(index % 256) - .expect("virtio-core::used: index out of bounds") - } - } - - pub fn flags(&self) -> u16 { - self.ring().flags.get() - } - - pub fn head_index(&self) -> u16 { - self.ring().head_index.get() - } - - pub fn phys_addr(&self) -> usize { - self.mem.physical() - } -} - -impl Drop for Used<'_> { - fn drop(&mut self) { - log::warn!( - "virtio-core: dropping 'used' ring at {:#x}", - self.phys_addr() - ); - } -} - -pub trait Transport: Sync + Send { - /// `size` specifies the size of the read in bytes. - /// - /// ## Panics - /// This function panics if the provided `size` is more then `size_of::()`. - fn load_config(&self, offset: u8, size: u8) -> u64; - - /// Resets the device. - fn reset(&self); - - /// Returns whether the device supports the specified feature. - fn check_device_feature(&self, feature: u32) -> bool; - - /// Acknowledges the specified feature. - /// - /// **Note**: [`Transport::check_device_feature`] must be used to check whether - /// the device supports the feature before acknowledging it. - fn ack_driver_feature(&self, feature: u32); - - /// Finalizes the acknowledged features by setting the `FEATURES_OK` bit in the - /// device status flags. - fn finalize_features(&self); - - /// Runs the device. - /// - /// At this point, all of the queues must be created and the features must be - /// finalized. - /// - /// ## Panics - /// This function panics if the device is already running. - fn run_device(&self) { - self.insert_status(DeviceStatusFlags::DRIVER_OK); - } - - /// Request to be notified on configuration changes on the given MSI-X vector. - fn setup_config_notify(&self, vector: u16); - - /// Each time the device configuration changes this number will be updated. - fn config_generation(&self) -> u32; - - /// Creates a new queue. - /// - /// ## Panics - /// This function panics if the device is running. - fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result>, Error>; - - // TODO(andypython): Should this function be unsafe? - fn reinit_queue(&self, queue: Arc); - fn insert_status(&self, status: DeviceStatusFlags); -} - -struct StandardBell<'a>(&'a mut AtomicU16); - -impl NotifyBell for StandardBell<'_> { - #[inline] - fn ring(&self, queue_index: u16) { - self.0.store(queue_index, Ordering::SeqCst); - } -} - -pub struct StandardTransport<'a> { - pub(crate) common: Mutex<&'a mut CommonCfg>, - notify: *const u8, - notify_mul: u32, - device_space: *const u8, - - queue_index: AtomicU16, -} - -impl<'a> StandardTransport<'a> { - pub fn new( - common: &'a mut CommonCfg, - notify: *const u8, - notify_mul: u32, - device_space: *const u8, - ) -> Arc { - Arc::new(Self { - common: Mutex::new(common), - notify, - notify_mul, - - queue_index: AtomicU16::new(0), - device_space, - }) - } -} - -impl Transport for StandardTransport<'_> { - fn load_config(&self, offset: u8, size: u8) -> u64 { - unsafe { - let ptr = self.device_space.add(offset as usize); - let size = size as usize; - - if size == size_of::() { - ptr.cast::().read() as u64 - } else if size == size_of::() { - ptr.cast::().read() as u64 - } else if size == size_of::() { - ptr.cast::().read() as u64 - } else if size == size_of::() { - ptr.cast::().read() as u64 - } else { - unreachable!() - } - } - } - - fn reset(&self) { - let mut common = self.common.lock().unwrap(); - - common.device_status.set(DeviceStatusFlags::empty()); - // Upon reset, the device must initialize device status to 0. - assert_eq!(common.device_status.get(), DeviceStatusFlags::empty()); - } - - fn check_device_feature(&self, feature: u32) -> bool { - let mut common = self.common.lock().unwrap(); - - common.device_feature_select.set(feature >> 5); - (common.device_feature.get() & (1 << (feature & 31))) != 0 - } - - fn ack_driver_feature(&self, feature: u32) { - let mut common = self.common.lock().unwrap(); - - common.driver_feature_select.set(feature >> 5); - - let current = common.driver_feature.get(); - common.driver_feature.set(current | (1 << (feature & 31))); - } - - fn finalize_features(&self) { - // Check VirtIO version 1 compliance. - assert!(self.check_device_feature(VIRTIO_F_VERSION_1)); - self.ack_driver_feature(VIRTIO_F_VERSION_1); - - let mut common = self.common.lock().unwrap(); - - let status = common.device_status.get(); - common - .device_status - .set(status | DeviceStatusFlags::FEATURES_OK); - - // Re-read device status to ensure the `FEATURES_OK` bit is still set: otherwise, - // the device does not support our subset of features and the device is unusable. - let confirm = common.device_status.get(); - assert!((confirm & DeviceStatusFlags::FEATURES_OK) == DeviceStatusFlags::FEATURES_OK); - } - - fn setup_config_notify(&self, vector: u16) { - self.common.lock().unwrap().config_msix_vector.set(vector); - } - - fn config_generation(&self) -> u32 { - u32::from(self.common.lock().unwrap().config_generation.get()) - } - - fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result>, Error> { - let mut common = self.common.lock().unwrap(); - - let queue_index = self.queue_index.fetch_add(1, Ordering::SeqCst); - common.queue_select.set(queue_index); - - let queue_size = common.queue_size.get() as usize; - let queue_notify_idx = common.queue_notify_off.get(); - - // Allocate memory for the queue structues. - let descriptor = unsafe { - Dma::<[Descriptor]>::zeroed_slice(queue_size) - .map_err(Error::SyscallError)? - .assume_init() - }; - - let avail = Available::new(queue_size)?; - let used = Used::new(queue_size)?; - - common.queue_desc.set(descriptor.physical() as u64); - common.queue_driver.set(avail.phys_addr() as u64); - common.queue_device.set(used.phys_addr() as u64); - - // Set the MSI-X vector. - common.queue_msix_vector.set(vector); - assert!(common.queue_msix_vector.get() == vector); - - // Enable the queue. - common.queue_enable.set(1); - - let notification_bell = unsafe { - let offset = self.notify_mul * queue_notify_idx as u32; - &mut *(self.notify.add(offset as usize) as *mut AtomicU16) - }; - - log::debug!("virtio-core: enabled queue #{queue_index} (size={queue_size})"); - - let queue = Queue::new( - descriptor, - avail, - used, - StandardBell(notification_bell), - queue_index, - vector, - ); - - spawn_irq_thread(irq_handle, &queue); - Ok(queue) - } - - fn insert_status(&self, status: DeviceStatusFlags) { - let mut common = self.common.lock().unwrap(); - let old = common.device_status.get(); - - common.device_status.set(old | status); - } - - /// Re-initializes a queue; usually done after a device reset. - fn reinit_queue(&self, queue: Arc) { - let mut common = self.common.lock().unwrap(); - queue.reinit(); - - common.queue_select.set(queue.queue_index); - - common.queue_desc.set(queue.descriptor.physical() as u64); - common.queue_driver.set(queue.available.phys_addr() as u64); - common.queue_device.set(queue.used.phys_addr() as u64); - - // Set the MSI-X vector. - common.queue_msix_vector.set(queue.vector); - assert!(common.queue_msix_vector.get() == queue.vector); - - // Enable the queue. - common.queue_enable.set(1); - } -} - -unsafe impl Send for StandardTransport<'_> {} -unsafe impl Sync for StandardTransport<'_> {} diff --git a/recipes/core/base/drivers/virtio-core/src/utils.rs b/recipes/core/base/drivers/virtio-core/src/utils.rs deleted file mode 100644 index 76d8ff7eb7..0000000000 --- a/recipes/core/base/drivers/virtio-core/src/utils.rs +++ /dev/null @@ -1,80 +0,0 @@ -use core::cell::UnsafeCell; -use core::fmt::Debug; -use core::marker::PhantomData; - -#[repr(C)] -pub struct VolatileCell { - value: UnsafeCell, -} - -impl VolatileCell { - #[inline] - pub const fn new(value: T) -> Self { - Self { - value: UnsafeCell::new(value), - } - } - - /// Returns a copy of the contained value. - #[inline] - pub fn get(&self) -> T { - unsafe { core::ptr::read_volatile(self.value.get()) } - } - - /// Sets the contained value. - #[inline] - pub fn set(&mut self, value: T) { - unsafe { core::ptr::write_volatile(self.value.get(), value) } - } -} - -impl Debug for VolatileCell -where - T: Debug + Copy, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("VolatileCell") - .field("value", &self.get()) - .finish() - } -} - -unsafe impl Sync for VolatileCell {} - -#[repr(C)] -pub struct IncompleteArrayField(PhantomData, [T; 0]); - -impl IncompleteArrayField { - #[inline] - pub const fn new() -> Self { - IncompleteArrayField(PhantomData, []) - } - - #[inline] - pub unsafe fn as_slice(&self, len: usize) -> &[T] { - core::slice::from_raw_parts(self.as_ptr(), len) - } - - #[inline] - pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { - core::slice::from_raw_parts_mut(self.as_mut_ptr(), len) - } - - #[inline] - pub unsafe fn as_ptr(&self) -> *const T { - self as *const _ as *const T - } - - #[inline] - pub unsafe fn as_mut_ptr(&mut self) -> *mut T { - self as *mut _ as *mut T - } -} - -pub const fn align(val: usize, align: usize) -> usize { - (val + align) & !align -} - -pub const fn align_down(addr: usize) -> usize { - addr & !(syscall::PAGE_SIZE - 1) -} diff --git a/recipes/core/base/fmt.sh b/recipes/core/base/fmt.sh deleted file mode 100755 index 007766e270..0000000000 --- a/recipes/core/base/fmt.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/bash - -set -eo pipefail - -printf "\e[1;32mFormatting\e[0m $dir\n" -if [[ "$CHECK_ONLY" -eq "1" ]]; then - cargo fmt --all --check -else - cargo fmt --all -fi diff --git a/recipes/core/base/init/Cargo.toml b/recipes/core/base/init/Cargo.toml deleted file mode 100644 index b0ae14a873..0000000000 --- a/recipes/core/base/init/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "init" -description = "Userspace process launcher" -version = "0.1.0" -edition = "2024" -license = "MIT" - -[dependencies] -libc.workspace = true -libredox.workspace = true -plain.workspace = true -redox_syscall.workspace = true -serde.workspace = true -serde_json.workspace = true -toml.workspace = true - -config = { path = "../config" } - -[lints] -workspace = true diff --git a/recipes/core/base/init/src/color.rs b/recipes/core/base/init/src/color.rs deleted file mode 100644 index db792c441f..0000000000 --- a/recipes/core/base/init/src/color.rs +++ /dev/null @@ -1,27 +0,0 @@ -pub fn status_ok(msg: &str) { - eprintln!("[ OK ] {msg}"); -} - -pub fn status_fail(msg: &str) { - eprintln!("[ FAILED ] {msg}"); -} - -pub fn status_skip(msg: &str) { - eprintln!("[ SKIP ] {msg}"); -} - -pub fn init_error(msg: &str) { - eprintln!("init: {msg}"); -} - -pub fn init_warn(msg: &str) { - eprintln!("init: {msg}"); -} - -pub fn init_info(msg: &str) { - eprintln!("init: {msg}"); -} - -pub fn init_debug(msg: &str) { - eprintln!("init: {msg}"); -} diff --git a/recipes/core/base/init/src/main.rs b/recipes/core/base/init/src/main.rs deleted file mode 100644 index e78a669990..0000000000 --- a/recipes/core/base/init/src/main.rs +++ /dev/null @@ -1,196 +0,0 @@ -use std::collections::BTreeMap; -use std::ffi::OsString; -use std::path::Path; -use std::{env, fs, io}; - -use libredox::flag::{O_RDONLY, O_WRONLY}; - -use crate::scheduler::Scheduler; -use crate::unit::{UnitId, UnitStore}; - -mod scheduler; -mod script; -mod service; -mod unit; - -fn switch_stdio(stdio: &str) -> io::Result<()> { - let stdin = libredox::Fd::open(stdio, O_RDONLY, 0)?; - let stdout = libredox::Fd::open(stdio, O_WRONLY, 0)?; - let stderr = libredox::Fd::open(stdio, O_WRONLY, 0)?; - - stdin.dup2(0, &[])?; - stdout.dup2(1, &[])?; - stderr.dup2(2, &[])?; - - Ok(()) -} - -struct InitConfig { - log_debug: bool, - skip_cmd: Vec, - envs: BTreeMap, -} - -impl InitConfig { - fn new() -> Self { - let log_level = env::var("INIT_LOG_LEVEL").unwrap_or("INFO".into()); - let log_debug = matches!(log_level.as_str(), "DEBUG" | "TRACE"); - let skip_cmd: Vec = match env::var("INIT_SKIP") { - Ok(v) if v.len() > 0 => v.split(',').map(|s| s.to_string()).collect(), - _ => Vec::new(), - }; - - Self { - log_debug, - skip_cmd, - envs: BTreeMap::from([("RUST_BACKTRACE".to_owned(), "1".into())]), - } - } -} - -fn switch_root(unit_store: &mut UnitStore, config: &mut InitConfig, prefix: &Path, etcdir: &Path) { - eprintln!( - "init: switchroot to {} {}", - prefix.display(), - etcdir.display() - ); - - config - .envs - .insert("PATH".to_owned(), prefix.join("bin").into_os_string()); - config.envs.insert( - "LD_LIBRARY_PATH".to_owned(), - prefix.join("lib").into_os_string(), - ); - - unit_store.config_dirs = vec![prefix.join("lib").join("init.d"), etcdir.join("init.d")]; - - let env_dirs = &[ - prefix.join("lib").join("environment.d"), - etcdir.join("environment.d"), - ]; - match config::config_for_dirs(env_dirs) { - Ok(files) => { - for file in files { - match fs::read_to_string(&file) { - Ok(envs) => { - for env in envs.lines() { - if env.is_empty() || env.starts_with("#") { - continue; - } - let Some((key, value)) = env.split_once('=') else { - eprintln!( - "init: failed to parse env line from {}: {env:?}", - file.display(), - ); - continue; - }; - config - .envs - .insert(key.to_owned().into(), value.to_owned().into()); - } - } - Err(err) => { - eprintln!( - "init: failed to read environment from {}: {err}", - file.display(), - ); - } - } - } - } - Err(err) => { - eprintln!( - "init: failed to read environments from {}: {err}", - env_dirs - .iter() - .map(|dir| dir.display().to_string()) - .collect::>() - .join(", ") - ); - } - } -} - -fn main() { - let mut init_config = InitConfig::new(); - let mut unit_store = UnitStore::new(); - let mut scheduler = Scheduler::new(); - - switch_root( - &mut unit_store, - &mut init_config, - Path::new("/scheme/initfs"), - Path::new("/scheme/initfs/etc"), - ); - - // Start logd first such that we can pass /scheme/log as stdio to all other services - scheduler - .schedule_start_and_report_errors(&mut unit_store, UnitId("00_logd.service".to_owned())); - scheduler.step(&mut unit_store, &mut init_config); - if let Err(err) = switch_stdio("/scheme/log") { - eprintln!("init: failed to switch stdio to '/scheme/log': {err}"); - } - - let runtime_target = UnitId("00_runtime.target".to_owned()); - scheduler.schedule_start_and_report_errors(&mut unit_store, runtime_target.clone()); - unit_store.set_runtime_target(runtime_target); - - scheduler - .schedule_start_and_report_errors(&mut unit_store, UnitId("90_initfs.target".to_owned())); - scheduler.step(&mut unit_store, &mut init_config); - - switch_root( - &mut unit_store, - &mut init_config, - Path::new("/usr"), - Path::new("/etc"), - ); - { - // FIXME introduce multi-user.target unit and replace the config dir iteration - // scheduler.schedule_start_and_report_errors(&mut unit_store, UnitId("multi-user.target".to_owned())); - - let entries = match config::config_for_dirs(&unit_store.config_dirs) { - Ok(entries) => entries, - Err(err) => { - eprintln!( - "init: failed to read configs from {}: {err}", - unit_store - .config_dirs - .iter() - .map(|dir| dir.display().to_string()) - .collect::>() - .join(", ") - ); - return; - } - }; - for entry in entries { - let Some(file_name) = entry.file_name().and_then(|n| n.to_str()) else { - eprintln!("init: skipping entry with invalid filename: {}", entry.display()); - continue; - }; - scheduler.schedule_start_and_report_errors( - &mut unit_store, - UnitId(file_name.to_owned()), - ); - } - }; - - eprintln!("init: DEBUG step start — {} jobs pending", scheduler.pending_len()); - scheduler.step(&mut unit_store, &mut init_config); - eprintln!("init: DEBUG step done — entering waitpid loop"); - - if let Err(err) = libredox::call::setrens(0, 0) { - eprintln!("init: failed to enter null namespace: {}", err); - return; - } - - loop { - let mut status = 0; - match libredox::call::waitpid(0, &mut status, 0) { - Ok(()) => {} - Err(err) => eprintln!("init: waitpid error: {}", err), - } - } -} diff --git a/recipes/core/base/init/src/scheduler.rs b/recipes/core/base/init/src/scheduler.rs deleted file mode 100644 index 44215bbba5..0000000000 --- a/recipes/core/base/init/src/scheduler.rs +++ /dev/null @@ -1,350 +0,0 @@ -use std::collections::VecDeque; -use std::io::Read; -use std::os::fd::AsRawFd; -use std::os::unix::process::CommandExt; -use std::process::Command; -use std::time::Duration; -use std::{env, io}; - -use crate::InitConfig; -use crate::service::ServiceType; -use crate::unit::{RestartPolicy, UnitId, UnitKind, UnitStore}; - -const MAX_DEPENDENCY_WAIT_RETRIES: u32 = 1000; - -pub struct Scheduler { - pending: VecDeque, -} - -struct Job { - unit: UnitId, - kind: JobKind, - dep_retries: u32, -} - -enum JobKind { - Start, - Restart { backoff: Duration }, -} - -impl Scheduler { - pub fn new() -> Scheduler { - Scheduler { - pending: VecDeque::new(), - } - } - - pub fn schedule_start_and_report_errors( - &mut self, - unit_store: &mut UnitStore, - unit_id: UnitId, - ) { - let mut errors = vec![]; - self.schedule_start(unit_store, unit_id, &mut errors); - for error in errors { - eprintln!("init: {error}"); - } - } - - pub fn schedule_start( - &mut self, - unit_store: &mut UnitStore, - unit_id: UnitId, - errors: &mut Vec, - ) { - let loaded_units = unit_store.load_units(unit_id.clone(), errors); - for unit_id in loaded_units { - if !unit_store.unit(&unit_id).conditions_met() { - continue; - } - - self.pending.push_back(Job { - unit: unit_id, - kind: JobKind::Start, - dep_retries: 0, - }); - } - } - - pub fn pending_len(&self) -> usize { - self.pending.len() - } - - pub fn step(&mut self, unit_store: &mut UnitStore, init_config: &mut InitConfig) { - 'a: loop { - let Some(mut job) = self.pending.pop_front() else { - return; - }; - - match job.kind { - JobKind::Start => { - let unit = unit_store.unit(&job.unit); - eprintln!( - "init: DEBUG processing {} ({}) — deps: {:?}", - job.unit.0, - match &unit.kind { - crate::unit::UnitKind::LegacyScript { .. } => "script", - crate::unit::UnitKind::Service { service } => &service.cmd, - crate::unit::UnitKind::Target { .. } => "target", - }, - unit.info.requires_weak.iter().map(|u| &u.0).collect::>() - ); - - let timeout_secs = unit.info.dependency_timeout_secs; - let mut deps_pending = false; - for dep in &unit.info.requires_weak { - for pending_job in &self.pending { - if &pending_job.unit == dep { - deps_pending = true; - break; - } - } - if deps_pending { - break; - } - } - - if deps_pending { - eprintln!( - "init: DEBUG {} waiting for deps (retry {})", - job.unit.0, job.dep_retries - ); - if timeout_secs > 0 { - job.dep_retries += 1; - let max_retries = timeout_secs * 100; // ~10ms per retry - if job.dep_retries > max_retries as u32 { - eprintln!( - "init: {}: dependency timeout after {}s, failing", - job.unit.0, timeout_secs - ); - continue; - } - } else if job.dep_retries >= MAX_DEPENDENCY_WAIT_RETRIES { - eprintln!( - "init: {}: dependency wait exceeded {} retries, failing", - job.unit.0, MAX_DEPENDENCY_WAIT_RETRIES - ); - continue; - } - job.dep_retries += 1; - self.pending.push_back(job); - continue 'a; - } - - if let Err(restart) = run(unit_store, &job.unit, init_config) { - if let Some(backoff) = restart { - self.pending.push_back(Job { - unit: job.unit.clone(), - kind: JobKind::Restart { backoff }, - dep_retries: 0, - }); - } - } - } - JobKind::Restart { backoff } => { - std::thread::sleep(backoff); - let next_backoff = (backoff * 2).min(Duration::from_secs(60)); - if let Err(restart) = run(unit_store, &job.unit, init_config) { - if let Some(_next) = restart { - self.pending.push_back(Job { - unit: job.unit, - kind: JobKind::Restart { - backoff: next_backoff, - }, - dep_retries: 0, - }); - } - } - } - } - } - } -} - -fn run( - unit_store: &UnitStore, - unit_id: &UnitId, - config: &mut InitConfig, -) -> Result<(), Option> { - let unit = unit_store.unit(unit_id); - - let restart_policy = unit.info.restart; - - match &unit.kind { - UnitKind::LegacyScript { script } => { - for cmd in script.clone() { - if config.log_debug { - eprintln!("init: running: {cmd:?}"); - } - cmd.run(config); - } - Ok(()) - } - UnitKind::Service { service } => { - if config.skip_cmd.contains(&service.cmd) { - eprintln!("Skipping '{} {}'", service.cmd, service.args.join(" ")); - return Ok(()); - } - if config.log_debug { - eprintln!( - "Starting {} ({})", - unit.info.description.as_ref().unwrap_or(&unit.id.0), - service.cmd, - ); - } - - let mut command = Command::new(&service.cmd); - command.args(&service.args); - command.env_clear(); - for env in &service.inherit_envs { - if let Some(value) = env::var_os(env) { - command.env(env, value); - } - } - command.envs(config.envs.iter().map(|(k, v)| (k.as_str(), v.as_os_str()))); - - let (read_pipe, write_pipe) = match io::pipe() { - Ok(p) => p, - Err(err) => { - eprintln!("init: pipe failed for {}: {}", service.cmd, err); - return Err(restart_signal(restart_policy)); - } - }; - - let write_fd: std::os::fd::OwnedFd = write_pipe.into(); - unsafe { - command.env("INIT_NOTIFY", format!("{}", write_fd.as_raw_fd())); - command.pre_exec(move || { - if unsafe { libc::fcntl(write_fd.as_raw_fd(), libc::F_SETFD, 0) } == -1 { - Err(io::Error::last_os_error()) - } else { - Ok(()) - } - }); - } - - let status = service_spawn_status(read_pipe, command, &service.type_, &service.cmd); - - match status { - SpawnStatus::Success => Ok(()), - SpawnStatus::Failed => Err(restart_signal(restart_policy)), - SpawnStatus::Async => Ok(()), - } - } - UnitKind::Target {} => { - if config.log_debug { - eprintln!( - "Reached target {}", - unit.info.description.as_ref().unwrap_or(&unit.id.0), - ); - } - Ok(()) - } - } -} - -enum SpawnStatus { - Success, - Failed, - Async, -} - -fn restart_signal(policy: RestartPolicy) -> Option { - match policy { - RestartPolicy::No => None, - RestartPolicy::OnFailure | RestartPolicy::Always => Some(Duration::from_secs(1)), - } -} - -fn service_spawn_status( - mut read_pipe: impl Read + AsRawFd, - mut command: Command, - service_type: &ServiceType, - cmd: &str, -) -> SpawnStatus { - let mut child = match command.spawn() { - Ok(child) => child, - Err(err) => { - eprintln!("init: failed to execute {}: {}", cmd, err); - return SpawnStatus::Failed; - } - }; - - match service_type { - ServiceType::Notify => match read_pipe.read_exact(&mut [0]) { - Ok(()) => SpawnStatus::Success, - Err(err) if err.kind() == io::ErrorKind::UnexpectedEof => { - eprintln!("init: {cmd} exited without notifying readiness"); - SpawnStatus::Failed - } - Err(err) => { - eprintln!("init: failed to wait for {cmd}: {err}"); - SpawnStatus::Failed - } - }, - ServiceType::Scheme(scheme) => { - let scheme = scheme.clone(); - let mut new_fd = usize::MAX; - let res = loop { - match syscall::call_ro( - read_pipe.as_raw_fd() as usize, - unsafe { plain::as_mut_bytes(&mut new_fd) }, - syscall::CallFlags::FD | syscall::CallFlags::FD_UPPER, - &[], - ) { - Err(syscall::Error { - errno: syscall::EINTR, - }) => continue, - Ok(0) => break SpawnStatus::Failed, - Ok(1) => break SpawnStatus::Success, - Ok(n) => { - eprintln!("init: incorrect amount of fds {n} returned from {cmd}"); - break SpawnStatus::Failed; - } - Err(err) => { - eprintln!("init: failed to wait for {cmd}: {err}"); - break SpawnStatus::Failed; - } - } - }; - - if matches!(res, SpawnStatus::Success) { - match libredox::call::getns() { - Ok(current_namespace_fd) => { - if let Err(err) = libredox::call::register_scheme_to_ns( - current_namespace_fd, - &scheme, - new_fd, - ) { - eprintln!("init: scheme registration failed for {cmd}: {err}"); - return SpawnStatus::Failed; - } - } - Err(err) => { - eprintln!("init: getns failed for {cmd}: {err}"); - return SpawnStatus::Failed; - } - } - } - res - } - ServiceType::Oneshot => { - drop(read_pipe); - match child.wait() { - Ok(exit_status) => { - if !exit_status.success() { - eprintln!("init: {cmd} failed with {exit_status}"); - SpawnStatus::Failed - } else { - SpawnStatus::Success - } - } - Err(err) => { - eprintln!("init: failed to wait for {cmd}: {err}"); - SpawnStatus::Failed - } - } - } - ServiceType::OneshotAsync => SpawnStatus::Async, - } -} diff --git a/recipes/core/base/init/src/script.rs b/recipes/core/base/init/src/script.rs deleted file mode 100644 index d18e3a045b..0000000000 --- a/recipes/core/base/init/src/script.rs +++ /dev/null @@ -1,163 +0,0 @@ -use std::collections::BTreeMap; -use std::{env, io, iter}; - -use crate::InitConfig; -use crate::unit::UnitId; - -pub fn subst_env<'a>(arg: &str) -> String { - if arg.starts_with('$') { - env::var(&arg[1..]).unwrap_or(String::new()) - } else { - arg.to_owned() - } -} - -pub struct Script(pub Vec, pub Vec); - -impl Script { - pub fn from_str(config: &str, errors: &mut Vec) -> io::Result