diff --git a/src/binary_c_code_options.h b/src/binary_c_code_options.h index 0ca25e7410dbda58fd8eb3fc6d9f33d9ddd84495..a74317f7e656bc6a6480409d38856777f8402031 100644 --- a/src/binary_c_code_options.h +++ b/src/binary_c_code_options.h @@ -749,15 +749,6 @@ void Print_trace(void); #define STRING_LENGTH ((size_t)4096) #define BATCHMODE_STRING_LENGTH STRING_LENGTH -/* - * The buffered string length should be longer than STRING_LENGTH, - * and long enough to put the (whole!) version string into it. - * - * At the time of writing, this requires just over 100KByte of RAM, - * so I have set the length to 250KByte. - */ -#define MAX_BUFFERED_STRING_LENGTH ((size_t)(1024*250)) - /* * Buffer increase ratio: this is the amount * by which the main buffer is increased each time it diff --git a/src/buffering/buffered_printf.c b/src/buffering/buffered_printf.c index 302e754fdbc72152ea1ed1934320a740eb4e742f..cdfbdc88f32459857015acb059ea45d84e6239d8 100644 --- a/src/buffering/buffered_printf.c +++ b/src/buffering/buffered_printf.c @@ -1,6 +1,13 @@ #define _GNU_SOURCE #include "../binary_c.h" +#undef BUFFERED_STRING_OVERRUN_WARNINGS +#define BUFFERED_STRING_OVERRUN_WARNINGS +#undef BUFFERED_PRINTF_MAX_BUFFER_SIZE +#define BUFFERED_PRINTF_MAX_BUFFER_SIZE ((size_t)(1024*1)) + +size_t __deslash(char * string); + /* * Send some output into the buffer. * @@ -8,86 +15,73 @@ * because that will call this function which results * in a loop. Instead, use the small amount of the buffer * which is allocated for errors. + * + * There are several things we do: + * + * First, make the "buffer_string". This is the + * string that is sent into this function. It has + * a maximum length MAX_BUFFERED_STRING_LENGTH. + * + * Second, we allocate space to fill the raw_buffer. + * This is the big buffer which is eventually output + * e.g. through the API. This has maximum size + * BUFFERED_PRINTF_MAX_BUFFER_SIZE. */ -int Gnu_format_args(3,4) buffered_printf(struct stardata_t * RESTRICT const stardata, - const Boolean deslash, - const char * RESTRICT const format, - ...) +int Gnu_format_args(3,4) buffered_printf( + struct stardata_t * RESTRICT const stardata, + const Boolean deslash, + const char * RESTRICT const format, + ...) { + int retval; /* return value */ + va_list args; + va_start(args,format); if(stardata && stardata->tmpstore) { + struct tmpstore_t * RESTRICT const t = stardata->tmpstore; - va_list args; - va_start(args,format); - - /* allocate tmpstore space for the new string */ - if(stardata->tmpstore->buffer_string == NULL) + /* + * Make the string + */ + char * string; + size_t dn = (size_t)( + sizeof(char)* + (size_t)vasprintf(&string, + format, + args) + ); + + if(dn == -1) { - stardata->tmpstore->buffer_string = - Malloc(sizeof(char) * MAX_BUFFERED_STRING_LENGTH); + /* + * asprintf error, e.g. memory allocation failed. + */ + //buffered_printf_error_handler(stardata); + retval = 0; } - - /* do the sprintf to make the string */ - char * string = stardata->tmpstore->buffer_string; - if(string) + else { /* - * Allocate space for the string. Keep the last - * char free for a \n that might be required. + * We made the output string, now process it */ - size_t dn = (size_t)sizeof(char)* - vsnprintf(string, - MAX_BUFFERED_STRING_LENGTH, - format, - args); - size_t dnwant = dn; - dn = Min(dn, - MAX_BUFFERED_STRING_LENGTH-1); - va_end(args); - -#ifdef BUFFERED_STRING_OVERRUN_WARNINGS - if(dn<dnwant) - { - fprintf(BUFFERED_STRING_OVERRUN_WARNINGS_STREAM, - "warning : buffer overrun : got %zu want %zu\n", - dn, - dnwant); - } -#endif - if(unlikely(deslash == TRUE)) { /* * convert _slash_ to / */ - char * match = strstr(string,"_slash_"); - size_t s = strlen(string); - while(match != NULL) - { - size_t i; - match[0] = '/'; - for(i=1;i<s;i++) - { - match[i] = match[i+6]; - if(match[i] == '\0') - { - break; - } - } - match = strstr(string,"_slash_"); - } - dn = strlen(string); + dn = __deslash(string); + } /* fprintf(stdout, "BUFPRINT %uz (%uz to %uz) \"%s\" (stardata %p prefs %p internal_buffering %d)\n", dn, - stardata->tmpstore->raw_buffer_size, - stardata->tmpstore->raw_buffer_size+dn, + t->raw_buffer_size, + t->raw_buffer_size+dn, string, stardata, stardata->preferences, @@ -99,7 +93,6 @@ int Gnu_format_args(3,4) buffered_printf(struct stardata_t * RESTRICT const star stardata->preferences) && stardata->preferences->internal_buffering) { - struct tmpstore_t * RESTRICT t = stardata->tmpstore; /* * data should be buffered here, then dumped * elsewhere (e.g. at the end of evolution) @@ -122,23 +115,38 @@ int Gnu_format_args(3,4) buffered_printf(struct stardata_t * RESTRICT const star * If final char in the new string is a newline, require a NULL * after it just in case this is the end */ - size_t lastn = Max(0,dn - 1); - Boolean require_null = string[lastn] == '\n'; - if(require_null==TRUE && dn<MAX_BUFFERED_STRING_LENGTH) dn++; + const size_t lastn = Max(0,dn - 1); + const Boolean require_null = string[lastn] == '\n'; - size_t new_buffer_size = t->raw_buffer_size + (size_t)(dn + 1); + // TODO CHECK THIS + //if(require_null==TRUE && dn<MAX_BUFFERED_STRING_LENGTH) dn++; + + /* + * Calculate the size of the buffer + */ + const size_t new_buffer_size = t->raw_buffer_size + (size_t)(dn + 1); - size_t new_alloc_size = new_buffer_size > t->raw_buffer_alloced ? + /* + * Calculate the size of what needs to be allocated + */ + const size_t new_alloc_size = new_buffer_size > t->raw_buffer_alloced ? Max(new_buffer_size+1, (size_t)(BUFFERED_PRINTF_INCREASE_RATIO * t->raw_buffer_alloced)) : t->raw_buffer_alloced; + fprintf(stderr,"new_alloc_size %zu vs %zu\n",new_alloc_size,BUFFERED_PRINTF_MAX_BUFFER_SIZE); + if(new_alloc_size < BUFFERED_PRINTF_MAX_BUFFER_SIZE - BUFFERED_PRINTF_ERROR_BUFFER_SIZE) { + /* + * Allocate more memory for the buffer + */ + fprintf(stderr,"new alloc size too small\n"); if(new_alloc_size > t->raw_buffer_alloced) { t->raw_buffer = t->raw_buffer==NULL ? - Malloc(dn+1) : Realloc(t->raw_buffer,new_alloc_size); + Malloc(dn+1) : + Realloc(t->raw_buffer,new_alloc_size); #ifdef BUFFER_MEMORY_DEBUGGING fprintf(stderr,//BUFFER_MEMORY_DEBUGGING_STREAM, "Realloc %6.2f %s\n", \ @@ -161,14 +169,20 @@ int Gnu_format_args(3,4) buffered_printf(struct stardata_t * RESTRICT const star { t->raw_buffer[t->raw_buffer_size-1]='\0'; } + + /* return number of characters processed */ + retval = (int)(dn/sizeof(char)); } else { printf("error\n");fflush(NULL); dn = BUFFERED_PRINTF_ERROR_BUFFER_SIZE; - size_t new_buffer_size = t->raw_buffer_size + (size_t)(dn + 1); + const size_t new_buffer_size = t->raw_buffer_size + (size_t)(dn + 1); + /* + * THIS CANNOT BE RIGHT: new_alloc_size is used twice! + */ size_t new_alloc_size = new_buffer_size > t->raw_buffer_alloced ? Max(new_buffer_size, (size_t)((size_t)BUFFERED_PRINTF_INCREASE_RATIO * t->raw_buffer_alloced + BUFFERED_PRINTF_ERROR_BUFFER_SIZE)) : @@ -192,11 +206,12 @@ int Gnu_format_args(3,4) buffered_printf(struct stardata_t * RESTRICT const star t->raw_buffer_alloced = new_alloc_size; } - return 0; + retval = 0; } } else { + fprintf(stderr,"Cannot output\n"); /* * We cannot output : this means we have filled the * buffer. @@ -226,35 +241,60 @@ int Gnu_format_args(3,4) buffered_printf(struct stardata_t * RESTRICT const star if(t) { + fprintf(stderr, + "error snprintf %zu\n", + BUFFERED_PRINTF_ERROR_BUFFER_SIZE-1); snprintf( string, BUFFERED_PRINTF_ERROR_BUFFER_SIZE-1, "SYSTEM_ERROR Cannot Printf because buffer has been exceeded (want %zu bytes, max is %zu)\n", new_alloc_size, BUFFERED_PRINTF_MAX_BUFFER_SIZE); - memcpy(t->raw_buffer + t->raw_buffer_size,string,dn); + memcpy(t->raw_buffer + t->raw_buffer_size, + string, + dn); t->raw_buffer_size += dn; } - return 0; + retval = 0;; } } else /* no buffering: just write directly to stdout */ { fwrite((char *)string,(int)(dn/sizeof(char)),1,stdout); + + /* return number of characters processed */ + retval = (int)(dn/sizeof(char)); } + } - /* return number of characters processed */ - return (int)(dn/sizeof(char)); - } - else - { - return 0; - } } else { - return 0; + retval = 0; } + + va_end(args); + return retval; } +size_t __deslash(char * string) +{ + char * match = strstr(string,"_slash_"); + const size_t s = strlen(string); + while(match != NULL) + { + size_t i; + match[0] = '/'; + for(i=1;i<s;i++) + { + match[i] = match[i+6]; + if(match[i] == '\0') + { + break; + } + } + match = strstr(string,"_slash_"); + } + return strlen(string); +} diff --git a/src/setup/version.c b/src/setup/version.c index 697e419856a765114843243c53f73c23f754ca54..e63980ea25dbb03f9dd4a96f19df780a737c97f7 100644 --- a/src/setup/version.c +++ b/src/setup/version.c @@ -1494,7 +1494,7 @@ void version(struct stardata_t * RESTRICT const stardata) Macrotest(BUFFER_MEMORY_DEBUGGING); Show_string_macro(BUFFER_MEMORY_DEBUGGING_STREAM); Macrotest(BUFFERED_STRING_OVERRUN_WARNINGS); - Show_int_macro(MAX_BUFFERED_STRING_LENGTH); + Show_string_macro(BUFFERED_STRING_OVERRUN_WARNINGS_STREAM); Show_float_macro(BUFFERED_PRINTF_INCREASE_RATIO);