From 67e0aea25850b8286f750e6458e5de741e6cb3b5 Mon Sep 17 00:00:00 2001
From: oharboe <oharboe@b42882b7-edfa-0310-969c-e2dbd0fdcd60>
Date: Fri, 29 Feb 2008 11:16:38 +0000
Subject: Summary: passing of variable argument list reduced, strings sent to
 logging are now formatted just once - more efficient. As a result, ugly
 string malloc+strcpy are not needed anymore.

git-svn-id: svn://svn.berlios.de/openocd/trunk@386 b42882b7-edfa-0310-969c-e2dbd0fdcd60
---
 src/helper/command.c        |  67 +++++++++--------------------
 src/helper/log.c            | 102 ++++++++++++++++++++++++--------------------
 src/helper/log.h            |  44 ++++++-------------
 src/helper/options.c        |   2 +-
 src/server/gdb_server.c     |  18 +++-----
 src/server/telnet_server.c  |  39 +++++++++--------
 src/target/target_request.c |   2 +-
 7 files changed, 118 insertions(+), 156 deletions(-)

(limited to 'src')

diff --git a/src/helper/command.c b/src/helper/command.c
index 0ec54216..aa71f0ba 100644
--- a/src/helper/command.c
+++ b/src/helper/command.c
@@ -260,66 +260,39 @@ int parse_line(char *line, char *words[], int max_words)
 	return nwords;
 }
 
-static void command_printv(command_context_t *context, char *format, va_list ap)
+void command_print_n(command_context_t *context, char *format, ...)
 {
-	char *buffer = NULL;
-	int n, size = 0;
-	char *p;
-
-	/* process format string */
-	for (;;)
-	{
-		if (!buffer || (n = vsnprintf(buffer, size, format, ap)) >= size)
-		{
-			/* increase buffer until it fits the whole string */
-			if (!(p = realloc(buffer, size += 4096)))
-			{
-				/* gotta free up */
-				if (buffer)
-					free(buffer);
-				return;
-			}
+	char *string;
 	
-			buffer = p;
-			
-			continue;
-		}
-		break;
-	}
-	
-	/* vsnprintf failed */
-	if (n < 0)
+	va_list ap;
+	va_start(ap, format);
+
+	string = alloc_printf(format, ap);
+	if (string != NULL)
 	{
-		if (buffer)
-			free(buffer);
-		return;
+		context->output_handler(context, string);
+		free(string);
 	}
 
-	context->output_handler(context, buffer);
-	
-	if (buffer)
-		free(buffer);
-}
-
-void command_print_sameline(command_context_t *context, char *format, ...)
-{
-	va_list ap;
-	va_start(ap, format);
-	command_printv(context, format, ap); 
 	va_end(ap);
 }
 
 void command_print(command_context_t *context, char *format, ...)
 {
-	char *t=malloc(strlen(format)+2);
-	strcpy(t, format);
-	strcat(t, "\n");
+	char *string;
+
 	va_list ap;
 	va_start(ap, format);
-	command_printv(context, t, ap); 
+
+	string = alloc_printf(format, ap);
+	if (string != NULL)
+	{
+		strcat(string, "\n"); /* alloc_printf guaranteed the buffer to be at least one char longer */
+		context->output_handler(context, string);
+		free(string);
+	}
+
 	va_end(ap);
-	free(t);
-	
 }
 
 int find_and_run_command(command_context_t *context, command_t *commands, char *words[], int num_words, int start_word)
diff --git a/src/helper/log.c b/src/helper/log.c
index a3e8e816..7abebc29 100644
--- a/src/helper/log.c
+++ b/src/helper/log.c
@@ -48,17 +48,15 @@ static char *log_strings[5] =
 
 static int count = 0;
 
-static void log_printfv(enum log_levels level, const char *file, int line, const char *function, const char *format, va_list args)
+
+static void log_puts(enum log_levels level, const char *file, int line, const char *function, const char *string)
 {
-	char buffer[512];
 	log_callback_t *cb;
 
-	vsnprintf(buffer, 512, format, args);
-
 	if (level == LOG_OUTPUT)
 	{
 		/* do not prepend any headers, just print out what we were given and return */
-		fputs(buffer, log_output);
+		fputs(string, log_output);
 		fflush(log_output);
 		return;
 	}
@@ -71,12 +69,12 @@ static void log_printfv(enum log_levels level, const char *file, int line, const
 	{
 		/* print with count and time information */
 		int t=(int)(time(NULL)-start);
-		fprintf(log_output, "%s %d %d %s:%d %s(): %s", log_strings[level+1], count, t, file, line, function, buffer);
+		fprintf(log_output, "%s %d %d %s:%d %s(): %s", log_strings[level+1], count, t, file, line, function, string);
 	}
 	else
 	{
 		/* do not print count and time */
-		fprintf(log_output, "%s %s:%d %s(): %s", log_strings[level+1], file, line, function, buffer);
+		fprintf(log_output, "%s %s:%d %s(): %s", log_strings[level+1], file, line, function, string);
 	}
 
 	fflush(log_output);
@@ -84,42 +82,55 @@ static void log_printfv(enum log_levels level, const char *file, int line, const
 	/* Never forward LOG_DEBUG, too verbose and they can be found in the log if need be */
 	if (level <= LOG_INFO)
 	{
+		log_callback_t *cb;
 		for (cb = log_callbacks; cb; cb = cb->next)
 		{
-			cb->fn(cb->priv, file, line, function, format, args);
+			cb->fn(cb->priv, file, line, function, string);
 		}
 	}
 }
 
 void log_printf(enum log_levels level, const char *file, int line, const char *function, const char *format, ...)
 {
+	char *string;
+
 	count++;
 	if (level > debug_level)
 		return;
 
-	va_list args;
-	va_start(args, format);
-	log_printfv(level, file, line, function, format, args);
-	va_end(args);
-	
+	va_list ap;
+	va_start(ap, format);
+
+	string = alloc_printf(format, ap);
+	if (string != NULL)
+	{
+		log_puts(level, file, line, function, string);
+		free(string);
+	}
+
+	va_end(ap);
 }
 
-void log_printfnl(enum log_levels level, const char *file, int line, const char *function, const char *format, ...)
+void log_printf_lf(enum log_levels level, const char *file, int line, const char *function, const char *format, ...)
 {
+	char *string;
+
 	count++;
 	if (level > debug_level)
 		return;
-	
-	char *t=malloc(strlen(format)+2);
-	strcpy(t, format);
-	strcat(t, "\n");
-	
-	va_list args;
-	va_start(args, format);
-	log_printfv(level, file, line, function, t, args);
-	va_end(args);
-	
-	free(t);
+
+	va_list ap;
+	va_start(ap, format);
+
+	string = alloc_printf(format, ap);
+	if (string != NULL)
+	{
+		strcat(string, "\n"); /* alloc_printf guaranteed the buffer to be at least one char longer */
+		log_puts(level, file, line, function, string);
+		free(string);
+	}
+
+	va_end(ap);
 }
 
 /* change the current debug level on the fly
@@ -237,35 +248,34 @@ int log_remove_callback(log_callback_fn fn, void *priv)
 /* return allocated string w/printf() result */
 char *alloc_printf(const char *fmt, va_list ap)
 {
+	/* no buffer at the beginning, force realloc to do the job */
 	char *string = NULL;
 	
-	/* start by 0 to exercise all the code paths. Need minimum 2 bytes to
-	 * fit 1 char and 0 terminator. */
-	int size = 0;
-	int first = 1;
+	/* start with minimal length to exercise all the code paths */
+	int size = 1;
+
 	for (;;)
 	{
-		if ((string == NULL) || (!first))
+		size *= 2; /* double the buffer size */
+
+		char *t = string;
+		string = realloc(string, size);
+		if (string == NULL)
 		{
-			size = size * 2 + 2;
-			char *t = string;
-			string = realloc(string, size);
-			if (string == NULL)
-			{
-				if (t != NULL)
-					free(t);
-				return NULL;
-			}
+			if (t != NULL)
+				free(t);
+			return NULL;
 		}
-	
+
 	    int ret;
-	    ret = vsnprintf(string, size, fmt, ap);
+		ret = vsnprintf(string, size, fmt, ap);
 	    /* NB! The result of the vsnprintf() might be an *EMPTY* string! */
 	    if ((ret >= 0) && ((ret + 1) < size))
-	    {
-	    	return string;
-	    }
-	    /* there was just enough or not enough space, allocate more. */
-	    first = 0;
+			break;
+
+	    /* there was just enough or not enough space, allocate more in the next round */
 	}
+	
+	/* the returned buffer is by principle guaranteed to be at least one character longer */
+	return string;
 }
diff --git a/src/helper/log.h b/src/helper/log.h
index a53b7f5e..c4078447 100644
--- a/src/helper/log.h
+++ b/src/helper/log.h
@@ -47,7 +47,7 @@ enum log_levels
 extern void log_printf(enum log_levels level, const char *file, int line, 
 	const char *function, const char *format, ...) 
 __attribute__ ((format (printf, 5, 6)));
-extern void log_printfnl(enum log_levels level, const char *file, int line, 
+extern void log_printf_lf(enum log_levels level, const char *file, int line,
 	const char *function, const char *format, ...) 
 __attribute__ ((format (printf, 5, 6)));
 extern int log_register_commands(struct command_context_s *cmd_ctx);
@@ -55,13 +55,13 @@ extern int log_init(struct command_context_s *cmd_ctx);
 extern int set_log_output(struct command_context_s *cmd_ctx, FILE *output);
 
 typedef void (*log_callback_fn)(void *priv, const char *file, int line,
-		const char *function, const char *format, va_list args);
+		const char *function, const char *string);
 
 typedef struct log_callback_s
 {
-    log_callback_fn fn;
+	log_callback_fn fn;
 	void *priv;
-    struct log_callback_s *next;
+	struct log_callback_s *next;
 } log_callback_t;
 
 extern int log_add_callback(log_callback_fn fn, void *priv);
@@ -76,44 +76,28 @@ extern int debug_level;
 
 
 #define DEBUG(expr ...) \
-	do { if (debug_level >= LOG_DEBUG) \
-		log_printfnl (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr); \
-	} while(0)
+		log_printf_lf (LOG_DEBUG, __FILE__, __LINE__, __FUNCTION__, expr)
 
 #define INFO(expr ...) \
-	do { if (debug_level >= LOG_INFO) \
-		log_printfnl (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr); \
-	} while(0)
+		log_printf_lf (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr)
 
-#define INFO_SAMELINE(expr ...) \
-	do { if (debug_level >= LOG_INFO) \
-		log_printf (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr); \
-	} while(0)
+#define INFO_N(expr ...) \
+		log_printf (LOG_INFO, __FILE__, __LINE__, __FUNCTION__, expr)
 
 #define WARNING(expr ...) \
-	do { \
-		log_printfnl (LOG_WARNING, __FILE__, __LINE__, __FUNCTION__, expr); \
-	} while(0)
+		log_printf_lf (LOG_WARNING, __FILE__, __LINE__, __FUNCTION__, expr)
 
 #define ERROR(expr ...) \
-	do { \
-		log_printfnl (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr); \
-	} while(0)
+		log_printf_lf (LOG_ERROR, __FILE__, __LINE__, __FUNCTION__, expr)
 
 #define USER(expr ...) \
-	do { \
-		log_printfnl (LOG_USER, __FILE__, __LINE__, __FUNCTION__, expr); \
-	} while(0)
+		log_printf_lf (LOG_USER, __FILE__, __LINE__, __FUNCTION__, expr)
 
-#define USER_SAMELINE(expr ...) \
-	do { \
-		log_printf (LOG_USER, __FILE__, __LINE__, __FUNCTION__, expr); \
-	} while(0)
+#define USER_N(expr ...) \
+		log_printf (LOG_USER, __FILE__, __LINE__, __FUNCTION__, expr)
 
 #define OUTPUT(expr ...) \
-	do { \
-		log_printf (LOG_OUTPUT, __FILE__, __LINE__, __FUNCTION__, expr); \
-	} while(0)
+		log_printf (LOG_OUTPUT, __FILE__, __LINE__, __FUNCTION__, expr)
 
 
 /* general failures
diff --git a/src/helper/options.c b/src/helper/options.c
index 6e1f10b7..35ab0f5d 100644
--- a/src/helper/options.c
+++ b/src/helper/options.c
@@ -48,7 +48,7 @@ static struct option long_options[] =
 
 int configuration_output_handler(struct command_context_s *context, char* line)
 {
-	INFO_SAMELINE(line);
+	INFO_N(line);
 
 	return ERROR_OK;
 }
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index d06c7a07..57ba2806 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -47,7 +47,7 @@ static unsigned short gdb_port;
 static const char *DIGITS = "0123456789abcdef";
 
 static void gdb_log_callback(void *priv, const char *file, int line,
-		const char *function, const char *format, va_list args);
+		const char *function, const char *string);
 
 enum gdb_detach_mode
 {
@@ -504,7 +504,7 @@ int gdb_get_packet(connection_t *connection, char *buffer, int *len)
 	return retval;
 }
 
-int gdb_output_con(connection_t *connection, char* line)
+int gdb_output_con(connection_t *connection, const char* line)
 {
 	char *hex_buffer;
 	int i, bin_size;
@@ -512,6 +512,8 @@ int gdb_output_con(connection_t *connection, char* line)
 	bin_size = strlen(line);
 
 	hex_buffer = malloc(bin_size*2 + 2);
+	if (hex_buffer == NULL)
+		return ERROR_GDB_BUFFER_TOO_SMALL;
 
 	hex_buffer[0] = 'O';
 	for (i=0; i<bin_size; i++)
@@ -527,7 +529,7 @@ int gdb_output_con(connection_t *connection, char* line)
 int gdb_output(struct command_context_s *context, char* line)
 {
 	/* this will be dumped to the log and also sent as an O packet if possible */
-	USER_SAMELINE(line);
+	USER_N(line);
 	return ERROR_OK;
 }
 
@@ -1796,7 +1798,7 @@ int gdb_detach(connection_t *connection, target_t *target)
 }
 
 static void gdb_log_callback(void *priv, const char *file, int line,
-		const char *function, const char *format, va_list args)
+		const char *function, const char *string)
 {
 	connection_t *connection = priv;
 	gdb_connection_t *gdb_con = connection->priv;
@@ -1807,13 +1809,7 @@ static void gdb_log_callback(void *priv, const char *file, int line,
 		return;
 	}
 
-	char *t = alloc_printf(format, args);
-	if (t == NULL)
-		return;
-
-	gdb_output_con(connection, t);
-
-	free(t);
+	gdb_output_con(connection, string);
 }
 
 int gdb_input_inner(connection_t *connection)
diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c
index ea5ec575..e2f0e019 100644
--- a/src/server/telnet_server.c
+++ b/src/server/telnet_server.c
@@ -54,7 +54,7 @@ static char *negotiate =
  * we write to it, we will fail. Subsequent write operations will
  * succeed. Shudder!
  */
-int telnet_write(connection_t *connection, void *data, int len)
+int telnet_write(connection_t *connection, const void *data, int len)
 {
 	telnet_connection_t *t_con = connection->priv;
 	if (t_con->closed)
@@ -75,26 +75,30 @@ int telnet_prompt(connection_t *connection)
 	return telnet_write(connection, t_con->prompt, strlen(t_con->prompt));
 }
 
-int telnet_outputline(connection_t *connection, char* line)
+int telnet_outputline(connection_t *connection, const char *line)
 {
+	int len;
 	
 	/* process lines in buffer */
-	char *p=line;
-	do {
-		char *next = strchr(p, '\n');
+	while (*line) {
+		char *line_end = strchr(line, '\n');
 		
-		if (next)
-			*next++ = 0;
+		if (line_end)
+			len = line_end-line;
+		else
+		    len = strlen(line);
 
-		
-		telnet_write(connection, p, strlen(p));
-		if (next)
+		telnet_write(connection, line, len);
+		if (line_end)
 		{
 			telnet_write(connection, "\r\n\0", 3);
+			line += len+1;
 		}
-
-		p = next;
-	} while (p);
+		else
+		{
+		    line += len;
+		}
+	}
 	
 	return ERROR_OK;
 }
@@ -107,15 +111,10 @@ int telnet_output(struct command_context_s *cmd_ctx, char* line)
 }
 
 void telnet_log_callback(void *priv, const char *file, int line, 
-		const char *function, const char *format, va_list args)
+		const char *function, const char *string)
 {
 	connection_t *connection = priv;
-	char *t = alloc_printf(format, args);
-	if (t == NULL)
-		return;
-	telnet_outputline(connection, t);
-	
-	free(t);
+	telnet_outputline(connection, string);
 }
 
 int telnet_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv)
diff --git a/src/target/target_request.c b/src/target/target_request.c
index 020ee790..e168d944 100644
--- a/src/target/target_request.c
+++ b/src/target/target_request.c
@@ -55,7 +55,7 @@ int target_asciimsg(target_t *target, u32 length)
 
 int target_charmsg(target_t *target, u8 msg)
 {
-	USER_SAMELINE("%c", msg);
+	USER_N("%c", msg);
 	
 	return ERROR_OK;
 }
-- 
cgit v1.2.3