jeremiah
 
 
  Joined: 20 Jul 2010 Posts: 1401
  
			
			 
			 
			
			
			
			
			
			
			
  
		  | 
		
			
				| Poor Man's snprintf() | 
			 
			
				 Posted: Thu Mar 12, 2015 2:28 pm     | 
				     | 
			 
			
				
  | 
			 
			
				Below is a quick and dirty way to get a snprintf() method without having to write all the parsing code.  It leverages a CCS extension to work.  It makes use of macros, so always be aware of the dangers there.
 
 
 	  | Code: | 	 		  
 
/******************************************************************************
 
* Name:  snprintf.h
 
* Auth:  Jeremiah
 
* Desc:  This file contains a poor man's implementation of snprintf() for the
 
*        CCS compiler.  It is not meant to be as efficient as a homemade 
 
*        snprintf() method.  It leverages the putc() substitution in printf(),
 
*        which is a CCS extension.
 
*
 
*        FUNCTIONS:
 
*           snprintf()
 
*
 
* Compiled with PCWHD v5.025
 
*
 
* History:
 
* 03/12/2015 - JHB - Creation
 
******************************************************************************/
 
#ifndef SNPRINTF_H
 
#define SNPRINTF_H
 
 
///////////////////////////////////////////////////////////////////////////////
 
// NAME: snprintf()
 
// DESC: Composes a string with the same text that would be printed if fmt 
 
//       was used on printf, but instead of being printed, the content is 
 
//       stored as a string in the buffer pointed by buf (taking max as the 
 
//       maximum buffer capacity to fill).
 
// IN:   buf = Pointer to a buffer where the resulting string is stored
 
//       max = Maximum number of bytes to be used in the buffer.  The
 
//             generated string has a length of max-1, leaving space for a
 
//             null character.  Expects an unsigned int16 > 0.
 
//       fmt = CString that contains a format that follows the same format
 
//             in printf (see printf for details).  This must be a constant
 
//             string (not a variable).
 
//       ... = List of parameters used as inputs to the format string.
 
// OUT:  The number of characters that would have been written if max was
 
//       large enough to hold them.
 
// NOTE: Does not return a negative value for format errors.  However the 
 
//       CCS compiler reports format errors at compile time.
 
///////////////////////////////////////////////////////////////////////////////
 
#define snprintf(buf,max,fmt,...) (       \
 
   snprintf_init(buf,max),                \
 
   printf(snprintf_putc,fmt,__VA_ARGS__), \
 
   snprintf_cleanup(),                    \
 
   g_snprintfNum                          )
 
//Macros that use a comma separated list of statements return the final
 
//statement as if it were a function return value.  Also note that
 
//semicolons are not needed using this method (they are implied)
 
 
///////////////////////////////////////////////////////////////////////////////
 
//****************** Implementation (Do Not Use Directly) *******************//
 
///////////////////////////////////////////////////////////////////////////////
 
static unsigned int16 g_snprintfMax;  //this will decrement with each character
 
static unsigned int16 g_snprintfNum;  //this will increment with each character
 
static char *         g_snprintfBuf;  //holds address of the output buffer
 
 
//function passed to printf() ... CCS option only
 
void snprintf_putc(char c){ 
 
   //only copy the maximum number of allowed characters
 
   if(g_snprintfMax){  
 
      if(--g_snprintfMax){  
 
         g_snprintfBuf[g_snprintfNum] = c;   
 
      }else{ //last spot in the buffer must be a '\0'
 
         g_snprintfBuf[g_snprintfNum] = '\0';  //append a null
 
      }
 
   }
 
   //update this regardless of max so the snprintf() return value is correct.
 
   g_snprintfNum++;
 
}
 
 
//function used to prepare for a new snprintf() call
 
void snprintf_init(char *buf, unsigned int16 max){
 
   g_snprintfMax = max;  
 
   g_snprintfNum = 0;    
 
   g_snprintfBuf = buf;
 
   if(g_snprintfMax){  //only write to it if buffer size non zero
 
      g_snprintfBuf[0] = '\0';
 
   }
 
}
 
 
//function used to finish up buffer with a null if needed.  
 
void snprintf_cleanup(){
 
   //if maximum buffer size was never reached, then null terminate
 
   if(g_snprintfMax){
 
      g_snprintfBuf[g_snprintfNum] = '\0';
 
   }
 
}
 
 
#endif
 
 | 	  
 
 
Test Code  (supply your own FUSES, etc.):
 
 	  | Code: | 	 		  
 
#case
 
#include "pic.h"  //has #device, #FUSES, #use delay(), #use rs232()
 
 
#include "snprintf.h"
 
 
void main(void){
 
   char buffer[15] = {
 
      'z','z','z','z','z',
 
      'z','z','z','z','z',
 
      'z','z','z','z','\0'
 
   };
 
   unsigned int16 i;
 
   unsigned int16 val=255;
 
   
 
   printf("\r\n*********Program Start*********\r\n");
 
   
 
   //Test empty input string
 
   val = snprintf(buffer,sizeof(buffer),"");
 
   printf("BUFFER(%03u,%03u): %s\r\n",sizeof(buffer),val,buffer);
 
   
 
   //Test being under the max
 
   val = snprintf(buffer,sizeof(buffer),"Hello");
 
   //show remaining buffer just for this one to verify algorithm isn't
 
   //overwriting the entire buffer.
 
   printf("BUFFER(%03u,%03u): %s %s\r\n", sizeof(buffer),
 
                                          val,
 
                                          buffer,
 
                                          &buffer[val+1]);
 
   val = snprintf(buffer,sizeof(buffer),"Hello ");
 
   printf("BUFFER(%03u,%03u): %s\r\n",sizeof(buffer),val,buffer);
 
   val = snprintf(buffer,sizeof(buffer),"Hello 7");
 
   printf("BUFFER(%03u,%03u): %s\r\n",sizeof(buffer),val,buffer);
 
   val = snprintf(buffer,sizeof(buffer),"Hello 78");
 
   printf("BUFFER(%03u,%03u): %s\r\n",sizeof(buffer),val,buffer);
 
   val = snprintf(buffer,sizeof(buffer),"Hello 789");
 
   printf("BUFFER(%03u,%03u): %s\r\n",sizeof(buffer),val,buffer);
 
   val = snprintf(buffer,sizeof(buffer),"Hello 789A");
 
   printf("BUFFER(%03u,%03u): %s\r\n",sizeof(buffer),val,buffer);
 
   val = snprintf(buffer,sizeof(buffer),"Hello 789AB");
 
   printf("BUFFER(%03u,%03u): %s\r\n",sizeof(buffer),val,buffer);
 
   val = snprintf(buffer,sizeof(buffer),"Hello 789ABC");
 
   printf("BUFFER(%03u,%03u): %s\r\n",sizeof(buffer),val,buffer);
 
   val = snprintf(buffer,sizeof(buffer),"Hello 789ABCD");
 
   printf("BUFFER(%03u,%03u): %s\r\n",sizeof(buffer),val,buffer);
 
   val = snprintf(buffer,sizeof(buffer),"Hello 789ABCDE");
 
   printf("BUFFER(%03u,%03u): %s\r\n",sizeof(buffer),val,buffer);
 
   val = snprintf(buffer,sizeof(buffer),"Hello 789ABCDEF");
 
   printf("BUFFER(%03u,%03u): %s\r\n",sizeof(buffer),val,buffer);
 
   
 
   //Test exceeding the max.  First loop should print out results from
 
   //previous snprintf() call since buffer max is 0
 
   for(i=0; i<=sizeof(buffer); i++){
 
      val = snprintf(buffer,i,"Hello %d ABCDEFGHIJKLMNOP",78);
 
      printf("BUFFER(%03u,%03u): %s\r\n",i,val,buffer);
 
   }
 
   
 
   while(TRUE);
 
}
 
 
 | 	  
 
 
Expected Output:
 
 	  | Code: | 	 		  
 
*********Program Start*********
 
BUFFER(015,000):
 
BUFFER(015,005): Hello zzzzzzzz
 
BUFFER(015,006): Hello
 
BUFFER(015,007): Hello 7
 
BUFFER(015,008): Hello 78
 
BUFFER(015,009): Hello 789
 
BUFFER(015,010): Hello 789A
 
BUFFER(015,011): Hello 789AB
 
BUFFER(015,012): Hello 789ABC
 
BUFFER(015,013): Hello 789ABCD
 
BUFFER(015,014): Hello 789ABCDE
 
BUFFER(015,015): Hello 789ABCDE
 
BUFFER(000,025): Hello 789ABCDE
 
BUFFER(001,025):
 
BUFFER(002,025): H
 
BUFFER(003,025): He
 
BUFFER(004,025): Hel
 
BUFFER(005,025): Hell
 
BUFFER(006,025): Hello
 
BUFFER(007,025): Hello
 
BUFFER(008,025): Hello 7
 
BUFFER(009,025): Hello 78
 
BUFFER(010,025): Hello 78
 
BUFFER(011,025): Hello 78 A
 
BUFFER(012,025): Hello 78 AB
 
BUFFER(013,025): Hello 78 ABC
 
BUFFER(014,025): Hello 78 ABCD
 
BUFFER(015,025): Hello 78 ABCDE
 
 
 | 	 
  | 
			 
		  |