Minor fix in Text::setFillColor.

Updated dr_flac, dr_mp3, subprocess.
This commit is contained in:
Martín Lucas Golini
2022-03-02 01:04:10 -03:00
parent 7c6d5d69bc
commit 43252db990
5 changed files with 865 additions and 313 deletions

View File

@@ -907,7 +907,7 @@ void Text::ensureColorUpdate() {
if ( mContainsColorEmoji ) {
auto positions = Font::emojiCodePointsPositions( mString );
for ( auto& position : positions )
setFillColor( Color( 255, 255, 255, mFillColor.a ), position, position + 1 );
setFillColor( Color( 255, 255, 255, mFillColor.a ), position, position );
}
}
}

View File

@@ -1792,7 +1792,8 @@ void UICodeEditor::drawLineText( const Int64& index, Vector2f position, const Fl
auto& tokens = mHighlighter.getLine( index );
Primitives primitives;
for ( auto& token : tokens ) {
Float textWidth = getTextWidth( token.text );
String text( token.text );
Float textWidth = getTextWidth( text );
if ( position.x + textWidth >= mScreenPos.x &&
position.x <= mScreenPos.x + mSize.getWidth() ) {
Text line( "", mFont, fontSize );
@@ -1806,7 +1807,7 @@ void UICodeEditor::drawLineText( const Int64& index, Vector2f position, const Fl
primitives.drawRectangle( Rectf( position, Sizef( textWidth, lineHeight ) ) );
}
line.setColor( Color( style.color ).blendAlpha( mAlpha ) );
line.setString( token.text );
line.setString( text );
line.draw( position.x, position.y );
} else if ( position.x > mScreenPos.x + mSize.getWidth() ) {
break;

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/*
MP3 audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file.
dr_mp3 - v0.6.16 - 2020-08-02
dr_mp3 - v0.6.32 - 2021-12-11
David Reid - mackron@gmail.com
@@ -95,7 +95,7 @@ extern "C" {
#define DRMP3_VERSION_MAJOR 0
#define DRMP3_VERSION_MINOR 6
#define DRMP3_VERSION_REVISION 16
#define DRMP3_VERSION_REVISION 32
#define DRMP3_VERSION_STRING DRMP3_XSTRINGIFY(DRMP3_VERSION_MAJOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_MINOR) "." DRMP3_XSTRINGIFY(DRMP3_VERSION_REVISION)
#include <stddef.h> /* For size_t. */
@@ -107,11 +107,11 @@ typedef signed short drmp3_int16;
typedef unsigned short drmp3_uint16;
typedef signed int drmp3_int32;
typedef unsigned int drmp3_uint32;
#if defined(_MSC_VER)
#if defined(_MSC_VER) && !defined(__clang__)
typedef signed __int64 drmp3_int64;
typedef unsigned __int64 drmp3_uint64;
#else
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
#if defined(__clang__)
@@ -120,11 +120,11 @@ typedef unsigned int drmp3_uint32;
#endif
typedef signed long long drmp3_int64;
typedef unsigned long long drmp3_uint64;
#if defined(__GNUC__)
#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)))
#pragma GCC diagnostic pop
#endif
#endif
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__)
typedef drmp3_uint64 drmp3_uintptr;
#else
typedef drmp3_uint32 drmp3_uintptr;
@@ -239,6 +239,8 @@ typedef drmp3_int32 drmp3_result;
#else
#define DRMP3_INLINE inline __attribute__((always_inline))
#endif
#elif defined(__WATCOMC__)
#define DRMP3_INLINE __inline
#else
#define DRMP3_INLINE
#endif
@@ -279,14 +281,6 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num
Main API (Pull API)
===================
*/
#ifndef DRMP3_DEFAULT_CHANNELS
#define DRMP3_DEFAULT_CHANNELS 2
#endif
#ifndef DRMP3_DEFAULT_SAMPLE_RATE
#define DRMP3_DEFAULT_SAMPLE_RATE 44100
#endif
typedef enum
{
drmp3_seek_origin_start,
@@ -596,7 +590,7 @@ DRMP3_API const char* drmp3_version_string(void)
#if !defined(DR_MP3_NO_SIMD)
#if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(_M_ARM64) || defined(__x86_64__) || defined(__aarch64__))
#if !defined(DR_MP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64))
/* x64 always have SSE2, arm64 always have neon, no need for generic code */
#define DR_MP3_ONLY_SIMD
#endif
@@ -672,7 +666,7 @@ end:
return g_have_simd - 1;
#endif
}
#elif defined(__ARM_NEON) || defined(__aarch64__)
#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)
#include <arm_neon.h>
#define DRMP3_HAVE_SSE 0
#define DRMP3_HAVE_SIMD 1
@@ -705,17 +699,44 @@ static int drmp3_have_simd(void)
#endif
#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__)
#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64)
#define DRMP3_HAVE_ARMV6 1
static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(int32_t a)
static __inline__ __attribute__((always_inline)) drmp3_int32 drmp3_clip_int16_arm(drmp3_int32 a)
{
drmp3_int32 x = 0;
__asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a));
return x;
}
#else
#define DRMP3_HAVE_ARMV6 0
#endif
/* Standard library stuff. */
#ifndef DRMP3_ASSERT
#include <assert.h>
#define DRMP3_ASSERT(expression) assert(expression)
#endif
#ifndef DRMP3_COPY_MEMORY
#define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
#endif
#ifndef DRMP3_MOVE_MEMORY
#define DRMP3_MOVE_MEMORY(dst, src, sz) memmove((dst), (src), (sz))
#endif
#ifndef DRMP3_ZERO_MEMORY
#define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
#endif
#define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p)))
#ifndef DRMP3_MALLOC
#define DRMP3_MALLOC(sz) malloc((sz))
#endif
#ifndef DRMP3_REALLOC
#define DRMP3_REALLOC(p, sz) realloc((p), (sz))
#endif
#ifndef DRMP3_FREE
#define DRMP3_FREE(p) free((p))
#endif
typedef struct
{
const drmp3_uint8 *buf;
@@ -982,7 +1003,7 @@ static int drmp3_L12_dequantize_granule(float *grbuf, drmp3_bs *bs, drmp3_L12_sc
static void drmp3_L12_apply_scf_384(drmp3_L12_scale_info *sci, const float *scf, float *dst)
{
int i, k;
memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float));
DRMP3_COPY_MEMORY(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float));
for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6)
{
for (k = 0; k < 12; k++)
@@ -1127,14 +1148,14 @@ static void drmp3_L3_read_scalefactors(drmp3_uint8 *scf, drmp3_uint8 *ist_pos, c
int cnt = scf_count[i];
if (scfsi & 8)
{
memcpy(scf, ist_pos, cnt);
DRMP3_COPY_MEMORY(scf, ist_pos, cnt);
} else
{
int bits = scf_size[i];
if (!bits)
{
memset(scf, 0, cnt);
memset(ist_pos, 0, cnt);
DRMP3_ZERO_MEMORY(scf, cnt);
DRMP3_ZERO_MEMORY(ist_pos, cnt);
} else
{
int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1;
@@ -1394,12 +1415,22 @@ static void drmp3_L3_midside_stereo(float *left, int n)
int i = 0;
float *right = left + 576;
#if DRMP3_HAVE_SIMD
if (drmp3_have_simd()) for (; i < n - 3; i += 4)
if (drmp3_have_simd())
{
drmp3_f4 vl = DRMP3_VLD(left + i);
drmp3_f4 vr = DRMP3_VLD(right + i);
DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr));
DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr));
for (; i < n - 3; i += 4)
{
drmp3_f4 vl = DRMP3_VLD(left + i);
drmp3_f4 vr = DRMP3_VLD(right + i);
DRMP3_VSTORE(left + i, DRMP3_VADD(vl, vr));
DRMP3_VSTORE(right + i, DRMP3_VSUB(vl, vr));
}
#ifdef __GNUC__
/* Workaround for spurious -Waggressive-loop-optimizations warning from gcc.
* For more info see: https://github.com/lieff/minimp3/issues/88
*/
if (__builtin_constant_p(n % 4 == 0) && n % 4 == 0)
return;
#endif
}
#endif
for (; i < n; i++)
@@ -1509,7 +1540,7 @@ static void drmp3_L3_reorder(float *grbuf, float *scratch, const drmp3_uint8 *sf
*dst++ = src[2*len];
}
}
memcpy(grbuf, scratch, (dst - scratch)*sizeof(float));
DRMP3_COPY_MEMORY(grbuf, scratch, (dst - scratch)*sizeof(float));
}
static void drmp3_L3_antialias(float *grbuf, int nbands)
@@ -1678,8 +1709,8 @@ static void drmp3_L3_imdct_short(float *grbuf, float *overlap, int nbands)
for (;nbands > 0; nbands--, overlap += 9, grbuf += 18)
{
float tmp[18];
memcpy(tmp, grbuf, sizeof(tmp));
memcpy(grbuf, overlap, 6*sizeof(float));
DRMP3_COPY_MEMORY(tmp, grbuf, sizeof(tmp));
DRMP3_COPY_MEMORY(grbuf, overlap, 6*sizeof(float));
drmp3_L3_imdct12(tmp, grbuf + 6, overlap + 6);
drmp3_L3_imdct12(tmp + 1, grbuf + 12, overlap + 6);
drmp3_L3_imdct12(tmp + 2, overlap, overlap + 6);
@@ -1723,7 +1754,7 @@ static void drmp3_L3_save_reservoir(drmp3dec *h, drmp3dec_scratch *s)
}
if (remains > 0)
{
memmove(h->reserv_buf, s->maindata + pos, remains);
DRMP3_MOVE_MEMORY(h->reserv_buf, s->maindata + pos, remains);
}
h->reserv = remains;
}
@@ -1732,8 +1763,8 @@ static int drmp3_L3_restore_reservoir(drmp3dec *h, drmp3_bs *bs, drmp3dec_scratc
{
int frame_bytes = (bs->limit - bs->pos)/8;
int bytes_have = DRMP3_MIN(h->reserv, main_data_begin);
memcpy(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin));
memcpy(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes);
DRMP3_COPY_MEMORY(s->maindata, h->reserv_buf + DRMP3_MAX(0, h->reserv - main_data_begin), DRMP3_MIN(h->reserv, main_data_begin));
DRMP3_COPY_MEMORY(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes);
drmp3_bs_init(&s->bs, s->maindata, bytes_have + frame_bytes);
return h->reserv >= main_data_begin;
}
@@ -1866,7 +1897,7 @@ static void drmp3d_DCT_II(float *grbuf, int n)
} else
#endif
#ifdef DR_MP3_ONLY_SIMD
{}
{} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */
#else
for (; k < n; k++)
{
@@ -2099,7 +2130,7 @@ static void drmp3d_synth(float *xl, drmp3d_sample_t *dstl, int nch, float *lins)
} else
#endif
#ifdef DR_MP3_ONLY_SIMD
{}
{} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */
#else
for (i = 14; i >= 0; i--)
{
@@ -2140,7 +2171,7 @@ static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int
drmp3d_DCT_II(grbuf + 576*i, nbands);
}
memcpy(lins, qmf_state, sizeof(float)*15*64);
DRMP3_COPY_MEMORY(lins, qmf_state, sizeof(float)*15*64);
for (i = 0; i < nbands; i += 2)
{
@@ -2156,7 +2187,7 @@ static void drmp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int
} else
#endif
{
memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64);
DRMP3_COPY_MEMORY(qmf_state, lins + nbands*64, sizeof(float)*15*64);
}
}
@@ -2234,7 +2265,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
}
if (!frame_size)
{
memset(dec, 0, sizeof(drmp3dec));
DRMP3_ZERO_MEMORY(dec, sizeof(drmp3dec));
i = drmp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size);
if (!frame_size || i + frame_size > mp3_bytes)
{
@@ -2244,7 +2275,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
}
hdr = mp3 + i;
memcpy(dec->header, hdr, DRMP3_HDR_SIZE);
DRMP3_COPY_MEMORY(dec->header, hdr, DRMP3_HDR_SIZE);
info->frame_bytes = i + frame_size;
info->channels = DRMP3_HDR_IS_MONO(hdr) ? 1 : 2;
info->hz = drmp3_hdr_sample_rate_hz(hdr);
@@ -2270,7 +2301,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
{
for (igr = 0; igr < (DRMP3_HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*576*info->channels))
{
memset(scratch.grbuf[0], 0, 576*2*sizeof(float));
DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
drmp3_L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels);
drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
}
@@ -2289,7 +2320,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
drmp3_L12_read_scale_info(hdr, bs_frame, sci);
memset(scratch.grbuf[0], 0, 576*2*sizeof(float));
DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
for (i = 0, igr = 0; igr < 3; igr++)
{
if (12 == (i += drmp3_L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1)))
@@ -2297,7 +2328,7 @@ DRMP3_API int drmp3dec_decode_frame(drmp3dec *dec, const drmp3_uint8 *mp3, int m
i = 0;
drmp3_L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]);
drmp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, (drmp3d_sample_t*)pcm, scratch.syn[0]);
memset(scratch.grbuf[0], 0, 576*2*sizeof(float));
DRMP3_ZERO_MEMORY(scratch.grbuf[0], 576*2*sizeof(float));
pcm = DRMP3_OFFSET_PTR(pcm, sizeof(drmp3d_sample_t)*384*info->channels);
}
if (bs_frame->pos > bs_frame->limit)
@@ -2400,28 +2431,6 @@ DRMP3_API void drmp3dec_f32_to_s16(const float *in, drmp3_int16 *out, size_t num
#endif
/* Standard library stuff. */
#ifndef DRMP3_ASSERT
#include <assert.h>
#define DRMP3_ASSERT(expression) assert(expression)
#endif
#ifndef DRMP3_COPY_MEMORY
#define DRMP3_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz))
#endif
#ifndef DRMP3_ZERO_MEMORY
#define DRMP3_ZERO_MEMORY(p, sz) memset((p), 0, (sz))
#endif
#define DRMP3_ZERO_OBJECT(p) DRMP3_ZERO_MEMORY((p), sizeof(*(p)))
#ifndef DRMP3_MALLOC
#define DRMP3_MALLOC(sz) malloc((sz))
#endif
#ifndef DRMP3_REALLOC
#define DRMP3_REALLOC(p, sz) realloc((p), (sz))
#endif
#ifndef DRMP3_FREE
#define DRMP3_FREE(p) free((p))
#endif
#define DRMP3_COUNTOF(x) (sizeof(x) / sizeof(x[0]))
#define DRMP3_CLAMP(x, lo, hi) (DRMP3_MAX(lo, DRMP3_MIN(x, hi)))
@@ -2653,7 +2662,7 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa
/* First we need to move the data down. */
if (pMP3->pData != NULL) {
memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
}
pMP3->dataConsumed = 0;
@@ -2689,6 +2698,9 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa
return 0; /* File too big. */
}
DRMP3_ASSERT(pMP3->pData != NULL);
DRMP3_ASSERT(pMP3->dataCapacity > 0);
pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->pData + pMP3->dataConsumed, (int)pMP3->dataSize, pPCMFrames, &info); /* <-- Safe size_t -> int conversion thanks to the check above. */
/* Consume the data. */
@@ -2710,7 +2722,7 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__callbacks(drmp3* pMP3, drmp3d_sa
size_t bytesRead;
/* First we need to move the data down. */
memmove(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
DRMP3_MOVE_MEMORY(pMP3->pData, pMP3->pData + pMP3->dataConsumed, pMP3->dataSize);
pMP3->dataConsumed = 0;
if (pMP3->dataCapacity == pMP3->dataSize) {
@@ -2755,12 +2767,22 @@ static drmp3_uint32 drmp3_decode_next_frame_ex__memory(drmp3* pMP3, drmp3d_sampl
return 0;
}
pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info);
if (pcmFramesRead > 0) {
pMP3->pcmFramesConsumedInMP3Frame = 0;
pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead;
pMP3->mp3FrameChannels = info.channels;
pMP3->mp3FrameSampleRate = info.hz;
for (;;) {
pcmFramesRead = drmp3dec_decode_frame(&pMP3->decoder, pMP3->memory.pData + pMP3->memory.currentReadPos, (int)(pMP3->memory.dataSize - pMP3->memory.currentReadPos), pPCMFrames, &info);
if (pcmFramesRead > 0) {
pcmFramesRead = drmp3_hdr_frame_samples(pMP3->decoder.header);
pMP3->pcmFramesConsumedInMP3Frame = 0;
pMP3->pcmFramesRemainingInMP3Frame = pcmFramesRead;
pMP3->mp3FrameChannels = info.channels;
pMP3->mp3FrameSampleRate = info.hz;
break;
} else if (info.frame_bytes > 0) {
/* No frames were read, but it looks like we skipped past one. Read the next MP3 frame. */
pMP3->memory.currentReadPos += (size_t)info.frame_bytes;
} else {
/* Nothing at all was read. Abort. */
break;
}
}
/* Consume the data. */
@@ -2823,8 +2845,8 @@ static drmp3_bool32 drmp3_init_internal(drmp3* pMP3, drmp3_read_proc onRead, drm
}
/* Decode the first frame to confirm that it is indeed a valid MP3 stream. */
if (!drmp3_decode_next_frame(pMP3)) {
drmp3_uninit(pMP3);
if (drmp3_decode_next_frame(pMP3) == 0) {
drmp3__free_from_callbacks(pMP3->pData, &pMP3->allocationCallbacks); /* The call above may have allocated memory. Need to make sure it's freed before aborting. */
return DRMP3_FALSE; /* Not a valid MP3 stream. */
}
@@ -3326,7 +3348,7 @@ static drmp3_result drmp3_result_from_errno(int e)
static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
{
#if _MSC_VER && _MSC_VER >= 1400
#if defined(_MSC_VER) && _MSC_VER >= 1400
errno_t err;
#endif
@@ -3338,7 +3360,7 @@ static drmp3_result drmp3_fopen(FILE** ppFile, const char* pFilePath, const char
return DRMP3_INVALID_ARGS;
}
#if _MSC_VER && _MSC_VER >= 1400
#if defined(_MSC_VER) && _MSC_VER >= 1400
err = fopen_s(ppFile, pFilePath, pOpenMode);
if (err != 0) {
return drmp3_result_from_errno(err);
@@ -3373,12 +3395,13 @@ _wfopen() isn't always available in all compilation environments.
* MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
* MinGW-64 (both 32- and 64-bit) seems to support it.
* MinGW wraps it in !defined(__STRICT_ANSI__).
* OpenWatcom wraps it in !defined(_NO_EXT_KEYS).
This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
*/
#if defined(_WIN32)
#if defined(_MSC_VER) || defined(__MINGW64__) || !defined(__STRICT_ANSI__)
#if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
#define DRMP3_HAS_WFOPEN
#endif
#endif
@@ -3479,22 +3502,38 @@ static drmp3_bool32 drmp3__on_seek_stdio(void* pUserData, int offset, drmp3_seek
DRMP3_API drmp3_bool32 drmp3_init_file(drmp3* pMP3, const char* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
drmp3_bool32 result;
FILE* pFile;
if (drmp3_fopen(&pFile, pFilePath, "rb") != DRMP3_SUCCESS) {
return DRMP3_FALSE;
}
return drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
if (result != DRMP3_TRUE) {
fclose(pFile);
return result;
}
return DRMP3_TRUE;
}
DRMP3_API drmp3_bool32 drmp3_init_file_w(drmp3* pMP3, const wchar_t* pFilePath, const drmp3_allocation_callbacks* pAllocationCallbacks)
{
drmp3_bool32 result;
FILE* pFile;
if (drmp3_wfopen(&pFile, pFilePath, L"rb", pAllocationCallbacks) != DRMP3_SUCCESS) {
return DRMP3_FALSE;
}
return drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
result = drmp3_init(pMP3, drmp3__on_read_stdio, drmp3__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
if (result != DRMP3_TRUE) {
fclose(pFile);
return result;
}
return DRMP3_TRUE;
}
#endif
@@ -3506,7 +3545,11 @@ DRMP3_API void drmp3_uninit(drmp3* pMP3)
#ifndef DR_MP3_NO_STDIO
if (pMP3->onRead == drmp3__on_read_stdio) {
fclose((FILE*)pMP3->pUserData);
FILE* pFile = (FILE*)pMP3->pUserData;
if (pFile != NULL) {
fclose(pFile);
pMP3->pUserData = NULL; /* Make sure the file handle is cleared to NULL to we don't attempt to close it a second time. */
}
}
#endif
@@ -4157,7 +4200,7 @@ static float* drmp3__full_read_and_close_f32(drmp3* pMP3, drmp3_config* pConfig,
oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(float);
newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(float);
if (newFramesBufferSize > DRMP3_SIZE_MAX) {
if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) {
break;
}
@@ -4224,7 +4267,7 @@ static drmp3_int16* drmp3__full_read_and_close_s16(drmp3* pMP3, drmp3_config* pC
oldFramesBufferSize = framesCapacity * pMP3->channels * sizeof(drmp3_int16);
newFramesBufferSize = newFramesCap * pMP3->channels * sizeof(drmp3_int16);
if (newFramesBufferSize > DRMP3_SIZE_MAX) {
if (newFramesBufferSize > (drmp3_uint64)DRMP3_SIZE_MAX) {
break;
}
@@ -4430,6 +4473,56 @@ counts rather than sample counts.
/*
REVISION HISTORY
================
v0.6.32 - 2021-12-11
- Fix a warning with Clang.
v0.6.31 - 2021-08-22
- Fix a bug when loading from memory.
v0.6.30 - 2021-08-16
- Silence some warnings.
- Replace memory operations with DRMP3_* macros.
v0.6.29 - 2021-08-08
- Bring up to date with minimp3.
v0.6.28 - 2021-07-31
- Fix platform detection for ARM64.
- Fix a compilation error with C89.
v0.6.27 - 2021-02-21
- Fix a warning due to referencing _MSC_VER when it is undefined.
v0.6.26 - 2021-01-31
- Bring up to date with minimp3.
v0.6.25 - 2020-12-26
- Remove DRMP3_DEFAULT_CHANNELS and DRMP3_DEFAULT_SAMPLE_RATE which are leftovers from some removed APIs.
v0.6.24 - 2020-12-07
- Fix a typo in version date for 0.6.23.
v0.6.23 - 2020-12-03
- Fix an error where a file can be closed twice when initialization of the decoder fails.
v0.6.22 - 2020-12-02
- Fix an error where it's possible for a file handle to be left open when initialization of the decoder fails.
v0.6.21 - 2020-11-28
- Bring up to date with minimp3.
v0.6.20 - 2020-11-21
- Fix compilation with OpenWatcom.
v0.6.19 - 2020-11-13
- Minor code clean up.
v0.6.18 - 2020-11-01
- Improve compiler support for older versions of GCC.
v0.6.17 - 2020-09-28
- Bring up to date with minimp3.
v0.6.16 - 2020-08-02
- Simplify sized types.

View File

@@ -35,6 +35,10 @@
#if defined(_MSC_VER)
#pragma warning(push, 1)
/* disable warning: '__cplusplus' is not defined as a preprocessor macro,
* replacing with '0' for '#if/#elif' */
#pragma warning(disable : 4668)
#endif
#include <stdio.h>
@@ -43,12 +47,12 @@
#pragma warning(pop)
#endif
#if defined(__clang__) || defined(__GNUC__)
#define subprocess_pure __attribute__((pure))
#define subprocess_weak __attribute__((weak))
#elif defined(_MSC_VER)
#if defined(_MSC_VER)
#define subprocess_pure
#define subprocess_weak __inline
#elif defined(__clang__) || defined(__GNUC__)
#define subprocess_pure __attribute__((pure))
#define subprocess_weak __attribute__((weak))
#else
#error Non clang, non gcc, non MSVC compiler found!
#endif
@@ -63,7 +67,11 @@ enum subprocess_option_e {
subprocess_option_inherit_environment = 0x2,
// Enable asynchronous reading of stdout/stderr before it has completed.
subprocess_option_enable_async = 0x4
subprocess_option_enable_async = 0x4,
// Enable the child process to be spawned with no window visible if supported
// by the platform.
subprocess_option_no_window = 0x8
};
#if defined(__cplusplus)
@@ -73,13 +81,34 @@ extern "C" {
/// @brief Create a process.
/// @param command_line An array of strings for the command line to execute for
/// this process. The last element must be NULL to signify the end of the array.
/// The memory backing this parameter only needs to persist until this function
/// returns.
/// @param options A bit field of subprocess_option_e's to pass.
/// @param out_process The newly created process.
/// @return On success 0 is returned.
/// @return On success zero is returned.
subprocess_weak int subprocess_create(const char *const command_line[],
int options,
struct subprocess_s *const out_process);
/// @brief Create a process (extended create).
/// @param command_line An array of strings for the command line to execute for
/// this process. The last element must be NULL to signify the end of the array.
/// The memory backing this parameter only needs to persist until this function
/// returns.
/// @param options A bit field of subprocess_option_e's to pass.
/// @param environment An optional array of strings for the environment to use
/// for a child process (each element of the form FOO=BAR). The last element
/// must be NULL to signify the end of the array.
/// @param out_process The newly created process.
/// @return On success zero is returned.
///
/// If `options` contains `subprocess_option_inherit_environment`, then
/// `environment` must be NULL.
subprocess_weak int
subprocess_create_ex(const char *const command_line[], int options,
const char *const environment[],
struct subprocess_s *const out_process);
/// @brief Get the standard input file for a process.
/// @param process The process to query.
/// @return The file for standard input of the process.
@@ -115,7 +144,7 @@ subprocess_stderr(const struct subprocess_s *const process);
/// @param process The process to wait for.
/// @param out_return_code The return code of the returned process (can be
/// NULL).
/// @return On success 0 is returned.
/// @return On success zero is returned.
///
/// Joining a process will close the stdin pipe to the process.
subprocess_weak int subprocess_join(struct subprocess_s *const process,
@@ -123,7 +152,7 @@ subprocess_weak int subprocess_join(struct subprocess_s *const process,
/// @brief Destroy a previously created process.
/// @param process The process to destroy.
/// @return On success 0 is returned.
/// @return On success zero is returned.
///
/// If the process to be destroyed had not finished execution, it may out live
/// the parent process.
@@ -131,7 +160,7 @@ subprocess_weak int subprocess_destroy(struct subprocess_s *const process);
/// @brief Terminate a previously created process.
/// @param process The process to terminate.
/// @return On success 0 is returned.
/// @return On success zero is returned.
///
/// If the process to be destroyed had not finished execution, it will be
/// terminated (i.e killed).
@@ -165,21 +194,34 @@ subprocess_weak unsigned
subprocess_read_stderr(struct subprocess_s *const process, char *const buffer,
unsigned size);
/// @brief Returns if the subprocess is currently still alive and executing.
/// @param process The process to check.
/// @return If the process is still alive non-zero is returned.
subprocess_weak int subprocess_alive(struct subprocess_s *const process);
#if defined(__cplusplus)
#define SUBPROCESS_CAST(type, x) static_cast<type>(x)
#define SUBPROCESS_PTR_CAST(type, x) reinterpret_cast<type>(x)
#define SUBPROCESS_CONST_CAST(type, x) const_cast<type>(x)
#define SUBPROCESS_NULL NULL
#else
#define SUBPROCESS_CAST(type, x) ((type)x)
#define SUBPROCESS_CAST(type, x) ((type)(x))
#define SUBPROCESS_PTR_CAST(type, x) ((type)(x))
#define SUBPROCESS_CONST_CAST(type, x) ((type)(x))
#define SUBPROCESS_NULL 0
#endif
#if !defined(_MSC_VER)
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#endif
#if defined(_MSC_VER)
#if (_MSC_VER < 1920)
#ifdef _WIN64
typedef __int64 subprocess_intptr_t;
typedef unsigned __int64 subprocess_size_t;
@@ -187,6 +229,12 @@ typedef unsigned __int64 subprocess_size_t;
typedef int subprocess_intptr_t;
typedef unsigned int subprocess_size_t;
#endif
#else
#include <inttypes.h>
typedef intptr_t subprocess_intptr_t;
typedef size_t subprocess_size_t;
#endif
typedef struct _PROCESS_INFORMATION *LPPROCESS_INFORMATION;
typedef struct _SECURITY_ATTRIBUTES *LPSECURITY_ATTRIBUTES;
@@ -272,8 +320,7 @@ __declspec(dllimport) unsigned long __stdcall WaitForSingleObject(
void *, unsigned long);
__declspec(dllimport) int __stdcall GetExitCodeProcess(
void *, unsigned long *lpExitCode);
__declspec(dllimport) int __stdcall TerminateProcess(
void *, unsigned int);
__declspec(dllimport) int __stdcall TerminateProcess(void *, unsigned int);
__declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(
unsigned long, void *const *, int, unsigned long);
__declspec(dllimport) int __stdcall GetOverlappedResult(void *, LPOVERLAPPED,
@@ -290,6 +337,8 @@ SUBPROCESS_DLLIMPORT int __cdecl _open_osfhandle(subprocess_intptr_t, int);
SUBPROCESS_DLLIMPORT subprocess_intptr_t __cdecl _get_osfhandle(int);
void *__cdecl _alloca(subprocess_size_t);
#else
typedef size_t subprocess_size_t;
#endif
#ifdef __clang__
@@ -308,7 +357,10 @@ struct subprocess_s {
void *hEventError;
#else
pid_t child;
int return_status;
#endif
subprocess_size_t alive;
};
#ifdef __clang__
#pragma clang diagnostic pop
@@ -324,40 +376,39 @@ int subprocess_create_named_pipe_helper(void **rd, void **wr) {
const unsigned long genericWrite = 0x40000000;
const unsigned long openExisting = 3;
const unsigned long fileAttributeNormal = 0x00000080;
const void *const invalidHandleValue = (void *)~((subprocess_intptr_t)0);
struct subprocess_security_attributes_s saAttr = {sizeof(saAttr), 0, 1};
const void *const invalidHandleValue =
SUBPROCESS_PTR_CAST(void *, ~(SUBPROCESS_CAST(subprocess_intptr_t, 0)));
struct subprocess_security_attributes_s saAttr = {sizeof(saAttr),
SUBPROCESS_NULL, 1};
char name[256] = {0};
__declspec(thread) static long index = 0;
const long unique = index++;
#if _MSC_VER < 1900
#pragma warning(disable : 4996)
#pragma warning(push, 1)
#pragma warning(disable : 4996)
_snprintf(name, sizeof(name) - 1,
"\\\\.\\pipe\\sheredom_subprocess_h.%08lx.%08lx.%ld",
GetCurrentProcessId(), GetCurrentThreadId(), unique);
#pragma warning(pop)
#else
#pragma warning(disable : 4710)
#pragma warning(push, 1)
snprintf(name, sizeof(name) - 1,
"\\\\.\\pipe\\sheredom_subprocess_h.%08lx.%08lx.%ld",
GetCurrentProcessId(), GetCurrentThreadId(), unique);
#pragma warning(pop)
#endif
*rd = CreateNamedPipeA(name, pipeAccessInbound | fileFlagOverlapped,
pipeTypeByte | pipeWait, 1, 4096, 4096, 0,
(LPSECURITY_ATTRIBUTES)&saAttr);
*rd =
CreateNamedPipeA(name, pipeAccessInbound | fileFlagOverlapped,
pipeTypeByte | pipeWait, 1, 4096, 4096, SUBPROCESS_NULL,
SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr));
if (invalidHandleValue == rd) {
return -1;
}
*wr = CreateFileA(name, genericWrite, 0, (LPSECURITY_ATTRIBUTES)&saAttr,
openExisting, fileAttributeNormal, 0);
*wr = CreateFileA(name, genericWrite, SUBPROCESS_NULL,
SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr),
openExisting, fileAttributeNormal, SUBPROCESS_NULL);
if (invalidHandleValue == wr) {
return -1;
@@ -369,29 +420,95 @@ int subprocess_create_named_pipe_helper(void **rd, void **wr) {
int subprocess_create(const char *const commandLine[], int options,
struct subprocess_s *const out_process) {
return subprocess_create_ex(commandLine, options, SUBPROCESS_NULL,
out_process);
}
int subprocess_create_ex(const char *const commandLine[], int options,
const char *const environment[],
struct subprocess_s *const out_process) {
#if defined(_MSC_VER)
int fd;
void *rd, *wr;
char *commandLineCombined;
subprocess_size_t len;
int i, j;
unsigned long flags = 0;
const unsigned long startFUseStdHandles = 0x00000100;
const unsigned long handleFlagInherit = 0x00000001;
const unsigned long createNoWindow = 0x08000000;
struct subprocess_subprocess_information_s processInfo;
struct subprocess_security_attributes_s saAttr = {sizeof(saAttr), 0, 1};
char *environment = 0;
struct subprocess_startup_info_s startInfo = {0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0};
struct subprocess_security_attributes_s saAttr = {sizeof(saAttr),
SUBPROCESS_NULL, 1};
char *used_environment = SUBPROCESS_NULL;
struct subprocess_startup_info_s startInfo = {0,
SUBPROCESS_NULL,
SUBPROCESS_NULL,
SUBPROCESS_NULL,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
SUBPROCESS_NULL,
SUBPROCESS_NULL,
SUBPROCESS_NULL,
SUBPROCESS_NULL};
startInfo.cb = sizeof(startInfo);
startInfo.dwFlags = startFUseStdHandles;
if (subprocess_option_inherit_environment !=
(options & subprocess_option_inherit_environment)) {
environment = "\0\0";
if (subprocess_option_no_window != (options & subprocess_option_no_window)) {
flags |= createNoWindow;
}
if (!CreatePipe(&rd, &wr, (LPSECURITY_ATTRIBUTES)&saAttr, 0)) {
if (subprocess_option_inherit_environment !=
(options & subprocess_option_inherit_environment)) {
if (SUBPROCESS_NULL == environment) {
used_environment = SUBPROCESS_CONST_CAST(char *, "\0\0");
} else {
// We always end with two null terminators.
len = 2;
for (i = 0; environment[i]; i++) {
for (j = 0; '\0' != environment[i][j]; j++) {
len++;
}
// For the null terminator too.
len++;
}
used_environment = SUBPROCESS_CAST(char *, _alloca(len));
// Re-use len for the insertion position
len = 0;
for (i = 0; environment[i]; i++) {
for (j = 0; '\0' != environment[i][j]; j++) {
used_environment[len++] = environment[i][j];
}
used_environment[len++] = '\0';
}
// End with the two null terminators.
used_environment[len++] = '\0';
used_environment[len++] = '\0';
}
} else {
if (SUBPROCESS_NULL != environment) {
return -1;
}
}
if (!CreatePipe(&rd, &wr, SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr),
0)) {
return -1;
}
@@ -399,12 +516,12 @@ int subprocess_create(const char *const commandLine[], int options,
return -1;
}
fd = _open_osfhandle((subprocess_intptr_t)wr, 0);
fd = _open_osfhandle(SUBPROCESS_PTR_CAST(subprocess_intptr_t, wr), 0);
if (-1 != fd) {
out_process->stdin_file = _fdopen(fd, "wb");
if (0 == out_process->stdin_file) {
if (SUBPROCESS_NULL == out_process->stdin_file) {
return -1;
}
}
@@ -416,7 +533,8 @@ int subprocess_create(const char *const commandLine[], int options,
return -1;
}
} else {
if (!CreatePipe(&rd, &wr, (LPSECURITY_ATTRIBUTES)&saAttr, 0)) {
if (!CreatePipe(&rd, &wr,
SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr), 0)) {
return -1;
}
}
@@ -425,12 +543,12 @@ int subprocess_create(const char *const commandLine[], int options,
return -1;
}
fd = _open_osfhandle((subprocess_intptr_t)rd, 0);
fd = _open_osfhandle(SUBPROCESS_PTR_CAST(subprocess_intptr_t, rd), 0);
if (-1 != fd) {
out_process->stdout_file = _fdopen(fd, "rb");
if (0 == out_process->stdout_file) {
if (SUBPROCESS_NULL == out_process->stdout_file) {
return -1;
}
}
@@ -447,7 +565,8 @@ int subprocess_create(const char *const commandLine[], int options,
return -1;
}
} else {
if (!CreatePipe(&rd, &wr, (LPSECURITY_ATTRIBUTES)&saAttr, 0)) {
if (!CreatePipe(&rd, &wr,
SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr), 0)) {
return -1;
}
}
@@ -456,12 +575,12 @@ int subprocess_create(const char *const commandLine[], int options,
return -1;
}
fd = _open_osfhandle((subprocess_intptr_t)rd, 0);
fd = _open_osfhandle(SUBPROCESS_PTR_CAST(subprocess_intptr_t, rd), 0);
if (-1 != fd) {
out_process->stderr_file = _fdopen(fd, "rb");
if (0 == out_process->stderr_file) {
if (SUBPROCESS_NULL == out_process->stderr_file) {
return -1;
}
}
@@ -471,12 +590,14 @@ int subprocess_create(const char *const commandLine[], int options,
if (options & subprocess_option_enable_async) {
out_process->hEventOutput =
CreateEventA((LPSECURITY_ATTRIBUTES)&saAttr, 1, 1, 0);
CreateEventA(SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr), 1, 1,
SUBPROCESS_NULL);
out_process->hEventError =
CreateEventA((LPSECURITY_ATTRIBUTES)&saAttr, 1, 1, 0);
CreateEventA(SUBPROCESS_PTR_CAST(LPSECURITY_ATTRIBUTES, &saAttr), 1, 1,
SUBPROCESS_NULL);
} else {
out_process->hEventOutput = 0;
out_process->hEventError = 0;
out_process->hEventOutput = SUBPROCESS_NULL;
out_process->hEventError = SUBPROCESS_NULL;
}
// Combine commandLine together into a single string
@@ -487,16 +608,23 @@ int subprocess_create(const char *const commandLine[], int options,
for (j = 0; '\0' != commandLine[i][j]; j++) {
switch (commandLine[i][j]) {
case '\\':
if (commandLine[i][j + 1] != '"') break;
case '"':
default:
break;
case '\\':
if (commandLine[i][j + 1] == '"') {
len++;
}
break;
case '"':
len++;
break;
}
len++;
}
}
commandLineCombined = (char *)_alloca(len);
commandLineCombined = SUBPROCESS_CAST(char *, _alloca(len));
if (!commandLineCombined) {
return -1;
@@ -513,11 +641,19 @@ int subprocess_create(const char *const commandLine[], int options,
for (j = 0; '\0' != commandLine[i][j]; j++) {
switch (commandLine[i][j]) {
case '\\':
if (commandLine[i][j + 1] != '"') break;
case '"':
default:
break;
case '\\':
if (commandLine[i][j + 1] == '"') {
commandLineCombined[len++] = '\\';
}
break;
case '"':
commandLineCombined[len++] = '\\';
break;
}
commandLineCombined[len++] = commandLine[i][j];
}
commandLineCombined[len++] = '"';
@@ -525,16 +661,18 @@ int subprocess_create(const char *const commandLine[], int options,
commandLineCombined[len] = '\0';
if (!CreateProcessA(NULL,
commandLineCombined, // command line
NULL, // process security attributes
NULL, // primary thread security attributes
1, // handles are inherited
0, // creation flags
environment, // use parent's environment
NULL, // use parent's current directory
(LPSTARTUPINFOA)&startInfo, // STARTUPINFO pointer
(LPPROCESS_INFORMATION)&processInfo)) {
if (!CreateProcessA(
SUBPROCESS_NULL,
commandLineCombined, // command line
SUBPROCESS_NULL, // process security attributes
SUBPROCESS_NULL, // primary thread security attributes
1, // handles are inherited
createNoWindow, // creation flags
used_environment, // used environment
SUBPROCESS_NULL, // use parent's current directory
SUBPROCESS_PTR_CAST(LPSTARTUPINFOA,
&startInfo), // STARTUPINFO pointer
SUBPROCESS_PTR_CAST(LPPROCESS_INFORMATION, &processInfo))) {
return -1;
}
@@ -545,7 +683,7 @@ int subprocess_create(const char *const commandLine[], int options,
// We don't need the handle of the primary thread in the called process.
CloseHandle(processInfo.hThread);
if (0 != startInfo.hStdOutput) {
if (SUBPROCESS_NULL != startInfo.hStdOutput) {
CloseHandle(startInfo.hStdOutput);
if (startInfo.hStdError != startInfo.hStdOutput) {
@@ -553,6 +691,8 @@ int subprocess_create(const char *const commandLine[], int options,
}
}
out_process->alive = 1;
return 0;
#else
int stdinfd[2];
@@ -560,6 +700,13 @@ int subprocess_create(const char *const commandLine[], int options,
int stderrfd[2];
pid_t child;
if (subprocess_option_inherit_environment ==
(options & subprocess_option_inherit_environment)) {
if (SUBPROCESS_NULL != environment) {
return -1;
}
}
if (0 != pipe(stdinfd)) {
return -1;
}
@@ -607,13 +754,19 @@ int subprocess_create(const char *const commandLine[], int options,
#pragma clang diagnostic ignored "-Wcast-qual"
#pragma clang diagnostic ignored "-Wold-style-cast"
#endif
if (subprocess_option_inherit_environment !=
(options & subprocess_option_inherit_environment)) {
char *const environment[1] = {0};
exit(execve(commandLine[0], (char *const *)commandLine, environment));
if (environment) {
_Exit(execve(commandLine[0], (char *const *)commandLine,
(char *const *)environment));
} else if (subprocess_option_inherit_environment !=
(options & subprocess_option_inherit_environment)) {
char *const empty_environment[1] = {SUBPROCESS_NULL};
_Exit(execve(commandLine[0], (char *const *)commandLine,
empty_environment));
} else {
exit(execvp(commandLine[0], (char *const *)commandLine));
_Exit(execvp(commandLine[0], (char *const *)commandLine));
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
@@ -641,6 +794,8 @@ int subprocess_create(const char *const commandLine[], int options,
// Store the child's pid
out_process->child = child;
out_process->alive = 1;
return 0;
}
#endif
@@ -658,7 +813,7 @@ FILE *subprocess_stderr(const struct subprocess_s *const process) {
if (process->stdout_file != process->stderr_file) {
return process->stderr_file;
} else {
return 0;
return SUBPROCESS_NULL;
}
}
@@ -667,43 +822,55 @@ int subprocess_join(struct subprocess_s *const process,
#if defined(_MSC_VER)
const unsigned long infinite = 0xFFFFFFFF;
if (0 != process->stdin_file) {
if (process->stdin_file) {
fclose(process->stdin_file);
process->stdin_file = 0;
process->stdin_file = SUBPROCESS_NULL;
}
if (0 != process->hStdInput) {
if (process->hStdInput) {
CloseHandle(process->hStdInput);
process->hStdInput = NULL;
process->hStdInput = SUBPROCESS_NULL;
}
WaitForSingleObject(process->hProcess, infinite);
if (out_return_code) {
if (!GetExitCodeProcess(process->hProcess,
(unsigned long *)out_return_code)) {
if (!GetExitCodeProcess(
process->hProcess,
SUBPROCESS_PTR_CAST(unsigned long *, out_return_code))) {
return -1;
}
}
process->alive = 0;
return 0;
#else
int status;
if (0 != process->stdin_file) {
if (process->stdin_file) {
fclose(process->stdin_file);
process->stdin_file = 0;
process->stdin_file = SUBPROCESS_NULL;
}
if (process->child != waitpid(process->child, &status, 0)) {
return -1;
if (process->child) {
if (process->child != waitpid(process->child, &status, 0)) {
return -1;
}
process->child = 0;
if (WIFEXITED(status)) {
process->return_status = WEXITSTATUS(status);
} else {
process->return_status = EXIT_FAILURE;
}
process->alive = 0;
}
if (out_return_code) {
if (WIFEXITED(status)) {
*out_return_code = WEXITSTATUS(status);
} else {
*out_return_code = EXIT_FAILURE;
}
*out_return_code = process->return_status;
}
return 0;
@@ -711,36 +878,36 @@ int subprocess_join(struct subprocess_s *const process,
}
int subprocess_destroy(struct subprocess_s *const process) {
if (0 != process->stdin_file) {
if (process->stdin_file) {
fclose(process->stdin_file);
process->stdin_file = 0;
process->stdin_file = SUBPROCESS_NULL;
}
if (0 != process->stdout_file) {
if (process->stdout_file) {
fclose(process->stdout_file);
if (process->stdout_file != process->stderr_file) {
fclose(process->stderr_file);
}
process->stdout_file = 0;
process->stderr_file = 0;
process->stdout_file = SUBPROCESS_NULL;
process->stderr_file = SUBPROCESS_NULL;
}
#if defined(_MSC_VER)
if (process->hProcess) {
CloseHandle(process->hProcess);
process->hProcess = 0;
process->hProcess = SUBPROCESS_NULL;
if (0 != process->hStdInput) {
if (process->hStdInput) {
CloseHandle(process->hStdInput);
}
if (0 != process->hEventOutput) {
if (process->hEventOutput) {
CloseHandle(process->hEventOutput);
}
if (0 != process->hEventError) {
if (process->hEventError) {
CloseHandle(process->hEventError);
}
}
@@ -754,10 +921,11 @@ int subprocess_terminate(struct subprocess_s *const process) {
unsigned int killed_process_exit_code;
int success_terminate;
int windows_call_result;
killed_process_exit_code = 99;
windows_call_result = TerminateProcess(process->hProcess, killed_process_exit_code);
success_terminate = (windows_call_result== 0) ? 1 : 0;
windows_call_result =
TerminateProcess(process->hProcess, killed_process_exit_code);
success_terminate = (windows_call_result == 0) ? 1 : 0;
return success_terminate;
#else
int result;
@@ -771,19 +939,22 @@ unsigned subprocess_read_stdout(struct subprocess_s *const process,
#if defined(_MSC_VER)
void *handle;
unsigned long bytes_read = 0;
struct subprocess_overlapped_s overlapped = {0};
struct subprocess_overlapped_s overlapped = {0, 0, {{0, 0}}, SUBPROCESS_NULL};
overlapped.hEvent = process->hEventOutput;
handle = (void *)_get_osfhandle(_fileno(process->stdout_file));
handle = SUBPROCESS_PTR_CAST(void *,
_get_osfhandle(_fileno(process->stdout_file)));
if (!ReadFile(handle, buffer, size, &bytes_read, (LPOVERLAPPED)&overlapped)) {
if (!ReadFile(handle, buffer, size, &bytes_read,
SUBPROCESS_PTR_CAST(LPOVERLAPPED, &overlapped))) {
const unsigned long errorIoPending = 997;
unsigned long error = GetLastError();
// Means we've got an async read!
if (error == errorIoPending) {
if (!GetOverlappedResult(handle, (LPOVERLAPPED)&overlapped, &bytes_read,
1)) {
if (!GetOverlappedResult(handle,
SUBPROCESS_PTR_CAST(LPOVERLAPPED, &overlapped),
&bytes_read, 1)) {
const unsigned long errorIoIncomplete = 996;
const unsigned long errorHandleEOF = 38;
error = GetLastError();
@@ -795,7 +966,7 @@ unsigned subprocess_read_stdout(struct subprocess_s *const process,
}
}
return (unsigned)bytes_read;
return SUBPROCESS_CAST(unsigned, bytes_read);
#else
const int fd = fileno(process->stdout_file);
const ssize_t bytes_read = read(fd, buffer, size);
@@ -813,19 +984,22 @@ unsigned subprocess_read_stderr(struct subprocess_s *const process,
#if defined(_MSC_VER)
void *handle;
unsigned long bytes_read = 0;
struct subprocess_overlapped_s overlapped = {0};
struct subprocess_overlapped_s overlapped = {0, 0, {{0, 0}}, SUBPROCESS_NULL};
overlapped.hEvent = process->hEventError;
handle = (void *)_get_osfhandle(_fileno(process->stderr_file));
handle = SUBPROCESS_PTR_CAST(void *,
_get_osfhandle(_fileno(process->stderr_file)));
if (!ReadFile(handle, buffer, size, &bytes_read, (LPOVERLAPPED)&overlapped)) {
if (!ReadFile(handle, buffer, size, &bytes_read,
SUBPROCESS_PTR_CAST(LPOVERLAPPED, &overlapped))) {
const unsigned long errorIoPending = 997;
unsigned long error = GetLastError();
// Means we've got an async read!
if (error == errorIoPending) {
if (!GetOverlappedResult(handle, (LPOVERLAPPED)&overlapped, &bytes_read,
1)) {
if (!GetOverlappedResult(handle,
SUBPROCESS_PTR_CAST(LPOVERLAPPED, &overlapped),
&bytes_read, 1)) {
const unsigned long errorIoIncomplete = 996;
const unsigned long errorHandleEOF = 38;
error = GetLastError();
@@ -837,7 +1011,7 @@ unsigned subprocess_read_stderr(struct subprocess_s *const process,
}
}
return (unsigned)bytes_read;
return SUBPROCESS_CAST(unsigned, bytes_read);
#else
const int fd = fileno(process->stderr_file);
const ssize_t bytes_read = read(fd, buffer, size);
@@ -850,6 +1024,50 @@ unsigned subprocess_read_stderr(struct subprocess_s *const process,
#endif
}
int subprocess_alive(struct subprocess_s *const process) {
int is_alive = SUBPROCESS_CAST(int, process->alive);
if (!is_alive) {
return 0;
}
#if defined(_MSC_VER)
{
const unsigned long zero = 0x0;
const unsigned long wait_object_0 = 0x00000000L;
is_alive = wait_object_0 != WaitForSingleObject(process->hProcess, zero);
}
#else
{
int status;
is_alive = 0 == waitpid(process->child, &status, WNOHANG);
// If the process was successfully waited on we need to cleanup now.
if (!is_alive) {
if (WIFEXITED(status)) {
process->return_status = WEXITSTATUS(status);
} else {
process->return_status = EXIT_FAILURE;
}
// Since we've already successfully waited on the process, we need to wipe
// the child now.
process->child = 0;
if (subprocess_join(process, SUBPROCESS_NULL)) {
return -1;
}
}
}
#endif
if (!is_alive) {
process->alive = 0;
}
return is_alive;
}
#if defined(__cplusplus)
} // extern "C"
#endif