Contiki 2.6

printf.c

00001 /*
00002  * Copyright (c) 2010, Mariano Alvira <mar@devl.org> and other contributors
00003  * to the MC1322x project (http://mc1322x.devl.org)
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. Neither the name of the Institute nor the names of its contributors
00015  *    may be used to endorse or promote products derived from this software
00016  *    without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00019  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00022  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00023  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00024  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00025  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00026  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00027  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * This file is part of libmc1322x: see http://mc1322x.devl.org
00031  * for details. 
00032  *
00033  *
00034  */
00035 
00036 /**
00037  * \file printf-stdarg.c
00038  *
00039  * \brief sprintf functions to replace newlib for AVR32 UC3.
00040  *
00041  * \author $Author: umanzoli $
00042  *
00043  * Created on : 17-mar-2009
00044  *
00045  *
00046  */
00047 
00048 /*
00049  * Copyright 2001, 2002 Georges Menie (www.menie.org)
00050  * stdarg version contributed by Christian Ettinger
00051  *
00052  * This program is free software; you can redistribute it and/or modify
00053  * it under the terms of the GNU Lesser General Public License as published by
00054  * the Free Software Foundation; either version 2 of the License, or
00055  * (at your option) any later version.
00056  *
00057  * This program is distributed in the hope that it will be useful,
00058  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00059  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00060  * GNU Lesser General Public License for more details.
00061  *
00062  * You should have received a copy of the GNU Lesser General Public License
00063  * along with this program; if not, write to the Free Software
00064  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00065  */
00066 
00067 
00068 #include <stdarg.h>
00069 #include <stdbool.h>
00070 #include <string.h>
00071 
00072 #include <mc1322x.h>
00073 #include <stdint.h>
00074 
00075 #define __putc(x) uart1_putc(x)
00076 
00077 /**
00078  * Structure to hold data to be passed to print function with format.
00079  * Aka print context.
00080  */
00081 struct __print_ctx_t
00082 {
00083         //! pointer to next char to be filled.
00084         char*   _ptr;
00085         //! maximum length of the buffer.
00086         size_t  _max_len;
00087 };
00088 typedef struct __print_ctx_t    _print_ctx_t;
00089 
00090 /**
00091  * Pad string to right
00092  */
00093 #define _PRINTFMT_PAD_RIGHT     1
00094 
00095 /**
00096  * Pad the number with zeroes
00097  */
00098 #define _PRINTFMT_PAD_ZERO      2
00099 
00100 /**
00101  * The following should be enough for 32 bit int
00102  */
00103 #define _PRINTFMT_INT_BUF_LEN   12
00104 
00105 /**
00106  * Print a character to stdout (if string is null)
00107  * otherwise, put the character at the end of the provided string.
00108  */
00109 static void __print_char( _print_ctx_t* ctx, char c )
00110 {
00111         if( ctx ) {
00112                 if( c == '\r' || c == '\n' ) {
00113                         if( ctx->_max_len > 1 ) {
00114                                 *(ctx->_ptr)='\r';
00115                                 ctx->_max_len--;
00116                                 ctx->_ptr++;
00117                                 *(ctx->_ptr)='\n';
00118                                 ctx->_max_len--;
00119                                 ctx->_ptr++;
00120                         } else {
00121                                 *(ctx->_ptr)='\n';
00122                                 ctx->_max_len--;
00123                                 ctx->_ptr++;
00124                         }
00125                 } else {
00126                         if( ctx->_max_len ) {
00127                                 *(ctx->_ptr)=c;
00128                                 ctx->_max_len--;
00129                                 ctx->_ptr++;
00130                         }
00131                 }
00132         } else {
00133                 __putc( (uint8_t)c );
00134         }
00135 }
00136 
00137 /**
00138  * Print a string to a given string.
00139  */
00140 static int __print_str( _print_ctx_t* ctx,
00141                         const char *string,
00142                         int width,
00143                         int pad,
00144                         int print_limit,
00145                         bool is_number )
00146 {
00147         int pc = 0;
00148         int padchar = ' ';
00149         int i, len;
00150 
00151         if( width > 0 ) {
00152                 register int len = 0;
00153                 register const char *ptr;
00154                 for( ptr = string; *ptr; ++ptr )
00155                         ++len;
00156                 if( len >= width )
00157                         width = 0;
00158                 else
00159                         width -= len;
00160                 if( pad & _PRINTFMT_PAD_ZERO )
00161                         padchar = '0';
00162         }
00163         if( !( pad & _PRINTFMT_PAD_RIGHT ) ) {
00164                 for( ; width > 0; --width ) {
00165                         __print_char( ctx, padchar );
00166                         ++pc;
00167                 }
00168         }
00169 
00170         // The string to print is not the result of a number conversion to ascii.
00171         if( false == is_number ) {
00172                 // For a string, printlimit is the max number of characters to display.
00173                 for( ; print_limit && *string; ++string, --print_limit ) {
00174                         __print_char( ctx, *string );
00175                         ++pc;
00176                 }
00177         }
00178 
00179         // The string to print represents an integer number.
00180         if( true == is_number ) {
00181                 // In this case, printlimit is the min number of digits to print.
00182 
00183                 // If the length of the number to print is less than the min nb of i
00184                 // digits to display, we add 0 before printing the number.
00185                 len = strlen( string );
00186                 if( len < print_limit ) {
00187                         i = print_limit - len;
00188                         for( ; i; i-- ) {
00189                                 __print_char( ctx, '0' );
00190                                 ++pc;
00191                         }
00192                 }
00193         }
00194 
00195         /*
00196          * Else: The string to print is not the result of a number conversion to ascii.
00197          * For a string, printlimit is the max number of characters to display.
00198          */
00199         for( ; print_limit && *string; ++string, --print_limit ) {
00200                 __print_char( ctx, *string );
00201                 ++pc;
00202         }
00203 
00204         for( ; width > 0; --width ) {
00205                 __print_char( ctx, padchar );
00206                 ++pc;
00207         }
00208 
00209         return pc;
00210 }
00211 
00212 /**
00213  * Print a number to the given string, with the given base.
00214  */
00215 static int __print_int( _print_ctx_t* ctx,
00216                         int i,
00217                         int b,
00218                         int sg,
00219                         int width,
00220                         int pad,
00221                         int letbase,
00222                         int print_limit )
00223 {
00224         char print_buf[_PRINTFMT_INT_BUF_LEN];
00225         register char *s;
00226         register int t, neg = 0, pc = 0;
00227         register unsigned int u = i;
00228 
00229         if( i == 0 ) {
00230                 print_buf[0] = '0';
00231                 print_buf[1] = '\0';
00232                 return __print_str( ctx, print_buf, width, pad, print_limit, true );
00233         }
00234 
00235         if( sg && b == 10 && i < 0 ) {
00236                 neg = 1;
00237                 u = -i;
00238         }
00239 
00240         s = print_buf + _PRINTFMT_INT_BUF_LEN - 1;
00241         *s = '\0';
00242 
00243         while( u ) {
00244                 t = u % b;
00245                 if( t >= 10 )
00246                         t += letbase - '0' - 10;
00247                 *--s = t + '0';
00248                 u /= b;
00249         }
00250 
00251         if( neg ) {
00252                 if( width && ( pad & _PRINTFMT_PAD_ZERO ) ) {
00253                         __print_char( ctx, '-' );
00254                         ++pc;
00255                         --width;
00256                 } else {
00257                         *--s = '-';
00258                 }
00259         }
00260 
00261         return pc + __print_str( ctx, s, width, pad, print_limit, true );
00262 }
00263 /*
00264 #if __GNUC__
00265 int fprintf( __FILE *stream, const char *format, ... )
00266 {
00267         return 0;
00268 }
00269 #endif
00270 */
00271 
00272 /**
00273  * Print the given arguments, with given format onto string out.
00274  */
00275 static int __print_fmt( _print_ctx_t* ctx, const char *format, va_list args )
00276 {
00277         int     width;
00278         int     pad;
00279         int     print_limit;
00280         int     pc = 0;
00281         char    scr[2];
00282 
00283         for( ; *format != 0; ++format ) {
00284                 if( *format == '%' ) {
00285                         ++format;
00286                         width = pad = print_limit = 0;
00287 
00288                         if( *format == '\0' ) {
00289                                 break;
00290                         }
00291 
00292                         if( *format == '%' ) {
00293                                 goto out;
00294                         }
00295 
00296                         if( *format == '-' ) {
00297                                 ++format;
00298                                 pad = _PRINTFMT_PAD_RIGHT;
00299                         }
00300 
00301                         while( *format == '0' ) {
00302                                 ++format;
00303                                 pad |= _PRINTFMT_PAD_ZERO;
00304                         }
00305 
00306                         for( ; *format >= '0' && *format <= '9'; ++format ) {
00307                                 width *= 10;
00308                                 width += *format - '0';
00309                         }
00310 
00311                         if( *format == '.' ) {
00312                                 ++format;
00313                                 for( ; *format >= '0' && *format <= '9'; ++format ) {
00314                                         print_limit *= 10;
00315                                         print_limit += *format - '0';
00316                                 }
00317                         }
00318 
00319                         if( 0 == print_limit ) {
00320                                 print_limit--;
00321                         }
00322 
00323                         if( *format == 'l' ) {
00324                                 ++format;
00325                         }
00326 
00327                         if( *format == 's' ) {
00328                                 register char *s = (char *) va_arg( args, int );
00329                                 pc += __print_str(      ctx,
00330                                                         s ? s : "(null)",
00331                                                         width,
00332                                                         pad,
00333                                                         print_limit,
00334                                                         false );
00335                                 continue;
00336                         }
00337 
00338                         if( *format == 'd' ) {
00339                                 pc += __print_int( ctx, va_arg( args, int ), 10, 1, width, pad, 'a', print_limit );
00340                                 continue;
00341                         }
00342 
00343                         if( ( *format == 'x' ) || ( *format == 'p' ) ) {
00344                                 pc += __print_int( ctx, va_arg( args, int ), 16, 0, width, pad, 'a', print_limit );
00345                                 continue;
00346                         }
00347 
00348                         if( *format == 'X' ) {
00349                                 pc += __print_int( ctx, va_arg( args, int ), 16, 0, width, pad, 'A', print_limit );
00350                                 continue;
00351                         }
00352 
00353                         if( *format == 'u' ) {
00354                                 pc += __print_int( ctx, va_arg( args, int ), 10, 0, width, pad, 'a', print_limit );
00355                                 continue;
00356                         }
00357 
00358                         if( *format == 'c' ) {
00359                                 // char are converted to int then pushed on the stack
00360                                 scr[0] = (char) va_arg( args, int );
00361                                 scr[1] = '\0';
00362                                 pc += __print_str( ctx, scr, width, pad, print_limit, false );
00363                                 continue;
00364                         }
00365                 } else {
00366 out:
00367                         __print_char( ctx, *format );
00368                         ++pc;
00369                 }
00370         }
00371 
00372         if( ctx && ctx->_max_len ) {
00373                 *(ctx->_ptr) = '\0';
00374         }
00375 
00376         return pc;
00377 }
00378 
00379 #define BLOCK_MEM_SIZE 1024
00380 
00381 int sprintf( char *out, const char *format, ... )
00382 {
00383         int             retval = 0;
00384         _print_ctx_t    ctx;
00385         va_list         args;
00386 
00387         ctx._ptr = out;
00388         ctx._max_len = BLOCK_MEM_SIZE;
00389 
00390         va_start( args, format );
00391         retval = __print_fmt( &ctx, format, args );
00392         va_end( args );
00393 
00394         return retval;
00395 }
00396 
00397 int printf( const char *format, ... )
00398 {
00399         int             retval = 0;
00400 //      memory_t*       buf;
00401         va_list         args;
00402 
00403         /*
00404         buf = memory_alloc( 10 );
00405 
00406         if( buf ) {
00407                 _print_ctx_t    ctx;
00408                 ctx._ptr = (char*)buf->_data;
00409                 ctx._max_len = BLOCK_MEM_SIZE;
00410 
00411                 va_start( args, format );
00412                 retval = __print_fmt( &ctx, format, args );
00413                 va_end( args );
00414 
00415                 buf->_len = strlen( (const char*)buf->_data );
00416 
00417 //              LCD_WriteString( ll, buf );
00418                 ll++;
00419                 ll &= 0x03;
00420                 if( uart_task_send( buf ) == false ) {
00421                         memory_free( buf );
00422                 }
00423         }
00424  */
00425 
00426         va_start( args, format );
00427         retval = __print_fmt( NULL, format, args );
00428         va_end( args );
00429 
00430         return retval;
00431 }