source: trunk/src/win32k/misc/vsprintf.c@ 4773

Last change on this file since 4773 was 4773, checked in by bird, 25 years ago

Corrected fatal error in _strnlen; Test length before accessing the
character point to. This resulted in a fatal Trap 000e when invoked on a
string ending at the page boundrary with an invalid page following.

File size: 10.4 KB
Line 
1/* $Id: vsprintf.c,v 1.5 2000-12-11 06:20:49 bird Exp $
2 *
3 * vsprintf and sprintf
4 *
5 * Copyright (c) 1999 knut st. osmundsen
6 *
7 * Project Odin Software License can be found in LICENSE.TXT
8 *
9 */
10
11/*******************************************************************************
12* Defined Constants *
13*******************************************************************************/
14#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
15#define MAX(a, b) ((a) >= (b) ? (a) : (b))
16#define MIN(a, b) ((a) < (b) ? (a) : (b))
17
18#define NTSF_CAPITAL 0x0001
19#define NTSF_LEFT 0x0002
20#define NTSF_ZEROPAD 0x0004
21#define NTSF_SPECIAL 0x0008
22#define NTSF_VALSIGNED 0x0010
23#define NTSF_PLUS 0x0020
24#define NTSF_BLANK 0x0040
25
26#define INCL_NOAPI
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <os2.h>
32
33#include <stdarg.h>
34
35#include "dev32.h"
36#include "sprintf.h"
37
38
39/*******************************************************************************
40* Internal Functions *
41*******************************************************************************/
42static unsigned _strnlen(const char *psz, unsigned cchMax);
43static int _atoi_skip(const char **ppsz);
44
45
46/**
47 * Read an integer (decimal) and update the string pointer while reading.
48 * Do not support sign values.
49 * @returns Integer value.
50 * @param ppsz Pointer to pointer to string. The string to be converted.
51 */
52static int _atoi_skip(const char **ppsz)
53{
54 int iValue = 0;
55
56 while (ISDIGIT(**ppsz))
57 {
58 iValue *= 10;
59 iValue += **ppsz - '0';
60 (*ppsz)++;
61 }
62
63 return iValue;
64}
65
66
67/**
68 * Finds the length of a string up to cchMax.
69 * @returns Length.
70 * @param psz Pointer to string.
71 * @param cchMax Max length.
72 */
73static unsigned _strnlen(const char *psz, unsigned cchMax)
74{
75 const char *pszC = psz;
76
77 while (cchMax-- > 0 && *psz != '\0')
78 psz++;
79
80 return psz - pszC;
81}
82
83
84/**
85 * Formats a number according to the parameters.
86 * @returns Pointer to next char. (after number)
87 * @param psz Pointer to output string.
88 * @param lValue Value
89 * @param uiBase Number representation base.
90 * @param cchWidth Width
91 * @param cchPrecision Precision.
92 * @param fFlags Flags (NTFS_*).
93 */
94static char * numtostr(char *psz, long lValue, unsigned int uiBase,
95 signed int cchWidth, signed int cchPrecision,
96 unsigned int fFlags
97 )
98{
99 char * achDigits = "0123456789abcdef";
100 int cchValue;
101 unsigned long ul;
102 int i;
103 int j;
104
105#ifdef DEBUG
106 if (uiBase < 2 || uiBase > 16)
107 return NULL;
108#endif
109 if (fFlags & NTSF_CAPITAL)
110 achDigits = "0123456789ABCDEF";
111 if (fFlags & NTSF_LEFT)
112 fFlags &= ~NTSF_ZEROPAD;
113
114 /* determin value length */
115 cchValue = 0;
116 ul = (unsigned long)((fFlags & NTSF_VALSIGNED) && lValue < 0L ? -lValue : lValue);
117 do
118 {
119 cchValue++;
120 ul /= uiBase;
121 } while (ul > 0);
122
123 i = 0;
124 if (fFlags & NTSF_VALSIGNED)
125 {
126 if (lValue < 0)
127 {
128 lValue = -lValue;
129 psz[i++] = '-';
130 }
131 else if (fFlags & (NTSF_PLUS | NTSF_BLANK))
132 psz[i++] = (char)(fFlags & NTSF_PLUS ? '+' : ' ');
133 }
134
135 if (fFlags & NTSF_SPECIAL && (uiBase % 8) == 0)
136 {
137 psz[i++] = '0';
138 if (uiBase == 16)
139 psz[i++] = (char)(fFlags & NTSF_CAPITAL ? 'X' : 'x');
140 }
141
142
143 /* width - only if ZEROPAD */
144 cchWidth -= i + cchValue;
145 if (fFlags & NTSF_ZEROPAD)
146 while (--cchWidth >= 0)
147 {
148 psz[i++] = '0';
149 cchPrecision--;
150 }
151 else if (!(fFlags & NTSF_LEFT) && cchWidth > 0)
152 {
153 for (j = i-1; j >= 0; j--)
154 psz[cchWidth + j] = psz[j];
155 for (j = 0; j < cchWidth; j++)
156 psz[j] = ' ';
157 i += cchWidth;
158 }
159
160 psz += i;
161
162 /* percision */
163 while (--cchPrecision >= cchValue)
164 *psz++ = '0';
165
166 /* write number - not good enough but it works */
167 i = -1;
168 psz += cchValue;
169 do
170 {
171 psz[i--] = achDigits[lValue % uiBase];
172 lValue /= uiBase;
173 } while (lValue > 0);
174
175 /* width if NTSF_LEFT */
176 if (fFlags & NTSF_LEFT)
177 while (--cchWidth >= 0)
178 *psz++ = ' ';
179
180
181 return psz;
182}
183
184
185#pragma info(notrd)
186/**
187 * Partial vsprintf implementation.
188 * @returns number of
189 * @param pszBuffer Output buffer.
190 * @param pszFormat Format string.
191 * @param args Argument list.
192 */
193int vsprintf(char *pszBuffer, const char *pszFormat, va_list args)
194{
195 char *psz = pszBuffer;
196
197 while (*pszFormat != '\0')
198 {
199 if (*pszFormat == '%')
200 {
201 pszFormat++; /* skip '%' */
202 if (*pszFormat == '%') /* '%%'-> '%' */
203 *psz++ = *pszFormat++;
204 else
205 {
206 long lValue;
207 unsigned int fFlags = 0;
208 int cchWidth = -1;
209 int cchPrecision = -1;
210 unsigned int uiBase = 10;
211 char chArgSize;
212
213 /* flags */
214 #pragma info(none)
215 while (1)
216 #pragma info(restore)
217 {
218 switch (*pszFormat++)
219 {
220 case '#': fFlags |= NTSF_SPECIAL; continue;
221 case '-': fFlags |= NTSF_LEFT; continue;
222 case '+': fFlags |= NTSF_PLUS; continue;
223 case ' ': fFlags |= NTSF_BLANK; continue;
224 case '0': fFlags |= NTSF_ZEROPAD; continue;
225 }
226 pszFormat--;
227 break;
228 }
229 /* width */
230 if (ISDIGIT(*pszFormat))
231 cchWidth = _atoi_skip(SSToDS(&pszFormat));
232 else if (*pszFormat == '*')
233 {
234 pszFormat++;
235 cchWidth = va_arg(args, int);
236 if (cchWidth < 0)
237 {
238 cchWidth = -cchWidth;
239 fFlags |= NTSF_LEFT;
240 }
241 }
242
243 /* precision */
244 if (*pszFormat == '.')
245 {
246 pszFormat++;
247 if (ISDIGIT(*pszFormat))
248 cchPrecision = _atoi_skip(SSToDS(&pszFormat));
249 else if (*pszFormat == '*')
250 {
251 pszFormat++;
252 cchPrecision = va_arg(args, int);
253 }
254 if (cchPrecision < 0)
255 cchPrecision = 0;
256 }
257
258 /* argsize */
259 chArgSize = *pszFormat;
260 if (chArgSize != 'l' && chArgSize != 'L' && chArgSize != 'H')
261 chArgSize = 0;
262 else
263 pszFormat++;
264
265 /* type */
266 switch (*pszFormat++)
267 {
268 /* char */
269 case 'c':
270 if (!(fFlags & NTSF_LEFT))
271 while (--cchWidth > 0)
272 *psz++ = ' ';
273
274 *psz++ = va_arg(args, int);
275
276 while (--cchWidth > 0)
277 *psz++ = ' ';
278 continue;
279
280 case 'd': /* signed decimal integer */
281 case 'i':
282 fFlags |= NTSF_VALSIGNED;
283 break;
284
285 case 'o':
286 uiBase = 8;
287 break;
288
289 case 'p':
290 fFlags |= NTSF_SPECIAL; /* Note not standard behaviour (but I like it this way!) */
291 uiBase = 16;
292 break;
293
294 case 's': /* string */
295 {
296 int i;
297 int cchStr;
298 char *pszStr = va_arg(args, char*);
299
300 if (pszStr < (char*)0x10000)
301 pszStr = "<NULL>";
302 cchStr = _strnlen(pszStr, (unsigned)cchPrecision);
303 if (!(fFlags & NTSF_LEFT))
304 while (--cchWidth >= cchStr)
305 *psz++ = ' ';
306 for (i = cchStr; i > 0; i--)
307 *psz++ = *pszStr++;
308
309 while (--cchWidth >= cchStr)
310 *psz++ = ' ';
311 continue;
312 }
313
314 case 'u':
315 uiBase = 10;
316 break;
317
318 case 'x':
319 case 'X':
320 uiBase = 16;
321 break;
322
323 default:
324 continue;
325 }
326 /*-----------------*/
327 /* integer/pointer */
328 /*-----------------*/
329 /* get value */
330 if (pszFormat[-1] == 'p')
331 lValue = (signed long)va_arg(args, char *);
332 else if (chArgSize == 'l')
333 lValue = va_arg(args, signed long);
334 else if (chArgSize == 'h')
335 lValue = va_arg(args, signed short);
336 else
337 lValue = va_arg(args, signed int);
338 psz = numtostr(psz, lValue, uiBase, cchWidth,
339 cchPrecision, fFlags);
340 }
341 }
342 else
343 *psz++ = *pszFormat++;
344 }
345 *psz = '\0';
346
347 return psz - pszBuffer;
348}
349
350
351/**
352 * sprintf - wraps arguments into a vsprintf call.
353 * @returns number of bytes written.
354 * @param pszBuffer Pointer to output buffer.
355 * @param pszFormat Pointer to format string.
356 * @param ... Optional parameters.
357 */
358int sprintf(char *pszBuffer, const char *pszFormat, ...)
359{
360 int cch;
361 va_list arguments;
362
363 va_start(arguments, pszFormat);
364 cch = vsprintf(pszBuffer, pszFormat, arguments);
365 va_end(arguments);
366
367 return cch;
368}
369
Note: See TracBrowser for help on using the repository browser.