Fossil SCM
Preserve the C89 compatibility of pikchr.c by using MSVC C89 implementations of rint() and snprintf() with older MSVC versions
Commit
6429a4bdc284dc03295a1d3d86dd061ca380e586ddb357eb986890b750c32a30
Parent
c945679735b0c97…
1 file changed
+54
+54
| --- src/pikchr.c | ||
| +++ src/pikchr.c | ||
| @@ -128,10 +128,64 @@ | ||
| 128 | 128 | #endif |
| 129 | 129 | |
| 130 | 130 | /* Tag intentionally unused parameters with this macro to prevent |
| 131 | 131 | ** compiler warnings with -Wextra */ |
| 132 | 132 | #define UNUSED_PARAMETER(X) (void)(X) |
| 133 | + | |
| 134 | +#if defined(_MSC_VER) && (_MSC_VER < 1900) /* before MSVC 2015 */ | |
| 135 | +#include <stdarg.h> | |
| 136 | + | |
| 137 | +/* NOTE: On truncation, this version of snprintf returns the input count, not | |
| 138 | +** the expected number of chars to fully output the requested format (as | |
| 139 | +** done in the C99 standard implementation). However the truncation test should | |
| 140 | +** still be applicable (nret >= count). | |
| 141 | +*/ | |
| 142 | +static __forceinline | |
| 143 | +int c89_snprintf(char *buf, size_t count, const char *fmt, ...){ | |
| 144 | + va_list argptr; | |
| 145 | + int n; | |
| 146 | + if( count==0 ) return 0; | |
| 147 | + va_start(argptr, fmt); | |
| 148 | + n = _vsprintf_p(buf, count, fmt, argptr); | |
| 149 | + va_end(argptr); | |
| 150 | + | |
| 151 | + /* force zero-termination to avoid some known MSVC bugs */ | |
| 152 | + if( count>0 ){ | |
| 153 | + buf[count - 1] = '\0'; | |
| 154 | + if( n<0 ) n = count; | |
| 155 | + } | |
| 156 | + return n; | |
| 157 | +} | |
| 158 | + | |
| 159 | +#if defined(_WIN64) | |
| 160 | +#include <emmintrin.h> | |
| 161 | +#include <limits.h> | |
| 162 | + | |
| 163 | +static __forceinline | |
| 164 | +double c89_rint(double v){ | |
| 165 | + return ( v<0.0 && v>=-0.5 ? -0.0 | |
| 166 | + : ( v!=0 && v>LLONG_MIN && v<LLONG_MAX | |
| 167 | + ? _mm_cvtsd_si64(_mm_load_sd(&v)) : v ) ); /* SSE2 */ | |
| 168 | +} | |
| 169 | +#else | |
| 170 | +static __forceinline | |
| 171 | +double c89_rint(double v){ | |
| 172 | + double rn; | |
| 173 | + __asm | |
| 174 | + { | |
| 175 | + FLD v | |
| 176 | + FRNDINT | |
| 177 | + FSTP rn | |
| 178 | + FWAIT | |
| 179 | + }; | |
| 180 | + return rn; | |
| 181 | +} | |
| 182 | +#endif /* _WIN64 */ | |
| 183 | + | |
| 184 | +#define snprintf c89_snprintf | |
| 185 | +#define rint c89_rint | |
| 186 | +#endif | |
| 133 | 187 | |
| 134 | 188 | typedef struct Pik Pik; /* Complete parsing context */ |
| 135 | 189 | typedef struct PToken PToken; /* A single token */ |
| 136 | 190 | typedef struct PObj PObj; /* A single diagram object */ |
| 137 | 191 | typedef struct PList PList; /* A list of diagram objects */ |
| 138 | 192 |
| --- src/pikchr.c | |
| +++ src/pikchr.c | |
| @@ -128,10 +128,64 @@ | |
| 128 | #endif |
| 129 | |
| 130 | /* Tag intentionally unused parameters with this macro to prevent |
| 131 | ** compiler warnings with -Wextra */ |
| 132 | #define UNUSED_PARAMETER(X) (void)(X) |
| 133 | |
| 134 | typedef struct Pik Pik; /* Complete parsing context */ |
| 135 | typedef struct PToken PToken; /* A single token */ |
| 136 | typedef struct PObj PObj; /* A single diagram object */ |
| 137 | typedef struct PList PList; /* A list of diagram objects */ |
| 138 |
| --- src/pikchr.c | |
| +++ src/pikchr.c | |
| @@ -128,10 +128,64 @@ | |
| 128 | #endif |
| 129 | |
| 130 | /* Tag intentionally unused parameters with this macro to prevent |
| 131 | ** compiler warnings with -Wextra */ |
| 132 | #define UNUSED_PARAMETER(X) (void)(X) |
| 133 | |
| 134 | #if defined(_MSC_VER) && (_MSC_VER < 1900) /* before MSVC 2015 */ |
| 135 | #include <stdarg.h> |
| 136 | |
| 137 | /* NOTE: On truncation, this version of snprintf returns the input count, not |
| 138 | ** the expected number of chars to fully output the requested format (as |
| 139 | ** done in the C99 standard implementation). However the truncation test should |
| 140 | ** still be applicable (nret >= count). |
| 141 | */ |
| 142 | static __forceinline |
| 143 | int c89_snprintf(char *buf, size_t count, const char *fmt, ...){ |
| 144 | va_list argptr; |
| 145 | int n; |
| 146 | if( count==0 ) return 0; |
| 147 | va_start(argptr, fmt); |
| 148 | n = _vsprintf_p(buf, count, fmt, argptr); |
| 149 | va_end(argptr); |
| 150 | |
| 151 | /* force zero-termination to avoid some known MSVC bugs */ |
| 152 | if( count>0 ){ |
| 153 | buf[count - 1] = '\0'; |
| 154 | if( n<0 ) n = count; |
| 155 | } |
| 156 | return n; |
| 157 | } |
| 158 | |
| 159 | #if defined(_WIN64) |
| 160 | #include <emmintrin.h> |
| 161 | #include <limits.h> |
| 162 | |
| 163 | static __forceinline |
| 164 | double c89_rint(double v){ |
| 165 | return ( v<0.0 && v>=-0.5 ? -0.0 |
| 166 | : ( v!=0 && v>LLONG_MIN && v<LLONG_MAX |
| 167 | ? _mm_cvtsd_si64(_mm_load_sd(&v)) : v ) ); /* SSE2 */ |
| 168 | } |
| 169 | #else |
| 170 | static __forceinline |
| 171 | double c89_rint(double v){ |
| 172 | double rn; |
| 173 | __asm |
| 174 | { |
| 175 | FLD v |
| 176 | FRNDINT |
| 177 | FSTP rn |
| 178 | FWAIT |
| 179 | }; |
| 180 | return rn; |
| 181 | } |
| 182 | #endif /* _WIN64 */ |
| 183 | |
| 184 | #define snprintf c89_snprintf |
| 185 | #define rint c89_rint |
| 186 | #endif |
| 187 | |
| 188 | typedef struct Pik Pik; /* Complete parsing context */ |
| 189 | typedef struct PToken PToken; /* A single token */ |
| 190 | typedef struct PObj PObj; /* A single diagram object */ |
| 191 | typedef struct PList PList; /* A list of diagram objects */ |
| 192 |