Contiki 2.5
printf.c
1 /*
2  * Copyright (c) 2010, Mariano Alvira <mar@devl.org> and other contributors
3  * to the MC1322x project (http://mc1322x.devl.org)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the Institute nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * This file is part of libmc1322x: see http://mc1322x.devl.org
31  * for details.
32  *
33  *
34  */
35 
36 /**
37  * \file printf-stdarg.c
38  *
39  * \brief sprintf functions to replace newlib for AVR32 UC3.
40  *
41  * \author $Author: umanzoli $
42  *
43  * Created on : 17-mar-2009
44  *
45  *
46  */
47 
48 /*
49  * Copyright 2001, 2002 Georges Menie (www.menie.org)
50  * stdarg version contributed by Christian Ettinger
51  *
52  * This program is free software; you can redistribute it and/or modify
53  * it under the terms of the GNU Lesser General Public License as published by
54  * the Free Software Foundation; either version 2 of the License, or
55  * (at your option) any later version.
56  *
57  * This program is distributed in the hope that it will be useful,
58  * but WITHOUT ANY WARRANTY; without even the implied warranty of
59  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
60  * GNU Lesser General Public License for more details.
61  *
62  * You should have received a copy of the GNU Lesser General Public License
63  * along with this program; if not, write to the Free Software
64  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
65  */
66 
67 
68 #include <stdarg.h>
69 #include <stdbool.h>
70 #include <string.h>
71 
72 #include <mc1322x.h>
73 #include <stdint.h>
74 
75 #define __putc(x) uart1_putc(x)
76 
77 /**
78  * Structure to hold data to be passed to print function with format.
79  * Aka print context.
80  */
81 struct __print_ctx_t
82 {
83  //! pointer to next char to be filled.
84  char* _ptr;
85  //! maximum length of the buffer.
86  size_t _max_len;
87 };
88 typedef struct __print_ctx_t _print_ctx_t;
89 
90 /**
91  * Pad string to right
92  */
93 #define _PRINTFMT_PAD_RIGHT 1
94 
95 /**
96  * Pad the number with zeroes
97  */
98 #define _PRINTFMT_PAD_ZERO 2
99 
100 /**
101  * The following should be enough for 32 bit int
102  */
103 #define _PRINTFMT_INT_BUF_LEN 12
104 
105 /**
106  * Print a character to stdout (if string is null)
107  * otherwise, put the character at the end of the provided string.
108  */
109 static void __print_char( _print_ctx_t* ctx, char c )
110 {
111  if( ctx ) {
112  if( c == '\r' || c == '\n' ) {
113  if( ctx->_max_len > 1 ) {
114  *(ctx->_ptr)='\r';
115  ctx->_max_len--;
116  ctx->_ptr++;
117  *(ctx->_ptr)='\n';
118  ctx->_max_len--;
119  ctx->_ptr++;
120  } else {
121  *(ctx->_ptr)='\n';
122  ctx->_max_len--;
123  ctx->_ptr++;
124  }
125  } else {
126  if( ctx->_max_len ) {
127  *(ctx->_ptr)=c;
128  ctx->_max_len--;
129  ctx->_ptr++;
130  }
131  }
132  } else {
133  __putc( (uint8_t)c );
134  }
135 }
136 
137 /**
138  * Print a string to a given string.
139  */
140 static int __print_str( _print_ctx_t* ctx,
141  const char *string,
142  int width,
143  int pad,
144  int print_limit,
145  bool is_number )
146 {
147  int pc = 0;
148  int padchar = ' ';
149  int i, len;
150 
151  if( width > 0 ) {
152  register int len = 0;
153  register const char *ptr;
154  for( ptr = string; *ptr; ++ptr )
155  ++len;
156  if( len >= width )
157  width = 0;
158  else
159  width -= len;
160  if( pad & _PRINTFMT_PAD_ZERO )
161  padchar = '0';
162  }
163  if( !( pad & _PRINTFMT_PAD_RIGHT ) ) {
164  for( ; width > 0; --width ) {
165  __print_char( ctx, padchar );
166  ++pc;
167  }
168  }
169 
170  // The string to print is not the result of a number conversion to ascii.
171  if( false == is_number ) {
172  // For a string, printlimit is the max number of characters to display.
173  for( ; print_limit && *string; ++string, --print_limit ) {
174  __print_char( ctx, *string );
175  ++pc;
176  }
177  }
178 
179  // The string to print represents an integer number.
180  if( true == is_number ) {
181  // In this case, printlimit is the min number of digits to print.
182 
183  // If the length of the number to print is less than the min nb of i
184  // digits to display, we add 0 before printing the number.
185  len = strlen( string );
186  if( len < print_limit ) {
187  i = print_limit - len;
188  for( ; i; i-- ) {
189  __print_char( ctx, '0' );
190  ++pc;
191  }
192  }
193  }
194 
195  /*
196  * Else: The string to print is not the result of a number conversion to ascii.
197  * For a string, printlimit is the max number of characters to display.
198  */
199  for( ; print_limit && *string; ++string, --print_limit ) {
200  __print_char( ctx, *string );
201  ++pc;
202  }
203 
204  for( ; width > 0; --width ) {
205  __print_char( ctx, padchar );
206  ++pc;
207  }
208 
209  return pc;
210 }
211 
212 /**
213  * Print a number to the given string, with the given base.
214  */
215 static int __print_int( _print_ctx_t* ctx,
216  int i,
217  int b,
218  int sg,
219  int width,
220  int pad,
221  int letbase,
222  int print_limit )
223 {
224  char print_buf[_PRINTFMT_INT_BUF_LEN];
225  register char *s;
226  register int t, neg = 0, pc = 0;
227  register unsigned int u = i;
228 
229  if( i == 0 ) {
230  print_buf[0] = '0';
231  print_buf[1] = '\0';
232  return __print_str( ctx, print_buf, width, pad, print_limit, true );
233  }
234 
235  if( sg && b == 10 && i < 0 ) {
236  neg = 1;
237  u = -i;
238  }
239 
240  s = print_buf + _PRINTFMT_INT_BUF_LEN - 1;
241  *s = '\0';
242 
243  while( u ) {
244  t = u % b;
245  if( t >= 10 )
246  t += letbase - '0' - 10;
247  *--s = t + '0';
248  u /= b;
249  }
250 
251  if( neg ) {
252  if( width && ( pad & _PRINTFMT_PAD_ZERO ) ) {
253  __print_char( ctx, '-' );
254  ++pc;
255  --width;
256  } else {
257  *--s = '-';
258  }
259  }
260 
261  return pc + __print_str( ctx, s, width, pad, print_limit, true );
262 }
263 /*
264 #if __GNUC__
265 int fprintf( __FILE *stream, const char *format, ... )
266 {
267  return 0;
268 }
269 #endif
270 */
271 
272 /**
273  * Print the given arguments, with given format onto string out.
274  */
275 static int __print_fmt( _print_ctx_t* ctx, const char *format, va_list args )
276 {
277  int width;
278  int pad;
279  int print_limit;
280  int pc = 0;
281  char scr[2];
282 
283  for( ; *format != 0; ++format ) {
284  if( *format == '%' ) {
285  ++format;
286  width = pad = print_limit = 0;
287 
288  if( *format == '\0' ) {
289  break;
290  }
291 
292  if( *format == '%' ) {
293  goto out;
294  }
295 
296  if( *format == '-' ) {
297  ++format;
298  pad = _PRINTFMT_PAD_RIGHT;
299  }
300 
301  while( *format == '0' ) {
302  ++format;
303  pad |= _PRINTFMT_PAD_ZERO;
304  }
305 
306  for( ; *format >= '0' && *format <= '9'; ++format ) {
307  width *= 10;
308  width += *format - '0';
309  }
310 
311  if( *format == '.' ) {
312  ++format;
313  for( ; *format >= '0' && *format <= '9'; ++format ) {
314  print_limit *= 10;
315  print_limit += *format - '0';
316  }
317  }
318 
319  if( 0 == print_limit ) {
320  print_limit--;
321  }
322 
323  if( *format == 'l' ) {
324  ++format;
325  }
326 
327  if( *format == 's' ) {
328  register char *s = (char *) va_arg( args, int );
329  pc += __print_str( ctx,
330  s ? s : "(null)",
331  width,
332  pad,
333  print_limit,
334  false );
335  continue;
336  }
337 
338  if( *format == 'd' ) {
339  pc += __print_int( ctx, va_arg( args, int ), 10, 1, width, pad, 'a', print_limit );
340  continue;
341  }
342 
343  if( ( *format == 'x' ) || ( *format == 'p' ) ) {
344  pc += __print_int( ctx, va_arg( args, int ), 16, 0, width, pad, 'a', print_limit );
345  continue;
346  }
347 
348  if( *format == 'X' ) {
349  pc += __print_int( ctx, va_arg( args, int ), 16, 0, width, pad, 'A', print_limit );
350  continue;
351  }
352 
353  if( *format == 'u' ) {
354  pc += __print_int( ctx, va_arg( args, int ), 10, 0, width, pad, 'a', print_limit );
355  continue;
356  }
357 
358  if( *format == 'c' ) {
359  // char are converted to int then pushed on the stack
360  scr[0] = (char) va_arg( args, int );
361  scr[1] = '\0';
362  pc += __print_str( ctx, scr, width, pad, print_limit, false );
363  continue;
364  }
365  } else {
366 out:
367  __print_char( ctx, *format );
368  ++pc;
369  }
370  }
371 
372  if( ctx && ctx->_max_len ) {
373  *(ctx->_ptr) = '\0';
374  }
375 
376  return pc;
377 }
378 
379 #define BLOCK_MEM_SIZE 1024
380 
381 int sprintf( char *out, const char *format, ... )
382 {
383  int retval = 0;
384  _print_ctx_t ctx;
385  va_list args;
386 
387  ctx._ptr = out;
388  ctx._max_len = BLOCK_MEM_SIZE;
389 
390  va_start( args, format );
391  retval = __print_fmt( &ctx, format, args );
392  va_end( args );
393 
394  return retval;
395 }
396 
397 int printf( const char *format, ... )
398 {
399  int retval = 0;
400 // memory_t* buf;
401  va_list args;
402 
403  /*
404  buf = memory_alloc( 10 );
405 
406  if( buf ) {
407  _print_ctx_t ctx;
408  ctx._ptr = (char*)buf->_data;
409  ctx._max_len = BLOCK_MEM_SIZE;
410 
411  va_start( args, format );
412  retval = __print_fmt( &ctx, format, args );
413  va_end( args );
414 
415  buf->_len = strlen( (const char*)buf->_data );
416 
417 // LCD_WriteString( ll, buf );
418  ll++;
419  ll &= 0x03;
420  if( uart_task_send( buf ) == false ) {
421  memory_free( buf );
422  }
423  }
424  */
425 
426  va_start( args, format );
427  retval = __print_fmt( NULL, format, args );
428  va_end( args );
429 
430  return retval;
431 }