Files
mercury/runtime/mercury_string.c
Simon Taylor 40e515eb31 Fix bug which caused the results of MR_hash_string() and
Estimated hours taken: 0.5
Branches: main, release

runtime/mercury_string.h:
runtime/mercury_string.c:
	Fix bug which caused the results of MR_hash_string() and
	string__hash to differ when `sizeof(int) != sizeof(MR_Integer)'.

runtime/mercury_misc.c:
	MR_hash_string() was defined here for non-GCC compilers
	for historical reasons. Move it to mercury_string.c.
2002-11-22 15:01:10 +00:00

109 lines
2.3 KiB
C

/*
** Copyright (C) 2000-2002 The University of Melbourne.
** This file may only be copied under the terms of the GNU Library General
** Public License - see the file COPYING.LIB in the Mercury distribution.
*/
/* mercury_string.c - string handling */
#include "mercury_imp.h"
#include "mercury_string.h"
#if defined(MR_HAVE__VSNPRINTF) && ! defined(MR_HAVE_VSNPRINTF)
#define vsnprintf _vsnprintf
#endif
#if defined(MR_HAVE_VSNPRINTF) || defined(MR_HAVE__VSNPRINTF)
#define MR_HAVE_A_VSNPRINTF
#endif
#define BUFFER_SIZE 4096
MR_String
MR_make_string(MR_Code *proclabel, const char *fmt, ...) {
va_list ap;
MR_String result;
int n;
char *p;
#ifdef MR_HAVE_A_VSNPRINTF
int size = BUFFER_SIZE;
char fixed[BUFFER_SIZE];
MR_bool dynamically_allocated = MR_FALSE;
/*
** On the first iteration we try with a fixed-size buffer.
** If that didn't work, use a dynamically allocated array twice
** the size of the fixed array and keep growing the array until
** the string fits.
*/
p = fixed;
while (1) {
/* Try to print in the allocated space. */
va_start(ap, fmt);
n = vsnprintf(p, size, fmt, ap);
va_end(ap);
/* If that worked, return the string. */
if (n > -1 && n < size) {
break;
}
/* Else try again with more space. */
if (n > -1) { /* glibc 2.1 */
size = n + 1; /* precisely what is needed */
} else { /* glibc 2.0 */
size *= 2; /* twice the old size */
}
if (!dynamically_allocated) {
p = MR_NEW_ARRAY(char, size);
dynamically_allocated = MR_TRUE;
} else {
p = MR_RESIZE_ARRAY(p, char, size);
}
}
#else
/*
** It is possible for this buffer to overflow and
** then bad things may happen
*/
char fixed[40960];
va_start(ap, fmt);
n = vsprintf(fixed, fmt, ap);
va_end(ap);
p = fixed;
#endif
MR_restore_transient_hp();
MR_allocate_aligned_string_msg(result, strlen(p), proclabel);
MR_save_transient_hp();
strcpy(result, p);
#ifdef MR_HAVE_A_VSNPRINTF
if (dynamically_allocated) {
MR_free(p);
}
#endif
return result;
}
/*
** Note that MR_hash_string is actually defined as a macro in
** mercury_string.h, if we're using GNU C.
** We define it here whether or not we're using gcc, so that users
** can easily switch between gcc and cc without rebuilding the libraries.
*/
#undef MR_hash_string
MR_Integer
MR_hash_string(MR_ConstString s)
{
MR_HASH_STRING_FUNC_BODY
}