~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to strings/my_vsnprintf.c

  • Committer: Stewart Smith
  • Date: 2008-07-09 01:40:54 UTC
  • mfrom: (105 drizzle)
  • mto: This revision was merged to the branch mainline in revision 111.
  • Revision ID: stewart@flamingspork.com-20080709014054-xfgfzirbhqzrzkkj
mergeĀ fromĀ mainline

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
 
 
16
 
#include <my_global.h>
17
 
#include <m_string.h>
18
 
#include <stdarg.h>
19
 
#include <m_ctype.h>
20
 
 
21
 
/*
22
 
  Limited snprintf() implementations
23
 
 
24
 
  SYNOPSIS
25
 
    my_vsnprintf()
26
 
    to          Store result here
27
 
    n           Store up to n-1 characters, followed by an end 0
28
 
    fmt         printf format
29
 
    ap          Arguments
30
 
 
31
 
  IMPLEMENTION:
32
 
    Supports following formats:
33
 
    %#[l]d
34
 
    %#[l]u
35
 
    %#[l]x
36
 
    %#.#b       Local format; note first # is ignored and second is REQUIRED
37
 
    %#.#s       Note first # is ignored
38
 
    
39
 
  RETURN
40
 
    length of result string
41
 
*/
42
 
 
43
 
size_t my_vsnprintf(char *to, size_t n, const char* fmt, va_list ap)
44
 
{
45
 
  char *start=to, *end=to+n-1;
46
 
  size_t length, width;
47
 
  uint pre_zero, have_long;
48
 
 
49
 
  for (; *fmt ; fmt++)
50
 
  {
51
 
    if (*fmt != '%')
52
 
    {
53
 
      if (to == end)                    /* End of buffer */
54
 
        break;
55
 
      *to++= *fmt;                      /* Copy ordinary char */
56
 
      continue;
57
 
    }
58
 
    fmt++;                                      /* skip '%' */
59
 
    /* Read max fill size (only used with %d and %u) */
60
 
    if (*fmt == '-')
61
 
      fmt++;
62
 
    length= width= 0;
63
 
    pre_zero= have_long= 0;
64
 
    if (*fmt == '*')
65
 
    {
66
 
      fmt++;
67
 
      length= va_arg(ap, int);
68
 
    }
69
 
    else
70
 
      for (; my_isdigit(&my_charset_latin1, *fmt); fmt++)
71
 
      {
72
 
        length= length * 10 + (uint)(*fmt - '0');
73
 
        if (!length)
74
 
          pre_zero= 1;                  /* first digit was 0 */
75
 
      }
76
 
    if (*fmt == '.')
77
 
    {
78
 
      fmt++;
79
 
      if (*fmt == '*')
80
 
      {
81
 
        fmt++;
82
 
        width= va_arg(ap, int);
83
 
      }
84
 
      else
85
 
        for (; my_isdigit(&my_charset_latin1, *fmt); fmt++)
86
 
          width= width * 10 + (uint)(*fmt - '0');
87
 
    }
88
 
    else
89
 
      width= ~0;
90
 
    if (*fmt == 'l')
91
 
    {
92
 
      fmt++;
93
 
      have_long= 1;
94
 
    }
95
 
    if (*fmt == 's')                            /* String parameter */
96
 
    {
97
 
      register char *par = va_arg(ap, char *);
98
 
      size_t plen,left_len = (size_t) (end - to) + 1;
99
 
      if (!par) par = (char*)"(null)";
100
 
      plen= (uint) strnlen(par, width);
101
 
      if (left_len <= plen)
102
 
        plen = left_len - 1;
103
 
      to=strnmov(to,par,plen);
104
 
      continue;
105
 
    }
106
 
    else if (*fmt == 'b')                               /* Buffer parameter */
107
 
    {
108
 
      char *par = va_arg(ap, char *);
109
 
      DBUG_ASSERT(to <= end);
110
 
      if (to + abs(width) + 1 > end)
111
 
        width= end - to - 1;  /* sign doesn't matter */
112
 
      memmove(to, par, abs(width));
113
 
      to+= width;
114
 
      continue;
115
 
    }
116
 
    else if (*fmt == 'd' || *fmt == 'u'|| *fmt== 'x')   /* Integer parameter */
117
 
    {
118
 
      register long larg;
119
 
      size_t res_length, to_length;
120
 
      char *store_start= to, *store_end;
121
 
      char buff[32];
122
 
 
123
 
      if ((to_length= (size_t) (end-to)) < 16 || length)
124
 
        store_start= buff;
125
 
      if (have_long)
126
 
        larg = va_arg(ap, long);
127
 
      else
128
 
        if (*fmt == 'd')
129
 
          larg = va_arg(ap, int);
130
 
        else
131
 
          larg= (long) (uint) va_arg(ap, int);
132
 
      if (*fmt == 'd')
133
 
        store_end= int10_to_str(larg, store_start, -10);
134
 
      else
135
 
        if (*fmt== 'u')
136
 
          store_end= int10_to_str(larg, store_start, 10);
137
 
        else
138
 
          store_end= int2str(larg, store_start, 16, 0);
139
 
      if ((res_length= (size_t) (store_end - store_start)) > to_length)
140
 
        break;                                  /* num doesn't fit in output */
141
 
      /* If %#d syntax was used, we have to pre-zero/pre-space the string */
142
 
      if (store_start == buff)
143
 
      {
144
 
        length= min(length, to_length);
145
 
        if (res_length < length)
146
 
        {
147
 
          size_t diff= (length- res_length);
148
 
          bfill(to, diff, pre_zero ? '0' : ' ');
149
 
          to+= diff;
150
 
        }
151
 
        bmove(to, store_start, res_length);
152
 
      }
153
 
      to+= res_length;
154
 
      continue;
155
 
    }
156
 
    else if (*fmt == 'c')                       /* Character parameter */
157
 
    {
158
 
      register int larg;
159
 
      if (to == end)
160
 
        break;
161
 
      larg = va_arg(ap, int);
162
 
      *to++= (char) larg;
163
 
      continue;
164
 
    }
165
 
 
166
 
    /* We come here on '%%', unknown code or too long parameter */
167
 
    if (to == end)
168
 
      break;
169
 
    *to++='%';                          /* % used as % or unknown code */
170
 
  }
171
 
  DBUG_ASSERT(to <= end);
172
 
  *to='\0';                             /* End of errmessage */
173
 
  return (size_t) (to - start);
174
 
}
175
 
 
176
 
 
177
 
size_t my_snprintf(char* to, size_t n, const char* fmt, ...)
178
 
{
179
 
  int result;
180
 
  va_list args;
181
 
  va_start(args,fmt);
182
 
  result= my_vsnprintf(to, n, fmt, args);
183
 
  va_end(args);
184
 
  return result;
185
 
}
186
 
 
187
 
#ifdef MAIN
188
 
#define OVERRUN_SENTRY  250
189
 
static void my_printf(const char * fmt, ...)
190
 
{
191
 
  char buf[33];
192
 
  int n;
193
 
  va_list ar;
194
 
  va_start(ar, fmt);
195
 
  buf[sizeof(buf)-1]=OVERRUN_SENTRY;
196
 
  n = my_vsnprintf(buf, sizeof(buf)-1,fmt, ar);
197
 
  printf(buf);
198
 
  printf("n=%d, strlen=%d\n", n, strlen(buf));
199
 
  if ((uchar) buf[sizeof(buf)-1] != OVERRUN_SENTRY)
200
 
  {
201
 
    fprintf(stderr, "Buffer overrun\n");
202
 
    abort();
203
 
  }
204
 
  va_end(ar);
205
 
}
206
 
 
207
 
 
208
 
int main()
209
 
{
210
 
 
211
 
  my_printf("Hello\n");
212
 
  my_printf("Hello int, %d\n", 1);
213
 
  my_printf("Hello string '%s'\n", "I am a string");
214
 
  my_printf("Hello hack hack hack hack hack hack hack %d\n", 1);
215
 
  my_printf("Hello %d hack  %d\n", 1, 4);
216
 
  my_printf("Hello %d hack hack hack hack hack %d\n", 1, 4);
217
 
  my_printf("Hello '%s' hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh\n", "hack");
218
 
  my_printf("Hello hhhhhhhhhhhhhh %d sssssssssssssss\n", 1);
219
 
  my_printf("Hello  %u\n", 1);
220
 
  my_printf("Hex:   %lx  '%6lx'\n", 32, 65);
221
 
  my_printf("conn %ld to: '%-.64s' user: '%-.32s' host:\
222
 
 `%-.64s' (%-.64s)", 1, 0,0,0,0);
223
 
  return 0;
224
 
}
225
 
#endif