diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml new file mode 100644 index 000000000..e02a61097 --- /dev/null +++ b/.github/workflows/appimage.yml @@ -0,0 +1,53 @@ +name: Continuous Integration + +on: [push, pull_request] + +jobs: + build-appimage: + name: Linux Clang 12 | AppImage + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Install GZDoom dependencies + run: | + sudo apt-get update + sudo apt-get install clang-12 libsdl2-dev libvpx-dev cmake -y + - name: Install appimage-builder dependencies + run: | + sudo apt-get install binutils coreutils desktop-file-utils fakeroot fuse libgdk-pixbuf2.0-dev patchelf -y + sudo apt-get install python3-pip python3-setuptools squashfs-tools strace util-linux zsync -y + sudo apt-get install imagemagick-6.q16hdri -y + - name: Install appimage-builder + run: | + python3 -m pip install --upgrade pip + pip install appimage-builder + - name: Build zmusic dependency + run: | + git clone -b 1.1.12 https://github.com/ZDoom/ZMusic.git zmusic_build + mkdir ./zmusic_build/build + cd ./zmusic_build/build + cmake -DCMAKE_BUILD_TYPE=Release .. + cmake --build . + cd ../../ + mkdir -p ./AppDir/zmusic/lib + mkdir ./AppDir/zmusic/include + mv ./zmusic_build/build/source/libzmusic* ./AppDir/zmusic/lib/ + mv ./zmusic_build/include/zmusic.h ./AppDir/zmusic/include/ + - name: Configure + run: cmake -B AppDir -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_PREFIX_PATH=`pwd`/AppDir/zmusic -DPK3_QUIET_ZIPDIR=ON -DCMAKE_C_COMPILER=clang-12 -DCMAKE_CXX_COMPILER=clang++-12 . + - name: Build + shell: bash + run: | + export MAKEFLAGS=--keep-going + cmake --build AppDir --config Release --parallel `nproc` + cp ./AppDir/zmusic/lib/* ./AppDir/ + mkdir -p ./AppDir/usr/share/icons + convert ./src/win32/icon1.ico[0] -flatten ./AppDir/usr/share/icons/game_icon.png + - name: Build AppImage + run: | + appimage-builder --skip-tests + - uses: actions/upload-artifact@v2 + with: + name: AppImage + path: './*.AppImage*' diff --git a/.gitignore b/.gitignore index 8be2eccd1..a7ea8ab4f 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,9 @@ .vscode /src/gl/unused /mapfiles_release/*.map +/AppDir +/appimage-build +*.AppImage .DS_Store /build_vc2017-32 /build2 diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml new file mode 100644 index 000000000..6f9ebcc3b --- /dev/null +++ b/AppImageBuilder.yml @@ -0,0 +1,45 @@ +# appimage-builder recipe see https://appimage-builder.readthedocs.io for details +version: 1 +AppDir: + path: ./AppDir + app_info: + id: com.GZDoom.app + name: GZDoom + icon: game_icon.png + version: latest + exec: ./gzdoom + exec_args: $@ + apt: + arch: amd64 + allow_unauthenticated: true + sources: + - sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy main restricted + - sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates main restricted + include: [] + files: + include: [] + exclude: + - usr/share/man + - usr/share/doc/*/README.* + - usr/share/doc/*/changelog.* + - usr/share/doc/*/NEWS.* + - usr/share/doc/*/TODO.* + test: + fedora-30: + image: appimagecrafters/tests-env:fedora-30 + command: ./AppRun + debian-stable: + image: appimagecrafters/tests-env:debian-stable + command: ./AppRun + archlinux-latest: + image: appimagecrafters/tests-env:archlinux-latest + command: ./AppRun + centos-7: + image: appimagecrafters/tests-env:centos-7 + command: ./AppRun + ubuntu-xenial: + image: appimagecrafters/tests-env:ubuntu-xenial + command: ./AppRun +AppImage: + arch: x86_64 + update-information: guess diff --git a/CMakeLists.txt b/CMakeLists.txt index 76c358417..5ea86a504 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,4 @@ -cmake_minimum_required( VERSION 3.1.0 ) -project(VkDoom) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) - +cmake_minimum_required( VERSION 3.16 ) if( COMMAND cmake_policy ) if( POLICY CMP0011 ) @@ -13,8 +7,22 @@ if( COMMAND cmake_policy ) if( POLICY CMP0054 ) cmake_policy( SET CMP0054 NEW ) endif() + if ( POLICY CMP0067 ) + cmake_policy( SET CMP0067 NEW ) + endif() + if ( POLICY CMP0091 ) + cmake_policy( SET CMP0091 NEW ) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") + endif() endif() +project(VkDoom) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + + list( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ) include( FindPackageHandleStandardArgs ) @@ -146,13 +154,6 @@ endif() if( DEM_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE ) set( PROFILE 0 CACHE BOOL "Enable profiling with gprof for Debug and RelWithDebInfo build types." ) - - if( CMAKE_CXX_STANDARD ) - # By default, try_compile() invocations ignore CXX_STANDARD value - # CMake 3.8 and newer have CMP0067 policy that fixes the issue, but it should be enabled explicitly - # Older versions require manual specification of the corresponding command line option - set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++${CMAKE_CXX_STANDARD}" ) - endif() endif() # Fast math flags, required by some subprojects @@ -236,28 +237,19 @@ if( MSVC ) # Avoid CRT DLL dependancies in release builds, optionally generate assembly output for checking crash locations. option( ZDOOM_GENERATE_ASM "Generate assembly output." OFF ) if( ZDOOM_GENERATE_ASM ) - set( REL_C_FLAGS "/MT /Oy /Oi /FAcs /GS-" ) + set( REL_C_FLAGS "/Oy /Oi /FAcs /GS-" ) else() - set( REL_C_FLAGS "/MT /Oy /Oi /GS-" ) + set( REL_C_FLAGS "/Oy /Oi /GS-" ) endif() # Debug allocations in debug builds - set( DEB_C_FLAGS "/D _CRTDBG_MAP_ALLOC /MTd" ) + set( DEB_C_FLAGS "/D _CRTDBG_MAP_ALLOC" ) # Disable warnings for unsecure CRT functions from VC8+ set( ALL_C_FLAGS "${ALL_C_FLAGS} /DUNICODE /D_UNICODE /D_WIN32_WINNT=0x0600 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS" ) - # The CMake configurations set /GR and /MD by default, which conflict with our settings. - string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} ) - string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL} ) - string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ) string(REPLACE "/Ob1 " "/Ob2 " CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ) - string(REPLACE "/MDd " " " CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG} ) - string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} ) - string(REPLACE "/MD " " " CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL} ) - string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO} ) - string(REPLACE "/MDd " " " CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG} ) else() set( REL_LINKER_FLAGS "" ) set( ALL_C_FLAGS "-ffp-contract=off" ) @@ -412,7 +404,6 @@ option( DYN_OPENAL "Dynamically load OpenAL" ON ) add_subdirectory( libraries/lzma ) add_subdirectory( tools ) -add_subdirectory( libraries/gdtoa ) add_subdirectory( wadsrc ) add_subdirectory( wadsrc_bm ) add_subdirectory( wadsrc_lights ) diff --git a/libraries/gdtoa/CMakeLists.txt b/libraries/gdtoa/CMakeLists.txt deleted file mode 100644 index 834340909..000000000 --- a/libraries/gdtoa/CMakeLists.txt +++ /dev/null @@ -1,45 +0,0 @@ -cmake_minimum_required( VERSION 3.1.0 ) - -set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG" ) - -# Disable warnings for << operator precedence (4554) and -# unreferenced labels (4102) from VC -if( MSVC ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /wd4554 /wd4102" ) -endif() - -if( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE ) - set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra" ) -endif() - -include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) -add_definitions( -DINFNAN_CHECK -DMULTIPLE_THREADS ) - -if( NOT MSVC AND NOT APPLE ) - if( NOT CMAKE_CROSSCOMPILING ) - add_executable( arithchk arithchk.c ) - endif() - add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/arith.h - COMMAND arithchk >${CMAKE_CURRENT_BINARY_DIR}/arith.h - DEPENDS arithchk ) - - if( NOT CMAKE_CROSSCOMPILING ) - add_executable( qnan qnan.c arith.h ) - set( CROSS_EXPORTS ${CROSS_EXPORTS} arithchk qnan PARENT_SCOPE ) - endif() - add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/gd_qnan.h - COMMAND qnan >${CMAKE_CURRENT_BINARY_DIR}/gd_qnan.h - DEPENDS qnan ) - - set( GEN_FP_FILES arith.h gd_qnan.h ) - set( GEN_FP_DEPS ${CMAKE_CURRENT_BINARY_DIR}/arith.h ${CMAKE_CURRENT_BINARY_DIR}/gd_qnan.h ) -endif() - -add_library( gdtoa STATIC - ${GEN_FP_FILES} - dmisc.c - dtoa.c - misc.c - ) -target_link_libraries( gdtoa ) - diff --git a/libraries/gdtoa/README b/libraries/gdtoa/README deleted file mode 100644 index 1bf7d91e4..000000000 --- a/libraries/gdtoa/README +++ /dev/null @@ -1,400 +0,0 @@ -This directory contains source for a library of binary -> decimal -and decimal -> binary conversion routines, for single-, double-, -and extended-precision IEEE binary floating-point arithmetic, and -other IEEE-like binary floating-point, including "double double", -as in - - T. J. Dekker, "A Floating-Point Technique for Extending the - Available Precision", Numer. Math. 18 (1971), pp. 224-242 - -and - - "Inside Macintosh: PowerPC Numerics", Addison-Wesley, 1994 - -The conversion routines use double-precision floating-point arithmetic -and, where necessary, high precision integer arithmetic. The routines -are generalizations of the strtod and dtoa routines described in - - David M. Gay, "Correctly Rounded Binary-Decimal and - Decimal-Binary Conversions", Numerical Analysis Manuscript - No. 90-10, Bell Labs, Murray Hill, 1990; - http://cm.bell-labs.com/cm/cs/what/ampl/REFS/rounding.ps.gz - -(based in part on papers by Clinger and Steele & White: see the -references in the above paper). - -The present conversion routines should be able to use any of IEEE binary, -VAX, or IBM-mainframe double-precision arithmetic internally, but I (dmg) -have so far only had a chance to test them with IEEE double precision -arithmetic. - -The core conversion routines are strtodg for decimal -> binary conversions -and gdtoa for binary -> decimal conversions. These routines operate -on arrays of unsigned 32-bit integers of type ULong, a signed 32-bit -exponent of type Long, and arithmetic characteristics described in -struct FPI; FPI, Long, and ULong are defined in gdtoa.h. File arith.h -is supposed to provide #defines that cause gdtoa.h to define its -types correctly. File arithchk.c is source for a program that -generates a suitable arith.h on all systems where I've been able to -test it. - -The core conversion routines are meant to be called by helper routines -that know details of the particular binary arithmetic of interest and -convert. The present directory provides helper routines for 5 variants -of IEEE binary floating-point arithmetic, each indicated by one or -two letters: - - f IEEE single precision - d IEEE double precision - x IEEE extended precision, as on Intel 80x87 - and software emulations of Motorola 68xxx chips - that do not pad the way the 68xxx does, but - only store 80 bits - xL IEEE extended precision, as on Motorola 68xxx chips - Q quad precision, as on Sun Sparc chips - dd double double, pairs of IEEE double numbers - whose sum is the desired value - -For decimal -> binary conversions, there are three families of -helper routines: one for round-nearest (or the current rounding -mode on IEEE-arithmetic systems that provide the C99 fegetround() -function, if compiled with -DHonor_FLT_ROUNDS): - - strtof - strtod - strtodd - strtopd - strtopf - strtopx - strtopxL - strtopQ - -one with rounding direction specified: - - strtorf - strtord - strtordd - strtorx - strtorxL - strtorQ - -and one for computing an interval (at most one bit wide) that contains -the decimal number: - - strtoIf - strtoId - strtoIdd - strtoIx - strtoIxL - strtoIQ - -The latter call strtoIg, which makes one call on strtodg and adjusts -the result to provide the desired interval. On systems where native -arithmetic can easily make one-ulp adjustments on values in the -desired floating-point format, it might be more efficient to use the -native arithmetic. Routine strtodI is a variant of strtoId that -illustrates one way to do this for IEEE binary double-precision -arithmetic -- but whether this is more efficient remains to be seen. - -Functions strtod and strtof have "natural" return types, float and -double -- strtod is specified by the C standard, and strtof appears -in the stdlib.h of some systems, such as (at least some) Linux systems. -The other functions write their results to their final argument(s): -to the final two argument for the strtoI... (interval) functions, -and to the final argument for the others (strtop... and strtor...). -Where possible, these arguments have "natural" return types (double* -or float*), to permit at least some type checking. In reality, they -are viewed as arrays of ULong (or, for the "x" functions, UShort) -values. On systems where long double is the appropriate type, one can -pass long double* final argument(s) to these routines. The int value -that these routines return is the return value from the call they make -on strtodg; see the enum of possible return values in gdtoa.h. - -Source files g_ddfmt.c, misc.c, smisc.c, strtod.c, strtodg.c, and ulp.c -should use true IEEE double arithmetic (not, e.g., double extended), -at least for storing (and viewing the bits of) the variables declared -"double" within them. - -One detail indicated in struct FPI is whether the target binary -arithmetic departs from the IEEE standard by flushing denormalized -numbers to 0. On systems that do this, the helper routines for -conversion to double-double format (when compiled with -Sudden_Underflow #defined) penalize the bottom of the exponent -range so that they return a nonzero result only when the least -significant bit of the less significant member of the pair of -double values returned can be expressed as a normalized double -value. An alternative would be to drop to 53-bit precision near -the bottom of the exponent range. To get correct rounding, this -would (in general) require two calls on strtodg (one specifying -126-bit arithmetic, then, if necessary, one specifying 53-bit -arithmetic). - -By default, the core routine strtodg and strtod set errno to ERANGE -if the result overflows to +Infinity or underflows to 0. Compile -these routines with NO_ERRNO #defined to inhibit errno assignments. - -Routine strtod is based on netlib's "dtoa.c from fp", and -(f = strtod(s,se)) is more efficient for some conversions than, say, -strtord(s,se,1,&f). Parts of strtod require true IEEE double -arithmetic with the default rounding mode (round-to-nearest) and, on -systems with IEEE extended-precision registers, double-precision -(53-bit) rounding precision. If the machine uses (the equivalent of) -Intel 80x87 arithmetic, the call - _control87(PC_53, MCW_PC); -does this with many compilers. Whether this or another call is -appropriate depends on the compiler; for this to work, it may be -necessary to #include "float.h" or another system-dependent header -file. - -Source file strtodnrp.c gives a strtod that does not require 53-bit -rounding precision on systems (such as Intel IA32 systems) that may -suffer double rounding due to use of extended-precision registers. -For some conversions this variant of strtod is less efficient than the -one in strtod.c when the latter is run with 53-bit rounding precision. - -When float or double are involved, the values that the strto* routines -return for NaNs are determined by gd_qnan.h, which the makefile -generates by running the program whose source is qnan.c. For other -types, default NaN values are specified in g__fmt.c and may need -adjusting. Note that the rules for distinguishing signaling from -quiet NaNs are system-dependent. For cross-compilation, you need to -determine arith.h and gd_qnan.h suitably, e.g., using the arithmetic -of the target machine. - -C99's hexadecimal floating-point constants are recognized by the -strto* routines (but this feature has not yet been heavily tested). -Compiling with NO_HEX_FP #defined disables this feature. - -When compiled with -DINFNAN_CHECK, the strto* routines recognize C99's -NaN and Infinity syntax. Moreover, unless No_Hex_NaN is #defined, the -strto* routines also recognize C99's NaN(...) syntax: they accept -(case insensitively) strings of the form NaN(x), where x is a string -of hexadecimal digits and spaces; if there is only one string of -hexadecimal digits, it is taken for the fraction bits of the resulting -NaN; if there are two or more strings of hexadecimal digits, each -string is assigned to the next available sequence of 32-bit words of -fractions bits (starting with the most significant), right-aligned in -each sequence. Strings of hexadecimal digits may be preceded by "0x" -or "0X". - -For binary -> decimal conversions, I've provided a family of helper -routines: - - g_ffmt - g_dfmt - g_ddfmt - g_xfmt - g_xLfmt - g_Qfmt - g_ffmt_p - g_dfmt_p - g_ddfmt_p - g_xfmt_p - g_xLfmt_p - g_Qfmt_p - -which do a "%g" style conversion either to a specified number of decimal -places (if their ndig argument is positive), or to the shortest -decimal string that rounds to the given binary floating-point value -(if ndig <= 0). They write into a buffer supplied as an argument -and return either a pointer to the end of the string (a null character) -in the buffer, if the buffer was long enough, or 0. Other forms of -conversion are easily done with the help of gdtoa(), such as %e or %f -style and conversions with direction of rounding specified (so that, if -desired, the decimal value is either >= or <= the binary value). -On IEEE-arithmetic systems that provide the C99 fegetround() function, -if compiled with -DHonor_FLT_ROUNDS, these routines honor the current -rounding mode. For pedants, the ...fmt_p() routines are similar to the -...fmt() routines, but have an additional final int argument, nik, -that for conversions of Infinity or NaN, determines whether upper, -lower, or mixed case is used, whether (...) is added to NaN values, -and whether the sign of a NaN is reported or suppressed: - - nik = ic + 6*(nb + 3*ns), - -where ic with 0 <= ic < 6 controls the rendering of Infinity and NaN: - - 0 ==> Infinity or NaN - 1 ==> infinity or nan - 2 ==> INFINITY or NAN - 3 ==> Inf or NaN - 4 ==> inf or nan - 5 ==> INF or NAN - -nb with 0 <= nb < 3 determines whether NaN values are rendered -as NaN(...): - - 0 ==> no - 1 ==> yes - 2 ==> no for default NaN values; yes otherwise - -ns = 0 or 1 determines whether the sign of NaN values reported: - - 0 ==> distinguish NaN and -NaN - 1 ==> report both as NaN - -For an example of more general conversions based on dtoa(), see -netlib's "printf.c from ampl/solvers". - -For double-double -> decimal, g_ddfmt() assumes IEEE-like arithmetic -of precision max(126, #bits(input)) bits, where #bits(input) is the -number of mantissa bits needed to represent the sum of the two double -values in the input. - -The makefile creates a library, gdtoa.a. To use the helper -routines, a program only needs to include gdtoa.h. All the -source files for gdtoa.a include a more extensive gdtoaimp.h; -among other things, gdtoaimp.h has #defines that make "internal" -names end in _D2A. To make a "system" library, one could modify -these #defines to make the names start with __. - -Various comments about possible #defines appear in gdtoaimp.h, -but for most purposes, arith.h should set suitable #defines. - -Systems with preemptive scheduling of multiple threads require some -manual intervention. On such systems, it's necessary to compile -dmisc.c, dtoa.c gdota.c, and misc.c with MULTIPLE_THREADS #defined, -and to provide (or suitably #define) two locks, acquired by -ACQUIRE_DTOA_LOCK(n) and freed by FREE_DTOA_LOCK(n) for n = 0 or 1. -(The second lock, accessed in pow5mult, ensures lazy evaluation of -only one copy of high powers of 5; omitting this lock would introduce -a small probability of wasting memory, but would otherwise be harmless.) -Routines that call dtoa or gdtoa directly must also invoke freedtoa(s) -to free the value s returned by dtoa or gdtoa. It's OK to do so whether -or not MULTIPLE_THREADS is #defined, and the helper g_*fmt routines -listed above all do this indirectly (in gfmt_D2A(), which they all call). - -By default, there is a private pool of memory of length 2000 bytes -for intermediate quantities, and MALLOC (see gdtoaimp.h) is called only -if the private pool does not suffice. 2000 is large enough that MALLOC -is called only under very unusual circumstances (decimal -> binary -conversion of very long strings) for conversions to and from double -precision. For systems with preemptively scheduled multiple threads -or for conversions to extended or quad, it may be appropriate to -#define PRIVATE_MEM nnnn, where nnnn is a suitable value > 2000. -For extended and quad precisions, -DPRIVATE_MEM=20000 is probably -plenty even for many digits at the ends of the exponent range. -Use of the private pool avoids some overhead. - -Directory test provides some test routines. See its README. -I've also tested this stuff (except double double conversions) -with Vern Paxson's testbase program: see - - V. Paxson and W. Kahan, "A Program for Testing IEEE Binary-Decimal - Conversion", manuscript, May 1991, - ftp://ftp.ee.lbl.gov/testbase-report.ps.Z . - -(The same ftp directory has source for testbase.) - -Some system-dependent additions to CFLAGS in the makefile: - - HU-UX: -Aa -Ae - OSF (DEC Unix): -ieee_with_no_inexact - SunOS 4.1x: -DKR_headers -DBad_float_h - -If you want to put this stuff into a shared library and your -operating system requires export lists for shared libraries, -the following would be an appropriate export list: - - dtoa - freedtoa - g_Qfmt - g_ddfmt - g_dfmt - g_ffmt - g_xLfmt - g_xfmt - gdtoa - strtoIQ - strtoId - strtoIdd - strtoIf - strtoIx - strtoIxL - strtod - strtodI - strtodg - strtof - strtopQ - strtopd - strtopdd - strtopf - strtopx - strtopxL - strtorQ - strtord - strtordd - strtorf - strtorx - strtorxL - -When time permits, I (dmg) hope to write in more detail about the -present conversion routines; for now, this README file must suffice. -Meanwhile, if you wish to write helper functions for other kinds of -IEEE-like arithmetic, some explanation of struct FPI and the bits -array may be helpful. Both gdtoa and strtodg operate on a bits array -described by FPI *fpi. The bits array is of type ULong, a 32-bit -unsigned integer type. Floating-point numbers have fpi->nbits bits, -with the least significant 32 bits in bits[0], the next 32 bits in -bits[1], etc. These numbers are regarded as integers multiplied by -2^e (i.e., 2 to the power of the exponent e), where e is the second -argument (be) to gdtoa and is stored in *exp by strtodg. The minimum -and maximum exponent values fpi->emin and fpi->emax for normalized -floating-point numbers reflect this arrangement. For example, the -P754 standard for binary IEEE arithmetic specifies doubles as having -53 bits, with normalized values of the form 1.xxxxx... times 2^(b-1023), -with 52 bits (the x's) and the biased exponent b represented explicitly; -b is an unsigned integer in the range 1 <= b <= 2046 for normalized -finite doubles, b = 0 for denormals, and b = 2047 for Infinities and NaNs. -To turn an IEEE double into the representation used by strtodg and gdtoa, -we multiply 1.xxxx... by 2^52 (to make it an integer) and reduce the -exponent e = (b-1023) by 52: - - fpi->emin = 1 - 1023 - 52 - fpi->emax = 1046 - 1023 - 52 - -In various wrappers for IEEE double, we actually write -53 + 1 rather -than -52, to emphasize that there are 53 bits including one implicit bit. -Field fpi->rounding indicates the desired rounding direction, with -possible values - FPI_Round_zero = toward 0, - FPI_Round_near = unbiased rounding -- the IEEE default, - FPI_Round_up = toward +Infinity, and - FPI_Round_down = toward -Infinity -given in gdtoa.h. - -Field fpi->sudden_underflow indicates whether strtodg should return -denormals or flush them to zero. Normal floating-point numbers have -bit fpi->nbits in the bits array on. Denormals have it off, with -exponent = fpi->emin. Strtodg provides distinct return values for normals -and denormals; see gdtoa.h. - -Compiling g__fmt.c, strtod.c, and strtodg.c with -DUSE_LOCALE causes -the decimal-point character to be taken from the current locale; otherwise -it is '.'. - -Source files dtoa.c and strtod.c in this directory are derived from -netlib's "dtoa.c from fp" and are meant to function equivalently. -When compiled with Honor_FLT_ROUNDS #defined (on systems that provide -FLT_ROUNDS and fegetround() as specified in the C99 standard), they -honor the current rounding mode. Because FLT_ROUNDS is buggy on some -(Linux) systems -- not reflecting calls on fesetround(), as the C99 -standard says it should -- when Honor_FLT_ROUNDS is #defined, the -current rounding mode is obtained from fegetround() rather than from -FLT_ROUNDS, unless Trust_FLT_ROUNDS is also #defined. - -Compile with -DUSE_LOCALE to use the current locale; otherwise -decimal points are assumed to be '.'. With -DUSE_LOCALE, unless -you also compile with -DNO_LOCALE_CACHE, the details about the -current "decimal point" character string are cached and assumed not -to change during the program's execution. - -On machines with a 64-bit long double and perhaps a 113-bit "quad" -type, you can invoke "make Printf" to add Printf (and variants, such -as Fprintf) to gdtoa.a. These are analogs, declared in stdio1.h, of -printf and fprintf, etc. in which %La, %Le, %Lf, and %Lg are for long -double and (if appropriate) %Lqa, %Lqe, %Lqf, and %Lqg are for quad -precision printing. - -Please send comments to David M. Gay (dmg at acm dot org, with " at " -changed at "@" and " dot " changed to "."). diff --git a/libraries/gdtoa/arithchk.c b/libraries/gdtoa/arithchk.c deleted file mode 100644 index ef6cda3db..000000000 --- a/libraries/gdtoa/arithchk.c +++ /dev/null @@ -1,183 +0,0 @@ -/**************************************************************** -Copyright (C) 1997, 1998 Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. -****************************************************************/ - -/* Try to deduce arith.h from arithmetic properties. */ - -#include - - static int dalign; - typedef struct -Akind { - char *name; - int kind; - } Akind; - - static Akind -IEEE_8087 = { "IEEE_8087", 1 }, -IEEE_MC68k = { "IEEE_MC68k", 2 }, -IBM = { "IBM", 3 }, -VAX = { "VAX", 4 }, -CRAY = { "CRAY", 5}; - - static Akind * -Lcheck() -{ - union { - double d; - long L[2]; - } u; - struct { - double d; - long L; - } x[2]; - - if (sizeof(x) > 2*(sizeof(double) + sizeof(long))) - dalign = 1; - u.L[0] = u.L[1] = 0; - u.d = 1e13; - if (u.L[0] == 1117925532 && u.L[1] == -448790528) - return &IEEE_MC68k; - if (u.L[1] == 1117925532 && u.L[0] == -448790528) - return &IEEE_8087; - if (u.L[0] == -2065213935 && u.L[1] == 10752) - return &VAX; - if (u.L[0] == 1267827943 && u.L[1] == 704643072) - return &IBM; - return 0; - } - - static Akind * -icheck() -{ - union { - double d; - int L[2]; - } u; - struct { - double d; - int L; - } x[2]; - - if (sizeof(x) > 2*(sizeof(double) + sizeof(int))) - dalign = 1; - u.L[0] = u.L[1] = 0; - u.d = 1e13; - if (u.L[0] == 1117925532 && u.L[1] == -448790528) - return &IEEE_MC68k; - if (u.L[1] == 1117925532 && u.L[0] == -448790528) - return &IEEE_8087; - if (u.L[0] == -2065213935 && u.L[1] == 10752) - return &VAX; - if (u.L[0] == 1267827943 && u.L[1] == 704643072) - return &IBM; - return 0; - } - -char *emptyfmt = ""; /* avoid possible warning message with printf("") */ - - static Akind * -ccheck() -{ - union { - double d; - long L; - } u; - long Cray1; - - /* Cray1 = 4617762693716115456 -- without overflow on non-Crays */ - Cray1 = printf("%s", emptyfmt) < 0 ? 0 : 4617762; - if (printf(emptyfmt, Cray1) >= 0) - Cray1 = 1000000*Cray1 + 693716; - if (printf(emptyfmt, Cray1) >= 0) - Cray1 = 1000000*Cray1 + 115456; - u.d = 1e13; - if (u.L == Cray1) - return &CRAY; - return 0; - } - - static int -fzcheck() -{ - double a, b; - int i; - - a = 1.; - b = .1; - for(i = 155;; b *= b, i >>= 1) { - if (i & 1) { - a *= b; - if (i == 1) - break; - } - } - b = a * a; - return b == 0.; - } - - int -main() -{ - Akind *a = 0; - int Ldef = 0; - FILE *f; - -#ifdef WRITE_ARITH_H /* for Symantec's buggy "make" */ - f = fopen("arith.h", "w"); - if (!f) { - printf("Cannot open arith.h\n"); - return 1; - } -#else - f = stdout; -#endif - - if (sizeof(double) == 2*sizeof(long)) - a = Lcheck(); - else if (sizeof(double) == 2*sizeof(int)) { - Ldef = 1; - a = icheck(); - } - else if (sizeof(double) == sizeof(long)) - a = ccheck(); - if (a) { - fprintf(f, "#define %s\n#define Arith_Kind_ASL %d\n", - a->name, a->kind); - if (Ldef) - fprintf(f, "#define Long int\n#define Intcast (int)(long)\n"); - if (dalign) - fprintf(f, "#define Double_Align\n"); - if (sizeof(char*) == 8) - fprintf(f, "#define X64_bit_pointers\n"); -#ifndef NO_LONG_LONG - if (sizeof(long long) < 8) -#endif - fprintf(f, "#define NO_LONG_LONG\n"); - if (a->kind <= 2 && fzcheck()) - fprintf(f, "#define Sudden_Underflow\n"); - return 0; - } - fprintf(f, "/* Unknown arithmetic */\n"); - return 1; - } diff --git a/libraries/gdtoa/dmisc.c b/libraries/gdtoa/dmisc.c deleted file mode 100644 index 3e712511b..000000000 --- a/libraries/gdtoa/dmisc.c +++ /dev/null @@ -1,216 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#ifndef MULTIPLE_THREADS - char *dtoa_result; -#endif - - char * -#ifdef KR_headers -rv_alloc(i) int i; -#else -rv_alloc(int i) -#endif -{ - int j, k, *r; - - j = sizeof(ULong); - for(k = 0; - sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (size_t)(i); - j <<= 1) - k++; - r = (int*)Balloc(k); - *r = k; - return -#ifndef MULTIPLE_THREADS - dtoa_result = -#endif - (char *)(r+1); - } - - char * -#ifdef KR_headers -nrv_alloc(s, rve, n) char *s, **rve; int n; -#else -nrv_alloc(char *s, char **rve, int n) -#endif -{ - char *rv, *t; - - t = rv = rv_alloc(n); - while((*t = *s++) !=0) - t++; - if (rve) - *rve = t; - return rv; - } - -/* freedtoa(s) must be used to free values s returned by dtoa - * when MULTIPLE_THREADS is #defined. It should be used in all cases, - * but for consistency with earlier versions of dtoa, it is optional - * when MULTIPLE_THREADS is not defined. - */ - - void -#ifdef KR_headers -freedtoa(s) char *s; -#else -freedtoa(char *s) -#endif -{ - Bigint *b = (Bigint *)((int *)s - 1); - b->maxwds = 1 << (b->k = *(int*)b); - Bfree(b); -#ifndef MULTIPLE_THREADS - if (s == dtoa_result) - dtoa_result = 0; -#endif - } - - int -quorem -#ifdef KR_headers - (b, S) Bigint *b, *S; -#else - (Bigint *b, Bigint *S) -#endif -{ - int n; - ULong *bx, *bxe, q, *sx, *sxe; -#ifdef ULLong - ULLong borrow, carry, y, ys; -#else - ULong borrow, carry, y, ys; -#ifdef Pack_32 - ULong si, z, zs; -#endif -#endif - - n = S->wds; -#ifdef DEBUG - /*debug*/ if (b->wds > n) - /*debug*/ Bug("oversize b in quorem"); -#endif - if (b->wds < n) - return 0; - sx = S->x; - sxe = sx + --n; - bx = b->x; - bxe = bx + n; - q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ -#ifdef DEBUG - /*debug*/ if (q > 9) - /*debug*/ Bug("oversized quotient in quorem"); -#endif - if (q) { - borrow = 0; - carry = 0; - do { -#ifdef ULLong - ys = *sx++ * (ULLong)q + carry; - carry = ys >> 32; - y = *bx - (ys & 0xffffffffUL) - borrow; - borrow = y >> 32 & 1UL; - *bx++ = (ULong)(y & 0xffffffffUL); -#else -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) * q + carry; - zs = (si >> 16) * q + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ * q + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif -#endif - } - while(sx <= sxe); - if (!*bxe) { - bx = b->x; - while(--bxe > bx && !*bxe) - --n; - b->wds = n; - } - } - if (cmp(b, S) >= 0) { - q++; - borrow = 0; - carry = 0; - bx = b->x; - sx = S->x; - do { -#ifdef ULLong - ys = *sx++ + carry; - carry = ys >> 32; - y = *bx - (ys & 0xffffffffUL) - borrow; - borrow = y >> 32 & 1UL; - *bx++ = (ULong)(y & 0xffffffffUL); -#else -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) + carry; - zs = (si >> 16) + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*bx >> 16) - (zs & 0xffff) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(bx, z, y); -#else - ys = *sx++ + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - *bx++ = y & 0xffff; -#endif -#endif - } - while(sx <= sxe); - bx = b->x; - bxe = bx + n; - if (!*bxe) { - while(--bxe > bx && !*bxe) - --n; - b->wds = n; - } - } - return q; - } diff --git a/libraries/gdtoa/dtoa.c b/libraries/gdtoa/dtoa.c deleted file mode 100644 index c96e6a545..000000000 --- a/libraries/gdtoa/dtoa.c +++ /dev/null @@ -1,780 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 1999 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. - * - * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. - * - * Modifications: - * 1. Rather than iterating, we use a simple numeric overestimate - * to determine k = floor(log10(d)). We scale relevant - * quantities using O(log2(k)) rather than O(k) multiplications. - * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't - * try to generate digits strictly left to right. Instead, we - * compute with fewer bits and propagate the carry if necessary - * when rounding the final digit up. This is often faster. - * 3. Under the assumption that input will be rounded nearest, - * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. - * That is, we allow equality in stopping tests when the - * round-nearest rule will give the same floating-point value - * as would satisfaction of the stopping test with strict - * inequality. - * 4. We remove common factors of powers of 2 from relevant - * quantities. - * 5. When converting floating-point integers less than 1e16, - * we use floating-point arithmetic rather than resorting - * to multiple-precision integers. - * 6. When asked to produce fewer than 15 digits, we first try - * to get by with floating-point arithmetic; we resort to - * multiple-precision integer arithmetic only if we cannot - * guarantee that the floating-point calculation has given - * the correctly rounded result. For k requested digits and - * "uniformly" distributed input, the probability is - * something like 10^(k-15) that we must resort to the Long - * calculation. - */ - -#ifdef Honor_FLT_ROUNDS -#undef Check_FLT_ROUNDS -#define Check_FLT_ROUNDS -#else -#define Rounding Flt_Rounds -#endif - - char * -dtoa -#ifdef KR_headers - (d0, mode, ndigits, decpt, sign, rve) - double d0; int mode, ndigits, *decpt, *sign; char **rve; -#else - (double d0, int mode, int ndigits, int *decpt, int *sign, char **rve) -#endif -{ - /* Arguments ndigits, decpt, sign are similar to those - of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If not null, *rve is set to point - to the end of the return value. If d is +-Infinity or NaN, - then *decpt is set to 9999. - - mode: - 0 ==> shortest string that yields d when read in - and rounded to nearest. - 1 ==> like 0, but with Steele & White stopping rule; - e.g. with IEEE P754 arithmetic , mode 0 gives - 1e23 whereas mode 1 gives 9.999999999999999e22. - 2 ==> max(1,ndigits) significant digits. This gives a - return value similar to that of ecvt, except - that trailing zeros are suppressed. - 3 ==> through ndigits past the decimal point. This - gives a return value similar to that from fcvt, - except that trailing zeros are suppressed, and - ndigits can be negative. - 4,5 ==> similar to 2 and 3, respectively, but (in - round-nearest mode) with the tests of mode 0 to - possibly return a shorter string that rounds to d. - With IEEE arithmetic and compilation with - -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same - as modes 2 and 3 when FLT_ROUNDS != 1. - 6-9 ==> Debugging modes similar to mode - 4: don't try - fast floating-point estimate (if applicable). - - Values of mode other than 0-9 are treated as mode 0. - - Sufficient space is allocated to the return value - to hold the suppressed trailing zeros. - */ - - int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1, - j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, - spec_case, try_quick; - Long L; -#ifndef Sudden_Underflow - int denorm; - ULong x; -#endif - Bigint *b, *b1, *delta, *mlo, *mhi, *S; - U d, d2, eps; - double ds; - char *s, *s0; -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif -#ifdef Honor_FLT_ROUNDS /*{*/ - int Rounding; -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - Rounding = Flt_Rounds; -#else /*}{*/ - Rounding = 1; - switch(fegetround()) { - case FE_TOWARDZERO: Rounding = 0; break; - case FE_UPWARD: Rounding = 2; break; - case FE_DOWNWARD: Rounding = 3; - } -#endif /*}}*/ -#endif /*}*/ - -#ifndef MULTIPLE_THREADS - if (dtoa_result) { - freedtoa(dtoa_result); - dtoa_result = 0; - } -#endif - d.d = d0; - if (word0(&d) & Sign_bit) { - /* set sign for everything, including 0's and NaNs */ - *sign = 1; - word0(&d) &= ~Sign_bit; /* clear sign bit */ - } - else - *sign = 0; - -#if defined(IEEE_Arith) + defined(VAX) -#ifdef IEEE_Arith - if ((word0(&d) & Exp_mask) == Exp_mask) -#else - if (word0(&d) == 0x8000) -#endif - { - /* Infinity or NaN */ - *decpt = 9999; -#ifdef IEEE_Arith - if (!word1(&d) && !(word0(&d) & 0xfffff)) - return nrv_alloc("Infinity", rve, 8); -#endif - return nrv_alloc("NaN", rve, 3); - } -#endif -#ifdef IBM - dval(&d) += 0; /* normalize */ -#endif - if (!dval(&d)) { - *decpt = 1; - return nrv_alloc("0", rve, 1); - } - -#ifdef SET_INEXACT - try_quick = oldinexact = get_inexact(); - inexact = 1; -#endif -#ifdef Honor_FLT_ROUNDS - if (Rounding >= 2) { - if (*sign) - Rounding = Rounding == 2 ? 0 : 2; - else - if (Rounding != 2) - Rounding = 0; - } -#endif - - b = d2b(dval(&d), &be, &bbits); -#ifdef Sudden_Underflow - i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); -#else - if (( i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) { -#endif - dval(&d2) = dval(&d); - word0(&d2) &= Frac_mask1; - word0(&d2) |= Exp_11; -#ifdef IBM - if (( j = 11 - hi0bits(word0(&d2) & Frac_mask) )!=0) - dval(&d2) /= 1 << j; -#endif - - /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 - * log10(x) = log(x) / log(10) - * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) - * log10(&d) = (i-Bias)*log(2)/log(10) + log10(&d2) - * - * This suggests computing an approximation k to log10(&d) by - * - * k = (i - Bias)*0.301029995663981 - * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); - * - * We want k to be too large rather than too small. - * The error in the first-order Taylor series approximation - * is in our favor, so we just round up the constant enough - * to compensate for any error in the multiplication of - * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, - * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, - * adding 1e-13 to the constant term more than suffices. - * Hence we adjust the constant term to 0.1760912590558. - * (We could get a more accurate k by invoking log10, - * but this is probably not worthwhile.) - */ - - i -= Bias; -#ifdef IBM - i <<= 2; - i += j; -#endif -#ifndef Sudden_Underflow - denorm = 0; - } - else { - /* d is denormalized */ - - i = bbits + be + (Bias + (P-1) - 1); - x = i > 32 ? word0(&d) << (64 - i) | word1(&d) >> (i - 32) - : word1(&d) << (32 - i); - dval(&d2) = x; - word0(&d2) -= 31*Exp_msk1; /* adjust exponent */ - i -= (Bias + (P-1) - 1) + 1; - denorm = 1; - } -#endif - ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; - k = (int)ds; - if (ds < 0. && ds != k) - k--; /* want k = floor(ds) */ - k_check = 1; - if (k >= 0 && k <= Ten_pmax) { - if (dval(&d) < tens[k]) - k--; - k_check = 0; - } - j = bbits - i - 1; - if (j >= 0) { - b2 = 0; - s2 = j; - } - else { - b2 = -j; - s2 = 0; - } - if (k >= 0) { - b5 = 0; - s5 = k; - s2 += k; - } - else { - b2 -= k; - b5 = -k; - s5 = 0; - } - if (mode < 0 || mode > 9) - mode = 0; - -#ifndef SET_INEXACT -#ifdef Check_FLT_ROUNDS - try_quick = Rounding == 1; -#else - try_quick = 1; -#endif -#endif /*SET_INEXACT*/ - - if (mode > 5) { - mode -= 4; - try_quick = 0; - } - leftright = 1; - ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ - /* silence erroneous "gcc -Wall" warning. */ - switch(mode) { - case 0: - case 1: - i = 18; - ndigits = 0; - break; - case 2: - leftright = 0; - /* no break */ - case 4: - if (ndigits <= 0) - ndigits = 1; - ilim = ilim1 = i = ndigits; - break; - case 3: - leftright = 0; - /* no break */ - case 5: - i = ndigits + k + 1; - ilim = i; - ilim1 = i - 1; - if (i <= 0) - i = 1; - } - s = s0 = rv_alloc(i); - -#ifdef Honor_FLT_ROUNDS - if (mode > 1 && Rounding != 1) - leftright = 0; -#endif - - if (ilim >= 0 && ilim <= Quick_max && try_quick) { - - /* Try to get by with floating-point arithmetic. */ - - i = 0; - dval(&d2) = dval(&d); - k0 = k; - ilim0 = ilim; - ieps = 2; /* conservative */ - if (k > 0) { - ds = tens[k&0xf]; - j = k >> 4; - if (j & Bletch) { - /* prevent overflows */ - j &= Bletch - 1; - dval(&d) /= bigtens[n_bigtens-1]; - ieps++; - } - for(; j; j >>= 1, i++) - if (j & 1) { - ieps++; - ds *= bigtens[i]; - } - dval(&d) /= ds; - } - else if (( j1 = -k )!=0) { - dval(&d) *= tens[j1 & 0xf]; - for(j = j1 >> 4; j; j >>= 1, i++) - if (j & 1) { - ieps++; - dval(&d) *= bigtens[i]; - } - } - if (k_check && dval(&d) < 1. && ilim > 0) { - if (ilim1 <= 0) - goto fast_failed; - ilim = ilim1; - k--; - dval(&d) *= 10.; - ieps++; - } - dval(&eps) = ieps*dval(&d) + 7.; - word0(&eps) -= (P-1)*Exp_msk1; - if (ilim == 0) { - S = mhi = 0; - dval(&d) -= 5.; - if (dval(&d) > dval(&eps)) - goto one_digit; - if (dval(&d) < -dval(&eps)) - goto no_digits; - goto fast_failed; - } -#ifndef No_leftright - if (leftright) { - /* Use Steele & White method of only - * generating digits needed. - */ - dval(&eps) = 0.5/tens[ilim-1] - dval(&eps); - for(i = 0;;) { - L = (Long)dval(&d); - dval(&d) -= L; - *s++ = '0' + (int)L; - if (dval(&d) < dval(&eps)) - goto ret1; - if (1. - dval(&d) < dval(&eps)) - goto bump_up; - if (++i >= ilim) - break; - dval(&eps) *= 10.; - dval(&d) *= 10.; - } - } - else { -#endif - /* Generate ilim digits, then fix them up. */ - dval(&eps) *= tens[ilim-1]; - for(i = 1;; i++, dval(&d) *= 10.) { - L = (Long)(dval(&d)); - if (!(dval(&d) -= L)) - ilim = i; - *s++ = '0' + (int)L; - if (i == ilim) { - if (dval(&d) > 0.5 + dval(&eps)) - goto bump_up; - else if (dval(&d) < 0.5 - dval(&eps)) { - while(*--s == '0'); - s++; - goto ret1; - } - break; - } - } -#ifndef No_leftright - } -#endif - fast_failed: - s = s0; - dval(&d) = dval(&d2); - k = k0; - ilim = ilim0; - } - - /* Do we have a "small" integer? */ - - if (be >= 0 && k <= Int_max) { - /* Yes. */ - ds = tens[k]; - if (ndigits < 0 && ilim <= 0) { - S = mhi = 0; - if (ilim < 0 || dval(&d) <= 5*ds) - goto no_digits; - goto one_digit; - } - for(i = 1;; i++, dval(&d) *= 10.) { - L = (Long)(dval(&d) / ds); - dval(&d) -= L*ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (dval(&d) < 0) { - L--; - dval(&d) += ds; - } -#endif - *s++ = '0' + (int)L; - if (!dval(&d)) { -#ifdef SET_INEXACT - inexact = 0; -#endif - break; - } - if (i == ilim) { -#ifdef Honor_FLT_ROUNDS - if (mode > 1) - switch(Rounding) { - case 0: goto ret1; - case 2: goto bump_up; - } -#endif - dval(&d) += dval(&d); -#ifdef ROUND_BIASED - if (dval(&d) >= ds) -#else - if (dval(&d) > ds || (dval(&d) == ds && L & 1)) -#endif - { - bump_up: - while(*--s == '9') - if (s == s0) { - k++; - *s = '0'; - break; - } - ++*s++; - } - break; - } - } - goto ret1; - } - - m2 = b2; - m5 = b5; - mhi = mlo = 0; - if (leftright) { - i = -#ifndef Sudden_Underflow - denorm ? be + (Bias + (P-1) - 1 + 1) : -#endif -#ifdef IBM - 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); -#else - 1 + P - bbits; -#endif - b2 += i; - s2 += i; - mhi = i2b(1); - } - if (m2 > 0 && s2 > 0) { - i = m2 < s2 ? m2 : s2; - b2 -= i; - m2 -= i; - s2 -= i; - } - if (b5 > 0) { - if (leftright) { - if (m5 > 0) { - mhi = pow5mult(mhi, m5); - b1 = mult(mhi, b); - Bfree(b); - b = b1; - } - if (( j = b5 - m5 )!=0) - b = pow5mult(b, j); - } - else - b = pow5mult(b, b5); - } - S = i2b(1); - if (s5 > 0) - S = pow5mult(S, s5); - - /* Check for special case that d is a normalized power of 2. */ - - spec_case = 0; - if ((mode < 2 || leftright) -#ifdef Honor_FLT_ROUNDS - && Rounding == 1 -#endif - ) { - if (!word1(&d) && !(word0(&d) & Bndry_mask) -#ifndef Sudden_Underflow - && word0(&d) & (Exp_mask & ~Exp_msk1) -#endif - ) { - /* The special case */ - b2 += Log2P; - s2 += Log2P; - spec_case = 1; - } - } - - /* Arrange for convenient computation of quotients: - * shift left if necessary so divisor has 4 leading 0 bits. - * - * Perhaps we should just compute leading 28 bits of S once - * and for all and pass them and a shift to quorem, so it - * can do shifts and ors to compute the numerator for q. - */ -#ifdef Pack_32 - if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f )!=0) - i = 32 - i; -#else - if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf )!=0) - i = 16 - i; -#endif - if (i > 4) { - i -= 4; - b2 += i; - m2 += i; - s2 += i; - } - else if (i < 4) { - i += 28; - b2 += i; - m2 += i; - s2 += i; - } - if (b2 > 0) - b = lshift(b, b2); - if (s2 > 0) - S = lshift(S, s2); - if (k_check) { - if (cmp(b,S) < 0) { - k--; - b = multadd(b, 10, 0); /* we botched the k estimate */ - if (leftright) - mhi = multadd(mhi, 10, 0); - ilim = ilim1; - } - } - if (ilim <= 0 && (mode == 3 || mode == 5)) { - if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { - /* no digits, fcvt style */ - no_digits: - k = -1 - ndigits; - goto ret; - } - one_digit: - *s++ = '1'; - k++; - goto ret; - } - if (leftright) { - if (m2 > 0) - mhi = lshift(mhi, m2); - - /* Compute mlo -- check for special case - * that d is a normalized power of 2. - */ - - mlo = mhi; - if (spec_case) { - mhi = Balloc(mhi->k); - Bcopy(mhi, mlo); - mhi = lshift(mhi, Log2P); - } - - for(i = 1;;i++) { - dig = quorem(b,S) + '0'; - /* Do we yet have the shortest decimal string - * that will round to d? - */ - j = cmp(b, mlo); - delta = diff(S, mhi); - j1 = delta->sign ? 1 : cmp(b, delta); - Bfree(delta); -#ifndef ROUND_BIASED - if (j1 == 0 && mode != 1 && !(word1(&d) & 1) -#ifdef Honor_FLT_ROUNDS - && Rounding >= 1 -#endif - ) { - if (dig == '9') - goto round_9_up; - if (j > 0) - dig++; -#ifdef SET_INEXACT - else if (!b->x[0] && b->wds <= 1) - inexact = 0; -#endif - *s++ = dig; - goto ret; - } -#endif - if (j < 0 || (j == 0 && mode != 1 -#ifndef ROUND_BIASED - && !(word1(&d) & 1) -#endif - )) { - if (!b->x[0] && b->wds <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif - goto accept_dig; - } -#ifdef Honor_FLT_ROUNDS - if (mode > 1) - switch(Rounding) { - case 0: goto accept_dig; - case 2: goto keep_dig; - } -#endif /*Honor_FLT_ROUNDS*/ - if (j1 > 0) { - b = lshift(b, 1); - j1 = cmp(b, S); -#ifdef ROUND_BIASED - if (j1 >= 0 /*)*/ -#else - if ((j1 > 0 || (j1 == 0 && dig & 1)) -#endif - && dig++ == '9') - goto round_9_up; - } - accept_dig: - *s++ = dig; - goto ret; - } - if (j1 > 0) { -#ifdef Honor_FLT_ROUNDS - if (!Rounding) - goto accept_dig; -#endif - if (dig == '9') { /* possible if i == 1 */ - round_9_up: - *s++ = '9'; - goto roundoff; - } - *s++ = dig + 1; - goto ret; - } -#ifdef Honor_FLT_ROUNDS - keep_dig: -#endif - *s++ = dig; - if (i == ilim) - break; - b = multadd(b, 10, 0); - if (mlo == mhi) - mlo = mhi = multadd(mhi, 10, 0); - else { - mlo = multadd(mlo, 10, 0); - mhi = multadd(mhi, 10, 0); - } - } - } - else - for(i = 1;; i++) { - *s++ = dig = quorem(b,S) + '0'; - if (!b->x[0] && b->wds <= 1) { -#ifdef SET_INEXACT - inexact = 0; -#endif - goto ret; - } - if (i >= ilim) - break; - b = multadd(b, 10, 0); - } - - /* Round off last digit */ - -#ifdef Honor_FLT_ROUNDS - switch(Rounding) { - case 0: goto trimzeros; - case 2: goto roundoff; - } -#endif - b = lshift(b, 1); - j = cmp(b, S); -#ifdef ROUND_BIASED - if (j >= 0) -#else - if (j > 0 || (j == 0 && dig & 1)) -#endif - { - roundoff: - while(*--s == '9') - if (s == s0) { - k++; - *s++ = '1'; - goto ret; - } - ++*s++; - } - else { -#ifdef Honor_FLT_ROUNDS - trimzeros: -#endif - while(*--s == '0'); - s++; - } - ret: - Bfree(S); - if (mhi) { - if (mlo && mlo != mhi) - Bfree(mlo); - Bfree(mhi); - } - ret1: -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&d) = Exp_1 + (70 << Exp_shift); - word1(&d) = 0; - dval(&d) += 1.; - } - } - else if (!oldinexact) - clear_inexact(); -#endif - Bfree(b); - *s = 0; - *decpt = k + 1; - if (rve) - *rve = s; - return s0; - } diff --git a/libraries/gdtoa/g_Qfmt.c b/libraries/gdtoa/g_Qfmt.c deleted file mode 100644 index 0f0697005..000000000 --- a/libraries/gdtoa/g_Qfmt.c +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#endif -#ifdef IEEE_8087 -#define _0 3 -#define _1 2 -#define _2 1 -#define _3 0 -#endif - - char* -#ifdef KR_headers -g_Qfmt(buf, V, ndig, bufsize) char *buf; char *V; int ndig; size_t bufsize; -#else -g_Qfmt(char *buf, void *V, int ndig, size_t bufsize) -#endif -{ - static FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, 0, Int_max }; - char *b, *s, *se; - ULong bits[4], *L, sign; - int decpt, ex, i, mode; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - if (ndig < 0) - ndig = 0; - if (bufsize < (size_t)(ndig + 10)) - return 0; - - L = (ULong*)V; - sign = L[_0] & 0x80000000L; - bits[3] = L[_0] & 0xffff; - bits[2] = L[_1]; - bits[1] = L[_2]; - bits[0] = L[_3]; - b = buf; - if ( (ex = (L[_0] & 0x7fff0000L) >> 16) !=0) { - if (ex == 0x7fff) { - /* Infinity or NaN */ - if (bits[0] | bits[1] | bits[2] | bits[3]) - b = strcp(b, "NaN"); - else { - b = buf; - if (sign) - *b++ = '-'; - b = strcp(b, "Infinity"); - } - return b; - } - i = STRTOG_Normal; - bits[3] |= 0x10000; - } - else if (bits[0] | bits[1] | bits[2] | bits[3]) { - i = STRTOG_Denormal; - ex = 1; - } - else { -#ifndef IGNORE_ZERO_SIGN - if (sign) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - ex -= 0x3fff + 112; - mode = 2; - if (ndig <= 0) { - if (bufsize < 48) - return 0; - mode = 0; - } - s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se); - return g__fmt(buf, s, se, decpt, sign, bufsize); - } diff --git a/libraries/gdtoa/g__fmt.c b/libraries/gdtoa/g__fmt.c deleted file mode 100644 index 652c82b68..000000000 --- a/libraries/gdtoa/g__fmt.c +++ /dev/null @@ -1,203 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#ifdef USE_LOCALE -#include "locale.h" -#endif - -#ifndef ldus_QNAN0 -#define ldus_QNAN0 0x7fff -#endif -#ifndef ldus_QNAN1 -#define ldus_QNAN1 0xc000 -#endif -#ifndef ldus_QNAN2 -#define ldus_QNAN2 0 -#endif -#ifndef ldus_QNAN3 -#define ldus_QNAN3 0 -#endif -#ifndef ldus_QNAN4 -#define ldus_QNAN4 0 -#endif - - const char *InfName[6] = { "Infinity", "infinity", "INFINITY", "Inf", "inf", "INF" }; - const char *NanName[3] = { "NaN", "nan", "NAN" }; - ULong NanDflt_Q_D2A[4] = { 0xffffffff, 0xffffffff, 0xffffffff, 0x7fffffff }; - ULong NanDflt_d_D2A[2] = { d_QNAN1, d_QNAN0 }; - ULong NanDflt_f_D2A[1] = { f_QNAN }; - ULong NanDflt_xL_D2A[3] = { 1, 0x80000000, 0x7fff0000 }; - UShort NanDflt_ldus_D2A[5] = { ldus_QNAN4, ldus_QNAN3, ldus_QNAN2, ldus_QNAN1, ldus_QNAN0 }; - - char * -#ifdef KR_headers -g__fmt(b, s, se, decpt, sign, blen) char *b; char *s; char *se; int decpt; ULong sign; size_t blen; -#else -g__fmt(char *b, char *s, char *se, int decpt, ULong sign, size_t blen) -#endif -{ - int i, j, k; - char *be, *s0; - size_t len; -#ifdef USE_LOCALE -#ifdef NO_LOCALE_CACHE - char *decimalpoint = localeconv()->decimal_point; - size_t dlen = strlen(decimalpoint); -#else - char *decimalpoint; - static char *decimalpoint_cache; - static size_t dlen; - if (!(s0 = decimalpoint_cache)) { - s0 = localeconv()->decimal_point; - dlen = strlen(s0); - if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { - strcpy(decimalpoint_cache, s0); - s0 = decimalpoint_cache; - } - } - decimalpoint = s0; -#endif -#else -#define dlen 0 -#endif - s0 = s; - len = (se-s) + dlen + 6; /* 6 = sign + e+dd + trailing null */ - if (blen < len) - goto ret0; - be = b + blen - 1; - if (sign) - *b++ = '-'; - if (decpt <= -4 || decpt > se - s + 5) { - *b++ = *s++; - if (*s) { -#ifdef USE_LOCALE - while((*b = *decimalpoint++)) - ++b; -#else - *b++ = '.'; -#endif - while((*b = *s++) !=0) - b++; - } - *b++ = 'e'; - /* sprintf(b, "%+.2d", decpt - 1); */ - if (--decpt < 0) { - *b++ = '-'; - decpt = -decpt; - } - else - *b++ = '+'; - for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10){} - for(;;) { - i = decpt / k; - if (b >= be) - goto ret0; - *b++ = i + '0'; - if (--j <= 0) - break; - decpt -= i*k; - decpt *= 10; - } - *b = 0; - } - else if (decpt <= 0) { -#ifdef USE_LOCALE - while((*b = *decimalpoint++)) - ++b; -#else - *b++ = '.'; -#endif - if (be < b - decpt + (se - s)) - goto ret0; - for(; decpt < 0; decpt++) - *b++ = '0'; - while((*b = *s++) != 0) - b++; - } - else { - while((*b = *s++) != 0) { - b++; - if (--decpt == 0 && *s) { -#ifdef USE_LOCALE - while(*b = *decimalpoint++) - ++b; -#else - *b++ = '.'; -#endif - } - } - if (b + decpt > be) { - ret0: - b = 0; - goto ret; - } - for(; decpt > 0; decpt--) - *b++ = '0'; - *b = 0; - } - ret: - freedtoa(s0); - return b; - } - - char * -add_nanbits_D2A(char *b, size_t blen, ULong *bits, int nb) -{ - ULong t; - char *rv; - int i, j; - size_t L; - static char Hexdig[16] = "0123456789abcdef"; - - while(!bits[--nb]) - if (!nb) - return b; - L = 8*nb + 3; - t = bits[nb]; - do ++L; while((t >>= 4)); - if (L > blen) - return b; - b += L; - *--b = 0; - rv = b; - *--b = /*(*/ ')'; - for(i = 0; i < nb; ++i) { - t = bits[i]; - for(j = 0; j < 8; ++j, t >>= 4) - *--b = Hexdig[t & 0xf]; - } - t = bits[nb]; - do *--b = Hexdig[t & 0xf]; while(t >>= 4); - *--b = '('; /*)*/ - return rv; - } diff --git a/libraries/gdtoa/g_ddfmt.c b/libraries/gdtoa/g_ddfmt.c deleted file mode 100644 index 5ce4a076b..000000000 --- a/libraries/gdtoa/g_ddfmt.c +++ /dev/null @@ -1,171 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg@acm.org). */ - -#include "gdtoaimp.h" -#include - - char * -#ifdef KR_headers -g_ddfmt(buf, dd0, ndig, bufsize) char *buf; double *dd0; int ndig; size_t bufsize; -#else -g_ddfmt(char *buf, double *dd0, int ndig, size_t bufsize) -#endif -{ - FPI fpi; - char *b, *s, *se; - ULong *L, bits0[4], *bits, *zx; - int bx, by, decpt, ex, ey, i, j, mode; - Bigint *x, *y, *z; - U *dd, ddx[2]; -#ifdef Honor_FLT_ROUNDS /*{{*/ - int Rounding; -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - Rounding = Flt_Rounds; -#else /*}{*/ - Rounding = 1; - switch(fegetround()) { - case FE_TOWARDZERO: Rounding = 0; break; - case FE_UPWARD: Rounding = 2; break; - case FE_DOWNWARD: Rounding = 3; - } -#endif /*}}*/ -#else /*}{*/ -#define Rounding FPI_Round_near -#endif /*}}*/ - - if (bufsize < 10 || bufsize < (size_t)(ndig + 8)) - return 0; - - dd = (U*)dd0; - L = dd->L; - if ((L[_0] & 0x7ff00000L) == 0x7ff00000L) { - /* Infinity or NaN */ - if (L[_0] & 0xfffff || L[_1]) { - nanret: - return strcp(buf, "NaN"); - } - if ((L[2+_0] & 0x7ff00000) == 0x7ff00000) { - if (L[2+_0] & 0xfffff || L[2+_1]) - goto nanret; - if ((L[_0] ^ L[2+_0]) & 0x80000000L) - goto nanret; /* Infinity - Infinity */ - } - infret: - b = buf; - if (L[_0] & 0x80000000L) - *b++ = '-'; - return strcp(b, "Infinity"); - } - if ((L[2+_0] & 0x7ff00000) == 0x7ff00000) { - L += 2; - if (L[_0] & 0xfffff || L[_1]) - goto nanret; - goto infret; - } - if (dval(&dd[0]) + dval(&dd[1]) == 0.) { - b = buf; -#ifndef IGNORE_ZERO_SIGN - if (L[_0] & L[2+_0] & 0x80000000L) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - if ((L[_0] & 0x7ff00000L) < (L[2+_0] & 0x7ff00000L)) { - dval(&ddx[1]) = dval(&dd[0]); - dval(&ddx[0]) = dval(&dd[1]); - dd = ddx; - L = dd->L; - } - z = d2b(dval(&dd[0]), &ex, &bx); - if (dval(&dd[1]) == 0.) - goto no_y; - x = z; - y = d2b(dval(&dd[1]), &ey, &by); - if ( (i = ex - ey) !=0) { - if (i > 0) { - x = lshift(x, i); - ex = ey; - } - else - y = lshift(y, -i); - } - if ((L[_0] ^ L[2+_0]) & 0x80000000L) { - z = diff(x, y); - if (L[_0] & 0x80000000L) - z->sign = 1 - z->sign; - } - else { - z = sum(x, y); - if (L[_0] & 0x80000000L) - z->sign = 1; - } - Bfree(x); - Bfree(y); - no_y: - bits = zx = z->x; - for(i = 0; !*zx; zx++) - i += 32; - i += lo0bits(zx); - if (i) { - rshift(z, i); - ex += i; - } - fpi.nbits = z->wds * 32 - hi0bits(z->x[j = z->wds-1]); - if (fpi.nbits < 106) { - fpi.nbits = 106; - if (j < 3) { - for(i = 0; i <= j; i++) - bits0[i] = bits[i]; - while(i < 4) - bits0[i++] = 0; - bits = bits0; - } - } - mode = 2; - if (ndig <= 0) { - if (bufsize < (size_t)((int)(fpi.nbits * .301029995664) + 10)) { - Bfree(z); - return 0; - } - mode = 0; - } - fpi.emin = 1-1023-53+1; - fpi.emax = 2046-1023-106+1; - fpi.rounding = Rounding; - fpi.sudden_underflow = 0; - fpi.int_max = Int_max; - i = STRTOG_Normal; - s = gdtoa(&fpi, ex, bits, &i, mode, ndig, &decpt, &se); - b = g__fmt(buf, s, se, decpt, z->sign, bufsize); - Bfree(z); - return b; - } diff --git a/libraries/gdtoa/g_dfmt.c b/libraries/gdtoa/g_dfmt.c deleted file mode 100644 index d8e1438c4..000000000 --- a/libraries/gdtoa/g_dfmt.c +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - char* -#ifdef KR_headers -g_dfmt(buf, d, ndig, bufsize) char *buf; double *d; int ndig; size_t bufsize; -#else -g_dfmt(char *buf, double *d, int ndig, size_t bufsize) -#endif -{ - static FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, 0, Int_max }; - char *b, *s, *se; - ULong bits[2], *L, sign; - int decpt, ex, i, mode; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - if (ndig < 0) - ndig = 0; - if (bufsize < (size_t)(ndig + 10)) - return 0; - - L = (ULong*)d; - sign = L[_0] & 0x80000000L; - if ((L[_0] & 0x7ff00000) == 0x7ff00000) { - /* Infinity or NaN */ - if (bufsize < 10) - return 0; - if (L[_0] & 0xfffff || L[_1]) { - return strcp(buf, "NaN"); - } - b = buf; - if (sign) - *b++ = '-'; - return strcp(b, "Infinity"); - } - if (L[_1] == 0 && (L[_0] ^ sign) == 0 /*d == 0.*/) { - b = buf; -#ifndef IGNORE_ZERO_SIGN - if (L[_0] & 0x80000000L) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - bits[0] = L[_1]; - bits[1] = L[_0] & 0xfffff; - if ( (ex = (L[_0] >> 20) & 0x7ff) !=0) - bits[1] |= 0x100000; - else - ex = 1; - ex -= 0x3ff + 52; - mode = 2; - if (ndig <= 0) - mode = 0; - i = STRTOG_Normal; - if (sign) - i = STRTOG_Normal | STRTOG_Neg; - s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se); - return g__fmt(buf, s, se, decpt, sign, bufsize); - } diff --git a/libraries/gdtoa/g_ffmt.c b/libraries/gdtoa/g_ffmt.c deleted file mode 100644 index 30b53ae7e..000000000 --- a/libraries/gdtoa/g_ffmt.c +++ /dev/null @@ -1,93 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - char* -#ifdef KR_headers -g_ffmt(buf, f, ndig, bufsize) char *buf; float *f; int ndig; size_t bufsize; -#else -g_ffmt(char *buf, float *f, int ndig, size_t bufsize) -#endif -{ - static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, 0, 6 }; - char *b, *s, *se; - ULong bits[1], *L, sign; - int decpt, ex, i, mode; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - if (ndig < 0) - ndig = 0; - if (bufsize < (size_t)(ndig + 10)) - return 0; - - L = (ULong*)f; - sign = L[0] & 0x80000000L; - if ((L[0] & 0x7f800000) == 0x7f800000) { - /* Infinity or NaN */ - if (L[0] & 0x7fffff) { - return strcp(buf, "NaN"); - } - b = buf; - if (sign) - *b++ = '-'; - return strcp(b, "Infinity"); - } - if (*f == 0.) { - b = buf; -#ifndef IGNORE_ZERO_SIGN - if (L[0] & 0x80000000L) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - bits[0] = L[0] & 0x7fffff; - if ( (ex = (L[0] >> 23) & 0xff) !=0) - bits[0] |= 0x800000; - else - ex = 1; - ex -= 0x7f + 23; - mode = 2; - if (ndig <= 0) { - if (bufsize < 16) - return 0; - mode = 0; - } - i = STRTOG_Normal; - s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se); - return g__fmt(buf, s, se, decpt, sign, bufsize); - } diff --git a/libraries/gdtoa/g_xLfmt.c b/libraries/gdtoa/g_xLfmt.c deleted file mode 100644 index 5cda8d59e..000000000 --- a/libraries/gdtoa/g_xLfmt.c +++ /dev/null @@ -1,113 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#endif -#ifdef IEEE_8087 -#define _0 2 -#define _1 1 -#define _2 0 -#endif - - char* -#ifdef KR_headers -g_xLfmt(buf, V, ndig, bufsize) char *buf; char *V; int ndig; size_t bufsize; -#else -g_xLfmt(char *buf, void *V, int ndig, size_t bufsize) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, 0, Int_max }; - char *b, *s, *se; - ULong bits[2], *L, sign; - int decpt, ex, i, mode; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - if (ndig < 0) - ndig = 0; - if (bufsize < (size_t)(ndig + 10)) - return 0; - - L = (ULong*)V; - sign = L[_0] & 0x80000000L; - bits[1] = L[_1]; - bits[0] = L[_2]; - if ( (ex = (L[_0] >> 16) & 0x7fff) !=0) { - if (ex == 0x7fff) { - /* Infinity or NaN */ - if (bits[0] | bits[1]) - b = strcp(buf, "NaN"); - else { - b = buf; - if (sign) - *b++ = '-'; - b = strcp(b, "Infinity"); - } - return b; - } - i = STRTOG_Normal; - } - else if (bits[0] | bits[1]) { - i = STRTOG_Denormal; - } - else { - b = buf; -#ifndef IGNORE_ZERO_SIGN - if (sign) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - ex -= 0x3fff + 63; - mode = 2; - if (ndig <= 0) { - if (bufsize < 32) - return 0; - mode = 0; - } - s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se); - return g__fmt(buf, s, se, decpt, sign, bufsize); - } diff --git a/libraries/gdtoa/g_xfmt.c b/libraries/gdtoa/g_xfmt.c deleted file mode 100644 index a0baa518c..000000000 --- a/libraries/gdtoa/g_xfmt.c +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#define _4 4 -#endif -#ifdef IEEE_8087 -#define _0 4 -#define _1 3 -#define _2 2 -#define _3 1 -#define _4 0 -#endif - - char* -#ifdef KR_headers -g_xfmt(buf, V, ndig, bufsize) char *buf; char *V; int ndig; size_t bufsize; -#else -g_xfmt(char *buf, void *V, int ndig, size_t bufsize) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, 0, Int_max }; - char *b, *s, *se; - ULong bits[2], sign; - UShort *L; - int decpt, ex, i, mode; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - if (ndig < 0) - ndig = 0; - if (bufsize < (size_t)(ndig + 10)) - return 0; - - L = (UShort *)V; - sign = L[_0] & 0x8000; - bits[1] = (L[_1] << 16) | L[_2]; - bits[0] = (L[_3] << 16) | L[_4]; - if ( (ex = L[_0] & 0x7fff) !=0) { - if (ex == 0x7fff) { - /* Infinity or NaN */ - if (!bits[0] && bits[1]== 0x80000000) { - b = buf; - if (sign) - *b++ = '-'; - b = strcp(b, "Infinity"); - } - else - b = strcp(buf, "NaN"); - return b; - } - i = STRTOG_Normal; - } - else if (bits[0] | bits[1]) { - i = STRTOG_Denormal; - ex = 1; - } - else { - b = buf; -#ifndef IGNORE_ZERO_SIGN - if (sign) - *b++ = '-'; -#endif - *b++ = '0'; - *b = 0; - return b; - } - ex -= 0x3fff + 63; - mode = 2; - if (ndig <= 0) { - if (bufsize < 32) - return 0; - mode = 0; - } - s = gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se); - return g__fmt(buf, s, se, decpt, sign, bufsize); - } diff --git a/libraries/gdtoa/gdtoa.c b/libraries/gdtoa/gdtoa.c deleted file mode 100644 index a4759968a..000000000 --- a/libraries/gdtoa/gdtoa.c +++ /dev/null @@ -1,764 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 1999 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - static Bigint * -#ifdef KR_headers -bitstob(bits, nbits, bbits) ULong *bits; int nbits; int *bbits; -#else -bitstob(ULong *bits, int nbits, int *bbits) -#endif -{ - int i, k; - Bigint *b; - ULong *be, *x, *x0; - - i = ULbits; - k = 0; - while(i < nbits) { - i <<= 1; - k++; - } -#ifndef Pack_32 - if (!k) - k = 1; -#endif - b = Balloc(k); - be = bits + ((nbits - 1) >> kshift); - x = x0 = b->x; - do { - *x++ = *bits & ALL_ON; -#ifdef Pack_16 - *x++ = (*bits >> 16) & ALL_ON; -#endif - } while(++bits <= be); - i = x - x0; - while(!x0[--i]) - if (!i) { - b->wds = 0; - *bbits = 0; - goto ret; - } - b->wds = i + 1; - *bbits = i*ULbits + 32 - hi0bits(b->x[i]); - ret: - return b; - } - -/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. - * - * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126]. - * - * Modifications: - * 1. Rather than iterating, we use a simple numeric overestimate - * to determine k = floor(log10(d)). We scale relevant - * quantities using O(log2(k)) rather than O(k) multiplications. - * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't - * try to generate digits strictly left to right. Instead, we - * compute with fewer bits and propagate the carry if necessary - * when rounding the final digit up. This is often faster. - * 3. Under the assumption that input will be rounded nearest, - * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. - * That is, we allow equality in stopping tests when the - * round-nearest rule will give the same floating-point value - * as would satisfaction of the stopping test with strict - * inequality. - * 4. We remove common factors of powers of 2 from relevant - * quantities. - * 5. When converting floating-point integers less than 1e16, - * we use floating-point arithmetic rather than resorting - * to multiple-precision integers. - * 6. When asked to produce fewer than 15 digits, we first try - * to get by with floating-point arithmetic; we resort to - * multiple-precision integer arithmetic only if we cannot - * guarantee that the floating-point calculation has given - * the correctly rounded result. For k requested digits and - * "uniformly" distributed input, the probability is - * something like 10^(k-15) that we must resort to the Long - * calculation. - */ - - char * -gdtoa -#ifdef KR_headers - (fpi, be, bits, kindp, mode, ndigits, decpt, rve) - FPI *fpi; int be; ULong *bits; - int *kindp, mode, ndigits, *decpt; char **rve; -#else - (FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits, int *decpt, char **rve) -#endif -{ - /* Arguments ndigits and decpt are similar to the second and third - arguments of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If not null, *rve is set to point - to the end of the return value. If d is +-Infinity or NaN, - then *decpt is set to 9999. - be = exponent: value = (integer represented by bits) * (2 to the power of be). - - mode: - 0 ==> shortest string that yields d when read in - and rounded to nearest. - 1 ==> like 0, but with Steele & White stopping rule; - e.g. with IEEE P754 arithmetic , mode 0 gives - 1e23 whereas mode 1 gives 9.999999999999999e22. - 2 ==> max(1,ndigits) significant digits. This gives a - return value similar to that of ecvt, except - that trailing zeros are suppressed. - 3 ==> through ndigits past the decimal point. This - gives a return value similar to that from fcvt, - except that trailing zeros are suppressed, and - ndigits can be negative. - 4-9 should give the same return values as 2-3, i.e., - 4 <= mode <= 9 ==> same return as mode - 2 + (mode & 1). These modes are mainly for - debugging; often they run slower but sometimes - faster than modes 2-3. - 4,5,8,9 ==> left-to-right digit generation. - 6-9 ==> don't try fast floating-point estimate - (if applicable). - - Values of mode other than 0-9 are treated as mode 0. - - Sufficient space is allocated to the return value - to hold the suppressed trailing zeros. - */ - - int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex; - int j, j1, k, k0, k_check, kind, leftright, m2, m5, nbits; - int rdir, s2, s5, spec_case, try_quick; - Long L; - Bigint *b, *b1, *delta, *mlo, *mhi, *mhi1, *S; - double d2, ds; - char *s, *s0; - U d, eps; - -#ifndef MULTIPLE_THREADS - if (dtoa_result) { - freedtoa(dtoa_result); - dtoa_result = 0; - } -#endif - inex = 0; - kind = *kindp &= ~STRTOG_Inexact; - switch(kind & STRTOG_Retmask) { - case STRTOG_Zero: - goto ret_zero; - case STRTOG_Normal: - case STRTOG_Denormal: - break; - case STRTOG_Infinite: - *decpt = -32768; - return nrv_alloc("Infinity", rve, 8); - case STRTOG_NaN: - *decpt = -32768; - return nrv_alloc("NaN", rve, 3); - default: - return 0; - } - b = bitstob(bits, nbits = fpi->nbits, &bbits); - be0 = be; - if ( (i = trailz(b)) !=0) { - rshift(b, i); - be += i; - bbits -= i; - } - if (!b->wds) { - Bfree(b); - ret_zero: - *decpt = 1; - return nrv_alloc("0", rve, 1); - } - - dval(&d) = b2d(b, &i); - i = be + bbits - 1; - word0(&d) &= Frac_mask1; - word0(&d) |= Exp_11; -#ifdef IBM - if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0) - dval(&d) /= 1 << j; -#endif - - /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 - * log10(x) = log(x) / log(10) - * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) - * log10(&d) = (i-Bias)*log(2)/log(10) + log10(d2) - * - * This suggests computing an approximation k to log10(&d) by - * - * k = (i - Bias)*0.301029995663981 - * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); - * - * We want k to be too large rather than too small. - * The error in the first-order Taylor series approximation - * is in our favor, so we just round up the constant enough - * to compensate for any error in the multiplication of - * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, - * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, - * adding 1e-13 to the constant term more than suffices. - * Hence we adjust the constant term to 0.1760912590558. - * (We could get a more accurate k by invoking log10, - * but this is probably not worthwhile.) - */ -#ifdef IBM - i <<= 2; - i += j; -#endif - ds = (dval(&d)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; - - /* correct assumption about exponent range */ - if ((j = i) < 0) - j = -j; - if ((j -= 1077) > 0) - ds += j * 7e-17; - - k = (int)ds; - if (ds < 0. && ds != k) - k--; /* want k = floor(ds) */ - k_check = 1; -#ifdef IBM - j = be + bbits - 1; - if ( (j1 = j & 3) !=0) - dval(&d) *= 1 << j1; - word0(&d) += j << Exp_shift - 2 & Exp_mask; -#else - word0(&d) += (be + bbits - 1) << Exp_shift; -#endif - if (k >= 0 && k <= Ten_pmax) { - if (dval(&d) < tens[k]) - k--; - k_check = 0; - } - j = bbits - i - 1; - if (j >= 0) { - b2 = 0; - s2 = j; - } - else { - b2 = -j; - s2 = 0; - } - if (k >= 0) { - b5 = 0; - s5 = k; - s2 += k; - } - else { - b2 -= k; - b5 = -k; - s5 = 0; - } - if (mode < 0 || mode > 9) - mode = 0; - try_quick = 1; - if (mode > 5) { - mode -= 4; - try_quick = 0; - } - else if (i >= -4 - Emin || i < Emin) - try_quick = 0; - leftright = 1; - ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */ - /* silence erroneous "gcc -Wall" warning. */ - switch(mode) { - case 0: - case 1: - i = (int)(nbits * .30103) + 3; - ndigits = 0; - break; - case 2: - leftright = 0; - /* no break */ - case 4: - if (ndigits <= 0) - ndigits = 1; - ilim = ilim1 = i = ndigits; - break; - case 3: - leftright = 0; - /* no break */ - case 5: - i = ndigits + k + 1; - ilim = i; - ilim1 = i - 1; - if (i <= 0) - i = 1; - } - s = s0 = rv_alloc(i); - - if ( (rdir = fpi->rounding - 1) !=0) { - if (rdir < 0) - rdir = 2; - if (kind & STRTOG_Neg) - rdir = 3 - rdir; - } - - /* Now rdir = 0 ==> round near, 1 ==> round up, 2 ==> round down. */ - - if (ilim >= 0 && ilim <= Quick_max && try_quick && !rdir -#ifndef IMPRECISE_INEXACT - && k == 0 -#endif - ) { - - /* Try to get by with floating-point arithmetic. */ - - i = 0; - d2 = dval(&d); -#ifdef IBM - if ( (j = 11 - hi0bits(word0(&d) & Frac_mask)) !=0) - dval(&d) /= 1 << j; -#endif - k0 = k; - ilim0 = ilim; - ieps = 2; /* conservative */ - if (k > 0) { - ds = tens[k&0xf]; - j = k >> 4; - if (j & Bletch) { - /* prevent overflows */ - j &= Bletch - 1; - dval(&d) /= bigtens[n_bigtens-1]; - ieps++; - } - for(; j; j >>= 1, i++) - if (j & 1) { - ieps++; - ds *= bigtens[i]; - } - } - else { - ds = 1.; - if ( (j1 = -k) !=0) { - dval(&d) *= tens[j1 & 0xf]; - for(j = j1 >> 4; j; j >>= 1, i++) - if (j & 1) { - ieps++; - dval(&d) *= bigtens[i]; - } - } - } - if (k_check && dval(&d) < 1. && ilim > 0) { - if (ilim1 <= 0) - goto fast_failed; - ilim = ilim1; - k--; - dval(&d) *= 10.; - ieps++; - } - dval(&eps) = ieps*dval(&d) + 7.; - word0(&eps) -= (P-1)*Exp_msk1; - if (ilim == 0) { - S = mhi = 0; - dval(&d) -= 5.; - if (dval(&d) > dval(&eps)) - goto one_digit; - if (dval(&d) < -dval(&eps)) - goto no_digits; - goto fast_failed; - } -#ifndef No_leftright - if (leftright) { - /* Use Steele & White method of only - * generating digits needed. - */ - dval(&eps) = ds*0.5/tens[ilim-1] - dval(&eps); - for(i = 0;;) { - L = (Long)(dval(&d)/ds); - dval(&d) -= L*ds; - *s++ = '0' + (int)L; - if (dval(&d) < dval(&eps)) { - if (dval(&d)) - inex = STRTOG_Inexlo; - goto ret1; - } - if (ds - dval(&d) < dval(&eps)) - goto bump_up; - if (++i >= ilim) - break; - dval(&eps) *= 10.; - dval(&d) *= 10.; - } - } - else { -#endif - /* Generate ilim digits, then fix them up. */ - dval(&eps) *= tens[ilim-1]; - for(i = 1;; i++, dval(&d) *= 10.) { - if ( (L = (Long)(dval(&d)/ds)) !=0) - dval(&d) -= L*ds; - *s++ = '0' + (int)L; - if (i == ilim) { - ds *= 0.5; - if (dval(&d) > ds + dval(&eps)) - goto bump_up; - else if (dval(&d) < ds - dval(&eps)) { - if (dval(&d)) - inex = STRTOG_Inexlo; - goto clear_trailing0; - } - break; - } - } -#ifndef No_leftright - } -#endif - fast_failed: - s = s0; - dval(&d) = d2; - k = k0; - ilim = ilim0; - } - - /* Do we have a "small" integer? */ - - if (be >= 0 && k <= fpi->int_max) { - /* Yes. */ - ds = tens[k]; - if (ndigits < 0 && ilim <= 0) { - S = mhi = 0; - if (ilim < 0 || dval(&d) <= 5*ds) - goto no_digits; - goto one_digit; - } - for(i = 1;; i++, dval(&d) *= 10.) { - L = (Long)(dval(&d) / ds); - dval(&d) -= L*ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (dval(&d) < 0) { - L--; - dval(&d) += ds; - } -#endif - *s++ = '0' + (int)L; - if (dval(&d) == 0.) - break; - if (i == ilim) { - if (rdir) { - if (rdir == 1) - goto bump_up; - inex = STRTOG_Inexlo; - goto ret1; - } - dval(&d) += dval(&d); -#ifdef ROUND_BIASED - if (dval(&d) >= ds) -#else - if (dval(&d) > ds || (dval(&d) == ds && L & 1)) -#endif - { - bump_up: - inex = STRTOG_Inexhi; - while(*--s == '9') - if (s == s0) { - k++; - *s = '0'; - break; - } - ++*s++; - } - else { - inex = STRTOG_Inexlo; - clear_trailing0: - while(*--s == '0'){} - ++s; - } - break; - } - } - goto ret1; - } - - m2 = b2; - m5 = b5; - mhi = mlo = 0; - if (leftright) { - i = nbits - bbits; - if (be - i++ < fpi->emin && mode != 3 && mode != 5) { - /* denormal */ - i = be - fpi->emin + 1; - if (mode >= 2 && ilim > 0 && ilim < i) - goto small_ilim; - } - else if (mode >= 2) { - small_ilim: - j = ilim - 1; - if (m5 >= j) - m5 -= j; - else { - s5 += j -= m5; - b5 += j; - m5 = 0; - } - if ((i = ilim) < 0) { - m2 -= i; - i = 0; - } - } - b2 += i; - s2 += i; - mhi = i2b(1); - } - if (m2 > 0 && s2 > 0) { - i = m2 < s2 ? m2 : s2; - b2 -= i; - m2 -= i; - s2 -= i; - } - if (b5 > 0) { - if (leftright) { - if (m5 > 0) { - mhi = pow5mult(mhi, m5); - b1 = mult(mhi, b); - Bfree(b); - b = b1; - } - if ( (j = b5 - m5) !=0) - b = pow5mult(b, j); - } - else - b = pow5mult(b, b5); - } - S = i2b(1); - if (s5 > 0) - S = pow5mult(S, s5); - - /* Check for special case that d is a normalized power of 2. */ - - spec_case = 0; - if (mode < 2) { - if (bbits == 1 && be0 > fpi->emin + 1) { - /* The special case */ - b2++; - s2++; - spec_case = 1; - } - } - - /* Arrange for convenient computation of quotients: - * shift left if necessary so divisor has 4 leading 0 bits. - * - * Perhaps we should just compute leading 28 bits of S once - * and for all and pass them and a shift to quorem, so it - * can do shifts and ors to compute the numerator for q. - */ - i = ((s5 ? hi0bits(S->x[S->wds-1]) : ULbits - 1) - s2 - 4) & kmask; - m2 += i; - if ((b2 += i) > 0) - b = lshift(b, b2); - if ((s2 += i) > 0) - S = lshift(S, s2); - if (k_check) { - if (cmp(b,S) < 0) { - k--; - b = multadd(b, 10, 0); /* we botched the k estimate */ - if (leftright) - mhi = multadd(mhi, 10, 0); - ilim = ilim1; - } - } - if (ilim <= 0 && mode > 2) { - if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { - /* no digits, fcvt style */ - no_digits: - k = -1 - ndigits; - inex = STRTOG_Inexlo; - goto ret; - } - one_digit: - inex = STRTOG_Inexhi; - *s++ = '1'; - k++; - goto ret; - } - if (leftright) { - if (m2 > 0) - mhi = lshift(mhi, m2); - - /* Compute mlo -- check for special case - * that d is a normalized power of 2. - */ - - mlo = mhi; - if (spec_case) { - mhi = Balloc(mhi->k); - Bcopy(mhi, mlo); - mhi = lshift(mhi, 1); - } - - for(i = 1;;i++) { - dig = quorem(b,S) + '0'; - /* Do we yet have the shortest decimal string - * that will round to d? - */ - j = cmp(b, mlo); - delta = diff(S, mhi); - j1 = delta->sign ? 1 : cmp(b, delta); - Bfree(delta); -#ifndef ROUND_BIASED - if (j1 == 0 && !mode && !(bits[0] & 1) && !rdir) { - if (dig == '9') - goto round_9_up; - if (j <= 0) { - if (b->wds > 1 || b->x[0]) - inex = STRTOG_Inexlo; - } - else { - dig++; - inex = STRTOG_Inexhi; - } - *s++ = dig; - goto ret; - } -#endif - if (j < 0 || (j == 0 && !mode -#ifndef ROUND_BIASED - && !(bits[0] & 1) -#endif - )) { - if (rdir && (b->wds > 1 || b->x[0])) { - if (rdir == 2) { - inex = STRTOG_Inexlo; - goto accept; - } - while (cmp(S,mhi) > 0) { - *s++ = dig; - mhi1 = multadd(mhi, 10, 0); - if (mlo == mhi) - mlo = mhi1; - mhi = mhi1; - b = multadd(b, 10, 0); - dig = quorem(b,S) + '0'; - } - if (dig++ == '9') - goto round_9_up; - inex = STRTOG_Inexhi; - goto accept; - } - if (j1 > 0) { - b = lshift(b, 1); - j1 = cmp(b, S); -#ifdef ROUND_BIASED - if (j1 >= 0 /*)*/ -#else - if ((j1 > 0 || (j1 == 0 && dig & 1)) -#endif - && dig++ == '9') - goto round_9_up; - inex = STRTOG_Inexhi; - } - if (b->wds > 1 || b->x[0]) - inex = STRTOG_Inexlo; - accept: - *s++ = dig; - goto ret; - } - if (j1 > 0 && rdir != 2) { - if (dig == '9') { /* possible if i == 1 */ - round_9_up: - *s++ = '9'; - inex = STRTOG_Inexhi; - goto roundoff; - } - inex = STRTOG_Inexhi; - *s++ = dig + 1; - goto ret; - } - *s++ = dig; - if (i == ilim) - break; - b = multadd(b, 10, 0); - if (mlo == mhi) - mlo = mhi = multadd(mhi, 10, 0); - else { - mlo = multadd(mlo, 10, 0); - mhi = multadd(mhi, 10, 0); - } - } - } - else - for(i = 1;; i++) { - *s++ = dig = quorem(b,S) + '0'; - if (i >= ilim) - break; - b = multadd(b, 10, 0); - } - - /* Round off last digit */ - - if (rdir) { - if (rdir == 2 || (b->wds <= 1 && !b->x[0])) - goto chopzeros; - goto roundoff; - } - b = lshift(b, 1); - j = cmp(b, S); -#ifdef ROUND_BIASED - if (j >= 0) -#else - if (j > 0 || (j == 0 && dig & 1)) -#endif - { - roundoff: - inex = STRTOG_Inexhi; - while(*--s == '9') - if (s == s0) { - k++; - *s++ = '1'; - goto ret; - } - ++*s++; - } - else { - chopzeros: - if (b->wds > 1 || b->x[0]) - inex = STRTOG_Inexlo; - while(*--s == '0'){} - ++s; - } - ret: - Bfree(S); - if (mhi) { - if (mlo && mlo != mhi) - Bfree(mlo); - Bfree(mhi); - } - ret1: - Bfree(b); - *s = 0; - *decpt = k + 1; - if (rve) - *rve = s; - *kindp |= inex; - return s0; - } diff --git a/libraries/gdtoa/gdtoa.h b/libraries/gdtoa/gdtoa.h deleted file mode 100644 index 516e6a68c..000000000 --- a/libraries/gdtoa/gdtoa.h +++ /dev/null @@ -1,189 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#ifndef GDTOA_H_INCLUDED -#define GDTOA_H_INCLUDED - -#if defined(_MSC_VER) -/* [RH] Generating arith.h strikes me as too cumbersome under Visual - * Studio, so here's the equivalent, given the limited number of - * architectures that MSC can target. (Itanium? Who cares about that?) - */ -#define IEEE_8087 -#define Arith_Kind_ASL 1 -#define Double_Align -#ifdef _M_X64 -#define X64_bit_pointers -#endif -#elif defined(__APPLE__) -/* [BL] While generating the files may be easy, on OS X we have cross - * compiling to deal with, which means we can't run the generation - * program on the target. - */ -#if defined(__x86_64__) || defined(__arm64__) -#define IEEE_8087 -#define Arith_Kind_ASL 1 -#define Long int -#define Intcast (int)(long) -#define Double_Align -#define X64_bit_pointers -#else -#error Unsupported architecture -#endif -#else -#include "arith.h" -#endif -#include /* for size_t */ - -#ifndef Long -#define Long int -#endif -#ifndef ULong -typedef unsigned Long ULong; -#endif -#ifndef UShort -typedef unsigned short UShort; -#endif - -#ifndef ANSI -#ifdef KR_headers -#define ANSI(x) () -#define Void /*nothing*/ -#else -#define ANSI(x) x -#define Void void -#endif -#endif /* ANSI */ - -#ifndef CONST -#ifdef KR_headers -#define CONST /* blank */ -#else -#define CONST const -#endif -#endif /* CONST */ - - enum { /* return values from strtodg */ - STRTOG_Zero = 0, - STRTOG_Normal = 1, - STRTOG_Denormal = 2, - STRTOG_Infinite = 3, - STRTOG_NaN = 4, - STRTOG_NaNbits = 5, - STRTOG_NoNumber = 6, - STRTOG_Retmask = 7, - - /* The following may be or-ed into one of the above values. */ - - STRTOG_Neg = 0x08, /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */ - STRTOG_Inexlo = 0x10, /* returned result rounded toward zero */ - STRTOG_Inexhi = 0x20, /* returned result rounded away from zero */ - STRTOG_Inexact = 0x30, - STRTOG_Underflow= 0x40, - STRTOG_Overflow = 0x80 - }; - - typedef struct -FPI { - int nbits; - int emin; - int emax; - int rounding; - int sudden_underflow; - int int_max; - } FPI; - -enum { /* FPI.rounding values: same as FLT_ROUNDS */ - FPI_Round_zero = 0, - FPI_Round_near = 1, - FPI_Round_up = 2, - FPI_Round_down = 3 - }; - -#ifdef __cplusplus -extern "C" { -#endif - -extern char* dtoa ANSI((double d, int mode, int ndigits, int *decpt, - int *sign, char **rve)); -extern char* gdtoa ANSI((FPI *fpi, int be, ULong *bits, int *kindp, - int mode, int ndigits, int *decpt, char **rve)); -extern void freedtoa ANSI((char*)); -//extern float strtof ANSI((CONST char *, char **)); -//extern double strtod ANSI((CONST char *, char **)); -extern int strtodg ANSI((CONST char*, char**, FPI*, Long*, ULong*)); - -extern char* g_ddfmt ANSI((char*, double*, int, size_t)); -extern char* g_ddfmt_p ANSI((char*, double*, int, size_t, int)); -extern char* g_dfmt ANSI((char*, double*, int, size_t)); -extern char* g_dfmt_p ANSI((char*, double*, int, size_t, int)); -extern char* g_ffmt ANSI((char*, float*, int, size_t)); -extern char* g_ffmt_p ANSI((char*, float*, int, size_t, int)); -extern char* g_Qfmt ANSI((char*, void*, int, size_t)); -extern char* g_Qfmt_p ANSI((char*, void*, int, size_t, int)); -extern char* g_xfmt ANSI((char*, void*, int, size_t)); -extern char* g_xfmt_p ANSI((char*, void*, int, size_t, int)); -extern char* g_xLfmt ANSI((char*, void*, int, size_t)); -extern char* g_xLfmt_p ANSI((char*, void*, int, size_t, int)); - -extern int strtoId ANSI((CONST char*, char**, double*, double*)); -extern int strtoIdd ANSI((CONST char*, char**, double*, double*)); -extern int strtoIf ANSI((CONST char*, char**, float*, float*)); -extern int strtoIQ ANSI((CONST char*, char**, void*, void*)); -extern int strtoIx ANSI((CONST char*, char**, void*, void*)); -extern int strtoIxL ANSI((CONST char*, char**, void*, void*)); -extern int strtord ANSI((CONST char*, char**, int, double*)); -extern int strtordd ANSI((CONST char*, char**, int, double*)); -extern int strtorf ANSI((CONST char*, char**, int, float*)); -extern int strtorQ ANSI((CONST char*, char**, int, void*)); -extern int strtorx ANSI((CONST char*, char**, int, void*)); -extern int strtorxL ANSI((CONST char*, char**, int, void*)); -#if 1 -extern int strtodI ANSI((CONST char*, char**, double*)); -extern int strtopd ANSI((CONST char*, char**, double*)); -extern int strtopdd ANSI((CONST char*, char**, double*)); -extern int strtopf ANSI((CONST char*, char**, float*)); -extern int strtopQ ANSI((CONST char*, char**, void*)); -extern int strtopx ANSI((CONST char*, char**, void*)); -extern int strtopxL ANSI((CONST char*, char**, void*)); -#else -#define strtopd(s,se,x) strtord(s,se,1,x) -#define strtopdd(s,se,x) strtordd(s,se,1,x) -#define strtopf(s,se,x) strtorf(s,se,1,x) -#define strtopQ(s,se,x) strtorQ(s,se,1,x) -#define strtopx(s,se,x) strtorx(s,se,1,x) -#define strtopxL(s,se,x) strtorxL(s,se,1,x) -#endif - -#ifdef __cplusplus -} -#endif -#endif /* GDTOA_H_INCLUDED */ diff --git a/libraries/gdtoa/gdtoa_fltrnds.h b/libraries/gdtoa/gdtoa_fltrnds.h deleted file mode 100644 index 33e5f9e53..000000000 --- a/libraries/gdtoa/gdtoa_fltrnds.h +++ /dev/null @@ -1,18 +0,0 @@ - FPI *fpi, fpi1; - int Rounding; -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - Rounding = Flt_Rounds; -#else /*}{*/ - Rounding = 1; - switch(fegetround()) { - case FE_TOWARDZERO: Rounding = 0; break; - case FE_UPWARD: Rounding = 2; break; - case FE_DOWNWARD: Rounding = 3; - } -#endif /*}}*/ - fpi = &fpi0; - if (Rounding != 1) { - fpi1 = fpi0; - fpi = &fpi1; - fpi1.rounding = Rounding; - } diff --git a/libraries/gdtoa/gdtoaimp.h b/libraries/gdtoa/gdtoaimp.h deleted file mode 100644 index ae7eeb572..000000000 --- a/libraries/gdtoa/gdtoaimp.h +++ /dev/null @@ -1,674 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998-2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* This is a variation on dtoa.c that converts arbitary binary - floating-point formats to and from decimal notation. It uses - double-precision arithmetic internally, so there are still - various #ifdefs that adapt the calculations to the native - double-precision arithmetic (any of IEEE, VAX D_floating, - or IBM mainframe arithmetic). - - Please send bug reports to David M. Gay (dmg at acm dot org, - with " at " changed at "@" and " dot " changed to "."). - */ - -/* On a machine with IEEE extended-precision registers, it is - * necessary to specify double-precision (53-bit) rounding precision - * before invoking strtod or dtoa. If the machine uses (the equivalent - * of) Intel 80x87 arithmetic, the call - * _control87(PC_53, MCW_PC); - * does this with many compilers. Whether this or another call is - * appropriate depends on the compiler; for this to work, it may be - * necessary to #include "float.h" or another system-dependent header - * file. - */ - -/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. - * - * This strtod returns a nearest machine number to the input decimal - * string (or sets errno to ERANGE). With IEEE arithmetic, ties are - * broken by the IEEE round-even rule. Otherwise ties are broken by - * biased rounding (add half and chop). - * - * Inspired loosely by William D. Clinger's paper "How to Read Floating - * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126]. - * - * Modifications: - * - * 1. We only require IEEE, IBM, or VAX double-precision - * arithmetic (not IEEE double-extended). - * 2. We get by with floating-point arithmetic in a case that - * Clinger missed -- when we're computing d * 10^n - * for a small integer d and the integer n is not too - * much larger than 22 (the maximum integer k for which - * we can represent 10^k exactly), we may be able to - * compute (d*10^k) * 10^(e-k) with just one roundoff. - * 3. Rather than a bit-at-a-time adjustment of the binary - * result in the hard case, we use floating-point - * arithmetic to determine the adjustment to within - * one bit; only in really hard cases do we need to - * compute a second residual. - * 4. Because of 3., we don't need a large table of powers of 10 - * for ten-to-e (just some small tables, e.g. of 10^k - * for 0 <= k <= 22). - */ - -/* - * #define IEEE_8087 for IEEE-arithmetic machines where the least - * significant byte has the lowest address. - * #define IEEE_MC68k for IEEE-arithmetic machines where the most - * significant byte has the lowest address. - * #define Long int on machines with 32-bit ints and 64-bit longs. - * #define Sudden_Underflow for IEEE-format machines without gradual - * underflow (i.e., that flush to zero on underflow). - * #define IBM for IBM mainframe-style floating-point arithmetic. - * #define VAX for VAX-style floating-point arithmetic (D_floating). - * #define No_leftright to omit left-right logic in fast floating-point - * computation of dtoa and gdtoa. This will cause modes 4 and 5 to be - * treated the same as modes 2 and 3 for some inputs. - * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3. - * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines - * that use extended-precision instructions to compute rounded - * products and quotients) with IBM. - * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic - * that rounds toward +Infinity. - * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased - * rounding when the underlying floating-point arithmetic uses - * unbiased rounding. This prevent using ordinary floating-point - * arithmetic when the result could be computed with one rounding error. - * #define Inaccurate_Divide for IEEE-format with correctly rounded - * products but inaccurate quotients, e.g., for Intel i860. - * #define NO_LONG_LONG on machines that do not have a "long long" - * integer type (of >= 64 bits). On such machines, you can - * #define Just_16 to store 16 bits per 32-bit Long when doing - * high-precision integer arithmetic. Whether this speeds things - * up or slows things down depends on the machine and the number - * being converted. If long long is available and the name is - * something other than "long long", #define Llong to be the name, - * and if "unsigned Llong" does not work as an unsigned version of - * Llong, #define #ULLong to be the corresponding unsigned type. - * #define KR_headers for old-style C function headers. - * #define Bad_float_h if your system lacks a float.h or if it does not - * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, - * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. - * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) - * if memory is available and otherwise does something you deem - * appropriate. If MALLOC is undefined, malloc will be invoked - * directly -- and assumed always to succeed. Similarly, if you - * want something other than the system's free() to be called to - * recycle memory acquired from MALLOC, #define FREE to be the - * name of the alternate routine. (FREE or free is only called in - * pathological cases, e.g., in a gdtoa call after a gdtoa return in - * mode 3 with thousands of digits requested.) - * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making - * memory allocations from a private pool of memory when possible. - * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes, - * unless #defined to be a different length. This default length - * suffices to get rid of MALLOC calls except for unusual cases, - * such as decimal-to-binary conversion of a very long string of - * digits. When converting IEEE double precision values, the - * longest string gdtoa can return is about 751 bytes long. For - * conversions by strtod of strings of 800 digits and all gdtoa - * conversions of IEEE doubles in single-threaded executions with - * 8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with - * 4-byte pointers, PRIVATE_MEM >= 7112 appears adequate. - * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK - * #defined automatically on IEEE systems. On such systems, - * when INFNAN_CHECK is #defined, strtod checks - * for Infinity and NaN (case insensitively). - * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined, - * strtodg also accepts (case insensitively) strings of the form - * NaN(x), where x is a string of hexadecimal digits (optionally - * preceded by 0x or 0X) and spaces; if there is only one string - * of hexadecimal digits, it is taken for the fraction bits of the - * resulting NaN; if there are two or more strings of hexadecimal - * digits, each string is assigned to the next available sequence - * of 32-bit words of fractions bits (starting with the most - * significant), right-aligned in each sequence. - * Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)" - * is consumed even when ... has the wrong form (in which case the - * "(...)" is consumed but ignored). - * #define MULTIPLE_THREADS if the system offers preemptively scheduled - * multiple threads. In this case, you must provide (or suitably - * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed - * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed - * in pow5mult, ensures lazy evaluation of only one copy of high - * powers of 5; omitting this lock would introduce a small - * probability of wasting memory, but would otherwise be harmless.) - * You must also invoke freedtoa(s) to free the value s returned by - * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined. - * #define IMPRECISE_INEXACT if you do not care about the setting of - * the STRTOG_Inexact bits in the special case of doing IEEE double - * precision conversions (which could also be done by the strtod in - * dtoa.c). - * #define NO_HEX_FP to disable recognition of C9x's hexadecimal - * floating-point constants. - * #define -DNO_ERRNO to suppress setting errno (in strtod.c and - * strtodg.c). - * #define NO_STRING_H to use private versions of memcpy. - * On some K&R systems, it may also be necessary to - * #define DECLARE_SIZE_T in this case. - * #define USE_LOCALE to use the current locale's decimal_point value. - */ - -#ifndef GDTOAIMP_H_INCLUDED -#define GDTOAIMP_H_INCLUDED -#include "gdtoa.h" - -#if defined(_MSC_VER) -/* [RH] Generating gd_qnan.h strikes me as too cumbersome under Visual - * Studio, so here's the equivalent, given the limited number of - * architectures that MSC can target. (Itanium? Who cares about that?) - */ -#define f_QNAN 0xffc00000 -#define d_QNAN0 0x0 -#define d_QNAN1 0xfff80000 -#define ld_QNAN0 0x0 -#define ld_QNAN1 0xfff80000 -#define ld_QNAN2 0x0 -#define ld_QNAN3 0x0 -#define ldus_QNAN0 0x0 -#define ldus_QNAN1 0x0 -#define ldus_QNAN2 0x0 -#define ldus_QNAN3 0xfff8 -#define ldus_QNAN4 0x0 -/* [RH] Interestingly, MinGW produces something different because - * it turns out that it has a true long double type. I thought that - * all ia32 compilers had phased out extended precision. - */ -#elif defined(__APPLE__) -#if defined(__x86_64__) || defined(__arm64__) -#define f_QNAN 0xffc00000 -#define d_QNAN0 0x0 -#define d_QNAN1 0xfff80000 -#define ld_QNAN0 0x0 -#define ld_QNAN1 0xc0000000 -#define ld_QNAN2 0xffff -#define ld_QNAN3 0x0 -#define ldus_QNAN0 0x0 -#define ldus_QNAN1 0x0 -#define ldus_QNAN2 0x0 -#define ldus_QNAN3 0xc000 -#define ldus_QNAN4 0xffff -#else -#error Unsupported architecture -#endif -#else -#include "gd_qnan.h" -#endif - -#ifdef Honor_FLT_ROUNDS -#include -#endif - -#ifdef DEBUG -#include "stdio.h" -#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} -#endif - -#include "stdlib.h" -#include "string.h" - -#ifdef KR_headers -#define Char char -#else -#define Char void -#endif - -#ifdef MALLOC -extern Char *MALLOC ANSI((size_t)); -#else -#define MALLOC malloc -#endif - -#undef IEEE_Arith -#undef Avoid_Underflow -#ifdef IEEE_MC68k -#define IEEE_Arith -#endif -#ifdef IEEE_8087 -#define IEEE_Arith -#endif - -#include "errno.h" -#ifdef Bad_float_h - -#ifdef IEEE_Arith -#define DBL_DIG 15 -#define DBL_MAX_10_EXP 308 -#define DBL_MAX_EXP 1024 -#define FLT_RADIX 2 -#define DBL_MAX 1.7976931348623157e+308 -#endif - -#ifdef IBM -#define DBL_DIG 16 -#define DBL_MAX_10_EXP 75 -#define DBL_MAX_EXP 63 -#define FLT_RADIX 16 -#define DBL_MAX 7.2370055773322621e+75 -#endif - -#ifdef VAX -#define DBL_DIG 16 -#define DBL_MAX_10_EXP 38 -#define DBL_MAX_EXP 127 -#define FLT_RADIX 2 -#define DBL_MAX 1.7014118346046923e+38 -#define n_bigtens 2 -#endif - -#ifndef LONG_MAX -#define LONG_MAX 2147483647 -#endif - -#else /* ifndef Bad_float_h */ -#include "float.h" -#endif /* Bad_float_h */ - -#ifdef IEEE_Arith -#define Scale_Bit 0x10 -#define n_bigtens 5 -#endif - -#ifdef IBM -#define n_bigtens 3 -#endif - -#ifdef VAX -#define n_bigtens 2 -#endif - -#ifndef __MATH_H__ -#include "math.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1 -Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined. -#endif - -typedef union { double d; ULong L[2]; } U; - -#ifdef IEEE_8087 -#define word0(x) (x)->L[1] -#define word1(x) (x)->L[0] -#else -#define word0(x) (x)->L[0] -#define word1(x) (x)->L[1] -#endif -#define dval(x) (x)->d - -/* The following definition of Storeinc is appropriate for MIPS processors. - * An alternative that might be better on some machines is - * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff) - */ -#if defined(IEEE_8087) + defined(VAX) -#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \ -((unsigned short *)a)[0] = (unsigned short)c, a++) -#else -#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \ -((unsigned short *)a)[1] = (unsigned short)c, a++) -#endif - -/* #define P DBL_MANT_DIG */ -/* Ten_pmax = floor(P*log(2)/log(5)) */ -/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ -/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ -/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ - -#ifdef IEEE_Arith -#define Exp_shift 20 -#define Exp_shift1 20 -#define Exp_msk1 0x100000 -#define Exp_msk11 0x100000 -#define Exp_mask 0x7ff00000 -#define P 53 -#define Bias 1023 -#define Emin (-1022) -#define Exp_1 0x3ff00000 -#define Exp_11 0x3ff00000 -#define Ebits 11 -#define Frac_mask 0xfffff -#define Frac_mask1 0xfffff -#define Ten_pmax 22 -#define Bletch 0x10 -#define Bndry_mask 0xfffff -#define Bndry_mask1 0xfffff -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 1 -#define Tiny0 0 -#define Tiny1 1 -#define Quick_max 14 -#define Int_max 14 - -#ifndef Flt_Rounds -#ifdef FLT_ROUNDS -#define Flt_Rounds FLT_ROUNDS -#else -#define Flt_Rounds 1 -#endif -#endif /*Flt_Rounds*/ - -#else /* ifndef IEEE_Arith */ -#undef Sudden_Underflow -#define Sudden_Underflow -#ifdef IBM -#undef Flt_Rounds -#define Flt_Rounds 0 -#define Exp_shift 24 -#define Exp_shift1 24 -#define Exp_msk1 0x1000000 -#define Exp_msk11 0x1000000 -#define Exp_mask 0x7f000000 -#define P 14 -#define Bias 65 -#define Exp_1 0x41000000 -#define Exp_11 0x41000000 -#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ -#define Frac_mask 0xffffff -#define Frac_mask1 0xffffff -#define Bletch 4 -#define Ten_pmax 22 -#define Bndry_mask 0xefffff -#define Bndry_mask1 0xffffff -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 4 -#define Tiny0 0x100000 -#define Tiny1 0 -#define Quick_max 14 -#define Int_max 15 -#else /* VAX */ -#undef Flt_Rounds -#define Flt_Rounds 1 -#define Exp_shift 23 -#define Exp_shift1 7 -#define Exp_msk1 0x80 -#define Exp_msk11 0x800000 -#define Exp_mask 0x7f80 -#define P 56 -#define Bias 129 -#define Exp_1 0x40800000 -#define Exp_11 0x4080 -#define Ebits 8 -#define Frac_mask 0x7fffff -#define Frac_mask1 0xffff007f -#define Ten_pmax 24 -#define Bletch 2 -#define Bndry_mask 0xffff007f -#define Bndry_mask1 0xffff007f -#define LSB 0x10000 -#define Sign_bit 0x8000 -#define Log2P 1 -#define Tiny0 0x80 -#define Tiny1 0 -#define Quick_max 15 -#define Int_max 15 -#endif /* IBM, VAX */ -#endif /* IEEE_Arith */ - -#ifndef IEEE_Arith -#define ROUND_BIASED -#else -#ifdef ROUND_BIASED_without_Round_Up -#undef ROUND_BIASED -#define ROUND_BIASED -#endif -#endif - -#ifdef RND_PRODQUOT -#define rounded_product(a,b) a = rnd_prod(a, b) -#define rounded_quotient(a,b) a = rnd_quot(a, b) -#ifdef KR_headers -extern double rnd_prod(), rnd_quot(); -#else -extern double rnd_prod(double, double), rnd_quot(double, double); -#endif -#else -#define rounded_product(a,b) a *= b -#define rounded_quotient(a,b) a /= b -#endif - -#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) -#define Big1 0xffffffff - -#undef Pack_16 -#ifndef Pack_32 -#define Pack_32 -#endif - -#ifdef NO_LONG_LONG -#undef ULLong -#ifdef Just_16 -#undef Pack_32 -#define Pack_16 -/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. - * This makes some inner loops simpler and sometimes saves work - * during multiplications, but it often seems to make things slightly - * slower. Hence the default is now to store 32 bits per Long. - */ -#endif -#else /* long long available */ -#ifndef Llong -#define Llong long long -#endif -#ifndef ULLong -#define ULLong unsigned Llong -#endif -#endif /* NO_LONG_LONG */ - -#ifdef Pack_32 -#define ULbits 32 -#define kshift 5 -#define kmask 31 -#define ALL_ON 0xffffffff -#else -#define ULbits 16 -#define kshift 4 -#define kmask 15 -#define ALL_ON 0xffff -#endif - -//#ifndef MULTIPLE_THREADS -#define ACQUIRE_DTOA_LOCK(n) /*nothing*/ -#define FREE_DTOA_LOCK(n) /*nothing*/ -//#endif - -#define Kmax 9 - - struct -Bigint { - struct Bigint *next; - int k, maxwds, sign, wds; - ULong x[1]; - }; - - typedef struct Bigint Bigint; - -#ifdef NO_STRING_H -#ifdef DECLARE_SIZE_T -typedef unsigned int size_t; -#endif -extern void memcpy_D2A ANSI((void*, const void*, size_t)); -#define Bcopy(x,y) memcpy_D2A(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int)) -#else /* !NO_STRING_H */ -#define Bcopy(x,y) memcpy(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int)) -#endif /* NO_STRING_H */ - -#define Balloc Balloc_D2A -#define Bfree Bfree_D2A -#define InfName InfName_D2A -#define NanName NanName_D2A -#define ULtoQ ULtoQ_D2A -#define ULtof ULtof_D2A -#define ULtod ULtod_D2A -#define ULtodd ULtodd_D2A -#define ULtox ULtox_D2A -#define ULtoxL ULtoxL_D2A -#define add_nanbits add_nanbits_D2A -#define any_on any_on_D2A -#define b2d b2d_D2A -#define bigtens bigtens_D2A -#define cmp cmp_D2A -#define copybits copybits_D2A -#define d2b d2b_D2A -#define decrement decrement_D2A -#define diff diff_D2A -#define dtoa_result dtoa_result_D2A -#define g__fmt g__fmt_D2A -#define gethex gethex_D2A -#define hexdig hexdig_D2A -#define hexnan hexnan_D2A -#define hi0bits(x) hi0bits_D2A((ULong)(x)) -#define i2b i2b_D2A -#define increment increment_D2A -#define lo0bits lo0bits_D2A -#define lshift lshift_D2A -#define match match_D2A -#define mult mult_D2A -#define multadd multadd_D2A -#define nrv_alloc nrv_alloc_D2A -#define pow5mult pow5mult_D2A -#define quorem quorem_D2A -#define ratio ratio_D2A -#define rshift rshift_D2A -#define rv_alloc rv_alloc_D2A -#define s2b s2b_D2A -#define set_ones set_ones_D2A -#define strcp strcp_D2A -#define strtoIg strtoIg_D2A -#define sum sum_D2A -#define tens tens_D2A -#define tinytens tinytens_D2A -#define tinytens tinytens_D2A -#define trailz trailz_D2A -#define ulp ulp_D2A - - extern char *add_nanbits ANSI((char*, size_t, ULong*, int)); - extern char *dtoa_result; - extern CONST double bigtens[], tens[], tinytens[]; - extern unsigned char hexdig[]; - extern const char *InfName[6], *NanName[3]; - - extern Bigint *Balloc ANSI((int)); - extern void Bfree ANSI((Bigint*)); - extern void ULtof ANSI((ULong*, ULong*, Long, int)); - extern void ULtod ANSI((ULong*, ULong*, Long, int)); - extern void ULtodd ANSI((ULong*, ULong*, Long, int)); - extern void ULtoQ ANSI((ULong*, ULong*, Long, int)); - extern void ULtox ANSI((UShort*, ULong*, Long, int)); - extern void ULtoxL ANSI((ULong*, ULong*, Long, int)); - extern ULong any_on ANSI((Bigint*, int)); - extern double b2d ANSI((Bigint*, int*)); - extern int cmp ANSI((Bigint*, Bigint*)); - extern void copybits ANSI((ULong*, int, Bigint*)); - extern Bigint *d2b ANSI((double, int*, int*)); - extern void decrement ANSI((Bigint*)); - extern Bigint *diff ANSI((Bigint*, Bigint*)); - extern char *dtoa ANSI((double d, int mode, int ndigits, - int *decpt, int *sign, char **rve)); - extern char *g__fmt ANSI((char*, char*, char*, int, ULong, size_t)); - extern int gethex ANSI((CONST char**, FPI*, Long*, Bigint**, int)); - extern void hexdig_init_D2A(Void); - extern int hexnan ANSI((CONST char**, FPI*, ULong*)); - extern int hi0bits_D2A ANSI((ULong)); - extern Bigint *i2b ANSI((int)); - extern Bigint *increment ANSI((Bigint*)); - extern int lo0bits ANSI((ULong*)); - extern Bigint *lshift ANSI((Bigint*, int)); - extern int match ANSI((CONST char**, char*)); - extern Bigint *mult ANSI((Bigint*, Bigint*)); - extern Bigint *multadd ANSI((Bigint*, int, int)); - extern char *nrv_alloc ANSI((char*, char **, int)); - extern Bigint *pow5mult ANSI((Bigint*, int)); - extern int quorem ANSI((Bigint*, Bigint*)); - extern double ratio ANSI((Bigint*, Bigint*)); - extern void rshift ANSI((Bigint*, int)); - extern char *rv_alloc ANSI((int)); - extern Bigint *s2b ANSI((CONST char*, int, int, ULong, int)); - extern Bigint *set_ones ANSI((Bigint*, int)); - extern char *strcp ANSI((char*, const char*)); - extern int strtoIg ANSI((CONST char*, char**, FPI*, Long*, Bigint**, int*)); -// extern double strtod ANSI((const char *s00, char **se)); - extern Bigint *sum ANSI((Bigint*, Bigint*)); - extern int trailz ANSI((Bigint*)); - extern double ulp ANSI((U*)); - -#ifdef __cplusplus -} -#endif -/* - * NAN_WORD0 and NAN_WORD1 are only referenced in strtod.c. Prior to - * 20050115, they used to be hard-wired here (to 0x7ff80000 and 0, - * respectively), but now are determined by compiling and running - * qnan.c to generate gd_qnan.h, which specifies d_QNAN0 and d_QNAN1. - * Formerly gdtoaimp.h recommended supplying suitable -DNAN_WORD0=... - * and -DNAN_WORD1=... values if necessary. This should still work. - * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.) - */ -#ifdef IEEE_Arith -#ifndef NO_INFNAN_CHECK -#undef INFNAN_CHECK -#define INFNAN_CHECK -#endif -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#ifndef NAN_WORD0 -#define NAN_WORD0 d_QNAN0 -#endif -#ifndef NAN_WORD1 -#define NAN_WORD1 d_QNAN1 -#endif -#else -#define _0 1 -#define _1 0 -#ifndef NAN_WORD0 -#define NAN_WORD0 d_QNAN1 -#endif -#ifndef NAN_WORD1 -#define NAN_WORD1 d_QNAN0 -#endif -#endif -#else -#undef INFNAN_CHECK -#endif - -#undef SI -#ifdef Sudden_Underflow -#define SI 1 -#else -#define SI 0 -#endif - -#endif /* GDTOAIMP_H_INCLUDED */ diff --git a/libraries/gdtoa/gethex.c b/libraries/gdtoa/gethex.c deleted file mode 100644 index 72da9d326..000000000 --- a/libraries/gdtoa/gethex.c +++ /dev/null @@ -1,349 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#ifdef USE_LOCALE -#include "locale.h" -#endif - - int -#ifdef KR_headers -gethex(sp, fpi, exp, bp, sign) - CONST char **sp; FPI *fpi; Long *exp; Bigint **bp; int sign; -#else -gethex( CONST char **sp, FPI *fpi, Long *exp, Bigint **bp, int sign) -#endif -{ - Bigint *b; - CONST unsigned char *decpt, *s0, *s, *s1; - int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret; - ULong L, lostbits, *x; - Long e, e1; -#ifdef USE_LOCALE - int i; -#ifdef NO_LOCALE_CACHE - const unsigned char *decimalpoint = (unsigned char*)localeconv()->decimal_point; -#else - const unsigned char *decimalpoint; - static unsigned char *decimalpoint_cache; - if (!(s0 = decimalpoint_cache)) { - s0 = (unsigned char*)localeconv()->decimal_point; - if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { - strcpy(decimalpoint_cache, s0); - s0 = decimalpoint_cache; - } - } - decimalpoint = s0; -#endif -#endif - - /**** if (!hexdig['0']) hexdig_init_D2A(); ****/ - *bp = 0; - havedig = 0; - s0 = *(CONST unsigned char **)sp + 2; - while(s0[havedig] == '0') - havedig++; - s0 += havedig; - s = s0; - decpt = 0; - zret = 0; - e = 0; - if (hexdig[*s]) - havedig++; - else { - zret = 1; -#ifdef USE_LOCALE - for(i = 0; decimalpoint[i]; ++i) { - if (s[i] != decimalpoint[i]) - goto pcheck; - } - decpt = s += i; -#else - if (*s != '.') - goto pcheck; - decpt = ++s; -#endif - if (!hexdig[*s]) - goto pcheck; - while(*s == '0') - s++; - if (hexdig[*s]) - zret = 0; - havedig = 1; - s0 = s; - } - while(hexdig[*s]) - s++; -#ifdef USE_LOCALE - if (*s == *decimalpoint && !decpt) { - for(i = 1; decimalpoint[i]; ++i) { - if (s[i] != decimalpoint[i]) - goto pcheck; - } - decpt = s += i; -#else - if (*s == '.' && !decpt) { - decpt = ++s; -#endif - while(hexdig[*s]) - s++; - }/*}*/ - if (decpt) - e = -(((Long)(s-decpt)) << 2); - pcheck: - s1 = s; - big = esign = 0; - switch(*s) { - case 'p': - case 'P': - switch(*++s) { - case '-': - esign = 1; - /* no break */ - case '+': - s++; - } - if ((n = hexdig[*s]) == 0 || n > 0x19) { - s = s1; - break; - } - e1 = n - 0x10; - while((n = hexdig[*++s]) !=0 && n <= 0x19) { - if (e1 & 0xf8000000) - big = 1; - e1 = 10*e1 + n - 0x10; - } - if (esign) - e1 = -e1; - e += e1; - } - *sp = (char*)s; - if (!havedig) - *sp = (char*)s0 - 1; - if (zret) - return STRTOG_Zero; - if (big) { - if (esign) { - switch(fpi->rounding) { - case FPI_Round_up: - if (sign) - break; - goto ret_tiny; - case FPI_Round_down: - if (!sign) - break; - goto ret_tiny; - } - goto retz; - ret_tiny: - b = Balloc(0); - b->wds = 1; - b->x[0] = 1; - goto dret; - } - switch(fpi->rounding) { - case FPI_Round_near: - goto ovfl1; - case FPI_Round_up: - if (!sign) - goto ovfl1; - goto ret_big; - case FPI_Round_down: - if (sign) - goto ovfl1; - goto ret_big; - } - ret_big: - nbits = fpi->nbits; - n0 = n = nbits >> kshift; - if (nbits & kmask) - ++n; - for(j = n, k = 0; j >>= 1; ++k); - *bp = b = Balloc(k); - b->wds = n; - for(j = 0; j < n0; ++j) - b->x[j] = ALL_ON; - if (n > n0) - b->x[j] = ULbits >> (ULbits - (nbits & kmask)); - *exp = fpi->emin; - return STRTOG_Normal | STRTOG_Inexlo; - } - n = s1 - s0 - 1; - for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1) - k++; - b = Balloc(k); - x = b->x; - n = 0; - L = 0; -#ifdef USE_LOCALE - for(i = 0; decimalpoint[i+1]; ++i); -#endif - while(s1 > s0) { -#ifdef USE_LOCALE - if (*--s1 == decimalpoint[i]) { - s1 -= i; - continue; - } -#else - if (*--s1 == '.') - continue; -#endif - if (n == ULbits) { - *x++ = L; - L = 0; - n = 0; - } - L |= (hexdig[*s1] & 0x0f) << n; - n += 4; - } - *x++ = L; - b->wds = n = x - b->x; - n = ULbits*n - hi0bits(L); - nbits = fpi->nbits; - lostbits = 0; - x = b->x; - if (n > nbits) { - n -= nbits; - if (any_on(b,n)) { - lostbits = 1; - k = n - 1; - if (x[k>>kshift] & 1 << (k & kmask)) { - lostbits = 2; - if (k > 0 && any_on(b,k)) - lostbits = 3; - } - } - rshift(b, n); - e += n; - } - else if (n < nbits) { - n = nbits - n; - b = lshift(b, n); - e -= n; - x = b->x; - } - if (e > fpi->emax) { - ovfl: - Bfree(b); - ovfl1: -#ifndef NO_ERRNO - errno = ERANGE; -#endif - return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; - } - irv = STRTOG_Normal; - if (e < fpi->emin) { - irv = STRTOG_Denormal; - n = fpi->emin - e; - if (n >= nbits) { - switch (fpi->rounding) { - case FPI_Round_near: - if (n == nbits && (n < 2 || any_on(b,n-1))) - goto one_bit; - break; - case FPI_Round_up: - if (!sign) - goto one_bit; - break; - case FPI_Round_down: - if (sign) { - one_bit: - x[0] = b->wds = 1; - dret: - *bp = b; - *exp = fpi->emin; -#ifndef NO_ERRNO - errno = ERANGE; -#endif - return STRTOG_Denormal | STRTOG_Inexhi - | STRTOG_Underflow; - } - } - Bfree(b); - retz: -#ifndef NO_ERRNO - errno = ERANGE; -#endif - return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow; - } - k = n - 1; - if (lostbits) - lostbits = 1; - else if (k > 0) - lostbits = any_on(b,k); - if (x[k>>kshift] & 1 << (k & kmask)) - lostbits |= 2; - nbits -= n; - rshift(b,n); - e = fpi->emin; - } - if (lostbits) { - up = 0; - switch(fpi->rounding) { - case FPI_Round_zero: - break; - case FPI_Round_near: - if (lostbits & 2 - && (lostbits | x[0]) & 1) - up = 1; - break; - case FPI_Round_up: - up = 1 - sign; - break; - case FPI_Round_down: - up = sign; - } - if (up) { - k = b->wds; - b = increment(b); - x = b->x; - if (irv == STRTOG_Denormal) { - if (nbits == fpi->nbits - 1 - && x[nbits >> kshift] & 1 << (nbits & kmask)) - irv = STRTOG_Normal; - } - else if (b->wds > k - || ((n = nbits & kmask) !=0 - && hi0bits(x[k-1]) < 32-n)) { - rshift(b,1); - if (++e > fpi->emax) - goto ovfl; - } - irv |= STRTOG_Inexhi; - } - else - irv |= STRTOG_Inexlo; - } - *bp = b; - *exp = e; - return irv; - } diff --git a/libraries/gdtoa/gmisc.c b/libraries/gdtoa/gmisc.c deleted file mode 100644 index 8270ef944..000000000 --- a/libraries/gdtoa/gmisc.c +++ /dev/null @@ -1,86 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - void -#ifdef KR_headers -rshift(b, k) Bigint *b; int k; -#else -rshift(Bigint *b, int k) -#endif -{ - ULong *x, *x1, *xe, y; - int n; - - x = x1 = b->x; - n = k >> kshift; - if (n < b->wds) { - xe = x + b->wds; - x += n; - if (k &= kmask) { - n = ULbits - k; - y = *x++ >> k; - while(x < xe) { - *x1++ = (y | (*x << n)) & ALL_ON; - y = *x++ >> k; - } - if ((*x1 = y) !=0) - x1++; - } - else - while(x < xe) - *x1++ = *x++; - } - if ((b->wds = x1 - b->x) == 0) - b->x[0] = 0; - } - - int -#ifdef KR_headers -trailz(b) Bigint *b; -#else -trailz(Bigint *b) -#endif -{ - ULong L, *x, *xe; - int n = 0; - - x = b->x; - xe = x + b->wds; - for(n = 0; x < xe && !*x; x++) - n += ULbits; - if (x < xe) { - L = *x; - n += lo0bits(&L); - } - return n; - } diff --git a/libraries/gdtoa/hd_init.c b/libraries/gdtoa/hd_init.c deleted file mode 100644 index d79ae2ec8..000000000 --- a/libraries/gdtoa/hd_init.c +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#if 0 - unsigned char hexdig[256]; - - static void -#ifdef KR_headers -htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc; -#else -htinit(unsigned char *h, unsigned char *s, int inc) -#endif -{ - int i, j; - for(i = 0; (j = s[i]) !=0; i++) - h[j] = i + inc; - } - - void -hexdig_init_D2A(Void) /* Use of hexdig_init omitted 20121220 to avoid a */ - /* race condition when multiple threads are used. */ -{ -#define USC (unsigned char *) - htinit(hexdig, USC "0123456789", 0x10); - htinit(hexdig, USC "abcdef", 0x10 + 10); - htinit(hexdig, USC "ABCDEF", 0x10 + 10); - } -#else - unsigned char hexdig[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0, - 0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - }; -#endif diff --git a/libraries/gdtoa/hexnan.c b/libraries/gdtoa/hexnan.c deleted file mode 100644 index 80721e97a..000000000 --- a/libraries/gdtoa/hexnan.c +++ /dev/null @@ -1,159 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - static void -#ifdef KR_headers -L_shift(x, x1, i) ULong *x; ULong *x1; int i; -#else -L_shift(ULong *x, ULong *x1, int i) -#endif -{ - int j; - - i = 8 - i; - i <<= 2; - j = ULbits - i; - do { - *x |= x[1] << j; - x[1] >>= i; - } while(++x < x1); - } - - int -#ifdef KR_headers -hexnan(sp, fpi, x0) - CONST char **sp; FPI *fpi; ULong *x0; -#else -hexnan( CONST char **sp, FPI *fpi, ULong *x0) -#endif -{ - ULong c, h, *x, *x1, *xe; - CONST char *s; - int havedig, hd0, i, nbits; - - /**** if (!hexdig['0']) hexdig_init_D2A(); ****/ - nbits = fpi->nbits; - x = x0 + (nbits >> kshift); - if (nbits & kmask) - x++; - *--x = 0; - x1 = xe = x; - havedig = hd0 = i = 0; - s = *sp; - /* allow optional initial 0x or 0X */ - while((c = *(CONST unsigned char*)(s+1)) && c <= ' ') { - if (!c) - goto retnan; - ++s; - } - if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X') - && *(CONST unsigned char*)(s+3) > ' ') - s += 2; - while((c = *(CONST unsigned char*)++s)) { - if (!(h = hexdig[c])) { - if (c <= ' ') { - if (hd0 < havedig) { - if (x < x1 && i < 8) - L_shift(x, x1, i); - if (x <= x0) { - i = 8; - continue; - } - hd0 = havedig; - *--x = 0; - x1 = x; - i = 0; - } - while((c = *(CONST unsigned char*)(s+1)) <= ' ') { - if (!c) - goto retnan; - ++s; - } - if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X') - && *(CONST unsigned char*)(s+3) > ' ') - s += 2; - continue; - } - if (/*(*/ c == ')' && havedig) { - *sp = s + 1; - break; - } -#ifndef GDTOA_NON_PEDANTIC_NANCHECK - do { - if (/*(*/ c == ')') { - *sp = s + 1; - goto break2; - } - } while((c = *++s)); -#endif - retnan: - return STRTOG_NaN; - } - havedig++; - if (++i > 8) { - if (x <= x0) - continue; - i = 1; - *--x = 0; - } - *x = (*x << 4) | (h & 0xf); - } -#ifndef GDTOA_NON_PEDANTIC_NANCHECK - break2: -#endif - if (!havedig) - return STRTOG_NaN; - if (x < x1 && i < 8) - L_shift(x, x1, i); - if (x > x0) { - x1 = x0; - do *x1++ = *x++; - while(x <= xe); - do *x1++ = 0; - while(x1 <= xe); - } - else { - /* truncate high-order word if necessary */ - if ( (i = nbits & (ULbits-1)) !=0) - *xe &= ((ULong)0xffffffff) >> (ULbits - i); - } - for(x1 = xe;; --x1) { - if (*x1 != 0) - break; - if (x1 == x0) { - *x1 = 1; - break; - } - } - return STRTOG_NaNbits; - } diff --git a/libraries/gdtoa/misc.c b/libraries/gdtoa/misc.c deleted file mode 100644 index d13046732..000000000 --- a/libraries/gdtoa/misc.c +++ /dev/null @@ -1,875 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 1999 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - static Bigint *freelist[Kmax+1]; -#ifndef Omit_Private_Memory -#ifndef PRIVATE_MEM -#define PRIVATE_MEM 2304 -#endif -#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double)) -static double private_mem[PRIVATE_mem], *pmem_next = private_mem; -#endif - - Bigint * -Balloc -#ifdef KR_headers - (k) int k; -#else - (int k) -#endif -{ - int x; - Bigint *rv; -#ifndef Omit_Private_Memory - unsigned int len; -#endif - - ACQUIRE_DTOA_LOCK(0); - /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */ - /* but this case seems very unlikely. */ - if (k <= Kmax && (rv = freelist[k]) !=0) { - freelist[k] = rv->next; - } - else { - x = 1 << k; -#ifdef Omit_Private_Memory - rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong)); -#else - len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1) - /sizeof(double); - if (k <= Kmax && pmem_next - private_mem + len <= PRIVATE_mem) { - rv = (Bigint*)pmem_next; - pmem_next += len; - } - else - rv = (Bigint*)MALLOC(len*sizeof(double)); -#endif - rv->k = k; - rv->maxwds = x; - } - FREE_DTOA_LOCK(0); - rv->sign = rv->wds = 0; - return rv; - } - - void -Bfree -#ifdef KR_headers - (v) Bigint *v; -#else - (Bigint *v) -#endif -{ - if (v) { - if (v->k > Kmax) -#ifdef FREE - FREE((void*)v); -#else - free((void*)v); -#endif - else { - ACQUIRE_DTOA_LOCK(0); - v->next = freelist[v->k]; - freelist[v->k] = v; - FREE_DTOA_LOCK(0); - } - } - } - - int -lo0bits -#ifdef KR_headers - (y) ULong *y; -#else - (ULong *y) -#endif -{ - int k; - ULong x = *y; - - if (x & 7) { - if (x & 1) - return 0; - if (x & 2) { - *y = x >> 1; - return 1; - } - *y = x >> 2; - return 2; - } - k = 0; - if (!(x & 0xffff)) { - k = 16; - x >>= 16; - } - if (!(x & 0xff)) { - k += 8; - x >>= 8; - } - if (!(x & 0xf)) { - k += 4; - x >>= 4; - } - if (!(x & 0x3)) { - k += 2; - x >>= 2; - } - if (!(x & 1)) { - k++; - x >>= 1; - if (!x) - return 32; - } - *y = x; - return k; - } - - Bigint * -multadd -#ifdef KR_headers - (b, m, a) Bigint *b; int m, a; -#else - (Bigint *b, int m, int a) /* multiply by m and add a */ -#endif -{ - int i, wds; -#ifdef ULLong - ULong *x; - ULLong carry, y; -#else - ULong carry, *x, y; -#ifdef Pack_32 - ULong xi, z; -#endif -#endif - Bigint *b1; - - wds = b->wds; - x = b->x; - i = 0; - carry = a; - do { -#ifdef ULLong - y = *x * (ULLong)m + carry; - carry = y >> 32; - *x++ = (ULong)(y & 0xffffffffUL); -#else -#ifdef Pack_32 - xi = *x; - y = (xi & 0xffff) * m + carry; - z = (xi >> 16) * m + (y >> 16); - carry = z >> 16; - *x++ = (z << 16) + (y & 0xffff); -#else - y = *x * m + carry; - carry = y >> 16; - *x++ = y & 0xffff; -#endif -#endif - } - while(++i < wds); - if (carry) { - if (wds >= b->maxwds) { - b1 = Balloc(b->k+1); - Bcopy(b1, b); - Bfree(b); - b = b1; - } - b->x[wds++] = (ULong)carry; - b->wds = wds; - } - return b; - } - - int -hi0bits_D2A -#ifdef KR_headers - (x) ULong x; -#else - (ULong x) -#endif -{ - int k = 0; - - if (!(x & 0xffff0000)) { - k = 16; - x <<= 16; - } - if (!(x & 0xff000000)) { - k += 8; - x <<= 8; - } - if (!(x & 0xf0000000)) { - k += 4; - x <<= 4; - } - if (!(x & 0xc0000000)) { - k += 2; - x <<= 2; - } - if (!(x & 0x80000000)) { - k++; - if (!(x & 0x40000000)) - return 32; - } - return k; - } - - Bigint * -i2b -#ifdef KR_headers - (i) int i; -#else - (int i) -#endif -{ - Bigint *b; - - b = Balloc(1); - b->x[0] = i; - b->wds = 1; - return b; - } - - Bigint * -mult -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif -{ - Bigint *c; - int k, wa, wb, wc; - ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; - ULong y; -#ifdef ULLong - ULLong carry, z; -#else - ULong carry, z; -#ifdef Pack_32 - ULong z2; -#endif -#endif - - if (a->wds < b->wds) { - c = a; - a = b; - b = c; - } - k = a->k; - wa = a->wds; - wb = b->wds; - wc = wa + wb; - if (wc > a->maxwds) - k++; - c = Balloc(k); - for(x = c->x, xa = x + wc; x < xa; x++) - *x = 0; - xa = a->x; - xae = xa + wa; - xb = b->x; - xbe = xb + wb; - xc0 = c->x; -#ifdef ULLong - for(; xb < xbe; xc0++) { - if ( (y = *xb++) !=0) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * (ULLong)y + *xc + carry; - carry = z >> 32; - *xc++ = (ULong)(z & 0xffffffffUL); - } - while(x < xae); - *xc = (ULong)carry; - } - } -#else -#ifdef Pack_32 - for(; xb < xbe; xb++, xc0++) { - if ( (y = *xb & 0xffff) !=0) { - x = xa; - xc = xc0; - carry = 0; - do { - z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; - carry = z >> 16; - z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; - carry = z2 >> 16; - Storeinc(xc, z2, z); - } - while(x < xae); - *xc = carry; - } - if ( (y = *xb >> 16) !=0) { - x = xa; - xc = xc0; - carry = 0; - z2 = *xc; - do { - z = (*x & 0xffff) * y + (*xc >> 16) + carry; - carry = z >> 16; - Storeinc(xc, z, z2); - z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; - carry = z2 >> 16; - } - while(x < xae); - *xc = z2; - } - } -#else - for(; xb < xbe; xc0++) { - if ( (y = *xb++) !=0) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * y + *xc + carry; - carry = z >> 16; - *xc++ = z & 0xffff; - } - while(x < xae); - *xc = carry; - } - } -#endif -#endif - for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; - c->wds = wc; - return c; - } - - static Bigint *p5s; - - Bigint * -pow5mult -#ifdef KR_headers - (b, k) Bigint *b; int k; -#else - (Bigint *b, int k) -#endif -{ - Bigint *b1, *p5, *p51; - int i; - static int p05[3] = { 5, 25, 125 }; - - if ( (i = k & 3) !=0) - b = multadd(b, p05[i-1], 0); - - if (!(k >>= 2)) - return b; - if ((p5 = p5s) == 0) { - /* first time */ -#ifdef MULTIPLE_THREADS - ACQUIRE_DTOA_LOCK(1); - if (!(p5 = p5s)) { - p5 = p5s = i2b(625); - p5->next = 0; - } - FREE_DTOA_LOCK(1); -#else - p5 = p5s = i2b(625); - p5->next = 0; -#endif - } - for(;;) { - if (k & 1) { - b1 = mult(b, p5); - Bfree(b); - b = b1; - } - if (!(k >>= 1)) - break; - if ((p51 = p5->next) == 0) { -#ifdef MULTIPLE_THREADS - ACQUIRE_DTOA_LOCK(1); - if (!(p51 = p5->next)) { - p51 = p5->next = mult(p5,p5); - p51->next = 0; - } - FREE_DTOA_LOCK(1); -#else - p51 = p5->next = mult(p5,p5); - p51->next = 0; -#endif - } - p5 = p51; - } - return b; - } - - Bigint * -lshift -#ifdef KR_headers - (b, k) Bigint *b; int k; -#else - (Bigint *b, int k) -#endif -{ - int i, k1, n, n1; - Bigint *b1; - ULong *x, *x1, *xe, z; - - n = k >> kshift; - k1 = b->k; - n1 = n + b->wds + 1; - for(i = b->maxwds; n1 > i; i <<= 1) - k1++; - b1 = Balloc(k1); - x1 = b1->x; - for(i = 0; i < n; i++) - *x1++ = 0; - x = b->x; - xe = x + b->wds; - if (k &= kmask) { -#ifdef Pack_32 - k1 = 32 - k; - z = 0; - do { - *x1++ = *x << k | z; - z = *x++ >> k1; - } - while(x < xe); - if ((*x1 = z) !=0) - ++n1; -#else - k1 = 16 - k; - z = 0; - do { - *x1++ = *x << k & 0xffff | z; - z = *x++ >> k1; - } - while(x < xe); - if (*x1 = z) - ++n1; -#endif - } - else do - *x1++ = *x++; - while(x < xe); - b1->wds = n1 - 1; - Bfree(b); - return b1; - } - - int -cmp -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif -{ - ULong *xa, *xa0, *xb, *xb0; - int i, j; - - i = a->wds; - j = b->wds; -#ifdef DEBUG - if (i > 1 && !a->x[i-1]) - Bug("cmp called with a->x[a->wds-1] == 0"); - if (j > 1 && !b->x[j-1]) - Bug("cmp called with b->x[b->wds-1] == 0"); -#endif - if (i -= j) - return i; - xa0 = a->x; - xa = xa0 + j; - xb0 = b->x; - xb = xb0 + j; - for(;;) { - if (*--xa != *--xb) - return *xa < *xb ? -1 : 1; - if (xa <= xa0) - break; - } - return 0; - } - - Bigint * -diff -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif -{ - Bigint *c; - int i, wa, wb; - ULong *xa, *xae, *xb, *xbe, *xc; -#ifdef ULLong - ULLong borrow, y; -#else - ULong borrow, y; -#ifdef Pack_32 - ULong z; -#endif -#endif - - i = cmp(a,b); - if (!i) { - c = Balloc(0); - c->wds = 1; - c->x[0] = 0; - return c; - } - if (i < 0) { - c = a; - a = b; - b = c; - i = 1; - } - else - i = 0; - c = Balloc(a->k); - c->sign = i; - wa = a->wds; - xa = a->x; - xae = xa + wa; - wb = b->wds; - xb = b->x; - xbe = xb + wb; - xc = c->x; - borrow = 0; -#ifdef ULLong - do { - y = (ULLong)*xa++ - *xb++ - borrow; - borrow = y >> 32 & 1UL; - *xc++ = (ULong)(y & 0xffffffffUL); - } - while(xb < xbe); - while(xa < xae) { - y = *xa++ - borrow; - borrow = y >> 32 & 1UL; - *xc++ = (ULong)(y & 0xffffffffUL); - } -#else -#ifdef Pack_32 - do { - y = (*xa & 0xffff) - (*xb & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*xa++ >> 16) - (*xb++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } - while(xb < xbe); - while(xa < xae) { - y = (*xa & 0xffff) - borrow; - borrow = (y & 0x10000) >> 16; - z = (*xa++ >> 16) - borrow; - borrow = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } -#else - do { - y = *xa++ - *xb++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } - while(xb < xbe); - while(xa < xae) { - y = *xa++ - borrow; - borrow = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } -#endif -#endif - while(!*--xc) - wa--; - c->wds = wa; - return c; - } - - double -b2d -#ifdef KR_headers - (a, e) Bigint *a; int *e; -#else - (Bigint *a, int *e) -#endif -{ - ULong *xa, *xa0, w, y, z; - int k; - U d; -#ifdef VAX - ULong d0, d1; -#else -#define d0 word0(&d) -#define d1 word1(&d) -#endif - - xa0 = a->x; - xa = xa0 + a->wds; - y = *--xa; -#ifdef DEBUG - if (!y) Bug("zero y in b2d"); -#endif - k = hi0bits(y); - *e = 32 - k; -#ifdef Pack_32 - if (k < Ebits) { - d0 = Exp_1 | y >> (Ebits - k); - w = xa > xa0 ? *--xa : 0; - d1 = y << ((32-Ebits) + k) | w >> (Ebits - k); - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - if (k -= Ebits) { - d0 = Exp_1 | y << k | z >> (32 - k); - y = xa > xa0 ? *--xa : 0; - d1 = z << k | y >> (32 - k); - } - else { - d0 = Exp_1 | y; - d1 = z; - } -#else - if (k < Ebits + 16) { - z = xa > xa0 ? *--xa : 0; - d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k; - w = xa > xa0 ? *--xa : 0; - y = xa > xa0 ? *--xa : 0; - d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k; - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - w = xa > xa0 ? *--xa : 0; - k -= Ebits + 16; - d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k; - y = xa > xa0 ? *--xa : 0; - d1 = w << k + 16 | y << k; -#endif - ret_d: -#ifdef VAX - word0(&d) = d0 >> 16 | d0 << 16; - word1(&d) = d1 >> 16 | d1 << 16; -#endif - return dval(&d); - } -#undef d0 -#undef d1 - - Bigint * -d2b -#ifdef KR_headers - (dd, e, bits) double dd; int *e, *bits; -#else - (double dd, int *e, int *bits) -#endif -{ - Bigint *b; - U d; -#ifndef Sudden_Underflow - int i; -#endif - int de, k; - ULong *x, y, z; -#ifdef VAX - ULong d0, d1; -#else -#define d0 word0(&d) -#define d1 word1(&d) -#endif - d.d = dd; -#ifdef VAX - d0 = word0(&d) >> 16 | word0(&d) << 16; - d1 = word1(&d) >> 16 | word1(&d) << 16; -#endif - -#ifdef Pack_32 - b = Balloc(1); -#else - b = Balloc(2); -#endif - x = b->x; - - z = d0 & Frac_mask; - d0 &= 0x7fffffff; /* clear sign bit, which we ignore */ -#ifdef Sudden_Underflow - de = (int)(d0 >> Exp_shift); -#ifndef IBM - z |= Exp_msk11; -#endif -#else - if ( (de = (int)(d0 >> Exp_shift)) !=0) - z |= Exp_msk1; -#endif -#ifdef Pack_32 - if ( (y = d1) !=0) { - if ( (k = lo0bits(&y)) !=0) { - x[0] = y | z << (32 - k); - z >>= k; - } - else - x[0] = y; -#ifndef Sudden_Underflow - i = -#endif - b->wds = (x[1] = z) !=0 ? 2 : 1; - } - else { - k = lo0bits(&z); - x[0] = z; -#ifndef Sudden_Underflow - i = -#endif - b->wds = 1; - k += 32; - } -#else - if ( (y = d1) !=0) { - if ( (k = lo0bits(&y)) !=0) - if (k >= 16) { - x[0] = y | z << 32 - k & 0xffff; - x[1] = z >> k - 16 & 0xffff; - x[2] = z >> k; - i = 2; - } - else { - x[0] = y & 0xffff; - x[1] = y >> 16 | z << 16 - k & 0xffff; - x[2] = z >> k & 0xffff; - x[3] = z >> k+16; - i = 3; - } - else { - x[0] = y & 0xffff; - x[1] = y >> 16; - x[2] = z & 0xffff; - x[3] = z >> 16; - i = 3; - } - } - else { -#ifdef DEBUG - if (!z) - Bug("Zero passed to d2b"); -#endif - k = lo0bits(&z); - if (k >= 16) { - x[0] = z; - i = 0; - } - else { - x[0] = z & 0xffff; - x[1] = z >> 16; - i = 1; - } - k += 32; - } - while(!x[i]) - --i; - b->wds = i + 1; -#endif -#ifndef Sudden_Underflow - if (de) { -#endif -#ifdef IBM - *e = (de - Bias - (P-1) << 2) + k; - *bits = 4*P + 8 - k - hi0bits(word0(&d) & Frac_mask); -#else - *e = de - Bias - (P-1) + k; - *bits = P - k; -#endif -#ifndef Sudden_Underflow - } - else { - *e = de - Bias - (P-1) + 1 + k; -#ifdef Pack_32 - *bits = 32*i - hi0bits(x[i-1]); -#else - *bits = (i+2)*16 - hi0bits(x[i]); -#endif - } -#endif - return b; - } -#undef d0 -#undef d1 - - CONST double -#ifdef IEEE_Arith -bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; -CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 - }; -#else -#ifdef IBM -bigtens[] = { 1e16, 1e32, 1e64 }; -CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 }; -#else -bigtens[] = { 1e16, 1e32 }; -CONST double tinytens[] = { 1e-16, 1e-32 }; -#endif -#endif - - CONST double -tens[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22 -#ifdef VAX - , 1e23, 1e24 -#endif - }; - - char * -#ifdef KR_headers -strcp_D2A(a, b) char *a; char *b; -#else -strcp_D2A(char *a, CONST char *b) -#endif -{ - while((*a = *b++)) - a++; - return a; - } - -#ifdef NO_STRING_H - - Char * -#ifdef KR_headers -memcpy_D2A(a, b, len) Char *a; Char *b; size_t len; -#else -memcpy_D2A(void *a1, void *b1, size_t len) -#endif -{ - char *a = (char*)a1, *ae = a + len; - char *b = (char*)b1, *a0 = a; - while(a < ae) - *a++ = *b++; - return a0; - } - -#endif /* NO_STRING_H */ diff --git a/libraries/gdtoa/qnan.c b/libraries/gdtoa/qnan.c deleted file mode 100644 index ea7e8745b..000000000 --- a/libraries/gdtoa/qnan.c +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 2005 by David M. Gay -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and its -documentation for any purpose and without fee is hereby granted, -provided that the above copyright notice appear in all copies and that -both that the copyright notice and this permission notice and warranty -disclaimer appear in supporting documentation, and that the name of -the author or any of his current or former employers not be used in -advertising or publicity pertaining to distribution of the software -without specific, written prior permission. - -THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN -NO EVENT SHALL THE AUTHOR OR ANY OF HIS CURRENT OR FORMER EMPLOYERS BE -LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY -DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS -SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -/* Program to compute quiet NaNs of various precisions (float, */ -/* double, and perhaps long double) on the current system, */ -/* provided the system uses binary IEEE (P754) arithmetic. */ -/* Note that one system's quiet NaN may be a signaling NaN on */ -/* another system. The IEEE arithmetic standards (P754, P854) */ -/* do not specify how to distinguish signaling NaNs from quiet */ -/* ones, and this detail varies across systems. The computed */ -/* NaN values are encoded in #defines for values for an */ -/* unsigned 32-bit integer type, called Ulong below, and */ -/* (for long double) perhaps as unsigned short values. Once */ -/* upon a time, there were PC compilers for Intel CPUs that */ -/* had sizeof(long double) = 10. Are such compilers still */ -/* distributed? */ - -#include -#include "arith.h" - -#ifndef Long -#define Long long -#endif - -typedef unsigned Long Ulong; - -#undef HAVE_IEEE -#ifdef IEEE_8087 -#define _0 1 -#define _1 0 -#define _3 3 -#if defined(Gen_ld_QNAN) && !defined(NO_LONG_LONG) -static int perm[4] = { 0, 1, 2, 3 }; -#endif -#define HAVE_IEEE -#endif -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _3 0 -#if defined(Gen_ld_QNAN) && !defined(NO_LONG_LONG) -static int perm[4] = { 3, 2, 1, 0 }; -#endif -#define HAVE_IEEE -#endif - -#define UL (unsigned long) - - int -main(void) -{ -#ifdef HAVE_IEEE - typedef union { - float f; - double d; - Ulong L[4]; -#ifndef NO_LONG_LONG - unsigned short u[5]; - long double D; -#endif - } U; - U a, b, c; -#if defined(Gen_ld_QNAN) && !defined(NO_LONG_LONG) - int i; -#endif - - a.L[0] = b.L[0] = 0x7f800000; - c.f = a.f - b.f; - printf("#define f_QNAN 0x%lx\n", UL (c.L[0] & 0x7fffffff)); - a.L[_0] = b.L[_0] = 0x7ff00000; - a.L[_1] = b.L[_1] = 0; - c.d = a.d - b.d; /* quiet NaN */ - c.L[_0] &= 0x7fffffff; - printf("#define d_QNAN0 0x%lx\n", UL c.L[_0]); - printf("#define d_QNAN1 0x%lx\n", UL c.L[_1]); -#ifndef NO_LONG_LONG -#ifdef Gen_ld_QNAN - if (sizeof(a.D) >= 16) { - b.D = c.D = a.d; - if (printf("") < 0) - c.D = 37; /* never executed; just defeat optimization */ - a.L[0] = a.L[1] = a.L[2] = a.L[3] = 0; - a.D = b.D - c.D; - a.L[_3] &= 0x7fffffff; - for(i = 0; i < 4; i++) - printf("#define ld_QNAN%d 0x%lx\n", i, UL a.L[perm[i]]); - } -#endif -#endif -#endif /* HAVE_IEEE */ - return 0; - } diff --git a/libraries/gdtoa/qnan.obj b/libraries/gdtoa/qnan.obj deleted file mode 100644 index 994af47d9..000000000 Binary files a/libraries/gdtoa/qnan.obj and /dev/null differ diff --git a/libraries/gdtoa/smisc.c b/libraries/gdtoa/smisc.c deleted file mode 100644 index f4dbafb21..000000000 --- a/libraries/gdtoa/smisc.c +++ /dev/null @@ -1,191 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 1999 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - Bigint * -s2b -#ifdef KR_headers - (s, nd0, nd, y9, dplen) CONST char *s; int dplen, nd0, nd; ULong y9; -#else - (CONST char *s, int nd0, int nd, ULong y9, int dplen) -#endif -{ - Bigint *b; - int i, k; - Long x, y; - - x = (nd + 8) / 9; - for(k = 0, y = 1; x > y; y <<= 1, k++) ; -#ifdef Pack_32 - b = Balloc(k); - b->x[0] = y9; - b->wds = 1; -#else - b = Balloc(k+1); - b->x[0] = y9 & 0xffff; - b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; -#endif - - i = 9; - if (9 < nd0) { - s += 9; - do b = multadd(b, 10, *s++ - '0'); - while(++i < nd0); - s += dplen; - } - else - s += dplen + 9; - for(; i < nd; i++) - b = multadd(b, 10, *s++ - '0'); - return b; - } - - double -ratio -#ifdef KR_headers - (a, b) Bigint *a, *b; -#else - (Bigint *a, Bigint *b) -#endif -{ - U da, db; - int k, ka, kb; - - dval(&da) = b2d(a, &ka); - dval(&db) = b2d(b, &kb); - k = ka - kb + ULbits*(a->wds - b->wds); -#ifdef IBM - if (k > 0) { - word0(&da) += (k >> 2)*Exp_msk1; - if (k &= 3) - dval(&da) *= 1 << k; - } - else { - k = -k; - word0(&db) += (k >> 2)*Exp_msk1; - if (k &= 3) - dval(&db) *= 1 << k; - } -#else - if (k > 0) - word0(&da) += k*Exp_msk1; - else { - k = -k; - word0(&db) += k*Exp_msk1; - } -#endif - return dval(&da) / dval(&db); - } - -#ifdef INFNAN_CHECK - - int -match -#ifdef KR_headers - (sp, t) char **sp, *t; -#else - (CONST char **sp, char *t) -#endif -{ - int c, d; - CONST char *s = *sp; - - while( (d = *t++) !=0) { - if ((c = *++s) >= 'A' && c <= 'Z') - c += 'a' - 'A'; - if (c != d) - return 0; - } - *sp = s + 1; - return 1; - } -#endif /* INFNAN_CHECK */ - - void -#ifdef KR_headers -copybits(c, n, b) ULong *c; int n; Bigint *b; -#else -copybits(ULong *c, int n, Bigint *b) -#endif -{ - ULong *ce, *x, *xe; -#ifdef Pack_16 - int nw, nw1; -#endif - - ce = c + ((n-1) >> kshift) + 1; - x = b->x; -#ifdef Pack_32 - xe = x + b->wds; - while(x < xe) - *c++ = *x++; -#else - nw = b->wds; - nw1 = nw & 1; - for(xe = x + (nw - nw1); x < xe; x += 2) - Storeinc(c, x[1], x[0]); - if (nw1) - *c++ = *x; -#endif - while(c < ce) - *c++ = 0; - } - - ULong -#ifdef KR_headers -any_on(b, k) Bigint *b; int k; -#else -any_on(Bigint *b, int k) -#endif -{ - int n, nwds; - ULong *x, *x0, x1, x2; - - x = b->x; - nwds = b->wds; - n = k >> kshift; - if (n > nwds) - n = nwds; - else if (n < nwds && (k &= kmask)) { - x1 = x2 = x[n]; - x1 >>= k; - x1 <<= k; - if (x1 != x2) - return 1; - } - x0 = x; - x += n; - while(x > x0) - if (*--x) - return 1; - return 0; - } diff --git a/libraries/gdtoa/strtoIQ.c b/libraries/gdtoa/strtoIQ.c deleted file mode 100644 index 9ce5120e6..000000000 --- a/libraries/gdtoa/strtoIQ.c +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIQ(s, sp, a, b) CONST char *s; char **sp; void *a; void *b; -#else -strtoIQ(CONST char *s, char **sp, void *a, void *b) -#endif -{ - static FPI fpi = { 113, 1-16383-113+1, 32766-16383-113+1, 1, SI }; - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - ULong *L = (ULong *)a, *M = (ULong *)b; - - B[0] = Balloc(2); - B[0]->wds = 4; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtoQ(L, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtoQ(M, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else { - M[0] = L[0]; - M[1] = L[1]; - M[2] = L[2]; - M[3] = L[3]; - } - return k; - } diff --git a/libraries/gdtoa/strtoId.c b/libraries/gdtoa/strtoId.c deleted file mode 100644 index 1c97d382d..000000000 --- a/libraries/gdtoa/strtoId.c +++ /dev/null @@ -1,60 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoId(s, sp, f0, f1) CONST char *s; char **sp; double *f0, *f1; -#else -strtoId(CONST char *s, char **sp, double *f0, double *f1) -#endif -{ - static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - - B[0] = Balloc(1); - B[0]->wds = 2; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtod((ULong*)f0, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtod((ULong*)f1, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else { - ((ULong*)f1)[0] = ((ULong*)f0)[0]; - ((ULong*)f1)[1] = ((ULong*)f0)[1]; - } - return k; - } diff --git a/libraries/gdtoa/strtoIdd.c b/libraries/gdtoa/strtoIdd.c deleted file mode 100644 index 40b7936bc..000000000 --- a/libraries/gdtoa/strtoIdd.c +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIdd(s, sp, f0, f1) CONST char *s; char **sp; double *f0, *f1; -#else -strtoIdd(CONST char *s, char **sp, double *f0, double *f1) -#endif -{ -#ifdef Sudden_Underflow - static FPI fpi = { 106, 1-1023, 2046-1023-106+1, 1, 1 }; -#else - static FPI fpi = { 106, 1-1023-53+1, 2046-1023-106+1, 1, 0 }; -#endif - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - - B[0] = Balloc(2); - B[0]->wds = 4; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtodd((ULong*)f0, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtodd((ULong*)f1, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else { - ((ULong*)f1)[0] = ((ULong*)f0)[0]; - ((ULong*)f1)[1] = ((ULong*)f0)[1]; - ((ULong*)f1)[2] = ((ULong*)f0)[2]; - ((ULong*)f1)[3] = ((ULong*)f0)[3]; - } - return k; - } diff --git a/libraries/gdtoa/strtoIf.c b/libraries/gdtoa/strtoIf.c deleted file mode 100644 index 65ecab2e0..000000000 --- a/libraries/gdtoa/strtoIf.c +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIf(s, sp, f0, f1) CONST char *s; char **sp; float *f0, *f1; -#else -strtoIf(CONST char *s, char **sp, float *f0, float *f1) -#endif -{ - static FPI fpi = { 24, 1-127-24+1, 254-127-24+1, 1, SI }; - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - - B[0] = Balloc(0); - B[0]->wds = 1; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtof((ULong*)f0, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtof((ULong*)f1, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else - *(ULong*)f1 = *(ULong*)f0; - return k; - } diff --git a/libraries/gdtoa/strtoIg.c b/libraries/gdtoa/strtoIg.c deleted file mode 100644 index 6a17760cf..000000000 --- a/libraries/gdtoa/strtoIg.c +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIg(s00, se, fpi, exp, B, rvp) CONST char *s00; char **se; FPI *fpi; Long *exp; Bigint **B; int *rvp; -#else -strtoIg(CONST char *s00, char **se, FPI *fpi, Long *exp, Bigint **B, int *rvp) -#endif -{ - Bigint *b, *b1; - int i, nb, nw, nw1, rv, rv1, swap; - unsigned int nb1, nb11; - Long e1; - - b = *B; - rv = strtodg(s00, se, fpi, exp, b->x); - if (!(rv & STRTOG_Inexact)) { - B[1] = 0; - return *rvp = rv; - } - e1 = exp[0]; - rv1 = rv ^ STRTOG_Inexact; - b1 = Balloc(b->k); - Bcopy(b1, b); - nb = fpi->nbits; - nb1 = nb & 31; - nb11 = (nb1 - 1) & 31; - nw = b->wds; - nw1 = nw - 1; - if (rv & STRTOG_Inexlo) { - swap = 0; - b1 = increment(b1); - if ((rv & STRTOG_Retmask) == STRTOG_Zero) { - if (fpi->sudden_underflow) { - b1->x[0] = 0; - b1->x[nw1] = 1L << nb11; - rv1 += STRTOG_Normal - STRTOG_Zero; - rv1 &= ~STRTOG_Underflow; - goto swapcheck; - } - rv1 &= STRTOG_Inexlo | STRTOG_Underflow | STRTOG_Zero; - rv1 |= STRTOG_Inexhi | STRTOG_Denormal; - goto swapcheck; - } - if (b1->wds > nw - || (nb1 && b1->x[nw1] & 1L << nb1)) { - if (++e1 > fpi->emax) - rv1 = STRTOG_Infinite | STRTOG_Inexhi; - rshift(b1, 1); - } - else if ((rv & STRTOG_Retmask) == STRTOG_Denormal) { - if (b1->x[nw1] & 1L << nb11) { - rv1 += STRTOG_Normal - STRTOG_Denormal; - rv1 &= ~STRTOG_Underflow; - } - } - } - else { - swap = STRTOG_Neg; - if ((rv & STRTOG_Retmask) == STRTOG_Infinite) { - b1 = set_ones(b1, nb); - e1 = fpi->emax; - rv1 = STRTOG_Normal | STRTOG_Inexlo; - goto swapcheck; - } - decrement(b1); - if ((rv & STRTOG_Retmask) == STRTOG_Denormal) { - for(i = nw1; !b1->x[i]; --i) - if (!i) { - rv1 = STRTOG_Zero | STRTOG_Inexlo; - break; - } - goto swapcheck; - } - if (!(b1->x[nw1] & 1L << nb11)) { - if (e1 == fpi->emin) { - if (fpi->sudden_underflow) - rv1 += STRTOG_Zero - STRTOG_Normal; - else - rv1 += STRTOG_Denormal - STRTOG_Normal; - rv1 |= STRTOG_Underflow; - } - else { - b1 = lshift(b1, 1); - b1->x[0] |= 1; - --e1; - } - } - } - swapcheck: - if (swap ^ (rv & STRTOG_Neg)) { - rvp[0] = rv1; - rvp[1] = rv; - B[0] = b1; - B[1] = b; - exp[1] = exp[0]; - exp[0] = e1; - } - else { - rvp[0] = rv; - rvp[1] = rv1; - B[1] = b1; - exp[1] = e1; - } - return rv; - } diff --git a/libraries/gdtoa/strtoIx.c b/libraries/gdtoa/strtoIx.c deleted file mode 100644 index 783a631f0..000000000 --- a/libraries/gdtoa/strtoIx.c +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIx(s, sp, a, b) CONST char *s; char **sp; void *a; void *b; -#else -strtoIx(CONST char *s, char **sp, void *a, void *b) -#endif -{ - static FPI fpi = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - UShort *L = (UShort *)a, *M = (UShort *)b; - - B[0] = Balloc(1); - B[0]->wds = 2; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtox(L, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtox(M, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else { - M[0] = L[0]; - M[1] = L[1]; - M[2] = L[2]; - M[3] = L[3]; - M[4] = L[4]; - } - return k; - } diff --git a/libraries/gdtoa/strtoIxL.c b/libraries/gdtoa/strtoIxL.c deleted file mode 100644 index 869bfd16f..000000000 --- a/libraries/gdtoa/strtoIxL.c +++ /dev/null @@ -1,62 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtoIxL(s, sp, a, b) CONST char *s; char **sp; void *a; void *b; -#else -strtoIxL(CONST char *s, char **sp, void *a, void *b) -#endif -{ - static FPI fpi = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - Long exp[2]; - Bigint *B[2]; - int k, rv[2]; - ULong *L = (ULong *)a, *M = (ULong *)b; - - B[0] = Balloc(1); - B[0]->wds = 2; - k = strtoIg(s, sp, &fpi, exp, B, rv); - ULtoxL(L, B[0]->x, exp[0], rv[0]); - Bfree(B[0]); - if (B[1]) { - ULtoxL(M, B[1]->x, exp[1], rv[1]); - Bfree(B[1]); - } - else { - M[0] = L[0]; - M[1] = L[1]; - M[2] = L[2]; - } - return k; - } diff --git a/libraries/gdtoa/strtod.c b/libraries/gdtoa/strtod.c deleted file mode 100644 index 3c2230053..000000000 --- a/libraries/gdtoa/strtod.c +++ /dev/null @@ -1,1074 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998-2001 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" -#if !defined(NO_FENV_H) && !defined(_MSC_VER) -#include -#endif - -#ifdef USE_LOCALE -#include "locale.h" -#endif - -#ifdef IEEE_Arith -#ifndef NO_IEEE_Scale -#define Avoid_Underflow -#undef tinytens -/* The factor of 2^106 in tinytens[4] helps us avoid setting the underflow */ -/* flag unnecessarily. It leads to a song and dance at the end of strtod. */ -static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, - 9007199254740992.*9007199254740992.e-256 - }; -#endif -#endif - -#ifdef Honor_FLT_ROUNDS -#undef Check_FLT_ROUNDS -#define Check_FLT_ROUNDS -#else -#define Rounding Flt_Rounds -#endif - -#ifdef Avoid_Underflow /*{*/ - static double -sulp -#ifdef KR_headers - (x, scale) U *x; int scale; -#else - (U *x, int scale) -#endif -{ - U u; - double rv; - int i; - - rv = ulp(x); - if (!scale || (i = 2*P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0) - return rv; /* Is there an example where i <= 0 ? */ - word0(&u) = Exp_1 + (i << Exp_shift); - word1(&u) = 0; - return rv * u.d; - } -#endif /*}*/ - - double -strtod -#ifdef KR_headers - (s00, se) CONST char *s00; char **se; -#else - (CONST char *s00, char **se) -#endif -{ -#ifdef Avoid_Underflow - int scale; -#endif - int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, dsign, - e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; - CONST char *s, *s0, *s1; - double aadj; - Long L; - U adj, aadj1, rv, rv0; - ULong y, z; - Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; -#ifdef Avoid_Underflow - ULong Lsb, Lsb1; -#endif -#ifdef SET_INEXACT - int inexact, oldinexact; -#endif -#ifdef USE_LOCALE /*{{*/ -#ifdef NO_LOCALE_CACHE - char *decimalpoint = localeconv()->decimal_point; - int dplen = strlen(decimalpoint); -#else - char *decimalpoint; - static char *decimalpoint_cache; - static int dplen; - if (!(s0 = decimalpoint_cache)) { - s0 = localeconv()->decimal_point; - if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { - strcpy(decimalpoint_cache, s0); - s0 = decimalpoint_cache; - } - dplen = strlen(s0); - } - decimalpoint = (char*)s0; -#endif /*NO_LOCALE_CACHE*/ -#else /*USE_LOCALE}{*/ -#define dplen 1 -#endif /*USE_LOCALE}}*/ - -#ifdef Honor_FLT_ROUNDS /*{*/ - int Rounding; -#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ - Rounding = Flt_Rounds; -#else /*}{*/ - Rounding = 1; - switch(fegetround()) { - case FE_TOWARDZERO: Rounding = 0; break; - case FE_UPWARD: Rounding = 2; break; - case FE_DOWNWARD: Rounding = 3; - } -#endif /*}}*/ -#endif /*}*/ - - sign = nz0 = nz = decpt = 0; - dval(&rv) = 0.; - for(s = s00;;s++) switch(*s) { - case '-': - sign = 1; - /* no break */ - case '+': - if (*++s) - goto break2; - /* no break */ - case 0: - goto ret0; - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - continue; - default: - goto break2; - } - break2: - if (*s == '0') { -#ifndef NO_HEX_FP /*{*/ - { - static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - Long exp; - ULong bits[2]; - switch(s[1]) { - case 'x': - case 'X': - { -#ifdef Honor_FLT_ROUNDS - FPI fpi1 = fpi; - fpi1.rounding = Rounding; -#else -#define fpi1 fpi -#endif - switch((i = gethex(&s, &fpi1, &exp, &bb, sign)) & STRTOG_Retmask) { - case STRTOG_NoNumber: - s = s00; - sign = 0; - case STRTOG_Zero: - break; - default: - if (bb) { - copybits(bits, fpi.nbits, bb); - Bfree(bb); - } - ULtod(((U*)&rv)->L, bits, exp, i); - }} - goto ret; - } - } -#endif /*}*/ - nz0 = 1; - while(*++s == '0') ; - if (!*s) - goto ret; - } - s0 = s; - y = z = 0; - for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) - if (nd < 9) - y = 10*y + c - '0'; - else if (nd < 16) - z = 10*z + c - '0'; - nd0 = nd; -#ifdef USE_LOCALE - if (c == *decimalpoint) { - for(i = 1; decimalpoint[i]; ++i) - if (s[i] != decimalpoint[i]) - goto dig_done; - s += i; - c = *s; -#else - if (c == '.') { - c = *++s; -#endif - decpt = 1; - if (!nd) { - for(; c == '0'; c = *++s) - nz++; - if (c > '0' && c <= '9') { - s0 = s; - nf += nz; - nz = 0; - goto have_dig; - } - goto dig_done; - } - for(; c >= '0' && c <= '9'; c = *++s) { - have_dig: - nz++; - if (c -= '0') { - nf += nz; - for(i = 1; i < nz; i++) - if (nd++ < 9) - y *= 10; - else if (nd <= DBL_DIG + 1) - z *= 10; - if (nd++ < 9) - y = 10*y + c; - else if (nd <= DBL_DIG + 1) - z = 10*z + c; - nz = 0; - } - } - }/*}*/ - dig_done: - e = 0; - if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { - goto ret0; - } - s00 = s; - esign = 0; - switch(c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; - } - if (c >= '0' && c <= '9') { - while(c == '0') - c = *++s; - if (c > '0' && c <= '9') { - L = c - '0'; - s1 = s; - while((c = *++s) >= '0' && c <= '9') - L = 10*L + c - '0'; - if (s - s1 > 8 || L > 19999) - /* Avoid confusion from exponents - * so large that e might overflow. - */ - e = 19999; /* safe for 16 bit ints */ - else - e = (int)L; - if (esign) - e = -e; - } - else - e = 0; - } - else - s = s00; - } - if (!nd) { - if (!nz && !nz0) { -#ifdef INFNAN_CHECK - /* Check for Nan and Infinity */ - ULong bits[2]; - static FPI fpinan = /* only 52 explicit bits */ - { 52, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - if (!decpt) - switch(c) { - case 'i': - case 'I': - if (match(&s,"nf")) { - --s; - if (!match(&s,"inity")) - ++s; - word0(&rv) = 0x7ff00000; - word1(&rv) = 0; - goto ret; - } - break; - case 'n': - case 'N': - if (match(&s, "an")) { -#ifndef No_Hex_NaN - if (*s == '(' /*)*/ - && hexnan(&s, &fpinan, bits) - == STRTOG_NaNbits) { - word0(&rv) = 0x7ff00000 | bits[1]; - word1(&rv) = bits[0]; - } - else { -#endif - word0(&rv) = NAN_WORD0; - word1(&rv) = NAN_WORD1; -#ifndef No_Hex_NaN - } -#endif - goto ret; - } - } -#endif /* INFNAN_CHECK */ - ret0: - s = s00; - sign = 0; - } - goto ret; - } - e1 = e -= nf; - - /* Now we have nd0 digits, starting at s0, followed by a - * decimal point, followed by nd-nd0 digits. The number we're - * after is the integer represented by those digits times - * 10**e */ - - if (!nd0) - nd0 = nd; - k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; - dval(&rv) = y; - if (k > 9) { -#ifdef SET_INEXACT - if (k > DBL_DIG) - oldinexact = get_inexact(); -#endif - dval(&rv) = tens[k - 9] * dval(&rv) + z; - } - bd0 = 0; - if (nd <= DBL_DIG -#ifndef RND_PRODQUOT -#ifndef Honor_FLT_ROUNDS - && Flt_Rounds == 1 -#endif -#endif - ) { - if (!e) - goto ret; -#ifndef ROUND_BIASED_without_Round_Up - if (e > 0) { - if (e <= Ten_pmax) { -#ifdef VAX - goto vax_ovfl_check; -#else -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - /* rv = */ rounded_product(dval(&rv), tens[e]); - goto ret; -#endif - } - i = DBL_DIG - nd; - if (e <= Ten_pmax + i) { - /* A fancier test would sometimes let us do - * this for larger i values. - */ -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - e -= i; - dval(&rv) *= tens[i]; -#ifdef VAX - /* VAX exponent range is so narrow we must - * worry about overflow here... - */ - vax_ovfl_check: - word0(&rv) -= P*Exp_msk1; - /* rv = */ rounded_product(dval(&rv), tens[e]); - if ((word0(&rv) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) - goto ovfl; - word0(&rv) += P*Exp_msk1; -#else - /* rv = */ rounded_product(dval(&rv), tens[e]); -#endif - goto ret; - } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { -#ifdef Honor_FLT_ROUNDS - /* round correctly FLT_ROUNDS = 2 or 3 */ - if (sign) { - rv.d = -rv.d; - sign = 0; - } -#endif - /* rv = */ rounded_quotient(dval(&rv), tens[-e]); - goto ret; - } -#endif -#endif /* ROUND_BIASED_without_Round_Up */ - } - e1 += nd - k; - -#ifdef IEEE_Arith -#ifdef SET_INEXACT - inexact = 1; - if (k <= DBL_DIG) - oldinexact = get_inexact(); -#endif -#ifdef Avoid_Underflow - scale = 0; -#endif -#ifdef Honor_FLT_ROUNDS - if (Rounding >= 2) { - if (sign) - Rounding = Rounding == 2 ? 0 : 2; - else - if (Rounding != 2) - Rounding = 0; - } -#endif -#endif /*IEEE_Arith*/ - - /* Get starting approximation = rv * 10**e1 */ - - if (e1 > 0) { - if ( (i = e1 & 15) !=0) - dval(&rv) *= tens[i]; - if (e1 &= ~15) { - if (e1 > DBL_MAX_10_EXP) { - ovfl: - /* Can't trust HUGE_VAL */ -#ifdef IEEE_Arith -#ifdef Honor_FLT_ROUNDS - switch(Rounding) { - case 0: /* toward 0 */ - case 3: /* toward -infinity */ - word0(&rv) = Big0; - word1(&rv) = Big1; - break; - default: - word0(&rv) = Exp_mask; - word1(&rv) = 0; - } -#else /*Honor_FLT_ROUNDS*/ - word0(&rv) = Exp_mask; - word1(&rv) = 0; -#endif /*Honor_FLT_ROUNDS*/ -#ifdef SET_INEXACT - /* set overflow bit */ - dval(&rv0) = 1e300; - dval(&rv0) *= dval(&rv0); -#endif -#else /*IEEE_Arith*/ - word0(&rv) = Big0; - word1(&rv) = Big1; -#endif /*IEEE_Arith*/ - range_err: - if (bd0) { - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); - } -#ifndef NO_ERRNO - errno = ERANGE; -#endif - goto ret; - } - e1 >>= 4; - for(j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= bigtens[j]; - /* The last multiplication could overflow. */ - word0(&rv) -= P*Exp_msk1; - dval(&rv) *= bigtens[j]; - if ((z = word0(&rv) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-P)) - goto ovfl; - if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { - /* set to largest number */ - /* (Can't trust DBL_MAX) */ - word0(&rv) = Big0; - word1(&rv) = Big1; - } - else - word0(&rv) += P*Exp_msk1; - } - } - else if (e1 < 0) { - e1 = -e1; - if ( (i = e1 & 15) !=0) - dval(&rv) /= tens[i]; - if (e1 >>= 4) { - if (e1 >= 1 << n_bigtens) - goto undfl; -#ifdef Avoid_Underflow - if (e1 & Scale_Bit) - scale = 2*P; - for(j = 0; e1 > 0; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= tinytens[j]; - if (scale && (j = 2*P + 1 - ((word0(&rv) & Exp_mask) - >> Exp_shift)) > 0) { - /* scaled rv is denormal; zap j low bits */ - if (j >= 32) { - word1(&rv) = 0; - if (j >= 53) - word0(&rv) = (P+2)*Exp_msk1; - else - word0(&rv) &= 0xffffffff << (j-32); - } - else - word1(&rv) &= 0xffffffff << j; - } -#else - for(j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= tinytens[j]; - /* The last multiplication could underflow. */ - dval(&rv0) = dval(&rv); - dval(&rv) *= tinytens[j]; - if (!dval(&rv)) { - dval(&rv) = 2.*dval(&rv0); - dval(&rv) *= tinytens[j]; -#endif - if (!dval(&rv)) { - undfl: - dval(&rv) = 0.; - goto range_err; - } -#ifndef Avoid_Underflow - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - /* The refinement below will clean - * this approximation up. - */ - } -#endif - } - } - - /* Now the hard part -- adjusting rv to the correct value.*/ - - /* Put digits into bd: true value = bd * 10^e */ - - bd0 = s2b(s0, nd0, nd, y, dplen); - - for(;;) { - bd = Balloc(bd0->k); - Bcopy(bd, bd0); - bb = d2b(dval(&rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ - bs = i2b(1); - - if (e >= 0) { - bb2 = bb5 = 0; - bd2 = bd5 = e; - } - else { - bb2 = bb5 = -e; - bd2 = bd5 = 0; - } - if (bbe >= 0) - bb2 += bbe; - else - bd2 -= bbe; - bs2 = bb2; -#ifdef Honor_FLT_ROUNDS - if (Rounding != 1) - bs2++; -#endif -#ifdef Avoid_Underflow - Lsb = LSB; - Lsb1 = 0; - j = bbe - scale; - i = j + bbbits - 1; /* logb(rv) */ - j = P + 1 - bbbits; - if (i < Emin) { /* denormal */ - i = Emin - i; - j -= i; - if (i < 32) - Lsb <<= i; - else - Lsb1 = Lsb << (i-32); - } -#else /*Avoid_Underflow*/ -#ifdef Sudden_Underflow -#ifdef IBM - j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); -#else - j = P + 1 - bbbits; -#endif -#else /*Sudden_Underflow*/ - j = bbe; - i = j + bbbits - 1; /* logb(&rv) */ - if (i < Emin) /* denormal */ - j += P - Emin; - else - j = P + 1 - bbbits; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - bb2 += j; - bd2 += j; -#ifdef Avoid_Underflow - bd2 += scale; -#endif - i = bb2 < bd2 ? bb2 : bd2; - if (i > bs2) - i = bs2; - if (i > 0) { - bb2 -= i; - bd2 -= i; - bs2 -= i; - } - if (bb5 > 0) { - bs = pow5mult(bs, bb5); - bb1 = mult(bs, bb); - Bfree(bb); - bb = bb1; - } - if (bb2 > 0) - bb = lshift(bb, bb2); - if (bd5 > 0) - bd = pow5mult(bd, bd5); - if (bd2 > 0) - bd = lshift(bd, bd2); - if (bs2 > 0) - bs = lshift(bs, bs2); - delta = diff(bb, bd); - dsign = delta->sign; - delta->sign = 0; - i = cmp(delta, bs); -#ifdef Honor_FLT_ROUNDS - if (Rounding != 1) { - if (i < 0) { - /* Error is less than an ulp */ - if (!delta->x[0] && delta->wds <= 1) { - /* exact */ -#ifdef SET_INEXACT - inexact = 0; -#endif - break; - } - if (Rounding) { - if (dsign) { - dval(&adj) = 1.; - goto apply_adj; - } - } - else if (!dsign) { - dval(&adj) = -1.; - if (!word1(&rv) - && !(word0(&rv) & Frac_mask)) { - y = word0(&rv) & Exp_mask; -#ifdef Avoid_Underflow - if (!scale || y > 2*P*Exp_msk1) -#else - if (y) -#endif - { - delta = lshift(delta,Log2P); - if (cmp(delta, bs) <= 0) - dval(&adj) = -0.5; - } - } - apply_adj: -#ifdef Avoid_Underflow - if (scale && (y = word0(&rv) & Exp_mask) - <= 2*P*Exp_msk1) - word0(&adj) += (2*P+1)*Exp_msk1 - y; -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= - P*Exp_msk1) { - word0(&rv) += P*Exp_msk1; - dval(&rv) += adj*ulp(&rv); - word0(&rv) -= P*Exp_msk1; - } - else -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - dval(&rv) += adj.d*ulp(&rv); - } - break; - } - dval(&adj) = ratio(delta, bs); - if (adj.d < 1.) - dval(&adj) = 1.; - if (adj.d <= 0x7ffffffe) { - /* dval(&adj) = Rounding ? ceil(&adj) : floor(&adj); */ - y = adj.d; - if (y != adj.d) { - if (!((Rounding>>1) ^ dsign)) - y++; - dval(&adj) = y; - } - } -#ifdef Avoid_Underflow - if (scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) - word0(&adj) += (2*P+1)*Exp_msk1 - y; -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { - word0(&rv) += P*Exp_msk1; - dval(&adj) *= ulp(&rv); - if (dsign) - dval(&rv) += adj; - else - dval(&rv) -= adj; - word0(&rv) -= P*Exp_msk1; - goto cont; - } -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - dval(&adj) *= ulp(&rv); - if (dsign) { - if (word0(&rv) == Big0 && word1(&rv) == Big1) - goto ovfl; - dval(&rv) += adj.d; - } - else - dval(&rv) -= adj.d; - goto cont; - } -#endif /*Honor_FLT_ROUNDS*/ - - if (i < 0) { - /* Error is less than half an ulp -- check for - * special case of mantissa a power of two. - */ - if (dsign || word1(&rv) || word0(&rv) & Bndry_mask -#ifdef IEEE_Arith -#ifdef Avoid_Underflow - || (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1 -#else - || (word0(&rv) & Exp_mask) <= Exp_msk1 -#endif -#endif - ) { -#ifdef SET_INEXACT - if (!delta->x[0] && delta->wds <= 1) - inexact = 0; -#endif - break; - } - if (!delta->x[0] && delta->wds <= 1) { - /* exact result */ -#ifdef SET_INEXACT - inexact = 0; -#endif - break; - } - delta = lshift(delta,Log2P); - if (cmp(delta, bs) > 0) - goto drop_down; - break; - } - if (i == 0) { - /* exactly half-way between */ - if (dsign) { - if ((word0(&rv) & Bndry_mask1) == Bndry_mask1 - && word1(&rv) == ( -#ifdef Avoid_Underflow - (scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1) - ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) : -#endif - 0xffffffff)) { - /*boundary case -- increment exponent*/ - if (word0(&rv) == Big0 && word1(&rv) == Big1) - goto ovfl; - word0(&rv) = (word0(&rv) & Exp_mask) - + Exp_msk1 -#ifdef IBM - | Exp_msk1 >> 4 -#endif - ; - word1(&rv) = 0; -#ifdef Avoid_Underflow - dsign = 0; -#endif - break; - } - } - else if (!(word0(&rv) & Bndry_mask) && !word1(&rv)) { - drop_down: - /* boundary case -- decrement exponent */ -#ifdef Sudden_Underflow /*{{*/ - L = word0(&rv) & Exp_mask; -#ifdef IBM - if (L < Exp_msk1) -#else -#ifdef Avoid_Underflow - if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1)) -#else - if (L <= Exp_msk1) -#endif /*Avoid_Underflow*/ -#endif /*IBM*/ - goto undfl; - L -= Exp_msk1; -#else /*Sudden_Underflow}{*/ -#ifdef Avoid_Underflow - if (scale) { - L = word0(&rv) & Exp_mask; - if (L <= (2*P+1)*Exp_msk1) { - if (L > (P+2)*Exp_msk1) - /* round even ==> */ - /* accept rv */ - break; - /* rv = smallest denormal */ - goto undfl; - } - } -#endif /*Avoid_Underflow*/ - L = (word0(&rv) & Exp_mask) - Exp_msk1; -#endif /*Sudden_Underflow}}*/ - word0(&rv) = L | Bndry_mask1; - word1(&rv) = 0xffffffff; -#ifdef IBM - goto cont; -#else - break; -#endif - } -#ifndef ROUND_BIASED -#ifdef Avoid_Underflow - if (Lsb1) { - if (!(word0(&rv) & Lsb1)) - break; - } - else if (!(word1(&rv) & Lsb)) - break; -#else - if (!(word1(&rv) & LSB)) - break; -#endif -#endif - if (dsign) -#ifdef Avoid_Underflow - dval(&rv) += sulp(&rv, scale); -#else - dval(&rv) += ulp(&rv); -#endif -#ifndef ROUND_BIASED - else { -#ifdef Avoid_Underflow - dval(&rv) -= sulp(&rv, scale); -#else - dval(&rv) -= ulp(&rv); -#endif -#ifndef Sudden_Underflow - if (!dval(&rv)) - goto undfl; -#endif - } -#ifdef Avoid_Underflow - dsign = 1 - dsign; -#endif -#endif - break; - } - if ((aadj = ratio(delta, bs)) <= 2.) { - if (dsign) - aadj = dval(&aadj1) = 1.; - else if (word1(&rv) || word0(&rv) & Bndry_mask) { -#ifndef Sudden_Underflow - if (word1(&rv) == Tiny1 && !word0(&rv)) - goto undfl; -#endif - aadj = 1.; - dval(&aadj1) = -1.; - } - else { - /* special case -- power of FLT_RADIX to be */ - /* rounded down... */ - - if (aadj < 2./FLT_RADIX) - aadj = 1./FLT_RADIX; - else - aadj *= 0.5; - dval(&aadj1) = -aadj; - } - } - else { - aadj *= 0.5; - dval(&aadj1) = dsign ? aadj : -aadj; -#ifdef Check_FLT_ROUNDS - switch(Rounding) { - case 2: /* towards +infinity */ - dval(&aadj1) -= 0.5; - break; - case 0: /* towards 0 */ - case 3: /* towards -infinity */ - dval(&aadj1) += 0.5; - } -#else - if (Flt_Rounds == 0) - dval(&aadj1) += 0.5; -#endif /*Check_FLT_ROUNDS*/ - } - y = word0(&rv) & Exp_mask; - - /* Check for overflow */ - - if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { - dval(&rv0) = dval(&rv); - word0(&rv) -= P*Exp_msk1; - dval(&adj) = dval(&aadj1) * ulp(&rv); - dval(&rv) += dval(&adj); - if ((word0(&rv) & Exp_mask) >= - Exp_msk1*(DBL_MAX_EXP+Bias-P)) { - if (word0(&rv0) == Big0 && word1(&rv0) == Big1) - goto ovfl; - word0(&rv) = Big0; - word1(&rv) = Big1; - goto cont; - } - else - word0(&rv) += P*Exp_msk1; - } - else { -#ifdef Avoid_Underflow - if (scale && y <= 2*P*Exp_msk1) { - if (aadj <= 0x7fffffff) { - if ((z = (ULong)aadj) <= 0) - z = 1; - aadj = z; - dval(&aadj1) = dsign ? aadj : -aadj; - } - word0(&aadj1) += (2*P+1)*Exp_msk1 - y; - } - dval(&adj) = dval(&aadj1) * ulp(&rv); - dval(&rv) += dval(&adj); -#else -#ifdef Sudden_Underflow - if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) { - dval(&rv0) = dval(&rv); - word0(&rv) += P*Exp_msk1; - dval(&adj) = dval(&aadj1) * ulp(&rv); - dval(&rv) += adj; -#ifdef IBM - if ((word0(&rv) & Exp_mask) < P*Exp_msk1) -#else - if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) -#endif - { - if (word0(&rv0) == Tiny0 - && word1(&rv0) == Tiny1) - goto undfl; - word0(&rv) = Tiny0; - word1(&rv) = Tiny1; - goto cont; - } - else - word0(&rv) -= P*Exp_msk1; - } - else { - dval(&adj) = dval(&aadj1) * ulp(&rv); - dval(&rv) += adj; - } -#else /*Sudden_Underflow*/ - /* Compute dval(&adj) so that the IEEE rounding rules will - * correctly round rv + dval(&adj) in some half-way cases. - * If rv * ulp(&rv) is denormalized (i.e., - * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid - * trouble from bits lost to denormalization; - * example: 1.2e-307 . - */ - if (y <= (P-1)*Exp_msk1 && aadj > 1.) { - dval(&aadj1) = (double)(int)(aadj + 0.5); - if (!dsign) - dval(&aadj1) = -dval(&aadj1); - } - dval(&adj) = dval(&aadj1) * ulp(&rv); - dval(&rv) += adj; -#endif /*Sudden_Underflow*/ -#endif /*Avoid_Underflow*/ - } - z = word0(&rv) & Exp_mask; -#ifndef SET_INEXACT -#ifdef Avoid_Underflow - if (!scale) -#endif - if (y == z) { - /* Can we stop now? */ - L = (Long)aadj; - aadj -= L; - /* The tolerances below are conservative. */ - if (dsign || word1(&rv) || word0(&rv) & Bndry_mask) { - if (aadj < .4999999 || aadj > .5000001) - break; - } - else if (aadj < .4999999/FLT_RADIX) - break; - } -#endif - cont: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(delta); - } - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); -#ifdef SET_INEXACT - if (inexact) { - if (!oldinexact) { - word0(&rv0) = Exp_1 + (70 << Exp_shift); - word1(&rv0) = 0; - dval(&rv0) += 1.; - } - } - else if (!oldinexact) - clear_inexact(); -#endif -#ifdef Avoid_Underflow - if (scale) { - word0(&rv0) = Exp_1 - 2*P*Exp_msk1; - word1(&rv0) = 0; - dval(&rv) *= dval(&rv0); -#ifndef NO_ERRNO - /* try to avoid the bug of testing an 8087 register value */ -#ifdef IEEE_Arith - if (!(word0(&rv) & Exp_mask)) -#else - if (word0(&rv) == 0 && word1(&rv) == 0) -#endif - errno = ERANGE; -#endif - } -#endif /* Avoid_Underflow */ -#ifdef SET_INEXACT - if (inexact && !(word0(&rv) & Exp_mask)) { - /* set underflow bit */ - dval(&rv0) = 1e-300; - dval(&rv0) *= dval(&rv0); - } -#endif - ret: - if (se) - *se = (char *)s; - return sign ? -dval(&rv) : dval(&rv); - } - diff --git a/libraries/gdtoa/strtodI.c b/libraries/gdtoa/strtodI.c deleted file mode 100644 index 0b7b8a45c..000000000 --- a/libraries/gdtoa/strtodI.c +++ /dev/null @@ -1,163 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - static double -#ifdef KR_headers -ulpdown(d) U *d; -#else -ulpdown(U *d) -#endif -{ - double u; - ULong *L = d->L; - - u = ulp(d); - if (!(L[_1] | (L[_0] & 0xfffff)) - && (L[_0] & 0x7ff00000) > 0x00100000) - u *= 0.5; - return u; - } - - int -#ifdef KR_headers -strtodI(s, sp, dd) CONST char *s; char **sp; double *dd; -#else -strtodI(CONST char *s, char **sp, double *dd) -#endif -{ - static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - ULong bits[2], sign; - Long exp; - int j, k; - U *u; - - k = strtodg(s, sp, &fpi, &exp, bits); - u = (U*)dd; - sign = k & STRTOG_Neg ? 0x80000000L : 0; - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - dval(&u[0]) = dval(&u[1]) = 0.; - break; - - case STRTOG_Zero: - dval(&u[0]) = dval(&u[1]) = 0.; -#ifdef Sudden_Underflow - if (k & STRTOG_Inexact) { - if (sign) - word0(&u[0]) = 0x80100000L; - else - word0(&u[1]) = 0x100000L; - } - break; -#else - goto contain; -#endif - - case STRTOG_Denormal: - word1(&u[0]) = bits[0]; - word0(&u[0]) = bits[1]; - goto contain; - - case STRTOG_Normal: - word1(&u[0]) = bits[0]; - word0(&u[0]) = (bits[1] & ~0x100000) | ((exp + 0x3ff + 52) << 20); - contain: - j = k & STRTOG_Inexact; - if (sign) { - word0(&u[0]) |= sign; - j = STRTOG_Inexact - j; - } - switch(j) { - case STRTOG_Inexlo: -#ifdef Sudden_Underflow - if ((u->L[_0] & 0x7ff00000) < 0x3500000) { - word0(&u[1]) = word0(&u[0]) + 0x3500000; - word1(&u[1]) = word1(&u[0]); - dval(&u[1]) += ulp(&u[1]); - word0(&u[1]) -= 0x3500000; - if (!(word0(&u[1]) & 0x7ff00000)) { - word0(&u[1]) = sign; - word1(&u[1]) = 0; - } - } - else -#endif - dval(&u[1]) = dval(&u[0]) + ulp(&u[0]); - break; - case STRTOG_Inexhi: - dval(&u[1]) = dval(&u[0]); -#ifdef Sudden_Underflow - if ((word0(&u[0]) & 0x7ff00000) < 0x3500000) { - word0(&u[0]) += 0x3500000; - dval(&u[0]) -= ulpdown(u); - word0(&u[0]) -= 0x3500000; - if (!(word0(&u[0]) & 0x7ff00000)) { - word0(&u[0]) = sign; - word1(&u[0]) = 0; - } - } - else -#endif - dval(&u[0]) -= ulpdown(u); - break; - default: - dval(&u[1]) = dval(&u[0]); - } - break; - - case STRTOG_Infinite: - word0(&u[0]) = word0(&u[1]) = sign | 0x7ff00000; - word1(&u[0]) = word1(&u[1]) = 0; - if (k & STRTOG_Inexact) { - if (sign) { - word0(&u[1]) = 0xffefffffL; - word1(&u[1]) = 0xffffffffL; - } - else { - word0(&u[0]) = 0x7fefffffL; - word1(&u[0]) = 0xffffffffL; - } - } - break; - - case STRTOG_NaN: - u->L[0] = (u+1)->L[0] = d_QNAN0; - u->L[1] = (u+1)->L[1] = d_QNAN1; - break; - - case STRTOG_NaNbits: - word0(&u[0]) = word0(&u[1]) = 0x7ff00000 | sign | bits[1]; - word1(&u[0]) = word1(&u[1]) = bits[0]; - } - return k; - } diff --git a/libraries/gdtoa/strtodg.c b/libraries/gdtoa/strtodg.c deleted file mode 100644 index c2e3365c7..000000000 --- a/libraries/gdtoa/strtodg.c +++ /dev/null @@ -1,1065 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998-2001 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#ifdef USE_LOCALE -#include "locale.h" -#endif - - static CONST int -fivesbits[] = { 0, 3, 5, 7, 10, 12, 14, 17, 19, 21, - 24, 26, 28, 31, 33, 35, 38, 40, 42, 45, - 47, 49, 52 -#ifdef VAX - , 54, 56 -#endif - }; - - Bigint * -#ifdef KR_headers -increment(b) Bigint *b; -#else -increment(Bigint *b) -#endif -{ - ULong *x, *xe; - Bigint *b1; -#ifdef Pack_16 - ULong carry = 1, y; -#endif - - x = b->x; - xe = x + b->wds; -#ifdef Pack_32 - do { - if (*x < (ULong)0xffffffffL) { - ++*x; - return b; - } - *x++ = 0; - } while(x < xe); -#else - do { - y = *x + carry; - carry = y >> 16; - *x++ = y & 0xffff; - if (!carry) - return b; - } while(x < xe); - if (carry) -#endif - { - if (b->wds >= b->maxwds) { - b1 = Balloc(b->k+1); - Bcopy(b1,b); - Bfree(b); - b = b1; - } - b->x[b->wds++] = 1; - } - return b; - } - - void -#ifdef KR_headers -decrement(b) Bigint *b; -#else -decrement(Bigint *b) -#endif -{ - ULong *x, *xe; -#ifdef Pack_16 - ULong borrow = 1, y; -#endif - - x = b->x; - xe = x + b->wds; -#ifdef Pack_32 - do { - if (*x) { - --*x; - break; - } - *x++ = 0xffffffffL; - } - while(x < xe); -#else - do { - y = *x - borrow; - borrow = (y & 0x10000) >> 16; - *x++ = y & 0xffff; - } while(borrow && x < xe); -#endif - } - - static int -#ifdef KR_headers -all_on(b, n) Bigint *b; int n; -#else -all_on(Bigint *b, int n) -#endif -{ - ULong *x, *xe; - - x = b->x; - xe = x + (n >> kshift); - while(x < xe) - if ((*x++ & ALL_ON) != ALL_ON) - return 0; - if (n &= kmask) - return ((*x | (ALL_ON << n)) & ALL_ON) == ALL_ON; - return 1; - } - - Bigint * -#ifdef KR_headers -set_ones(b, n) Bigint *b; int n; -#else -set_ones(Bigint *b, int n) -#endif -{ - int k; - ULong *x, *xe; - - k = (n + ((1 << kshift) - 1)) >> kshift; - if (b->k < k) { - Bfree(b); - b = Balloc(k); - } - k = n >> kshift; - if (n &= kmask) - k++; - b->wds = k; - x = b->x; - xe = x + k; - while(x < xe) - *x++ = ALL_ON; - if (n) - x[-1] >>= ULbits - n; - return b; - } - - static int -rvOK -#ifdef KR_headers - (d, fpi, exp, bits, exact, rd, irv) - U *d; FPI *fpi; Long *exp; ULong *bits; int exact, rd, *irv; -#else - (U *d, FPI *fpi, Long *exp, ULong *bits, int exact, int rd, int *irv) -#endif -{ - Bigint *b; - ULong carry, inex, lostbits; - int bdif, e, j, k, k1, nb, rv; - - carry = rv = 0; - b = d2b(dval(d), &e, &bdif); - bdif -= nb = fpi->nbits; - e += bdif; - if (bdif <= 0) { - if (exact) - goto trunc; - goto ret; - } - if (P == nb) { - if ( -#ifndef IMPRECISE_INEXACT - exact && -#endif - fpi->rounding == -#ifdef RND_PRODQUOT - FPI_Round_near -#else - Flt_Rounds -#endif - ) goto trunc; - goto ret; - } - switch(rd) { - case 1: /* round down (toward -Infinity) */ - goto trunc; - case 2: /* round up (toward +Infinity) */ - break; - default: /* round near */ - k = bdif - 1; - if (k < 0) - goto trunc; - if (!k) { - if (!exact) - goto ret; - if (b->x[0] & 2) - break; - goto trunc; - } - if (b->x[k>>kshift] & ((ULong)1 << (k & kmask))) - break; - goto trunc; - } - /* "break" cases: round up 1 bit, then truncate; bdif > 0 */ - carry = 1; - trunc: - inex = lostbits = 0; - if (bdif > 0) { - if ( (lostbits = any_on(b, bdif)) !=0) - inex = STRTOG_Inexlo; - rshift(b, bdif); - if (carry) { - inex = STRTOG_Inexhi; - b = increment(b); - if ( (j = nb & kmask) !=0) - j = ULbits - j; - if (hi0bits(b->x[b->wds - 1]) != j) { - if (!lostbits) - lostbits = b->x[0] & 1; - rshift(b, 1); - e++; - } - } - } - else if (bdif < 0) - b = lshift(b, -bdif); - if (e < fpi->emin) { - k = fpi->emin - e; - e = fpi->emin; - if (k > nb || fpi->sudden_underflow) { - b->wds = inex = 0; - *irv = STRTOG_Underflow | STRTOG_Inexlo; - } - else { - k1 = k - 1; - if (k1 > 0 && !lostbits) - lostbits = any_on(b, k1); - if (!lostbits && !exact) - goto ret; - lostbits |= - carry = b->x[k1>>kshift] & (1 << (k1 & kmask)); - rshift(b, k); - *irv = STRTOG_Denormal; - if (carry) { - b = increment(b); - inex = STRTOG_Inexhi | STRTOG_Underflow; - } - else if (lostbits) - inex = STRTOG_Inexlo | STRTOG_Underflow; - } - } - else if (e > fpi->emax) { - e = fpi->emax + 1; - *irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; -#ifndef NO_ERRNO - errno = ERANGE; -#endif - b->wds = inex = 0; - } - *exp = e; - copybits(bits, nb, b); - *irv |= inex; - rv = 1; - ret: - Bfree(b); - return rv; - } - - static int -#ifdef KR_headers -mantbits(d) U *d; -#else -mantbits(U *d) -#endif -{ - ULong L; -#ifdef VAX - L = word1(d) << 16 | word1(d) >> 16; - if (L) -#else - if ( (L = word1(d)) !=0) -#endif - return P - lo0bits(&L); -#ifdef VAX - L = word0(d) << 16 | word0(d) >> 16 | Exp_msk11; -#else - L = word0(d) | Exp_msk1; -#endif - return P - 32 - lo0bits(&L); - } - - int -strtodg -#ifdef KR_headers - (s00, se, fpi, exp, bits) - CONST char *s00; char **se; FPI *fpi; Long *exp; ULong *bits; -#else - (CONST char *s00, char **se, FPI *fpi, Long *exp, ULong *bits) -#endif -{ - int abe, abits, asub; - int bb0, bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, denorm; - int dsign, e, e1, e2, emin, esign, finished, i, inex, irv; - int j, k, nbits, nd, nd0, nf, nz, nz0, rd, rvbits, rve, rve1, sign; - int sudden_underflow; - CONST char *s, *s0, *s1; - double adj0, tol; - Long L; - U adj, rv; - ULong *b, *be, y, z; - Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0; -#ifdef USE_LOCALE /*{{*/ -#ifdef NO_LOCALE_CACHE - char *decimalpoint = localeconv()->decimal_point; - int dplen = strlen(decimalpoint); -#else - char *decimalpoint; - static char *decimalpoint_cache; - static int dplen; - if (!(s0 = decimalpoint_cache)) { - s0 = localeconv()->decimal_point; - if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) { - strcpy(decimalpoint_cache, s0); - s0 = decimalpoint_cache; - } - dplen = strlen(s0); - } - decimalpoint = (char*)s0; -#endif /*NO_LOCALE_CACHE*/ -#else /*USE_LOCALE}{*/ -#define dplen 1 -#endif /*USE_LOCALE}}*/ - - irv = STRTOG_Zero; - denorm = sign = nz0 = nz = 0; - dval(&rv) = 0.; - rvb = 0; - nbits = fpi->nbits; - for(s = s00;;s++) switch(*s) { - case '-': - sign = 1; - /* no break */ - case '+': - if (*++s) - goto break2; - /* no break */ - case 0: - sign = 0; - irv = STRTOG_NoNumber; - s = s00; - goto ret; - case '\t': - case '\n': - case '\v': - case '\f': - case '\r': - case ' ': - continue; - default: - goto break2; - } - break2: - if (*s == '0') { -#ifndef NO_HEX_FP - switch(s[1]) { - case 'x': - case 'X': - irv = gethex(&s, fpi, exp, &rvb, sign); - if (irv == STRTOG_NoNumber) { - s = s00; - sign = 0; - } - goto ret; - } -#endif - nz0 = 1; - while(*++s == '0') ; - if (!*s) - goto ret; - } - sudden_underflow = fpi->sudden_underflow; - s0 = s; - y = z = 0; - for(decpt = nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) - if (nd < 9) - y = 10*y + c - '0'; - else if (nd < 16) - z = 10*z + c - '0'; - nd0 = nd; -#ifdef USE_LOCALE - if (c == *decimalpoint) { - for(i = 1; decimalpoint[i]; ++i) - if (s[i] != decimalpoint[i]) - goto dig_done; - s += i; - c = *s; -#else - if (c == '.') { - c = *++s; -#endif - decpt = 1; - if (!nd) { - for(; c == '0'; c = *++s) - nz++; - if (c > '0' && c <= '9') { - s0 = s; - nf += nz; - nz = 0; - goto have_dig; - } - goto dig_done; - } - for(; c >= '0' && c <= '9'; c = *++s) { - have_dig: - nz++; - if (c -= '0') { - nf += nz; - for(i = 1; i < nz; i++) - if (nd++ < 9) - y *= 10; - else if (nd <= DBL_DIG + 1) - z *= 10; - if (nd++ < 9) - y = 10*y + c; - else if (nd <= DBL_DIG + 1) - z = 10*z + c; - nz = 0; - } - } - }/*}*/ - dig_done: - e = 0; - if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { - irv = STRTOG_NoNumber; - s = s00; - goto ret; - } - s00 = s; - esign = 0; - switch(c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; - } - if (c >= '0' && c <= '9') { - while(c == '0') - c = *++s; - if (c > '0' && c <= '9') { - L = c - '0'; - s1 = s; - while((c = *++s) >= '0' && c <= '9') - L = 10*L + c - '0'; - if (s - s1 > 8 || L > 19999) - /* Avoid confusion from exponents - * so large that e might overflow. - */ - e = 19999; /* safe for 16 bit ints */ - else - e = (int)L; - if (esign) - e = -e; - } - else - e = 0; - } - else - s = s00; - } - if (!nd) { - if (!nz && !nz0) { -#ifdef INFNAN_CHECK - /* Check for Nan and Infinity */ - if (!decpt) - switch(c) { - case 'i': - case 'I': - if (match(&s,"nf")) { - --s; - if (!match(&s,"inity")) - ++s; - irv = STRTOG_Infinite; - goto infnanexp; - } - break; - case 'n': - case 'N': - if (match(&s, "an")) { - irv = STRTOG_NaN; - *exp = fpi->emax + 1; -#ifndef No_Hex_NaN - if (*s == '(') /*)*/ - irv = hexnan(&s, fpi, bits); -#endif - goto infnanexp; - } - } -#endif /* INFNAN_CHECK */ - irv = STRTOG_NoNumber; - s = s00; - } - goto ret; - } - - irv = STRTOG_Normal; - e1 = e -= nf; - rd = 0; - switch(fpi->rounding & 3) { - case FPI_Round_up: - rd = 2 - sign; - break; - case FPI_Round_zero: - rd = 1; - break; - case FPI_Round_down: - rd = 1 + sign; - } - - /* Now we have nd0 digits, starting at s0, followed by a - * decimal point, followed by nd-nd0 digits. The number we're - * after is the integer represented by those digits times - * 10**e */ - - if (!nd0) - nd0 = nd; - k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; - dval(&rv) = y; - if (k > 9) - dval(&rv) = tens[k - 9] * dval(&rv) + z; - bd0 = 0; - if (nbits <= P && nd <= DBL_DIG) { - if (!e) { - if (rvOK(&rv, fpi, exp, bits, 1, rd, &irv)) - goto ret; - } - else if (e > 0) { - if (e <= Ten_pmax) { -#ifdef VAX - goto vax_ovfl_check; -#else - i = fivesbits[e] + mantbits(&rv) <= P; - /* rv = */ rounded_product(dval(&rv), tens[e]); - if (rvOK(&rv, fpi, exp, bits, i, rd, &irv)) - goto ret; - e1 -= e; - goto rv_notOK; -#endif - } - i = DBL_DIG - nd; - if (e <= Ten_pmax + i) { - /* A fancier test would sometimes let us do - * this for larger i values. - */ - e2 = e - i; - e1 -= i; - dval(&rv) *= tens[i]; -#ifdef VAX - /* VAX exponent range is so narrow we must - * worry about overflow here... - */ - vax_ovfl_check: - dval(&adj) = dval(&rv); - word0(&adj) -= P*Exp_msk1; - /* adj = */ rounded_product(dval(&adj), tens[e2]); - if ((word0(&adj) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) - goto rv_notOK; - word0(&adj) += P*Exp_msk1; - dval(&rv) = dval(&adj); -#else - /* rv = */ rounded_product(dval(&rv), tens[e2]); -#endif - if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv)) - goto ret; - e1 -= e2; - } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { - /* rv = */ rounded_quotient(dval(&rv), tens[-e]); - if (rvOK(&rv, fpi, exp, bits, 0, rd, &irv)) - goto ret; - e1 -= e; - } -#endif - } - rv_notOK: - e1 += nd - k; - - /* Get starting approximation = rv * 10**e1 */ - - e2 = 0; - if (e1 > 0) { - if ( (i = e1 & 15) !=0) - dval(&rv) *= tens[i]; - if (e1 &= ~15) { - e1 >>= 4; - while(e1 >= (1 << (n_bigtens-1))) { - e2 += ((word0(&rv) & Exp_mask) - >> Exp_shift1) - Bias; - word0(&rv) &= ~Exp_mask; - word0(&rv) |= Bias << Exp_shift1; - dval(&rv) *= bigtens[n_bigtens-1]; - e1 -= 1 << (n_bigtens-1); - } - e2 += ((word0(&rv) & Exp_mask) >> Exp_shift1) - Bias; - word0(&rv) &= ~Exp_mask; - word0(&rv) |= Bias << Exp_shift1; - for(j = 0; e1 > 0; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= bigtens[j]; - } - } - else if (e1 < 0) { - e1 = -e1; - if ( (i = e1 & 15) !=0) - dval(&rv) /= tens[i]; - if (e1 &= ~15) { - e1 >>= 4; - while(e1 >= (1 << (n_bigtens-1))) { - e2 += ((word0(&rv) & Exp_mask) - >> Exp_shift1) - Bias; - word0(&rv) &= ~Exp_mask; - word0(&rv) |= Bias << Exp_shift1; - dval(&rv) *= tinytens[n_bigtens-1]; - e1 -= 1 << (n_bigtens-1); - } - e2 += ((word0(&rv) & Exp_mask) >> Exp_shift1) - Bias; - word0(&rv) &= ~Exp_mask; - word0(&rv) |= Bias << Exp_shift1; - for(j = 0; e1 > 0; j++, e1 >>= 1) - if (e1 & 1) - dval(&rv) *= tinytens[j]; - } - } -#ifdef IBM - /* e2 is a correction to the (base 2) exponent of the return - * value, reflecting adjustments above to avoid overflow in the - * native arithmetic. For native IBM (base 16) arithmetic, we - * must multiply e2 by 4 to change from base 16 to 2. - */ - e2 <<= 2; -#endif - rvb = d2b(dval(&rv), &rve, &rvbits); /* rv = rvb * 2^rve */ - rve += e2; - if ((j = rvbits - nbits) > 0) { - rshift(rvb, j); - rvbits = nbits; - rve += j; - } - bb0 = 0; /* trailing zero bits in rvb */ - e2 = rve + rvbits - nbits; - if (e2 > fpi->emax + 1) - goto huge; - rve1 = rve + rvbits - nbits; - if (e2 < (emin = fpi->emin)) { - denorm = 1; - j = rve - emin; - if (j > 0) { - rvb = lshift(rvb, j); - rvbits += j; - } - else if (j < 0) { - rvbits += j; - if (rvbits <= 0) { - if (rvbits < -1) { - ufl: - rvb->wds = 0; - rvb->x[0] = 0; - *exp = emin; - irv = STRTOG_Underflow | STRTOG_Inexlo; - goto ret; - } - rvb->x[0] = rvb->wds = rvbits = 1; - } - else - rshift(rvb, -j); - } - rve = rve1 = emin; - if (sudden_underflow && e2 + 1 < emin) - goto ufl; - } - - /* Now the hard part -- adjusting rv to the correct value.*/ - - /* Put digits into bd: true value = bd * 10^e */ - - bd0 = s2b(s0, nd0, nd, y, dplen); - - for(;;) { - bd = Balloc(bd0->k); - Bcopy(bd, bd0); - bb = Balloc(rvb->k); - Bcopy(bb, rvb); - bbbits = rvbits - bb0; - bbe = rve + bb0; - bs = i2b(1); - - if (e >= 0) { - bb2 = bb5 = 0; - bd2 = bd5 = e; - } - else { - bb2 = bb5 = -e; - bd2 = bd5 = 0; - } - if (bbe >= 0) - bb2 += bbe; - else - bd2 -= bbe; - bs2 = bb2; - j = nbits + 1 - bbbits; - i = bbe + bbbits - nbits; - if (i < emin) /* denormal */ - j += i - emin; - bb2 += j; - bd2 += j; - i = bb2 < bd2 ? bb2 : bd2; - if (i > bs2) - i = bs2; - if (i > 0) { - bb2 -= i; - bd2 -= i; - bs2 -= i; - } - if (bb5 > 0) { - bs = pow5mult(bs, bb5); - bb1 = mult(bs, bb); - Bfree(bb); - bb = bb1; - } - bb2 -= bb0; - if (bb2 > 0) - bb = lshift(bb, bb2); - else if (bb2 < 0) - rshift(bb, -bb2); - if (bd5 > 0) - bd = pow5mult(bd, bd5); - if (bd2 > 0) - bd = lshift(bd, bd2); - if (bs2 > 0) - bs = lshift(bs, bs2); - asub = 1; - inex = STRTOG_Inexhi; - delta = diff(bb, bd); - if (delta->wds <= 1 && !delta->x[0]) - break; - dsign = delta->sign; - delta->sign = finished = 0; - L = 0; - i = cmp(delta, bs); - if (rd && i <= 0) { - irv = STRTOG_Normal; - if ( (finished = dsign ^ (rd&1)) !=0) { - if (dsign != 0) { - irv |= STRTOG_Inexhi; - goto adj1; - } - irv |= STRTOG_Inexlo; - if (rve1 == emin) - goto adj1; - for(i = 0, j = nbits; j >= ULbits; - i++, j -= ULbits) { - if (rvb->x[i] & ALL_ON) - goto adj1; - } - if (j > 1 && lo0bits(rvb->x + i) < j - 1) - goto adj1; - rve = rve1 - 1; - rvb = set_ones(rvb, rvbits = nbits); - break; - } - irv |= dsign ? STRTOG_Inexlo : STRTOG_Inexhi; - break; - } - if (i < 0) { - /* Error is less than half an ulp -- check for - * special case of mantissa a power of two. - */ - irv = dsign - ? STRTOG_Normal | STRTOG_Inexlo - : STRTOG_Normal | STRTOG_Inexhi; - if (dsign || bbbits > 1 || denorm || rve1 == emin) - break; - delta = lshift(delta,1); - if (cmp(delta, bs) > 0) { - irv = STRTOG_Normal | STRTOG_Inexlo; - goto drop_down; - } - break; - } - if (i == 0) { - /* exactly half-way between */ - if (dsign) { - if (denorm && all_on(rvb, rvbits)) { - /*boundary case -- increment exponent*/ - rvb->wds = 1; - rvb->x[0] = 1; - rve = emin + nbits - (rvbits = 1); - irv = STRTOG_Normal | STRTOG_Inexhi; - denorm = 0; - break; - } - irv = STRTOG_Normal | STRTOG_Inexlo; - } - else if (bbbits == 1) { - irv = STRTOG_Normal; - drop_down: - /* boundary case -- decrement exponent */ - if (rve1 == emin) { - irv = STRTOG_Normal | STRTOG_Inexhi; - if (rvb->wds == 1 && rvb->x[0] == 1) - sudden_underflow = 1; - break; - } - rve -= nbits; - rvb = set_ones(rvb, rvbits = nbits); - break; - } - else - irv = STRTOG_Normal | STRTOG_Inexhi; - if ((bbbits < nbits && !denorm) || !(rvb->x[0] & 1)) - break; - if (dsign) { - rvb = increment(rvb); - j = kmask & (ULbits - (rvbits & kmask)); - if (hi0bits(rvb->x[rvb->wds - 1]) != j) - rvbits++; - irv = STRTOG_Normal | STRTOG_Inexhi; - } - else { - if (bbbits == 1) - goto undfl; - decrement(rvb); - irv = STRTOG_Normal | STRTOG_Inexlo; - } - break; - } - if ((dval(&adj) = ratio(delta, bs)) <= 2.) { - adj1: - inex = STRTOG_Inexlo; - if (dsign) { - asub = 0; - inex = STRTOG_Inexhi; - } - else if (denorm && bbbits <= 1) { - undfl: - rvb->wds = 0; - rve = emin; - irv = STRTOG_Underflow | STRTOG_Inexlo; - break; - } - adj0 = dval(&adj) = 1.; - } - else { - adj0 = dval(&adj) *= 0.5; - if (dsign) { - asub = 0; - inex = STRTOG_Inexlo; - } - if (dval(&adj) < 2147483647.) { - L = (Long)adj0; - adj0 -= L; - switch(rd) { - case 0: - if (adj0 >= .5) - goto inc_L; - break; - case 1: - if (asub && adj0 > 0.) - goto inc_L; - break; - case 2: - if (!asub && adj0 > 0.) { - inc_L: - L++; - inex = STRTOG_Inexact - inex; - } - } - dval(&adj) = L; - } - } - y = rve + rvbits; - - /* adj *= ulp(dval(&rv)); */ - /* if (asub) rv -= adj; else rv += adj; */ - - if (!denorm && rvbits < nbits) { - rvb = lshift(rvb, j = nbits - rvbits); - rve -= j; - rvbits = nbits; - } - ab = d2b(dval(&adj), &abe, &abits); - if (abe < 0) - rshift(ab, -abe); - else if (abe > 0) - ab = lshift(ab, abe); - rvb0 = rvb; - if (asub) { - /* rv -= adj; */ - j = hi0bits(rvb->x[rvb->wds-1]); - rvb = diff(rvb, ab); - k = rvb0->wds - 1; - if (denorm) - /* do nothing */; - else if (rvb->wds <= k - || hi0bits( rvb->x[k]) > - hi0bits(rvb0->x[k])) { - /* unlikely; can only have lost 1 high bit */ - if (rve1 == emin) { - --rvbits; - denorm = 1; - } - else { - rvb = lshift(rvb, 1); - --rve; - --rve1; - L = finished = 0; - } - } - } - else { - rvb = sum(rvb, ab); - k = rvb->wds - 1; - if (k >= rvb0->wds - || hi0bits(rvb->x[k]) < hi0bits(rvb0->x[k])) { - if (denorm) { - if (++rvbits == nbits) - denorm = 0; - } - else { - rshift(rvb, 1); - rve++; - rve1++; - L = 0; - } - } - } - Bfree(ab); - Bfree(rvb0); - if (finished) - break; - - z = rve + rvbits; - if (y == z && L) { - /* Can we stop now? */ - tol = dval(&adj) * 5e-16; /* > max rel error */ - dval(&adj) = adj0 - .5; - if (dval(&adj) < -tol) { - if (adj0 > tol) { - irv |= inex; - break; - } - } - else if (dval(&adj) > tol && adj0 < 1. - tol) { - irv |= inex; - break; - } - } - bb0 = denorm ? 0 : trailz(rvb); - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(delta); - } - if (!denorm && (j = nbits - rvbits)) { - if (j > 0) - rvb = lshift(rvb, j); - else - rshift(rvb, -j); - rve -= j; - } - *exp = rve; - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); - if (rve > fpi->emax) { - switch(fpi->rounding & 3) { - case FPI_Round_near: - goto huge; - case FPI_Round_up: - if (!sign) - goto huge; - break; - case FPI_Round_down: - if (sign) - goto huge; - } - /* Round to largest representable magnitude */ - Bfree(rvb); - rvb = 0; - irv = STRTOG_Normal | STRTOG_Inexlo; - *exp = fpi->emax; - b = bits; - be = b + ((fpi->nbits + 31) >> 5); - while(b < be) - *b++ = -1; - if ((j = fpi->nbits & 0x1f)) - *--be >>= (32 - j); - goto ret; - huge: - rvb->wds = 0; - irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; -#ifndef NO_ERRNO - errno = ERANGE; -#endif - infnanexp: - *exp = fpi->emax + 1; - } - ret: - if (denorm) { - if (sudden_underflow) { - rvb->wds = 0; - irv = STRTOG_Underflow | STRTOG_Inexlo; -#ifndef NO_ERRNO - errno = ERANGE; -#endif - } - else { - irv = (irv & ~STRTOG_Retmask) | - (rvb->wds > 0 ? STRTOG_Denormal : STRTOG_Zero); - if (irv & STRTOG_Inexact) { - irv |= STRTOG_Underflow; -#ifndef NO_ERRNO - errno = ERANGE; -#endif - } - } - } - if (se) - *se = (char *)s; - if (sign) - irv |= STRTOG_Neg; - if (rvb) { - copybits(bits, nbits, rvb); - Bfree(rvb); - } - return irv; - } diff --git a/libraries/gdtoa/strtodnrp.c b/libraries/gdtoa/strtodnrp.c deleted file mode 100644 index 19a769f0b..000000000 --- a/libraries/gdtoa/strtodnrp.c +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 2004 by David M. Gay. -All Rights Reserved -Based on material in the rest of /netlib/fp/gdota.tar.gz, -which is copyright (C) 1998, 2000 by Lucent Technologies. - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* This is a variant of strtod that works on Intel ia32 systems */ -/* with the default extended-precision arithmetic -- it does not */ -/* require setting the precision control to 53 bits. */ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - double -#ifdef KR_headers -strtod(s, sp) CONST char *s; char **sp; -#else -strtod(CONST char *s, char **sp) -#endif -{ - static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - ULong bits[2]; - Long exp; - int k; - union { ULong L[2]; double d; } u; - - k = strtodg(s, sp, &fpi, &exp, bits); - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - u.L[0] = u.L[1] = 0; - break; - - case STRTOG_Normal: - u.L[_1] = bits[0]; - u.L[_0] = (bits[1] & ~0x100000) | ((exp + 0x3ff + 52) << 20); - break; - - case STRTOG_Denormal: - u.L[_1] = bits[0]; - u.L[_0] = bits[1]; - break; - - case STRTOG_Infinite: - u.L[_0] = 0x7ff00000; - u.L[_1] = 0; - break; - - case STRTOG_NaN: - u.L[0] = d_QNAN0; - u.L[1] = d_QNAN1; - break; - - case STRTOG_NaNbits: - u.L[_0] = 0x7ff00000 | bits[1]; - u.L[_1] = bits[0]; - } - if (k & STRTOG_Neg) - u.L[_0] |= 0x80000000L; - return u.d; - } diff --git a/libraries/gdtoa/strtof.c b/libraries/gdtoa/strtof.c deleted file mode 100644 index a8beb3520..000000000 --- a/libraries/gdtoa/strtof.c +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - float -#ifdef KR_headers -strtof(s, sp) CONST char *s; char **sp; -#else -strtof(CONST char *s, char **sp) -#endif -{ - static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI }; - ULong bits[1]; - Long exp; - int k; - union { ULong L[1]; float f; } u; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - u.L[0] = 0; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - u.L[0] = (bits[0] & 0x7fffff) | ((exp + 0x7f + 23) << 23); - break; - - case STRTOG_Denormal: - u.L[0] = bits[0]; - break; - - case STRTOG_Infinite: - u.L[0] = 0x7f800000; - break; - - case STRTOG_NaN: - u.L[0] = f_QNAN; - } - if (k & STRTOG_Neg) - u.L[0] |= 0x80000000L; - return u.f; - } diff --git a/libraries/gdtoa/strtopQ.c b/libraries/gdtoa/strtopQ.c deleted file mode 100644 index 2acf7e910..000000000 --- a/libraries/gdtoa/strtopQ.c +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#endif -#ifdef IEEE_8087 -#define _0 3 -#define _1 2 -#define _2 1 -#define _3 0 -#endif - - extern ULong NanDflt_Q_D2A[4]; - - - int -#ifdef KR_headers -strtopQ(s, sp, V) CONST char *s; char **sp; void *V; -#else -strtopQ(CONST char *s, char **sp, void *V) -#endif -{ - static FPI fpi0 = { 113, 1-16383-113+1, 32766 - 16383 - 113 + 1, 1, SI }; - ULong bits[4]; - Long exp; - int k; - ULong *L = (ULong*)V; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = L[3] = 0; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[_3] = bits[0]; - L[_2] = bits[1]; - L[_1] = bits[2]; - L[_0] = (bits[3] & ~0x10000) | ((exp + 0x3fff + 112) << 16); - break; - - case STRTOG_Denormal: - L[_3] = bits[0]; - L[_2] = bits[1]; - L[_1] = bits[2]; - L[_0] = bits[3]; - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff0000; - L[_1] = L[_2] = L[_3] = 0; - break; - - case STRTOG_NaN: - L[_0] = NanDflt_Q_D2A[3]; - L[_1] = NanDflt_Q_D2A[2]; - L[_2] = NanDflt_Q_D2A[1]; - L[_3] = NanDflt_Q_D2A[0]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x80000000L; - return k; - } diff --git a/libraries/gdtoa/strtopd.c b/libraries/gdtoa/strtopd.c deleted file mode 100644 index 0fb35daea..000000000 --- a/libraries/gdtoa/strtopd.c +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtopd(s, sp, d) char *s; char **sp; double *d; -#else -strtopd(CONST char *s, char **sp, double *d) -#endif -{ - static FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - ULong bits[2]; - Long exp; - int k; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - ULtod((ULong*)d, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtopdd.c b/libraries/gdtoa/strtopdd.c deleted file mode 100644 index 738372d88..000000000 --- a/libraries/gdtoa/strtopdd.c +++ /dev/null @@ -1,183 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtopdd(s, sp, dd) CONST char *s; char **sp; double *dd; -#else -strtopdd(CONST char *s, char **sp, double *dd) -#endif -{ -#ifdef Sudden_Underflow - static FPI fpi0 = { 106, 1-1023, 2046-1023-106+1, 1, 1 }; -#else - static FPI fpi0 = { 106, 1-1023-53+1, 2046-1023-106+1, 1, 0 }; -#endif - ULong bits[4]; - Long exp; - int i, j, rv; - typedef union { - double d[2]; - ULong L[4]; - } U; - U *u; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - rv = strtodg(s, sp, fpi, &exp, bits); - u = (U*)dd; - switch(rv & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - u->d[0] = u->d[1] = 0.; - break; - - case STRTOG_Normal: - u->L[_1] = (bits[1] >> 21 | bits[2] << 11) & 0xffffffffL; - u->L[_0] = (bits[2] >> 21) | ((bits[3] << 11) & 0xfffff) - | ((exp + 0x3ff + 105) << 20); - exp += 0x3ff + 52; - if (bits[1] &= 0x1fffff) { - i = hi0bits(bits[1]) - 11; - if (i >= exp) { - i = exp - 1; - exp = 0; - } - else - exp -= i; - if (i > 0) { - bits[1] = bits[1] << i | bits[0] >> (32-i); - bits[0] = bits[0] << i & 0xffffffffL; - } - } - else if (bits[0]) { - i = hi0bits(bits[0]) + 21; - if (i >= exp) { - i = exp - 1; - exp = 0; - } - else - exp -= i; - if (i < 32) { - bits[1] = bits[0] >> (32 - i); - bits[0] = bits[0] << i & 0xffffffffL; - } - else { - bits[1] = bits[0] << (i - 32); - bits[0] = 0; - } - } - else { - u->L[2] = u->L[3] = 0; - break; - } - u->L[2+_1] = bits[0]; - u->L[2+_0] = (bits[1] & 0xfffff) | (exp << 20); - break; - - case STRTOG_Denormal: - if (bits[3]) - goto nearly_normal; - if (bits[2]) - goto partly_normal; - if (bits[1] & 0xffe00000) - goto hardly_normal; - /* completely denormal */ - u->L[2] = u->L[3] = 0; - u->L[_1] = bits[0]; - u->L[_0] = bits[1]; - break; - - nearly_normal: - i = hi0bits(bits[3]) - 11; /* i >= 12 */ - j = 32 - i; - u->L[_0] = ((bits[3] << i | bits[2] >> j) & 0xfffff) - | ((65 - i) << 20); - u->L[_1] = (bits[2] << i | bits[1] >> j) & 0xffffffffL; - u->L[2+_0] = bits[1] & ((1L << j) - 1); - u->L[2+_1] = bits[0]; - break; - - partly_normal: - i = hi0bits(bits[2]) - 11; - if (i < 0) { - j = -i; - i += 32; - u->L[_0] = (bits[2] >> j & 0xfffff) | (33 + j) << 20; - u->L[_1] = ((bits[2] << i) | (bits[1] >> j)) & 0xffffffffL; - u->L[2+_0] = bits[1] & ((1L << j) - 1); - u->L[2+_1] = bits[0]; - break; - } - if (i == 0) { - u->L[_0] = (bits[2] & 0xfffff) | (33 << 20); - u->L[_1] = bits[1]; - u->L[2+_0] = 0; - u->L[2+_1] = bits[0]; - break; - } - j = 32 - i; - u->L[_0] = (((bits[2] << i) | (bits[1] >> j)) & 0xfffff) - | ((j + 1) << 20); - u->L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL; - u->L[2+_0] = 0; - u->L[2+_1] = bits[0] & ((1L << j) - 1); - break; - - hardly_normal: - j = 11 - hi0bits(bits[1]); - i = 32 - j; - u->L[_0] = (bits[1] >> j & 0xfffff) | ((j + 1) << 20); - u->L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL; - u->L[2+_0] = 0; - u->L[2+_1] = bits[0] & ((1L << j) - 1); - break; - - case STRTOG_Infinite: - u->L[_0] = u->L[2+_0] = 0x7ff00000; - u->L[_1] = u->L[2+_1] = 0; - break; - - case STRTOG_NaN: - u->L[0] = u->L[2] = d_QNAN0; - u->L[1] = u->L[3] = d_QNAN1; - } - if (rv & STRTOG_Neg) { - u->L[ _0] |= 0x80000000L; - u->L[2+_0] |= 0x80000000L; - } - return rv; - } diff --git a/libraries/gdtoa/strtopf.c b/libraries/gdtoa/strtopf.c deleted file mode 100644 index 23ca5cbe5..000000000 --- a/libraries/gdtoa/strtopf.c +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - int -#ifdef KR_headers -strtopf(s, sp, f) CONST char *s; char **sp; float *f; -#else -strtopf(CONST char *s, char **sp, float *f) -#endif -{ - static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI }; - ULong bits[1], *L; - Long exp; - int k; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - L = (ULong*)f; - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = 0; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[0] = (bits[0] & 0x7fffff) | ((exp + 0x7f + 23) << 23); - break; - - case STRTOG_Denormal: - L[0] = bits[0]; - break; - - case STRTOG_Infinite: - L[0] = 0x7f800000; - break; - - case STRTOG_NaN: - L[0] = f_QNAN; - } - if (k & STRTOG_Neg) - L[0] |= 0x80000000L; - return k; - } diff --git a/libraries/gdtoa/strtopx.c b/libraries/gdtoa/strtopx.c deleted file mode 100644 index 32192c572..000000000 --- a/libraries/gdtoa/strtopx.c +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - extern UShort NanDflt_ldus_D2A[5]; - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#define _4 4 -#endif -#ifdef IEEE_8087 -#define _0 4 -#define _1 3 -#define _2 2 -#define _3 1 -#define _4 0 -#endif - - int -#ifdef KR_headers -strtopx(s, sp, V) CONST char *s; char **sp; void *V; -#else -strtopx(CONST char *s, char **sp, void *V) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - ULong bits[2]; - Long exp; - int k; - UShort *L = (UShort*)V; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = L[3] = L[4] = 0; - break; - - case STRTOG_Denormal: - L[_0] = 0; - goto normal_bits; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[_0] = exp + 0x3fff + 63; - normal_bits: - L[_4] = (UShort)bits[0]; - L[_3] = (UShort)(bits[0] >> 16); - L[_2] = (UShort)bits[1]; - L[_1] = (UShort)(bits[1] >> 16); - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff; - L[_1] = 0x8000; - L[_2] = L[_3] = L[_4] = 0; - break; - - case STRTOG_NaN: - L[_4] = NanDflt_ldus_D2A[0]; - L[_3] = NanDflt_ldus_D2A[1]; - L[_2] = NanDflt_ldus_D2A[2]; - L[_1] = NanDflt_ldus_D2A[3]; - L[_0] = NanDflt_ldus_D2A[4]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x8000; - return k; - } diff --git a/libraries/gdtoa/strtopxL.c b/libraries/gdtoa/strtopxL.c deleted file mode 100644 index 6166c1e62..000000000 --- a/libraries/gdtoa/strtopxL.c +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - extern ULong NanDflt_xL_D2A[3]; - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#endif -#ifdef IEEE_8087 -#define _0 2 -#define _1 1 -#define _2 0 -#endif - - int -#ifdef KR_headers -strtopxL(s, sp, V) CONST char *s; char **sp; void *V; -#else -strtopxL(CONST char *s, char **sp, void *V) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - ULong bits[2]; - Long exp; - int k; - ULong *L = (ULong*)V; -#ifdef Honor_FLT_ROUNDS -#include "gdtoa_fltrnds.h" -#else -#define fpi &fpi0 -#endif - - k = strtodg(s, sp, fpi, &exp, bits); - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = 0; - break; - - case STRTOG_Normal: - case STRTOG_Denormal: - case STRTOG_NaNbits: - L[_2] = bits[0]; - L[_1] = bits[1]; - L[_0] = (exp + 0x3fff + 63) << 16; - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff << 16; - L[_1] = 0x80000000; - L[_2] = 0; - break; - - case STRTOG_NaN: - L[_0] = NanDflt_xL_D2A[2]; - L[_1] = NanDflt_xL_D2A[1]; - L[_2] = NanDflt_xL_D2A[0]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x80000000L; - return k; - } diff --git a/libraries/gdtoa/strtorQ.c b/libraries/gdtoa/strtorQ.c deleted file mode 100644 index f5fd7bba9..000000000 --- a/libraries/gdtoa/strtorQ.c +++ /dev/null @@ -1,119 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#endif -#ifdef IEEE_8087 -#define _0 3 -#define _1 2 -#define _2 1 -#define _3 0 -#endif - - extern ULong NanDflt_Q_D2A[4]; - - void -#ifdef KR_headers -ULtoQ(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k; -#else -ULtoQ(ULong *L, ULong *bits, Long exp, int k) -#endif -{ - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = L[3] = 0; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[_3] = bits[0]; - L[_2] = bits[1]; - L[_1] = bits[2]; - L[_0] = (bits[3] & ~0x10000) | ((exp + 0x3fff + 112) << 16); - break; - - case STRTOG_Denormal: - L[_3] = bits[0]; - L[_2] = bits[1]; - L[_1] = bits[2]; - L[_0] = bits[3]; - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff0000; - L[_1] = L[_2] = L[_3] = 0; - break; - - case STRTOG_NaN: - L[_0] = NanDflt_Q_D2A[3]; - L[_1] = NanDflt_Q_D2A[2]; - L[_2] = NanDflt_Q_D2A[1]; - L[_3] = NanDflt_Q_D2A[0]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x80000000L; - } - - int -#ifdef KR_headers -strtorQ(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L; -#else -strtorQ(CONST char *s, char **sp, int rounding, void *L) -#endif -{ - static FPI fpi0 = { 113, 1-16383-113+1, 32766-16383-113+1, 1, SI }; - FPI *fpi, fpi1; - ULong bits[4]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtoQ((ULong*)L, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtord.c b/libraries/gdtoa/strtord.c deleted file mode 100644 index dd0769698..000000000 --- a/libraries/gdtoa/strtord.c +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - extern ULong NanDflt_d_D2A[2]; - - void -#ifdef KR_headers -ULtod(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k; -#else -ULtod(ULong *L, ULong *bits, Long exp, int k) -#endif -{ - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = 0; - break; - - case STRTOG_Denormal: - L[_1] = bits[0]; - L[_0] = bits[1]; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[_1] = bits[0]; - L[_0] = (bits[1] & ~0x100000) | ((exp + 0x3ff + 52) << 20); - break; - - case STRTOG_Infinite: - L[_0] = 0x7ff00000; - L[_1] = 0; - break; - - case STRTOG_NaN: - L[_0] = NanDflt_d_D2A[1]; - L[_1] = NanDflt_d_D2A[0]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x80000000L; - } - - int -#ifdef KR_headers -strtord(s, sp, rounding, d) CONST char *s; char **sp; int rounding; double *d; -#else -strtord(CONST char *s, char **sp, int rounding, double *d) -#endif -{ - static FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; - FPI *fpi, fpi1; - ULong bits[2]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtod((ULong*)d, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtordd.c b/libraries/gdtoa/strtordd.c deleted file mode 100644 index 62152dbd4..000000000 --- a/libraries/gdtoa/strtordd.c +++ /dev/null @@ -1,202 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - extern ULong NanDflt_d_D2A[2]; - - void -#ifdef KR_headers -ULtodd(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k; -#else -ULtodd(ULong *L, ULong *bits, Long exp, int k) -#endif -{ - int i, j; - - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = L[3] = 0; - break; - - case STRTOG_Normal: - L[_1] = (bits[1] >> 21 | bits[2] << 11) & (ULong)0xffffffffL; - L[_0] = (bits[2] >> 21) | (bits[3] << 11 & 0xfffff) - | ((exp + 0x3ff + 105) << 20); - exp += 0x3ff + 52; - if (bits[1] &= 0x1fffff) { - i = hi0bits(bits[1]) - 11; - if (i >= exp) { - i = exp - 1; - exp = 0; - } - else - exp -= i; - if (i > 0) { - bits[1] = bits[1] << i | bits[0] >> (32-i); - bits[0] = bits[0] << i & (ULong)0xffffffffL; - } - } - else if (bits[0]) { - i = hi0bits(bits[0]) + 21; - if (i >= exp) { - i = exp - 1; - exp = 0; - } - else - exp -= i; - if (i < 32) { - bits[1] = bits[0] >> (32 - i); - bits[0] = bits[0] << i & (ULong)0xffffffffL; - } - else { - bits[1] = bits[0] << (i - 32); - bits[0] = 0; - } - } - else { - L[2] = L[3] = 0; - break; - } - L[2+_1] = bits[0]; - L[2+_0] = (bits[1] & 0xfffff) | (exp << 20); - break; - - case STRTOG_Denormal: - if (bits[3]) - goto nearly_normal; - if (bits[2]) - goto partly_normal; - if (bits[1] & 0xffe00000) - goto hardly_normal; - /* completely denormal */ - L[2] = L[3] = 0; - L[_1] = bits[0]; - L[_0] = bits[1]; - break; - - nearly_normal: - i = hi0bits(bits[3]) - 11; /* i >= 12 */ - j = 32 - i; - L[_0] = ((bits[3] << i | bits[2] >> j) & 0xfffff) - | ((65 - i) << 20); - L[_1] = (bits[2] << i | bits[1] >> j) & 0xffffffffL; - L[2+_0] = bits[1] & (((ULong)1L << j) - 1); - L[2+_1] = bits[0]; - break; - - partly_normal: - i = hi0bits(bits[2]) - 11; - if (i < 0) { - j = -i; - i += 32; - L[_0] = (bits[2] >> j & 0xfffff) | ((33 + j) << 20); - L[_1] = (bits[2] << i | bits[1] >> j) & 0xffffffffL; - L[2+_0] = bits[1] & (((ULong)1L << j) - 1); - L[2+_1] = bits[0]; - break; - } - if (i == 0) { - L[_0] = (bits[2] & 0xfffff) | (33 << 20); - L[_1] = bits[1]; - L[2+_0] = 0; - L[2+_1] = bits[0]; - break; - } - j = 32 - i; - L[_0] = (((bits[2] << i) | (bits[1] >> j)) & 0xfffff) - | ((j + 1) << 20); - L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL; - L[2+_0] = 0; - L[2+_1] = bits[0] & ((1L << j) - 1); - break; - - hardly_normal: - j = 11 - hi0bits(bits[1]); - i = 32 - j; - L[_0] = (bits[1] >> j & 0xfffff) | ((j + 1) << 20); - L[_1] = (bits[1] << i | bits[0] >> j) & 0xffffffffL; - L[2+_0] = 0; - L[2+_1] = bits[0] & (((ULong)1L << j) - 1); - break; - - case STRTOG_Infinite: - L[_0] = L[2+_0] = 0x7ff00000; - L[_1] = L[2+_1] = 0; - break; - - case STRTOG_NaN: - L[_0] = L[_0+2] = NanDflt_d_D2A[1]; - L[_1] = L[_1+2] = NanDflt_d_D2A[0]; - break; - - case STRTOG_NaNbits: - L[_1] = (bits[1] >> 20 | bits[2] << 12) & (ULong)0xffffffffL; - L[_0] = bits[2] >> 20 | bits[3] << 12; - L[_0] |= (L[_1] | L[_0]) ? (ULong)0x7ff00000L : (ULong)0x7ff80000L; - L[2+_1] = bits[0] & (ULong)0xffffffffL; - L[2+_0] = bits[1] & 0xfffffL; - L[2+_0] |= (L[2+_1] | L[2+_0]) ? (ULong)0x7ff00000L : (ULong)0x7ff80000L; - } - if (k & STRTOG_Neg) { - L[_0] |= 0x80000000L; - L[2+_0] |= 0x80000000L; - } - } - - int -#ifdef KR_headers -strtordd(s, sp, rounding, dd) CONST char *s; char **sp; int rounding; double *dd; -#else -strtordd(CONST char *s, char **sp, int rounding, double *dd) -#endif -{ -#ifdef Sudden_Underflow - static FPI fpi0 = { 106, 1-1023, 2046-1023-106+1, 1, 1 }; -#else - static FPI fpi0 = { 106, 1-1023-53+1, 2046-1023-106+1, 1, 0 }; -#endif - FPI *fpi, fpi1; - ULong bits[4]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtodd((ULong*)dd, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtorf.c b/libraries/gdtoa/strtorf.c deleted file mode 100644 index 99b4ab710..000000000 --- a/libraries/gdtoa/strtorf.c +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - extern ULong NanDflt_f_D2A[1]; - - void -#ifdef KR_headers -ULtof(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k; -#else -ULtof(ULong *L, ULong *bits, Long exp, int k) -#endif -{ - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - *L = 0; - break; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[0] = (bits[0] & 0x7fffff) | ((exp + 0x7f + 23) << 23); - break; - - case STRTOG_Denormal: - L[0] = bits[0]; - break; - - case STRTOG_Infinite: - L[0] = 0x7f800000; - break; - - case STRTOG_NaN: - L[0] = NanDflt_f_D2A[0]; - } - if (k & STRTOG_Neg) - L[0] |= 0x80000000L; - } - - int -#ifdef KR_headers -strtorf(s, sp, rounding, f) CONST char *s; char **sp; int rounding; float *f; -#else -strtorf(CONST char *s, char **sp, int rounding, float *f) -#endif -{ - static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI }; - FPI *fpi, fpi1; - ULong bits[1]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtof((ULong*)f, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtorx.c b/libraries/gdtoa/strtorx.c deleted file mode 100644 index 994ce8e63..000000000 --- a/libraries/gdtoa/strtorx.c +++ /dev/null @@ -1,122 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#define _3 3 -#define _4 4 -#endif -#ifdef IEEE_8087 -#define _0 4 -#define _1 3 -#define _2 2 -#define _3 1 -#define _4 0 -#endif - - extern UShort NanDflt_ldus_D2A[5]; - - void -#ifdef KR_headers -ULtox(L, bits, exp, k) UShort *L; ULong *bits; Long exp; int k; -#else -ULtox(UShort *L, ULong *bits, Long exp, int k) -#endif -{ - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = L[3] = L[4] = 0; - break; - - case STRTOG_Denormal: - L[_0] = 0; - goto normal_bits; - - case STRTOG_Normal: - case STRTOG_NaNbits: - L[_0] = exp + 0x3fff + 63; - normal_bits: - L[_4] = (UShort)bits[0]; - L[_3] = (UShort)(bits[0] >> 16); - L[_2] = (UShort)bits[1]; - L[_1] = (UShort)(bits[1] >> 16); - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff; - L[_1] = 0x8000; - L[_2] = L[_3] = L[_4] = 0; - break; - - case STRTOG_NaN: - L[_4] = NanDflt_ldus_D2A[0]; - L[_3] = NanDflt_ldus_D2A[1]; - L[_2] = NanDflt_ldus_D2A[2]; - L[_1] = NanDflt_ldus_D2A[3]; - L[_0] = NanDflt_ldus_D2A[4]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x8000; - } - - int -#ifdef KR_headers -strtorx(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L; -#else -strtorx(CONST char *s, char **sp, int rounding, void *L) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - FPI *fpi, fpi1; - ULong bits[2]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtox((UShort*)L, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/strtorxL.c b/libraries/gdtoa/strtorxL.c deleted file mode 100644 index bac4a0bb1..000000000 --- a/libraries/gdtoa/strtorxL.c +++ /dev/null @@ -1,110 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 2000 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - -#undef _0 -#undef _1 - -/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */ - -#ifdef IEEE_MC68k -#define _0 0 -#define _1 1 -#define _2 2 -#endif -#ifdef IEEE_8087 -#define _0 2 -#define _1 1 -#define _2 0 -#endif - - extern ULong NanDflt_xL_D2A[3]; - - void -#ifdef KR_headers -ULtoxL(L, bits, exp, k) ULong *L; ULong *bits; Long exp; int k; -#else -ULtoxL(ULong *L, ULong *bits, Long exp, int k) -#endif -{ - switch(k & STRTOG_Retmask) { - case STRTOG_NoNumber: - case STRTOG_Zero: - L[0] = L[1] = L[2] = 0; - break; - - case STRTOG_Normal: - case STRTOG_Denormal: - case STRTOG_NaNbits: - L[_0] = (exp + 0x3fff + 63) << 16; - L[_1] = bits[1]; - L[_2] = bits[0]; - break; - - case STRTOG_Infinite: - L[_0] = 0x7fff0000; - L[_1] = 0x80000000; - L[_2] = 0; - break; - - case STRTOG_NaN: - L[_0] = NanDflt_xL_D2A[2]; - L[_1] = NanDflt_xL_D2A[1]; - L[_2] = NanDflt_xL_D2A[0]; - } - if (k & STRTOG_Neg) - L[_0] |= 0x80000000L; - } - - int -#ifdef KR_headers -strtorxL(s, sp, rounding, L) CONST char *s; char **sp; int rounding; void *L; -#else -strtorxL(CONST char *s, char **sp, int rounding, void *L) -#endif -{ - static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI }; - FPI *fpi, fpi1; - ULong bits[2]; - Long exp; - int k; - - fpi = &fpi0; - if (rounding != FPI_Round_near) { - fpi1 = fpi0; - fpi1.rounding = rounding; - fpi = &fpi1; - } - k = strtodg(s, sp, fpi, &exp, bits); - ULtoxL((ULong*)L, bits, exp, k); - return k; - } diff --git a/libraries/gdtoa/sum.c b/libraries/gdtoa/sum.c deleted file mode 100644 index dc0c88bcf..000000000 --- a/libraries/gdtoa/sum.c +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - Bigint * -#ifdef KR_headers -sum(a, b) Bigint *a; Bigint *b; -#else -sum(Bigint *a, Bigint *b) -#endif -{ - Bigint *c; - ULong carry, *xc, *xa, *xb, *xe, y; -#ifdef Pack_32 - ULong z; -#endif - - if (a->wds < b->wds) { - c = b; b = a; a = c; - } - c = Balloc(a->k); - c->wds = a->wds; - carry = 0; - xa = a->x; - xb = b->x; - xc = c->x; - xe = xc + b->wds; -#ifdef Pack_32 - do { - y = (*xa & 0xffff) + (*xb & 0xffff) + carry; - carry = (y & 0x10000) >> 16; - z = (*xa++ >> 16) + (*xb++ >> 16) + carry; - carry = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } - while(xc < xe); - xe += a->wds - b->wds; - while(xc < xe) { - y = (*xa & 0xffff) + carry; - carry = (y & 0x10000) >> 16; - z = (*xa++ >> 16) + carry; - carry = (z & 0x10000) >> 16; - Storeinc(xc, z, y); - } -#else - do { - y = *xa++ + *xb++ + carry; - carry = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } - while(xc < xe); - xe += a->wds - b->wds; - while(xc < xe) { - y = *xa++ + carry; - carry = (y & 0x10000) >> 16; - *xc++ = y & 0xffff; - } -#endif - if (carry) { - if (c->wds == c->maxwds) { - b = Balloc(c->k + 1); - Bcopy(b, c); - Bfree(c); - c = b; - } - c->x[c->wds++] = 1; - } - return c; - } diff --git a/libraries/gdtoa/ulp.c b/libraries/gdtoa/ulp.c deleted file mode 100644 index 17e9f862c..000000000 --- a/libraries/gdtoa/ulp.c +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************** - -The author of this software is David M. Gay. - -Copyright (C) 1998, 1999 by Lucent Technologies -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name of Lucent or any of its entities -not be used in advertising or publicity pertaining to -distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. - -****************************************************************/ - -/* Please send bug reports to David M. Gay (dmg at acm dot org, - * with " at " changed at "@" and " dot " changed to "."). */ - -#include "gdtoaimp.h" - - double -ulp -#ifdef KR_headers - (x) U *x; -#else - (U *x) -#endif -{ - Long L; - U a; - - L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1; -#ifndef Sudden_Underflow - if (L > 0) { -#endif -#ifdef IBM - L |= Exp_msk1 >> 4; -#endif - word0(&a) = L; - word1(&a) = 0; -#ifndef Sudden_Underflow - } - else { - L = -L >> Exp_shift; - if (L < Exp_shift) { - word0(&a) = 0x80000 >> L; - word1(&a) = 0; - } - else { - word0(&a) = 0; - L -= Exp_shift; - word1(&a) = L >= 31 ? 1 : 1 << (31 - L); - } - } -#endif - return dval(&a); - } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 15ce6ea25..ed4244f88 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required( VERSION 3.1.0 ) +cmake_minimum_required( VERSION 3.16.0 ) include(precompiled_headers) @@ -97,7 +97,7 @@ else() if( NOT DYN_GTK ) set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} ${GTK3_LIBRARIES} ) endif() - include_directories( ${GTK3_INCLUDE_DIRS} ) + include_directories( SYSTEM ${GTK3_INCLUDE_DIRS} ) link_directories( ${GTK3_LIBRARY_DIRS} ) else() pkg_check_modules( GTK2 gtk+-2.0 ) @@ -105,7 +105,7 @@ else() if( NOT DYN_GTK ) set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} ${GTK2_LIBRARIES} ) endif() - include_directories( ${GTK2_INCLUDE_DIRS} ) + include_directories( SYSTEM ${GTK2_INCLUDE_DIRS} ) link_directories( ${GTK2_LIBRARY_DIRS} ) else() set( NO_GTK ON ) @@ -132,7 +132,7 @@ else() # Non-Windows version also needs SDL except native OS X backend if( NOT APPLE OR NOT OSX_COCOA_BACKEND ) find_package( SDL2 REQUIRED ) - include_directories( "${SDL2_INCLUDE_DIR}" ) + include_directories( SYSTEM "${SDL2_INCLUDE_DIR}" ) set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} "${SDL2_LIBRARY}" ) endif() @@ -143,7 +143,7 @@ if( NOT NO_OPENAL ) find_package( OpenAL ) mark_as_advanced(CLEAR OPENAL_INCLUDE_DIR) if( OPENAL_INCLUDE_DIR ) - include_directories( ${OPENAL_INCLUDE_DIR} ) + include_directories( SYSTEM ${OPENAL_INCLUDE_DIR} ) mark_as_advanced(CLEAR OPENAL_LIBRARY) if( OPENAL_LIBRARY ) set( PROJECT_LIBRARIES ${OPENAL_LIBRARY} ${PROJECT_LIBRARIES} ) @@ -278,10 +278,7 @@ endif() # Check for thread_local keyword, it's optional at the moment -CHECK_CXX_SOURCE_COMPILES("thread_local int i; int main() { i = 0; }" - HAVE_THREAD_LOCAL) - -if( NOT HAVE_THREAD_LOCAL ) +if ( NOT (cxx_thread_local IN_LIST CMAKE_CXX_COMPILE_FEATURES) ) message( SEND_ERROR "C++ compiler doesn't support thread_local storage duration specifier" ) endif() @@ -373,17 +370,17 @@ endif() if( VPX_FOUND ) add_definitions( "-DUSE_LIBVPX=1" ) - include_directories( "${VPX_INCLUDE_DIR}" ) + include_directories( SYSTEM "${VPX_INCLUDE_DIR}" ) set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} ${VPX_LIBRARIES} ) else() message( SEND_ERROR "Could not find libvpx" ) endif() -include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${ZMUSIC_INCLUDE_DIR}" "${DRPC_INCLUDE_DIR}") +include_directories( SYSTEM "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" "${JPEG_INCLUDE_DIR}" "${ZMUSIC_INCLUDE_DIR}" "${DRPC_INCLUDE_DIR}") if( ${HAVE_VM_JIT} ) add_definitions( -DHAVE_VM_JIT ) - include_directories( "${ASMJIT_INCLUDE_DIR}" ) + include_directories( SYSTEM "${ASMJIT_INCLUDE_DIR}" ) set( PROJECT_LIBRARIES ${PROJECT_LIBRARIES} "${ASMJIT_LIBRARIES}") endif() @@ -407,7 +404,7 @@ set( PLAT_WIN32_SOURCES ) if (HAVE_VULKAN) - set (PLAT_WIN32_SOURCES ${PLAT_WIN32_SOURCES} common/platform/win32/win32vulkanvideo.cpp ) + list (APPEND PLAT_WIN32_SOURCES common/platform/win32/win32vulkanvideo.cpp ) endif() # todo: implement an actual crash catcher for ARM @@ -698,10 +695,6 @@ set( VM_JIT_SOURCES common/scripting/jit/jit_store.cpp ) -# This is disabled for now because I cannot find a way to give the .pch file a different name. -# Visual C++ 2015 seems hell-bent on only allowing one .pch file with the same name as the executable. -#enable_precompiled_headers( g_pch2.h FASTMATH_PCH_SOURCES ) - # Enable fast math for some sources set( FASTMATH_SOURCES rendering/swrenderer/r_all.cpp @@ -760,7 +753,7 @@ set (VULKAN_SOURCES ) if (HAVE_VULKAN) - set (FASTMATH_SOURCES ${FASTMATH_SOURCES} ${VULKAN_SOURCES}) + list (APPEND FASTMATH_SOURCES ${VULKAN_SOURCES}) endif() set (FASTMATH_SOURCES ${FASTMATH_SOURCES}) @@ -1016,6 +1009,7 @@ set (PCH_SOURCES common/textures/formats/stbtexture.cpp common/textures/formats/anmtexture.cpp common/textures/formats/startscreentexture.cpp + common/textures/formats/qoitexture.cpp common/textures/hires/hqresize.cpp common/models/models_md3.cpp common/models/models_md2.cpp @@ -1054,7 +1048,6 @@ set (PCH_SOURCES common/utility/i_time.cpp common/utility/m_argv.cpp common/utility/s_playlist.cpp - common/utility/zstrformat.cpp common/utility/name.cpp common/utility/r_memory.cpp common/thirdparty/base64.cpp @@ -1157,14 +1150,7 @@ else() set( NOT_COMPILED_SOURCE_FILES ${NOT_COMPILED_SOURCE_FILES} ${VM_JIT_SOURCES} ) endif() -if( MSVC ) - enable_precompiled_headers( g_pch.h PCH_SOURCES ) -else() - # Temporary solution for compilers other than MSVC - set_source_files_properties( ${PCH_SOURCES} PROPERTIES COMPILE_FLAGS "-include g_pch.h" ) -endif() - -add_executable( zdoom WIN32 MACOSX_BUNDLE +set( ZDOOM_SOURCES ${HEADER_FILES} ${NOT_COMPILED_SOURCE_FILES} ${SYSTEM_SOURCES} @@ -1172,6 +1158,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE ${PCH_SOURCES} common/utility/x86.cpp common/thirdparty/strnatcmp.c + common/thirdparty/stb/stb_sprintf.c common/utility/zstring.cpp common/utility/findfile.cpp common/thirdparty/math/asin.c @@ -1194,10 +1181,18 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE common/thirdparty/math/fastsin.cpp ) +set( ZDOOM_NONPCH_SOURCES ${ZDOOM_SOURCES} ) +list( REMOVE_ITEM ZDOOM_NONPCH_SOURCES ${PCH_SOURCES} ) + +add_executable( zdoom WIN32 MACOSX_BUNDLE ${ZDOOM_SOURCES} ) + +target_precompile_headers( zdoom PRIVATE g_pch.h ) + set_source_files_properties( ${FASTMATH_SOURCES} PROPERTIES COMPILE_FLAGS ${ZD_FASTMATH_FLAG} ) set_source_files_properties( xlat/parse_xlat.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/xlat_parser.c" ) set_source_files_properties( common/engine/sc_man.cpp PROPERTIES OBJECT_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/sc_man_scanner.h" ) set_source_files_properties( ${NOT_COMPILED_SOURCE_FILES} PROPERTIES HEADER_FILE_ONLY TRUE ) +set_source_files_properties( ${ZDOOM_NONPCH_SOURCES} common/textures/hires/hqresize.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS TRUE ) if(${CMAKE_SYSTEM_NAME} STREQUAL "SunOS") @@ -1212,15 +1207,18 @@ if( UNIX ) endif() endif() -target_link_libraries( zdoom ${PROJECT_LIBRARIES} gdtoa lzma ${ZMUSIC_LIBRARIES} ) +target_link_libraries( zdoom ${PROJECT_LIBRARIES} lzma ${ZMUSIC_LIBRARIES} ) -include_directories( . +include_directories( + BEFORE + . common/audio/sound common/audio/music common/2d common/cutscenes common/thirdparty/libsmackerdec/include common/thirdparty + common/thirdparty/stb common/textures common/textures/formats common/textures/hires @@ -1264,9 +1262,7 @@ include_directories( . scripting scripting/zscript rendering - ../libraries/gdtoa ../libraries/ZVulkan/include - ${CMAKE_BINARY_DIR}/libraries/gdtoa ${SYSTEM_SOURCES_DIR} ) @@ -1457,6 +1453,7 @@ source_group("Common\\Third Party" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_D source_group("Common\\Third Party\\Math" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/math/.+") source_group("Common\\Third Party\\RapidJSON" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/rapidjson/.+") source_group("Common\\Third Party\\SFMT" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/sfmt/.+") +source_group("Common\\Third Party\\stb" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/common/thirdparty/stb/.+") source_group("Utility" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/.+") source_group("Utility\\Node Builder" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/utility/nodebuilder/.+") source_group("Utility\\Smackerdec" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/smackerdec/.+") diff --git a/src/am_map.cpp b/src/am_map.cpp index 8948921fb..373a7f810 100644 --- a/src/am_map.cpp +++ b/src/am_map.cpp @@ -2018,6 +2018,9 @@ void DAutomap::drawSubsectors() PalEntry flatcolor; mpoint_t originpt; + auto lm = getRealLightmode(Level, false); + bool softlightramp = !V_IsHardwareRenderer() || lm == ELightMode::Doom || lm == ELightMode::DoomDark; + auto &subsectors = Level->subsectors; for (unsigned i = 0; i < subsectors.Size(); ++i) { @@ -2192,15 +2195,14 @@ void DAutomap::drawSubsectors() // Why the +12? I wish I knew, but experimentation indicates it // is necessary in order to best reproduce Doom's original lighting. double fadelevel; - - if (!V_IsHardwareRenderer() || primaryLevel->lightMode == ELightMode::DoomDark || primaryLevel->lightMode == ELightMode::Doom || primaryLevel->lightMode == ELightMode::ZDoomSoftware || primaryLevel->lightMode == ELightMode::DoomSoftware) + if (softlightramp) { double map = (NUMCOLORMAPS * 2.) - ((floorlight + 12) * (NUMCOLORMAPS / 128.)); fadelevel = clamp((map - 12) / NUMCOLORMAPS, 0.0, 1.0); } else { - // The hardware renderer's light modes 0, 1 and 4 use a linear light scale which must be used here as well. Otherwise the automap gets too dark. + // for the hardware renderer's light modes that use a linear light scale this must do the same. Otherwise the automap gets too dark. fadelevel = 1. - clamp(floorlight, 0, 255) / 255.f; } diff --git a/src/common/2d/v_2ddrawer.cpp b/src/common/2d/v_2ddrawer.cpp index 375dcc6ac..4397e0f7a 100644 --- a/src/common/2d/v_2ddrawer.cpp +++ b/src/common/2d/v_2ddrawer.cpp @@ -68,7 +68,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Clear, Shape2DTransform_Clear) static void Shape2DTransform_Rotate(DShape2DTransform* self, double angle) { - self->transform = DMatrix3x3::Rotate2D(DEG2RAD(angle)) * self->transform; + self->transform = DMatrix3x3::Rotate2D(angle) * self->transform; } DEFINE_ACTION_FUNCTION_NATIVE(DShape2DTransform, Rotate, Shape2DTransform_Rotate) diff --git a/src/common/audio/music/i_soundfont.cpp b/src/common/audio/music/i_soundfont.cpp index af1c5634c..dd487954c 100644 --- a/src/common/audio/music/i_soundfont.cpp +++ b/src/common/audio/music/i_soundfont.cpp @@ -197,7 +197,7 @@ FileReader FSF2Reader::OpenFile(const char *name) FZipPatReader::FZipPatReader(const char *filename) { mAllowAbsolutePaths = true; - resf = FResourceFile::OpenResourceFile(filename, true); + resf = FResourceFile::OpenResourceFile(filename); } FZipPatReader::~FZipPatReader() diff --git a/src/common/audio/music/music.cpp b/src/common/audio/music/music.cpp index 6101dc1cc..d9b99fc2b 100644 --- a/src/common/audio/music/music.cpp +++ b/src/common/audio/music/music.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "i_sound.h" #include "i_music.h" diff --git a/src/common/console/c_cvars.cpp b/src/common/console/c_cvars.cpp index b529e830e..0f92791b2 100644 --- a/src/common/console/c_cvars.cpp +++ b/src/common/console/c_cvars.cpp @@ -397,7 +397,7 @@ const char *FBaseCVar::ToString (UCVarValue value, ECVarType type) case CVAR_Float: IGNORE_FORMAT_PRE - mysnprintf (cstrbuf, countof(cstrbuf), "%H", value.Float); + mysnprintf (cstrbuf, countof(cstrbuf), "%g", value.Float); IGNORE_FORMAT_POST break; @@ -489,7 +489,7 @@ UCVarValue FBaseCVar::FromFloat (float value, ECVarType type) case CVAR_String: IGNORE_FORMAT_PRE - mysnprintf (cstrbuf, countof(cstrbuf), "%H", value); + mysnprintf (cstrbuf, countof(cstrbuf), "%g", value); IGNORE_FORMAT_POST ret.String = cstrbuf; break; diff --git a/src/common/cutscenes/screenjob.cpp b/src/common/cutscenes/screenjob.cpp index dbf86aa46..00afee804 100644 --- a/src/common/cutscenes/screenjob.cpp +++ b/src/common/cutscenes/screenjob.cpp @@ -87,8 +87,8 @@ VMFunction* LookupFunction(const char* qname, bool validate) size_t p = strcspn(qname, "."); if (p == 0) I_Error("Call to undefined function %s", qname); - FString clsname(qname, p); - FString funcname = qname + p + 1; + FName clsname(qname, p, true); + FName funcname(qname + p + 1, true); auto func = PClass::FindFunction(clsname, funcname); if (func == nullptr) diff --git a/src/common/engine/m_joy.cpp b/src/common/engine/m_joy.cpp index dec49377f..49ad103ae 100644 --- a/src/common/engine/m_joy.cpp +++ b/src/common/engine/m_joy.cpp @@ -120,6 +120,11 @@ bool M_LoadJoystickConfig(IJoystickConfig *joy) { return false; } + value = GameConfig->GetValueForKey("Enabled"); + if (value != NULL) + { + joy->SetEnabled((bool)atoi(value)); + } value = GameConfig->GetValueForKey("Sensitivity"); if (value != NULL) { @@ -176,6 +181,10 @@ void M_SaveJoystickConfig(IJoystickConfig *joy) if (GameConfig != NULL && M_SetJoystickConfigSection(joy, true, GameConfig)) { GameConfig->ClearCurrentSection(); + if (!joy->GetEnabled()) + { + GameConfig->SetValueForKey("Enabled", "0"); + } if (!joy->IsSensitivityDefault()) { mysnprintf(value, countof(value), "%g", joy->GetSensitivity()); diff --git a/src/common/engine/m_joy.h b/src/common/engine/m_joy.h index fc99379b0..088d5bd6d 100644 --- a/src/common/engine/m_joy.h +++ b/src/common/engine/m_joy.h @@ -18,7 +18,7 @@ enum EJoyAxis }; // Generic configuration interface for a controller. -struct NOVTABLE IJoystickConfig +struct IJoystickConfig { virtual ~IJoystickConfig() = 0; @@ -36,6 +36,9 @@ struct NOVTABLE IJoystickConfig virtual void SetAxisMap(int axis, EJoyAxis gameaxis) = 0; virtual void SetAxisScale(int axis, float scale) = 0; + virtual bool GetEnabled() = 0; + virtual void SetEnabled(bool enabled) = 0; + // Used by the saver to not save properties that are at their defaults. virtual bool IsSensitivityDefault() = 0; virtual bool IsAxisDeadZoneDefault(int axis) = 0; diff --git a/src/common/engine/printf.h b/src/common/engine/printf.h index 98af91ff8..990b199b9 100644 --- a/src/common/engine/printf.h +++ b/src/common/engine/printf.h @@ -7,8 +7,9 @@ # define ATTRIBUTE(attrlist) #endif -// This header collects all things printf, so that this doesn't need to pull in other, far more dirty headers, just for outputting some text. +#include "stb_sprintf.h" +// This header collects all things printf, so that this doesn't need to pull in other, far more dirty headers, just for outputting some text. extern "C" int mysnprintf(char* buffer, size_t count, const char* format, ...) ATTRIBUTE((format(printf, 3, 4))); extern "C" int myvsnprintf(char* buffer, size_t count, const char* format, va_list argptr) ATTRIBUTE((format(printf, 3, 0))); diff --git a/src/common/engine/serializer.cpp b/src/common/engine/serializer.cpp index 28fc9ff26..1cd2d5811 100644 --- a/src/common/engine/serializer.cpp +++ b/src/common/engine/serializer.cpp @@ -55,6 +55,7 @@ #include "textures.h" #include "texturemanager.h" #include "base64.h" +#include "vm.h" extern DObject *WP_NOCHANGE; bool save_full = false; // for testing. Should be removed afterward. @@ -1567,6 +1568,35 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, Dictionary } } +template<> FSerializer& Serialize(FSerializer& arc, const char* key, VMFunction*& func, VMFunction**) +{ + if (arc.isWriting()) + { + arc.WriteKey(key); + if (func) arc.w->String(func->QualifiedName); + else arc.w->Null(); + } + else + { + func = nullptr; + + auto val = arc.r->FindKey(key); + if (val != nullptr && val->IsString()) + { + auto qname = val->GetString(); + size_t p = strcspn(qname, "."); + if (p != 0) + { + FName clsname(qname, p, true); + FName funcname(qname + p + 1, true); + func = PClass::FindFunction(clsname, funcname); + } + } + + } + return arc; +} + //========================================================================== // // Handler to retrieve a numeric value of any kind. diff --git a/src/common/engine/serializer.h b/src/common/engine/serializer.h index 93c7ef5a1..c9cc26320 100644 --- a/src/common/engine/serializer.h +++ b/src/common/engine/serializer.h @@ -310,6 +310,7 @@ inline FSerializer& Serialize(FSerializer& arc, const char* key, BitArray& value template<> FSerializer& Serialize(FSerializer& arc, const char* key, PClass*& clst, PClass** def); template<> FSerializer& Serialize(FSerializer& arc, const char* key, FFont*& font, FFont** def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, Dictionary *&dict, Dictionary **def); +template<> FSerializer& Serialize(FSerializer& arc, const char* key, VMFunction*& dict, VMFunction** def); inline FSerializer &Serialize(FSerializer &arc, const char *key, DVector3 &p, DVector3 *def) { diff --git a/src/common/filesystem/file_7z.cpp b/src/common/filesystem/file_7z.cpp index f207702d0..2bdd2e38f 100644 --- a/src/common/filesystem/file_7z.cpp +++ b/src/common/filesystem/file_7z.cpp @@ -39,7 +39,6 @@ #include "resourcefile.h" #include "cmdlib.h" -#include "printf.h" @@ -189,7 +188,7 @@ class F7ZFile : public FResourceFile public: F7ZFile(const char * filename, FileReader &filer); - bool Open(bool quiet, LumpFilterInfo* filter); + bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); virtual ~F7ZFile(); virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } }; @@ -216,7 +215,7 @@ F7ZFile::F7ZFile(const char * filename, FileReader &filer) // //========================================================================== -bool F7ZFile::Open(bool quiet, LumpFilterInfo *filter) +bool F7ZFile::Open(LumpFilterInfo *filter, FileSystemMessageFunc Printf) { Archive = new C7zArchive(Reader); int skipped = 0; @@ -227,25 +226,21 @@ bool F7ZFile::Open(bool quiet, LumpFilterInfo *filter) { delete Archive; Archive = NULL; - if (!quiet) + if (res == SZ_ERROR_UNSUPPORTED) { - Printf("\n" TEXTCOLOR_RED "%s: ", FileName.GetChars()); - if (res == SZ_ERROR_UNSUPPORTED) - { - Printf("Decoder does not support this archive\n"); - } - else if (res == SZ_ERROR_MEM) - { - Printf("Cannot allocate memory\n"); - } - else if (res == SZ_ERROR_CRC) - { - Printf("CRC error\n"); - } - else - { - Printf("error #%d\n", res); - } + Printf(FSMessageLevel::Error, "%s: Decoder does not support this archive\n", FileName.GetChars()); + } + else if (res == SZ_ERROR_MEM) + { + Printf(FSMessageLevel::Error, "Cannot allocate memory\n"); + } + else if (res == SZ_ERROR_CRC) + { + Printf(FSMessageLevel::Error, "CRC error\n"); + } + else + { + Printf(FSMessageLevel::Error, "error #%d\n", res); } return false; } @@ -308,7 +303,7 @@ bool F7ZFile::Open(bool quiet, LumpFilterInfo *filter) if (SZ_OK != Archive->Extract(Lumps[0].Position, &temp[0])) { - if (!quiet) Printf("\n%s: unsupported 7z/LZMA file!\n", FileName.GetChars()); + Printf(FSMessageLevel::Error, "%s: unsupported 7z/LZMA file!\n", FileName.GetChars()); return false; } } @@ -356,7 +351,7 @@ int F7ZLump::FillCache() // //========================================================================== -FResourceFile *Check7Z(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) +FResourceFile *Check7Z(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { char head[k7zSignatureSize]; @@ -368,7 +363,7 @@ FResourceFile *Check7Z(const char *filename, FileReader &file, bool quiet, LumpF if (!memcmp(head, k7zSignature, k7zSignatureSize)) { auto rf = new F7ZFile(filename, file); - if (rf->Open(quiet, filter)) return rf; + if (rf->Open(filter, Printf)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; diff --git a/src/common/filesystem/file_directory.cpp b/src/common/filesystem/file_directory.cpp index 80b9f6e57..f0ba89bfc 100644 --- a/src/common/filesystem/file_directory.cpp +++ b/src/common/filesystem/file_directory.cpp @@ -38,7 +38,6 @@ #include "resourcefile.h" #include "cmdlib.h" -#include "printf.h" #include "findfile.h" //========================================================================== @@ -67,12 +66,12 @@ class FDirectory : public FResourceFile TArray Lumps; const bool nosubdir; - int AddDirectory(const char *dirpath); + int AddDirectory(const char* dirpath, FileSystemMessageFunc Printf); void AddEntry(const char *fullpath, int size); public: FDirectory(const char * dirname, bool nosubdirflag = false); - bool Open(bool quiet, LumpFilterInfo* filter); + bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } }; @@ -110,7 +109,7 @@ FDirectory::FDirectory(const char * directory, bool nosubdirflag) // //========================================================================== -int FDirectory::AddDirectory(const char *dirpath) +int FDirectory::AddDirectory(const char *dirpath, FileSystemMessageFunc Printf) { void * handle; int count = 0; @@ -122,7 +121,7 @@ int FDirectory::AddDirectory(const char *dirpath) handle = I_FindFirst(dirmatch.GetChars(), &find); if (handle == ((void *)(-1))) { - Printf("Could not scan '%s': %s\n", dirpath, strerror(errno)); + Printf(FSMessageLevel::Error, "Could not scan '%s': %s\n", dirpath, strerror(errno)); } else { @@ -148,7 +147,7 @@ int FDirectory::AddDirectory(const char *dirpath) } FString newdir = dirpath; newdir << fi << '/'; - count += AddDirectory(newdir); + count += AddDirectory(newdir, Printf); } else { @@ -193,9 +192,9 @@ int FDirectory::AddDirectory(const char *dirpath) // //========================================================================== -bool FDirectory::Open(bool quiet, LumpFilterInfo* filter) +bool FDirectory::Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf) { - NumLumps = AddDirectory(FileName); + NumLumps = AddDirectory(FileName, Printf); PostProcessArchive(&Lumps[0], sizeof(FDirectoryLump), filter); return true; } @@ -265,10 +264,10 @@ int FDirectoryLump::FillCache() // //========================================================================== -FResourceFile *CheckDir(const char *filename, bool quiet, bool nosubdirflag, LumpFilterInfo* filter) +FResourceFile *CheckDir(const char *filename, bool nosubdirflag, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { auto rf = new FDirectory(filename, nosubdirflag); - if (rf->Open(quiet, filter)) return rf; + if (rf->Open(filter, Printf)) return rf; delete rf; return nullptr; } diff --git a/src/common/filesystem/file_grp.cpp b/src/common/filesystem/file_grp.cpp index 7128c1307..7ed922263 100644 --- a/src/common/filesystem/file_grp.cpp +++ b/src/common/filesystem/file_grp.cpp @@ -34,7 +34,6 @@ */ #include "resourcefile.h" -#include "printf.h" //========================================================================== // @@ -72,7 +71,7 @@ class FGrpFile : public FUncompressedFile { public: FGrpFile(const char * filename, FileReader &file); - bool Open(bool quiet, LumpFilterInfo* filter); + bool Open(LumpFilterInfo* filter); }; @@ -93,7 +92,7 @@ FGrpFile::FGrpFile(const char *filename, FileReader &file) // //========================================================================== -bool FGrpFile::Open(bool quiet, LumpFilterInfo*) +bool FGrpFile::Open(LumpFilterInfo* filter) { GrpHeader header; @@ -129,7 +128,7 @@ bool FGrpFile::Open(bool quiet, LumpFilterInfo*) // //========================================================================== -FResourceFile *CheckGRP(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) +FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { char head[12]; @@ -141,7 +140,7 @@ FResourceFile *CheckGRP(const char *filename, FileReader &file, bool quiet, Lump if (!memcmp(head, "KenSilverman", 12)) { auto rf = new FGrpFile(filename, file); - if (rf->Open(quiet, filter)) return rf; + if (rf->Open(filter)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; diff --git a/src/common/filesystem/file_lump.cpp b/src/common/filesystem/file_lump.cpp index abeb9cf71..0101aecf4 100644 --- a/src/common/filesystem/file_lump.cpp +++ b/src/common/filesystem/file_lump.cpp @@ -34,7 +34,6 @@ #include "resourcefile.h" #include "cmdlib.h" -#include "printf.h" //========================================================================== // @@ -46,7 +45,7 @@ class FLumpFile : public FUncompressedFile { public: FLumpFile(const char * filename, FileReader &file); - bool Open(bool quiet, LumpFilterInfo* filter); + bool Open(LumpFilterInfo* filter); }; @@ -67,7 +66,7 @@ FLumpFile::FLumpFile(const char *filename, FileReader &file) // //========================================================================== -bool FLumpFile::Open(bool quiet, LumpFilterInfo*) +bool FLumpFile::Open(LumpFilterInfo*) { FString name(ExtractFileBase(FileName, true)); @@ -78,10 +77,6 @@ bool FLumpFile::Open(bool quiet, LumpFilterInfo*) Lumps[0].LumpSize = (int)Reader.GetLength(); Lumps[0].Flags = 0; NumLumps = 1; - if (!quiet) - { - Printf("\n"); - } return true; } @@ -91,11 +86,11 @@ bool FLumpFile::Open(bool quiet, LumpFilterInfo*) // //========================================================================== -FResourceFile *CheckLump(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) +FResourceFile *CheckLump(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { // always succeeds auto rf = new FLumpFile(filename, file); - if (rf->Open(quiet, filter)) return rf; + if (rf->Open(filter)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; return NULL; diff --git a/src/common/filesystem/file_pak.cpp b/src/common/filesystem/file_pak.cpp index 3a868766c..f9e96eed6 100644 --- a/src/common/filesystem/file_pak.cpp +++ b/src/common/filesystem/file_pak.cpp @@ -33,7 +33,6 @@ */ #include "resourcefile.h" -#include "printf.h" //========================================================================== // @@ -65,7 +64,7 @@ class FPakFile : public FUncompressedFile { public: FPakFile(const char * filename, FileReader &file); - bool Open(bool quiet, LumpFilterInfo* filter); + bool Open(LumpFilterInfo* filter); }; @@ -88,7 +87,7 @@ FPakFile::FPakFile(const char *filename, FileReader &file) // //========================================================================== -bool FPakFile::Open(bool quiet, LumpFilterInfo* filter) +bool FPakFile::Open(LumpFilterInfo* filter) { dpackheader_t header; @@ -123,7 +122,7 @@ bool FPakFile::Open(bool quiet, LumpFilterInfo* filter) // //========================================================================== -FResourceFile *CheckPak(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) +FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { char head[4]; @@ -135,7 +134,7 @@ FResourceFile *CheckPak(const char *filename, FileReader &file, bool quiet, Lump if (!memcmp(head, "PACK", 4)) { auto rf = new FPakFile(filename, file); - if (rf->Open(quiet, filter)) return rf; + if (rf->Open(filter)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; diff --git a/src/common/filesystem/file_rff.cpp b/src/common/filesystem/file_rff.cpp index 3e512b62d..8d59749a5 100644 --- a/src/common/filesystem/file_rff.cpp +++ b/src/common/filesystem/file_rff.cpp @@ -35,8 +35,6 @@ #include "resourcefile.h" -#include "printf.h" - //========================================================================== // // @@ -111,7 +109,7 @@ class FRFFFile : public FResourceFile public: FRFFFile(const char * filename, FileReader &file); virtual ~FRFFFile(); - virtual bool Open(bool quiet, LumpFilterInfo* filter); + virtual bool Open(LumpFilterInfo* filter); virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } }; @@ -134,7 +132,7 @@ FRFFFile::FRFFFile(const char *filename, FileReader &file) // //========================================================================== -bool FRFFFile::Open(bool quiet, LumpFilterInfo*) +bool FRFFFile::Open(LumpFilterInfo*) { RFFLump *lumps; RFFInfo header; @@ -237,7 +235,7 @@ int FRFFLump::FillCache() // //========================================================================== -FResourceFile *CheckRFF(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) +FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { char head[4]; @@ -249,7 +247,7 @@ FResourceFile *CheckRFF(const char *filename, FileReader &file, bool quiet, Lump if (!memcmp(head, "RFF\x1a", 4)) { auto rf = new FRFFFile(filename, file); - if (rf->Open(quiet, filter)) return rf; + if (rf->Open(filter)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; diff --git a/src/common/filesystem/file_ssi.cpp b/src/common/filesystem/file_ssi.cpp index 64623e805..6bf60cc1e 100644 --- a/src/common/filesystem/file_ssi.cpp +++ b/src/common/filesystem/file_ssi.cpp @@ -34,7 +34,6 @@ */ #include "resourcefile.h" -#include "printf.h" //========================================================================== // @@ -46,7 +45,7 @@ class FSSIFile : public FUncompressedFile { public: FSSIFile(const char * filename, FileReader &file); - bool Open(bool quiet, int version, int lumpcount, LumpFilterInfo* filter); + bool Open(int version, int lumpcount, LumpFilterInfo* filter); }; @@ -68,7 +67,7 @@ FSSIFile::FSSIFile(const char *filename, FileReader &file) // //========================================================================== -bool FSSIFile::Open(bool quiet, int version, int lumpcount, LumpFilterInfo*) +bool FSSIFile::Open(int version, int lumpcount, LumpFilterInfo*) { NumLumps = lumpcount*2; Lumps.Resize(lumpcount*2); @@ -115,7 +114,7 @@ bool FSSIFile::Open(bool quiet, int version, int lumpcount, LumpFilterInfo*) // //========================================================================== -FResourceFile* CheckSSI(const char* filename, FileReader& file, bool quiet, LumpFilterInfo* filter) +FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { char zerobuf[72]; char buf[72]; @@ -146,7 +145,7 @@ FResourceFile* CheckSSI(const char* filename, FileReader& file, bool quiet, Lump if (!skipstring(70)) return nullptr; } auto ssi = new FSSIFile(filename, file); - if (ssi->Open(filename, version, numfiles, filter)) return ssi; + if (ssi->Open(version, numfiles, filter)) return ssi; file = std::move(ssi->Reader); // to avoid destruction of reader delete ssi; } diff --git a/src/common/filesystem/file_wad.cpp b/src/common/filesystem/file_wad.cpp index 8af39b5f8..45e2ec39c 100644 --- a/src/common/filesystem/file_wad.cpp +++ b/src/common/filesystem/file_wad.cpp @@ -35,7 +35,6 @@ #include #include "resourcefile.h" -#include "v_text.h" #include "filesystem.h" #include "engineerrors.h" @@ -125,13 +124,13 @@ class FWadFile : public FResourceFile TArray Lumps; bool IsMarker(int lump, const char *marker); - void SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, bool flathack=false); - void SkinHack (); + void SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, FileSystemMessageFunc Printf, bool flathack=false); + void SkinHack (FileSystemMessageFunc Printf); public: FWadFile(const char * filename, FileReader &file); FResourceLump *GetLump(int lump) { return &Lumps[lump]; } - bool Open(bool quiet, LumpFilterInfo* filter); + bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); }; @@ -154,7 +153,7 @@ FWadFile::FWadFile(const char *filename, FileReader &file) // //========================================================================== -bool FWadFile::Open(bool quiet, LumpFilterInfo*) +bool FWadFile::Open(LumpFilterInfo*, FileSystemMessageFunc Printf) { wadinfo_t header; uint32_t InfoTableOfs; @@ -176,7 +175,8 @@ bool FWadFile::Open(bool quiet, LumpFilterInfo*) // Check again to detect broken wads if (InfoTableOfs + NumLumps*sizeof(wadlump_t) > (unsigned)wadSize) { - I_Error("Cannot load broken WAD file %s\n", FileName.GetChars()); + Printf(FSMessageLevel::Error, "%s: Bad directory offset.\n", FileName.GetChars()); + return false; } } @@ -212,7 +212,7 @@ bool FWadFile::Open(bool quiet, LumpFilterInfo*) { if (Lumps[i].LumpSize != 0) { - Printf(PRINT_HIGH, "%s: Lump %s contains invalid positioning info and will be ignored\n", FileName.GetChars(), Lumps[i].getName()); + Printf(FSMessageLevel::Warning, "%s: Lump %s contains invalid positioning info and will be ignored\n", FileName.GetChars(), Lumps[i].getName()); Lumps[i].LumpNameSetup(""); } Lumps[i].LumpSize = Lumps[i].Position = 0; @@ -221,18 +221,15 @@ bool FWadFile::Open(bool quiet, LumpFilterInfo*) GenerateHash(); // Do this before the lump processing below. - if (!quiet) // don't bother with namespaces in quiet mode. We won't need them. - { - SetNamespace("S_START", "S_END", ns_sprites); - SetNamespace("F_START", "F_END", ns_flats, true); - SetNamespace("C_START", "C_END", ns_colormaps); - SetNamespace("A_START", "A_END", ns_acslibrary); - SetNamespace("TX_START", "TX_END", ns_newtextures); - SetNamespace("V_START", "V_END", ns_strifevoices); - SetNamespace("HI_START", "HI_END", ns_hires); - SetNamespace("VX_START", "VX_END", ns_voxels); - SkinHack(); - } + SetNamespace("S_START", "S_END", ns_sprites, Printf); + SetNamespace("F_START", "F_END", ns_flats, Printf, true); + SetNamespace("C_START", "C_END", ns_colormaps, Printf); + SetNamespace("A_START", "A_END", ns_acslibrary, Printf); + SetNamespace("TX_START", "TX_END", ns_newtextures, Printf); + SetNamespace("V_START", "V_END", ns_strifevoices, Printf); + SetNamespace("HI_START", "HI_END", ns_hires, Printf); + SetNamespace("VX_START", "VX_END", ns_voxels, Printf); + SkinHack(Printf); return true; } @@ -273,7 +270,7 @@ struct Marker unsigned int index; }; -void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, bool flathack) +void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, namespace_t space, FileSystemMessageFunc Printf, bool flathack) { bool warned = false; int numstartmarkers = 0, numendmarkers = 0; @@ -300,7 +297,7 @@ void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, name { if (numendmarkers == 0) return; // no markers found - Printf(TEXTCOLOR_YELLOW"WARNING: %s marker without corresponding %s found.\n", endmarker, startmarker); + Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName.GetChars(), endmarker, startmarker); if (flathack) @@ -314,7 +311,7 @@ void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, name { // We can't add this to the flats namespace but // it needs to be flagged for the texture manager. - DPrintf(DMSG_NOTIFY, "Marking %s as potential flat\n", Lumps[ii].getName()); + Printf(FSMessageLevel::DebugNotify, "%s: Marking %s as potential flat\n", FileName.GetChars(), Lumps[ii].getName()); Lumps[ii].Flags |= LUMPF_MAYBEFLAT; } } @@ -328,7 +325,7 @@ void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, name int start, end; if (markers[i].markertype != 0) { - Printf(TEXTCOLOR_YELLOW"WARNING: %s marker without corresponding %s found.\n", endmarker, startmarker); + Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName.GetChars(), endmarker, startmarker); i++; continue; } @@ -337,21 +334,21 @@ void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, name // skip over subsequent x_START markers while (i < markers.Size() && markers[i].markertype == 0) { - Printf(TEXTCOLOR_YELLOW"WARNING: duplicate %s marker found.\n", startmarker); + Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName.GetChars(), startmarker); i++; continue; } // same for x_END markers while (i < markers.Size()-1 && (markers[i].markertype == 1 && markers[i+1].markertype == 1)) { - Printf(TEXTCOLOR_YELLOW"WARNING: duplicate %s marker found.\n", endmarker); + Printf(FSMessageLevel::Warning, "%s: duplicate %s marker found.\n", FileName.GetChars(), endmarker); i++; continue; } // We found a starting marker but no end marker. Ignore this block. if (i >= markers.Size()) { - Printf(TEXTCOLOR_YELLOW"WARNING: %s marker without corresponding %s found.\n", startmarker, endmarker); + Printf(FSMessageLevel::Warning, "%s: %s marker without corresponding %s found.\n", FileName.GetChars(), startmarker, endmarker); end = NumLumps; } else @@ -360,14 +357,14 @@ void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, name } // we found a marked block - DPrintf(DMSG_NOTIFY, "Found %s block at (%d-%d)\n", startmarker, markers[start].index, end); + Printf(FSMessageLevel::DebugNotify, "%s: Found %s block at (%d-%d)\n", FileName.GetChars(), startmarker, markers[start].index, end); for(int j = markers[start].index + 1; j < end; j++) { if (Lumps[j].Namespace != ns_global) { if (!warned) { - Printf(TEXTCOLOR_YELLOW"WARNING: Overlapping namespaces found (lump %d)\n", j); + Printf(FSMessageLevel::Warning, "%s: Overlapping namespaces found (lump %d)\n", FileName.GetChars(), j); } warned = true; } @@ -377,7 +374,7 @@ void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, name // ignore sprite lumps smaller than 8 bytes (the smallest possible) // in size -- this was used by some dmadds wads // as an 'empty' graphics resource - DPrintf(DMSG_WARNING, " Skipped empty sprite %s (lump %d)\n", Lumps[j].getName(), j); + Printf(FSMessageLevel::DebugWarn, "%s: Skipped empty sprite %s (lump %d)\n", FileName.GetChars(), Lumps[j].getName(), j); } else { @@ -401,7 +398,7 @@ void FWadFile::SetNamespace(const char *startmarker, const char *endmarker, name // //========================================================================== -void FWadFile::SkinHack () +void FWadFile::SkinHack (FileSystemMessageFunc Printf) { // this being static is not a problem. The only relevant thing is that each skin gets a different number. static int namespc = ns_firstskin; @@ -447,11 +444,8 @@ void FWadFile::SkinHack () } if (skinned && hasmap) { - Printf (TEXTCOLOR_BLUE - "The maps in %s will not be loaded because it has a skin.\n" - TEXTCOLOR_BLUE - "You should remove the skin from the wad to play these maps.\n", - FileName.GetChars()); + Printf(FSMessageLevel::Attention, "%s: The maps will not be loaded because it has a skin.\n", FileName.GetChars()); + Printf(FSMessageLevel::Attention, "You should remove the skin from the wad to play these maps.\n"); } } @@ -462,7 +456,7 @@ void FWadFile::SkinHack () // //========================================================================== -FResourceFile *CheckWad(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) +FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { char head[4]; @@ -474,7 +468,7 @@ FResourceFile *CheckWad(const char *filename, FileReader &file, bool quiet, Lump if (!memcmp(head, "IWAD", 4) || !memcmp(head, "PWAD", 4)) { auto rf = new FWadFile(filename, file); - if (rf->Open(quiet, filter)) return rf; + if (rf->Open(filter, Printf)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; diff --git a/src/common/filesystem/file_whres.cpp b/src/common/filesystem/file_whres.cpp index 969aaafab..cc37ec26c 100644 --- a/src/common/filesystem/file_whres.cpp +++ b/src/common/filesystem/file_whres.cpp @@ -35,7 +35,6 @@ */ #include "resourcefile.h" -#include "printf.h" #include "cmdlib.h" //========================================================================== @@ -68,7 +67,7 @@ class FWHResFile : public FUncompressedFile FString basename; public: FWHResFile(const char * filename, FileReader &file); - bool Open(bool quiet, LumpFilterInfo* filter); + bool Open(LumpFilterInfo* filter); }; @@ -92,7 +91,7 @@ FWHResFile::FWHResFile(const char *filename, FileReader &file) // //========================================================================== -bool FWHResFile::Open(bool quiet, LumpFilterInfo*) +bool FWHResFile::Open(LumpFilterInfo*) { int directory[1024]; @@ -129,7 +128,7 @@ bool FWHResFile::Open(bool quiet, LumpFilterInfo*) // //========================================================================== -FResourceFile *CheckWHRes(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) +FResourceFile *CheckWHRes(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { if (file.GetLength() >= 8192) // needs to be at least 8192 to contain one file and the directory. { @@ -149,7 +148,7 @@ FResourceFile *CheckWHRes(const char *filename, FileReader &file, bool quiet, Lu checkpos += (length+4095) / 4096; } auto rf = new FWHResFile(filename, file); - if (rf->Open(quiet, filter)) return rf; + if (rf->Open(filter)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; } diff --git a/src/common/filesystem/file_zip.cpp b/src/common/filesystem/file_zip.cpp index e14305b52..75ca09da1 100644 --- a/src/common/filesystem/file_zip.cpp +++ b/src/common/filesystem/file_zip.cpp @@ -37,7 +37,6 @@ #include "file_zip.h" #include "cmdlib.h" -#include "printf.h" #include "w_zip.h" #include "ancientzip.h" @@ -52,50 +51,42 @@ static bool UncompressZipLump(char *Cache, FileReader &Reader, int Method, int LumpSize, int CompressedSize, int GPFlags) { - try + switch (Method) { - switch (Method) - { - case METHOD_STORED: - { - Reader.Read(Cache, LumpSize); - break; - } - - case METHOD_DEFLATE: - case METHOD_BZIP2: - case METHOD_LZMA: - { - FileReader frz; - if (frz.OpenDecompressor(Reader, LumpSize, Method, false, [](const char* err) { I_Error("%s", err); })) - { - frz.Read(Cache, LumpSize); - } - break; - } - - // Fixme: These should also use a stream - case METHOD_IMPLODE: - { - FZipExploder exploder; - exploder.Explode((unsigned char *)Cache, LumpSize, Reader, CompressedSize, GPFlags); - break; - } - - case METHOD_SHRINK: - { - ShrinkLoop((unsigned char *)Cache, LumpSize, Reader, CompressedSize); - break; - } - - default: - assert(0); - return false; - } + case METHOD_STORED: + { + Reader.Read(Cache, LumpSize); + break; } - catch (CRecoverableError &err) + + case METHOD_DEFLATE: + case METHOD_BZIP2: + case METHOD_LZMA: { - Printf("%s\n", err.GetMessage()); + FileReader frz; + if (frz.OpenDecompressor(Reader, LumpSize, Method, false, [](const char* err) { I_Error("%s", err); })) + { + frz.Read(Cache, LumpSize); + } + break; + } + + // Fixme: These should also use a stream + case METHOD_IMPLODE: + { + FZipExploder exploder; + exploder.Explode((unsigned char *)Cache, LumpSize, Reader, CompressedSize, GPFlags); + break; + } + + case METHOD_SHRINK: + { + ShrinkLoop((unsigned char *)Cache, LumpSize, Reader, CompressedSize); + break; + } + + default: + assert(0); return false; } return true; @@ -173,7 +164,7 @@ FZipFile::FZipFile(const char * filename, FileReader &file) Lumps = NULL; } -bool FZipFile::Open(bool quiet, LumpFilterInfo* filter) +bool FZipFile::Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf) { bool zip64 = false; uint32_t centraldir = Zip_FindCentralDir(Reader, &zip64); @@ -183,7 +174,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter) if (centraldir == 0) { - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: ZIP file corrupt!\n", FileName.GetChars()); + Printf(FSMessageLevel::Error, "%s: ZIP file corrupt!\n", FileName.GetChars()); return false; } @@ -199,7 +190,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter) if (info.NumEntries != info.NumEntriesOnAllDisks || info.FirstDisk != 0 || info.DiskNumber != 0) { - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Multipart Zip files are not supported.\n", FileName.GetChars()); + Printf(FSMessageLevel::Error, "%s: Multipart Zip files are not supported.\n", FileName.GetChars()); return false; } @@ -218,7 +209,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter) if (info.NumEntries != info.NumEntriesOnAllDisks || info.FirstDisk != 0 || info.DiskNumber != 0) { - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Multipart Zip files are not supported.\n", FileName.GetChars()); + Printf(FSMessageLevel::Error, "%s: Multipart Zip files are not supported.\n", FileName.GetChars()); return false; } @@ -257,7 +248,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter) if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. { free(directory); - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", FileName.GetChars()); + Printf(FSMessageLevel::Error, "%s: Central directory corrupted.", FileName.GetChars()); return false; } @@ -323,7 +314,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter) if (dirptr > ((char*)directory) + dirsize) // This directory entry goes beyond the end of the file. { free(directory); - if (!quiet) Printf(TEXTCOLOR_RED "\n%s: Central directory corrupted.", FileName.GetChars()); + Printf(FSMessageLevel::Error, "%s: Central directory corrupted.", FileName.GetChars()); return false; } @@ -350,7 +341,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter) zip_fh->Method != METHOD_IMPLODE && zip_fh->Method != METHOD_SHRINK) { - if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' uses an unsupported compression algorithm (#%d).\n", FileName.GetChars(), name.GetChars(), zip_fh->Method); + Printf(FSMessageLevel::Error, "%s: '%s' uses an unsupported compression algorithm (#%d).\n", FileName.GetChars(), name.GetChars(), zip_fh->Method); skipped++; continue; } @@ -358,7 +349,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter) zip_fh->Flags = LittleShort(zip_fh->Flags); if (zip_fh->Flags & ZF_ENCRYPTED) { - if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' is encrypted. Encryption is not supported.\n", FileName.GetChars(), name.GetChars()); + Printf(FSMessageLevel::Error, "%s: '%s' is encrypted. Encryption is not supported.\n", FileName.GetChars(), name.GetChars()); skipped++; continue; } @@ -385,7 +376,7 @@ bool FZipFile::Open(bool quiet, LumpFilterInfo* filter) if (zip_64->CompressedSize > 0x7fffffff || zip_64->UncompressedSize > 0x7fffffff) { // The file system is limited to 32 bit file sizes; - if (!quiet) Printf(TEXTCOLOR_YELLOW "\n%s: '%s' is too large.\n", FileName.GetChars(), name.GetChars()); + Printf(FSMessageLevel::Warning, "%s: '%s' is too large.\n", FileName.GetChars(), name.GetChars()); skipped++; continue; } @@ -508,7 +499,16 @@ int FZipLump::FillCache() Owner->Reader.Seek(Position, FileReader::SeekSet); Cache = new char[LumpSize]; - UncompressZipLump(Cache, Owner->Reader, Method, LumpSize, CompressedSize, GPFlags); + try + { + UncompressZipLump(Cache, Owner->Reader, Method, LumpSize, CompressedSize, GPFlags); + } + catch (const CRecoverableError& ) + { + // this cannot propagate the exception but also has no means to handle the error message. Damn... + // At least don't return uninitialized memory here. + memset(Cache, 0, LumpSize); + } RefCount = 1; return 1; } @@ -532,7 +532,7 @@ int FZipLump::GetFileOffset() // //========================================================================== -FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter) +FResourceFile *CheckZip(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { char head[4]; @@ -544,7 +544,7 @@ FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet, Lump if (!memcmp(head, "PK\x3\x4", 4)) { auto rf = new FZipFile(filename, file); - if (rf->Open(quiet, filter)) return rf; + if (rf->Open(filter, Printf)) return rf; file = std::move(rf->Reader); // to avoid destruction of reader delete rf; diff --git a/src/common/filesystem/file_zip.h b/src/common/filesystem/file_zip.h index c6a42d9a4..fc1d9acab 100644 --- a/src/common/filesystem/file_zip.h +++ b/src/common/filesystem/file_zip.h @@ -41,7 +41,7 @@ class FZipFile : public FResourceFile public: FZipFile(const char * filename, FileReader &file); virtual ~FZipFile(); - bool Open(bool quiet, LumpFilterInfo* filter); + bool Open(LumpFilterInfo* filter, FileSystemMessageFunc Printf); virtual FResourceLump *GetLump(int no) { return ((unsigned)no < NumLumps)? &Lumps[no] : NULL; } }; diff --git a/src/common/filesystem/filesystem.cpp b/src/common/filesystem/filesystem.cpp index 6b60e8e68..c4bcb64cd 100644 --- a/src/common/filesystem/filesystem.cpp +++ b/src/common/filesystem/filesystem.cpp @@ -152,7 +152,7 @@ struct FileSystem::LumpRecord // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- -static void PrintLastError (); +static void PrintLastError (FileSystemMessageFunc Printf); // PUBLIC DATA DEFINITIONS ------------------------------------------------- @@ -162,7 +162,7 @@ FileSystem fileSystem; FileSystem::FileSystem() { - // This is needed to initialize the LumpRecord array, which depends on data only available here. + // Cannot be defaulted! This is needed to initialize the LumpRecord array, which depends on data only available here. } FileSystem::~FileSystem () @@ -199,14 +199,14 @@ void FileSystem::DeleteAll () // //========================================================================== -void FileSystem::InitSingleFile(const char* filename, bool quiet) +bool FileSystem::InitSingleFile(const char* filename, FileSystemMessageFunc Printf) { TArray filenames; filenames.Push(filename); - InitMultipleFiles(filenames, true); + return InitMultipleFiles(filenames, nullptr, Printf); } -void FileSystem::InitMultipleFiles (TArray &filenames, bool quiet, LumpFilterInfo* filter, bool allowduplicates, FILE* hashfile) +bool FileSystem::InitMultipleFiles (TArray &filenames, LumpFilterInfo* filter, FileSystemMessageFunc Printf, bool allowduplicates, FILE* hashfile) { int numfiles; @@ -232,7 +232,7 @@ void FileSystem::InitMultipleFiles (TArray &filenames, bool quiet, Lump for(unsigned i=0;iGetHash().GetChars()); @@ -242,13 +242,13 @@ void FileSystem::InitMultipleFiles (TArray &filenames, bool quiet, Lump NumEntries = FileInfo.Size(); if (NumEntries == 0) { - if (!quiet) I_FatalError("W_InitMultipleFiles: no files found"); - else return; + return false; } if (filter && filter->postprocessFunc) filter->postprocessFunc(); // [RH] Set up hash table InitHashChains (); + return true; } //========================================================================== @@ -308,7 +308,7 @@ int FileSystem::AddFromBuffer(const char* name, const char* type, char* data, in // [RH] Removed reload hack //========================================================================== -void FileSystem::AddFile (const char *filename, FileReader *filer, bool quiet, LumpFilterInfo* filter, FILE* hashfile) +void FileSystem::AddFile (const char *filename, FileReader *filer, LumpFilterInfo* filter, FileSystemMessageFunc Printf, FILE* hashfile) { int startlump; bool isdir = false; @@ -319,10 +319,10 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, bool quiet, L // Does this exist? If so, is it a directory? if (!DirEntryExists(filename, &isdir)) { - if (!quiet) + if (Printf) { - Printf(TEXTCOLOR_RED "%s: File or Directory not found\n", filename); - PrintLastError(); + Printf(FSMessageLevel::Error, "%s: File or Directory not found\n", filename); + PrintLastError(Printf); } return; } @@ -331,10 +331,10 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, bool quiet, L { if (!filereader.OpenFile(filename)) { // Didn't find file - if (!quiet) + if (Printf) { - Printf(TEXTCOLOR_RED "%s: File not found\n", filename); - PrintLastError(); + Printf(FSMessageLevel::Error, "%s: File not found\n", filename); + PrintLastError(Printf); } return; } @@ -342,19 +342,20 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, bool quiet, L } else filereader = std::move(*filer); - if (!batchrun && !quiet) Printf (" adding %s", filename); startlump = NumEntries; FResourceFile *resfile; + if (!isdir) - resfile = FResourceFile::OpenResourceFile(filename, filereader, quiet, false, filter); + resfile = FResourceFile::OpenResourceFile(filename, filereader, false, filter, Printf); else - resfile = FResourceFile::OpenDirectory(filename, quiet, filter); + resfile = FResourceFile::OpenDirectory(filename, filter, Printf); if (resfile != NULL) { - if (!quiet && !batchrun) Printf(", %d lumps\n", resfile->LumpCount()); + if (!batchrun && Printf) + Printf(FSMessageLevel::Message, "adding %s, %d lumps\n", filename, resfile->LumpCount()); uint32_t lumpstart = FileInfo.Size(); @@ -376,11 +377,11 @@ void FileSystem::AddFile (const char *filename, FileReader *filer, bool quiet, L FString path; path.Format("%s:%s", filename, lump->getName()); auto embedded = lump->NewReader(); - AddFile(path, &embedded, quiet, filter, hashfile); + AddFile(path, &embedded, filter, Printf, hashfile); } } - if (hashfile && !quiet) + if (hashfile) { uint8_t cksum[16]; char cksumout[33]; @@ -1647,7 +1648,7 @@ __declspec(dllimport) void * __stdcall LocalFree (void *); __declspec(dllimport) unsigned long __stdcall GetLastError (); } -static void PrintLastError () +static void PrintLastError (FileSystemMessageFunc Printf) { char *lpMsgBuf; FormatMessageA(0x1300 /*FORMAT_MESSAGE_ALLOCATE_BUFFER | @@ -1660,14 +1661,14 @@ static void PrintLastError () 0, NULL ); - Printf (TEXTCOLOR_RED " %s\n", lpMsgBuf); + Printf (FSMessageLevel::Error, " %s\n", lpMsgBuf); // Free the buffer. LocalFree( lpMsgBuf ); } #else -static void PrintLastError () +static void PrintLastError (FileSystemMessageFunc Printf) { - Printf (TEXTCOLOR_RED " %s\n", strerror(errno)); + Printf(FSMessageLevel::Error, " %s\n", strerror(errno)); } #endif @@ -1681,21 +1682,3 @@ FResourceLump* FileSystem::GetFileAt(int no) { return FileInfo[no].lump; } - -#include "c_dispatch.h" - -CCMD(fs_dir) -{ - int numfiles = fileSystem.GetNumEntries(); - - for (int i = 0; i < numfiles; i++) - { - auto container = fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(i)); - auto fn1 = fileSystem.GetFileFullName(i); - auto fns = fileSystem.GetFileShortName(i); - auto fnid = fileSystem.GetResourceId(i); - auto length = fileSystem.FileLength(i); - bool hidden = fileSystem.FindFile(fn1) != i; - Printf(PRINT_HIGH | PRINT_NONOTIFY, "%s%-64s %-15s (%5d) %10d %s %s\n", hidden ? TEXTCOLOR_RED : TEXTCOLOR_UNTRANSLATED, fn1, fns, fnid, length, container, hidden ? "(h)" : ""); - } -} diff --git a/src/common/filesystem/filesystem.h b/src/common/filesystem/filesystem.h index 2dc80f7ff..fb72d77de 100644 --- a/src/common/filesystem/filesystem.h +++ b/src/common/filesystem/filesystem.h @@ -57,7 +57,7 @@ struct FolderEntry class FileSystem { public: - FileSystem (); + FileSystem(); ~FileSystem (); // The wadnum for the IWAD @@ -67,9 +67,9 @@ public: int GetMaxIwadNum() { return MaxIwadIndex; } void SetMaxIwadNum(int x) { MaxIwadIndex = x; } - void InitSingleFile(const char *filename, bool quiet = false); - void InitMultipleFiles (TArray &filenames, bool quiet = false, LumpFilterInfo* filter = nullptr, bool allowduplicates = false, FILE* hashfile = nullptr); - void AddFile (const char *filename, FileReader *wadinfo, bool quiet, LumpFilterInfo* filter, FILE* hashfile); + bool InitSingleFile(const char *filename, FileSystemMessageFunc Printf = nullptr); + bool InitMultipleFiles (TArray &filenames, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr, bool allowduplicates = false, FILE* hashfile = nullptr); + void AddFile (const char *filename, FileReader *wadinfo, LumpFilterInfo* filter, FileSystemMessageFunc Printf, FILE* hashfile); int CheckIfResourceFileLoaded (const char *name) noexcept; void AddAdditionalFile(const char* filename, FileReader* wadinfo = NULL) {} diff --git a/src/common/filesystem/resourcefile.cpp b/src/common/filesystem/resourcefile.cpp index 3b8e39915..f8ae9b09c 100644 --- a/src/common/filesystem/resourcefile.cpp +++ b/src/common/filesystem/resourcefile.cpp @@ -223,46 +223,54 @@ int FResourceLump::Unlock() // //========================================================================== -typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); +typedef FResourceFile * (*CheckFunc)(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf); -FResourceFile *CheckWad(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); -FResourceFile *CheckGRP(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); -FResourceFile *CheckRFF(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); -FResourceFile *CheckPak(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); -FResourceFile *CheckZip(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); -FResourceFile *Check7Z(const char *filename, FileReader &file, bool quiet, LumpFilterInfo* filter); -FResourceFile* CheckSSI(const char* filename, FileReader& file, bool quiet, LumpFilterInfo* filter); -FResourceFile *CheckLump(const char *filename,FileReader &file, bool quiet, LumpFilterInfo* filter); -FResourceFile *CheckDir(const char *filename, bool quiet, bool nosub, LumpFilterInfo* filter); +FResourceFile *CheckWad(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf); +FResourceFile *CheckGRP(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf); +FResourceFile *CheckRFF(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf); +FResourceFile *CheckPak(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf); +FResourceFile *CheckZip(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf); +FResourceFile *Check7Z(const char *filename, FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf); +FResourceFile* CheckSSI(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf); +FResourceFile* CheckWHRes(const char* filename, FileReader& file, LumpFilterInfo* filter, FileSystemMessageFunc Printf); +FResourceFile *CheckLump(const char *filename,FileReader &file, LumpFilterInfo* filter, FileSystemMessageFunc Printf); +FResourceFile *CheckDir(const char *filename, bool nosub, LumpFilterInfo* filter, FileSystemMessageFunc Printf); -static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckPak, CheckGRP, CheckRFF, CheckSSI, CheckLump }; +static CheckFunc funcs[] = { CheckWad, CheckZip, Check7Z, CheckPak, CheckGRP, CheckRFF, CheckSSI, CheckWHRes, CheckLump }; -FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly, LumpFilterInfo* filter) +static int nulPrintf(FSMessageLevel msg, const char* fmt, ...) { + return 0; +} + +FResourceFile *FResourceFile::DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf) +{ + if (Printf == nullptr) Printf = nulPrintf; for(size_t i = 0; i < countof(funcs) - containeronly; i++) { - FResourceFile *resfile = funcs[i](filename, file, quiet, filter); + FResourceFile *resfile = funcs[i](filename, file, filter, Printf); if (resfile != NULL) return resfile; } return NULL; } -FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly, LumpFilterInfo* filter) +FResourceFile *FResourceFile::OpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { - return DoOpenResourceFile(filename, file, quiet, containeronly, filter); + return DoOpenResourceFile(filename, file, containeronly, filter, Printf); } -FResourceFile *FResourceFile::OpenResourceFile(const char *filename, bool quiet, bool containeronly, LumpFilterInfo* filter) +FResourceFile *FResourceFile::OpenResourceFile(const char *filename, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { FileReader file; if (!file.OpenFile(filename)) return nullptr; - return DoOpenResourceFile(filename, file, quiet, containeronly, filter); + return DoOpenResourceFile(filename, file, containeronly, filter, Printf); } -FResourceFile *FResourceFile::OpenDirectory(const char *filename, bool quiet, LumpFilterInfo* filter) +FResourceFile *FResourceFile::OpenDirectory(const char *filename, LumpFilterInfo* filter, FileSystemMessageFunc Printf) { - return CheckDir(filename, quiet, false, filter); + if (Printf == nullptr) Printf = nulPrintf; + return CheckDir(filename, false, filter, Printf); } //========================================================================== diff --git a/src/common/filesystem/resourcefile.h b/src/common/filesystem/resourcefile.h index d64c278e8..65a6a4636 100644 --- a/src/common/filesystem/resourcefile.h +++ b/src/common/filesystem/resourcefile.h @@ -8,6 +8,7 @@ #include "files.h" #include "zstring.h" +// user context in which the file system gets opened. This also contains a few callbacks to avoid direct dependencies on the engine. struct LumpFilterInfo { TArray gameTypeFilter; // this can contain multiple entries @@ -20,6 +21,20 @@ struct LumpFilterInfo std::function postprocessFunc; }; +enum class FSMessageLevel +{ + Error = 1, + Warning = 2, + Attention = 3, + Message = 4, + DebugWarn = 5, + DebugNotify = 6, +}; + +// pass the text output function as parameter to avoid a hard dependency on higher level code. +using FileSystemMessageFunc = int(*)(FSMessageLevel msglevel, const char* format, ...); + + class FResourceFile; // [RH] Namespaces from BOOM. @@ -151,12 +166,12 @@ private: int FilterLumpsByGameType(LumpFilterInfo *filter, void *lumps, size_t lumpsize, uint32_t max); bool FindPrefixRange(FString filter, void *lumps, size_t lumpsize, uint32_t max, uint32_t &start, uint32_t &end); void JunkLeftoverFilters(void *lumps, size_t lumpsize, uint32_t max); - static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool quiet, bool containeronly, LumpFilterInfo* filter); + static FResourceFile *DoOpenResourceFile(const char *filename, FileReader &file, bool containeronly, LumpFilterInfo* filter, FileSystemMessageFunc Printf); public: - static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool quiet = false, bool containeronly = false, LumpFilterInfo* filter = nullptr); - static FResourceFile *OpenResourceFile(const char *filename, bool quiet = false, bool containeronly = false, LumpFilterInfo* filter = nullptr); - static FResourceFile *OpenDirectory(const char *filename, bool quiet = false, LumpFilterInfo* filter = nullptr); + static FResourceFile *OpenResourceFile(const char *filename, FileReader &file, bool containeronly = false, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr); + static FResourceFile *OpenResourceFile(const char *filename, bool containeronly = false, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr); + static FResourceFile *OpenDirectory(const char *filename, LumpFilterInfo* filter = nullptr, FileSystemMessageFunc Printf = nullptr); virtual ~FResourceFile(); // If this FResourceFile represents a directory, the Reader object is not usable so don't return it. FileReader *GetReader() { return Reader.isOpen()? &Reader : nullptr; } diff --git a/src/common/menu/joystickmenu.cpp b/src/common/menu/joystickmenu.cpp index 21c667d31..10408d916 100644 --- a/src/common/menu/joystickmenu.cpp +++ b/src/common/menu/joystickmenu.cpp @@ -119,6 +119,20 @@ DEFINE_ACTION_FUNCTION(IJoystickConfig, GetNumAxes) ACTION_RETURN_INT(self->GetNumAxes()); } +DEFINE_ACTION_FUNCTION(IJoystickConfig, GetEnabled) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + ACTION_RETURN_BOOL(self->GetEnabled()); +} + +DEFINE_ACTION_FUNCTION(IJoystickConfig, SetEnabled) +{ + PARAM_SELF_STRUCT_PROLOGUE(IJoystickConfig); + PARAM_BOOL(enabled); + self->SetEnabled(enabled); + return 0; +} + void UpdateJoystickMenu(IJoystickConfig *selected) { diff --git a/src/common/platform/posix/cocoa/i_joystick.cpp b/src/common/platform/posix/cocoa/i_joystick.cpp index 733380366..a2a27eaff 100644 --- a/src/common/platform/posix/cocoa/i_joystick.cpp +++ b/src/common/platform/posix/cocoa/i_joystick.cpp @@ -104,6 +104,9 @@ public: virtual bool IsAxisMapDefault(int axis); virtual bool IsAxisScaleDefault(int axis); + virtual bool GetEnabled(); + virtual void SetEnabled(bool enabled); + virtual void SetDefaultConfig(); virtual FString GetIdentifier(); @@ -165,6 +168,7 @@ private: TArray m_buttons; TArray m_POVs; + bool m_enabled; bool m_useAxesPolling; io_object_t m_notification; @@ -279,6 +283,7 @@ IOKitJoystick::IOKitJoystick(const io_object_t device) : m_interface(CreateDeviceInterface(device)) , m_queue(CreateDeviceQueue(m_interface)) , m_sensitivity(DEFAULT_SENSITIVITY) +, m_enabled(true) , m_useAxesPolling(true) , m_notification(0) { @@ -430,6 +435,17 @@ bool IOKitJoystick::IsAxisScaleDefault(int axis) : true; } + + +bool IOKitJoystick::GetEnabled() +{ + return m_enabled; +} +void IOKitJoystick::SetEnabled(bool enabled) +{ + m_enabled = enabled; +} + #undef IS_AXIS_VALID void IOKitJoystick::SetDefaultConfig() @@ -547,7 +563,7 @@ void IOKitJoystick::Update() if (kIOReturnSuccess == eventResult) { - if (use_joystick) + if (use_joystick && m_enabled) { ProcessAxis(event) || ProcessButton(event) || ProcessPOV(event); } @@ -557,7 +573,7 @@ void IOKitJoystick::Update() Printf(TEXTCOLOR_RED "IOHIDQueueInterface::getNextEvent() failed with code 0x%08X\n", eventResult); } - ProcessAxes(); + if(m_enabled) ProcessAxes(); } diff --git a/src/common/platform/posix/sdl/i_joystick.cpp b/src/common/platform/posix/sdl/i_joystick.cpp index 0fa33ba63..8f147112d 100644 --- a/src/common/platform/posix/sdl/i_joystick.cpp +++ b/src/common/platform/posix/sdl/i_joystick.cpp @@ -44,7 +44,7 @@ class SDLInputJoystick: public IJoystickConfig { public: - SDLInputJoystick(int DeviceIndex) : DeviceIndex(DeviceIndex), Multiplier(1.0f) + SDLInputJoystick(int DeviceIndex) : DeviceIndex(DeviceIndex), Multiplier(1.0f) , Enabled(true) { Device = SDL_JoystickOpen(DeviceIndex); if(Device != NULL) @@ -154,6 +154,17 @@ public: Axes.Push(info); } } + + bool GetEnabled() + { + return Enabled; + } + + void SetEnabled(bool enabled) + { + Enabled = enabled; + } + FString GetIdentifier() { char id[16]; @@ -248,9 +259,12 @@ protected: SDL_Joystick *Device; float Multiplier; + bool Enabled; TArray Axes; int NumAxes; int NumHats; + + friend class SDLInputJoystickManager; }; const EJoyAxis SDLInputJoystick::DefaultAxes[5] = {JOYAXIS_Side, JOYAXIS_Forward, JOYAXIS_Pitch, JOYAXIS_Yaw, JOYAXIS_Up}; @@ -291,7 +305,7 @@ public: void ProcessInput() const { for(unsigned int i = 0;i < Joysticks.Size();++i) - Joysticks[i]->ProcessInput(); + if(Joysticks[i]->Enabled) Joysticks[i]->ProcessInput(); } protected: TArray Joysticks; diff --git a/src/common/platform/posix/sdl/st_start.cpp b/src/common/platform/posix/sdl/st_start.cpp index d372e79bc..c068e682a 100644 --- a/src/common/platform/posix/sdl/st_start.cpp +++ b/src/common/platform/posix/sdl/st_start.cpp @@ -257,6 +257,7 @@ bool FTTYStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) struct timeval tv; int retval; char k; + bool stdin_eof = false; for (;;) { @@ -265,7 +266,10 @@ bool FTTYStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) tv.tv_usec = 500000; FD_ZERO (&rfds); - FD_SET (STDIN_FILENO, &rfds); + if (!stdin_eof) + { + FD_SET (STDIN_FILENO, &rfds); + } retval = select (1, &rfds, NULL, NULL, &tv); @@ -281,13 +285,21 @@ bool FTTYStartupScreen::NetLoop(bool (*timer_callback)(void *), void *userdata) return true; } } - else if (read (STDIN_FILENO, &k, 1) == 1) + else { - // Check input on stdin - if (k == 'q' || k == 'Q') + ssize_t amt = read (STDIN_FILENO, &k, 1); // Check input on stdin + if (amt == 0) { - fprintf (stderr, "\nNetwork game synchronization aborted."); - return false; + // EOF. Stop reading + stdin_eof = true; + } + else if (amt == 1) + { + if (k == 'q' || k == 'Q') + { + fprintf (stderr, "\nNetwork game synchronization aborted."); + return false; + } } } } diff --git a/src/common/platform/win32/i_dijoy.cpp b/src/common/platform/win32/i_dijoy.cpp index 11f60a35f..c22c5492b 100644 --- a/src/common/platform/win32/i_dijoy.cpp +++ b/src/common/platform/win32/i_dijoy.cpp @@ -180,6 +180,9 @@ public: bool IsAxisMapDefault(int axis); bool IsAxisScaleDefault(int axis); + bool GetEnabled(); + void SetEnabled(bool enabled); + void SetDefaultConfig(); FString GetIdentifier(); @@ -219,6 +222,8 @@ protected: DIOBJECTDATAFORMAT *Objects; DIDATAFORMAT DataFormat; + bool Enabled; + static BOOL CALLBACK EnumObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef); void OrderAxes(); bool ReorderAxisPair(const GUID &x, const GUID &y, int pos); @@ -297,6 +302,7 @@ FDInputJoystick::FDInputJoystick(const GUID *instance, FString &name) Instance = *instance; Name = name; Marked = false; + Enabled = true; } //=========================================================================== @@ -410,7 +416,7 @@ void FDInputJoystick::ProcessInput() { hr = Device->Acquire(); } - if (FAILED(hr)) + if (FAILED(hr) || !Enabled) { return; } @@ -984,6 +990,28 @@ bool FDInputJoystick::IsAxisScaleDefault(int axis) return true; } +//=========================================================================== +// +// FDInputJoystick :: GetEnabled +// +//=========================================================================== + +bool FDInputJoystick::GetEnabled() +{ + return Enabled; +} + +//=========================================================================== +// +// FDInputJoystick :: SetEnabled +// +//=========================================================================== + +void FDInputJoystick::SetEnabled(bool enabled) +{ + Enabled = enabled; +} + //=========================================================================== // // FDInputJoystick :: IsAxisMapDefault diff --git a/src/common/platform/win32/i_input.h b/src/common/platform/win32/i_input.h index 643cc65b3..16a276ce8 100644 --- a/src/common/platform/win32/i_input.h +++ b/src/common/platform/win32/i_input.h @@ -115,7 +115,7 @@ protected: void PostKeyEvent(int keynum, INTBOOL down, bool foreground); }; -class NOVTABLE FJoystickCollection : public FInputDevice +class FJoystickCollection : public FInputDevice { public: virtual void AddAxes(float axes[NUM_JOYAXIS]) = 0; diff --git a/src/common/platform/win32/i_rawps2.cpp b/src/common/platform/win32/i_rawps2.cpp index f06378803..834431580 100644 --- a/src/common/platform/win32/i_rawps2.cpp +++ b/src/common/platform/win32/i_rawps2.cpp @@ -114,6 +114,9 @@ public: bool IsAxisMapDefault(int axis); bool IsAxisScaleDefault(int axis); + bool GetEnabled(); + void SetEnabled(bool enabled); + void SetDefaultConfig(); FString GetIdentifier(); @@ -153,6 +156,7 @@ protected: bool Connected; bool Marked; bool Active; + bool Enabled; void Attached(); void Detached(); @@ -376,6 +380,7 @@ FRawPS2Controller::FRawPS2Controller(HANDLE handle, EAdapterType type, int seque ControllerNumber = controller; Sequence = sequence; DeviceID = devid; + Enabled = true; // The EMS USB2 controller provides attachment status. The others do not. Connected = (Descriptors[type].ControllerStatus < 0); @@ -849,6 +854,28 @@ bool FRawPS2Controller::IsAxisScaleDefault(int axis) return true; } +//=========================================================================== +// +// FRawPS2Controller :: GetEnabled +// +//=========================================================================== + +bool FRawPS2Controller::GetEnabled() +{ + return Enabled; +} + +//=========================================================================== +// +// FRawPS2Controller :: SetEnabled +// +//=========================================================================== + +void FRawPS2Controller::SetEnabled(bool enabled) +{ + Enabled = enabled; +} + //=========================================================================== // // FRawPS2Controller :: IsAxisMapDefault @@ -972,7 +999,7 @@ bool FRawPS2Manager::ProcessRawInput(RAWINPUT *raw, int code) { if (Devices[i]->Handle == raw->header.hDevice) { - if (Devices[i]->ProcessInput(&raw->data.hid, code)) + if (Devices[i]->Enabled && Devices[i]->ProcessInput(&raw->data.hid, code)) { return true; } diff --git a/src/common/platform/win32/i_xinput.cpp b/src/common/platform/win32/i_xinput.cpp index ba4605dd0..d1dc4364d 100644 --- a/src/common/platform/win32/i_xinput.cpp +++ b/src/common/platform/win32/i_xinput.cpp @@ -102,6 +102,9 @@ public: bool IsAxisMapDefault(int axis); bool IsAxisScaleDefault(int axis); + bool GetEnabled(); + void SetEnabled(bool enabled); + void SetDefaultConfig(); FString GetIdentifier(); @@ -138,6 +141,7 @@ protected: DWORD LastPacketNumber; int LastButtons; bool Connected; + bool Enabled; void Attached(); void Detached(); @@ -221,6 +225,7 @@ FXInputController::FXInputController(int index) { Index = index; Connected = false; + Enabled = true; M_LoadJoystickConfig(this); } @@ -269,7 +274,7 @@ void FXInputController::ProcessInput() { Attached(); } - if (state.dwPacketNumber == LastPacketNumber) + if (state.dwPacketNumber == LastPacketNumber || !Enabled) { // Nothing has changed since last time. return; } @@ -628,6 +633,28 @@ bool FXInputController::IsAxisScaleDefault(int axis) return true; } +//=========================================================================== +// +// FXInputController :: GetEnabled +// +//=========================================================================== + +bool FXInputController::GetEnabled() +{ + return Enabled; +} + +//=========================================================================== +// +// FXInputController :: SetEnabled +// +//=========================================================================== + +void FXInputController::SetEnabled(bool enabled) +{ + Enabled = enabled; +} + //=========================================================================== // // FXInputController :: IsAxisMapDefault diff --git a/src/common/rendering/hwrenderer/data/hw_cvars.h b/src/common/rendering/hwrenderer/data/hw_cvars.h index eb190d1ae..90770974e 100644 --- a/src/common/rendering/hwrenderer/data/hw_cvars.h +++ b/src/common/rendering/hwrenderer/data/hw_cvars.h @@ -19,7 +19,6 @@ EXTERN_CVAR (Bool, gl_light_raytrace); EXTERN_CVAR (Int, gl_shadowmap_quality); EXTERN_CVAR(Int, gl_fogmode) -EXTERN_CVAR(Int, gl_lightmode) EXTERN_CVAR(Bool,gl_mirror_envmap) EXTERN_CVAR(Bool,gl_mirrors) diff --git a/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp b/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp index ac80eec54..c51ce2ee9 100644 --- a/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp +++ b/src/common/rendering/hwrenderer/data/hw_vrmodes.cpp @@ -34,7 +34,7 @@ ** */ -#include "vectors.h" // RAD2DEG +#include "vectors.h" #include "hw_cvars.h" #include "hw_vrmodes.h" #include "v_video.h" @@ -67,6 +67,16 @@ static VRMode vrmi_righteye = { 1, 1.f, 1.f, 1.f,{ { .5f, 1.f },{ 0.f, 0.f } } } static VRMode vrmi_topbottom = { 2, 1.f, .5f, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; static VRMode vrmi_checker = { 2, isqrt2, isqrt2, 1.f,{ { -.5f, 1.f },{ .5f, 1.f } } }; +static float DEG2RAD(float deg) +{ + return deg * float(M_PI / 180.0); +} + +static float RAD2DEG(float rad) +{ + return rad * float(180. / M_PI); +} + const VRMode *VRMode::GetVRMode(bool toscreen) { int mode = !toscreen || (sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter()) ? 0 : vr_mode; diff --git a/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h index 523b8d8d0..7ecbd4f84 100644 --- a/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h +++ b/src/common/rendering/hwrenderer/postprocessing/hw_postprocessshader.h @@ -1,5 +1,8 @@ #pragma once +#include "zstring.h" +#include "tarray.h" + enum class PostProcessUniformType { Undefined, diff --git a/src/common/rendering/vulkan/textures/vk_hwtexture.cpp b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp index ffb9da351..9c7f0a03e 100644 --- a/src/common/rendering/vulkan/textures/vk_hwtexture.cpp +++ b/src/common/rendering/vulkan/textures/vk_hwtexture.cpp @@ -113,7 +113,7 @@ void VkHardwareTexture::CreateImage(FTexture *tex, int translation, int flags) } else { - VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; + VkFormat format = tex->IsHDR() ? VK_FORMAT_R32G32B32A32_SFLOAT : VK_FORMAT_R8G8B8A8_UNORM; int w = tex->GetWidth(); int h = tex->GetHeight(); diff --git a/src/common/scripting/backend/codegen.cpp b/src/common/scripting/backend/codegen.cpp index 2659eda26..8acbe668e 100644 --- a/src/common/scripting/backend/codegen.cpp +++ b/src/common/scripting/backend/codegen.cpp @@ -277,7 +277,8 @@ bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare) // null pointers can be assigned to everything, everything can be assigned to void pointers. if (fromtype == nullptr || totype == TypeVoidPtr) return true; // when comparing const-ness does not matter. - if (!forcompare && totype->IsConst != fromtype->IsConst) return false; + // If not comparing, then we should not allow const to be cast away. + if (!forcompare && fromtype->IsConst && !totype->IsConst) return false; // A type is always compatible to itself. if (fromtype == totype) return true; // Pointers to different types are only compatible if both point to an object and the source type is a child of the destination type. @@ -4793,7 +4794,7 @@ FxExpression *FxTypeCheck::Resolve(FCompileContext& ctx) } else { - left = new FxTypeCast(left, NewPointer(RUNTIME_CLASS(DObject)), false); + left = new FxTypeCast(left, NewPointer(RUNTIME_CLASS(DObject), true), false); ClassCheck = false; } right = new FxClassTypeCast(NewClassPointer(RUNTIME_CLASS(DObject)), right, false); @@ -8858,7 +8859,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } } - if (Self->ValueType->isRealPointer()) + if (Self->ValueType->isRealPointer() && Self->ValueType->toPointer()->PointedType) { auto ptype = Self->ValueType->toPointer()->PointedType; cls = ptype->toContainer(); @@ -9151,7 +9152,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) // [Player701] Catch attempts to call abstract functions directly at compile time if (NoVirtual && Function->Variants[0].Implementation->VarFlags & VARF_Abstract) { - ScriptPosition.Message(MSG_ERROR, "Cannot call abstract function %s", Function->Variants[0].Implementation->PrintableName.GetChars()); + ScriptPosition.Message(MSG_ERROR, "Cannot call abstract function %s", Function->Variants[0].Implementation->PrintableName); delete this; return nullptr; } diff --git a/src/common/scripting/backend/codegen.h b/src/common/scripting/backend/codegen.h index c12e33d3f..2781adbe5 100644 --- a/src/common/scripting/backend/codegen.h +++ b/src/common/scripting/backend/codegen.h @@ -348,8 +348,8 @@ public: bool IsQuaternion() const { return ValueType == TypeQuaternion || ValueType == TypeFQuaternion || ValueType == TypeQuaternionStruct; }; bool IsBoolCompat() const { return ValueType->isScalar(); } bool IsObject() const { return ValueType->isObjectPointer(); } - bool IsArray() const { return ValueType->isArray() || (ValueType->isPointer() && ValueType->toPointer()->PointedType->isArray()); } - bool isStaticArray() const { return (ValueType->isPointer() && ValueType->toPointer()->PointedType->isStaticArray()); } // can only exist in pointer form. + bool IsArray() const { return ValueType->isArray() || (ValueType->isPointer() && ValueType->toPointer()->PointedType && ValueType->toPointer()->PointedType->isArray()); } + bool isStaticArray() const { return (ValueType->isPointer() && ValueType->toPointer()->PointedType && ValueType->toPointer()->PointedType->isStaticArray()); } // can only exist in pointer form. bool IsDynamicArray() const { return (ValueType->isDynArray()); } bool IsMap() const { return ValueType->isMap(); } bool IsMapIterator() const { return ValueType->isMapIterator(); } diff --git a/src/common/scripting/backend/vmbuilder.cpp b/src/common/scripting/backend/vmbuilder.cpp index 7d270af61..ae34ea4c5 100644 --- a/src/common/scripting/backend/vmbuilder.cpp +++ b/src/common/scripting/backend/vmbuilder.cpp @@ -790,7 +790,7 @@ VMFunction *FFunctionBuildList::AddFunction(PNamespace *gnspc, const VersionInfo it.PrintableName = name; it.Function = new VMScriptFunction; it.Function->Name = functype->SymbolName; - it.Function->PrintableName = name; + it.Function->QualifiedName = it.Function->PrintableName = ClassDataAllocator.Strdup(name); it.Function->ImplicitArgs = functype->GetImplicitArgs(); it.Proto = nullptr; it.FromDecorate = fromdecorate; diff --git a/src/common/scripting/core/imports.cpp b/src/common/scripting/core/imports.cpp index c5a8cf9c5..3006462cd 100644 --- a/src/common/scripting/core/imports.cpp +++ b/src/common/scripting/core/imports.cpp @@ -198,7 +198,8 @@ void InitImports() { assert(afunc->VMPointer != NULL); *(afunc->VMPointer) = new VMNativeFunction(afunc->Function, afunc->FuncName); - (*(afunc->VMPointer))->PrintableName.Format("%s.%s [Native]", afunc->ClassName+1, afunc->FuncName); + (*(afunc->VMPointer))->QualifiedName = ClassDataAllocator.Strdup(FStringf("%s.%s", afunc->ClassName + 1, afunc->FuncName)); + (*(afunc->VMPointer))->PrintableName = ClassDataAllocator.Strdup(FStringf("%s.%s [Native]", afunc->ClassName+1, afunc->FuncName)); (*(afunc->VMPointer))->DirectNativeCall = afunc->DirectNative; AFTable.Push(*afunc); }); diff --git a/src/common/scripting/core/scopebarrier.cpp b/src/common/scripting/core/scopebarrier.cpp index a6c5a2370..8e03f757f 100644 --- a/src/common/scripting/core/scopebarrier.cpp +++ b/src/common/scripting/core/scopebarrier.cpp @@ -221,5 +221,5 @@ void FScopeBarrier::ValidateCall(PClass* selftype, VMFunction *calledfunc, int o { int innerside = FScopeBarrier::SideFromObjectFlags(selftype->VMType->ScopeFlags); if ((outerside != innerside) && (innerside != FScopeBarrier::Side_PlainData)) - ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->PrintableName.GetChars(), FScopeBarrier::StringFromSide(outerside)); + ThrowAbortException(X_OTHER, "Cannot call %s function %s from %s context", FScopeBarrier::StringFromSide(innerside), calledfunc->PrintableName, FScopeBarrier::StringFromSide(outerside)); } \ No newline at end of file diff --git a/src/common/scripting/core/symbols.h b/src/common/scripting/core/symbols.h index de5caaae9..15d547f7d 100644 --- a/src/common/scripting/core/symbols.h +++ b/src/common/scripting/core/symbols.h @@ -9,6 +9,16 @@ class PPrototype; struct ZCC_TreeNode; class PContainerType; +// This is needed in common code, despite being Doom specific. +enum EStateUseFlags +{ + SUF_ACTOR = 1, + SUF_OVERLAY = 2, + SUF_WEAPON = 4, + SUF_ITEM = 8, +}; + + // Symbol information ------------------------------------------------------- class PTypeBase diff --git a/src/common/scripting/core/vmdisasm.cpp b/src/common/scripting/core/vmdisasm.cpp index 433a2fd1a..86d566985 100644 --- a/src/common/scripting/core/vmdisasm.cpp +++ b/src/common/scripting/core/vmdisasm.cpp @@ -528,7 +528,7 @@ void VMDisasm(FILE *out, const VMOP *code, int codesize, const VMScriptFunction } else if (code[i].op == OP_CALL_K && callfunc) { - printf_wrapper(out, " [%s]\n", callfunc->PrintableName.GetChars()); + printf_wrapper(out, " [%s]\n", callfunc->PrintableName); } else { diff --git a/src/common/scripting/frontend/zcc_compile.cpp b/src/common/scripting/frontend/zcc_compile.cpp index ffba4c301..fb21526f1 100644 --- a/src/common/scripting/frontend/zcc_compile.cpp +++ b/src/common/scripting/frontend/zcc_compile.cpp @@ -2798,7 +2798,7 @@ void ZCCCompiler::InitFunctions() { if (v->VarFlags & VARF_Abstract) { - Error(c->cls, "Non-abstract class %s must override abstract function %s", c->Type()->TypeName.GetChars(), v->PrintableName.GetChars()); + Error(c->cls, "Non-abstract class %s must override abstract function %s", c->Type()->TypeName.GetChars(), v->PrintableName); } } } diff --git a/src/common/scripting/jit/jit.cpp b/src/common/scripting/jit/jit.cpp index 13679d59a..27b69cac4 100644 --- a/src/common/scripting/jit/jit.cpp +++ b/src/common/scripting/jit/jit.cpp @@ -15,7 +15,7 @@ static void OutputJitLog(const asmjit::StringLogger &logger); JitFuncPtr JitCompile(VMScriptFunction *sfunc) { #if 0 - if (strcmp(sfunc->PrintableName.GetChars(), "StatusScreen.drawNum") != 0) + if (strcmp(sfunc->PrintableName, "StatusScreen.drawNum") != 0) return nullptr; #endif @@ -35,7 +35,7 @@ JitFuncPtr JitCompile(VMScriptFunction *sfunc) catch (const CRecoverableError &e) { OutputJitLog(logger); - Printf("%s: Unexpected JIT error: %s\n",sfunc->PrintableName.GetChars(), e.what()); + Printf("%s: Unexpected JIT error: %s\n",sfunc->PrintableName, e.what()); return nullptr; } } @@ -237,7 +237,7 @@ void JitCompiler::Setup() cc.comment(marks, 56); FString funcname; - funcname.Format("Function: %s", sfunc->PrintableName.GetChars()); + funcname.Format("Function: %s", sfunc->PrintableName); cc.comment(funcname.GetChars(), funcname.Len()); cc.comment(marks, 56); @@ -364,7 +364,7 @@ void JitCompiler::SetupSimpleFrame() if (errorDetails) { - I_FatalError("JIT: inconsistent number of %s for function %s", errorDetails, sfunc->PrintableName.GetChars()); + I_FatalError("JIT: inconsistent number of %s for function %s", errorDetails, sfunc->PrintableName); } for (int i = regd; i < sfunc->NumRegD; i++) diff --git a/src/common/scripting/jit/jit_call.cpp b/src/common/scripting/jit/jit_call.cpp index e6c1feb0b..d7074edc9 100644 --- a/src/common/scripting/jit/jit_call.cpp +++ b/src/common/scripting/jit/jit_call.cpp @@ -97,7 +97,7 @@ void JitCompiler::EmitVMCall(asmjit::X86Gp vmfunc, VMFunction *target) call->setArg(2, Imm(B)); call->setArg(3, GetCallReturns()); call->setArg(4, Imm(C)); - call->setInlineComment(target ? target->PrintableName.GetChars() : "VMCall"); + call->setInlineComment(target ? target->PrintableName : "VMCall"); LoadInOuts(); LoadReturns(pc + 1, C); @@ -360,7 +360,7 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target) asmjit::CBNode *cursorBefore = cc.getCursor(); auto call = cc.call(imm_ptr(target->DirectNativeCall), CreateFuncSignature()); - call->setInlineComment(target->PrintableName.GetChars()); + call->setInlineComment(target->PrintableName); asmjit::CBNode *cursorAfter = cc.getCursor(); cc.setCursor(cursorBefore); diff --git a/src/common/scripting/jit/jit_runtime.cpp b/src/common/scripting/jit/jit_runtime.cpp index 89672b940..cdfbedb67 100644 --- a/src/common/scripting/jit/jit_runtime.cpp +++ b/src/common/scripting/jit/jit_runtime.cpp @@ -306,7 +306,7 @@ void *AddJitFunction(asmjit::CodeHolder* code, JitCompiler *compiler) if (result == 0) I_Error("RtlAddFunctionTable failed"); - JitDebugInfo.Push({ compiler->GetScriptFunction()->PrintableName, compiler->GetScriptFunction()->SourceFileName, compiler->LineInfo, startaddr, endaddr }); + JitDebugInfo.Push({ FString(compiler->GetScriptFunction()->PrintableName), compiler->GetScriptFunction()->SourceFileName, compiler->LineInfo, startaddr, endaddr }); #endif return p; diff --git a/src/common/scripting/vm/vm.h b/src/common/scripting/vm/vm.h index 805f4d99e..73c4b48bb 100644 --- a/src/common/scripting/vm/vm.h +++ b/src/common/scripting/vm/vm.h @@ -451,7 +451,8 @@ public: FName Name; const uint8_t *RegTypes = nullptr; TArray DefaultArgs; - FString PrintableName; // so that the VM can print meaningful info if something in this function goes wrong. + const char* QualifiedName = nullptr; + const char* PrintableName = nullptr; // same as QualifiedName, but can have additional annotations. class PPrototype *Proto; TArray ArgFlags; // Should be the same length as Proto->ArgumentTypes diff --git a/src/common/scripting/vm/vmexec.h b/src/common/scripting/vm/vmexec.h index f303304b8..5ddac8bd4 100644 --- a/src/common/scripting/vm/vmexec.h +++ b/src/common/scripting/vm/vmexec.h @@ -895,7 +895,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) catch (CVMAbortException &err) { err.MaybePrintMessage(); - err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName.GetChars()); + err.stacktrace.AppendFormat("Called from %s\n", call->PrintableName); // PrintParameters(reg.param + f->NumParam - B, B); throw; } @@ -2000,7 +2000,7 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret) catch (CVMAbortException &err) { err.MaybePrintMessage(); - err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName.GetChars(), sfunc->SourceFileName.GetChars(), sfunc->PCToLine(pc)); + err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName, sfunc->SourceFileName.GetChars(), sfunc->PCToLine(pc)); // PrintParameters(reg.param + f->NumParam - B, B); throw; } diff --git a/src/common/scripting/vm/vmframe.cpp b/src/common/scripting/vm/vmframe.cpp index a2c972820..a13829dda 100644 --- a/src/common/scripting/vm/vmframe.cpp +++ b/src/common/scripting/vm/vmframe.cpp @@ -80,7 +80,7 @@ void VMFunction::CreateRegUse() if (!Proto) { //if (RegTypes) return; - //Printf(TEXTCOLOR_ORANGE "Function without prototype needs register info manually set: %s\n", PrintableName.GetChars()); + //Printf(TEXTCOLOR_ORANGE "Function without prototype needs register info manually set: %s\n", PrintableName); return; } assert(Proto->isPrototype()); @@ -277,7 +277,7 @@ static bool CanJit(VMScriptFunction *func) if (func->NumRegA + func->NumRegD + func->NumRegF + func->NumRegS < maxregs) return true; - Printf(TEXTCOLOR_ORANGE "%s is using too many registers (%d of max %d)! Function will not use native code.\n", func->PrintableName.GetChars(), func->NumRegA + func->NumRegD + func->NumRegF + func->NumRegS, maxregs); + Printf(TEXTCOLOR_ORANGE "%s is using too many registers (%d of max %d)! Function will not use native code.\n", func->PrintableName, func->NumRegA + func->NumRegD + func->NumRegF + func->NumRegS, maxregs); return false; } @@ -289,7 +289,7 @@ int VMScriptFunction::FirstScriptCall(VMFunction *func, VMValue *params, int num // rather than let GZDoom crash. if (func->VarFlags & VARF_Abstract) { - ThrowAbortException(X_OTHER, "attempt to call abstract function %s.", func->PrintableName.GetChars()); + ThrowAbortException(X_OTHER, "attempt to call abstract function %s.", func->PrintableName); } #ifdef HAVE_VM_JIT if (vm_jit && CanJit(static_cast(func))) @@ -320,7 +320,7 @@ int VMNativeFunction::NativeScriptCall(VMFunction *func, VMValue *params, int nu catch (CVMAbortException &err) { err.MaybePrintMessage(); - err.stacktrace.AppendFormat("Called from %s\n", func->PrintableName.GetChars()); + err.stacktrace.AppendFormat("Called from %s\n", func->PrintableName); throw; } } @@ -702,7 +702,7 @@ void CVMAbortException::MaybePrintMessage() CVMAbortException err(reason, moreinfo, ap); - err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName.GetChars(), sfunc->SourceFileName.GetChars(), sfunc->PCToLine(line)); + err.stacktrace.AppendFormat("Called from %s at %s, line %d\n", sfunc->PrintableName, sfunc->SourceFileName.GetChars(), sfunc->PCToLine(line)); throw err; } diff --git a/src/common/textures/formats/qoitexture.cpp b/src/common/textures/formats/qoitexture.cpp new file mode 100644 index 000000000..d0aa2fd81 --- /dev/null +++ b/src/common/textures/formats/qoitexture.cpp @@ -0,0 +1,213 @@ +/* +** qoitexture.cpp +** Texture class for QOI (Quite OK Image Format) images +** +**--------------------------------------------------------------------------- +** Copyright 2023 Cacodemon345 +** Copyright 2022 Dominic Szablewski +** All rights reserved. +** +** Permission is hereby granted, free of charge, to any person obtaining a copy +** of this software and associated documentation files (the "Software"), to deal +** in the Software without restriction, including without limitation the rights +** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +** copies of the Software, and to permit persons to whom the Software is +** furnished to do so, subject to the following conditions: +** +** The above copyright notice and this permission notice shall be included in all +** copies or substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +** SOFTWARE. +**--------------------------------------------------------------------------- +** +** +*/ + +#include "files.h" +#include "filesystem.h" +#include "bitmap.h" +#include "imagehelpers.h" +#include "image.h" + +#pragma pack(1) + +struct QOIHeader +{ + char magic[4]; + uint32_t width; + uint32_t height; + uint8_t channels; + uint8_t colorspace; +}; +#pragma pack() + +class FQOITexture : public FImageSource +{ +public: + FQOITexture(int lumpnum, QOIHeader& header); + PalettedPixels CreatePalettedPixels(int conversion) override; + int CopyPixels(FBitmap *bmp, int conversion) override; +}; + +FImageSource *QOIImage_TryCreate(FileReader &file, int lumpnum) +{ + QOIHeader header; + + if (file.GetLength() < (sizeof(header) + 8)) + { + return nullptr; + } + + file.Seek(0, FileReader::SeekSet); + file.Read((void *)&header, sizeof(header)); + + if (header.magic[0] != 'q' || header.magic[1] != 'o' || header.magic[2] != 'i' || header.magic[3] != 'f') + { + return nullptr; + } + + if (header.width == 0 || header.height == 0 || header.channels < 3 || header.channels > 4 || header.colorspace > 1) + { + return nullptr; + } + + return new FQOITexture(lumpnum, header); +} + +FQOITexture::FQOITexture(int lumpnum, QOIHeader& header) + : FImageSource(lumpnum) +{ + LeftOffset = TopOffset = 0; + Width = header.width; + Height = header.height; + if (header.channels == 3) bMasked = bTranslucent = false; +} + +PalettedPixels FQOITexture::CreatePalettedPixels(int conversion) +{ + FBitmap bitmap; + bitmap.Create(Width, Height); + CopyPixels(&bitmap, conversion); + const uint8_t *data = bitmap.GetPixels(); + + uint8_t *dest_p; + int dest_adv = Height; + int dest_rew = Width * Height - 1; + + PalettedPixels Pixels(Width * Height); + dest_p = Pixels.Data(); + + bool doalpha = conversion == luminance; + // Convert the source image from row-major to column-major format and remap it + for (int y = Height; y != 0; --y) + { + for (int x = Width; x != 0; --x) + { + int b = *data++; + int g = *data++; + int r = *data++; + int a = *data++; + if (a < 128) + *dest_p = 0; + else + *dest_p = ImageHelpers::RGBToPalette(doalpha, r, g, b); + dest_p += dest_adv; + } + dest_p -= dest_rew; + } + return Pixels; +} + +int FQOITexture::CopyPixels(FBitmap *bmp, int conversion) +{ + enum + { + QOI_OP_INDEX = 0x00, /* 00xxxxxx */ + QOI_OP_DIFF = 0x40, /* 01xxxxxx */ + QOI_OP_LUMA = 0x80, /* 10xxxxxx */ + QOI_OP_RUN = 0xc0, /* 11xxxxxx */ + QOI_OP_RGB = 0xfe, /* 11111110 */ + QOI_OP_RGBA = 0xff, /* 11111111 */ + + QOI_MASK_2 = 0xc0, /* 11000000 */ + }; + + constexpr auto QOI_COLOR_HASH = [](PalEntry C) { return (C.r * 3 + C.g * 5 + C.b * 7 + C.a * 11); }; + + auto lump = fileSystem.OpenFileReader(SourceLump); + auto bytes = lump.Read(); + if (bytes.Size() < 22) return 0; // error + PalEntry index[64] = {}; + PalEntry pe = 0xff000000; + + size_t p = 14, run = 0; + + size_t chunks_len = bytes.Size() - 8; + + for (int h = 0; h < Height; h++) + { + auto pixels = bmp->GetPixels() + h * bmp->GetPitch(); + for (int w = 0; w < Width; w++) + { + if (run > 0) + { + run--; + } + else if (p < chunks_len) + { + int b1 = bytes[p++]; + + if (b1 == QOI_OP_RGB) + { + pe.r = bytes[p++]; + pe.g = bytes[p++]; + pe.b = bytes[p++]; + } + else if (b1 == QOI_OP_RGBA) + { + pe.r = bytes[p++]; + pe.g = bytes[p++]; + pe.b = bytes[p++]; + pe.a = bytes[p++]; + } + else if ((b1 & QOI_MASK_2) == QOI_OP_INDEX) + { + pe = index[b1]; + } + else if ((b1 & QOI_MASK_2) == QOI_OP_DIFF) + { + pe.r += ((b1 >> 4) & 0x03) - 2; + pe.g += ((b1 >> 2) & 0x03) - 2; + pe.b += (b1 & 0x03) - 2; + } + else if ((b1 & QOI_MASK_2) == QOI_OP_LUMA) + { + int b2 = bytes[p++]; + int vg = (b1 & 0x3f) - 32; + pe.r += vg - 8 + ((b2 >> 4) & 0x0f); + pe.g += vg; + pe.b += vg - 8 + (b2 & 0x0f); + } + else if ((b1 & QOI_MASK_2) == QOI_OP_RUN) + { + run = (b1 & 0x3f); + } + + index[QOI_COLOR_HASH(pe) % 64] = pe; + } + } + + pixels[0] = pe.b; + pixels[1] = pe.g; + pixels[2] = pe.r; + pixels[3] = pe.a; + pixels += 4; + } + return bMasked? -1 : 0; +} diff --git a/src/common/textures/image.cpp b/src/common/textures/image.cpp index b32634948..e1939dfe1 100644 --- a/src/common/textures/image.cpp +++ b/src/common/textures/image.cpp @@ -322,6 +322,7 @@ FImageSource *DDSImage_TryCreate(FileReader &, int lumpnum); FImageSource *PCXImage_TryCreate(FileReader &, int lumpnum); FImageSource *TGAImage_TryCreate(FileReader &, int lumpnum); FImageSource *StbImage_TryCreate(FileReader &, int lumpnum); +FImageSource *QOIImage_TryCreate(FileReader &, int lumpnum); FImageSource *AnmImage_TryCreate(FileReader &, int lumpnum); FImageSource *RawPageImage_TryCreate(FileReader &, int lumpnum); FImageSource *FlatImage_TryCreate(FileReader &, int lumpnum); @@ -342,6 +343,7 @@ FImageSource * FImageSource::GetImage(int lumpnum, bool isflat) { DDSImage_TryCreate, false }, { PCXImage_TryCreate, false }, { StbImage_TryCreate, false }, + { QOIImage_TryCreate, false }, { TGAImage_TryCreate, false }, { AnmImage_TryCreate, false }, { StartupPageImage_TryCreate, false }, diff --git a/src/common/textures/textures.h b/src/common/textures/textures.h index da2c7a167..0d88f3843 100644 --- a/src/common/textures/textures.h +++ b/src/common/textures/textures.h @@ -217,6 +217,7 @@ protected: bool Masked = false; // Texture (might) have holes bool bHasCanvas = false; + bool bHdr = false; // only canvas textures for now. int8_t bTranslucent = -1; int8_t areacount = 0; // this is capped at 4 sections. @@ -253,6 +254,8 @@ public: bool isHardwareCanvas() const { return bHasCanvas; } // There's two here so that this can deal with software canvases in the hardware renderer later. bool isCanvas() const { return bHasCanvas; } + bool IsHDR() const { return bHdr; } + int GetSourceLump() { return SourceLump; } // needed by the scripted GetName method. void SetSourceLump(int sl) { SourceLump = sl; } bool FindHoles(const unsigned char * buffer, int w, int h); @@ -345,6 +348,12 @@ public: float aspectRatio; friend struct FCanvasTextureInfo; + friend class FTextureAnimator; + +private: + void SetHDR(bool hdr) { + bHdr = hdr; + } }; diff --git a/src/common/thirdparty/richpresence.cpp b/src/common/thirdparty/richpresence.cpp index 7a081adac..a8d8e8115 100644 --- a/src/common/thirdparty/richpresence.cpp +++ b/src/common/thirdparty/richpresence.cpp @@ -36,6 +36,7 @@ */ #include +#include #include "common/engine/printf.h" #include "discord_rpc.h" diff --git a/src/common/textures/formats/stb_image.h b/src/common/thirdparty/stb/stb_image.h similarity index 89% rename from src/common/textures/formats/stb_image.h rename to src/common/thirdparty/stb/stb_image.h index 44117802a..5e807a0a6 100644 --- a/src/common/textures/formats/stb_image.h +++ b/src/common/thirdparty/stb/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.23 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,10 +48,15 @@ LICENSE RECENT REVISION HISTORY: + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff + 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically 2.23 (2019-08-11) fix clang static analysis warning 2.22 (2019-03-04) gif fixes, fix warnings 2.21 (2019-02-25) fix typo in comment - 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs 2.19 (2018-02-11) fix warning 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings @@ -86,26 +91,37 @@ RECENT REVISION HISTORY: Jeremy Sawicki (handle all ImageNet JPGs) Optimizations & bugfixes Mikhail Morozov (1-bit BMP) Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) - Arseny Kapoulkine + Arseny Kapoulkine Simon Breuss (16-bit PNM) John-Mark Allen Carmelo J Fdez-Aguera Bug & warning fixes - Marc LeBlanc David Woo Guillaume George Martins Mozeiko - Christpher Lloyd Jerry Jansson Joseph Thomson Phil Jordan - Dave Moore Roy Eltham Hayaki Saito Nathan Reed - Won Chun Luke Graham Johan Duparc Nick Verigakis - the Horde3D community Thomas Ruf Ronny Chevalier github:rlyeh - Janez Zemva John Bartholomew Michal Cichon github:romigrou - Jonathan Blow Ken Hamada Tero Hanninen github:svdijk - Laurent Gomila Cort Stratton Sergio Gonzalez github:snagar - Aruelien Pocheville Thibault Reuille Cass Everitt github:Zelex - Ryamond Barbiero Paul Du Bois Engin Manap github:grim210 - Aldo Culquicondor Philipp Wiesemann Dale Weiler github:sammyhw - Oriol Ferrer Mesia Josh Tobin Matthew Gregan github:phprus - Julian Raschke Gregory Mullen Baldur Karlsson github:poppolopoppo - Christian Floisand Kevin Schmidt JR Smith github:darealshinji - Blazej Dariusz Roszkowski github:Michaelangel007 + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Eugene Golushkov Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko github:mosra + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + Jacko Dirks + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. */ #ifndef STBI_INCLUDE_STB_IMAGE_H @@ -125,7 +141,7 @@ RECENT REVISION HISTORY: // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel // // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) +// stbi_image_free(data); // // Standard parameters: // int *x -- outputs image width in pixels @@ -164,6 +180,32 @@ RECENT REVISION HISTORY: // // Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. // +// To query the width, height and component count of an image without having to +// decode the full file, you can use the stbi_info family of functions: +// +// int x,y,n,ok; +// ok = stbi_info(filename, &x, &y, &n); +// // returns ok=1 and sets x, y, n if image is a supported format, +// // 0 otherwise. +// +// Note that stb_image pervasively uses ints in its public API for sizes, +// including sizes of memory buffers. This is now part of the API and thus +// hard to change without causing breakage. As a result, the various image +// loaders all have certain limits on image size; these differ somewhat +// by format but generally boil down to either just under 2GB or just under +// 1GB. When the decoded image would be larger than this, stb_image decoding +// will fail. +// +// Additionally, stb_image will reject image files that have any of their +// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS, +// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit, +// the only way to have an image with such dimensions load correctly +// is for it to have a rather extreme aspect ratio. Either way, the +// assumption here is that such larger images are likely to be malformed +// or malicious. If you do need to load an image with individual dimensions +// larger than that, and it still fits in the overall size limit, you can +// #define STBI_MAX_DIMENSIONS on your own to be something larger. +// // =========================================================================== // // UNICODE: @@ -269,11 +311,10 @@ RECENT REVISION HISTORY: // // iPhone PNG support: // -// By default we convert iphone-formatted PNGs back to RGB, even though -// they are internally encoded differently. You can disable this conversion -// by calling stbi_convert_iphone_png_to_rgb(0), in which case -// you will always just get the native iphone "format" through (which -// is BGR stored in RGB). +// We optionally support converting iPhone-formatted PNGs (which store +// premultiplied BGRA) back to RGB, even though they're internally encoded +// differently. To enable this conversion, call +// stbi_convert_iphone_png_to_rgb(1). // // Call stbi_set_unpremultiply_on_load(1) as well to force a divide per // pixel to remove any premultiplied alpha *only* if the image file explicitly @@ -315,7 +356,14 @@ RECENT REVISION HISTORY: // - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still // want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB // - +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. #ifndef STBI_NO_STDIO #include @@ -434,7 +482,7 @@ STBIDEF int stbi_is_hdr_from_file(FILE *f); // get a VERY brief reason for failure -// NOT THREADSAFE +// on most compilers (and ALL modern mainstream compilers) this is threadsafe STBIDEF const char *stbi_failure_reason (void); // free the loaded image -- this is just free() @@ -467,6 +515,13 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); // flip the image vertically, so the first pixel in the output array is the bottom left STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply); +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert); +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + // ZLIB client - used by PNG, available for other purposes STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); @@ -563,8 +618,25 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #define stbi_inline __forceinline #endif +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif -#ifdef _MSC_VER + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#if defined(_MSC_VER) || defined(__SYMBIAN32__) typedef unsigned short stbi__uint16; typedef signed short stbi__int16; typedef unsigned int stbi__uint32; @@ -593,7 +665,7 @@ typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; #ifdef STBI_HAS_LROTL #define stbi_lrot(x,y) _lrotl(x,y) #else - #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31))) #endif #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) @@ -707,14 +779,21 @@ static int stbi__sse2_available(void) #ifdef STBI_NEON #include -// assume GCC or Clang on ARM targets +#ifdef _MSC_VER +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name +#else #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) #endif +#endif #ifndef STBI_SIMD_ALIGN #define STBI_SIMD_ALIGN(type, name) type name #endif +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + /////////////////////////////////////////////// // // stbi__context struct and start_xxx functions @@ -732,6 +811,7 @@ typedef struct int read_from_callbacks; int buflen; stbi_uc buffer_start[128]; + int callback_already_read; stbi_uc *img_buffer, *img_buffer_end; stbi_uc *img_buffer_original, *img_buffer_original_end; @@ -745,6 +825,7 @@ static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) { s->io.read = NULL; s->read_from_callbacks = 0; + s->callback_already_read = 0; s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; } @@ -756,7 +837,8 @@ static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void * s->io_user_data = user; s->buflen = sizeof(s->buffer_start); s->read_from_callbacks = 1; - s->img_buffer_original = s->buffer_start; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; stbi__refill_buffer(s); s->img_buffer_original_end = s->img_buffer_end; } @@ -770,12 +852,17 @@ static int stbi__stdio_read(void *user, char *data, int size) static void stbi__stdio_skip(void *user, int n) { + int ch; fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } } static int stbi__stdio_eof(void *user) { - return feof((FILE*) user); + return feof((FILE*) user) || ferror((FILE *) user); } static stbi_io_callbacks stbi__stdio_callbacks = @@ -871,21 +958,27 @@ static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); static int stbi__pnm_test(stbi__context *s); static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__pnm_is16(stbi__context *s); #endif -// this is not threadsafe -static const char *stbi__g_failure_reason; +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; STBIDEF const char *stbi_failure_reason(void) { return stbi__g_failure_reason; } +#ifndef STBI_NO_FAILURE_STRINGS static int stbi__err(const char *str) { stbi__g_failure_reason = str; return 0; } +#endif static void *stbi__malloc(size_t size) { @@ -924,11 +1017,13 @@ static int stbi__mul2sizes_valid(int a, int b) return a <= INT_MAX/b; } +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow static int stbi__mad2sizes_valid(int a, int b, int add) { return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); } +#endif // returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow static int stbi__mad3sizes_valid(int a, int b, int c, int add) @@ -938,7 +1033,7 @@ static int stbi__mad3sizes_valid(int a, int b, int c, int add) } // returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) { return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && @@ -946,12 +1041,14 @@ static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) } #endif +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) // mallocs with size overflow checking static void *stbi__malloc_mad2(int a, int b, int add) { if (!stbi__mad2sizes_valid(a, b, add)) return NULL; return stbi__malloc(a*b + add); } +#endif static void *stbi__malloc_mad3(int a, int b, int c, int add) { @@ -959,7 +1056,7 @@ static void *stbi__malloc_mad3(int a, int b, int c, int add) return stbi__malloc(a*b*c + add); } -#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM) static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) { if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; @@ -967,6 +1064,23 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) } #endif +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two signed shorts is valid, 0 on overflow. +static int stbi__mul2shorts_valid(short a, short b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + // stbi__err - error // stbi__errpf - error returning pointer to float // stbi__errpuc - error returning pointer to unsigned char @@ -995,13 +1109,29 @@ static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); #endif -static int stbi__vertically_flip_on_load = 0; +static int stbi__vertically_flip_on_load_global = 0; STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) { - stbi__vertically_flip_on_load = flag_true_if_should_flip; + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; } +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) { memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields @@ -1009,9 +1139,8 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order ri->num_channels = 0; - #ifndef STBI_NO_JPEG - if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); - #endif + // test the formats with a very explicit header first (at least a FOURCC + // or distinctive magic number first) #ifndef STBI_NO_PNG if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); #endif @@ -1023,10 +1152,19 @@ static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int re #endif #ifndef STBI_NO_PSD if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); #endif #ifndef STBI_NO_PIC if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); #endif + + // then the formats that can end up attempting to load with just 1 or 2 + // bytes matching expectations; these are prone to false positives, so + // try them later + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif #ifndef STBI_NO_PNM if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); #endif @@ -1111,8 +1249,8 @@ static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int byt stbi_uc *bytes = (stbi_uc *)image; for (slice = 0; slice < z; ++slice) { - stbi__vertical_flip(bytes, w, h, bytes_per_pixel); - bytes += slice_size; + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; } } #endif @@ -1125,8 +1263,10 @@ static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, if (result == NULL) return NULL; + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + if (ri.bits_per_channel != 8) { - STBI_ASSERT(ri.bits_per_channel == 16); result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); ri.bits_per_channel = 8; } @@ -1149,8 +1289,10 @@ static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, if (result == NULL) return NULL; + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + if (ri.bits_per_channel != 16) { - STBI_ASSERT(ri.bits_per_channel == 8); result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); ri.bits_per_channel = 16; } @@ -1178,12 +1320,12 @@ static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, in #ifndef STBI_NO_STDIO -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); #endif -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) { return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); @@ -1193,16 +1335,16 @@ STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wch static FILE *stbi__fopen(char const *filename, char const *mode) { FILE *f; -#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8) wchar_t wMode[64]; wchar_t wFilename[1024]; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename))) return 0; - if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode))) return 0; -#if _MSC_VER >= 1400 +#if defined(_MSC_VER) && _MSC_VER >= 1400 if (0 != _wfopen_s(&f, wFilename, wMode)) f = 0; #else @@ -1300,15 +1442,15 @@ STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *u STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { unsigned char *result; - stbi__context s; - stbi__start_mem(&s,buffer,len); + stbi__context s; + stbi__start_mem(&s,buffer,len); result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); if (stbi__vertically_flip_on_load) { - stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); } - return result; + return result; } #endif @@ -1453,6 +1595,7 @@ enum static void stbi__refill_buffer(stbi__context *s) { int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); if (n == 0) { // at end of file, treat same as if from memory, but need to handle case // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file @@ -1477,6 +1620,9 @@ stbi_inline static stbi_uc stbi__get8(stbi__context *s) return 0; } +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else stbi_inline static int stbi__at_eof(stbi__context *s) { if (s->io.read) { @@ -1488,9 +1634,14 @@ stbi_inline static int stbi__at_eof(stbi__context *s) return s->img_buffer >= s->img_buffer_end; } +#endif +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else static void stbi__skip(stbi__context *s, int n) { + if (n == 0) return; // already there! if (n < 0) { s->img_buffer = s->img_buffer_end; return; @@ -1505,7 +1656,11 @@ static void stbi__skip(stbi__context *s, int n) } s->img_buffer += n; } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) { if (s->io.read) { @@ -1529,18 +1684,27 @@ static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) } else return 0; } +#endif +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else static int stbi__get16be(stbi__context *s) { int z = stbi__get8(s); return (z << 8) + stbi__get8(s); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else static stbi__uint32 stbi__get32be(stbi__context *s) { stbi__uint32 z = stbi__get16be(s); return (z << 16) + stbi__get16be(s); } +#endif #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) // nothing @@ -1556,13 +1720,16 @@ static int stbi__get16le(stbi__context *s) static stbi__uint32 stbi__get32le(stbi__context *s) { stbi__uint32 z = stbi__get16le(s); - return z + (stbi__get16le(s) << 16); + z += (stbi__uint32)stbi__get16le(s) << 16; + return z; } #endif #define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings - +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else ////////////////////////////////////////////////////////////////////////////// // // generic converter from built-in img_n to req_comp @@ -1578,7 +1745,11 @@ static stbi_uc stbi__compute_y(int r, int g, int b) { return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; @@ -1614,7 +1785,7 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; - default: STBI_ASSERT(0); + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); } #undef STBI__CASE } @@ -1622,12 +1793,20 @@ static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int r STBI_FREE(data); return good; } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else static stbi__uint16 stbi__compute_y_16(int r, int g, int b) { return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); } +#endif +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) { int i,j; @@ -1663,7 +1842,7 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; - default: STBI_ASSERT(0); + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); } #undef STBI__CASE } @@ -1671,6 +1850,7 @@ static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int r STBI_FREE(data); return good; } +#endif #ifndef STBI_NO_LINEAR static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) @@ -1823,9 +2003,12 @@ static int stbi__build_huffman(stbi__huffman *h, int *count) int i,j,k=0; unsigned int code; // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } h->size[k] = 0; // compute actual symbols (from jpeg spec) @@ -1950,6 +2133,8 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) // convert the huffman code to the symbol id c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); // convert the id to a symbol @@ -1968,14 +2153,14 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) unsigned int k; int sgn; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing - sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) k = stbi_lrot(j->code_buffer, n); - STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; j->code_bits -= n; - return k + (stbi__jbias[n] & ~sgn); + return k + (stbi__jbias[n] & (sgn - 1)); } // get some unsigned bits @@ -1983,6 +2168,7 @@ stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { unsigned int k; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing k = stbi_lrot(j->code_buffer, n); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; @@ -1994,6 +2180,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { unsigned int k; if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing k = j->code_buffer; j->code_buffer <<= 1; --j->code_bits; @@ -2025,14 +2212,16 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); t = stbi__jpeg_huff_decode(j, hdc); - if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + if (t < 0 || t > 15) return stbi__err("bad huffman code","Corrupt JPEG"); // 0 all the ac values now so we can do it 32-bits at a time memset(data,0,64*sizeof(data[0])); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); data[0] = (short) (dc * dequant[0]); // decode AC components, see JPEG spec @@ -2046,6 +2235,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; // decode into unzigzag'd location @@ -2082,11 +2272,14 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__ // first scan for DC coefficient, must be first memset(data,0,64*sizeof(data[0])); // 0 all the ac values now t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; - data[0] = (short) (dc << j->succ_low); + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + data[0] = (short) (dc * (1 << j->succ_low)); } else { // refinement scan for DC coefficient if (stbi__jpeg_get_bit(j)) @@ -2120,10 +2313,11 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) ((r >> 8) << shift); + data[zig] = (short) ((r >> 8) * (1 << shift)); } else { int rs = stbi__jpeg_huff_decode(j, hac); if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); @@ -2141,7 +2335,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ } else { k += r; zig = stbi__jpeg_dezigzag[k++]; - data[zig] = (short) (stbi__extend_receive(j,s) << shift); + data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift)); } } } while (k <= j->spec_end); @@ -2940,6 +3134,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m) sizes[i] = stbi__get8(z->s); n += sizes[i]; } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! L -= 17; if (tc == 0) { if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; @@ -3072,6 +3267,8 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); c = stbi__get8(s); if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); s->img_n = c; @@ -3103,6 +3300,13 @@ static int stbi__process_frame_header(stbi__jpeg *z, int scan) if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; } + // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios + // and I've never seen a non-corrupted JPEG file actually use them + for (i=0; i < s->img_n; ++i) { + if (h_max % z->img_comp[i].h != 0) return stbi__err("bad H","Corrupt JPEG"); + if (v_max % z->img_comp[i].v != 0) return stbi__err("bad V","Corrupt JPEG"); + } + // compute interleaved mcu info z->img_h_max = h_max; z->img_v_max = v_max; @@ -3180,6 +3384,28 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) return 1; } +static int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + while (x == 255) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + // decode image to YCbCr format static int stbi__decode_jpeg_image(stbi__jpeg *j) { @@ -3196,25 +3422,22 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j) if (!stbi__process_scan_header(j)) return 0; if (!stbi__parse_entropy_coded_data(j)) return 0; if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } - } + j->marker = stbi__skip_jpeg_junk_at_end(j); // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); } else if (stbi__DNL(m)) { int Ld = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s); if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); } else { - if (!stbi__process_marker(j, m)) return 0; + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); } - m = stbi__get_marker(j); } if (j->progressive) stbi__jpeg_finish(j); @@ -3658,6 +3881,10 @@ static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp else decode_n = z->s->img_n; + // nothing to do if no components requested; check this now to avoid + // accessing uninitialized coutput[0] later + if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; } + // resample and color-convert { int k; @@ -3800,6 +4027,8 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re { unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); @@ -3812,6 +4041,8 @@ static int stbi__jpeg_test(stbi__context *s) { int r; stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; stbi__setup_jpeg(j); r = stbi__decode_jpeg_header(j, STBI__SCAN_type); @@ -3836,6 +4067,8 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) { int result; stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; result = stbi__jpeg_info_raw(j, x, y, comp); STBI_FREE(j); @@ -3855,6 +4088,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) // fast-way is faster to check than jpeg huffman, but slow way is slower #define STBI__ZFAST_BITS 9 // accelerate all cases in default tables #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) +#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet // zlib-style huffman encoding // (jpegs packs from left, zlib from right, so can't share code) @@ -3864,8 +4098,8 @@ typedef struct stbi__uint16 firstcode[16]; int maxcode[17]; stbi__uint16 firstsymbol[16]; - stbi_uc size[288]; - stbi__uint16 value[288]; + stbi_uc size[STBI__ZNSYMS]; + stbi__uint16 value[STBI__ZNSYMS]; } stbi__zhuffman; stbi_inline static int stbi__bitreverse16(int n) @@ -3952,16 +4186,23 @@ typedef struct stbi__zhuffman z_length, z_distance; } stbi__zbuf; +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) { - if (z->zbuffer >= z->zbuffer_end) return 0; - return *z->zbuffer++; + return stbi__zeof(z) ? 0 : *z->zbuffer++; } static void stbi__fill_bits(stbi__zbuf *z) { do { - STBI_ASSERT(z->code_buffer < (1U << z->num_bits)); + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; z->num_bits += 8; } while (z->num_bits <= 24); @@ -3986,10 +4227,11 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) for (s=STBI__ZFAST_BITS+1; ; ++s) if (k < z->maxcode[s]) break; - if (s == 16) return -1; // invalid code! + if (s >= 16) return -1; // invalid code! // code size is s, so: b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; - STBI_ASSERT(z->size[b] == s); + if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. a->code_buffer >>= s; a->num_bits -= s; return z->value[b]; @@ -3998,7 +4240,12 @@ static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) { int b,s; - if (a->num_bits < 16) stbi__fill_bits(a); + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + return -1; /* report error for unexpected end of data. */ + } + stbi__fill_bits(a); + } b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; if (b) { s = b >> 9; @@ -4012,13 +4259,16 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes { char *q; - int cur, limit, old_limit; + unsigned int cur, limit, old_limit; z->zout = zout; if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); - cur = (int) (z->zout - z->zout_start); - limit = old_limit = (int) (z->zout_end - z->zout_start); - while (cur + n > limit) + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); limit *= 2; + } q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); STBI_NOTUSED(old_limit); if (q == NULL) return stbi__err("outofmem", "Out of memory"); @@ -4061,11 +4311,12 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) a->zout = zout; return 1; } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data z -= 257; len = stbi__zlength_base[z]; if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data dist = stbi__zdist_base[z]; if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); @@ -4116,11 +4367,12 @@ static int stbi__compute_huffman_codes(stbi__zbuf *a) c = stbi__zreceive(a,2)+3; if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); fill = lencodes[n-1]; - } else if (c == 17) + } else if (c == 17) { c = stbi__zreceive(a,3)+3; - else { - STBI_ASSERT(c == 18); + } else if (c == 18) { c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); } if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); memset(lencodes+n, fill, c); @@ -4146,7 +4398,7 @@ static int stbi__parse_uncompressed_block(stbi__zbuf *a) a->code_buffer >>= 8; a->num_bits -= 8; } - STBI_ASSERT(a->num_bits == 0); + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); // now fill header the normal way while (k < 4) header[k++] = stbi__zget8(a); @@ -4168,6 +4420,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) int cm = cmf & 15; /* int cinfo = cmf >> 4; */ int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png @@ -4175,7 +4428,7 @@ static int stbi__parse_zlib_header(stbi__zbuf *a) return 1; } -static const stbi_uc stbi__zdefault_length[288] = +static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] = { 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, @@ -4221,7 +4474,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) } else { if (type == 1) { // use fixed code lengths - if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0; if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; } else { if (!stbi__compute_huffman_codes(a)) return 0; @@ -4429,7 +4682,7 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r return stbi__err("invalid filter","Corrupt PNG"); if (depth < 8) { - STBI_ASSERT(img_width_bytes <= x); + if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place filter_bytes = 1; width = img_width_bytes; @@ -4617,6 +4870,7 @@ static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint3 // de-interlacing final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + if (!final) return stbi__err("outofmem", "Out of memory"); for (p=0; p < 7; ++p) { int xorig[] = { 0,4,0,2,0,1,0 }; int yorig[] = { 0,0,4,0,2,0,1 }; @@ -4737,19 +4991,46 @@ static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int return 1; } -static int stbi__unpremultiply_on_load = 0; -static int stbi__de_iphone_flag = 0; +static int stbi__unpremultiply_on_load_global = 0; +static int stbi__de_iphone_flag_global = 0; STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) { - stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply; } STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) { - stbi__de_iphone_flag = flag_true_if_should_convert; + stbi__de_iphone_flag_global = flag_true_if_should_convert; } +#ifndef STBI_THREAD_LOCAL +#define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global +#define stbi__de_iphone_flag stbi__de_iphone_flag_global +#else +static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; +static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; + +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; + stbi__unpremultiply_on_load_set = 1; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag_local = flag_true_if_should_convert; + stbi__de_iphone_flag_set = 1; +} + +#define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \ + ? stbi__unpremultiply_on_load_local \ + : stbi__unpremultiply_on_load_global) +#define stbi__de_iphone_flag (stbi__de_iphone_flag_set \ + ? stbi__de_iphone_flag_local \ + : stbi__de_iphone_flag_global) +#endif // STBI_THREAD_LOCAL + static void stbi__de_iphone(stbi__png *z) { stbi__context *s = z->s; @@ -4824,8 +5105,10 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); first = 0; if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); - s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); - s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); @@ -4837,14 +5120,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; } else { // if paletted, then pal_n is our final components, and // img_n is # components to decompress/filter. s->img_n = 1; if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS } + // even with SCAN_header, have to scan to see if we have a tRNS break; } @@ -4876,6 +5158,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } if (z->depth == 16) { for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is } else { @@ -4888,7 +5172,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) case STBI__PNG_TYPE('I','D','A','T'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); if ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) { stbi__uint32 idata_limit_old = idata_limit; @@ -4942,6 +5232,8 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) ++s->img_n; } STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); return 1; } @@ -4972,10 +5264,12 @@ static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, st void *result=NULL; if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { - if (p->depth < 8) + if (p->depth <= 8) ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; else - ri->bits_per_channel = p->depth; + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); result = p->out; p->out = NULL; if (req_comp && req_comp != p->s->img_out_n) { @@ -5111,7 +5405,7 @@ static int stbi__shiftsigned(unsigned int v, int shift, int bits) v <<= -shift; else v >>= shift; - STBI_ASSERT(v >= 0 && v < 256); + STBI_ASSERT(v < 256); v >>= (8-bits); STBI_ASSERT(bits >= 0 && bits <= 8); return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; @@ -5121,8 +5415,35 @@ typedef struct { int bpp, offset, hsz; unsigned int mr,mg,mb,ma, all_a; + int extra_read; } stbi__bmp_data; +static int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress) +{ + // BI_BITFIELDS specifies masks explicitly, don't override + if (compress == 3) + return 1; + + if (compress == 0) { + if (info->bpp == 16) { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } else if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + // otherwise, use defaults, which is all-0 + info->mr = info->mg = info->mb = info->ma = 0; + } + return 1; + } + return 0; // error +} + static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) { int hsz; @@ -5133,6 +5454,9 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->offset = stbi__get32le(s); info->hsz = hsz = stbi__get32le(s); info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); if (hsz == 12) { @@ -5147,6 +5471,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) if (hsz != 12) { int compress = stbi__get32le(s); if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + if (compress >= 4) return stbi__errpuc("BMP JPEG/PNG", "BMP type not supported: unsupported compression"); // this includes PNG/JPEG modes + if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc("bad BMP", "bad BMP"); // bitfields requires 16 or 32 bits/pixel stbi__get32le(s); // discard sizeof stbi__get32le(s); // discard hres stbi__get32le(s); // discard vres @@ -5161,21 +5487,12 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) } if (info->bpp == 16 || info->bpp == 32) { if (compress == 0) { - if (info->bpp == 32) { - info->mr = 0xffu << 16; - info->mg = 0xffu << 8; - info->mb = 0xffu << 0; - info->ma = 0xffu << 24; - info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 - } else { - info->mr = 31u << 10; - info->mg = 31u << 5; - info->mb = 31u << 0; - } + stbi__bmp_set_mask_defaults(info, compress); } else if (compress == 3) { info->mr = stbi__get32le(s); info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); + info->extra_read += 12; // not documented, but generated by photoshop and handled by mspaint if (info->mr == info->mg && info->mg == info->mb) { // ?!?!? @@ -5185,6 +5502,7 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) return stbi__errpuc("bad BMP", "bad BMP"); } } else { + // V4/V5 header int i; if (hsz != 108 && hsz != 124) return stbi__errpuc("bad BMP", "bad BMP"); @@ -5192,6 +5510,8 @@ static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) info->mg = stbi__get32le(s); info->mb = stbi__get32le(s); info->ma = stbi__get32le(s); + if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs + stbi__bmp_set_mask_defaults(info, compress); stbi__get32le(s); // discard color space for (i=0; i < 12; ++i) stbi__get32le(s); // discard color space parameters @@ -5224,6 +5544,9 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req flip_vertically = ((int) s->img_y) > 0; s->img_y = abs((int) s->img_y); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + mr = info.mr; mg = info.mg; mb = info.mb; @@ -5232,10 +5555,29 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req if (info.hsz == 12) { if (info.bpp < 24) - psize = (info.offset - 14 - 24) / 3; + psize = (info.offset - info.extra_read - 24) / 3; } else { if (info.bpp < 16) - psize = (info.offset - 14 - info.hsz) >> 2; + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); + } } if (info.bpp == 24 && ma == 0xff000000) @@ -5263,7 +5605,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req if (info.hsz != 12) stbi__get8(s); pal[i][3] = 255; } - stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); if (info.bpp == 1) width = (s->img_x + 7) >> 3; else if (info.bpp == 4) width = (s->img_x + 1) >> 1; else if (info.bpp == 8) width = s->img_x; @@ -5312,7 +5654,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; int z = 0; int easy=0; - stbi__skip(s, info.offset - 14 - info.hsz); + stbi__skip(s, info.offset - info.extra_read - info.hsz); if (info.bpp == 24) width = 3 * s->img_x; else if (info.bpp == 16) width = 2*s->img_x; else /* bpp = 32 and pad = 0 */ width=0; @@ -5330,6 +5672,7 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } } for (j=0; j < (int) s->img_y; ++j) { if (easy) { @@ -5554,6 +5897,9 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req STBI_NOTUSED(tga_x_origin); // @TODO STBI_NOTUSED(tga_y_origin); // @TODO + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + // do a tiny bit of precessing if ( tga_image_type >= 8 ) { @@ -5593,6 +5939,11 @@ static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req // do I need to load a palette? if ( tga_indexed) { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + // any data to skip? (offset usually = 0) stbi__skip(s, tga_palette_start ); // load the palette @@ -5801,6 +6152,9 @@ static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req h = stbi__get32be(s); w = stbi__get32be(s); + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + // Make sure the depth is 8 bits. bitdepth = stbi__get16be(s); if (bitdepth != 8 && bitdepth != 16) @@ -6155,6 +6509,10 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c x = stbi__get16be(s); y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); @@ -6164,6 +6522,7 @@ static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_c // intermediate buffer is RGBA result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + if (!result) return stbi__errpuc("outofmem", "Out of memory"); memset(result, 0xff, x*y*4); if (!stbi__pic_load_core(s,x,y,comp, result)) { @@ -6202,7 +6561,7 @@ typedef struct int w,h; stbi_uc *out; // output buffer (always 4 components) stbi_uc *background; // The current "background" as far as a gif is concerned - stbi_uc *history; + stbi_uc *history; int flags, bgindex, ratio, transparent, eflags; stbi_uc pal[256][4]; stbi_uc lpal[256][4]; @@ -6263,6 +6622,9 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in g->ratio = stbi__get8(s); g->transparent = -1; + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments if (is_info) return 1; @@ -6276,6 +6638,7 @@ static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_in static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) { stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!g) return stbi__err("outofmem", "Out of memory"); if (!stbi__gif_header(s, g, comp, 1)) { STBI_FREE(g); stbi__rewind( s ); @@ -6290,7 +6653,7 @@ static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) { stbi_uc *p, *c; - int idx; + int idx; // recurse to decode the prefixes, since the linked-list is backwards, // and working backwards through an interleaved image would be nasty @@ -6299,12 +6662,12 @@ static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) if (g->cur_y >= g->max_y) return; - idx = g->cur_x + g->cur_y; + idx = g->cur_x + g->cur_y; p = &g->out[idx]; - g->history[idx / 4] = 1; + g->history[idx / 4] = 1; c = &g->color_table[g->codes[code].suffix * 4]; - if (c[3] > 128) { // don't render transparent pixels; + if (c[3] > 128) { // don't render transparent pixels; p[0] = c[2]; p[1] = c[1]; p[2] = c[0]; @@ -6413,14 +6776,14 @@ static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) // two back is the image from two frames ago, used for a very specific disposal format static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) { - int dispose; - int first_frame; - int pi; - int pcount; + int dispose; + int first_frame; + int pi; + int pcount; STBI_NOTUSED(req_comp); // on first frame, any non-written pixels get the background colour (non-transparent) - first_frame = 0; + first_frame = 0; if (g->out == 0) { if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) @@ -6432,17 +6795,17 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i if (!g->out || !g->background || !g->history) return stbi__errpuc("outofmem", "Out of memory"); - // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; // background colour is only used for pixels that are not rendered first frame, after that "background" - // color refers to the color that was there the previous frame. + // color refers to the color that was there the previous frame. memset(g->out, 0x00, 4 * pcount); memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) memset(g->history, 0x00, pcount); // pixels that were affected previous frame - first_frame = 1; + first_frame = 1; } else { - // second frame - how do we dispoase of the previous one? - dispose = (g->eflags & 0x1C) >> 2; - pcount = g->w * g->h; + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; if ((dispose == 3) && (two_back == 0)) { dispose = 2; // if I don't have an image to revert back to, default to the old background @@ -6451,32 +6814,32 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i if (dispose == 3) { // use previous graphic for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { - memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); } } - } else if (dispose == 2) { - // restore what was changed last frame to background before that frame; + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; for (pi = 0; pi < pcount; ++pi) { if (g->history[pi]) { - memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); } } } else { - // This is a non-disposal case eithe way, so just + // This is a non-disposal case eithe way, so just // leave the pixels as is, and they will become the new background // 1: do not dispose // 0: not specified. } - // background is what out is after the undoing of the previou frame; - memcpy( g->background, g->out, 4 * g->w * g->h ); + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); } - // clear my history; + // clear my history; memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame for (;;) { - int tag = stbi__get8(s); + int tag = stbi__get8(s); switch (tag) { case 0x2C: /* Image Descriptor */ { @@ -6521,19 +6884,19 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } else if (g->flags & 0x80) { g->color_table = (stbi_uc *) g->pal; } else - return stbi__errpuc("missing color table", "Corrupt GIF"); + return stbi__errpuc("missing color table", "Corrupt GIF"); o = stbi__process_gif_raster(s, g); if (!o) return NULL; - // if this was the first frame, - pcount = g->w * g->h; + // if this was the first frame, + pcount = g->w * g->h; if (first_frame && (g->bgindex > 0)) { // if first frame, any pixel not drawn to gets the background color for (pi = 0; pi < pcount; ++pi) { if (g->history[pi] == 0) { - g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; - memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); } } } @@ -6544,7 +6907,7 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i case 0x21: // Comment Extension. { int len; - int ext = stbi__get8(s); + int ext = stbi__get8(s); if (ext == 0xF9) { // Graphic Control Extension. len = stbi__get8(s); if (len == 4) { @@ -6553,23 +6916,23 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i // unset old transparent if (g->transparent >= 0) { - g->pal[g->transparent][3] = 255; - } + g->pal[g->transparent][3] = 255; + } if (g->eflags & 0x01) { g->transparent = stbi__get8(s); if (g->transparent >= 0) { - g->pal[g->transparent][3] = 0; + g->pal[g->transparent][3] = 0; } } else { // don't need transparent - stbi__skip(s, 1); - g->transparent = -1; + stbi__skip(s, 1); + g->transparent = -1; } } else { stbi__skip(s, len); break; } - } + } while ((len = stbi__get8(s)) != 0) { stbi__skip(s, len); } @@ -6585,18 +6948,35 @@ static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, i } } +static void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays) +{ + STBI_FREE(g->out); + STBI_FREE(g->history); + STBI_FREE(g->background); + + if (out) STBI_FREE(out); + if (delays && *delays) STBI_FREE(*delays); + return stbi__errpuc("outofmem", "Out of memory"); +} + static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) { if (stbi__gif_test(s)) { - int layers = 0; + int layers = 0; stbi_uc *u = 0; stbi_uc *out = 0; - stbi_uc *two_back = 0; + stbi_uc *two_back = 0; stbi__gif g; - int stride; + int stride; + int out_size = 0; + int delays_size = 0; + + STBI_NOTUSED(out_size); + STBI_NOTUSED(delays_size); + memset(&g, 0, sizeof(g)); if (delays) { - *delays = 0; + *delays = 0; } do { @@ -6606,44 +6986,61 @@ static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, if (u) { *x = g.w; *y = g.h; - ++layers; - stride = g.w * g.h * 4; + ++layers; + stride = g.w * g.h * 4; if (out) { - out = (stbi_uc*) STBI_REALLOC( out, layers * stride ); + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride ); + if (!tmp) + return stbi__load_gif_main_outofmem(&g, out, delays); + else { + out = (stbi_uc*) tmp; + out_size = layers * stride; + } + if (delays) { - *delays = (int*) STBI_REALLOC( *delays, sizeof(int) * layers ); + int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers ); + if (!new_delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + *delays = new_delays; + delays_size = layers * sizeof(int); } } else { - out = (stbi_uc*)stbi__malloc( layers * stride ); + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (!out) + return stbi__load_gif_main_outofmem(&g, out, delays); + out_size = layers * stride; if (delays) { - *delays = (int*) stbi__malloc( layers * sizeof(int) ); + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + if (!*delays) + return stbi__load_gif_main_outofmem(&g, out, delays); + delays_size = layers * sizeof(int); } } - memcpy( out + ((layers - 1) * stride), u, stride ); + memcpy( out + ((layers - 1) * stride), u, stride ); if (layers >= 2) { - two_back = out - 2 * stride; + two_back = out - 2 * stride; } if (delays) { - (*delays)[layers - 1U] = g.delay; + (*delays)[layers - 1U] = g.delay; } } - } while (u != 0); + } while (u != 0); - // free temp buffer; - STBI_FREE(g.out); - STBI_FREE(g.history); - STBI_FREE(g.background); + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); - // do the final conversion after loading everything; + // do the final conversion after loading everything; if (req_comp && req_comp != 4) out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); - *z = layers; + *z = layers; return out; } else { - return stbi__errpuc("not GIF", "Image was not as a gif type."); + return stbi__errpuc("not GIF", "Image was not as a gif type."); } } @@ -6661,7 +7058,7 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req *y = g.h; // moved conversion to after successful load so that the same - // can be done for multiple frames. + // can be done for multiple frames. if (req_comp && req_comp != 4) u = stbi__convert_format(u, 4, req_comp, g.w, g.h); } else if (g.out) { @@ -6669,9 +7066,9 @@ static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req STBI_FREE(g.out); } - // free buffers needed for multiple frame loading; + // free buffers needed for multiple frame loading; STBI_FREE(g.history); - STBI_FREE(g.background); + STBI_FREE(g.background); return u; } @@ -6796,6 +7193,9 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re token += 3; width = (int) strtol(token, NULL, 10); + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + *x = width; *y = height; @@ -6864,12 +7264,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re // Run value = stbi__get8(s); count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = stbi__get8(s); } @@ -6938,9 +7338,10 @@ static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) info.all_a = 255; p = stbi__bmp_parse_header(s, &info); - stbi__rewind( s ); - if (p == NULL) + if (p == NULL) { + stbi__rewind( s ); return 0; + } if (x) *x = s->img_x; if (y) *y = s->img_y; if (comp) { @@ -7006,8 +7407,8 @@ static int stbi__psd_is16(stbi__context *s) stbi__rewind( s ); return 0; } - (void) stbi__get32be(s); - (void) stbi__get32be(s); + STBI_NOTUSED(stbi__get32be(s)); + STBI_NOTUSED(stbi__get32be(s)); depth = stbi__get16be(s); if (depth != 16) { stbi__rewind( s ); @@ -7086,7 +7487,6 @@ static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) // Known limitations: // Does not support comments in the header section // Does not support ASCII image data (formats P2 and P3) -// Does not support 16-bit-per-channel #ifndef STBI_NO_PNM @@ -7107,22 +7507,33 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req stbi_uc *out; STBI_NOTUSED(ri); - if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n); + if (ri->bits_per_channel == 0) return 0; + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + *x = s->img_x; *y = s->img_y; if (comp) *comp = s->img_n; - if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0)) return stbi__errpuc("too large", "PNM too large"); - out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } if (out == NULL) return out; // stbi__convert_format frees input on failure } return out; @@ -7159,6 +7570,8 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { value = value*10 + (*c - '0'); *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); } return value; @@ -7189,17 +7602,29 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) stbi__pnm_skip_whitespace(s, &c); *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); maxv = stbi__pnm_getinteger(s, &c); // read max value - - if (maxv > 255) - return stbi__err("max value > 255", "PPM image not 8-bit"); + if (maxv > 65535) + return stbi__err("max value > 65535", "PPM image supports only 8-bit and 16-bit images"); + else if (maxv > 255) + return 16; else - return 1; + return 8; +} + +static int stbi__pnm_is16(stbi__context *s) +{ + if (stbi__pnm_info(s, NULL, NULL, NULL) == 16) + return 1; + return 0; } #endif @@ -7255,6 +7680,9 @@ static int stbi__is_16_main(stbi__context *s) if (stbi__psd_is16(s)) return 1; #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_is16(s)) return 1; + #endif return 0; } @@ -7334,7 +7762,7 @@ STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user /* revision history: - 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs 2.19 (2018-02-11) fix warning 2.18 (2018-01-30) fix warnings 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug diff --git a/src/common/thirdparty/stb/stb_sprintf.c b/src/common/thirdparty/stb/stb_sprintf.c new file mode 100644 index 000000000..948362c3b --- /dev/null +++ b/src/common/thirdparty/stb/stb_sprintf.c @@ -0,0 +1,21 @@ +#define STB_SPRINTF_IMPLEMENTATION +#define STB_SPRINTF_UTF8_CHARS +#include "stb_sprintf.h" + +// We still need our own wrappers because they use a size_t for count, not an int. +int mysnprintf(char* buf, size_t count, char const* fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + + result = stbsp_vsnprintf(buf, (int)count, fmt, va); + va_end(va); + + return result; +} + +int myvsnprintf(char* buf, size_t count, const char* fmt, va_list va) +{ + return stbsp_vsnprintf(buf, (int)count, fmt, va); +} diff --git a/src/common/thirdparty/stb/stb_sprintf.h b/src/common/thirdparty/stb/stb_sprintf.h new file mode 100644 index 000000000..ee4a601f8 --- /dev/null +++ b/src/common/thirdparty/stb/stb_sprintf.h @@ -0,0 +1,1947 @@ +// stb_sprintf - v1.10 - public domain snprintf() implementation +// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 +// http://github.com/nothings/stb +// +// allowed types: sc uidBboXx p AaGgEef n +// lengths : hh h ll j z t I64 I32 I +// +// Contributors: +// Fabian "ryg" Giesen (reformatting) +// github:aganm (attribute format) +// +// Contributors (bugfixes): +// github:d26435 +// github:trex78 +// github:account-login +// Jari Komppa (SI suffixes) +// Rohit Nirmal +// Marcin Wojdyr +// Leonard Ritter +// Stefano Zanotti +// Adam Allison +// Arvid Gerstmann +// Markus Kolb +// +// LICENSE: +// +// See end of file for license information. + +#ifndef STB_SPRINTF_H_INCLUDE +#define STB_SPRINTF_H_INCLUDE + +/* +Single file sprintf replacement. + +Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. +Hereby placed in public domain. + +This is a full sprintf replacement that supports everything that +the C runtime sprintfs support, including float/double, 64-bit integers, +hex floats, field parameters (%*.*d stuff), length reads backs, etc. + +Why would you need this if sprintf already exists? Well, first off, +it's *much* faster (see below). It's also much smaller than the CRT +versions code-space-wise. We've also added some simple improvements +that are super handy (commas in thousands, callbacks at buffer full, +for example). Finally, the format strings for MSVC and GCC differ +for 64-bit integers (among other small things), so this lets you use +the same format strings in cross platform code. + +It uses the standard single file trick of being both the header file +and the source itself. If you just include it normally, you just get +the header file function definitions. To get the code, you include +it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. + +It only uses va_args macros from the C runtime to do it's work. It +does cast doubles to S64s and shifts and divides U64s, which does +drag in CRT code on most platforms. + +It compiles to roughly 8K with float support, and 4K without. +As a comparison, when using MSVC static libs, calling sprintf drags +in 16K. + +API: +==== +int stbsp_sprintf( char * buf, char const * fmt, ... ) +int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) + Convert an arg list into a buffer. stbsp_snprintf always returns + a zero-terminated string (unlike regular snprintf). + +int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) +int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) + Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns + a zero-terminated string (unlike regular snprintf). + +int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) + typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); + Convert into a buffer, calling back every STB_SPRINTF_MIN chars. + Your callback can then copy the chars out, print them or whatever. + This function is actually the workhorse for everything else. + The buffer you pass in must hold at least STB_SPRINTF_MIN characters. + // you return the next buffer to use or 0 to stop converting + +void stbsp_set_separators( char comma, char period ) + Set the comma and period characters to use. + +FLOATS/DOUBLES: +=============== +This code uses a internal float->ascii conversion method that uses +doubles with error correction (double-doubles, for ~105 bits of +precision). This conversion is round-trip perfect - that is, an atof +of the values output here will give you the bit-exact double back. + +One difference is that our insignificant digits will be different than +with MSVC or GCC (but they don't match each other either). We also +don't attempt to find the minimum length matching float (pre-MSVC15 +doesn't either). + +If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT +and you'll save 4K of code space. + +64-BIT INTS: +============ +This library also supports 64-bit integers and you can use MSVC style or +GCC style indicators (%I64d or %lld). It supports the C99 specifiers +for size_t and ptr_diff_t (%jd %zd) as well. + +EXTRAS: +======= +Like some GCCs, for integers and floats, you can use a ' (single quote) +specifier and commas will be inserted on the thousands: "%'d" on 12345 +would print 12,345. + +For integers and floats, you can use a "$" specifier and the number +will be converted to float and then divided to get kilo, mega, giga or +tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is +"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn +2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three +$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the +suffix, add "_" specifier: "%_$d" -> "2.53M". + +In addition to octal and hexadecimal conversions, you can print +integers in binary: "%b" for 256 would print 100. + +PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): +=================================================================== +"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) +"%24d" across all 32-bit ints (4.5x/4.2x faster) +"%x" across all 32-bit ints (4.5x/3.8x faster) +"%08x" across all 32-bit ints (4.3x/3.8x faster) +"%f" across e-10 to e+10 floats (7.3x/6.0x faster) +"%e" across e-10 to e+10 floats (8.1x/6.0x faster) +"%g" across e-10 to e+10 floats (10.0x/7.1x faster) +"%f" for values near e-300 (7.9x/6.5x faster) +"%f" for values near e+300 (10.0x/9.1x faster) +"%e" for values near e-300 (10.1x/7.0x faster) +"%e" for values near e+300 (9.2x/6.0x faster) +"%.320f" for values near e-300 (12.6x/11.2x faster) +"%a" for random values (8.6x/4.3x faster) +"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) +"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) +"%s%s%s" for 64 char strings (7.1x/7.3x faster) +"...512 char string..." ( 35.0x/32.5x faster!) +*/ + +#if defined(__clang__) + #if defined(__has_feature) && defined(__has_attribute) + #if __has_feature(address_sanitizer) + #if __has_attribute(__no_sanitize__) + #define STBSP__ASAN __attribute__((__no_sanitize__("address"))) + #elif __has_attribute(__no_sanitize_address__) + #define STBSP__ASAN __attribute__((__no_sanitize_address__)) + #elif __has_attribute(__no_address_safety_analysis__) + #define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) + #endif + #endif + #endif +#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ + #define STBSP__ASAN __attribute__((__no_sanitize_address__)) + #endif +#endif + +#ifndef STBSP__ASAN +#define STBSP__ASAN +#endif + +#ifdef STB_SPRINTF_STATIC +#define STBSP__PUBLICDEC static +#define STBSP__PUBLICDEF static STBSP__ASAN +#else +#ifdef __cplusplus +#define STBSP__PUBLICDEC extern "C" +#define STBSP__PUBLICDEF extern "C" STBSP__ASAN +#else +#define STBSP__PUBLICDEC extern +#define STBSP__PUBLICDEF STBSP__ASAN +#endif +#endif + +#if defined(__has_attribute) + #if __has_attribute(format) + #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) + #endif +#endif + +#ifndef STBSP__ATTRIBUTE_FORMAT +#define STBSP__ATTRIBUTE_FORMAT(fmt,va) +#endif + +#ifdef _MSC_VER +#define STBSP__NOTUSED(v) (void)(v) +#else +#define STBSP__NOTUSED(v) (void)sizeof(v) +#endif + +#include // for va_arg(), va_list() +#include // size_t, ptrdiff_t + +#ifndef STB_SPRINTF_MIN +#define STB_SPRINTF_MIN 512 // how many characters per callback +#endif +typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); + +#ifndef STB_SPRINTF_DECORATE +#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names +#endif + +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); + +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); + +#endif // STB_SPRINTF_H_INCLUDE + +#ifdef STB_SPRINTF_IMPLEMENTATION + +#define stbsp__uint32 unsigned int +#define stbsp__int32 signed int + +#ifdef _MSC_VER +#define stbsp__uint64 unsigned __int64 +#define stbsp__int64 signed __int64 +#else +#define stbsp__uint64 unsigned long long +#define stbsp__int64 signed long long +#endif +#define stbsp__uint16 unsigned short + +#ifndef stbsp__uintptr +#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) +#define stbsp__uintptr stbsp__uint64 +#else +#define stbsp__uintptr stbsp__uint32 +#endif +#endif + +#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define STB_SPRINTF_MSVC_MODE +#endif +#endif + +#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses +#define STBSP__UNALIGNED(code) +#else +#define STBSP__UNALIGNED(code) code +#endif + +#ifndef STB_SPRINTF_NOFLOAT +// internal float utility functions +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); +#define STBSP__SPECIAL 0x7000 +#endif + +static char stbsp__period = '.'; +static char stbsp__comma = ','; +static struct +{ + short temp; // force next field to be 2-byte aligned + char pair[201]; +} stbsp__digitpair = +{ + 0, + "00010203040506070809101112131415161718192021222324" + "25262728293031323334353637383940414243444546474849" + "50515253545556575859606162636465666768697071727374" + "75767778798081828384858687888990919293949596979899" +}; + +#ifdef STB_SPRINTF_UTF8_CHARS +static int stbsp_utf8_encode(int codepoint, char* buffer) +{ + if (codepoint < -0x80 || codepoint > 0x10FFFF) + { + codepoint = 0xfffd; + } + if (codepoint < 0x80) + { + buffer[0] = (char)codepoint; + return 1; + } + else if (codepoint < 0x800) + { + buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); + buffer[1] = 0x80 + ((codepoint & 0x03F)); + return 2; + } + else if (codepoint < 0x10000) + { + buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); + buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); + buffer[2] = 0x80 + ((codepoint & 0x003F)); + return 3; + } + else + { + buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); + buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); + buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); + buffer[3] = 0x80 + ((codepoint & 0x00003F)); + return 4; + } +} +#endif + +STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) +{ + stbsp__period = pperiod; + stbsp__comma = pcomma; +} + +#define STBSP__LEFTJUST 1 +#define STBSP__LEADINGPLUS 2 +#define STBSP__LEADINGSPACE 4 +#define STBSP__LEADING_0X 8 +#define STBSP__LEADINGZERO 16 +#define STBSP__INTMAX 32 +#define STBSP__TRIPLET_COMMA 64 +#define STBSP__NEGATIVE 128 +#define STBSP__METRIC_SUFFIX 256 +#define STBSP__HALFWIDTH 512 +#define STBSP__METRIC_NOSPACE 1024 +#define STBSP__METRIC_1024 2048 +#define STBSP__METRIC_JEDEC 4096 + +static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) +{ + sign[0] = 0; + if (fl & STBSP__NEGATIVE) { + sign[0] = 1; + sign[1] = '-'; + } else if (fl & STBSP__LEADINGSPACE) { + sign[0] = 1; + sign[1] = ' '; + } else if (fl & STBSP__LEADINGPLUS) { + sign[0] = 1; + sign[1] = '+'; + } +} + +static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) +{ + char const * sn = s; + + // get up to 4-byte alignment + for (;;) { + if (((stbsp__uintptr)sn & 3) == 0) + break; + + if (!limit || *sn == 0) + return (stbsp__uint32)(sn - s); + + ++sn; + --limit; + } + + // scan over 4 bytes at a time to find terminating 0 + // this will intentionally scan up to 3 bytes past the end of buffers, + // but becase it works 4B aligned, it will never cross page boundaries + // (hence the STBSP__ASAN markup; the over-read here is intentional + // and harmless) + while (limit >= 4) { + stbsp__uint32 v = *(stbsp__uint32 *)sn; + // bit hack to find if there's a 0 byte in there + if ((v - 0x01010101) & (~v) & 0x80808080UL) + break; + + sn += 4; + limit -= 4; + } + + // handle the last few characters to find actual size + while (limit && *sn) { + ++sn; + --limit; + } + + return (stbsp__uint32)(sn - s); +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) +{ + static char hex[] = "0123456789abcdefxp"; + static char hexu[] = "0123456789ABCDEFXP"; + char *bf; + char const *f; + int tlen = 0; + + bf = buf; + f = fmt; + for (;;) { + stbsp__int32 fw, pr, tz; + stbsp__uint32 fl; + + // macros for the callback buffer stuff + #define stbsp__chk_cb_bufL(bytes) \ + { \ + int len = (int)(bf - buf); \ + if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ + tlen += len; \ + if (0 == (bf = buf = callback(buf, user, len))) \ + goto done; \ + } \ + } + #define stbsp__chk_cb_buf(bytes) \ + { \ + if (callback) { \ + stbsp__chk_cb_bufL(bytes); \ + } \ + } + #define stbsp__flush_cb() \ + { \ + stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ + } // flush if there is even one byte in the buffer + #define stbsp__cb_buf_clamp(cl, v) \ + cl = v; \ + if (callback) { \ + int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ + if (cl > lg) \ + cl = lg; \ + } + + // fast copy everything up to the next % (or end of string) + for (;;) { + while (((stbsp__uintptr)f) & 3) { + schk1: + if (f[0] == '%') + goto scandd; + schk2: + if (f[0] == 0) + goto endfmt; + stbsp__chk_cb_buf(1); + *bf++ = f[0]; + ++f; + } + for (;;) { + // Check if the next 4 bytes contain %(0x25) or end of string. + // Using the 'hasless' trick: + // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord + stbsp__uint32 v, c; + v = *(stbsp__uint32 *)f; + c = (~v) & 0x80808080; + if (((v ^ 0x25252525) - 0x01010101) & c) + goto schk1; + if ((v - 0x01010101) & c) + goto schk2; + if (callback) + if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) + goto schk1; + #ifdef STB_SPRINTF_NOUNALIGNED + if(((stbsp__uintptr)bf) & 3) { + bf[0] = f[0]; + bf[1] = f[1]; + bf[2] = f[2]; + bf[3] = f[3]; + } else + #endif + { + *(stbsp__uint32 *)bf = v; + } + bf += 4; + f += 4; + } + } + scandd: + + ++f; + + // ok, we have a percent, read the modifiers first + fw = 0; + pr = -1; + fl = 0; + tz = 0; + + // flags + for (;;) { + switch (f[0]) { + // if we have left justify + case '-': + fl |= STBSP__LEFTJUST; + ++f; + continue; + // if we have leading plus + case '+': + fl |= STBSP__LEADINGPLUS; + ++f; + continue; + // if we have leading space + case ' ': + fl |= STBSP__LEADINGSPACE; + ++f; + continue; + // if we have leading 0x + case '#': + fl |= STBSP__LEADING_0X; + ++f; + continue; + // if we have thousand commas + case '\'': + fl |= STBSP__TRIPLET_COMMA; + ++f; + continue; + // if we have kilo marker (none->kilo->kibi->jedec) + case '$': + if (fl & STBSP__METRIC_SUFFIX) { + if (fl & STBSP__METRIC_1024) { + fl |= STBSP__METRIC_JEDEC; + } else { + fl |= STBSP__METRIC_1024; + } + } else { + fl |= STBSP__METRIC_SUFFIX; + } + ++f; + continue; + // if we don't want space between metric suffix and number + case '_': + fl |= STBSP__METRIC_NOSPACE; + ++f; + continue; + // if we have leading zero + case '0': + fl |= STBSP__LEADINGZERO; + ++f; + goto flags_done; + default: goto flags_done; + } + } + flags_done: + + // get the field width + if (f[0] == '*') { + fw = va_arg(va, stbsp__uint32); + ++f; + } else { + while ((f[0] >= '0') && (f[0] <= '9')) { + fw = fw * 10 + f[0] - '0'; + f++; + } + } + // get the precision + if (f[0] == '.') { + ++f; + if (f[0] == '*') { + pr = va_arg(va, stbsp__uint32); + ++f; + } else { + pr = 0; + while ((f[0] >= '0') && (f[0] <= '9')) { + pr = pr * 10 + f[0] - '0'; + f++; + } + } + } + + // handle integer size overrides + switch (f[0]) { + // are we halfwidth? + case 'h': + fl |= STBSP__HALFWIDTH; + ++f; + if (f[0] == 'h') + ++f; // QUARTERWIDTH + break; + // are we 64-bit (unix style) + case 'l': + fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); + ++f; + if (f[0] == 'l') { + fl |= STBSP__INTMAX; + ++f; + } + break; + // are we 64-bit on intmax? (c99) + case 'j': + fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + // are we 64-bit on size_t or ptrdiff_t? (c99) + case 'z': + fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + case 't': + fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + // are we 64-bit (msft style) + case 'I': + if ((f[1] == '6') && (f[2] == '4')) { + fl |= STBSP__INTMAX; + f += 3; + } else if ((f[1] == '3') && (f[2] == '2')) { + f += 3; + } else { + fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); + ++f; + } + break; + default: break; + } + + // handle each replacement + switch (f[0]) { + #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 + char num[STBSP__NUMSZ]; + char lead[8]; + char tail[8]; + char *s; + char const *h; + stbsp__uint32 l, n, cs; + stbsp__uint64 n64; +#ifndef STB_SPRINTF_NOFLOAT + double fv; +#endif + stbsp__int32 dp; + char const *sn; + + case 's': + // get the string + s = va_arg(va, char *); + if (s == 0) + s = (char *)"null"; + // get the length, limited to desired precision + // always limit to ~0u chars since our counts are 32b + l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + // copy the string in + goto scopy; + + case 'c': // char + // get the character +#ifndef STB_SPRINTF_UTF8_CHARS + s = num + STBSP__NUMSZ - 1; + *s = (char)va_arg(va, int); + l = 1; +#else + s = num + STBSP__NUMSZ - 4; // UTF-8 needs 4 bytes at most. + l = stbsp_utf8_encode(va_arg(va, int), s); +#endif + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + + case 'n': // weird write-bytes specifier + { + int *d = va_arg(va, int *); + *d = tlen + (int)(bf - buf); + } break; + +#ifdef STB_SPRINTF_NOFLOAT + case 'A': // float + case 'a': // hex float + case 'G': // float + case 'g': // float + case 'E': // float + case 'e': // float + case 'f': // float + va_arg(va, double); // eat it + s = (char *)"No float"; + l = 8; + lead[0] = 0; + tail[0] = 0; + pr = 0; + cs = 0; + STBSP__NOTUSED(dp); + goto scopy; +#else + case 'A': // hex float + case 'a': // hex float + h = (f[0] == 'A') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) + fl |= STBSP__NEGATIVE; + + s = num + 64; + + stbsp__lead_sign(fl, lead); + + if (dp == -1023) + dp = (n64) ? -1022 : 0; + else + n64 |= (((stbsp__uint64)1) << 52); + n64 <<= (64 - 56); + if (pr < 15) + n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); +// add leading chars + +#ifdef STB_SPRINTF_MSVC_MODE + *s++ = '0'; + *s++ = 'x'; +#else + lead[1 + lead[0]] = '0'; + lead[2 + lead[0]] = 'x'; + lead[0] += 2; +#endif + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + if (pr) + *s++ = stbsp__period; + sn = s; + + // print the bits + n = pr; + if (n > 13) + n = 13; + if (pr > (stbsp__int32)n) + tz = pr - n; + pr = 0; + while (n--) { + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + } + + // print the expo + tail[1] = h[17]; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; + n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + + dp = (int)(s - sn); + l = (int)(s - (num + 64)); + s = num + 64; + cs = 1 + (3 << 24); + goto scopy; + + case 'G': // float + case 'g': // float + h = (f[0] == 'G') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; + else if (pr == 0) + pr = 1; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) + fl |= STBSP__NEGATIVE; + + // clamp the precision and delete extra zeros after clamp + n = pr; + if (l > (stbsp__uint32)pr) + l = pr; + while ((l > 1) && (pr) && (sn[l - 1] == '0')) { + --pr; + --l; + } + + // should we use %e + if ((dp <= -4) || (dp > (stbsp__int32)n)) { + if (pr > (stbsp__int32)l) + pr = l - 1; + else if (pr) + --pr; // when using %e, there is one digit before the decimal + goto doexpfromg; + } + // this is the insane action to get the pr to match %g semantics for %f + if (dp > 0) { + pr = (dp < (stbsp__int32)l) ? l - dp : 0; + } else { + pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); + } + goto dofloatfromg; + + case 'E': // float + case 'e': // float + h = (f[0] == 'E') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) + fl |= STBSP__NEGATIVE; + doexpfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + // handle leading chars + *s++ = sn[0]; + + if (pr) + *s++ = stbsp__period; + + // handle after decimal + if ((l - 1) > (stbsp__uint32)pr) + l = pr + 1; + for (n = 1; n < l; n++) + *s++ = sn[n]; + // trailing zeros + tz = pr - (l - 1); + pr = 0; + // dump expo + tail[1] = h[0xe]; + dp -= 1; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; +#ifdef STB_SPRINTF_MSVC_MODE + n = 5; +#else + n = (dp >= 100) ? 5 : 4; +#endif + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + cs = 1 + (3 << 24); // how many tens + goto flt_lead; + + case 'f': // float + fv = va_arg(va, double); + doafloat: + // do kilos + if (fl & STBSP__METRIC_SUFFIX) { + double divisor; + divisor = 1000.0f; + if (fl & STBSP__METRIC_1024) + divisor = 1024.0; + while (fl < 0x4000000) { + if ((fv < divisor) && (fv > -divisor)) + break; + fv /= divisor; + fl += 0x1000000; + } + } + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) + fl |= STBSP__NEGATIVE; + dofloatfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + + // handle the three decimal varieties + if (dp <= 0) { + stbsp__int32 i; + // handle 0.000*000xxxx + *s++ = '0'; + if (pr) + *s++ = stbsp__period; + n = -dp; + if ((stbsp__int32)n > pr) + n = pr; + i = n; + while (i) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + i -= 4; + } + while (i) { + *s++ = '0'; + --i; + } + if ((stbsp__int32)(l + n) > pr) + l = pr - n; + i = l; + while (i) { + *s++ = *sn++; + --i; + } + tz = pr - (n + l); + cs = 1 + (3 << 24); // how many tens did we write (for commas below) + } else { + cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; + if ((stbsp__uint32)dp >= l) { + // handle xxxx000*000.0 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= l) + break; + } + } + if (n < (stbsp__uint32)dp) { + n = dp - n; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (n) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --n; + } + while (n >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + n -= 4; + } + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = '0'; + --n; + } + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) { + *s++ = stbsp__period; + tz = pr; + } + } else { + // handle xxxxx.xxxx000*000 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= (stbsp__uint32)dp) + break; + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) + *s++ = stbsp__period; + if ((l - dp) > (stbsp__uint32)pr) + l = pr + dp; + while (n < l) { + *s++ = sn[n]; + ++n; + } + tz = pr - (l - dp); + } + } + pr = 0; + + // handle k,m,g,t + if (fl & STBSP__METRIC_SUFFIX) { + char idx; + idx = 1; + if (fl & STBSP__METRIC_NOSPACE) + idx = 0; + tail[0] = idx; + tail[1] = ' '; + { + if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. + if (fl & STBSP__METRIC_1024) + tail[idx + 1] = "_KMGT"[fl >> 24]; + else + tail[idx + 1] = "_kMGT"[fl >> 24]; + idx++; + // If printing kibits and not in jedec, add the 'i'. + if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { + tail[idx + 1] = 'i'; + idx++; + } + tail[0] = idx; + } + } + }; + + flt_lead: + // get the length that we copied + l = (stbsp__uint32)(s - (num + 64)); + s = num + 64; + goto scopy; +#endif + + case 'B': // upper binary + case 'b': // lower binary + h = (f[0] == 'B') ? hexu : hex; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[0xb]; + } + l = (8 << 4) | (1 << 8); + goto radixnum; + + case 'o': // octal + h = hexu; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 1; + lead[1] = '0'; + } + l = (3 << 4) | (3 << 8); + goto radixnum; + + case 'p': // pointer + fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; + pr = sizeof(void *) * 2; + fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros + // fall through - to X + + case 'X': // upper hex + case 'x': // lower hex + h = (f[0] == 'X') ? hexu : hex; + l = (4 << 4) | (4 << 8); + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[16]; + } + radixnum: + // get the number + if (fl & STBSP__INTMAX) + n64 = va_arg(va, stbsp__uint64); + else + n64 = va_arg(va, stbsp__uint32); + + s = num + STBSP__NUMSZ; + dp = 0; + // clear tail, and clear leading if value is zero + tail[0] = 0; + if (n64 == 0) { + lead[0] = 0; + if (pr == 0) { + l = 0; + cs = 0; + goto scopy; + } + } + // convert to string + for (;;) { + *--s = h[n64 & ((1 << (l >> 8)) - 1)]; + n64 >>= (l >> 8); + if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) + break; + if (fl & STBSP__TRIPLET_COMMA) { + ++l; + if ((l & 15) == ((l >> 4) & 15)) { + l &= ~15; + *--s = stbsp__comma; + } + } + }; + // get the tens and the comma pos + cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + // copy it + goto scopy; + + case 'u': // unsigned + case 'i': + case 'd': // integer + // get the integer and abs it + if (fl & STBSP__INTMAX) { + stbsp__int64 i64 = va_arg(va, stbsp__int64); + n64 = (stbsp__uint64)i64; + if ((f[0] != 'u') && (i64 < 0)) { + n64 = (stbsp__uint64)-i64; + fl |= STBSP__NEGATIVE; + } + } else { + stbsp__int32 i = va_arg(va, stbsp__int32); + n64 = (stbsp__uint32)i; + if ((f[0] != 'u') && (i < 0)) { + n64 = (stbsp__uint32)-i; + fl |= STBSP__NEGATIVE; + } + } + +#ifndef STB_SPRINTF_NOFLOAT + if (fl & STBSP__METRIC_SUFFIX) { + if (n64 < 1024) + pr = 0; + else if (pr == -1) + pr = 1; + fv = (double)(stbsp__int64)n64; + goto doafloat; + } +#endif + + // convert to string + s = num + STBSP__NUMSZ; + l = 0; + + for (;;) { + // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) + char *o = s - 8; + if (n64 >= 100000000) { + n = (stbsp__uint32)(n64 % 100000000); + n64 /= 100000000; + } else { + n = (stbsp__uint32)n64; + n64 = 0; + } + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + do { + s -= 2; + *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; + n /= 100; + } while (n); + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = (char)(n % 10) + '0'; + n /= 10; + } + } + if (n64 == 0) { + if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) + ++s; + break; + } + while (s != o) + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = '0'; + } + } + + tail[0] = 0; + stbsp__lead_sign(fl, lead); + + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + if (l == 0) { + *--s = '0'; + l = 1; + } + cs = l + (3 << 24); + if (pr < 0) + pr = 0; + + scopy: + // get fw=leading/trailing space, pr=leading zeros + if (pr < (stbsp__int32)l) + pr = l; + n = pr + lead[0] + tail[0] + tz; + if (fw < (stbsp__int32)n) + fw = n; + fw -= n; + pr -= l; + + // handle right justify and leading zeros + if ((fl & STBSP__LEFTJUST) == 0) { + if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr + { + pr = (fw > pr) ? fw : pr; + fw = 0; + } else { + fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas + } + } + + // copy the spaces and/or zeros + if (fw + pr) { + stbsp__int32 i; + stbsp__uint32 c; + + // copy leading spaces (or when doing %8.4d stuff) + if ((fl & STBSP__LEFTJUST) == 0) + while (fw > 0) { + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = ' '; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leader + sn = lead + 1; + while (lead[0]) { + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leading zeros + c = cs >> 24; + cs &= 0xffffff; + cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; + while (pr > 0) { + stbsp__cb_buf_clamp(i, pr); + pr -= i; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + } + while (i) { + if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { + cs = 0; + *bf++ = stbsp__comma; + } else + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + } + + // copy leader if there is still one + sn = lead + 1; + while (lead[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy the string + n = l; + while (n) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, n); + n -= i; + STBSP__UNALIGNED(while (i >= 4) { + *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; + bf += 4; + s += 4; + i -= 4; + }) + while (i) { + *bf++ = *s++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy trailing zeros + while (tz) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tz); + tz -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy tail if there is one + sn = tail + 1; + while (tail[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tail[0]); + tail[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // handle the left justify + if (fl & STBSP__LEFTJUST) + if (fw > 0) { + while (fw) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i--) + *bf++ = ' '; + stbsp__chk_cb_buf(1); + } + } + break; + + default: // unknown, just copy code + s = num + STBSP__NUMSZ - 1; + *s = f[0]; + l = 1; + fw = fl = 0; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + } + ++f; + } +endfmt: + + if (!callback) + *bf = 0; + else + stbsp__flush_cb(); + +done: + return tlen + (int)(bf - buf); +} + +// cleanup +#undef STBSP__LEFTJUST +#undef STBSP__LEADINGPLUS +#undef STBSP__LEADINGSPACE +#undef STBSP__LEADING_0X +#undef STBSP__LEADINGZERO +#undef STBSP__INTMAX +#undef STBSP__TRIPLET_COMMA +#undef STBSP__NEGATIVE +#undef STBSP__METRIC_SUFFIX +#undef STBSP__NUMSZ +#undef stbsp__chk_cb_bufL +#undef stbsp__chk_cb_buf +#undef stbsp__flush_cb +#undef stbsp__cb_buf_clamp + +// ============================================================================ +// wrapper functions + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); + va_end(va); + return result; +} + +typedef struct stbsp__context { + char *buf; + int count; + int length; + char tmp[STB_SPRINTF_MIN]; +} stbsp__context; + +static char *stbsp__clamp_callback(const char *buf, void *user, int len) +{ + stbsp__context *c = (stbsp__context *)user; + c->length += len; + + if (len > c->count) + len = c->count; + + if (len) { + if (buf != c->buf) { + const char *s, *se; + char *d; + d = c->buf; + s = buf; + se = buf + len; + do { + *d++ = *s++; + } while (s < se); + } + c->buf += len; + c->count -= len; + } + + if (c->count <= 0) + return c->tmp; + return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can +} + +static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) +{ + stbsp__context * c = (stbsp__context*)user; + (void) sizeof(buf); + + c->length += len; + return c->tmp; // go direct into buffer if you can +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) +{ + stbsp__context c; + + if ( (count == 0) && !buf ) + { + c.length = 0; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); + } + else + { + int l; + + c.buf = buf; + c.count = count; + c.length = 0; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); + + // zero-terminate + l = (int)( c.buf - buf ); + if ( l >= count ) // should never be greater, only equal (or less) than count + l = count - 1; + buf[l] = 0; + } + + return c.length; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + + result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); + va_end(va); + + return result; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) +{ + return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); +} + +// ======================================================================= +// low level float utility functions + +#ifndef STB_SPRINTF_NOFLOAT + +// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) +#define STBSP__COPYFP(dest, src) \ + { \ + int cn; \ + for (cn = 0; cn < 8; cn++) \ + ((char *)&dest)[cn] = ((char *)&src)[cn]; \ + } + +// get float info +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) +{ + double d; + stbsp__int64 b = 0; + + // load value and round at the frac_digits + d = value; + + STBSP__COPYFP(b, d); + + *bits = b & ((((stbsp__uint64)1) << 52) - 1); + *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); + + return (stbsp__int32)((stbsp__uint64) b >> 63); +} + +static double const stbsp__bot[23] = { + 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, + 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 +}; +static double const stbsp__negbot[22] = { + 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, + 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 +}; +static double const stbsp__negboterr[22] = { + -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, + 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, + -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, + 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 +}; +static double const stbsp__top[13] = { + 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 +}; +static double const stbsp__negtop[13] = { + 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 +}; +static double const stbsp__toperr[13] = { + 8388608, + 6.8601809640529717e+028, + -7.253143638152921e+052, + -4.3377296974619174e+075, + -1.5559416129466825e+098, + -3.2841562489204913e+121, + -3.7745893248228135e+144, + -1.7356668416969134e+167, + -3.8893577551088374e+190, + -9.9566444326005119e+213, + 6.3641293062232429e+236, + -5.2069140800249813e+259, + -5.2504760255204387e+282 +}; +static double const stbsp__negtoperr[13] = { + 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, + -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, + 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, + 8.0970921678014997e-317 +}; + +#if defined(_MSC_VER) && (_MSC_VER <= 1200) +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U +}; +#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) +#else +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + 10000000000000000000ULL +}; +#define stbsp__tento19th (1000000000000000000ULL) +#endif + +#define stbsp__ddmulthi(oh, ol, xh, yh) \ + { \ + double ahi = 0, alo, bhi = 0, blo; \ + stbsp__int64 bt; \ + oh = xh * yh; \ + STBSP__COPYFP(bt, xh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(ahi, bt); \ + alo = xh - ahi; \ + STBSP__COPYFP(bt, yh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(bhi, bt); \ + blo = yh - bhi; \ + ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ + } + +#define stbsp__ddtoS64(ob, xh, xl) \ + { \ + double ahi = 0, alo, vh, t; \ + ob = (stbsp__int64)xh; \ + vh = (double)ob; \ + ahi = (xh - vh); \ + t = (ahi - xh); \ + alo = (xh - (ahi - t)) - (vh + t); \ + ob += (stbsp__int64)(ahi + alo + xl); \ + } + +#define stbsp__ddrenorm(oh, ol) \ + { \ + double s; \ + s = oh + ol; \ + ol = ol - (s - oh); \ + oh = s; \ + } + +#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); + +#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); + +static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 +{ + double ph, pl; + if ((power >= 0) && (power <= 22)) { + stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); + } else { + stbsp__int32 e, et, eb; + double p2h, p2l; + + e = power; + if (power < 0) + e = -e; + et = (e * 0x2c9) >> 14; /* %23 */ + if (et > 13) + et = 13; + eb = e - (et * 23); + + ph = d; + pl = 0.0; + if (power < 0) { + if (eb) { + --eb; + stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); + stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); + ph = p2h; + pl = p2l; + } + } else { + if (eb) { + e = eb; + if (eb > 22) + eb = 22; + e -= eb; + stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); + if (e) { + stbsp__ddrenorm(ph, pl); + stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); + stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); + ph = p2h; + pl = p2l; + } + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); + ph = p2h; + pl = p2l; + } + } + } + stbsp__ddrenorm(ph, pl); + *ohi = ph; + *olo = pl; +} + +// given a float value, returns the significant bits in bits, and the position of the +// decimal point in decimal_pos. +/-INF and NAN are specified by special values +// returned in the decimal_pos parameter. +// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) +{ + double d; + stbsp__int64 bits = 0; + stbsp__int32 expo, e, ng, tens; + + d = value; + STBSP__COPYFP(bits, d); + expo = (stbsp__int32)((bits >> 52) & 2047); + ng = (stbsp__int32)((stbsp__uint64) bits >> 63); + if (ng) + d = -d; + + if (expo == 2047) // is nan or inf? + { + *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; + *decimal_pos = STBSP__SPECIAL; + *len = 3; + return ng; + } + + if (expo == 0) // is zero or denormal + { + if (((stbsp__uint64) bits << 1) == 0) // do zero + { + *decimal_pos = 1; + *start = out; + out[0] = '0'; + *len = 1; + return ng; + } + // find the right expo for denormals + { + stbsp__int64 v = ((stbsp__uint64)1) << 51; + while ((bits & v) == 0) { + --expo; + v >>= 1; + } + } + } + + // find the decimal exponent as well as the decimal bits of the value + { + double ph, pl; + + // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 + tens = expo - 1023; + tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); + + // move the significant bits into position and stick them into an int + stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); + + // get full as much precision from double-double as possible + stbsp__ddtoS64(bits, ph, pl); + + // check if we undershot + if (((stbsp__uint64)bits) >= stbsp__tento19th) + ++tens; + } + + // now do the rounding in integer land + frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); + if ((frac_digits < 24)) { + stbsp__uint32 dg = 1; + if ((stbsp__uint64)bits >= stbsp__powten[9]) + dg = 10; + while ((stbsp__uint64)bits >= stbsp__powten[dg]) { + ++dg; + if (dg == 20) + goto noround; + } + if (frac_digits < dg) { + stbsp__uint64 r; + // add 0.5 at the right position and round + e = dg - frac_digits; + if ((stbsp__uint32)e >= 24) + goto noround; + r = stbsp__powten[e]; + bits = bits + (r / 2); + if ((stbsp__uint64)bits >= stbsp__powten[dg]) + ++tens; + bits /= r; + } + noround:; + } + + // kill long trailing runs of zeros + if (bits) { + stbsp__uint32 n; + for (;;) { + if (bits <= 0xffffffff) + break; + if (bits % 1000) + goto donez; + bits /= 1000; + } + n = (stbsp__uint32)bits; + while ((n % 1000) == 0) + n /= 1000; + bits = n; + donez:; + } + + // convert to string + out += 64; + e = 0; + for (;;) { + stbsp__uint32 n; + char *o = out - 8; + // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) + if (bits >= 100000000) { + n = (stbsp__uint32)(bits % 100000000); + bits /= 100000000; + } else { + n = (stbsp__uint32)bits; + bits = 0; + } + while (n) { + out -= 2; + *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; + n /= 100; + e += 2; + } + if (bits == 0) { + if ((e) && (out[0] == '0')) { + ++out; + --e; + } + break; + } + while (out != o) { + *--out = '0'; + ++e; + } + } + + *decimal_pos = tens; + *start = out; + *len = e; + return ng; +} + +#undef stbsp__ddmulthi +#undef stbsp__ddrenorm +#undef stbsp__ddmultlo +#undef stbsp__ddmultlos +#undef STBSP__SPECIAL +#undef STBSP__COPYFP + +#endif // STB_SPRINTF_NOFLOAT + +// clean up +#undef stbsp__uint16 +#undef stbsp__uint32 +#undef stbsp__int32 +#undef stbsp__uint64 +#undef stbsp__int64 +#undef STBSP__UNALIGNED + +#endif // STB_SPRINTF_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/src/common/utility/basics.h b/src/common/utility/basics.h index 6655ede2c..0dbb47c67 100644 --- a/src/common/utility/basics.h +++ b/src/common/utility/basics.h @@ -3,7 +3,6 @@ #include #include #include -#include "xs_Float.h" #define MAXWIDTH 12000 #define MAXHEIGHT 5000 @@ -22,7 +21,6 @@ typedef int32_t fixed_t; // the last remnants of tables.h #define ANGLE_90 (0x40000000) #define ANGLE_180 (0x80000000) -#define ANGLE_270 (0xc0000000) #define ANGLE_MAX (0xffffffff) typedef uint32_t angle_t; @@ -39,14 +37,6 @@ typedef uint32_t angle_t; #define FORCE_PACKED #endif -// Todo: get rid of this. Static file name buffers suck. -#ifndef PATH_MAX -#define BMAX_PATH 256 -#else -#define BMAX_PATH PATH_MAX -#endif - - #ifdef __GNUC__ #define GCCPRINTF(stri,firstargi) __attribute__((format(printf,stri,firstargi))) #define GCCFORMAT(stri) __attribute__((format(printf,stri,0))) @@ -69,12 +59,6 @@ using INTBOOL = int; using BITFIELD = uint32_t; -#if defined(_MSC_VER) -#define NOVTABLE __declspec(novtable) -#else -#define NOVTABLE -#endif - // always use our own definition for consistency. #ifdef M_PI #undef M_PI @@ -82,46 +66,6 @@ using BITFIELD = uint32_t; const double M_PI = 3.14159265358979323846; // matches value in gcc v2 math.h -inline float DEG2RAD(float deg) -{ - return deg * float(M_PI / 180.0); -} - -inline double DEG2RAD(double deg) -{ - return deg * (M_PI / 180.0); -} - -inline float RAD2DEG(float rad) -{ - return rad * float(180. / M_PI); -} - -inline double RAD2DEG(double rad) -{ - return rad * (180. / M_PI); -} - -inline angle_t RAD2BAM(float rad) -{ - return angle_t(xs_RoundToUInt(rad * float(0x80000000u / M_PI))); -} - -inline angle_t RAD2BAM(double rad) -{ - return angle_t(xs_RoundToUInt(rad * (0x80000000u / M_PI))); -} - - -// This is needed in common code, despite being Doom specific. -enum EStateUseFlags -{ - SUF_ACTOR = 1, - SUF_OVERLAY = 2, - SUF_WEAPON = 4, - SUF_ITEM = 8, -}; - using std::min; using std::max; using std::clamp; diff --git a/src/common/utility/cmdlib.cpp b/src/common/utility/cmdlib.cpp index 02ab18959..a3b2ef4f5 100644 --- a/src/common/utility/cmdlib.cpp +++ b/src/common/utility/cmdlib.cpp @@ -122,25 +122,6 @@ char *copystring (const char *s) return b; } -//========================================================================== -// -// ReplaceString -// -// Do not use in new code. -// -//========================================================================== - -void ReplaceString (char **ptr, const char *str) -{ - if (*ptr) - { - if (*ptr == str) - return; - delete[] *ptr; - } - *ptr = copystring (str); -} - /* ============================================================================= diff --git a/src/common/utility/cmdlib.h b/src/common/utility/cmdlib.h index 392d0f46d..b319056e8 100644 --- a/src/common/utility/cmdlib.h +++ b/src/common/utility/cmdlib.h @@ -54,7 +54,6 @@ struct FScriptPosition; bool IsNum (const char *str); // [RH] added char *copystring(const char *s); -void ReplaceString (char **ptr, const char *str); bool CheckWildcards (const char *pattern, const char *text); diff --git a/src/common/utility/files.cpp b/src/common/utility/files.cpp index 6f915a2ce..cbefc7bbc 100644 --- a/src/common/utility/files.cpp +++ b/src/common/utility/files.cpp @@ -34,8 +34,8 @@ */ #include "files.h" - // just for 'clamp' -#include "zstring.h" +#include "utf8.h" +#include "stb_sprintf.h" FILE *myfopen(const char *filename, const char *flags) @@ -472,13 +472,18 @@ long FileWriter::Seek(long offset, int mode) size_t FileWriter::Printf(const char *fmt, ...) { - va_list ap; - FString out; + char workbuf[STB_SPRINTF_MIN]; + va_list arglist; + va_start(arglist, fmt); + auto r = stbsp_vsprintfcb([](const char* cstr, void* data, int len) -> char* + { + auto fr = (FileWriter*)data; + auto writ = fr->Write(cstr, len); + return writ == (size_t)len? (char*)cstr : nullptr; // abort if writing caused an error. + }, this, workbuf, fmt, arglist); - va_start(ap, fmt); - out.VFormat(fmt, ap); - va_end(ap); - return Write(out.GetChars(), out.Len()); + va_end(arglist); + return r; } size_t BufferWriter::Write(const void *buffer, size_t len) diff --git a/src/common/utility/files_decompress.cpp b/src/common/utility/files_decompress.cpp index cd2e36ed7..7954b5101 100644 --- a/src/common/utility/files_decompress.cpp +++ b/src/common/utility/files_decompress.cpp @@ -43,7 +43,6 @@ #include "files.h" -#include "zstring.h" #include "cmdlib.h" //========================================================================== diff --git a/src/common/utility/memarena.cpp b/src/common/utility/memarena.cpp index 2a9467dc2..767824a64 100644 --- a/src/common/utility/memarena.cpp +++ b/src/common/utility/memarena.cpp @@ -132,6 +132,13 @@ void* FMemArena::Calloc(size_t size) return mem; } +const char* FMemArena::Strdup(const char* str) +{ + char* p = (char*)Alloc(strlen(str) + 1); + strcpy(p, str); + return p; +} + //========================================================================== // // FMemArena :: FreeAll diff --git a/src/common/utility/memarena.h b/src/common/utility/memarena.h index bb7f60b9a..8c1def64d 100644 --- a/src/common/utility/memarena.h +++ b/src/common/utility/memarena.h @@ -45,6 +45,7 @@ public: void *Alloc(size_t size); void* Calloc(size_t size); + const char* Strdup(const char*); void FreeAll(); void FreeAllBlocks(); FString DumpInfo(); diff --git a/src/common/utility/utf8.cpp b/src/common/utility/utf8.cpp index 100c06a13..1ac6ea62b 100644 --- a/src/common/utility/utf8.cpp +++ b/src/common/utility/utf8.cpp @@ -1157,3 +1157,17 @@ bool myisupper(int code) return false; } +std::wstring WideString(const char* cin) +{ + std::wstring buildbuffer; + if (cin) + { + // This is a bit tricky because we need to support both UTF-8 and legacy content in ISO-8859-1 / Windows 1252 + // and thanks to user-side string manipulation it can be that a text mixes both. + // To convert the string this uses the same function as all text printing in the engine. + const uint8_t* in = (const uint8_t*)cin; + while (*in) buildbuffer.push_back((wchar_t)GetCharFromString(in)); + } + return buildbuffer; +} + diff --git a/src/common/utility/utf8.h b/src/common/utility/utf8.h index 7ca8a5f32..fe883232b 100644 --- a/src/common/utility/utf8.h +++ b/src/common/utility/utf8.h @@ -18,3 +18,8 @@ int getAlternative(int code); extern uint16_t win1252map[]; extern uint16_t lowerforupper[65536]; extern uint16_t upperforlower[65536]; + +// make this only visible on Windows, on other platforms this should not be called. +#ifdef _WIN32 +std::wstring WideString(const char*); +#endif diff --git a/src/common/utility/vectors.h b/src/common/utility/vectors.h index 692d4a80d..a7bc2b2f3 100644 --- a/src/common/utility/vectors.h +++ b/src/common/utility/vectors.h @@ -55,7 +55,7 @@ namespace pi inline constexpr float pif() { return 3.14159265358979323846f; } } -// optionally use reliable math routines if reproducability across hardware is important., but let this still compile without them. +// optionally use reliable math routines if reproducability across hardware is important, but let this still compile without them. #if __has_include("math/cmath.h") #include "math/cmath.h" #else @@ -1043,44 +1043,9 @@ struct TMatrix3x3 // Construct a rotation matrix about an arbitrary axis. // (The axis vector must be normalized.) - TMatrix3x3(const Vector3 &axis, double radians) + TMatrix3x3(const Vector3 &axis, double degrees) + : TMatrix3x3(axis, g_sindeg(degrees), g_cosdeg(degrees)) { - double c = g_cos(radians), s = g_sin(radians), t = 1 - c; -/* In comments: A more readable version of the matrix setup. -This was found in Diana Gruber's article "The Mathematics of the -3D Rotation Matrix" at and is -attributed to Graphics Gems (Glassner, Academic Press, 1990). - - Cells[0][0] = t*axis.X*axis.X + c; - Cells[0][1] = t*axis.X*axis.Y - s*axis.Z; - Cells[0][2] = t*axis.X*axis.Z + s*axis.Y; - - Cells[1][0] = t*axis.Y*axis.X + s*axis.Z; - Cells[1][1] = t*axis.Y*axis.Y + c; - Cells[1][2] = t*axis.Y*axis.Z - s*axis.X; - - Cells[2][0] = t*axis.Z*axis.X - s*axis.Y; - Cells[2][1] = t*axis.Z*axis.Y + s*axis.X; - Cells[2][2] = t*axis.Z*axis.Z + c; - -Outside comments: A faster version with only 10 (not 24) multiplies. -*/ - double sx = s*axis.X, sy = s*axis.Y, sz = s*axis.Z; - double tx, ty, txx, tyy, u, v; - - tx = t*axis.X; - Cells[0][0] = vec_t( (txx=tx*axis.X) + c ); - Cells[0][1] = vec_t( (u=tx*axis.Y) - sz); - Cells[0][2] = vec_t( (v=tx*axis.Z) + sy); - - ty = t*axis.Y; - Cells[1][0] = vec_t( u + sz); - Cells[1][1] = vec_t( (tyy=ty*axis.Y) + c ); - Cells[1][2] = vec_t( (u=ty*axis.Z) - sx); - - Cells[2][0] = vec_t( v - sy); - Cells[2][1] = vec_t( u + sx); - Cells[2][2] = vec_t( (t-txx-tyy) + c ); } TMatrix3x3(const Vector3 &axis, double c/*cosine*/, double s/*sine*/) @@ -1106,10 +1071,10 @@ Outside comments: A faster version with only 10 (not 24) multiplies. TMatrix3x3(const Vector3 &axis, TAngle degrees); - static TMatrix3x3 Rotate2D(double radians) + static TMatrix3x3 Rotate2D(double degrees) { - double c = g_cos(radians); - double s = g_sin(radians); + double c = g_cosdeg(degrees); + double s = g_sindeg(degrees); TMatrix3x3 ret; ret.Cells[0][0] = c; ret.Cells[0][1] = -s; ret.Cells[0][2] = 0; ret.Cells[1][0] = s; ret.Cells[1][1] = c; ret.Cells[1][2] = 0; @@ -1521,12 +1486,6 @@ inline TAngle absangle(const TAngle &a1, const TAngle &a2) return fabs(deltaangle(a2, a1)); } -template -inline TAngle clamp(const TAngle &angle, const TAngle &min, const TAngle &max) -{ - return TAngle::fromDeg(clamp(angle.Degrees(), min.Degrees(), max.Degrees())); -} - inline TAngle VecToAngle(double x, double y) { return TAngle::fromRad(g_atan2(y, x)); diff --git a/src/common/utility/zstrformat.cpp b/src/common/utility/zstrformat.cpp deleted file mode 100644 index 0d8bcfbc2..000000000 --- a/src/common/utility/zstrformat.cpp +++ /dev/null @@ -1,1061 +0,0 @@ -/* -** zstrformat.cpp -** Routines for generic printf-style formatting. -** -**--------------------------------------------------------------------------- -** Copyright 2005-2008 Randy Heit -** All rights reserved. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -**--------------------------------------------------------------------------- -** -** Portions of this file relating to printing floating point numbers -** are covered by the following copyright: -** -**--------------------------------------------------------------------------- -** Copyright (c) 1990, 1993 -** The Regents of the University of California. All rights reserved. -** -** This code is derived from software contributed to Berkeley by -** Chris Torek. -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 4. Neither the name of the University nor the names of its contributors -** may be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND -** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -** ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -** SUCH DAMAGE. -** -**--------------------------------------------------------------------------- -** -** Even though the standard C library has a function to do printf-style -** formatting in a generic way, there is no standard interface to this -** function. So if you want to do some printf formatting that doesn't fit in -** the context of the provided functions, you need to roll your own. Why is -** that? -** -** Maybe Microsoft wants you to write a better one yourself? When used as -** part of a sprintf replacement, this function is significantly faster than -** Microsoft's offering. When used as part of a fprintf replacement, this -** function turns out to be slower, but that's probably because the CRT's -** fprintf can interact with the FILE object on a low level for better -** perfomance. If you sprintf into a buffer and then fwrite that buffer, this -** routine wins again, though the difference isn't great. -*/ - -#include -#include -#include -#include -#include - -#include "zstring.h" -#include "gdtoa.h" -#include "utf8.h" - - -/* - * MAXEXPDIG is the maximum number of decimal digits needed to store a - * floating point exponent in the largest supported format. It should - * be ceil(log10(LDBL_MAX_10_EXP)) or, if hexadecimal floating point - * conversions are supported, ceil(log10(LDBL_MAX_EXP)). But since it - * is presently never greater than 5 in practice, we fudge it. - */ -#define MAXEXPDIG 6 -#if LDBL_MAX_EXP > 999999 -#error "floating point buffers too small" -#endif - -#define DEFPREC 6 - -static const char hexits[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; -static const char HEXits[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; -static const char spaces[16] = {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '}; -static const char zeroes[17] = {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','.'}; - -namespace StringFormat -{ - static int writepad (OutputFunc output, void *outputData, const char *pad, int padsize, int spaceToFill); - static int printandpad (OutputFunc output, void *outputData, const char *p, const char *ep, int len, const char *with, int padsize); - static int exponent (char *p0, int exp, int fmtch); - - int Worker (OutputFunc output, void *outputData, const char *fmt, ...) - { - va_list arglist; - int len; - - va_start (arglist, fmt); - len = VWorker (output, outputData, fmt, arglist); - va_end (arglist); - return len; - } - - int VWorker (OutputFunc output, void *outputData, const char *fmt, va_list arglist) - { - const char *c; - const char *base; - int len = 0; - int width; - int precision; - int flags; - - base = c = fmt; - for (;;) - { - while (*c && *c != '%') - { - ++c; - } - if (*c == '\0') - { - return len + output (outputData, base, int(c - base)); - } - - if (c - base > 0) - { - len += output (outputData, base, int(c - base)); - } - c++; - - // Gather the flags, if any - for (flags = 0;; ++c) - { - if (*c == '-') - { - flags |= F_MINUS; // bit 0 - } - else if (*c == '+') - { - flags |= F_PLUS; // bit 1 - } - else if (*c == '0') - { - flags |= F_ZERO; // bit 2 - } - else if (*c == ' ') - { - flags |= F_BLANK; // bit 3 - } - else if (*c == '#') - { - flags |= F_HASH; // bit 4 - } - else - { - break; - } - } - - width = precision = -1; - - // Read the width, if any - if (*c == '*') - { - ++c; - width = va_arg (arglist, int); - if (width < 0) - { // Negative width means minus flag and positive width - flags |= F_MINUS; - width = -width; - } - } - else if (*c >= '0' && *c <= '9') - { - width = *c++ - '0'; - while (*c >= '0' && *c <= '9') - { - width = width * 10 + *c++ - '0'; - } - } - - // If 0 and - both appear, 0 is ignored. - // If the blank and + both appear, the blank is ignored. - flags &= ~((flags & 3) << 2); - - // Read the precision, if any - if (*c == '.') - { - precision = 0; - if (*++c == '*') - { - ++c; - precision = va_arg (arglist, int); - } - else if (*c >= '0' && *c <= '9') - { - precision = *c++ - '0'; - while (*c >= '0' && *c <= '9') - { - precision = precision * 10 + *c++ - '0'; - } - } - } - - // Read the size prefix, if any - if (*c == 'h') - { - if (*++c == 'h') - { - flags |= F_HALFHALF; - ++c; - } - else - { - flags |= F_HALF; - } - } - else if (*c == 'l') - { - if (*++c == 'l') - { - flags |= F_LONGLONG; - ++c; - } - else - { - flags |= F_LONG; - } - } - else if (*c == 'I') - { - if (*++c == '6') - { - if (*++c == '4') - { - flags |= F_LONGLONG; - ++c; - } - } - else - { - flags |= F_BIGI; - } - } - else if (*c == 't') - { - flags |= F_PTRDIFF; - ++c; - } - else if (*c == 'z') - { - flags |= F_SIZE; - ++c; - } - - base = c+1; - - // Now that that's all out of the way, we should be pointing at the type specifier - { - char prefix[3]; - int prefixlen; - char hexprefix = '\0'; - char sign = '\0'; - int postprefixzeros = 0; - int size = flags & 0xF000; - char buffer[80], *ibuff; - const char *obuff = 0; - char type = *c++; - int bufflen = 0; - int outlen = 0; - unsigned int intarg = 0; - uint64_t int64arg = 0; - const void *voidparg; - const char *charparg; - double dblarg; - const char *xits = hexits; - int inlen = len; - /* - * We can decompose the printed representation of floating - * point numbers into several parts, some of which may be empty: - * - * [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ - * A B ---C--- D E F - * - * A: 'sign' holds this value if present; '\0' otherwise - * B: hexprefix holds the 'x' or 'X'; '\0' if not hexadecimal - * C: obuff points to the string MMMNNN. Leading and trailing - * zeros are not in the string and must be added. - * D: expchar holds this character; '\0' if no exponent, e.g. %f - * F: at least two digits for decimal, at least one digit for hex - */ - const char *decimal_point = ".";/* locale specific decimal point */ - int signflag; /* true if float is negative */ - int expt = 0; /* integer value of exponent */ - char expchar = 'e'; /* exponent character: [eEpP\0] */ - char* dtoaend = nullptr; /* pointer to end of converted digits */ - int expsize = 0; /* character count for expstr */ - int ndig = 0; /* actual number of digits returned by dtoa */ - char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */ - char *dtoaresult = NULL; /* buffer allocated by dtoa */ - - // Using a bunch of if/else if statements is faster than a switch, because a switch generates - // a jump table. A jump table means a possible data cache miss and a hefty penalty while the - // cache line is loaded. - - if (type == 'x' || type == 'X' || - type == 'p' || - type == 'd' || type == 'u' || type == 'i' || - type == 'o' || - type == 'B') - { - if (type == 'X' || type == 'p') - { - xits = HEXits; - } - if (type == 'p') - { - type = 'X'; - voidparg = va_arg (arglist, void *); - if (sizeof(void*) == sizeof(int)) - { - intarg = (unsigned int)(size_t)voidparg; - precision = 8; - size = 0; - } - else - { - int64arg = (uint64_t)(size_t)voidparg; - precision = 16; - size = F_LONGLONG; - } - } - else - { - if (size == 0) - { - intarg = va_arg (arglist, int); - } - else if (size == F_HALFHALF) - { - intarg = va_arg (arglist, int); - intarg = (signed char)intarg; - } - else if (size == F_HALF) - { - intarg = va_arg (arglist, int); - intarg = (short)intarg; - } - else if (size == F_LONG) - { - if (sizeof(long) == sizeof(int)) intarg = va_arg (arglist, int); - else { int64arg = va_arg (arglist, int64_t); size = F_LONGLONG; } - } - else if (size == F_BIGI) - { - if (sizeof(void*) == sizeof(int)) intarg = va_arg (arglist, int); - else { int64arg = va_arg (arglist, int64_t); size = F_LONGLONG; } - } - else if (size == F_LONGLONG) - { - int64arg = va_arg (arglist, int64_t); - } - else if (size == F_PTRDIFF) - { - if (sizeof(ptrdiff_t) == sizeof(int)) intarg = va_arg (arglist, int); - else { int64arg = va_arg (arglist, int64_t); size = F_LONGLONG; } - } - else if (size == F_SIZE) - { - if (sizeof(size_t) == sizeof(int)) intarg = va_arg (arglist, int); - else { int64arg = va_arg (arglist, int64_t); size = F_LONGLONG; } - } - else - { - intarg = va_arg (arglist, int); - } - } - - if (precision < 0) precision = 1; - - ibuff = &buffer[sizeof(buffer)]; - - if (size == F_LONGLONG) - { - if (int64arg == 0) - { - flags |= F_ZEROVALUE; - } - else - { - if (type == 'o') - { // Octal: Dump digits until it fits in an unsigned int - while (int64arg > UINT_MAX) - { - *--ibuff = char(int64arg & 7) + '0'; int64arg >>= 3; - } - intarg = int(int64arg); - } - else if (type == 'x' || type == 'X') - { // Hexadecimal: Dump digits until it fits in an unsigned int - while (int64arg > UINT_MAX) - { - *--ibuff = xits[int64arg & 15]; int64arg >>= 4; - } - intarg = int(int64arg); - } - else if (type == 'B') - { // Binary: Dump digits until it fits in an unsigned int - while (int64arg > UINT_MAX) - { - *--ibuff = char(int64arg & 1) + '0'; int64arg >>= 1; - } - intarg = int(int64arg); - } - else - { - if (type != 'u') - { - // If a signed number is negative, set the negative flag and make it positive. - int64_t sint64arg = (int64_t)int64arg; - if (sint64arg < 0) - { - flags |= F_NEGATIVE; - sint64arg = -sint64arg; - int64arg = sint64arg; - } - flags |= F_SIGNED; - type = 'u'; - } - // If an unsigned int64 is too big to fit in an unsigned int, dump out - // digits until it is sufficiently small. - while (int64arg > INT_MAX) - { - *--ibuff = char(int64arg % 10) + '0'; int64arg /= 10; - } - intarg = (unsigned int)(int64arg); - } - } - } - else - { - if (intarg == 0) - { - flags |= F_ZEROVALUE; - } - else if (type == 'i' || type == 'd') - { // If a signed int is negative, set the negative flag and make it positive. - signed int sintarg = (signed int)intarg; - if (sintarg < 0) - { - flags |= F_NEGATIVE; - sintarg = -sintarg; - intarg = sintarg; - } - flags |= F_SIGNED; - type = 'u'; - } - } - if (flags & F_ZEROVALUE) - { - if (precision != 0) - { - *--ibuff = '0'; - } - } - else if (type == 'u') - { // Decimal - int i; - - // Unsigned division is typically slower than signed division. - // Do it at most once. - if (intarg > INT_MAX) - { - *--ibuff = char(intarg % 10) + '0'; intarg /= 10; - } - i = (int)intarg; - while (i != 0) - { - *--ibuff = char(i % 10) + '0'; i /= 10; - } - } - else if (type == 'o') - { // Octal - while (intarg != 0) - { - *--ibuff = char(intarg & 7) + '0'; intarg >>= 3; - } - } - else if (type == 'B') - { // Binary - while (intarg != 0) - { - *--ibuff = char(intarg & 1) + '0'; intarg >>= 1; - } - } - else - { // Hexadecimal - while (intarg != 0) - { - *--ibuff = xits[intarg & 15]; intarg >>= 4; - } - } - // Check for prefix (only for non-decimal, which are always unsigned) - if ((flags & (F_HASH|F_ZEROVALUE)) == F_HASH) - { - if (type == 'o') - { - if (bufflen >= precision) - { - sign = '0'; - } - } - else if (type == 'x' || type == 'X') - { - hexprefix = type; - } - else if (type == 'B') - { - hexprefix = '!'; - } - } - bufflen = (int)(ptrdiff_t)(&buffer[sizeof(buffer)] - ibuff); - obuff = ibuff; - if (precision >= 0) - { - postprefixzeros = precision - bufflen; - if (postprefixzeros < 0) postprefixzeros = 0; -// flags &= ~F_ZERO; - } - } - else if (type == 'c') - { - intarg = va_arg (arglist, int); - if (utf8_encode(intarg, (uint8_t*)buffer, &bufflen) != 0) - { - buffer[0] = '?'; - bufflen = 1; - } - obuff = buffer; - } - else if (type == 's') - { - charparg = va_arg (arglist, const char *); - if (charparg == NULL) - { - obuff = "(null)"; - bufflen = 6; - } - else - { - obuff = charparg; - if (precision < 0) - { - bufflen = (int)strlen (charparg); - } - else - { - for (bufflen = 0; bufflen < precision && charparg[bufflen] != '\0'; ++bufflen) - { /* empty */ } - } - } - } - else if (type == '%') - { // Just print a '%': Output it with the next stage. - base--; - continue; - } - else if (type == 'n') - { - if (size == F_HALFHALF) - { - *va_arg (arglist, char *) = (char)inlen; - } - else if (size == F_HALF) - { - *va_arg (arglist, short *) = (short)inlen; - } - else if (size == F_LONG) - { - *va_arg (arglist, long *) = inlen; - } - else if (size == F_LONGLONG) - { - *va_arg (arglist, int64_t *) = inlen; - } - else if (size == F_BIGI) - { - *va_arg (arglist, ptrdiff_t *) = inlen; - } - else - { - *va_arg (arglist, int *) = inlen; - } - } - else if (type == 'f' || type == 'F') - { - expchar = '\0'; - goto fp_begin; - } - else if (type == 'g' || type == 'G') - { - expchar = type - ('g' - 'e'); - if (precision == 0) - { - precision = 1; - } - goto fp_begin; - } - else if (type == 'H') - { // %H is an extension that behaves similarly to %g, except it automatically - // selects precision based on whatever will produce the smallest string. - expchar = 'e'; - goto fp_begin; - } -#if 0 - // The hdtoa function provided with FreeBSD uses a hexadecimal FP constant. - // Microsoft's compiler does not support these, so I would need to hack it - // together with ints instead. It's very do-able, but until I actually have - // some reason to print hex FP numbers, I won't bother. - else if (type == 'a' || type == 'A') - { - if (type == 'A') - { - xits = HEXits; - hexprefix = 'X'; - expchar = 'P'; - } - else - { - hexprefix = 'x'; - expchar = 'p'; - } - if (precision >= 0) - { - precision++; - } - dblarg = va_arg(arglist, double); - dtoaresult = obuff = hdtoa(dblarg, xits, precision, &expt, &signflag, &dtoaend); - if (precision < 0) - { - precision = (int)(dtoaend - obuff); - } - if (expt == INT_MAX) - { - hexprefix = '\0'; - } - goto fp_common; - } -#endif - else if (type == 'e' || type == 'E') - { - expchar = type; - if (precision < 0) // account for digit before decpt - { - precision = DEFPREC + 1; - } - else - { - precision++; - } -fp_begin: - if (precision < 0) - { - precision = DEFPREC; - } - dblarg = va_arg(arglist, double); - obuff = dtoaresult = dtoa(dblarg, type != 'H' ? (expchar ? 2 : 3) : 0, precision, &expt, &signflag, &dtoaend); -//fp_common: - decimal_point = localeconv()->decimal_point; - flags |= F_SIGNED; - if (signflag) - { - flags |= F_NEGATIVE; - } - if (expt == 9999) // inf or nan - { - if (*obuff == 'N') - { - obuff = (type >= 'a') ? "nan" : "NAN"; - flags &= ~F_SIGNED; - } - else - { - obuff = (type >= 'a') ? "inf" : "INF"; - } - bufflen = 3; - flags &= ~F_ZERO; - } - else - { - flags |= F_FPT; - ndig = (int)(dtoaend - obuff); - if (type == 'g' || type == 'G') - { - if (expt > -4 && expt <= precision) - { // Make %[gG] smell like %[fF]. - expchar = '\0'; - if (flags & F_HASH) - { - precision -= expt; - } - else - { - precision = ndig - expt; - } - if (precision < 0) - { - precision = 0; - } - } - else - { // Make %[gG] smell like %[eE], but trim trailing zeroes if no # flag. - if (!(flags & F_HASH)) - { - precision = ndig; - } - } - } - else if (type == 'H') - { - if (expt > -(ndig + 2) && expt <= (ndig + 4)) - { // Make %H smell like %f - expchar = '\0'; - precision = ndig - expt; - if (precision < 0) - { - precision = 0; - } - } - else - {// Make %H smell like %e - precision = ndig; - } - } - if (expchar) - { - expsize = exponent(expstr, expt - 1, expchar); - bufflen = expsize + precision; - if (precision > 1 || (flags & F_HASH)) - { - ++bufflen; - } - } - else - { // space for digits before decimal point - if (expt > 0) - { - bufflen = expt; - } - else // "0" - { - bufflen = 1; - } - // space for decimal pt and following digits - if (precision != 0 || (flags & F_HASH)) - { - bufflen += precision + 1; - } - } - } - } - - // Check for sign prefix (only for signed numbers) - if (flags & F_SIGNED) - { - if (flags & F_NEGATIVE) - { - sign = '-'; - } - else if (flags & F_PLUS) - { - sign = '+'; - } - else if (flags & F_BLANK) - { - sign = ' '; - } - } - - // Construct complete prefix from sign and hex prefix character - prefixlen = 0; - if (sign != '\0') - { - prefix[0] = sign; - prefixlen = 1; - } - if (hexprefix != '\0') - { - prefix[prefixlen] = '0'; - prefix[prefixlen + 1] = hexprefix; - prefixlen += 2; - } - - // Pad the output to the field width, if needed - int fieldlen = prefixlen + postprefixzeros + bufflen; - const char *pad = (flags & F_ZERO) ? zeroes : spaces; - - // If the output is right aligned and zero-padded, then the prefix must come before the padding. - if ((flags & (F_ZERO|F_MINUS)) == F_ZERO && prefixlen > 0) - { - outlen += output (outputData, prefix, prefixlen); - prefixlen = 0; - } - if (!(flags & F_MINUS) && fieldlen < width) - { // Field is right-justified, so padding comes first - outlen += writepad (output, outputData, pad, sizeof(spaces), width - fieldlen); - width = -1; - } - - // Output field: Prefix, post-prefix zeros, buffer text - if (prefixlen > 0) - { - outlen += output (outputData, prefix, prefixlen); - } - outlen += writepad (output, outputData, zeroes, sizeof(spaces), postprefixzeros); - if (!(flags & F_FPT)) - { - if (bufflen > 0) - { - outlen += output (outputData, obuff, bufflen); - } - } - else - { - if (expchar == '\0') // %[fF] or sufficiently short %[gG] - { - if (expt <= 0) - { - outlen += output (outputData, zeroes, 1); - if (precision != 0 || (flags & F_HASH)) - { - outlen += output (outputData, decimal_point, 1); - } - outlen += writepad (output, outputData, zeroes, sizeof(zeroes), -expt); - // already handled initial 0's - precision += expt; - } - else - { - outlen += printandpad (output, outputData, obuff, dtoaend, expt, zeroes, sizeof(zeroes)); - obuff += expt; - if (precision || (flags & F_HASH)) - { - outlen += output (outputData, decimal_point, 1); - } - } - outlen += printandpad (output, outputData, obuff, dtoaend, precision, zeroes, sizeof(zeroes)); - } - else // %[eE] or sufficiently long %[gG] - { - if (precision > 1 || (flags & F_HASH)) - { - buffer[0] = *obuff++; - buffer[1] = *decimal_point; - outlen += output (outputData, buffer, 2); - outlen += output (outputData, obuff, ndig - 1); - outlen += writepad (output, outputData, zeroes, sizeof(zeroes), precision - ndig); - } - else // XeYY - { - outlen += output (outputData, obuff, 1); - } - outlen += output (outputData, expstr, expsize); - } - } - - if ((flags & F_MINUS) && fieldlen < width) - { // Field is left-justified, so padding comes last - outlen += writepad (output, outputData, pad, sizeof(spaces), width - fieldlen); - } - len += outlen; - if (dtoaresult != NULL) - { - freedtoa(dtoaresult); - dtoaresult = NULL; - } - } - } - } - - static int writepad (OutputFunc output, void *outputData, const char *pad, int padsize, int spaceToFill) - { - int outlen = 0; - while (spaceToFill > 0) - { - int count = spaceToFill > padsize ? padsize : spaceToFill; - outlen += output (outputData, pad, count); - spaceToFill -= count; - } - return outlen; - } - - static int printandpad (OutputFunc output, void *outputData, const char *p, const char *ep, int len, const char *with, int padsize) - { - int outlen = 0; - int n2 = (int)(ep - p); - if (n2 > len) - { - n2 = len; - } - if (n2 > 0) - { - outlen = output (outputData, p, n2); - } - return outlen + writepad (output, outputData, with, padsize, len - (n2 > 0 ? n2 : 0)); - } - - static int exponent (char *p0, int exp, int fmtch) - { - char *p, *t; - char expbuf[MAXEXPDIG]; - - p = p0; - *p++ = fmtch; - if (exp < 0) - { - exp = -exp; - *p++ = '-'; - } - else - { - *p++ = '+'; - } - t = expbuf + MAXEXPDIG; - if (exp > 9) - { - do - { - *--t = '0' + (exp % 10); - } - while ((exp /= 10) > 9); - *--t = '0' + exp; - for(; t < expbuf + MAXEXPDIG; *p++ = *t++) - { } - } - else - { - // Exponents for decimal floating point conversions - // (%[eEgG]) must be at least two characters long, - // whereas exponents for hexadecimal conversions can - // be only one character long. - if (fmtch == 'e' || fmtch == 'E') - { - *p++ = '0'; - } - *p++ = '0' + exp; - } - return (int)(p - p0); - } -}; - -//========================================================================// -// snprintf / vsnprintf imitations - -#ifdef __GNUC__ -#define GCCPRINTF(stri,firstargi) __attribute__((format(printf,stri,firstargi))) -#define GCCFORMAT(stri) __attribute__((format(printf,stri,0))) -#define GCCNOWARN __attribute__((unused)) -#else -#define GCCPRINTF(a,b) -#define GCCFORMAT(a) -#define GCCNOWARN -#endif - -struct snprintf_state -{ - char *buffer; - size_t maxlen; - size_t curlen; - int ideallen; -}; - -static int myvsnprintf_helper(void *data, const char *cstr, int cstr_len) -{ - snprintf_state *state = (snprintf_state *)data; - - if (INT_MAX - cstr_len < state->ideallen) - { - state->ideallen = INT_MAX; - } - else - { - state->ideallen += cstr_len; - } - if (state->curlen + cstr_len > state->maxlen) - { - cstr_len = (int)(state->maxlen - state->curlen); - } - if (cstr_len > 0) - { - memcpy(state->buffer + state->curlen, cstr, cstr_len); - state->curlen += cstr_len; - } - return cstr_len; -} - -extern "C" -{ - -// Unlike the MS CRT function snprintf, this one always writes a terminating -// null character to the buffer. It also returns the full length of the string -// that would have been output if the buffer had been large enough. In other -// words, it follows BSD/Linux rules and not MS rules. -int myvsnprintf(char *buffer, size_t count, const char *format, va_list argptr) -{ - size_t originalcount = count; - if (count != 0) - { - count--; - } - if (count > INT_MAX) - { // This is probably an error. Output nothing. - originalcount = 0; - count = 0; - } - snprintf_state state = { buffer, count, 0, 0 }; - StringFormat::VWorker(myvsnprintf_helper, &state, format, argptr); - if (originalcount > 0) - { - buffer[state.curlen] = '\0'; - } - return state.ideallen; -} - -int mysnprintf(char *buffer, size_t count, const char *format, ...) -{ - va_list argptr; - va_start(argptr, format); - int len = myvsnprintf(buffer, count, format, argptr); - va_end(argptr); - return len; -} - -} diff --git a/src/common/utility/zstring.cpp b/src/common/utility/zstring.cpp index 2b3c4f1fe..e32dd97a0 100644 --- a/src/common/utility/zstring.cpp +++ b/src/common/utility/zstring.cpp @@ -39,6 +39,7 @@ #include "zstring.h" #include "utf8.h" +#include "stb_sprintf.h" extern uint16_t lowerforupper[65536]; extern uint16_t upperforlower[65536]; @@ -274,25 +275,28 @@ void FString::Format (const char *fmt, ...) void FString::AppendFormat (const char *fmt, ...) { + char workbuf[STB_SPRINTF_MIN]; va_list arglist; va_start (arglist, fmt); - StringFormat::VWorker (FormatHelper, this, fmt, arglist); + stbsp_vsprintfcb(FormatHelper, this, workbuf, fmt, arglist); va_end (arglist); } void FString::VFormat (const char *fmt, va_list arglist) { + char workbuf[STB_SPRINTF_MIN]; Data()->Release(); Chars = (char *)(FStringData::Alloc(128) + 1); - StringFormat::VWorker (FormatHelper, this, fmt, arglist); + stbsp_vsprintfcb(FormatHelper, this, workbuf, fmt, arglist); } void FString::VAppendFormat (const char *fmt, va_list arglist) { - StringFormat::VWorker (FormatHelper, this, fmt, arglist); + char workbuf[STB_SPRINTF_MIN]; + stbsp_vsprintfcb(FormatHelper, this, workbuf, fmt, arglist); } -int FString::FormatHelper (void *data, const char *cstr, int len) +char* FString::FormatHelper (const char *cstr, void* data, int len) { FString *str = (FString *)data; size_t len1 = str->Len(); @@ -302,7 +306,7 @@ int FString::FormatHelper (void *data, const char *cstr, int len) } StrCopy (str->Chars + len1, cstr, len); str->Data()->Len = (unsigned int)(len1 + len); - return len; + return (char*)cstr; } FString FString::operator + (const FString &tail) const @@ -1322,19 +1326,6 @@ FString &FString::operator=(const wchar_t *copyStr) return *this; } -std::wstring WideString(const char *cin) -{ - if (!cin) return L""; - const uint8_t *in = (const uint8_t*)cin; - // This is a bit tricky because we need to support both UTF-8 and legacy content in ISO-8859-1 - // and thanks to user-side string manipulation it can be that a text mixes both. - // To convert the string this uses the same function as all text printing in the engine. - TArray buildbuffer; - while (*in) buildbuffer.Push((wchar_t)GetCharFromString(in)); - buildbuffer.Push(0); - return std::wstring(buildbuffer.Data()); -} - static HANDLE StringHeap; const SIZE_T STRING_HEAP_SIZE = 64*1024; #endif diff --git a/src/common/utility/zstring.h b/src/common/utility/zstring.h index 4640d5c28..50e41d9c6 100644 --- a/src/common/utility/zstring.h +++ b/src/common/utility/zstring.h @@ -39,6 +39,7 @@ #include #include #include "tarray.h" +#include "utf8.h" #ifdef __GNUC__ #define PRINTFISH(x) __attribute__((format(printf, 2, x))) @@ -57,10 +58,6 @@ #define IGNORE_FORMAT_POST #endif -#ifdef _WIN32 -std::wstring WideString(const char *); -#endif - struct FStringData { unsigned int Len; // Length of string, excluding terminating null @@ -364,7 +361,7 @@ protected: void AllocBuffer (size_t len); void ReallocBuffer (size_t newlen); - static int FormatHelper (void *data, const char *str, int len); + static char* FormatHelper (const char *str, void* data, int len); static void StrCopy (char *to, const char *from, size_t len); static void StrCopy (char *to, const FString &from); @@ -431,6 +428,7 @@ public: }; +/* namespace StringFormat { enum @@ -461,6 +459,7 @@ namespace StringFormat int VWorker (OutputFunc output, void *outputData, const char *fmt, va_list arglist); int Worker (OutputFunc output, void *outputData, const char *fmt, ...); }; +*/ #undef PRINTFISH diff --git a/src/ct_chat.cpp b/src/ct_chat.cpp index 5f16a872a..1ced34702 100644 --- a/src/ct_chat.cpp +++ b/src/ct_chat.cpp @@ -374,14 +374,13 @@ static void ShoveChatStr (const char *str, uint8_t who) Net_WriteByte (DEM_SAY); Net_WriteByte (who); - if (!chat_substitution || !DoSubstitution (substBuff, str)) + if (chat_substitution && DoSubstitution (substBuff, str)) { - Net_WriteString(MakeUTF8(str)); - } - else - { - Net_WriteString(MakeUTF8(substBuff)); + str = substBuff.GetChars(); } + + Net_WriteString(CleanseString(const_cast(MakeUTF8(str)))); + } //=========================================================================== diff --git a/src/d_iwad.cpp b/src/d_iwad.cpp index 4266b75a7..27bcb7276 100644 --- a/src/d_iwad.cpp +++ b/src/d_iwad.cpp @@ -308,8 +308,7 @@ FIWadManager::FIWadManager(const char *firstfn, const char *optfn) fns.Push(firstfn); if (optfn) fns.Push(optfn); - check.InitMultipleFiles(fns, true); - if (check.GetNumEntries() > 0) + if (check.InitMultipleFiles(fns, nullptr, nullptr)) { int num = check.CheckNumForName("IWADINFO"); if (num >= 0) @@ -331,7 +330,7 @@ FIWadManager::FIWadManager(const char *firstfn, const char *optfn) int FIWadManager::ScanIWAD (const char *iwad) { FileSystem check; - check.InitSingleFile(iwad, true); + check.InitSingleFile(iwad, nullptr); mLumpsFound.Resize(mIWadInfos.Size()); @@ -390,8 +389,7 @@ int FIWadManager::CheckIWADInfo(const char* fn) TArray filenames; filenames.Push(fn); - check.InitMultipleFiles(filenames, true, &lfi); - if (check.GetNumEntries() > 0) + if (check.InitMultipleFiles(filenames, &lfi, nullptr)) { int num = check.CheckNumForName("IWADINFO"); if (num >= 0) diff --git a/src/d_main.cpp b/src/d_main.cpp index 77cfa7d3d..bcd99a829 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -1937,8 +1937,7 @@ static FString CheckGameInfo(TArray & pwads) GetReserved(lfi); // Open the entire list as a temporary file system and look for a GAMEINFO lump. The last one will automatically win. - check.InitMultipleFiles(pwads, true, &lfi); - if (check.GetNumEntries() > 0) + if (check.InitMultipleFiles(pwads, &lfi, nullptr)) { int num = check.CheckNumForName("GAMEINFO"); if (num >= 0) @@ -3044,6 +3043,35 @@ static FILE* D_GetHashFile() return hashfile; } +static int FileSystemPrintf(FSMessageLevel level, const char* fmt, ...) +{ + va_list arg; + va_start(arg, fmt); + FString text; + text.VFormat(fmt, arg); + switch (level) + { + case FSMessageLevel::Error: + return Printf(TEXTCOLOR_RED "%s", text.GetChars()); + break; + case FSMessageLevel::Warning: + Printf(TEXTCOLOR_YELLOW "%s", text.GetChars()); + break; + case FSMessageLevel::Attention: + Printf(TEXTCOLOR_BLUE "%s", text.GetChars()); + break; + case FSMessageLevel::Message: + Printf("%s", text.GetChars()); + break; + case FSMessageLevel::DebugWarn: + DPrintf(DMSG_WARNING, "%s", text.GetChars()); + break; + case FSMessageLevel::DebugNotify: + DPrintf(DMSG_NOTIFY, "%s", text.GetChars()); + break; + } + return text.Len(); +} //========================================================================== // // D_InitGame @@ -3132,7 +3160,10 @@ static int D_InitGame(const FIWADInfo* iwad_info, TArray& allwads, TArr bool allowduplicates = Args->CheckParm("-allowduplicates"); auto hashfile = D_GetHashFile(); - fileSystem.InitMultipleFiles (allwads, false, &lfi, allowduplicates, hashfile); + if (!fileSystem.InitMultipleFiles(allwads, &lfi, FileSystemPrintf, allowduplicates, hashfile)) + { + I_FatalError("FileSystem: no files found"); + } allwads.Clear(); allwads.ShrinkToFit(); SetMapxxFlag(); @@ -3928,6 +3959,22 @@ void I_UpdateWindowTitle() I_SetWindowTitle(copy.Data()); } +CCMD(fs_dir) +{ + int numfiles = fileSystem.GetNumEntries(); + + for (int i = 0; i < numfiles; i++) + { + auto container = fileSystem.GetResourceFileFullName(fileSystem.GetFileContainer(i)); + auto fn1 = fileSystem.GetFileFullName(i); + auto fns = fileSystem.GetFileShortName(i); + auto fnid = fileSystem.GetResourceId(i); + auto length = fileSystem.FileLength(i); + bool hidden = fileSystem.FindFile(fn1) != i; + Printf(PRINT_HIGH | PRINT_NONOTIFY, "%s%-64s %-15s (%5d) %10d %s %s\n", hidden ? TEXTCOLOR_RED : TEXTCOLOR_UNTRANSLATED, fn1, fns, fnid, length, container, hidden ? "(h)" : ""); + } +} + #ifdef _WIN32 // For broadest GL compatibility, require user to explicitly enable quad-buffered stereo mode. // Setting vr_enable_quadbuffered_stereo does not automatically invoke quad-buffered stereo, diff --git a/src/d_net.cpp b/src/d_net.cpp index 80f43e1a2..4f86f0da4 100644 --- a/src/d_net.cpp +++ b/src/d_net.cpp @@ -1406,7 +1406,6 @@ struct ArbitrateData bool DoArbitrate (void *userdata) { ArbitrateData *data = (ArbitrateData *)userdata; - char *s; uint8_t *stream; int version; int node; @@ -1468,9 +1467,7 @@ bool DoArbitrate (void *userdata) NetMode = netbuffer[2]; stream = &netbuffer[3]; - s = ReadString (&stream); - startmap = s; - delete[] s; + startmap = ReadStringConst(&stream); rngseed = ReadLong (&stream); C_ReadCVars (&stream); } @@ -2166,7 +2163,7 @@ static int RemoveClass(FLevelLocals *Level, const PClass *cls) void Net_DoCommand (int type, uint8_t **stream, int player) { uint8_t pos = 0; - char *s = NULL; + const char* s = nullptr; int i; switch (type) @@ -2176,8 +2173,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) const char *name = players[player].userinfo.GetName(); uint8_t who = ReadByte (stream); - s = ReadString (stream); - CleanseString (s); + s = ReadStringConst(stream); if (((who & 1) == 0) || players[player].userinfo.GetTeam() == TEAM_NONE) { // Said to everyone if (who & 2) @@ -2206,18 +2202,15 @@ void Net_DoCommand (int type, uint8_t **stream, int player) break; case DEM_MUSICCHANGE: - s = ReadString (stream); - S_ChangeMusic (s); + S_ChangeMusic(ReadStringConst(stream)); break; case DEM_PRINT: - s = ReadString (stream); - Printf ("%s", s); + Printf("%s", ReadStringConst(stream)); break; case DEM_CENTERPRINT: - s = ReadString (stream); - C_MidPrint (nullptr, s); + C_MidPrint(nullptr, ReadStringConst(stream)); break; case DEM_UINFCHANGED: @@ -2233,7 +2226,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) break; case DEM_GIVECHEAT: - s = ReadString (stream); + s = ReadStringConst(stream); cht_Give (&players[player], s, ReadLong (stream)); if (player != consoleplayer) { @@ -2245,12 +2238,12 @@ void Net_DoCommand (int type, uint8_t **stream, int player) break; case DEM_TAKECHEAT: - s = ReadString (stream); + s = ReadStringConst(stream); cht_Take (&players[player], s, ReadLong (stream)); break; case DEM_SETINV: - s = ReadString(stream); + s = ReadStringConst(stream); i = ReadLong(stream); cht_SetInv(&players[player], s, i, !!ReadByte(stream)); break; @@ -2274,7 +2267,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) /* intentional fall-through */ case DEM_CHANGEMAP: // Change to another map without disconnecting other players - s = ReadString (stream); + s = ReadStringConst(stream); // Using LEVEL_NOINTERMISSION tends to throw the game out of sync. // That was a long time ago. Maybe it works now? primaryLevel->flags |= LEVEL_CHANGEMAPCHEAT; @@ -2361,7 +2354,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) uint8_t special = 0; int args[5]; - s = ReadString (stream); + s = ReadStringConst(stream); if (type >= DEM_SUMMON2 && type <= DEM_SUMMONFOE2) { angle = ReadWord(stream); @@ -2425,12 +2418,12 @@ void Net_DoCommand (int type, uint8_t **stream, int player) break; case DEM_SPRAY: - s = ReadString(stream); + s = ReadStringConst(stream); SprayDecal(players[player].mo, s); break; case DEM_MDK: - s = ReadString(stream); + s = ReadStringConst(stream); cht_DoMDK(&players[player], s); break; @@ -2453,11 +2446,8 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_SAVEGAME: if (gamestate == GS_LEVEL) { - s = ReadString (stream); - savegamefile = s; - delete[] s; - s = ReadString (stream); - savedescription = s; + savegamefile = ReadStringConst(stream); + savedescription = ReadStringConst(stream); if (player != consoleplayer) { // Paths sent over the network will be valid for the system that sent @@ -2525,7 +2515,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_RUNNAMEDSCRIPT: { - s = ReadString(stream); + s = ReadStringConst(stream); int argn = ReadByte(stream); RunScript(stream, players[player].mo, -FName(s).GetIndex(), argn & 127, (argn & 128) ? ACS_ALWAYS : 0); @@ -2564,8 +2554,8 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_MORPHEX: { - s = ReadString (stream); - FString msg = cht_Morph (players + player, PClass::FindActor (s), false); + s = ReadStringConst(stream); + FString msg = cht_Morph (players + player, PClass::FindActor(s), false); if (player == consoleplayer) { Printf ("%s\n", msg[0] != '\0' ? msg.GetChars() : "Morph failed."); @@ -2595,7 +2585,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_KILLCLASSCHEAT: { - s = ReadString (stream); + s = ReadStringConst(stream); int killcount = 0; PClassActor *cls = PClass::FindActor(s); @@ -2618,7 +2608,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) break; case DEM_REMOVE: { - s = ReadString(stream); + s = ReadStringConst(stream); int removecount = 0; PClassActor *cls = PClass::FindActor(s); if (cls != NULL && cls->IsDescendantOf(RUNTIME_CLASS(AActor))) @@ -2702,7 +2692,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player) case DEM_NETEVENT: { - s = ReadString(stream); + s = ReadStringConst(stream); int argn = ReadByte(stream); int arg[3] = { 0, 0, 0 }; for (int i = 0; i < 3; i++) @@ -2720,9 +2710,6 @@ void Net_DoCommand (int type, uint8_t **stream, int player) I_Error ("Unknown net command: %d", type); break; } - - if (s) - delete[] s; } // Used by DEM_RUNSCRIPT, DEM_RUNSCRIPT2, and DEM_RUNNAMEDSCRIPT diff --git a/src/g_game.cpp b/src/g_game.cpp index 7ed108cce..6e80c7708 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -317,7 +317,8 @@ CCMD (slot) } // [Nash] Option to display the name of the weapon being switched to. - if ((paused || pauseext) || players[consoleplayer].playerstate != PST_LIVE) return; + if ((paused || pauseext) || players[consoleplayer].playerstate != PST_LIVE) + return; if (SendItemUse != players[consoleplayer].ReadyWeapon && (displaynametags & 2) && StatusBar && SmallFont && SendItemUse) { StatusBar->AttachMessage(Create(nullptr, SendItemUse->GetTag(), @@ -328,6 +329,8 @@ CCMD (slot) CCMD (centerview) { + if ((players[consoleplayer].cheats & CF_TOTALLYFROZEN)) + return; Net_WriteByte (DEM_CENTERVIEW); } @@ -1972,7 +1975,7 @@ void G_DoLoadGame () hidecon = gameaction == ga_loadgamehidecon; gameaction = ga_nothing; - std::unique_ptr resfile(FResourceFile::OpenResourceFile(savename.GetChars(), true, true)); + std::unique_ptr resfile(FResourceFile::OpenResourceFile(savename.GetChars(), true)); if (resfile == nullptr) { LoadGameError("TXT_COULDNOTREAD"); diff --git a/src/g_game.h b/src/g_game.h index cbb18d5d6..caaf93188 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -30,6 +30,8 @@ struct event_t; +#include + #include "dobjgc.h" #include "name.h" #include "gamestate.h" diff --git a/src/g_level.cpp b/src/g_level.cpp index 9e2f7dd9b..f66999e0a 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -146,17 +146,30 @@ CUSTOM_CVAR(Bool, gl_notexturefill, false, CVAR_NOINITCALL) } } -CUSTOM_CVAR(Int, gl_lightmode, 8, CVAR_ARCHIVE | CVAR_NOINITCALL) +CUSTOM_CVAR(Int, gl_maplightmode, -1, CVAR_NOINITCALL) // this is just for testing. -1 means 'inactive' { - int newself = self; - if (newself > 8) newself = 16; // use 8 and 16 for software lighting to avoid conflicts with the bit mask ( in hindsight a bad idea.) - else if (newself > 5) newself = 8; - else if (newself < 0) newself = 0; - if (self != newself) self = newself; - else for (auto Level : AllLevels()) + if (self > 5 || self < -1) self = -1; +} + +CUSTOM_CVAR(Int, gl_lightmode, 1, CVAR_ARCHIVE | CVAR_NOINITCALL) +{ + if (self < 0 || self > 2) self = 2; +} + +ELightMode getRealLightmode(FLevelLocals* Level, bool for3d) +{ + auto lightmode = Level->info->lightmode; + if (lightmode == ELightMode::NotSet) { - if ((Level->info == nullptr || Level->info->lightmode == ELightMode::NotSet)) Level->lightMode = (ELightMode)*self; + if (gl_maplightmode != -1) lightmode = (ELightMode)*gl_maplightmode; + else lightmode = ELightMode::Doom; } + if (lightmode == ELightMode::Doom && for3d) + { + if (gl_lightmode == 1) lightmode = ELightMode::ZDoomSoftware; + else if (gl_lightmode == 2) lightmode = ELightMode::DoomSoftware; + } + return lightmode; } CVAR(Int, sv_alwaystally, 0, CVAR_SERVERINFO) @@ -1870,7 +1883,6 @@ void FLevelLocals::Init() DefaultEnvironment = info->DefaultEnvironment; - lightMode = info->lightmode == ELightMode::NotSet? (ELightMode)*gl_lightmode : info->lightmode; brightfog = info->brightfog < 0? gl_brightfog : !!info->brightfog; lightadditivesurfaces = info->lightadditivesurfaces < 0 ? gl_lightadditivesurfaces : !!info->lightadditivesurfaces; notexturefill = info->notexturefill < 0 ? gl_notexturefill : !!info->notexturefill; diff --git a/src/g_levellocals.h b/src/g_levellocals.h index 0509b114c..19c154bd6 100644 --- a/src/g_levellocals.h +++ b/src/g_levellocals.h @@ -680,7 +680,6 @@ public: float MusicVolume; // Hardware render stuff that can either be set via CVAR or MAPINFO - ELightMode lightMode; bool brightfog; bool lightadditivesurfaces; bool notexturefill; @@ -880,3 +879,5 @@ inline TArrayView AllLevels() { return TArrayView(&primaryLevel, 1); } + +ELightMode getRealLightmode(FLevelLocals* Level, bool for3d); diff --git a/src/g_statusbar/hudmessages.cpp b/src/g_statusbar/hudmessages.cpp index ccf6174c3..c03d3cdd4 100644 --- a/src/g_statusbar/hudmessages.cpp +++ b/src/g_statusbar/hudmessages.cpp @@ -208,28 +208,13 @@ DHUDMessage::DHUDMessage (FFont *font, const char *text, float x, float y, int h TextColor = textColor; State = 0; - SourceText = copystring (text); + SourceText = text; VisibilityFlags = 0; Style = STYLE_Translucent; Alpha = 1.; ResetText (SourceText); } -//============================================================================ -// -// DHUDMessage Destructor -// -//============================================================================ - -void DHUDMessage::OnDestroy() -{ - if (SourceText != NULL) - { - delete[] SourceText; - SourceText = nullptr; - } -} - //============================================================================ // // DHUDMessage :: Serialize @@ -263,7 +248,7 @@ void DHUDMessage::Serialize(FSerializer &arc) if (arc.isReading()) { - ResetText(SourceText); + ResetText(SourceText.GetChars()); } } @@ -277,7 +262,7 @@ void DHUDMessage::ScreenSizeChanged () { if (HUDWidth == 0) { - ResetText (SourceText); + ResetText (SourceText.GetChars()); } } diff --git a/src/g_statusbar/sbar.h b/src/g_statusbar/sbar.h index 278f6d923..767e4de6e 100644 --- a/src/g_statusbar/sbar.h +++ b/src/g_statusbar/sbar.h @@ -99,7 +99,6 @@ class DHUDMessage : public DHUDMessageBase public: DHUDMessage (FFont *font, const char *text, float x, float y, int hudwidth, int hudheight, EColorRange textColor, float holdTime); - virtual void OnDestroy () override; virtual void Serialize(FSerializer &arc); @@ -125,7 +124,7 @@ public: void SetNoWrap(bool nowrap) { NoWrap = nowrap; - ResetText(SourceText); + ResetText(SourceText.GetChars()); } void SetClipRect(int x, int y, int width, int height, bool aspect) { @@ -138,7 +137,7 @@ public: void SetWrapWidth(int wrap) { WrapWidth = wrap; - ResetText(SourceText); + ResetText(SourceText.GetChars()); } protected: @@ -160,10 +159,10 @@ protected: double Alpha; void CalcClipCoords(int hudheight); - DHUDMessage () : SourceText(NULL) {} + DHUDMessage() = default; private: - char *SourceText; + FString SourceText; }; diff --git a/src/gameconfigfile.cpp b/src/gameconfigfile.cpp index a054d5930..45e2a035e 100644 --- a/src/gameconfigfile.cpp +++ b/src/gameconfigfile.cpp @@ -598,6 +598,15 @@ void FGameConfigFile::DoGlobalSetup () var->SetGenericRep(v, CVAR_Float); } } + if (last < 225) + { + if (const auto var = FindCVar("gl_lightmode", NULL)) + { + UCVarValue v = var->GetGenericRep(CVAR_Int); + v.Int /= 8; // all legacy modes map to 0, ZDoom software to 1 and Vanilla software to 2. + var->SetGenericRep(v, CVAR_Int); + } + } } } } diff --git a/src/gamedata/d_dehacked.cpp b/src/gamedata/d_dehacked.cpp index 442068a67..96925365c 100644 --- a/src/gamedata/d_dehacked.cpp +++ b/src/gamedata/d_dehacked.cpp @@ -1016,7 +1016,7 @@ static void SetDehParams(FState *state, int codepointer, VMDisassemblyDumper &di sfunc->NumArgs = numargs; sfunc->ImplicitArgs = numargs; state->SetAction(sfunc); - sfunc->PrintableName.Format("Dehacked.%s.%d.%d", MBFCodePointers[codepointer].name.GetChars(), value1, value2); + sfunc->PrintableName = ClassDataAllocator.Strdup(FStringf("Dehacked.%s.%d.%d", MBFCodePointers[codepointer].name.GetChars(), value1, value2)); disasmdump.Write(sfunc, sfunc->PrintableName); diff --git a/src/gamedata/g_mapinfo.cpp b/src/gamedata/g_mapinfo.cpp index df99618ca..6ebd91634 100644 --- a/src/gamedata/g_mapinfo.cpp +++ b/src/gamedata/g_mapinfo.cpp @@ -1522,7 +1522,8 @@ DEFINE_MAP_OPTION(lightmode, false) parse.ParseAssign(); parse.sc.MustGetNumber(); - if ((parse.sc.Number >= 0 && parse.sc.Number <= 4) || parse.sc.Number == 8 || parse.sc.Number == 16) + if (parse.sc.Number == 8 || parse.sc.Number == 16) info->lightmode = ELightMode::NotSet; + else if (parse.sc.Number >= 0 && parse.sc.Number <= 5) { info->lightmode = ELightMode(parse.sc.Number); } diff --git a/src/gamedata/info.cpp b/src/gamedata/info.cpp index 3736cb4d2..2e0109db4 100644 --- a/src/gamedata/info.cpp +++ b/src/gamedata/info.cpp @@ -132,16 +132,16 @@ void FState::CheckCallerType(AActor *self, AActor *stateowner) // This should really never happen. Any valid action function must have actor pointers here. if (!requiredType->isObjectPointer()) { - ThrowAbortException(X_OTHER, "Bad function prototype in function call to %s", ActionFunc->PrintableName.GetChars()); + ThrowAbortException(X_OTHER, "Bad function prototype in function call to %s", ActionFunc->PrintableName); } auto cls = static_cast(requiredType)->PointedClass(); if (check == nullptr) { - ThrowAbortException(X_OTHER, "%s called without valid caller. %s expected", ActionFunc->PrintableName.GetChars(), cls->TypeName.GetChars()); + ThrowAbortException(X_OTHER, "%s called without valid caller. %s expected", ActionFunc->PrintableName, cls->TypeName.GetChars()); } if (!(StateFlags & STF_DEHACKED) && !check->IsKindOf(cls)) { - ThrowAbortException(X_OTHER, "Invalid class %s in function call to %s. %s expected", check->GetClass()->TypeName.GetChars(), ActionFunc->PrintableName.GetChars(), cls->TypeName.GetChars()); + ThrowAbortException(X_OTHER, "Invalid class %s in function call to %s. %s expected", check->GetClass()->TypeName.GetChars(), ActionFunc->PrintableName, cls->TypeName.GetChars()); } }; diff --git a/src/gamedata/textures/animations.cpp b/src/gamedata/textures/animations.cpp index 61bb6d29c..0091a3ba5 100644 --- a/src/gamedata/textures/animations.cpp +++ b/src/gamedata/textures/animations.cpp @@ -742,6 +742,17 @@ void FTextureAnimator::ParseCameraTexture(FScanner &sc) TexMan.AddGameTexture (viewer); } if (sc.GetString()) + { + if (sc.Compare ("hdr")) + { + canvas->SetHDR(true); + } + else + { + sc.UnGet(); + } + } + if (sc.GetString()) { if (sc.Compare ("fit")) { diff --git a/src/maploader/glnodes.cpp b/src/maploader/glnodes.cpp index 21da9462a..b7d773f03 100644 --- a/src/maploader/glnodes.cpp +++ b/src/maploader/glnodes.cpp @@ -883,7 +883,7 @@ bool MapLoader::LoadGLNodes(MapData * map) strcpy(ext, ".gwa"); // Todo: Compare file dates - f_gwa = FResourceFile::OpenResourceFile(path, true); + f_gwa = FResourceFile::OpenResourceFile(path); if (f_gwa==nullptr) return false; strncpy(map->MapLumps[0].Name, fileSystem.GetFileFullName(map->lumpnum), 8); diff --git a/src/menu/loadsavemenu.cpp b/src/menu/loadsavemenu.cpp index 3eba26114..aaeb5ccbf 100644 --- a/src/menu/loadsavemenu.cpp +++ b/src/menu/loadsavemenu.cpp @@ -77,7 +77,7 @@ void FSavegameManager::ReadSaveStrings() // I_FindName only returns the file's name and not its full path FString filepath = G_BuildSaveName(I_FindName(&c_file)); - std::unique_ptr savegame(FResourceFile::OpenResourceFile(filepath, true, true)); + std::unique_ptr savegame(FResourceFile::OpenResourceFile(filepath, true)); if (savegame != nullptr) { bool oldVer = false; diff --git a/src/p_openmap.cpp b/src/p_openmap.cpp index 771ae1d87..759c54022 100644 --- a/src/p_openmap.cpp +++ b/src/p_openmap.cpp @@ -125,7 +125,7 @@ MapData *P_OpenMapData(const char * mapname, bool justcheck) delete map; return NULL; } - map->resource = FResourceFile::OpenResourceFile(mapname, true); + map->resource = FResourceFile::OpenResourceFile(mapname); wadReader = map->resource->GetReader(); } else diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 569e9052c..2b9bd1ed8 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -969,6 +969,7 @@ void FLevelLocals::Serialize(FSerializer &arc, bool hubload) arc("flags", flags) ("flags2", flags2) + ("flags3", flags3) ("vkdflags", vkdflags) ("fadeto", fadeto) ("found_secrets", found_secrets) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 17ff41ae8..2528e0e76 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -285,7 +285,7 @@ void FLevelLocals::ClearLevelData(bool fullgc) auto it = GetThinkerIterator(NAME_None, STAT_TRAVELLING); for (AActor *actor = it.Next(); actor != nullptr; actor = it.Next()) { - actor->BlockingLine = nullptr; + actor->BlockingLine = actor->MovementBlockingLine = nullptr; actor->BlockingFloor = actor->BlockingCeiling = actor->Blocking3DFloor = nullptr; } } diff --git a/src/playsim/a_sharedglobal.h b/src/playsim/a_sharedglobal.h index 3c86aa109..466ec5c60 100644 --- a/src/playsim/a_sharedglobal.h +++ b/src/playsim/a_sharedglobal.h @@ -116,6 +116,7 @@ enum QF_GROUNDONLY = 1 << 7, QF_AFFECTACTORS = 1 << 8, QF_SHAKEONLY = 1 << 9, + QF_DAMAGEFALLOFF = 1 << 10, }; struct FQuakeJiggers @@ -134,8 +135,8 @@ class DEarthquake : public DThinker public: static const int DEFAULT_STAT = STAT_EARTHQUAKE; void Construct(AActor *center, double intensityX, double intensityY, double intensityZ, int duration, - int damrad, int tremrad, FSoundID quakesfx, int flags, - double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, double rollIntensity, double rollWave); + int damrad, int tremrad, FSoundID quakesfx, int flags, + double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage); void Serialize(FSerializer &arc); void Tick (); @@ -150,11 +151,13 @@ public: double m_Falloff; int m_Highpoint, m_MiniCount; double m_RollIntensity, m_RollWave; + double m_DamageMultiplier, m_ThrustMultiplier; + int m_Damage; double GetModIntensity(double intensity, bool fake = false) const; double GetModWave(double ticFrac, double waveMultiplier) const; - double GetFalloff(double dist) const; - void DoQuakeDamage(DEarthquake *quake, AActor *victim) const; + double GetFalloff(double dist, double radius) const; + void DoQuakeDamage(DEarthquake *quake, AActor *victim, bool falloff) const; static int StaticGetQuakeIntensities(double ticFrac, AActor *viewer, FQuakeJiggers &jiggers); }; diff --git a/src/playsim/actor.h b/src/playsim/actor.h index c89a6ec4e..4819dc603 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -206,8 +206,7 @@ enum ActorFlag2 // but still considered solid MF2_INVULNERABLE = 0x08000000, // mobj is invulnerable MF2_DORMANT = 0x10000000, // thing is dormant - MF2_ARGSDEFINED = 0x20000000, // Internal flag used by DECORATE to signal that the - // args should not be taken from the mapthing definition + MF2_ARGSDEFINED = 0x20000000, // Internal flag used by DECORATE to signal that the args should not be taken from the mapthing definition MF2_SEEKERMISSILE = 0x40000000, // is a seeker (for reflection) MF2_REFLECTIVE = 0x80000000, // reflects missiles }; @@ -394,11 +393,13 @@ enum ActorFlag7 MF7_SPRITEANGLE = 0x02000000, // [MC] Utilize the SpriteAngle property and lock the rotation to the degrees specified. MF7_SMASHABLE = 0x04000000, // dies if hitting the floor. MF7_NOSHIELDREFLECT = 0x08000000, // will not be reflected by shields. - MF7_FORCEZERORADIUSDMG = 0x10000000, // passes zero radius damage on to P_DamageMobj, this is necessary in some cases where DoSpecialDamage gets overrideen. + MF7_FORCEZERORADIUSDMG = 0x10000000,// passes zero radius damage on to P_DamageMobj, this is necessary in some cases where DoSpecialDamage gets overrideen. MF7_NOINFIGHTSPECIES = 0x20000000, // don't start infights with one's own species. MF7_FORCEINFIGHTING = 0x40000000, // overrides a map setting of 'no infighting'. MF7_INCHASE = 0x80000000, // [RH] used by A_Chase and A_Look to avoid recursion }; + +// --- mobj.flags8 --- enum ActorFlag8 { MF8_FRIGHTENING = 0x00000001, // for those moments when halloween just won't do @@ -428,12 +429,21 @@ enum ActorFlag8 MF8_STAYONLIFT = 0x02000000, // MBF AI enhancement. MF8_DONTFOLLOWPLAYERS = 0x04000000, // [inkoalawetrust] Friendly monster will not follow players. MF8_SEEFRIENDLYMONSTERS = 0X08000000, // [inkoalawetrust] Hostile monster can see friendly monsters. - MF8_CROSSLINECHECK = 0x10000000, // [MC]Enables CanCrossLine virtual + MF8_CROSSLINECHECK = 0x10000000, // [MC] Enables CanCrossLine virtual MF8_MASTERNOSEE = 0x20000000, // Don't show object in first person if their master is the current camera. MF8_ADDLIGHTLEVEL = 0x40000000, // [MC] Actor light level is additive with sector. MF8_ONLYSLAMSOLID = 0x80000000, // [B] Things with skullfly will ignore non-solid Actors. }; +// --- mobj.flags9 --- +enum ActorFlag9 +{ + MF9_SHADOWAIM = 0x00000001, // [inkoalawetrust] Monster still gets aim penalty from aiming at shadow actors even with MF6_SEEINVISIBLE on. + MF9_DOSHADOWBLOCK = 0x00000002, // [inkoalawetrust] Should the monster look for SHADOWBLOCK actors ? + MF9_SHADOWBLOCK = 0x00000004, // [inkoalawetrust] Actors in the line of fire with this flag trigger the MF_SHADOW aiming penalty. + MF9_SHADOWAIMVERT = 0x00000008, // [inkoalawetrust] Monster aim is also offset vertically when aiming at shadow actors. +}; + // --- mobj.renderflags --- enum ActorRenderFlag { @@ -588,6 +598,7 @@ typedef TFlags ActorFlags5; typedef TFlags ActorFlags6; typedef TFlags ActorFlags7; typedef TFlags ActorFlags8; +typedef TFlags ActorFlags9; typedef TFlags ActorRenderFlags; typedef TFlags ActorRenderFlags2; typedef TFlags ActorBounceFlags; @@ -600,6 +611,7 @@ DEFINE_TFLAGS_OPERATORS (ActorFlags5) DEFINE_TFLAGS_OPERATORS (ActorFlags6) DEFINE_TFLAGS_OPERATORS (ActorFlags7) DEFINE_TFLAGS_OPERATORS (ActorFlags8) +DEFINE_TFLAGS_OPERATORS (ActorFlags9) DEFINE_TFLAGS_OPERATORS (ActorRenderFlags) DEFINE_TFLAGS_OPERATORS (ActorRenderFlags2) DEFINE_TFLAGS_OPERATORS (ActorBounceFlags) @@ -838,6 +850,11 @@ public: // (virtual on the script side only) int SpecialMissileHit (AActor *victim); + // Called when bouncing to allow for custom behavior. + // Returns -1 for normal behavior, 0 to stop, and 1 to keep going. + // (virtual on the script side only) + int SpecialBounceHit(AActor* bounceMobj, line_t* bounceLine, secplane_t* bouncePlane); + // Returns true if it's okay to switch target to "other" after being attacked by it. bool CallOkayToSwitchTarget(AActor *other); bool OkayToSwitchTarget (AActor *other); @@ -1080,6 +1097,7 @@ public: ActorFlags6 flags6; // Shit! Where did all the flags go? ActorFlags7 flags7; // WHO WANTS TO BET ON 8!? ActorFlags8 flags8; // I see your 8, and raise you a bet for 9. + ActorFlags9 flags9; // Happy ninth actor flag field GZDoom ! double Floorclip; // value to use for floor clipping double radius, Height; // for movement checking @@ -1196,6 +1214,8 @@ public: double Gravity; // [GRB] Gravity factor double Friction; double pushfactor; + double ShadowAimFactor; // [inkoalawetrust] How much the actors' aim is affected when attacking shadow actors. + double ShadowPenaltyFactor;// [inkoalawetrust] How much the shadow actor affects its' shooters' aim. int bouncecount; // Strife's grenades only bounce twice before exploding int FastChaseStrafeCount; int lastpush; @@ -1208,6 +1228,7 @@ public: AActor *BlockingMobj; // Actor that blocked the last move line_t *BlockingLine; // Line that blocked the last move + line_t *MovementBlockingLine; // Line that stopped the Actor's movement in P_XYMovement sector_t *Blocking3DFloor; // 3D floor that blocked the last move (if any) sector_t *BlockingCeiling; // Sector that blocked the last move (ceiling plane slope) sector_t *BlockingFloor; // Sector that blocked the last move (floor plane slope) diff --git a/src/playsim/mapthinkers/a_quake.cpp b/src/playsim/mapthinkers/a_quake.cpp index 35e979a49..6cb82cd3e 100644 --- a/src/playsim/mapthinkers/a_quake.cpp +++ b/src/playsim/mapthinkers/a_quake.cpp @@ -33,6 +33,7 @@ #include "d_player.h" #include "r_utility.h" #include "g_levellocals.h" +#include static FRandom pr_quake ("Quake"); @@ -51,7 +52,7 @@ IMPLEMENT_POINTERS_END void DEarthquake::Construct(AActor *center, double intensityX, double intensityY, double intensityZ, int duration, int damrad, int tremrad, FSoundID quakesound, int flags, double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, - double rollIntensity, double rollWave) + double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage) { m_QuakeSFX = quakesound; m_Spot = center; @@ -68,6 +69,9 @@ void DEarthquake::Construct(AActor *center, double intensityX, double intensityY m_MiniCount = highpoint; m_RollIntensity = rollIntensity; m_RollWave = rollWave; + m_DamageMultiplier = damageMultiplier; + m_ThrustMultiplier = thrustMultiplier; + m_Damage = damage; } //========================================================================== @@ -93,13 +97,16 @@ void DEarthquake::Serialize(FSerializer &arc) ("minicount", m_MiniCount) ("rollintensity", m_RollIntensity) ("rollwave", m_RollWave); + ("damagemultiplier", m_DamageMultiplier); + ("thrustmultiplier", m_ThrustMultiplier); + ("damage", m_Damage); } //========================================================================== // // DEarthquake :: Tick // -// Deals damage to any players near the earthquake and makes sure it's +// Deals damage to any actors near the earthquake and makes sure it's // making noise. // //========================================================================== @@ -123,16 +130,17 @@ void DEarthquake::Tick () { if (m_Flags & QF_AFFECTACTORS) { - auto iterator = m_Spot->Level->GetThinkerIterator(); - AActor* mo = nullptr; + FPortalGroupArray check(FPortalGroupArray::PGA_Full3d); + FMultiBlockThingsIterator it(check,m_Spot,m_DamageRadius,false); + FMultiBlockThingsIterator::CheckResult cres; - while ((mo = iterator.Next()) != NULL) + while (it.Next(&cres)) { - if (mo == m_Spot) //Ignore the earthquake origin. + AActor *mo = cres.thing; + if (mo == nullptr || mo == m_Spot) //Ignore null references and the earthquake origin. continue; - - DoQuakeDamage(this, mo); + DoQuakeDamage(this, mo, !!(m_Flags & QF_DAMAGEFALLOFF)); } } else @@ -142,7 +150,7 @@ void DEarthquake::Tick () if (Level->PlayerInGame(i) && !(Level->Players[i]->cheats & CF_NOCLIP)) { AActor* victim = Level->Players[i]->mo; - DoQuakeDamage(this, victim); + DoQuakeDamage(this, victim, !!(m_Flags & QF_DAMAGEFALLOFF)); } } } @@ -168,26 +176,37 @@ void DEarthquake::Tick () // //========================================================================== -void DEarthquake::DoQuakeDamage(DEarthquake *quake, AActor *victim) const +void DEarthquake::DoQuakeDamage(DEarthquake *quake, AActor *victim, bool falloff) const { double dist; + double thrustfalloff; + int damage; if (!quake || !victim) return; dist = quake->m_Spot->Distance2D(victim, true); + thrustfalloff = falloff ? GetFalloff(dist, m_DamageRadius) : 1.0; // Check if in damage radius if (dist < m_DamageRadius && victim->Z() <= victim->floorz) { if (!(quake->m_Flags & QF_SHAKEONLY) && pr_quake() < 50) { - P_DamageMobj(victim, NULL, NULL, pr_quake.HitDice(1), NAME_Quake); + if (m_Damage < 1) + damage = falloff ? (int)(pr_quake.HitDice(1) * GetFalloff(dist, m_DamageRadius) * m_DamageMultiplier) : (int)(pr_quake.HitDice(1) * m_DamageMultiplier); + //[inkoalawetrust] Do the exact specified damage. + else + damage = falloff ? (int)(m_Damage * GetFalloff(dist, m_DamageRadius) * m_DamageMultiplier) : (int)(m_Damage * m_DamageMultiplier); + + damage = damage < 1 ? 1 : damage; //Do at least a tiny bit of damage when in radius. + + P_DamageMobj(victim, NULL, NULL, damage, NAME_Quake); } - // Thrust player or thrustable actor around - if (victim->player || !(victim->flags7 & MF7_DONTTHRUST)) + // Thrust pushable actor around + if (!(victim->flags7 & MF7_DONTTHRUST) && m_ThrustMultiplier > 0) { DAngle an = victim->Angles.Yaw + DAngle::fromDeg(pr_quake()); - victim->Vel.X += m_Intensity.X * an.Cos() * 0.5; - victim->Vel.Y += m_Intensity.Y * an.Sin() * 0.5; + victim->Vel.X += m_Intensity.X * an.Cos() * m_ThrustMultiplier * thrustfalloff; + victim->Vel.Y += m_Intensity.Y * an.Sin() * m_ThrustMultiplier * thrustfalloff; } } return; @@ -285,19 +304,19 @@ double DEarthquake::GetModIntensity(double intensity, bool fake) const // // DEarthquake :: GetFalloff // -// Given the distance of the player from the quake, find the multiplier. +// Given the distance of the actor from the quake, find the multiplier. // //========================================================================== -double DEarthquake::GetFalloff(double dist) const +double DEarthquake::GetFalloff(double dist, double radius) const { - if ((dist < m_Falloff) || (m_Falloff >= m_TremorRadius) || (m_Falloff <= 0) || (m_TremorRadius - m_Falloff <= 0)) - { //Player inside the minimum falloff range, or safety check kicked in. + if ((dist < m_Falloff) || (m_Falloff >= radius) || (m_Falloff <= 0) || (radius - m_Falloff <= 0)) + { //Actor inside the minimum falloff range, or safety check kicked in. return 1.; } - else if ((dist > m_Falloff) && (dist < m_TremorRadius)) - { //Player inside the radius, and outside the min distance for falloff. - double tremorsize = m_TremorRadius - m_Falloff; + else if ((dist > m_Falloff) && (dist < radius)) + { //Actor inside the radius, and outside the min distance for falloff. + double tremorsize = radius - m_Falloff; assert(tremorsize > 0); return (1. - ((dist - m_Falloff) / tremorsize)); } @@ -341,7 +360,7 @@ int DEarthquake::StaticGetQuakeIntensities(double ticFrac, AActor *victim, FQuak if (dist < quake->m_TremorRadius) { ++count; - const double falloff = quake->GetFalloff(dist); + const double falloff = quake->GetFalloff(dist, quake->m_TremorRadius); const double r = quake->GetModIntensity(quake->m_RollIntensity); const double strength = quake->GetModIntensity(1.0, true); DVector3 intensity; @@ -411,7 +430,7 @@ int DEarthquake::StaticGetQuakeIntensities(double ticFrac, AActor *victim, FQuak bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, double intensityX, double intensityY, double intensityZ, int duration, int damrad, int tremrad, FSoundID quakesfx, int flags, double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, - double rollIntensity, double rollWave) + double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage) { AActor *center; bool res = false; @@ -425,7 +444,7 @@ bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, double int if (activator != NULL) { Level->CreateThinker(activator, intensityX, intensityY, intensityZ, duration, damrad, tremrad, - quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ, falloff, highpoint, rollIntensity, rollWave); + quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ, falloff, highpoint, rollIntensity, rollWave, damageMultiplier, thrustMultiplier, damage); return true; } } @@ -436,14 +455,14 @@ bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, double int { res = true; Level->CreateThinker(center, intensityX, intensityY, intensityZ, duration, damrad, tremrad, - quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ, falloff, highpoint, rollIntensity, rollWave); + quakesfx, flags, waveSpeedX, waveSpeedY, waveSpeedZ, falloff, highpoint, rollIntensity, rollWave, damageMultiplier, thrustMultiplier, damage); } } return res; } -bool P_StartQuake(FLevelLocals *Level, AActor *activator, int tid, double intensity, int duration, int damrad, int tremrad, FSoundID quakesfx) +bool P_StartQuake(FLevelLocals * Level, AActor * activator, int tid, double intensity, int duration, int damrad, int tremrad, FSoundID quakesfx) { //Maintains original behavior by passing 0 to intensityZ, flags, and everything else after QSFX. - return P_StartQuakeXYZ(Level, activator, tid, intensity, intensity, 0, duration, damrad, tremrad, quakesfx, 0, 0, 0, 0, 0, 0, 0, 0); + return P_StartQuakeXYZ(Level, activator, tid, intensity, intensity, 0, duration, damrad, tremrad, quakesfx, 0, 0, 0, 0, 0, 0, 0, 0, 1.0, 0.5, 0); } diff --git a/src/playsim/p_acs.cpp b/src/playsim/p_acs.cpp index ff97c7484..429fe1b69 100644 --- a/src/playsim/p_acs.cpp +++ b/src/playsim/p_acs.cpp @@ -6243,7 +6243,10 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) argCount > 12 ? args[12] : 0, argCount > 13 ? args[13] : 0, argCount > 14 ? ACSToDouble(args[14]) : 0, - argCount > 15 ? ACSToDouble(args[15]) : 0); + argCount > 15 ? ACSToDouble(args[15]) : 0, + argCount > 16 ? ACSToDouble(args[16]) : 1.0, + argCount > 17 ? ACSToDouble(args[17]) : 0.5, + argCount > 18 ? args[18] : 0); } case ACSF_SetLineActivation: diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 2d9e488a1..5eb72ef17 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -70,20 +70,21 @@ #include "actorinlines.h" #include "types.h" #include "model.h" +#include "shadowinlines.h" static FRandom pr_camissile ("CustomActorfire"); static FRandom pr_cabullet ("CustomBullet"); static FRandom pr_cwjump ("CustomWpJump"); static FRandom pr_cwpunch ("CustomWpPunch"); static FRandom pr_grenade ("ThrowGrenade"); -static FRandom pr_crailgun ("CustomRailgun"); + FRandom pr_crailgun ("CustomRailgun"); static FRandom pr_spawndebris ("SpawnDebris"); static FRandom pr_spawnitemex ("SpawnItemEx"); static FRandom pr_burst ("Burst"); static FRandom pr_monsterrefire ("MonsterRefire"); static FRandom pr_teleport("A_Teleport"); static FRandom pr_bfgselfdamage("BFGSelfDamage"); -FRandom pr_cajump("CustomJump"); + FRandom pr_cajump("CustomJump"); //========================================================================== // @@ -129,7 +130,7 @@ static int CallStateChain (AActor *self, AActor *actor, FState *state) // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. auto owner = FState::StaticFindStateOwner(state); Printf(TEXTCOLOR_RED "Unsafe state call in state %s to %s which accesses user variables. The action function has been removed from this state\n", - FState::StaticGetStateName(state).GetChars(), state->ActionFunc->PrintableName.GetChars()); + FState::StaticGetStateName(state).GetChars(), state->ActionFunc->PrintableName); state->ActionFunc = nullptr; } @@ -1226,11 +1227,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_CustomRailgun) self->Angles.Yaw = self->AngleTo(self->target,- self->target->Vel.X * veleffect, -self->target->Vel.Y * veleffect); } - if (self->target->flags & MF_SHADOW) - { - DAngle rnd = DAngle::fromDeg(pr_crailgun.Random2() * (45. / 256.)); - self->Angles.Yaw += rnd; - } + A_CustomRailgun_ShadowHandling(self, spawnofs_xy, spawnofs_z, spread_xy, flags); } if (!(flags & CRF_EXPLICITANGLE)) @@ -1399,7 +1396,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LogFloat) if (local && !self->CheckLocalView()) return 0; IGNORE_FORMAT_PRE - Printf("%H\n", num); + Printf("%g\n", num); IGNORE_FORMAT_POST return 0; } @@ -2092,6 +2089,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Respawn) self->flags6 = defs->flags6; self->flags7 = defs->flags7; self->flags8 = defs->flags8; + self->flags9 = defs->flags9; self->SetState (self->SpawnState); self->renderflags &= ~RF_INVISIBLE; @@ -3369,8 +3367,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_QuakeEx) PARAM_INT(highpoint); PARAM_FLOAT(rollIntensity); PARAM_FLOAT(rollWave); + PARAM_FLOAT(damageMultiplier); + PARAM_FLOAT(thrustMultiplier); + PARAM_INT(damage); P_StartQuakeXYZ(self->Level, self, 0, intensityX, intensityY, intensityZ, duration, damrad, tremrad, sound, flags, mulWaveX, mulWaveY, mulWaveZ, falloff, highpoint, - rollIntensity, rollWave); + rollIntensity, rollWave, damageMultiplier, thrustMultiplier, damage); return 0; } @@ -3526,7 +3527,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_WolfAttack) hitchance -= idist * (dodge ? 16 : 8); // While we're here, we may as well do something for this: - if (self->target->flags & MF_SHADOW) + if (A_WolfAttack_ShadowHandling(self)) { hitchance >>= 2; } diff --git a/src/playsim/p_enemy.cpp b/src/playsim/p_enemy.cpp index 89ac8e210..b93f528a4 100644 --- a/src/playsim/p_enemy.cpp +++ b/src/playsim/p_enemy.cpp @@ -50,6 +50,7 @@ #include "vm.h" #include "actorinlines.h" #include "a_ceiling.h" +#include "shadowinlines.h" #include "gi.h" @@ -61,8 +62,8 @@ static FRandom pr_lookformonsters ("LookForMonsters"); static FRandom pr_lookforplayers ("LookForPlayers"); static FRandom pr_scaredycat ("Anubis"); FRandom pr_chase ("Chase"); -static FRandom pr_facetarget ("FaceTarget"); -static FRandom pr_railface ("RailFace"); + FRandom pr_facetarget ("FaceTarget"); + FRandom pr_railface ("RailFace"); static FRandom pr_look2 ("LookyLooky"); static FRandom pr_look3 ("IGotHooky"); static FRandom pr_slook ("SlooK"); @@ -2206,6 +2207,7 @@ enum ChaseFlags CHF_NOPOSTATTACKTURN = 128, CHF_STOPIFBLOCKED = 256, CHF_DONTIDLE = 512, + CHF_DONTLOOKALLAROUND = 1024, }; void A_Wander(AActor *self, int flags) @@ -2440,7 +2442,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi // hurt our old one temporarily. actor->threshold = 0; } - if (P_LookForPlayers (actor, true, NULL) && actor->target != actor->goal) + if (P_LookForPlayers (actor, !(flags & CHF_DONTLOOKALLAROUND), NULL) && actor->target != actor->goal) { // got a new target actor->flags7 &= ~MF7_INCHASE; return; @@ -2615,7 +2617,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi lookForBetter = true; } AActor * oldtarget = actor->target; - gotNew = P_LookForPlayers (actor, true, NULL); + gotNew = P_LookForPlayers (actor, !(flags & CHF_DONTLOOKALLAROUND), NULL); if (lookForBetter) { actor->flags3 |= MF3_NOSIGHTCHECK; @@ -3018,15 +3020,11 @@ void A_Face(AActor *self, AActor *other, DAngle max_turn, DAngle max_pitch, DAng self->Angles.Pitch = other_pitch; } self->Angles.Pitch += pitch_offset; + A_Face_ShadowHandling(self, other, max_pitch, other_pitch, true); } - - // This will never work well if the turn angle is limited. - if (max_turn == nullAngle && (self->Angles.Yaw == other_angle) && other->flags & MF_SHADOW && !(self->flags6 & MF6_SEEINVISIBLE) ) - { - self->Angles.Yaw += DAngle::fromDeg(pr_facetarget.Random2() * (45 / 256.)); - } + A_Face_ShadowHandling(self,other,max_turn,other_angle,false); } void A_FaceTarget(AActor *self) @@ -3073,10 +3071,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MonsterRail) // Let the aim trail behind the player self->Angles.Yaw = self->AngleTo(self->target, -self->target->Vel.X * 3, -self->target->Vel.Y * 3); - if (self->target->flags & MF_SHADOW && !(self->flags6 & MF6_SEEINVISIBLE)) - { - self->Angles.Yaw += DAngle::fromDeg(pr_railface.Random2() * 45./256); - } + A_MonsterRail_ShadowHandling(self); FRailParams p; diff --git a/src/playsim/p_local.h b/src/playsim/p_local.h index e1fae8d62..45de6c462 100644 --- a/src/playsim/p_local.h +++ b/src/playsim/p_local.h @@ -268,6 +268,7 @@ void P_PlayerStartStomp (AActor *actor, bool mononly=false); // [RH] Stomp on t void P_SlideMove (AActor* mo, const DVector2 &pos, int numsteps); bool P_BounceWall (AActor *mo); bool P_BounceActor (AActor *mo, AActor *BlockingMobj, bool ontop); +bool P_ReflectOffActor(AActor* mo, AActor* blocking); int P_CheckSight (AActor *t1, AActor *t2, int flags=0); enum ESightFlags @@ -406,9 +407,12 @@ enum RADF_SOURCEISSPOT = 4, RADF_NODAMAGE = 8, RADF_THRUSTZ = 16, - RADF_OLDRADIUSDAMAGE = 32 + RADF_OLDRADIUSDAMAGE = 32, + RADF_THRUSTLESS = 64, + RADF_NOALLIES = 128, + RADF_CIRCULAR = 256 }; -int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg); +int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg, bool circular); int P_RadiusAttack (AActor *spot, AActor *source, int damage, int distance, FName damageType, int flags, int fulldamagedistance=0, FName species = NAME_None); diff --git a/src/playsim/p_map.cpp b/src/playsim/p_map.cpp index 0ec9b6863..797feb8e7 100644 --- a/src/playsim/p_map.cpp +++ b/src/playsim/p_map.cpp @@ -92,6 +92,7 @@ #include "r_sky.h" #include "g_levellocals.h" #include "actorinlines.h" +#include CVAR(Bool, cl_bloodsplats, true, CVAR_ARCHIVE) CVAR(Int, sv_smartaim, 0, CVAR_ARCHIVE | CVAR_SERVERINFO) @@ -3517,6 +3518,16 @@ bool FSlide::BounceWall(AActor *mo) } line = bestslideline; + if (mo->flags & MF_MISSILE) + { + switch (mo->SpecialBounceHit(nullptr, line, nullptr)) + { + case 1: return true; + case 0: return false; + default: break; + } + } + if (line->special == Line_Horizon || ((mo->BounceFlags & BOUNCE_NotOnSky) && line->hitSkyWall(mo))) { mo->SeeSound = mo->BounceSound = NO_SOUND; // it might make a sound otherwise @@ -3607,6 +3618,13 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) case 0: return false; default: break; } + + switch (mo->SpecialBounceHit(BlockingMobj, nullptr, nullptr)) + { + case 1: return true; + case 0: return false; + default: break; + } } //Don't go through all of this if the actor is reflective and wants things to pass through them. @@ -3706,6 +3724,48 @@ bool P_BounceActor(AActor *mo, AActor *BlockingMobj, bool ontop) return false; } +bool P_ReflectOffActor(AActor* mo, AActor* blocking) +{ + if (!(blocking->flags2 & MF2_REFLECTIVE)) + return false; + + // Don't change the angle if there's THRUREFLECT on the monster. + if (!(blocking->flags7 & MF7_THRUREFLECT)) + { + DAngle angle = blocking->AngleTo(mo); + if (mo->AdjustReflectionAngle(blocking, angle)) + return false; + + // Change angle for deflection/reflection + auto target = mo->target != NULL ? mo->target : blocking->target; + if (target && (blocking->flags7 & MF7_AIMREFLECT)) + { + //dest->x - source->x + DVector3 vect = mo->Vec3To(target); + vect.Z += target->Height * 0.5; + mo->Vel = vect.Resized(mo->Speed); + } + else if (blocking->flags7 & MF7_MIRRORREFLECT) + { + mo->Angles.Yaw += DAngle::fromDeg(180.0); + mo->Vel *= -0.5; + } + else + { + mo->Angles.Yaw = angle; + mo->VelFromAngle(mo->Speed * 0.5); + mo->Vel.Z *= -0.5; + } + } + + if (mo->flags2 & MF2_SEEKERMISSILE) + mo->tracer = mo->target; + + mo->target = blocking; + + return true; +} + //============================================================================ // // Aiming @@ -4452,6 +4512,11 @@ DAngle P_AimLineAttack(AActor *t1, DAngle angle, double distance, FTranslatedLin { *pLineTarget = *result; } + + DAngle newPitch = P_AimLineAttack_ShadowHandling(t1,target,result->linetarget,shootz); + if (newPitch != nullAngle) + result->pitch = newPitch; + return result->linetarget ? result->pitch : t1->Angles.Pitch; } @@ -5838,7 +5903,7 @@ int P_UsePuzzleItem(AActor *PuzzleItemUser, int PuzzleItemType) //========================================================================== // // RADIUS ATTACK -// +// Most of the explosion code resides here. Except P_GeometryRadiusAttack(). // //========================================================================== @@ -5864,7 +5929,7 @@ CUSTOM_CVAR(Float, splashfactor, 1.f, CVAR_SERVERINFO) // Used by anything without OLDRADIUSDMG flag //========================================================================== -static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, int bombdistance, int fulldamagedistance, bool thingbombsource) +static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, int bombdamage, int bombdistance, int fulldamagedistance, bool thingbombsource, bool round) { // [RH] New code. The bounding box only covers the // height of the thing and not the height of the map. @@ -5876,41 +5941,49 @@ static double GetRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, double bombdistancefloat = 1. / (double)(bombdistance - fulldamagedistance); double bombdamagefloat = (double)bombdamage; - DVector2 vec = bombspot->Vec2To(thing); - dx = fabs(vec.X); - dy = fabs(vec.Y); - boxradius = thing->radius; - - // The damage pattern is square, not circular. - len = double(dx > dy ? dx : dy); - - if (bombspot->Z() < thing->Z() || bombspot->Z() >= thing->Top()) + if (!round) { - double dz; + DVector2 vec = bombspot->Vec2To(thing); + dx = fabs(vec.X); + dy = fabs(vec.Y); + boxradius = thing->radius; - if (bombspot->Z() > thing->Z()) + // The damage pattern is square, not circular. + len = double(dx > dy ? dx : dy); + + if (bombspot->Z() < thing->Z() || bombspot->Z() >= thing->Top()) { - dz = double(bombspot->Z() - thing->Top()); - } - else - { - dz = double(thing->Z() - bombspot->Z()); - } - if (len <= boxradius) - { - len = dz; + double dz; + + if (bombspot->Z() > thing->Z()) + { + dz = double(bombspot->Z() - thing->Top()); + } + else + { + dz = double(thing->Z() - bombspot->Z()); + } + if (len <= boxradius) + { + len = dz; + } + else + { + len -= boxradius; + len = g_sqrt(len*len + dz*dz); + } } else { len -= boxradius; - len = g_sqrt(len*len + dz*dz); + if (len < 0.f) + len = 0.f; } } + //[inkoalwetrust]: Round explosions just use the actual distance between the source and victim. else { - len -= boxradius; - if (len < 0.f) - len = 0.f; + len = bombspot->Distance3D (thing); } len = clamp(len - (double)fulldamagedistance, 0, len); points = bombdamagefloat * (1. - len * bombdistancefloat); @@ -5985,7 +6058,7 @@ static int GetOldRadiusDamage(bool fromaction, AActor *bombspot, AActor *thing, // damage and not taking into account any damage reduction. //========================================================================== -int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg) +int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int fulldmgdistance, bool oldradiusdmg, bool circular) { if (!thing) @@ -6005,7 +6078,7 @@ int P_GetRadiusDamage(AActor *self, AActor *thing, int damage, int distance, int const int newdam = oldradiusdmg ? GetOldRadiusDamage(true, self, thing, damage, distance, fulldmgdistance) - : int(GetRadiusDamage(true, self, thing, damage, distance, fulldmgdistance, false)); + : int(GetRadiusDamage(true, self, thing, damage, distance, fulldmgdistance, false, circular)); return newdam; } @@ -6072,10 +6145,12 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom ) ) continue; - if((species != NAME_None) && (thing->Species != species)) - { + if ((species != NAME_None) && (thing->Species != species)) + continue; + + //[inkoalawetrust] Don't harm actors friendly to the explosions' source. But do harm the source. + if ((flags & RADF_NOALLIES) && bombsource->IsFriend(thing) && !(thing == bombsource || thing == bombspot)) continue; - } if (bombsource && thing != bombsource && bombsource->player && P_ShouldPassThroughPlayer(bombsource, thing)) continue; @@ -6092,7 +6167,7 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom if ((flags & RADF_NODAMAGE) || (!((bombspot->flags5 | thing->flags5) & MF5_OLDRADIUSDMG) && !(flags & RADF_OLDRADIUSDAMAGE) && !(thing->Level->i_compatflags2 & COMPATF2_EXPLODE2))) { - double points = GetRadiusDamage(false, bombspot, thing, bombdamage, bombdistance, fulldamagedistance, bombsource == thing); + double points = GetRadiusDamage(false, bombspot, thing, bombdamage, bombdistance, fulldamagedistance, bombsource == thing,!!(flags & RADF_CIRCULAR)); double check = int(points) * bombdamage; // points and bombdamage should be the same sign (the double cast of 'points' is needed to prevent overflows and incorrect values slipping through.) if ((check > 0 || (check == 0 && bombspot->flags7 & MF7_FORCEZERORADIUSDMG)) && P_CheckSight(thing, bombspot, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY)) @@ -6101,15 +6176,22 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom double thrust; int damage = abs((int)points); int newdam = damage; + int dmgmask = 0; if (!(flags & RADF_NODAMAGE)) { + //[inkoalawetrust] Thrustless explosions don't push anything. + if (!(flags & RADF_THRUSTLESS)) + dmgmask = DMG_EXPLOSION; + else + dmgmask = DMG_EXPLOSION | DMG_THRUSTLESS; + //[MC] Don't count actors saved by buddha if already at 1 health. int prehealth = thing->health; - newdam = P_DamageMobj(thing, bombspot, bombsource, damage, bombmod, DMG_EXPLOSION); + newdam = P_DamageMobj(thing, bombspot, bombsource, damage, bombmod, dmgmask); if (thing->health < prehealth) count++; } - else if (thing->player == NULL && (!(flags & RADF_NOIMPACTDAMAGE) && !(thing->flags7 & MF7_DONTTHRUST))) + else if (thing->player == NULL && (!(flags & RADF_NOIMPACTDAMAGE && !(flags & RADF_THRUSTLESS)) && !(thing->flags7 & MF7_DONTTHRUST))) thing->flags2 |= MF2_BLASTED; if (!(thing->flags & MF_ICECORPSE)) @@ -6117,13 +6199,12 @@ int P_RadiusAttack(AActor *bombspot, AActor *bombsource, int bombdamage, int bom if (!(flags & RADF_NODAMAGE) && !(bombspot->flags3 & MF3_BLOODLESSIMPACT)) P_TraceBleed(newdam > 0 ? newdam : damage, thing, bombspot); - if ((flags & RADF_NODAMAGE) || !(bombspot->flags2 & MF2_NODMGTHRUST)) + if ((flags & RADF_NODAMAGE && !(flags & RADF_THRUSTLESS)) || !(bombspot->flags2 & MF2_NODMGTHRUST) && !(flags & RADF_THRUSTLESS)) { if (bombsource == NULL || !(bombsource->flags2 & MF2_NODMGTHRUST)) { if (!(thing->flags7 & MF7_DONTTHRUST)) { - thrust = points * 0.5 / (double)thing->Mass; if (bombsource == thing) { diff --git a/src/playsim/p_mobj.cpp b/src/playsim/p_mobj.cpp index e9be195f2..fa4d4df33 100644 --- a/src/playsim/p_mobj.cpp +++ b/src/playsim/p_mobj.cpp @@ -99,6 +99,7 @@ #include "actorinlines.h" #include "a_dynlight.h" #include "fragglescript/t_fs.h" +#include "shadowinlines.h" // MACROS ------------------------------------------------------------------ @@ -120,7 +121,6 @@ EXTERN_CVAR (Int, cl_rockettrails) // PRIVATE DATA DEFINITIONS ------------------------------------------------ static FRandom pr_explodemissile ("ExplodeMissile"); -FRandom pr_bounce ("Bounce"); static FRandom pr_reflect ("Reflect"); static FRandom pr_nightmarerespawn ("NightmareRespawn"); static FRandom pr_botspawnmobj ("BotSpawnActor"); @@ -133,7 +133,6 @@ static FRandom pr_splat ("FAxeSplatter"); static FRandom pr_ripperblood ("RipperBlood"); static FRandom pr_chunk ("Chunk"); static FRandom pr_checkmissilespawn ("CheckMissileSpawn"); -static FRandom pr_spawnmissile ("SpawnMissile"); static FRandom pr_missiledamage ("MissileDamage"); static FRandom pr_multiclasschoice ("MultiClassChoice"); static FRandom pr_rockettrail("RocketTrail"); @@ -142,6 +141,8 @@ static FRandom pr_uniquetid("UniqueTID"); // PUBLIC DATA DEFINITIONS ------------------------------------------------- FRandom pr_spawnmobj ("SpawnActor"); +FRandom pr_bounce("Bounce"); +FRandom pr_spawnmissile("SpawnMissile"); CUSTOM_CVAR (Float, sv_gravity, 800.f, CVAR_SERVERINFO|CVAR_NOSAVE|CVAR_NOINITCALL) { @@ -233,6 +234,7 @@ void AActor::Serialize(FSerializer &arc) A("flags6", flags6) A("flags7", flags7) A("flags8", flags8) + A("flags9", flags9) A("weaponspecial", weaponspecial) A("special1", special1) A("special2", special2) @@ -308,6 +310,7 @@ void AActor::Serialize(FSerializer &arc) A("smokecounter", smokecounter) ("blockingmobj", BlockingMobj) A("blockingline", BlockingLine) + A("movementblockingline", MovementBlockingLine) A("blocking3dfloor", Blocking3DFloor) A("blockingceiling", BlockingCeiling) A("blockingfloor", BlockingFloor) @@ -1543,6 +1546,17 @@ void AActor::PlayBounceSound(bool onfloor) bool AActor::FloorBounceMissile (secplane_t &plane) { + if (flags & MF_MISSILE) + { + switch (SpecialBounceHit(nullptr, nullptr, &plane)) + { + // This one is backwards for some reason... + case 1: return false; + case 0: return true; + default: break; + } + } + // [ZZ] if bouncing missile hits a damageable sector(plane), it dies if (P_ProjectileHitPlane(this, -1) && bouncecount > 0) { @@ -1984,7 +1998,7 @@ static double P_XYMovement (AActor *mo, DVector2 scroll) { // blocked move AActor *BlockingMobj = mo->BlockingMobj; - line_t *BlockingLine = mo->BlockingLine; + line_t *BlockingLine = mo->MovementBlockingLine = mo->BlockingLine; // [ZZ] if (!BlockingLine && !BlockingMobj) // hit floor or ceiling while XY movement - sector actions @@ -2112,57 +2126,11 @@ static double P_XYMovement (AActor *mo, DVector2 scroll) return Oldfloorz; } } - if (BlockingMobj && (BlockingMobj->flags2 & MF2_REFLECTIVE)) + if (BlockingMobj && P_ReflectOffActor(mo, BlockingMobj)) { - bool seeker = (mo->flags2 & MF2_SEEKERMISSILE) ? true : false; - // Don't change the angle if there's THRUREFLECT on the monster. - if (!(BlockingMobj->flags7 & MF7_THRUREFLECT)) - { - DAngle angle = BlockingMobj->AngleTo(mo); - bool dontReflect = (mo->AdjustReflectionAngle(BlockingMobj, angle)); - // Change angle for deflection/reflection - - if (!dontReflect) - { - bool tg = (mo->target != NULL); - bool blockingtg = (BlockingMobj->target != NULL); - if ((BlockingMobj->flags7 & MF7_AIMREFLECT) && (tg | blockingtg)) - { - AActor *origin = tg ? mo->target : BlockingMobj->target; - - //dest->x - source->x - DVector3 vect = mo->Vec3To(origin); - vect.Z += origin->Height / 2; - mo->Vel = vect.Resized(mo->Speed); - } - else - { - if ((BlockingMobj->flags7 & MF7_MIRRORREFLECT) && (tg | blockingtg)) - { - mo->Angles.Yaw += DAngle::fromDeg(180.); - mo->Vel *= -.5; - } - else - { - mo->Angles.Yaw = angle; - mo->VelFromAngle(mo->Speed / 2); - mo->Vel.Z *= -.5; - } - } - } - else - { - goto explode; - } - } - if (mo->flags2 & MF2_SEEKERMISSILE) - { - mo->tracer = mo->target; - } - mo->target = BlockingMobj; return Oldfloorz; } -explode: + // explode a missile bool onsky = false; if (tm.ceilingline && tm.ceilingline->hitSkyWall(mo)) @@ -3240,6 +3208,21 @@ int AActor::SpecialMissileHit (AActor *victim) else return -1; } +// This virtual method only exists on the script side. +int AActor::SpecialBounceHit(AActor* bounceMobj, line_t* bounceLine, secplane_t* bouncePlane) +{ + IFVIRTUAL(AActor, SpecialBounceHit) + { + VMValue params[4] = { (DObject*)this, bounceMobj, bounceLine, bouncePlane }; + VMReturn ret; + int retval; + ret.IntAt(&retval); + VMCall(func, params, 4, &ret, 1); + return retval; + } + else return -1; +} + bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle) { if (flags2 & MF2_DONTREFLECT) return true; @@ -3248,11 +3231,9 @@ bool AActor::AdjustReflectionAngle (AActor *thing, DAngle &angle) if (thing->flags4&MF4_SHIELDREFLECT) { // Shield reflection (from the Centaur) - if (absangle(angle, thing->Angles.Yaw) > DAngle::fromDeg(45)) + if ((flags7 & MF7_NOSHIELDREFLECT) || absangle(angle, thing->Angles.Yaw) > DAngle::fromDeg(45)) return true; // Let missile explode - if (thing->flags7 & MF7_NOSHIELDREFLECT) return true; - if (pr_reflect () < 128) angle += DAngle::fromDeg(45); else @@ -4103,6 +4084,7 @@ void AActor::Tick () // Handle X and Y velocities BlockingMobj = nullptr; + MovementBlockingLine = nullptr; sector_t* oldBlockingCeiling = BlockingCeiling; sector_t* oldBlockingFloor = BlockingFloor; Blocking3DFloor = nullptr; @@ -6665,7 +6647,7 @@ AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassAct if (dest == NULL) { - Printf ("P_SpawnMissilyXYZ: Tried to shoot %s from %s with no dest\n", + Printf ("P_SpawnMissileXYZ: Tried to shoot %s from %s with no destination\n", type->TypeName.GetChars(), source->GetClass()->TypeName.GetChars()); return NULL; } @@ -6704,21 +6686,8 @@ AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassAct } th->Vel = velocity.Resized(speed); - // invisible target: rotate velocity vector in 2D - // [RC] Now monsters can aim at invisible player as if they were fully visible. - if (dest->flags & MF_SHADOW && !(source->flags6 & MF6_SEEINVISIBLE)) - { - DAngle an = DAngle::fromDeg(pr_spawnmissile.Random2() * (22.5 / 256)); - double c = an.Cos(); - double s = an.Sin(); - - double newx = th->Vel.X * c - th->Vel.Y * s; - double newy = th->Vel.X * s + th->Vel.Y * c; - - th->Vel.X = newx; - th->Vel.Y = newy; - } - + P_SpawnMissileXYZ_ShadowHandling(source,dest,th,pos); + th->AngleFromVel(); if (th->flags4 & MF4_SPECTRAL) @@ -6839,14 +6808,11 @@ AActor *P_SpawnMissileZAimed (AActor *source, double z, AActor *dest, PClassActo an = source->Angles.Yaw; - if (dest->flags & MF_SHADOW) - { - an += DAngle::fromDeg(pr_spawnmissile.Random2() * (16. / 360.)); - } dist = source->Distance2D (dest); speed = GetDefaultSpeed (type); dist /= speed; vz = dist != 0 ? (dest->Z() - source->Z())/dist : speed; + an += P_SpawnMissileZAimed_ShadowHandling(source, dest, vz, speed, source->PosAtZ(z)); return P_SpawnMissileAngleZSpeed (source, z, type, an, vz, speed); } @@ -7711,6 +7677,9 @@ void PrintMiscActorInfo(AActor *query) Printf("\n flags8: %x", query->flags8.GetValue()); for (flagi = 0; flagi <= 31; flagi++) if (query->flags8 & ActorFlags8::FromInt(1<flags9.GetValue()); + for (flagi = 0; flagi <= 31; flagi++) + if (query->flags9 & ActorFlags9::FromInt(1 << flagi)) Printf(" %s", FLAG_NAME(1 << flagi, flags9)); Printf("\nBounce flags: %x\nBounce factors: f:%f, w:%f", query->BounceFlags.GetValue(), query->bouncefactor, query->wallbouncefactor); diff --git a/src/playsim/p_pspr.cpp b/src/playsim/p_pspr.cpp index 161e09076..d6860525b 100644 --- a/src/playsim/p_pspr.cpp +++ b/src/playsim/p_pspr.cpp @@ -326,6 +326,13 @@ DPSprite *player_t::GetPSprite(PSPLayers layer) else { oldcaller = pspr->Caller; + + // update scaling properties here + if (newcaller != nullptr && newcaller->IsKindOf(NAME_Weapon)) + { + pspr->baseScale.X = newcaller->FloatVar(NAME_WeaponScaleX); + pspr->baseScale.Y = newcaller->FloatVar(NAME_WeaponScaleY); + } } // Always update the caller here in case we switched weapon @@ -556,7 +563,7 @@ void DPSprite::SetState(FState *newstate, bool pending) { // If an unsafe function (i.e. one that accesses user variables) is being detected, print a warning once and remove the bogus function. We may not call it because that would inevitably crash. Printf(TEXTCOLOR_RED "Unsafe state call in state %sd to %s which accesses user variables. The action function has been removed from this state\n", - FState::StaticGetStateName(newstate).GetChars(), newstate->ActionFunc->PrintableName.GetChars()); + FState::StaticGetStateName(newstate).GetChars(), newstate->ActionFunc->PrintableName); newstate->ActionFunc = nullptr; } if (newstate->CallAction(Owner->mo, Caller, &stp, &nextstate)) diff --git a/src/playsim/p_spec.h b/src/playsim/p_spec.h index a0918da91..ff0095eea 100644 --- a/src/playsim/p_spec.h +++ b/src/playsim/p_spec.h @@ -164,7 +164,7 @@ void P_TerminateScript (FLevelLocals *Level, int script, const char *map); // // [RH] p_quake.c // -bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, double intensityX, double intensityY, double intensityZ, int duration, int damrad, int tremrad, FSoundID quakesfx, int flags, double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, double rollIntensity, double rollWave); +bool P_StartQuakeXYZ(FLevelLocals *Level, AActor *activator, int tid, double intensityX, double intensityY, double intensityZ, int duration, int damrad, int tremrad, FSoundID quakesfx, int flags, double waveSpeedX, double waveSpeedY, double waveSpeedZ, int falloff, int highpoint, double rollIntensity, double rollWave, double damageMultiplier, double thrustMultiplier, int damage); bool P_StartQuake(FLevelLocals *Level, AActor *activator, int tid, double intensity, int duration, int damrad, int tremrad, FSoundID quakesfx); #endif diff --git a/src/playsim/shadowinlines.h b/src/playsim/shadowinlines.h new file mode 100644 index 000000000..fce131f7b --- /dev/null +++ b/src/playsim/shadowinlines.h @@ -0,0 +1,233 @@ +#pragma once + +#include "actor.h" +#include "r_defs.h" +#include "m_random.h" + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// Handling of MF_SHADOW related code for attack and aiming functions. +// +//----------------------------------------------------------------------------- + + +// RNG VARIABLES ------------------------------------------------ +extern FRandom pr_spawnmissile; +extern FRandom pr_facetarget; +extern FRandom pr_railface; +extern FRandom pr_crailgun; +inline FRandom pr_shadowaimz("VerticalShadowAim"); + +//========================================================================== +// +// Generic checks +// +//========================================================================== + +struct ShadowCheckData +{ + AActor* HitShadow; +}; + +static ETraceStatus CheckForShadowBlockers(FTraceResults& res, void* userdata) +{ + ShadowCheckData* output = (ShadowCheckData*)userdata; + if (res.HitType == TRACE_HitActor && res.Actor && (res.Actor->flags9 & MF9_SHADOWBLOCK)) + { + output->HitShadow = res.Actor; + return TRACE_Stop; + } + + if (res.HitType != TRACE_HitActor) + { + return TRACE_Stop; + } + + return TRACE_Continue; +} + +// [inkoalawetrust] Check if an MF9_SHADOWBLOCK actor is standing between t1 and t2. +inline bool P_CheckForShadowBlock(AActor* t1, AActor* t2, DVector3 pos, double& penaltyFactor) +{ + FTraceResults result; + ShadowCheckData ShadowCheck; + ShadowCheck.HitShadow = nullptr; + DVector3 dir; + double dist; + if (t2) + { + dir = t1->Vec3To(t2); + dist = dir.Length(); + } + //No second actor, fall back to shooting at facing direction. + else + { + dir = DRotator(-(t1->Angles.Pitch), t1->Angles.Yaw, t1->Angles.Yaw); + dist = 65536.0; //Arbitrary large value. + } + + Trace(pos, t1->Sector, dir, dist, ActorFlags::FromInt(0xFFFFFFFF), ML_BLOCKEVERYTHING, t1, result, 0, CheckForShadowBlockers, &ShadowCheck); + + //Use the penalty factor of the shadowblocker that was hit. Otherwise, use the factor passed by PerformShadowChecks(). + if (ShadowCheck.HitShadow) + { + penaltyFactor = ShadowCheck.HitShadow->ShadowPenaltyFactor; + } + + return ShadowCheck.HitShadow; +} + +inline bool AffectedByShadows(AActor* self, AActor* other) +{ + return (!(self->flags6 & MF6_SEEINVISIBLE) || self->flags9 & MF9_SHADOWAIM); +} + +inline bool CheckForShadows(AActor* self, AActor* other, DVector3 pos, double& penaltyFactor) +{ + return ((other && (other->flags & MF_SHADOW)) || (self->flags9 & MF9_DOSHADOWBLOCK) && P_CheckForShadowBlock(self, other, pos, penaltyFactor)); +} + +inline bool PerformShadowChecks(AActor* self, AActor* other, DVector3 pos, double& penaltyFactor) +{ + if (other != nullptr) penaltyFactor = other->ShadowPenaltyFactor; //Use target penalty factor by default. + else penaltyFactor = 1.0; + return (AffectedByShadows(self, other) && CheckForShadows(self, other, pos, penaltyFactor)); +} + +//========================================================================== +// +// Function-specific inlines. +// +//========================================================================== + +inline void P_SpawnMissileXYZ_ShadowHandling(AActor* source, AActor* target, AActor* missile, DVector3 pos) +{ + double penaltyFactor; + // invisible target: rotate velocity vector in 2D + // [RC] Now monsters can aim at invisible player as if they were fully visible. + if (PerformShadowChecks(source, target, pos, penaltyFactor)) + { + DAngle an = DAngle::fromDeg(pr_spawnmissile.Random2() * (22.5 / 256)) * source->ShadowAimFactor * penaltyFactor; + double c = an.Cos(); + double s = an.Sin(); + + double newx = missile->Vel.X * c - missile->Vel.Y * s; + double newy = missile->Vel.X * s + missile->Vel.Y * c; + + missile->Vel.X = newx; + missile->Vel.Y = newy; + + if (source->flags9 & MF9_SHADOWAIMVERT) + { + DAngle pitch = DAngle::fromDeg(pr_spawnmissile.Random2() * (22.5 / 256)) * source->ShadowAimFactor * penaltyFactor; + double newz = -pitch.Sin() * missile->Speed; + missile->Vel.Z = newz; + } + } + return; +} + +//P_SpawnMissileZAimed uses a local variable for the angle it passes on. +inline DAngle P_SpawnMissileZAimed_ShadowHandling(AActor* source, AActor* target, double& vz, double speed, DVector3 pos) +{ + double penaltyFactor; + if (PerformShadowChecks(source, target, pos, penaltyFactor)) + { + if (source->flags9 & MF9_SHADOWAIMVERT) + { + DAngle pitch = DAngle::fromDeg(pr_spawnmissile.Random2() * (16. / 360.)) * source->ShadowAimFactor * penaltyFactor; + vz += -pitch.Sin() * speed; //Modify the Z velocity pointer that is then passed to P_SpawnMissileAngleZSpeed. + } + return DAngle::fromDeg(pr_spawnmissile.Random2() * (16. / 360.)) * source->ShadowAimFactor * penaltyFactor; + } + return nullAngle; +} + +inline void A_Face_ShadowHandling(AActor* self, AActor* other, DAngle max_turn, DAngle other_angle, bool vertical) +{ + double penaltyFactor; + if (!vertical) + { + // This will never work well if the turn angle is limited. + if (max_turn == nullAngle && (self->Angles.Yaw == other_angle) && PerformShadowChecks(self, other, self->PosAtZ(self->Center()), penaltyFactor)) + { + self->Angles.Yaw += DAngle::fromDeg(pr_facetarget.Random2() * (45 / 256.)) * self->ShadowAimFactor * penaltyFactor; + } + } + else + { + //Randomly offset the pitch when looking at shadows. + if (self->flags9 & MF9_SHADOWAIMVERT && max_turn == nullAngle && (self->Angles.Pitch == other_angle) && PerformShadowChecks(self, other, self->PosAtZ(self->Center()), penaltyFactor)) + { + self->Angles.Pitch += DAngle::fromDeg(pr_facetarget.Random2() * (45 / 256.)) * self->ShadowAimFactor * penaltyFactor; + } + } + return; +} + +inline void A_MonsterRail_ShadowHandling(AActor* self) +{ + double penaltyFactor; + double shootZ = self->Center() - self->FloatSpeed - self->Floorclip; // The formula P_RailAttack uses, minus offset_z since A_MonsterRail doesn't use it. + + if (PerformShadowChecks(self, self->target, self->PosAtZ(shootZ), penaltyFactor)) + { + self->Angles.Yaw += DAngle::fromDeg(pr_railface.Random2() * 45. / 256) * self->ShadowAimFactor * penaltyFactor; + if (self->flags9 & MF9_SHADOWAIMVERT) + self->Angles.Pitch += DAngle::fromDeg(pr_railface.Random2() * 45. / 256) * self->ShadowAimFactor * penaltyFactor; + } + return; +} + +//Also passes parameters to determine a firing position for the SHADOWBLOCK check. +inline void A_CustomRailgun_ShadowHandling(AActor* self, double spawnofs_xy, double spawnofs_z, DAngle spread_xy, int flags) +{ + double penaltyFactor; + // [inkoalawetrust] The exact formula P_RailAttack uses to determine where the railgun trace should spawn from. + DVector2 shootXY = (self->Vec2Angle(spawnofs_xy, (self->Angles.Yaw + spread_xy) - DAngle::fromDeg(90.))); + double shootZ = self->Center() - self->FloatSpeed + spawnofs_z - self->Floorclip; + if (flags & 16) shootZ += self->AttackOffset(); //16 is RGF_CENTERZ + DVector3 checkPos; + checkPos.X = shootXY.X; + checkPos.Y = shootXY.Y; + checkPos.Z = shootZ; + + if (PerformShadowChecks(self, self->target, checkPos, penaltyFactor)) + { + self->Angles.Yaw += DAngle::fromDeg(pr_crailgun.Random2() * (45. / 256.)) * self->ShadowAimFactor * penaltyFactor; + if (self->flags9 & MF9_SHADOWAIMVERT) + { + self->Angles.Pitch += DAngle::fromDeg(pr_crailgun.Random2() * (45. / 256.)) * self->ShadowAimFactor * penaltyFactor; + } + } + return; +} + +//If anything is returned, then AimLineAttacks' result pitch is changed to that value. +inline DAngle P_AimLineAttack_ShadowHandling(AActor*source, AActor* target, AActor* linetarget, double shootZ) +{ + double penaltyFactor; + AActor* mo; + if (target) + mo = target; + else + mo = linetarget; + + // [inkoalawetrust] Randomly offset the vertical aim of monsters. Roughly uses the SSG vertical spread. + if (source->player == NULL && source->flags9 & MF9_SHADOWAIMVERT && PerformShadowChecks (source, mo, source->PosAtZ (shootZ), penaltyFactor)) + { + if (linetarget) + return DAngle::fromDeg(pr_shadowaimz.Random2() * (28.388 / 256.)) * source->ShadowAimFactor * penaltyFactor; //Change the autoaims' pitch to this. + else + source->Angles.Pitch = DAngle::fromDeg(pr_shadowaimz.Random2() * (28.388 / 256.)) * source->ShadowAimFactor * penaltyFactor; + } + return nullAngle; +} + +//A_WolfAttack directly harms the target instead of firing a hitscan or projectile. So it handles shadows by lowering the chance of harming the target. +inline bool A_WolfAttack_ShadowHandling(AActor* self) +{ + double p; //Does nothing. + return (PerformShadowChecks(self, self->target, self->PosAtZ(self->Center()), p)); +} \ No newline at end of file diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index f22edad58..f9d17e8b0 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -368,8 +368,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr //modelFrame if (actor->modelData->modelFrameGenerators.Size() > i - && actor->modelData->modelFrameGenerators[i] >= 0 - && actor->modelData->modelFrameGenerators[i] < modelsamount + && (unsigned)actor->modelData->modelFrameGenerators[i] < modelsamount && smf->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0 ) { modelframe = smf->modelframes[actor->modelData->modelFrameGenerators[i]]; diff --git a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp index 141247962..24bd640ee 100644 --- a/src/rendering/hwrenderer/scene/hw_drawinfo.cpp +++ b/src/rendering/hwrenderer/scene/hw_drawinfo.cpp @@ -86,7 +86,8 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni mClipper = &drawctx->staticClipper; Viewpoint = parentvp; - lightmode = Level->lightMode; + lightmode = getRealLightmode(Level, true); + if (uniforms) { VPUniforms = *uniforms; @@ -100,7 +101,7 @@ void HWDrawInfo::StartScene(FRenderViewpoint &parentvp, HWViewpointUniforms *uni VPUniforms.mViewMatrix.loadIdentity(); VPUniforms.mNormalViewMatrix.loadIdentity(); VPUniforms.mViewHeight = viewheight; - if (gl_lightmode == 5) + if (lightmode == ELightMode::Build) { VPUniforms.mGlobVis = 1 / 64.f; VPUniforms.mPalLightLevels = 32 | (static_cast(gl_fogmode) << 8) | ((int)lightmode << 16); diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index cbed8d5ec..2e4fb7045 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -477,7 +477,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) // which is nicer in VR float xrel = xcenter - vp->X; float yrel = ycenter - vp->Y; - float absAngleDeg = RAD2DEG(atan2(-yrel, xrel)); + float absAngleDeg = atan2(-yrel, xrel) * (180 / M_PI); float counterRotationDeg = 270. - HWAngles.Yaw.Degrees(); // counteracts existing sprite rotation float relAngleDeg = counterRotationDeg + absAngleDeg; diff --git a/src/scripting/backend/codegen_doom.cpp b/src/scripting/backend/codegen_doom.cpp index 1d008446c..9f2b37e84 100644 --- a/src/scripting/backend/codegen_doom.cpp +++ b/src/scripting/backend/codegen_doom.cpp @@ -309,7 +309,7 @@ static bool UnravelVarArgAJump(FxVMFunctionCall *func, FCompileContext &ctx) static bool AJumpProcessing(FxVMFunctionCall *func, FCompileContext &ctx) { // Unfortunately the PrintableName is the only safe thing to catch this special case here. - if (func->Function->Variants[0].Implementation->PrintableName.CompareNoCase("Actor.A_Jump [Native]") == 0) + if (stricmp(func->Function->Variants[0].Implementation->QualifiedName, "Actor.A_Jump") == 0) { // Unravel the varargs part of this function here so that the VM->native interface does not have to deal with it anymore. if (func->ArgList.Size() > 2) diff --git a/src/scripting/thingdef_data.cpp b/src/scripting/thingdef_data.cpp index 57ce42852..cedf305b0 100644 --- a/src/scripting/thingdef_data.cpp +++ b/src/scripting/thingdef_data.cpp @@ -347,6 +347,11 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(MF8, ADDLIGHTLEVEL, AActor, flags8), DEFINE_FLAG(MF8, ONLYSLAMSOLID, AActor, flags8), + DEFINE_FLAG(MF9, SHADOWAIM, AActor, flags9), + DEFINE_FLAG(MF9, DOSHADOWBLOCK, AActor, flags9), + DEFINE_FLAG(MF9, SHADOWBLOCK, AActor, flags9), + DEFINE_FLAG(MF9, SHADOWAIMVERT, AActor, flags9), + // Effect flags DEFINE_FLAG(FX, VISIBILITYPULSE, AActor, effects), DEFINE_FLAG2(FX_ROCKET, ROCKETTRAIL, AActor, effects), @@ -355,8 +360,7 @@ static FFlagDef ActorFlagDefs[]= DEFINE_FLAG(RF, FORCEYBILLBOARD, AActor, renderflags), DEFINE_FLAG(RF, FORCEXYBILLBOARD, AActor, renderflags), DEFINE_FLAG(RF, ROLLSPRITE, AActor, renderflags), // [marrub] roll the sprite billboard - // [fgsfds] Flat sprites - DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags), + DEFINE_FLAG(RF, FLATSPRITE, AActor, renderflags), // [fgsfds] Flat sprites DEFINE_FLAG(RF, WALLSPRITE, AActor, renderflags), DEFINE_FLAG(RF, DONTFLIP, AActor, renderflags), DEFINE_FLAG(RF, ROLLCENTER, AActor, renderflags), diff --git a/src/scripting/thingdef_properties.cpp b/src/scripting/thingdef_properties.cpp index 1202d2489..675fef34a 100644 --- a/src/scripting/thingdef_properties.cpp +++ b/src/scripting/thingdef_properties.cpp @@ -988,6 +988,7 @@ DEFINE_PROPERTY(clearflags, 0, Actor) defaults->flags6 = 0; defaults->flags7 = 0; defaults->flags8 = 0; + defaults->flags9 = 0; } //========================================================================== diff --git a/src/scripting/vmthunks_actors.cpp b/src/scripting/vmthunks_actors.cpp index f302d335d..e3438d6f6 100644 --- a/src/scripting/vmthunks_actors.cpp +++ b/src/scripting/vmthunks_actors.cpp @@ -1302,7 +1302,8 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetRadiusDamage, P_GetRadiusDamage) PARAM_INT(distance); PARAM_INT(fulldmgdistance); PARAM_BOOL(oldradiusdmg); - ACTION_RETURN_INT(P_GetRadiusDamage(self, thing, damage, distance, fulldmgdistance, oldradiusdmg)); + PARAM_BOOL(circular); + ACTION_RETURN_INT(P_GetRadiusDamage(self, thing, damage, distance, fulldmgdistance, oldradiusdmg, circular)); } static int RadiusAttack(AActor *self, AActor *bombsource, int bombdamage, int bombdistance, int damagetype, int flags, int fulldamagedistance, int species) @@ -1538,20 +1539,21 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, LookForPlayers, P_LookForPlayers) ACTION_RETURN_BOOL(P_LookForPlayers(self, allaround, params)); } -static int CheckMonsterUseSpecials(AActor *self) +static int CheckMonsterUseSpecials(AActor *self, line_t *blocking) { spechit_t spec; int good = 0; if (!(self->flags6 & MF6_NOTRIGGER)) { + auto checkLine = blocking ? blocking : self->BlockingLine; while (spechit.Pop (spec)) { // [RH] let monsters push lines, as well as use them if (((self->flags4 & MF4_CANUSEWALLS) && P_ActivateLine (spec.line, self, 0, SPAC_Use)) || ((self->flags2 & MF2_PUSHWALL) && P_ActivateLine (spec.line, self, 0, SPAC_Push))) { - good |= spec.line == self->BlockingLine ? 1 : 2; + good |= spec.line == checkLine ? 1 : 2; } } } @@ -1563,8 +1565,9 @@ static int CheckMonsterUseSpecials(AActor *self) DEFINE_ACTION_FUNCTION_NATIVE(AActor, CheckMonsterUseSpecials, CheckMonsterUseSpecials) { PARAM_SELF_PROLOGUE(AActor); + PARAM_POINTER(blocking, line_t); - ACTION_RETURN_INT(CheckMonsterUseSpecials(self)); + ACTION_RETURN_INT(CheckMonsterUseSpecials(self, blocking)); } DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_Wander, A_Wander) @@ -1860,6 +1863,15 @@ DEFINE_ACTION_FUNCTION(AActor, PlayBounceSound) return 0; } +DEFINE_ACTION_FUNCTION(AActor, ReflectOffActor) +{ + PARAM_SELF_PROLOGUE(AActor); + PARAM_OBJECT(blocking, AActor); + + ACTION_RETURN_BOOL(P_ReflectOffActor(self, blocking)); +} + + static int isFrozen(AActor *self) { @@ -2045,6 +2057,7 @@ DEFINE_FIELD(AActor, lastbump) DEFINE_FIELD(AActor, DesignatedTeam) DEFINE_FIELD(AActor, BlockingMobj) DEFINE_FIELD(AActor, BlockingLine) +DEFINE_FIELD(AActor, MovementBlockingLine) DEFINE_FIELD(AActor, Blocking3DFloor) DEFINE_FIELD(AActor, BlockingCeiling) DEFINE_FIELD(AActor, BlockingFloor) @@ -2108,6 +2121,8 @@ DEFINE_FIELD_NAMED(AActor, ViewAngles.Yaw, viewangle) DEFINE_FIELD_NAMED(AActor, ViewAngles.Pitch, viewpitch) DEFINE_FIELD_NAMED(AActor, ViewAngles.Roll, viewroll) DEFINE_FIELD(AActor, LightLevel) +DEFINE_FIELD(AActor, ShadowAimFactor) +DEFINE_FIELD(AActor, ShadowPenaltyFactor) DEFINE_FIELD_X(FCheckPosition, FCheckPosition, thing); DEFINE_FIELD_X(FCheckPosition, FCheckPosition, pos); diff --git a/src/version.h b/src/version.h index 824b157ef..62abeae71 100644 --- a/src/version.h +++ b/src/version.h @@ -71,7 +71,7 @@ const char *GetVersionString(); // Version stored in the ini's [LastRun] section. // Bump it if you made some configuration change that you want to // be able to migrate in FGameConfigFile::DoGlobalSetup(). -#define LASTRUNVERSION "224" +#define LASTRUNVERSION "225" // Protocol version used in demos. // Bump it if you change existing DEM_ commands or add new ones. diff --git a/tools/zipdir/CMakeLists.txt b/tools/zipdir/CMakeLists.txt index 65eb2fb72..762d9027f 100644 --- a/tools/zipdir/CMakeLists.txt +++ b/tools/zipdir/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required( VERSION 3.1.0 ) if( NOT CMAKE_CROSSCOMPILING ) - include_directories( "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" ) + include_directories( SYSTEM "${ZLIB_INCLUDE_DIR}" "${BZIP2_INCLUDE_DIR}" "${LZMA_INCLUDE_DIR}" ) add_executable( zipdir zipdir.c ) target_link_libraries( zipdir ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES} lzma ) diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index 7ba58b44d..e320e6912 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -2576,14 +2576,9 @@ OptionValue "Colormaps" OptionValue "LightingModes" { - 0, "$OPTVAL_STANDARD" - 1, "$OPTVAL_BRIGHT" - 2, "$OPTVAL_DOOM" - 3, "$OPTVAL_DARK" - 4, "$OPTVAL_LEGACY" - 5, "$OPTVAL_BUILD" - 8, "$OPTVAL_SOFTWARE" - 16, "$OPTVAL_VANILLA" + 0, "$OPTVAL_CLASSIC" + 1, "$OPTVAL_SOFTWARE" + 2, "$OPTVAL_VANILLA" } OptionValue "Precision" diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 9a007dd49..4e8e5977c 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -202,6 +202,7 @@ class Actor : Thinker native native int DesignatedTeam; native Actor BlockingMobj; native Line BlockingLine; + native Line MovementBlockingLine; native Sector Blocking3DFloor; native Sector BlockingCeiling; native Sector BlockingFloor; @@ -248,6 +249,7 @@ class Actor : Thinker native native double ViewAngle, ViewPitch, ViewRoll; native double RadiusDamageFactor; // Radius damage factor native double SelfDamageFactor; + native double ShadowAimFactor, ShadowPenaltyFactor; native double StealthAlpha; native int WoundHealth; // Health needed to enter wound state native readonly color BloodColor; @@ -361,6 +363,8 @@ class Actor : Thinker native property FriendlySeeBlocks: FriendlySeeBlocks; property ThruBits: ThruBits; property LightLevel: LightLevel; + property ShadowAimFactor: ShadowAimFactor; + property ShadowPenaltyFactor: ShadowPenaltyFactor; // need some definition work first //FRenderStyle RenderStyle; @@ -438,6 +442,8 @@ class Actor : Thinker native FastSpeed -1; RadiusDamageFactor 1; SelfDamageFactor 1; + ShadowAimFactor 1; + ShadowPenaltyFactor 1; StealthAlpha 0; WoundHealth 6; GibHealth int.min; @@ -537,6 +543,12 @@ class Actor : Thinker native return -1; } + // This is called when a missile bounces off something. + virtual int SpecialBounceHit(Actor bounceMobj, Line bounceLine, SecPlane bouncePlane) + { + return -1; + } + // Called when the player presses 'use' and an actor is found, except if the // UseSpecial flag is set. Use level.ExecuteSpecial to call action specials // instead. @@ -693,7 +705,7 @@ class Actor : Thinker native native void CheckFakeFloorTriggers (double oldz, bool oldz_has_viewheight = false); native bool CheckFor3DFloorHit(double z, bool trigger); native bool CheckFor3DCeilingHit(double z, bool trigger); - native int CheckMonsterUseSpecials(); + native int CheckMonsterUseSpecials(Line blocking = null); native bool CheckMissileSpawn(double maxdist); native bool CheckPosition(Vector2 pos, bool actorsonly = false, FCheckPosition tm = null); @@ -814,6 +826,7 @@ class Actor : Thinker native native bool BounceWall(Line l = null); native bool BouncePlane(SecPlane plane); native void PlayBounceSound(bool onFloor); + native bool ReflectOffActor(Actor blocking); clearscope double PitchTo(Actor target, double zOfs = 0, double targZOfs = 0, bool absolute = false) const { @@ -1187,7 +1200,7 @@ class Actor : Thinker native native void A_CustomComboAttack(class missiletype, double spawnheight, int damage, sound meleesound = "", name damagetype = "none", bool bleed = true); native void A_Burst(class chunktype); native void A_RadiusDamageSelf(int damage = 128, double distance = 128, int flags = 0, class flashtype = null); - native int GetRadiusDamage(Actor thing, int damage, int distance, int fulldmgdistance = 0, bool oldradiusdmg = false); + native int GetRadiusDamage(Actor thing, int damage, int distance, int fulldmgdistance = 0, bool oldradiusdmg = false, bool circular = false); native int RadiusAttack(Actor bombsource, int bombdamage, int bombdistance, Name bombmod = 'none', int flags = RADF_HURTSOURCE, int fulldamagedistance = 0, name species = "None"); native void A_Respawn(int flags = 1); @@ -1209,7 +1222,7 @@ class Actor : Thinker native deprecated("2.3", "User variables are deprecated in ZScript. Actor variables are directly accessible") native void A_SetUserVarFloat(name varname, double value); deprecated("2.3", "User variables are deprecated in ZScript. Actor variables are directly accessible") native void A_SetUserArrayFloat(name varname, int index, double value); native void A_Quake(double intensity, int duration, int damrad, int tremrad, sound sfx = "world/quake"); - native void A_QuakeEx(double intensityX, double intensityY, double intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, double mulWaveX = 1, double mulWaveY = 1, double mulWaveZ = 1, int falloff = 0, int highpoint = 0, double rollIntensity = 0, double rollWave = 0); + native void A_QuakeEx(double intensityX, double intensityY, double intensityZ, int duration, int damrad, int tremrad, sound sfx = "world/quake", int flags = 0, double mulWaveX = 1, double mulWaveY = 1, double mulWaveZ = 1, int falloff = 0, int highpoint = 0, double rollIntensity = 0, double rollWave = 0, double damageMultiplier = 1, double thrustMultiplier = 0.5, int damage = 0); action native void A_SetTics(int tics); native void A_DamageSelf(int amount, name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); native void A_DamageTarget(int amount, name damagetype = "none", int flags = 0, class filter = null, name species = "None", int src = AAPTR_DEFAULT, int inflict = AAPTR_DEFAULT); diff --git a/wadsrc/static/zscript/actors/attacks.zs b/wadsrc/static/zscript/actors/attacks.zs index edefdd24f..ac754d1e1 100644 --- a/wadsrc/static/zscript/actors/attacks.zs +++ b/wadsrc/static/zscript/actors/attacks.zs @@ -606,6 +606,9 @@ extend class Actor if (flags & XF_HURTSOURCE) pflags |= RADF_HURTSOURCE; if (flags & XF_NOTMISSILE) pflags |= RADF_SOURCEISSPOT; if (flags & XF_THRUSTZ) pflags |= RADF_THRUSTZ; + if (flags & XF_THRUSTLESS) pflags |= RADF_THRUSTLESS; + if (flags & XF_NOALLIES) pflags |= RADF_NOALLIES; + if (flags & XF_CIRCULAR) pflags |= RADF_CIRCULAR; int count = RadiusAttack (target, damage, distance, damagetype, pflags, fulldamagedistance); if (!(flags & XF_NOSPLASH)) CheckSplash(distance); diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index 28166e9fc..4e9c8f9d6 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -141,6 +141,7 @@ enum EChaseFlags CHF_NOPOSTATTACKTURN = 128, CHF_STOPIFBLOCKED = 256, CHF_DONTIDLE = 512, + CHF_DONTLOOKALLAROUND = 1024, CHF_DONTTURN = CHF_NORANDOMTURN | CHF_NOPOSTATTACKTURN | CHF_STOPIFBLOCKED }; @@ -261,7 +262,9 @@ enum EExplodeFlags XF_EXPLICITDAMAGETYPE = 8, XF_NOSPLASH = 16, XF_THRUSTZ = 32, - + XF_THRUSTLESS = 64, + XF_NOALLIES = 128, + XF_CIRCULAR = 256, }; // Flags for A_RadiusThrust @@ -653,6 +656,7 @@ enum EQuakeFlags QF_GROUNDONLY = 1 << 7, QF_AFFECTACTORS = 1 << 8, QF_SHAKEONLY = 1 << 9, + QF_DAMAGEFALLOFF = 1 << 10, }; // A_CheckProximity flags @@ -1227,7 +1231,10 @@ enum RadiusDamageFlags RADF_SOURCEISSPOT = 4, RADF_NODAMAGE = 8, RADF_THRUSTZ = 16, - RADF_OLDRADIUSDAMAGE = 32 + RADF_OLDRADIUSDAMAGE = 32, + RADF_THRUSTLESS = 64, + RADF_NOALLIES = 128, + RADF_CIRCULAR = 256 }; enum IntermissionSequenceType diff --git a/wadsrc/static/zscript/engine/service.zs b/wadsrc/static/zscript/engine/service.zs index a536cd616..6df17f126 100644 --- a/wadsrc/static/zscript/engine/service.zs +++ b/wadsrc/static/zscript/engine/service.zs @@ -14,67 +14,83 @@ class Service abstract } // Play variants - virtual play String GetString(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual play String GetString(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return ""; } - virtual play int GetInt(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual play int GetInt(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return 0; } - virtual play double GetDouble(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual play double GetDouble(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return 0.0; } - virtual play Object GetObject(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual play Object GetObject(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return null; } + virtual play Name GetName(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return ''; + } + + // UI variants - virtual ui String GetStringUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual ui String GetStringUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return ""; } - virtual ui int GetIntUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual ui int GetIntUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return 0; } - virtual ui double GetDoubleUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual ui double GetDoubleUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return 0.0; } - virtual ui Object GetObjectUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual ui Object GetObjectUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return null; } + virtual ui Name GetNameUI(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return ''; + } + // data/clearscope variants - virtual clearscope String GetStringData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual clearscope String GetStringData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return ""; } - virtual clearscope int GetIntData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual clearscope int GetIntData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return 0; } - virtual clearscope double GetDoubleData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual clearscope double GetDoubleData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return 0.0; } - virtual clearscope Object GetObjectData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null) + virtual clearscope Object GetObjectData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') { return null; } + + virtual clearscope Name GetNameData(String request, string stringArg = "", int intArg = 0, double doubleArg = 0, Object objectArg = null, Name nameArg = '') + { + return ''; + } static Service Find(class serviceName){ return AllServices.GetIfExists(serviceName.GetClassName()); diff --git a/wadsrc/static/zscript/engine/ui/menu/custommessagebox.zs b/wadsrc/static/zscript/engine/ui/menu/custommessagebox.zs index 68a79417c..948d9046b 100644 --- a/wadsrc/static/zscript/engine/ui/menu/custommessagebox.zs +++ b/wadsrc/static/zscript/engine/ui/menu/custommessagebox.zs @@ -78,7 +78,7 @@ class CustomMessageBoxMenuBase : Menu abstract } else { - arrowFont = ConFont; + arrowFont = ((textFont && textFont.GetGlyphHeight(0xd) > 0) ? textFont : ConFont); destWidth = CleanWidth; destHeight = CleanHeight; selector = "\xd"; @@ -133,7 +133,7 @@ class CustomMessageBoxMenuBase : Menu abstract if ((MenuTime() % 8) < 6) { screen.DrawText(arrowFont, OptionMenuSettings.mFontColorSelection, - (destWidth/2 - 11) + OptionXOffset(messageSelection), y + fontheight * messageSelection, selector, DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true); + (destWidth/2 - 3 - arrowFont.StringWidth(selector)) + OptionXOffset(messageSelection), y + fontheight * messageSelection, selector, DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true); } } } diff --git a/wadsrc/static/zscript/engine/ui/menu/joystickmenu.zs b/wadsrc/static/zscript/engine/ui/menu/joystickmenu.zs index 06b412f17..206a31098 100644 --- a/wadsrc/static/zscript/engine/ui/menu/joystickmenu.zs +++ b/wadsrc/static/zscript/engine/ui/menu/joystickmenu.zs @@ -220,6 +220,29 @@ class OptionMenuItemInverter : OptionMenuItemOptionBase // //============================================================================= + +class OptionMenuJoyEnable : OptionMenuItemOptionBase +{ + JoystickConfig mJoy; + + OptionMenuJoyEnable Init(String label, JoystickConfig joy) + { + Super.Init(label,"none","YesNo",null,0); + mJoy = joy; + return self; + } + + override int GetSelection() + { + return mJoy.GetEnabled() ? 1 : 0; + } + + override void SetSelection(int Selection) + { + mJoy.SetEnabled(Selection); + } +} + class OptionMenuItemJoyConfigMenu : OptionMenuItemSubmenu { JoystickConfig mJoy; @@ -259,6 +282,9 @@ class OptionMenuItemJoyConfigMenu : OptionMenuItemSubmenu it = new("OptionMenuItemStaticText").Init(joy.GetName(), false); it = new("OptionMenuItemStaticText").Init("", false); + it = new("OptionMenuJoyEnable").Init("$JOYMNU_JOYENABLE", joy); + opt.mItems.Push(it); + it = new("OptionMenuSliderJoySensitivity").Init("$JOYMNU_OVRSENS", 0, 2, 0.1, 3, joy); opt.mItems.Push(it); it = new("OptionMenuItemStaticText").Init(" ", false); diff --git a/wadsrc/static/zscript/engine/ui/menu/menu.zs b/wadsrc/static/zscript/engine/ui/menu/menu.zs index 181234808..1c1877041 100644 --- a/wadsrc/static/zscript/engine/ui/menu/menu.zs +++ b/wadsrc/static/zscript/engine/ui/menu/menu.zs @@ -84,6 +84,9 @@ struct JoystickConfig native version("2.4") native int GetNumAxes(); native String GetAxisName(int axis); + native bool GetEnabled(); + native void SetEnabled(bool enabled); + } class Menu : Object native ui version("2.4") diff --git a/wadsrc/static/zscript/engine/ui/menu/messagebox.zs b/wadsrc/static/zscript/engine/ui/menu/messagebox.zs index 8e76cae31..a49ff6f3f 100644 --- a/wadsrc/static/zscript/engine/ui/menu/messagebox.zs +++ b/wadsrc/static/zscript/engine/ui/menu/messagebox.zs @@ -79,7 +79,7 @@ class MessageBoxMenu : Menu } else { - arrowFont = ConFont; + arrowFont = ((textFont && textFont.GetGlyphHeight(0xd) > 0) ? textFont : ConFont); destWidth = CleanWidth; destHeight = CleanHeight; selector = "\xd"; @@ -134,7 +134,7 @@ class MessageBoxMenu : Menu if ((MenuTime() % 8) < 6) { screen.DrawText(arrowFont, OptionMenuSettings.mFontColorSelection, - destWidth/2 - 11, y + fontheight * messageSelection, selector, DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true); + destWidth/2 - 3 - arrowFont.StringWidth(selector), y + fontheight * messageSelection, selector, DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true); } } }