source: trunk/src/win32k/misc/vprintf.c@ 1535

Last change on this file since 1535 was 1535, checked in by bird, 26 years ago

Updated option/argument handling.
Corrected a few bugs.

File size: 14.8 KB
Line 
1/* $Id: vprintf.c,v 1.3 1999-10-31 23:57:07 bird Exp $
2 *
3 * vprintf and printf
4 *
5 * Copyright (c) 1999 knut st. osmundsen
6 *
7 */
8
9/*******************************************************************************
10* Defined Constants *
11*******************************************************************************/
12#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
13#define MAX(a, b) ((a) >= (b) ? (a) : (b))
14#define MIN(a, b) ((a) < (b) ? (a) : (b))
15
16#define NTSF_CAPITAL 0x0001
17#define NTSF_LEFT 0x0002
18#define NTSF_ZEROPAD 0x0004
19#define NTSF_SPECIAL 0x0008
20#define NTSF_VALSIGNED 0x0010
21#define NTSF_PLUS 0x0020
22#define NTSF_BLANK 0x0040
23
24#define INCL_NOAPI
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#include <os2.h>
30
31#include <stdarg.h>
32
33#include "dev32.h"
34#include "vprintf.h"
35#ifdef RING0
36 #include <builtin.h>
37 #include "options.h"
38 #include "Yield.h"
39#endif
40
41
42/*******************************************************************************
43* Global Variables *
44*******************************************************************************/
45static char chNewLine = '\n';
46static char chReturn = '\r';
47
48/*******************************************************************************
49* Internal Functions *
50*******************************************************************************/
51static int _atoi_skip(const char **ppsz);
52static unsigned _strnlen(const char *psz, unsigned cchMax);
53static void chout(int ch);
54static char * strout(char *psz, signed cchMax);
55
56
57/**
58 * Read an integer (decimal) and update the string pointer while reading.
59 * Do not support sign values.
60 * @returns Integer value.
61 * @param ppsz Pointer to pointer to string. The string to be converted.
62 */
63static int _atoi_skip(const char **ppsz)
64{
65 int iValue = 0;
66
67 while (ISDIGIT(**ppsz))
68 {
69 iValue *= 10;
70 iValue += **ppsz - '0';
71 (*ppsz)++;
72 }
73
74 return iValue;
75}
76
77
78/**
79 * Finds the length of a string up to cchMax.
80 * @returns Length.
81 * @param psz Pointer to string.
82 * @param cchMax Max length.
83 */
84static unsigned _strnlen(const char *psz, unsigned cchMax)
85{
86 const char *pszC = psz;
87
88 while (*psz != '\0' && cchMax-- > 0)
89 psz++;
90
91 return psz - pszC;
92}
93
94
95/**
96 * Formats a number according to the parameters.
97 * @returns Pointer to next char. (after number)
98 * @param psz Pointer to output string.
99 * @param lValue Value
100 * @param uiBase Number representation base.
101 * @param cchWidth Width
102 * @param cchPrecision Precision.
103 * @param fFlags Flags (NTFS_*).
104 */
105static char * numtostr(long lValue, unsigned int uiBase,
106 signed int cchWidth, signed int cchPrecision,
107 unsigned int fFlags
108 )
109{
110 char * achDigits = "0123456789abcdef";
111 int cchValue;
112 unsigned long ul;
113 int i;
114 int j;
115
116#ifdef DEBUG
117 if (uiBase < 2 || uiBase > 16)
118 return NULL;
119#endif
120 if (fFlags & NTSF_CAPITAL)
121 achDigits = "0123456789ABCDEF";
122 if (fFlags & NTSF_LEFT)
123 fFlags &= ~NTSF_ZEROPAD;
124
125 /* determin value length */
126 cchValue = 0;
127 ul = (unsigned long)((fFlags & NTSF_VALSIGNED) && lValue < 0L ? -lValue : lValue);
128 do
129 {
130 cchValue++;
131 ul /= uiBase;
132 } while (ul > 0);
133
134 i = 0;
135 if (fFlags & NTSF_VALSIGNED)
136 {
137 if (lValue < 0)
138 {
139 lValue = -lValue;
140 chout('-');
141 i++;
142 }
143 else if (fFlags & (NTSF_PLUS | NTSF_BLANK))
144 {
145 chout(fFlags & NTSF_PLUS ? '+' : ' ');
146 i++;
147 }
148 }
149
150 if (fFlags & NTSF_SPECIAL && (uiBase % 8) == 0)
151 {
152 chout('0');
153 i++;
154 if (uiBase == 16)
155 {
156 chout(fFlags & NTSF_CAPITAL ? 'X' : 'x');
157 i++;
158 }
159 }
160
161
162 /* width - only if ZEROPAD */
163 cchWidth -= i + cchValue;
164 if (fFlags & NTSF_ZEROPAD)
165 while (--cchWidth >= 0)
166 {
167 chout('0');
168 cchPrecision--;
169 }
170 #if 0
171 else if (!(fFlags & NTSF_LEFT) && cchWidth > 0)
172 { /* not yet supported! */
173 /*
174 for (j = i-1; j >= 0; j--)
175 psz[cchWidth + j] = psz[j];
176 for (j = 0; j < cchWidth; j++)
177 psz[j] = ' ';
178 i += cchWidth;
179 */
180 }
181 #endif
182
183 /* percision */
184 while (--cchPrecision >= cchValue)
185 chout('0');
186
187 ul = 1;
188 for (i = 1; i < cchValue; i++)
189 ul *= uiBase;
190 for (i = 0; i < cchValue; i++)
191 {
192 chout(achDigits[lValue / ul]);
193 lValue %= ul;
194 ul /= uiBase;
195 }
196
197 /* width if NTSF_LEFT */
198 if (fFlags & NTSF_LEFT)
199 while (--cchWidth >= 0)
200 chout(' ');
201
202
203 return NULL;
204}
205
206
207#pragma info(notrd)
208/**
209 * Partial vprintf implementation.
210 * @returns number of
211 * @param pszBuffer Output buffer.
212 * @param pszFormat Format string.
213 * @param args Argument list.
214 */
215int vprintf(const char *pszFormat, va_list args)
216{
217 #ifdef RING0
218 if (!options.fLogging)
219 return 0;
220 #else
221 int cch = 0;
222 #endif
223
224 while (*pszFormat != '\0')
225 {
226 if (*pszFormat == '%')
227 {
228 #ifndef RING0
229 if (cch > 0)
230 {
231 strout((char*)(pszFormat - cch), cch);
232 cch = 0;
233 }
234 #endif
235
236 pszFormat++; /* skip '%' */
237 if (*pszFormat == '%') /* '%%'-> '%' */
238 chout(*pszFormat++);
239 else
240 {
241 long lValue;
242 unsigned int fFlags = 0;
243 int cchWidth = -1;
244 int cchPrecision = -1;
245 unsigned int uiBase = 10;
246 char chArgSize;
247
248 /* flags */
249 #pragma info(none)
250 while (1)
251 #pragma info(restore)
252 {
253 switch (*pszFormat++)
254 {
255 case '#': fFlags |= NTSF_SPECIAL; continue;
256 case '-': fFlags |= NTSF_LEFT; continue;
257 case '+': fFlags |= NTSF_PLUS; continue;
258 case ' ': fFlags |= NTSF_BLANK; continue;
259 case '0': fFlags |= NTSF_ZEROPAD; continue;
260 }
261 pszFormat--;
262 break;
263 }
264 /* width */
265 if (ISDIGIT(*pszFormat))
266 cchWidth = _atoi_skip(SSToDS(&pszFormat));
267 else if (*pszFormat == '*')
268 {
269 pszFormat++;
270 cchWidth = va_arg(args, int);
271 if (cchWidth < 0)
272 {
273 cchWidth = -cchWidth;
274 fFlags |= NTSF_LEFT;
275 }
276 }
277
278 /* precision */
279 if (*pszFormat == '.')
280 {
281 pszFormat++;
282 if (ISDIGIT(*pszFormat))
283 cchPrecision = _atoi_skip(SSToDS(&pszFormat));
284 else if (*pszFormat == '*')
285 {
286 pszFormat++;
287 cchPrecision = va_arg(args, int);
288 }
289 if (cchPrecision < 0)
290 cchPrecision = 0;
291 }
292
293 /* argsize */
294 chArgSize = *pszFormat;
295 if (chArgSize != 'l' && chArgSize != 'L' && chArgSize != 'H')
296 chArgSize = 0;
297 else
298 pszFormat++;
299
300 /* type */
301 switch (*pszFormat++)
302 {
303 /* char */
304 case 'c':
305 if (!(fFlags & NTSF_LEFT))
306 while (--cchWidth > 0)
307 chout(' ');
308
309 chout(va_arg(args, int));
310
311 while (--cchWidth > 0)
312 chout(' ');
313 continue;
314
315 case 'd': /* signed decimal integer */
316 case 'i':
317 fFlags |= NTSF_VALSIGNED;
318 break;
319
320 case 'o':
321 uiBase = 8;
322 break;
323
324 case 'p':
325 fFlags |= NTSF_SPECIAL; /* Note not standard behaviour (but I like it this way!) */
326 uiBase = 16;
327 break;
328
329 case 's': /* string */
330 {
331 int cchStr;
332 char *pszStr = va_arg(args, char*);
333
334 if (pszStr < (char*)0x10000)
335 pszStr = "<NULL>";
336 cchStr = _strnlen(pszStr, (unsigned)cchPrecision);
337 if (!(fFlags & NTSF_LEFT))
338 while (--cchWidth >= cchStr)
339 chout(' ');
340
341 pszStr = strout(pszStr, cchStr);
342
343 while (--cchWidth >= cchStr)
344 chout(' ');
345 continue;
346 }
347
348 case 'u':
349 uiBase = 10;
350 break;
351
352 case 'x':
353 case 'X':
354 uiBase = 16;
355 break;
356
357 default:
358 continue;
359 }
360 /*-----------------*/
361 /* integer/pointer */
362 /*-----------------*/
363 /* get value */
364 if (pszFormat[-1] == 'p')
365 lValue = (signed long)va_arg(args, char *);
366 else if (chArgSize == 'l')
367 lValue = va_arg(args, signed long);
368 else if (chArgSize == 'h')
369 lValue = va_arg(args, signed short);
370 else
371 lValue = va_arg(args, signed int);
372 numtostr(lValue, uiBase, cchWidth, cchPrecision, fFlags);
373 }
374 }
375 else
376 {
377 #ifdef RING0
378 chout(*pszFormat++);
379 #else
380 cch++;
381 pszFormat++;
382 #endif
383 }
384 }
385
386 #ifndef RING0
387 if (cch > 0)
388 {
389 strout((char*)(pszFormat - cch), cch);
390 cch = 0;
391 }
392 #endif
393
394 return 0UL;
395}
396
397/* stub */
398int _vprintfieee(const char *pszFormat, va_list args)
399{
400 return vprintf(pszFormat, args);
401}
402
403
404/**
405 * printf - wraps arguments into a vprintf call.
406 * @returns number of bytes written.
407 * @param pszFormat Pointer to format string.
408 * @param ... Optional parameters.
409 */
410int printf(const char *pszFormat, ...)
411{
412 int cch;
413 va_list arguments;
414
415 #ifdef RING0
416 if (!options.fLogging)
417 return 0;
418 #endif
419
420 va_start(arguments, pszFormat);
421 cch = vprintf(pszFormat, arguments);
422 va_end(arguments);
423
424 return cch;
425}
426
427
428/* stub */
429int _printfieee(const char *pszFormat, ...)
430{
431 int cch;
432 va_list arguments;
433
434 #ifdef RING0
435 if (!options.fLogging)
436 return 0;
437 #endif
438
439 va_start(arguments, pszFormat);
440 cch = vprintf(pszFormat, arguments);
441 va_end(arguments);
442
443 return cch;
444}
445
446/* stub */
447int _printf_ansi(const char *pszFormat, ...)
448{
449 int cch;
450 va_list arguments;
451
452 #ifdef RING0
453 if (!options.fLogging)
454 return 0;
455 #endif
456
457 va_start(arguments, pszFormat);
458 cch = vprintf(pszFormat, arguments);
459 va_end(arguments);
460
461 return cch;
462}
463
464
465
466
467/**
468 * Writes a char to output device.
469 * @param ch Char to write.
470 * @status completely
471 * @author knut st. osmundsen
472 */
473static void chout(int ch)
474{
475 #ifndef RING0
476 ULONG ulWrote;
477 #endif
478
479 if (ch != '\r')
480 {
481 if (ch == '\n')
482 {
483 #ifdef RING0
484 while (!(_inp(options.usCom + 5) & 0x20)); /* Waits for the port to be ready. */
485 _outp(options.usCom, chReturn); /* Put the char. */
486 #else
487 DosWrite(1, (void*)&chReturn, 1, &ulWrote);
488 #endif
489 }
490 #ifdef RING0
491 while (!(_inp(options.usCom + 5) & 0x20)); /* Waits for the port to be ready. */
492 _outp(options.usCom, ch); /* Put the char. */
493 Yield();
494 #else
495 DosWrite(1, (void*)&ch, 1, &ulWrote);
496 #endif
497 }
498}
499
500
501/**
502 * Write a string to the output device.
503 * @returns pointer end of string.
504 * @param psz Pointer to the string to write.
505 * @param cchMax Max count of chars to write. (or until '\0')
506 * @status completely implemented.
507 * @author knut st. osmundsen
508 */
509static char *strout(char *psz, signed cchMax)
510{
511 int cchYield = 0;
512 while (cchMax > 0 && *psz != '\0')
513 {
514 ULONG cch = 0;
515 ULONG ul;
516
517 while (cchMax - cch > 0 && psz[cch] != '\0' && psz[cch] != '\r' && psz[cch] != '\n')
518 cch++;
519
520 /* write string part */
521 #ifdef RING0
522 for (ul = 0; ul < cch; ul++)
523 {
524 while (!(_inp(options.usCom + 5) & 0x20)); /* Waits for the port to be ready. */
525 _outp(options.usCom, psz[ul]); /* Put the char. */
526 }
527 #else
528 DosWrite(1, (void*)psz, cch, &ul);
529 #endif
530
531 /* cr and lf check + skip */
532 if (psz[cch] == '\n' || psz[cch] == '\r')
533 {
534 if (psz[cch] == '\n')
535 {
536 #ifdef RING0
537 while (!(_inp(options.usCom + 5) & 0x20)); /* Waits for the port to be ready. */
538 _outp(options.usCom, chReturn); /* Put the char. */
539 while (!(_inp(options.usCom + 5) & 0x20)); /* Waits for the port to be ready. */
540 _outp(options.usCom, chNewLine); /* Put the char. */
541 cchYield ++;
542 #else
543 DosWrite(1, (void*)&chReturn, 1, &ul);
544 DosWrite(1, (void*)&chNewLine, 1, &ul);
545 #endif
546
547 }
548
549 while (cchMax - cch > 0 && (psz[cch] == '\r' || psz[cch] == '\n'))
550 cch++;
551 }
552
553 /* next */
554 psz += cch;
555 cchMax -= cch;
556 cchYield += cch;
557 if (cchYield > 3)
558 if (Yield())
559 cchYield = 0;
560 }
561 return psz;
562}
563
Note: See TracBrowser for help on using the repository browser.