mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-20 20:26:42 +00:00
2000-03-23 Mirko Viviani <mirko.viviani@rccr.cremona.it>
* Source/NSString.m: ([-initWithFormat:arguments:]) added implementation using vasprintf() to avoid stack problems. * Headers/gnustep/base/preface.h.in: added VASPRINT_* definitions. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@6367 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
54e75a58b9
commit
0350ab6c0f
3 changed files with 197 additions and 2 deletions
|
@ -1,3 +1,9 @@
|
||||||
|
2000-03-23 Mirko Viviani <mirko.viviani@rccr.cremona.it>
|
||||||
|
|
||||||
|
* Source/NSString.m: ([-initWithFormat:arguments:]) added
|
||||||
|
implementation using vasprintf() to avoid stack problems.
|
||||||
|
* Headers/gnustep/base/preface.h.in: added VASPRINT_* definitions.
|
||||||
|
|
||||||
2000-03-23 Richard Frith-Macdonald <rfm@gnu.org>
|
2000-03-23 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
NSNumber - more extensive rewrite/optimisation ...
|
NSNumber - more extensive rewrite/optimisation ...
|
||||||
|
|
|
@ -155,5 +155,11 @@ extern const char o_NeXT_cc_version[];
|
||||||
#define VSPRINTF_LENGTH(VSPF_CALL) strlen((VSPF_CALL))
|
#define VSPRINTF_LENGTH(VSPF_CALL) strlen((VSPF_CALL))
|
||||||
#endif /* VSPRINTF_RETURNS_LENGTH */
|
#endif /* VSPRINTF_RETURNS_LENGTH */
|
||||||
|
|
||||||
|
#if VASPRINTF_RETURNS_LENGTH
|
||||||
|
#define VASPRINTF_LENGTH(VASPF_CALL) (VASPF_CALL)
|
||||||
|
#else
|
||||||
|
#error /* not implemented yet */
|
||||||
|
#endif /* VSPRINTF_RETURNS_LENGTH */
|
||||||
|
|
||||||
|
|
||||||
#endif /* __preface_h_OBJECTS_INCLUDE */
|
#endif /* __preface_h_OBJECTS_INCLUDE */
|
||||||
|
|
|
@ -502,9 +502,191 @@ handle_printf_atsign (FILE *stream,
|
||||||
- (id) initWithFormat: (NSString*)format
|
- (id) initWithFormat: (NSString*)format
|
||||||
arguments: (va_list)arg_list
|
arguments: (va_list)arg_list
|
||||||
{
|
{
|
||||||
#if HAVE_VSPRINTF
|
#if defined(HAVE_VSPRINTF) || defined(HAVE_VASPRINTF)
|
||||||
const char *format_cp = [format cString];
|
const char *format_cp = [format cString];
|
||||||
int format_len = strlen (format_cp);
|
int format_len = strlen (format_cp);
|
||||||
|
#if HAVE_VASPRINTF
|
||||||
|
char *buf;
|
||||||
|
int printed_len = 0;
|
||||||
|
NSString *ret;
|
||||||
|
|
||||||
|
#if ! HAVE_REGISTER_PRINTF_FUNCTION
|
||||||
|
NSZone *z = fastZone(self);
|
||||||
|
|
||||||
|
/* If the available libc doesn't have `register_printf_function()', then
|
||||||
|
the `%@' printf directive isn't available with printf() and friends.
|
||||||
|
Here we make a feable attempt to handle it. */
|
||||||
|
{
|
||||||
|
/* We need a local copy since we change it. (Changing and undoing
|
||||||
|
the change doesn't work because some format strings are constant
|
||||||
|
strings, placed in a non-writable section of the executable, and
|
||||||
|
writing to them will cause a segfault.) */
|
||||||
|
char format_cp_copy[format_len+1];
|
||||||
|
char *atsign_pos; /* points to a location inside format_cp_copy */
|
||||||
|
char *format_to_go = format_cp_copy;
|
||||||
|
char *buf_l;
|
||||||
|
#define _PRINTF_BUF_LEN 256
|
||||||
|
int printed_local_len, avail_len = _PRINTF_BUF_LEN;
|
||||||
|
int cstring_len;
|
||||||
|
|
||||||
|
buf = NSZoneMalloc(z, _PRINTF_BUF_LEN);
|
||||||
|
strcpy (format_cp_copy, format_cp);
|
||||||
|
/* Loop once for each `%@' in the format string. */
|
||||||
|
while ((atsign_pos = strstr (format_to_go, "%@")))
|
||||||
|
{
|
||||||
|
const char *cstring;
|
||||||
|
char *formatter_pos; // Position for formatter.
|
||||||
|
|
||||||
|
/* If there is a "%%@", then do the right thing: print it literally. */
|
||||||
|
if ((*(atsign_pos-1) == '%')
|
||||||
|
&& atsign_pos != format_cp_copy)
|
||||||
|
continue;
|
||||||
|
/* Temporarily terminate the string before the `%@'. */
|
||||||
|
*atsign_pos = '\0';
|
||||||
|
/* Print the part before the '%@' */
|
||||||
|
printed_local_len = VASPRINTF_LENGTH (vasprintf (&buf_l,
|
||||||
|
format_to_go, arg_list));
|
||||||
|
if(buf_l)
|
||||||
|
{
|
||||||
|
if(avail_len < printed_local_len+1)
|
||||||
|
{
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
|
buf = NSZoneRealloc(z, buf,
|
||||||
|
printed_len+printed_local_len+_PRINTF_BUF_LEN);
|
||||||
|
avail_len += _PRINTF_BUF_LEN;
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
free(buf_l);
|
||||||
|
[localException raise];
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
}
|
||||||
|
memcpy(&buf[printed_len], buf_l, printed_local_len+1);
|
||||||
|
avail_len -= printed_local_len;
|
||||||
|
printed_len += printed_local_len;
|
||||||
|
free(buf_l);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[NSException raise: NSMallocException
|
||||||
|
format: @"No available memory"];
|
||||||
|
}
|
||||||
|
/* Skip arguments used in last vsprintf(). */
|
||||||
|
while ((formatter_pos = strchr(format_to_go, '%')))
|
||||||
|
{
|
||||||
|
char *spec_pos; // Position of conversion specifier.
|
||||||
|
|
||||||
|
if (*(formatter_pos+1) == '%')
|
||||||
|
{
|
||||||
|
format_to_go = formatter_pos+2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
spec_pos = strpbrk(formatter_pos+1, "dioxXucsfeEgGpn\0");
|
||||||
|
switch (*spec_pos)
|
||||||
|
{
|
||||||
|
#ifndef powerpc
|
||||||
|
/* FIXME: vsprintf on powerpc apparently advances the arg list
|
||||||
|
so this doesn't need to be done. Make a more general check
|
||||||
|
for this */
|
||||||
|
case 'd': case 'i': case 'o':
|
||||||
|
case 'x': case 'X': case 'u': case 'c':
|
||||||
|
va_arg(arg_list, int);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if (*(spec_pos - 1) == '*')
|
||||||
|
va_arg(arg_list, int*);
|
||||||
|
va_arg(arg_list, char*);
|
||||||
|
break;
|
||||||
|
case 'f': case 'e': case 'E': case 'g': case 'G':
|
||||||
|
va_arg(arg_list, double);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
va_arg(arg_list, void*);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
va_arg(arg_list, int*);
|
||||||
|
break;
|
||||||
|
#endif /* NOT powerpc */
|
||||||
|
case '\0':
|
||||||
|
spec_pos--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
format_to_go = spec_pos+1;
|
||||||
|
}
|
||||||
|
/* Get a C-string (char*) from the String object, and print it. */
|
||||||
|
cstring = [[(id) va_arg (arg_list, id) description] cString];
|
||||||
|
if (!cstring)
|
||||||
|
cstring = "<null string>";
|
||||||
|
cstring_len = strlen(cstring);
|
||||||
|
|
||||||
|
if(cstring_len)
|
||||||
|
{
|
||||||
|
if(avail_len < cstring_len+1)
|
||||||
|
{
|
||||||
|
buf = NSZoneRealloc(z, buf,
|
||||||
|
printed_len+cstring_len+_PRINTF_BUF_LEN);
|
||||||
|
avail_len += _PRINTF_BUF_LEN;
|
||||||
|
}
|
||||||
|
memcpy(&buf[printed_len], cstring, cstring_len+1);
|
||||||
|
avail_len -= cstring_len;
|
||||||
|
printed_len += cstring_len;
|
||||||
|
}
|
||||||
|
/* Skip over this `%@', and look for another one. */
|
||||||
|
format_to_go = atsign_pos + 2;
|
||||||
|
}
|
||||||
|
/* Print the rest of the string after the last `%@'. */
|
||||||
|
printed_local_len = VASPRINTF_LENGTH (vasprintf (&buf_l,
|
||||||
|
format_to_go, arg_list));
|
||||||
|
if(buf_l)
|
||||||
|
{
|
||||||
|
if(avail_len < printed_local_len+1)
|
||||||
|
{
|
||||||
|
NS_DURING
|
||||||
|
{
|
||||||
|
buf = NSZoneRealloc(z, buf,
|
||||||
|
printed_len+printed_local_len+_PRINTF_BUF_LEN);
|
||||||
|
avail_len += _PRINTF_BUF_LEN;
|
||||||
|
}
|
||||||
|
NS_HANDLER
|
||||||
|
{
|
||||||
|
free(buf_l);
|
||||||
|
[localException raise];
|
||||||
|
}
|
||||||
|
NS_ENDHANDLER
|
||||||
|
}
|
||||||
|
memcpy(&buf[printed_len], buf_l, printed_local_len+1);
|
||||||
|
avail_len -= printed_local_len;
|
||||||
|
printed_len += printed_local_len;
|
||||||
|
free(buf_l);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[NSException raise: NSMallocException
|
||||||
|
format: @"No available memory"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else /* HAVE_VSPRINTF */
|
||||||
|
/* The available libc has `register_printf_function()', so the `%@'
|
||||||
|
printf directive is handled by printf and friends. */
|
||||||
|
printed_len = VASPRINTF_LENGTH (vasprintf (&buf, format_cp, arg_list));
|
||||||
|
|
||||||
|
if(!buf)
|
||||||
|
{
|
||||||
|
[NSException raise: NSMallocException
|
||||||
|
format: @"No available memory"];
|
||||||
|
}
|
||||||
|
#endif /* !HAVE_REGISTER_PRINTF_FUNCTION */
|
||||||
|
|
||||||
|
ret = [self initWithCString: buf];
|
||||||
|
#if ! HAVE_REGISTER_PRINTF_FUNCTION
|
||||||
|
NSZoneFree(z, buf);
|
||||||
|
#else
|
||||||
|
free(buf);
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
#else
|
||||||
/* xxx horrible disgusting BUFFER_EXTRA arbitrary limit; fix this! */
|
/* xxx horrible disgusting BUFFER_EXTRA arbitrary limit; fix this! */
|
||||||
#define BUFFER_EXTRA 1024*500
|
#define BUFFER_EXTRA 1024*500
|
||||||
char buf[format_len + BUFFER_EXTRA];
|
char buf[format_len + BUFFER_EXTRA];
|
||||||
|
@ -602,7 +784,8 @@ handle_printf_atsign (FILE *stream,
|
||||||
/* Raise an exception if we overran our buffer. */
|
/* Raise an exception if we overran our buffer. */
|
||||||
NSParameterAssert (printed_len < format_len + BUFFER_EXTRA - 1);
|
NSParameterAssert (printed_len < format_len + BUFFER_EXTRA - 1);
|
||||||
return [self initWithCString: buf];
|
return [self initWithCString: buf];
|
||||||
#else /* HAVE_VSPRINTF */
|
#endif /* HAVE_VASPRINTF */
|
||||||
|
#else /* HAVE_VSPRINTF || HAVE_VASPRINTF */
|
||||||
[self notImplemented: _cmd];
|
[self notImplemented: _cmd];
|
||||||
return self;
|
return self;
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue