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

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