Subversion Repositories HelenOS

Rev

Rev 4377 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2006 Josef Cejka
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - 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.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup libc
  30.  * @{
  31.  */
  32. /** @file
  33.  */
  34.  
  35. #include <stdarg.h>
  36. #include <stdio.h>
  37. #include <string.h>
  38. #include <io/printf_core.h>
  39. #include <errno.h>
  40.  
  41. typedef struct {
  42.     size_t size;    /* Total size of the buffer (in bytes) */
  43.     size_t len;     /* Number of already used bytes */
  44.     char *dst;      /* Destination */
  45. } vsnprintf_data_t;
  46.  
  47. /** Write string to given buffer.
  48.  *
  49.  * Write at most data->size plain characters including trailing zero.
  50.  * According to C99, snprintf() has to return number of characters that
  51.  * would have been written if enough space had been available. Hence
  52.  * the return value is not the number of actually printed characters
  53.  * but size of the input string.
  54.  *
  55.  * @param str  Source string to print.
  56.  * @param size Number of plain characters in str.
  57.  * @param data Structure describing destination string, counter
  58.  *             of used space and total string size.
  59.  *
  60.  * @return Number of characters to print (not characters actually
  61.  *         printed).
  62.  *
  63.  */
  64. static int vsnprintf_str_write(const char *str, size_t size, vsnprintf_data_t *data)
  65. {
  66.     size_t left = data->size - data->len;
  67.    
  68.     if (left == 0)
  69.         return ((int) size);
  70.    
  71.     if (left == 1) {
  72.         /* We have only one free byte left in buffer
  73.          * -> store trailing zero
  74.          */
  75.         data->dst[data->size - 1] = 0;
  76.         data->len = data->size;
  77.         return ((int) size);
  78.     }
  79.    
  80.     if (left <= size) {
  81.         /* We do not have enough space for the whole string
  82.          * with the trailing zero => print only a part
  83.          * of string
  84.          */
  85.         size_t index = 0;
  86.        
  87.         while (index < size) {
  88.             wchar_t uc = str_decode(str, &index, size);
  89.            
  90.             if (chr_encode(uc, data->dst, &data->len, data->size - 1) != EOK)
  91.                 break;
  92.         }
  93.        
  94.         /* Put trailing zero at end, but not count it
  95.          * into data->len so it could be rewritten next time
  96.          */
  97.         data->dst[data->len] = 0;
  98.        
  99.         return ((int) size);
  100.     }
  101.    
  102.     /* Buffer is big enought to print the whole string */
  103.     memcpy((void *)(data->dst + data->len), (void *) str, size);
  104.     data->len += size;
  105.    
  106.     /* Put trailing zero at end, but not count it
  107.      * into data->len so it could be rewritten next time
  108.      */
  109.     data->dst[data->len] = 0;
  110.    
  111.     return ((int) size);
  112. }
  113.  
  114. /** Write wide string to given buffer.
  115.  *
  116.  * Write at most data->size plain characters including trailing zero.
  117.  * According to C99, snprintf() has to return number of characters that
  118.  * would have been written if enough space had been available. Hence
  119.  * the return value is not the number of actually printed characters
  120.  * but size of the input string.
  121.  *
  122.  * @param str  Source wide string to print.
  123.  * @param size Number of bytes in str.
  124.  * @param data Structure describing destination string, counter
  125.  *             of used space and total string size.
  126.  *
  127.  * @return Number of wide characters to print (not characters actually
  128.  *         printed).
  129.  *
  130.  */
  131. static int vsnprintf_wstr_write(const wchar_t *str, size_t size, vsnprintf_data_t *data)
  132. {
  133.     size_t index = 0;
  134.    
  135.     while (index < (size / sizeof(wchar_t))) {
  136.         size_t left = data->size - data->len;
  137.        
  138.         if (left == 0)
  139.             return ((int) size);
  140.        
  141.         if (left == 1) {
  142.             /* We have only one free byte left in buffer
  143.              * -> store trailing zero
  144.              */
  145.             data->dst[data->size - 1] = 0;
  146.             data->len = data->size;
  147.             return ((int) size);
  148.         }
  149.        
  150.         if (chr_encode(str[index], data->dst, &data->len, data->size - 1) != EOK)
  151.             break;
  152.        
  153.         index++;
  154.     }
  155.    
  156.     /* Put trailing zero at end, but not count it
  157.      * into data->len so it could be rewritten next time
  158.      */
  159.     data->dst[data->len] = 0;
  160.    
  161.     return ((int) size);
  162. }
  163.  
  164. int vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
  165. {
  166.     vsnprintf_data_t data = {
  167.         size,
  168.         0,
  169.         str
  170.     };
  171.     printf_spec_t ps = {
  172.         (int(*) (const char *, size_t, void *)) vsnprintf_str_write,
  173.         (int(*) (const wchar_t *, size_t, void *)) vsnprintf_wstr_write,
  174.         &data
  175.     };
  176.    
  177.     /* Print 0 at end of string - fix the case that nothing will be printed */
  178.     if (size > 0)
  179.         str[0] = 0;
  180.    
  181.     /* vsnprintf_write ensures that str will be terminated by zero. */
  182.     return printf_core(fmt, &ps, ap);
  183. }
  184.  
  185. /** @}
  186.  */
  187.