Yahoo Groups archive

Lpc2000

Index last updated: 2026-04-28 23:31 UTC

Message

Re: large code generation with vsprintf

2005-01-28 by tah2k

I couldn't figure out how to get your email, so I will just attach 
it here....Now that I pasted it, its a mess. If you can't resolve 
the linewrap mess, just send me your email address.

/********************************************************************
**********
Filename:		tprintf.h
Description:	The following function is a limited version of 
sprintf(). It is 
				useful for applications where memory 
is limited or code size
				is an issue.
*********************************************************************
**********/

#ifndef TPRINTF_H
#define TPRINTF_H

extern "C" void tprintf(INT8S* buf, const INT8S* format, ...);

#endif

/******************************* End of 
file***********************************/


/********************************************************************
**********
Filename:		tprintf.cpp
Description:	The following function is a limited version of 
sprintf(). It is 
				useful for applications where memory 
is limited or code size
				is an issue.
*********************************************************************
**********/

/////////////////////////////////////////////////////////////////////
//////////
// includes
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include "Typedefs.h"

/////////////////////////////////////////////////////////////////////
//////////
// defines

/////////////////////////////////////////////////////////////////////
//////////
// Static's

/********************************************************************
**********
Name:			numToAscii()
Description:	The following function converts an integer to its 
ASCII 
				representation in a given numeric 
base.
Input:			char* buf: Preallocated storage to place the 
ASCII representation
				unsigned long num: The number to be 
converted to ASCII
				int base: The number base to 
represent the number.
Output:		None
*********************************************************************
**********/
extern "C" void numToAscii(INT8S* buf, INT32U num, INT32S base) {

	static INT8S digits[] = "0123456789ABCDEF";

	INT32U temp;

	if(num == 0L){
		// If the number is 0, just stuf a "0" into the 
buffer
		buf[0] = '0';
		buf[1] = '\0';
	}
	else{
		// Figure out the length necessary of the ASCII 
string representing
		// the number
		for(temp = num; temp > 0; temp /= base)
			buf++;

		// Mark the spot that will be the end of the string
		*buf = '\0';

		// Generate ASCII representation
		for(temp = num; temp > 0; temp /= base)
			*--buf = digits[temp % base];
	}
}

/********************************************************************
**********
Name:			tprintf()
Description:	The following function is a limited version of 
sprintf(). It is 
				useful for applications where memory 
is limited or code size
				is an issue. The syntax implements 
the sprintf() standard argument
				passing. A conversion specification 
looks like:
				% {flags} {field_width} 
{length_modifier} conversion

				where flags=
					'-':	Left justify field
					'0':	Zero padding to 
field width, for d, l, h, and X

				where field_width=
					Number of characters to be 
printed in the field. Field width 
					will be padded with space if 
needed. If given as '*', the
					next argument should be an 
integer holding the field width.

				where length_modifier=
					h: Used before d or X 
conversions to denote a short int
					l: Used before d or X 
conversions to denote a long int

				where conversion=
					d: Write signed decimal 
integer value
					X: Write an unsigned 
hexadecimal (0-9, ABC...) integer value
					c: Write a single character
					s: Write a string

Input:			char* buf: Pointer to a preallocated buffer 
to store formatted
						   output
				const char* format: The printf style 
format string reduced to
								
	the above control fields
				...: Variable length argument list
Output:		None
*********************************************************************
**********/
extern "C" void tprintf(INT8S* buf, const INT8S* format, ...) {

	// Points to each unnamed argument in turn
	va_list argPtr;

	// Value of the pad string
	INT32S pad;
	INT32S clip;

	// Conversion of ASCII to long
	INT32S longVal;

	INT8S* src;
	INT8S* dst;

	// Character used to pad a field appropriately given a width 
argument
	INT8S padChar = ' ';

	// Is the format requesting a zero pad?
	BOOL reqZeroPad = FALSE;

	// Make argPtr point to the first unnamed argument
	va_start(argPtr, format);

	while(*format) {
		// Loop through the entire format string

		if(*format != '%'){
			// If not the start of a conversion 
specification, copy the character
			// literally
			*buf++ = *format++;
		}
		else{
			// Found the start of a conversion 
specification, increment past the
			// "%" and get the field width value
			format++;

			if(*format == '*'){
				// A width specification, an 'int' 
argument from the argument
				// list supplies the value
				pad = va_arg(argPtr, int);
				
				// Increment past the '*'
				format++;
			}
			else{
				if(*format == '-' || (*format >= '0' 
&& *format <= '9')){
					// A width specification 
controlling the minimum number of
					// characters printed. The '-
' specifies left justification.
					pad = atoi(format);

					// A leading zero indicates 
the pad character should be a 
					// '0' instead of a space
					if(*format == '0')
						reqZeroPad = TRUE;

					do{
						// Increment past 
the width specification
						format++;
					}
					while((*format >= '0')&&
(*format <= '9'));
				}
				else
					// No width value was 
specified
					pad = 0;
			}

			// Handle the type
			switch(*format++){
				case 'c':
					// Write a single character. 
Note: `char's are always widened 
					// when they appear in 
variable or unknown argument positions.
					// Obtain a widened char and 
narrow it.
					buf[0] = (char)(va_arg
(argPtr, INT32U));
					buf[1] = '\0';
					break;
				case 's':
					// Write a string
					src = va_arg(argPtr, char*);
					strcpy(buf, src);
					break;
				case 'l':
					// Write a signed decimal 
long integer value

					// Skip the 'd' in '%ld'
					format++;

					// Pop the argument off teh 
list
					longVal = va_arg(argPtr, 
long);

					dst = buf;
					if(longVal<0){
						// Negative number
						*dst++ = '-';
						longVal = -longVal;
					}

					// Convert number to ASCII 
representation
					numToAscii(dst, longVal, 10);

					// Determine pad character
					if(reqZeroPad)
						padChar = '0';

					break;
				case 'h':
					// Write a signed short 
integer value

					// Skip the 'd' in '%ld'
					format++;

					// Pop the argument off teh 
list
					longVal = va_arg(argPtr, 
INT32U);

					dst = buf;
					if(longVal<0){
						// Negative number
						*dst++ = '-';
						longVal = -longVal;
					}

					// Convert number to ASCII 
representation
					numToAscii(dst, longVal, 10);

					// Determine pad character
					if(reqZeroPad)
						padChar = '0';

					break;
				case 'X':
					// Write an unsigned 
hexidecimal (0-9, ABC...) integer value
					longVal = (long)va_arg
(argPtr, int);

					// Convert number to ASCII 
representation
					numToAscii(buf, longVal, 16);

					// Determine pad character
					if(reqZeroPad)
						padChar = '0';

					break;
				case 'd':
					// Write a signed decimal 
integer value
					longVal = (long)va_arg
(argPtr, int);

					dst = buf;
					if(longVal<0){
						// Negative number
						*dst++ = '-';
						longVal = -longVal;
					}

					// Convert number to ASCII 
representation
					numToAscii(dst, longVal, 10);

					break;
				default:
					buf[0] = format[-1];
					buf[1] = '\0';
					break;			
					
			};

			// Fix the padding if the value is too short
			clip = strlen(buf);
			if(pad < 0){
				// Add spaces after the value
				pad = -pad - clip;

				for(buf += clip; pad > 0; pad++)
					*buf++ = padChar;
				buf = '\0';
			}
			else{
				// Add spaces before the value
				pad -= clip;

				if(pad > 0){
					// Width specification is 
greater than string length, therefore
					// pad appropriatly
					
					// Point to the end of the 
destination string
					src = buf + clip;

					// Point to the end of the 
unpadded destination string
					dst = src + pad;

					// Terminate this field
					*dst = '\0';

					while(src > buf)
						// Right justify the 
string within the width specification
						*--dst = *--src;

					while(dst > buf)
						// Fill with spaces 
to the left
						*--dst = padChar;
				}

				buf += strlen(buf);
			}
		}
	}

	// Mark the end of the output strin
	*buf = '\0';

	// Clean up the variable argument list
	va_end(argPtr);
}

/******************************* End of 
file***********************************/






--- In lpc2000@yahoogroups.com, "gene_klein2000" <gene_klein@h...> 
wrote:
> 
> Hoi Tim,
> 
> It would be great if you wanna mail it to me.
> 
> THANKS,
> 
> Gene.
> 
> --- In lpc2000@yahoogroups.com, "tah2k" <tah2k@y...> wrote:
> > 
> > Hi Gene-
> > 
> > I ran into the same problem a few years ago when I was trying to 
use 
> > sprintf in my boot block. It turns out that most of the code is 
> > related to floating point conversions. I wrote my own 'tprintf' 
('t' 
> > for Tim) that does everything except floating point and it is 
very 
> > tight and small. I can email it to you if youlike.
> > 
> > -Tim
> > 
> > --- In lpc2000@yahoogroups.com, "gene_klein2000" 
<gene_klein@h...> 
> > wrote:
> > > 
> > > Hi,
> > > 
> > > I hope someone will help me with the next problem.
> > > 
> > > 
> > > When I'm using vsprintf the code generated by th compiler
> > > grows with about 30kB. 
> > > Can anyone explain what I can to keep the code small and
> > > still be using th vsprintf.
> > > 
> > > I'm using the gnuarm compiler.
> > > 
> > > 
> > > Thanks,
> > > 
> > > Gene

Attachments

Move to quarantaine

This moves the raw source file on disk only. The archive index is not changed automatically, so you still need to run a manual refresh afterward.