"Fossies" - the Fresh Open Source Software Archive

Member "socat-1.7.3.2/vsnprintf_r.c" (15 Jan 2017, 16232 Bytes) of package /linux/privat/socat-1.7.3.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "vsnprintf_r.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.7.3.1_vs_1.7.3.2.

    1 /* vsnprintf_r.c */
    2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
    3 
    4 /* a reduced but async-signal-safe and thread-safe version of vsnprintf */
    5 
    6 #include "config.h"
    7 
    8 #include <stddef.h> /* ptrdiff_t */
    9 #include <ctype.h>  /* isdigit() */
   10 #include <stdarg.h>
   11 #include <stdlib.h>
   12 #include <errno.h>
   13 #if HAVE_SYSLOG_H
   14 #include <syslog.h>
   15 #endif
   16 #include <sys/utsname.h>
   17 #include <time.h>   /* time_t, strftime() */
   18 #include <sys/time.h>   /* gettimeofday() */
   19 #include <stdio.h>
   20 #include <string.h>
   21 #if HAVE_UNISTD_H
   22 #include <unistd.h>
   23 #endif
   24 
   25 #include "vsnprintf_r.h"
   26 
   27 /* helper functions for vsnprintf_r():
   28    e.g. convert an unsigned long to decimal string.
   29    in: field (must be long enough for all digits and \0
   30        n: length of field in bytes
   31        ulo: the value
   32    returns: the pointer to the result string (need not be ==field)
   33 */
   34 
   35 /* this function converts an unsigned long number to decimal ASCII
   36    it is async signal safe and thread safe
   37    it returns NULL if n==0
   38    it returns NULL if field is too short to hold the result
   39    it returns a pointer to the result string (somewhere within field)
   40    it terminates result with \0
   41  */
   42 static char *_diag_ulong_to_dec(char *field, size_t n, unsigned long ulo) {
   43    char *np = field+n;  /* point to the end */
   44 
   45    if (n == 0)  return NULL;
   46    *--np = '\0';    /* \0 in last char of string */
   47    /* this is not optimal - uses much CPU, but simple to implement */
   48    /*  calculate the result from right to left */
   49    do { if (np==field) return NULL; *--np = '0'+(ulo%10); } while (ulo/=10);
   50    return np;
   51 }
   52 
   53 /* this function converts an unsigned long number to decimal ASCII
   54    and pads it with space or '0' when size and leading0 are set appropriately
   55    it is async signal safe and thread safe
   56    it returns NULL if n==0
   57    it returns NULL if field is too short to hold the result
   58    it returns a pointer to the result string (somewhere within field)
   59    it reduces size to n-1 if it is greater or equal
   60    it terminates result with \0
   61  */
   62 static char *diag_ulong_to_dec(char *field, size_t n, unsigned long ulo, int leading0, int size) {
   63    char *np;
   64    char c;
   65    int i;
   66 
   67    if (n == 0)  return NULL;
   68    np = _diag_ulong_to_dec(field, n, ulo);
   69    if (np == NULL) return np;
   70    if (size) {
   71       if (size >= n)  size = n-1;
   72       if (leading0) {
   73      c = '0';
   74       } else {
   75      c = ' ';
   76       }
   77       i = size - strlen(np);
   78       while (--i >= 0) {
   79      *--np = c;
   80       }
   81    }         
   82    return np;
   83 }
   84 
   85 /* this function converts a signed long number to decimal ASCII  
   86    and pads it with space or '0' when size and leading0 are set appropriately
   87    it is async signal safe and thread safe
   88    it returns NULL if n==0
   89    it returns NULL if field is too short to hold the result
   90    it returns a pointer to the result string (somewhere within field)
   91    it reduces size to n-1 if it is greater or equal
   92    it terminates result with \0
   93  */
   94 /* like diag_ulong_to_dec but signed; fields need also space for '-' */
   95 static char *diag_long_to_dec(char *field, size_t n, long lo, int leading0, int size) {
   96    char *np;
   97    int minus;
   98    unsigned long ulo;
   99    int i;
  100 
  101    if ((minus = (lo < 0))) {
  102       ulo = (~lo)+1;
  103    } else {
  104       ulo = lo;
  105    }
  106    np = _diag_ulong_to_dec(field, n, ulo);
  107    if (np == NULL)  return np;
  108 
  109    if (size) {
  110       if (size >= n)  size = n-1;
  111       i = size - strlen(np);
  112       if (leading0) {
  113      if (minus) --i; 
  114      while (--i >= 0) {
  115         *--np = '0';
  116      }
  117      if (minus)  *--np = '-';
  118       } else {
  119      if (minus)  { *--np = '-'; --i; }
  120      while (--i >= 0) {
  121         *--np = ' ';
  122      }
  123       }
  124    } else {
  125       if (minus)  *--np = '-';
  126    }
  127    return np;
  128 }
  129 
  130 /* this function converts an unsigned long number to hexadecimal ASCII
  131    it is async signal safe and thread safe
  132    it returns NULL if n==0
  133    it returns NULL if field is too short to hold the result
  134    it returns a pointer to the result string (somewhere within field)
  135    it terminates result with \0
  136  */
  137 static char *diag_ulong_to_hex(char *field, size_t n, unsigned long ulo, int leading0, size_t size) {
  138    char *np = field+n;  /* point to the end */
  139    int i;
  140    char c;
  141 
  142    if (n == 0)  return NULL;
  143    *--np = '\0';    /* \0 in last char of string */
  144    /*  calculate the result from right to left */
  145    do { if (np==field) return NULL; i = (ulo&0x0f);
  146       *--np = (i<10?'0':('a'-10))+i; }
  147    while (ulo>>=4);
  148    if (size) {
  149       if (size >= n)  size = n-1;
  150       if (leading0) {
  151      c = '0';
  152       } else {
  153      c = ' ';
  154       }
  155       i = size - strlen(np);
  156       while (--i >= 0) {
  157      *--np = c;
  158       }
  159    }         
  160    return np;
  161 }
  162 
  163 /* this function converts an unsigned long number to octal ASCII
  164    it is async signal safe and thread safe
  165    it returns NULL if n==0
  166    it returns NULL if field is too short to hold the result
  167    it returns a pointer to the result string (somewhere within field)
  168    it terminates result with \0
  169  */
  170 static char *diag_ulong_to_oct(char *field, size_t n, unsigned long ulo, int leading0, size_t size) {
  171    char *np = field+n;  /* point to the end */
  172    int i;
  173    char c;
  174 
  175    if (n == 0)  return NULL;
  176    *--np = '\0';    /* \0 in last char of string */
  177    /* calculate the result from right to left */
  178    do { if (np==field) return NULL;  i = (ulo&0x07); *--np = '0'+i; }
  179    while (ulo>>=3);
  180    if (size) {
  181       if (size >= n)  size = n-1;
  182       if (leading0) {
  183      c = '0';
  184       } else {
  185      c = ' ';
  186       }
  187       i = size - strlen(np);
  188       while (--i >= 0) {
  189      *--np = c;
  190       }
  191    }         
  192    return np;
  193 }
  194 
  195 
  196 #if HAVE_TYPE_LONGLONG
  197 
  198 /* this function converts an unsigned long long number to decimal ASCII
  199    it is async signal safe and thread safe
  200    it returns NULL if n==0
  201    it returns NULL if field is too short to hold the result
  202    it returns a pointer to the result string (somewhere within field)
  203    it terminates result with \0
  204  */
  205 static char *_diag_ulonglong_to_dec(char *field, size_t n, unsigned long long ull) {
  206    char *np = field+n;  /* point to the end */
  207 
  208    if (n == 0)  return NULL;
  209    *--np = '\0';    /* \0 in last char of string */
  210    /* this is not optimal - uses much CPU, but simple to implement */
  211    /* calculate the result from right to left */
  212    do { if (np==field) return NULL; *--np = '0'+(ull%10); } while (ull/=10);
  213    return np;
  214 }
  215 
  216 /* this function converts an unsigned long long number to decimal ASCII
  217    and pads it with space or '0' when size and leading0 are set appropriately
  218    it is async signal safe and thread safe
  219    it returns NULL if n==0
  220    it returns NULL if field is too short to hold the result
  221    it returns a pointer to the result string (somewhere within field)
  222    it reduces size to n-1 if it is greater or equal
  223    it terminates result with \0
  224  */
  225 static char *diag_ulonglong_to_dec(char *field, size_t n, unsigned long long ull, int leading0, int size) {
  226    char *np;
  227    char c;
  228    int i;
  229 
  230    if (n == 0)  return NULL;
  231    np = _diag_ulonglong_to_dec(field, n, ull);
  232    if (size) {
  233       if (size >= n)  size = n-1;
  234       if (leading0) {
  235      c = '0';
  236       } else {
  237      c = ' ';
  238       }
  239       i = size - strlen(np);
  240       while (i-- > 0) {
  241      *--np = c;
  242       }
  243    }         
  244    return np;
  245 }
  246 
  247 /* this function converts a signed long long number to decimal ASCII  
  248    and pads it with space or '0' when size and leading0 are set appropriately
  249    it is async signal safe and thread safe
  250    it returns NULL if n==0
  251    it returns NULL if field is too short to hold the result
  252    it returns a pointer to the result string (somewhere within field)
  253    it reduces size to n-1 if it is greater or equal
  254    it terminates result with \0
  255  */
  256 /* like diag_ulonglong_to_dec but signed; fields need also space for '-' */
  257 static char *diag_longlong_to_dec(char *field, size_t n, long long ll, int leading0, int size) {
  258    char *np;
  259    int minus;
  260    unsigned long ull;
  261    int i;
  262 
  263    if ((minus = (ll < 0))) {
  264       ull = (~ll)+1;
  265    } else {
  266       ull = ll;
  267    }
  268    np = _diag_ulonglong_to_dec(field, n, ull);
  269    if (np == NULL)  return np;
  270 
  271    if (size) {
  272       if (size >= n)  size = n-1;
  273       i = size - strlen(np);
  274       if (leading0) {
  275      if (minus) --i; 
  276      while (--i >= 0) {
  277         *--np = '0';
  278      }
  279      if (minus)  *--np = '-';
  280       } else {
  281      if (minus)  { *--np = '-'; --i; }
  282      while (--i >= 0) {
  283         *--np = ' ';
  284      }
  285       }
  286    }         
  287    return np;
  288 }
  289 
  290 /* this function converts an unsigned long long number to hexadecimal ASCII
  291    it is async signal safe and thread safe
  292    it returns NULL if n==0
  293    it returns NULL if field is too short to hold the result
  294    it returns a pointer to the result string (somewhere within field)
  295    it terminates result with \0
  296  */
  297 static char *diag_ulonglong_to_hex(char *field, size_t n, unsigned long long ull, int leading0, size_t size) {
  298    char *np = field+n;  /* point to the end */
  299    ptrdiff_t i;
  300    char c;
  301 
  302    if (n == 0)  return NULL;
  303    *--np = '\0';    /* \0 in last char of string */
  304    /* calculate the result from right to left */
  305    do { if (np==field) return NULL; i = (ull&0x0f);
  306       *--np = (i<10?'0':('a'-10))+i; }
  307    while (ull>>=4);
  308    if (size) {
  309       if (size >= n)  size = n-1;
  310       if (leading0) {
  311      c = '0';
  312       } else {
  313      c = ' ';
  314       }
  315       i = size - strlen(np);
  316       while (i-- > 0) {
  317      *--np = c;
  318       }
  319    }         
  320    return np;
  321 }
  322 
  323 /* this function converts an unsigned long long number to octal ASCII
  324    it is async signal safe and thread safe
  325    it returns NULL if n==0
  326    it returns NULL if field is too short to hold the result
  327    it returns a pointer to the result string (somewhere within field)
  328    it terminates result with \0
  329  */
  330 static char *diag_ulonglong_to_oct(char *field, size_t n, unsigned long long ull, int leading0, size_t size) {
  331    char *np = field+n;  /* point to the end */
  332    int i;
  333    char c;
  334 
  335    if (n == 0)  return NULL;
  336    *--np = '\0';    /* \0 in last char of string */
  337    /* calculate the result from right to left */
  338    do { if (np==field) return NULL;  i = (ull&0x07); *--np = '0'+i; }
  339    while (ull>>=3);
  340    if (size) {
  341       if (size >= n)  size = n-1;
  342       if (leading0) {
  343      c = '0';
  344       } else {
  345      c = ' ';
  346       }
  347       i = size - strlen(np);
  348       while (--i >= 0) {
  349      *--np = c;
  350       }
  351    }         
  352    return np;
  353 }
  354 
  355 #endif /* HAVE_TYPE_LONGLONG */
  356 
  357 
  358 /* this function is designed as a variant of vsnprintf(3) but async signal safe
  359    and thread safe
  360    it currently only implements a subset of the format directives
  361    returns <0 if an error occurred (no scenario know yet)
  362    returns >=size if output is truncated (conforming to C99 standard)
  363 */
  364 int vsnprintf_r(char *str, size_t size, const char *format, va_list ap) {
  365    size_t i = 0;
  366    char c;
  367    int full = 0;        /* indicate if output buffer full */
  368 
  369    --size;  /* without trailing \0 */
  370    while (c = *format++) {
  371       if (c == '\\') {
  372      
  373       } else if (c == '%') {
  374 #if HAVE_TYPE_LONGLONG
  375 #    define num_buff_len ((sizeof(unsigned long long)*8+2)/3+1) /* hold up to u long long in octal w/ \0 */
  376 #else
  377 #    define num_buff_len ((sizeof(unsigned long)*8+2)/3+1)];    /* hold up to u long in octal w/ \0 */
  378 #endif
  379      char lengthmod = '\0'; /* 'h' 'l' 'L' 'z' */
  380      int leading0 = 0;  /* or 1 */
  381      size_t fsize = 0;  /* size of field */
  382      const char *st;        /* string */
  383      long  lo; unsigned long  ulo;
  384 #if HAVE_TYPE_LONGLONG
  385      long long ll; unsigned long long ull;
  386 #endif
  387      char field[num_buff_len];  /* result of number conversion */
  388      char *np;          /* num pointer */
  389 
  390      c = *format++;
  391      if (c == '\0')  { break; }
  392      
  393      /* flag characters */
  394      switch (c) {
  395      case '0': leading0 = 1;  c = *format++;  break;
  396         /* not handled: '#' '-' ' ' '+' '\'' */
  397      }
  398      if (c == '\0')  { break; }
  399 
  400      /* field width */
  401      switch (c) {
  402      case '1': case '2': case '3': case '4':
  403      case '5': case '6': case '7': case '8': case '9':
  404         do {
  405            fsize = 10*fsize+(c-'0');
  406            c = *format++;
  407         } while (c && isdigit(c));
  408         break;
  409      }
  410      if (c == '\0')  { break; }
  411 
  412      /* precision - not handles */
  413 
  414      /* length modifier */
  415      switch (c) {
  416         /* not handled: 'q' 'j' 't' */
  417         /* handled: 'h' 'hh'->'H' 'z' 'Z'->'z' 'l' 'll'->'L' 'L' */
  418      case 'Z': c = 'z'; /* fall through */
  419 #if HAVE_TYPE_LONGLONG
  420      case 'L':
  421 #endif
  422      case 'z': lengthmod = c; c = *format++; break;
  423      case 'h':
  424         lengthmod = c;
  425         if ((c = *format++) == 'h') {
  426            lengthmod = 'H'; c = *format++; 
  427         }
  428         break;
  429      case 'l': 
  430         lengthmod = c;
  431         if ((c = *format++) == 'l') {
  432            lengthmod = 'L'; c = *format++; 
  433         }
  434         break;
  435      }
  436      if (c == '\0')  { break; }
  437 
  438      /* conversion specifier */
  439      switch (c) {
  440      case 'c': c = va_arg(ap, int); /* fall through */
  441      case '%': *str++ = c; if (++i == size) { full = 1; } break;
  442 
  443      case 's': st = va_arg(ap, const char *);
  444         /* no modifier handled! */
  445         while (c = *st++) {
  446            *str++ = c;
  447            if (++i == size) { full = 1; break; }
  448         }
  449         break;
  450      case 'd':
  451 #if HAVE_TYPE_LONGLONG
  452         if (lengthmod == 'L') {
  453            ll = va_arg(ap, long long);
  454            np = diag_longlong_to_dec(field, num_buff_len, ll, leading0, fsize);
  455            while (c = *np++)  {
  456           *str++ = c;
  457           if (++i == size) { full = 1; break; }
  458            }
  459         } else
  460 #endif
  461         {
  462            switch (lengthmod) {
  463            case 'l': lo = va_arg(ap, long); break;
  464            case 'z': lo = va_arg(ap, ptrdiff_t); break;
  465            default: lo = va_arg(ap, int); break;
  466            }
  467            np = diag_long_to_dec(field, num_buff_len, lo, leading0, fsize);
  468            while (c = *np++)  { *str++ = c;
  469           if (++i == size) { full = 1; break; }
  470            }
  471         }
  472         break;
  473      case 'u':
  474 #if HAVE_TYPE_LONGLONG
  475         if (lengthmod == 'L') {
  476            ull = va_arg(ap, unsigned long long);
  477            np = diag_ulonglong_to_dec(field, num_buff_len, ull, leading0, fsize);
  478            while (c = *np++)  { *str++ = c;
  479           if (++i == size) { full = 1; break; }
  480            }
  481         } else
  482 #endif
  483         {
  484            switch (lengthmod) {
  485            case 'l': ulo = va_arg(ap, unsigned long); break;
  486            case 'z': ulo = va_arg(ap, size_t); break;
  487            default: ulo = va_arg(ap, unsigned int); break;
  488            }
  489            np = diag_ulong_to_dec(field, num_buff_len, ulo, leading0, fsize);
  490            while (c = *np++)  { *str++ = c;
  491           if (++i == size) { full = 1; break; }
  492            }
  493         }
  494         break;
  495      case 'p':
  496         ulo = va_arg(ap, size_t);
  497         np = diag_ulong_to_hex(field, num_buff_len, ulo, leading0, fsize);
  498         *str++ = '0'; if (++i == size) { full = 1; break; }
  499         *str++ = 'x'; if (++i == size) { full = 1; break; }
  500         while (c = *np++)  { *str++ = c;
  501            if (++i == size) { full = 1; break; }
  502         }
  503         break;
  504      case 'x':
  505 #if HAVE_TYPE_LONGLONG
  506         if (lengthmod == 'L') {
  507            ull = va_arg(ap, unsigned long long);
  508            np = diag_ulonglong_to_hex(field, num_buff_len, ull, leading0, fsize);
  509            while (c = *np++)  { *str++ = c;
  510           if (++i == size) { full = 1; break; }
  511            }
  512         } else
  513 #endif
  514         {
  515            switch (lengthmod) {
  516            case 'l': ulo = va_arg(ap, unsigned long); break;
  517            case 'z': ulo = va_arg(ap, size_t); break;
  518            default: ulo = va_arg(ap, unsigned int); break;
  519            }
  520            np = diag_ulong_to_hex(field, num_buff_len, ulo, leading0, fsize);
  521            while (c = *np++)  { *str++ = c;
  522           if (++i == size) { full = 1; break; }
  523            }
  524         }
  525         break;
  526      case 'o':
  527 #if HAVE_TYPE_LONGLONG
  528         if (lengthmod == 'L') {
  529            ull = va_arg(ap, unsigned long long);
  530            np = diag_ulonglong_to_oct(field, num_buff_len, ull, leading0, fsize);
  531            while (c = *np++)  { *str++ = c;
  532           if (++i == size) break;
  533            }
  534         } else
  535 #endif
  536         {
  537            switch (lengthmod) {
  538            case 'l': ulo = va_arg(ap, unsigned long); break;
  539            case 'z': ulo = va_arg(ap, size_t); break;
  540            default: ulo = va_arg(ap, unsigned int); break;
  541            }
  542            np = diag_ulong_to_oct(field, num_buff_len, ulo, leading0, fsize);
  543            while (c = *np++)  { *str++ = c;
  544           if (++i == size) { full = 1; break; }
  545            }
  546         }
  547         break;
  548      default:
  549         *str++ = c;  if (++i == size) { full = 1; break; }
  550      }
  551      if (full)  break;
  552       } else {
  553      *str++ = c;
  554      if (++i == size)  break;
  555       }
  556    }
  557    *str = '\0';
  558    return i;
  559 }
  560 
  561 int snprintf_r(char *str, size_t size, const char *format, ...) {
  562    int result;
  563    va_list ap;
  564    va_start(ap, format);
  565    result = vsnprintf_r(str, size, format, ap);
  566    va_end(ap);
  567    return result;
  568 }
  569