Fixed memory access outside of the range for source bits in 24-bit bitmaps.
[wine] / misc / wsprintf.c
1 /*
2  * wsprintf functions
3  *
4  * Copyright 1996 Alexandre Julliard
5  */
6
7 #include <stdarg.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include "wine/winbase16.h"
11 #include "windef.h"
12 #include "wingdi.h"
13 #include "winuser.h"
14 #include "ldt.h"
15 #include "stackframe.h"
16 #include "module.h"
17 #include "global.h"
18 #include "debugtools.h"
19
20 DEFAULT_DEBUG_CHANNEL(string)
21
22
23 #define WPRINTF_LEFTALIGN   0x0001  /* Align output on the left ('-' prefix) */
24 #define WPRINTF_PREFIX_HEX  0x0002  /* Prefix hex with 0x ('#' prefix) */
25 #define WPRINTF_ZEROPAD     0x0004  /* Pad with zeros ('0' prefix) */
26 #define WPRINTF_LONG        0x0008  /* Long arg ('l' prefix) */
27 #define WPRINTF_SHORT       0x0010  /* Short arg ('h' prefix) */
28 #define WPRINTF_UPPER_HEX   0x0020  /* Upper-case hex ('X' specifier) */
29 #define WPRINTF_WIDE        0x0040  /* Wide arg ('w' prefix) */
30
31 typedef enum
32 {
33     WPR_UNKNOWN,
34     WPR_CHAR,
35     WPR_WCHAR,
36     WPR_STRING,
37     WPR_WSTRING,
38     WPR_SIGNED,
39     WPR_UNSIGNED,
40     WPR_HEXA
41 } WPRINTF_TYPE;
42
43 typedef struct
44 {
45     UINT         flags;
46     UINT         width;
47     UINT         precision;
48     WPRINTF_TYPE   type;
49 } WPRINTF_FORMAT;
50
51 typedef union {
52     WCHAR   wchar_view;
53     CHAR    char_view;
54     LPCSTR  lpcstr_view;
55     LPCWSTR lpcwstr_view;
56     INT     int_view;
57 } WPRINTF_DATA;
58
59 static const CHAR null_stringA[] = "(null)";
60 static const WCHAR null_stringW[] = { '(', 'n', 'u', 'l', 'l', ')', 0 };
61
62 /***********************************************************************
63  *           WPRINTF_ParseFormatA
64  *
65  * Parse a format specification. A format specification has the form:
66  *
67  * [-][#][0][width][.precision]type
68  *
69  * Return value is the length of the format specification in characters.
70  */
71 static INT WPRINTF_ParseFormatA( LPCSTR format, WPRINTF_FORMAT *res )
72 {
73     LPCSTR p = format;
74
75     res->flags = 0;
76     res->width = 0;
77     res->precision = 0;
78     if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
79     if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
80     if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
81     while ((*p >= '0') && (*p <= '9'))  /* width field */
82     {
83         res->width = res->width * 10 + *p - '0';
84         p++;
85     }
86     if (*p == '.')  /* precision field */
87     {
88         p++;
89         while ((*p >= '0') && (*p <= '9'))
90         {
91             res->precision = res->precision * 10 + *p - '0';
92             p++;
93         }
94     }
95     if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
96     else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
97     else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
98     switch(*p)
99     {
100     case 'c':
101         res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
102         break;
103     case 'C':
104         res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
105         break;
106     case 'd':
107     case 'i':
108         res->type = WPR_SIGNED;
109         break;
110     case 's':
111         res->type = (res->flags & (WPRINTF_LONG |WPRINTF_WIDE)) 
112                     ? WPR_WSTRING : WPR_STRING;
113         break;
114     case 'S':
115         res->type = (res->flags & (WPRINTF_SHORT|WPRINTF_WIDE))
116                     ? WPR_STRING : WPR_WSTRING;
117         break;
118     case 'u':
119         res->type = WPR_UNSIGNED;
120         break;
121     case 'X':
122         res->flags |= WPRINTF_UPPER_HEX;
123         /* fall through */
124     case 'x':
125         res->type = WPR_HEXA;
126         break;
127     default: /* unknown format char */
128         res->type = WPR_UNKNOWN;
129         p--;  /* print format as normal char */
130         break;
131     }
132     return (INT)(p - format) + 1;
133 }
134
135
136 /***********************************************************************
137  *           WPRINTF_ParseFormatW
138  *
139  * Parse a format specification. A format specification has the form:
140  *
141  * [-][#][0][width][.precision]type
142  *
143  * Return value is the length of the format specification in characters.
144  */
145 static INT WPRINTF_ParseFormatW( LPCWSTR format, WPRINTF_FORMAT *res )
146 {
147     LPCWSTR p = format;
148
149     res->flags = 0;
150     res->width = 0;
151     res->precision = 0;
152     if (*p == '-') { res->flags |= WPRINTF_LEFTALIGN; p++; }
153     if (*p == '#') { res->flags |= WPRINTF_PREFIX_HEX; p++; }
154     if (*p == '0') { res->flags |= WPRINTF_ZEROPAD; p++; }
155     while ((*p >= '0') && (*p <= '9'))  /* width field */
156     {
157         res->width = res->width * 10 + *p - '0';
158         p++;
159     }
160     if (*p == '.')  /* precision field */
161     {
162         p++;
163         while ((*p >= '0') && (*p <= '9'))
164         {
165             res->precision = res->precision * 10 + *p - '0';
166             p++;
167         }
168     }
169     if (*p == 'l') { res->flags |= WPRINTF_LONG; p++; }
170     else if (*p == 'h') { res->flags |= WPRINTF_SHORT; p++; }
171     else if (*p == 'w') { res->flags |= WPRINTF_WIDE; p++; }
172     switch((CHAR)*p)
173     {
174     case 'c':
175         res->type = (res->flags & WPRINTF_SHORT) ? WPR_CHAR : WPR_WCHAR;
176         break;
177     case 'C':
178         res->type = (res->flags & WPRINTF_LONG) ? WPR_WCHAR : WPR_CHAR;
179         break;
180     case 'd':
181     case 'i':
182         res->type = WPR_SIGNED;
183         break;
184     case 's':
185         res->type = ((res->flags & WPRINTF_SHORT) && !(res->flags & WPRINTF_WIDE)) ? WPR_STRING : WPR_WSTRING;
186         break;
187     case 'S':
188         res->type = (res->flags & (WPRINTF_LONG|WPRINTF_WIDE)) ? WPR_WSTRING : WPR_STRING;
189         break;
190     case 'u':
191         res->type = WPR_UNSIGNED;
192         break;
193     case 'X':
194         res->flags |= WPRINTF_UPPER_HEX;
195         /* fall through */
196     case 'x':
197         res->type = WPR_HEXA;
198         break;
199     default:
200         res->type = WPR_UNKNOWN;
201         p--;  /* print format as normal char */
202         break;
203     }
204     return (INT)(p - format) + 1;
205 }
206
207
208 /***********************************************************************
209  *           WPRINTF_GetLen
210  */
211 static UINT WPRINTF_GetLen( WPRINTF_FORMAT *format, WPRINTF_DATA *arg,
212                               LPSTR number, UINT maxlen )
213 {
214     UINT len;
215
216     if (format->flags & WPRINTF_LEFTALIGN) format->flags &= ~WPRINTF_ZEROPAD;
217     if (format->width > maxlen) format->width = maxlen;
218     switch(format->type)
219     {
220     case WPR_CHAR:
221     case WPR_WCHAR:
222         return (format->precision = 1);
223     case WPR_STRING:
224         if (!arg->lpcstr_view) arg->lpcstr_view = null_stringA;
225         for (len = 0; !format->precision || (len < format->precision); len++)
226             if (!*(arg->lpcstr_view + len)) break;
227         if (len > maxlen) len = maxlen;
228         return (format->precision = len);
229     case WPR_WSTRING:
230         if (!arg->lpcwstr_view) arg->lpcwstr_view = null_stringW;
231         for (len = 0; !format->precision || (len < format->precision); len++)
232             if (!*(arg->lpcwstr_view + len)) break;
233         if (len > maxlen) len = maxlen;
234         return (format->precision = len);
235     case WPR_SIGNED:
236         len = sprintf( number, "%d", arg->int_view );
237         break;
238     case WPR_UNSIGNED:
239         len = sprintf( number, "%u", (UINT)arg->int_view );
240         break;
241     case WPR_HEXA:
242         len = sprintf( number,
243                        (format->flags & WPRINTF_UPPER_HEX) ? "%X" : "%x",
244                        (UINT)arg->int_view);
245         break;
246     default:
247         return 0;
248     }
249     if (len > maxlen) len = maxlen;
250     if (format->precision < len) format->precision = len;
251     if (format->precision > maxlen) format->precision = maxlen;
252     if ((format->flags & WPRINTF_ZEROPAD) && (format->width > format->precision))
253         format->precision = format->width;
254     if (format->flags & WPRINTF_PREFIX_HEX) len += 2;
255     return len;
256 }
257
258 /***********************************************************************
259  *           WPRINTF_ExtractVAPtr (Not a Windows API)
260  */
261 static WPRINTF_DATA WPRINTF_ExtractVAPtr( WPRINTF_FORMAT *format, va_list* args )
262 {
263     WPRINTF_DATA result;
264     switch(format->type)
265     {
266         case WPR_WCHAR:
267             result.wchar_view = va_arg( *args, WCHAR );     break;
268         case WPR_CHAR:
269             result.char_view = va_arg( *args, CHAR );       break;
270         case WPR_STRING:
271             result.lpcstr_view = va_arg( *args, LPCSTR);    break;
272         case WPR_WSTRING:
273             result.lpcwstr_view = va_arg( *args, LPCWSTR);  break;
274         case WPR_HEXA:
275         case WPR_SIGNED:
276         case WPR_UNSIGNED:
277             result.int_view = va_arg( *args, INT );         break;
278         default:
279             result.wchar_view = 0;                          break;
280     }
281     return result;
282 }
283
284 /***********************************************************************
285  *           wvsnprintf16   (Not a Windows API)
286  */
287 INT16 WINAPI wvsnprintf16( LPSTR buffer, UINT16 maxlen, LPCSTR spec,
288                            LPCVOID args )
289 {
290     WPRINTF_FORMAT format;
291     LPSTR p = buffer;
292     UINT i, len;
293     CHAR number[20];
294     WPRINTF_DATA cur_arg;
295     SEGPTR seg_str;
296
297     while (*spec && (maxlen > 1))
298     {
299         if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
300         spec++;
301         if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
302         spec += WPRINTF_ParseFormatA( spec, &format );
303         switch(format.type)
304         {
305         case WPR_WCHAR:  /* No Unicode in Win16 */
306         case WPR_CHAR:
307             cur_arg.char_view = VA_ARG16( args, CHAR );
308             break;
309         case WPR_WSTRING:  /* No Unicode in Win16 */
310         case WPR_STRING:
311             seg_str = VA_ARG16( args, SEGPTR );
312             if (IsBadReadPtr16(seg_str, 1 )) cur_arg.lpcstr_view = "";
313             else cur_arg.lpcstr_view = PTR_SEG_TO_LIN( seg_str );
314             break;
315         case WPR_SIGNED:
316             if (!(format.flags & WPRINTF_LONG))
317             {
318                 cur_arg.int_view = VA_ARG16( args, INT16 );
319                 break;
320             }
321             /* fall through */
322         case WPR_HEXA:
323         case WPR_UNSIGNED:
324             if (format.flags & WPRINTF_LONG)
325                 cur_arg.int_view = VA_ARG16( args, UINT );
326             else
327                 cur_arg.int_view = VA_ARG16( args, UINT16 );
328             break;
329         case WPR_UNKNOWN:
330             continue;
331         }
332         len = WPRINTF_GetLen( &format, &cur_arg, number, maxlen - 1 );
333         if (!(format.flags & WPRINTF_LEFTALIGN))
334             for (i = format.precision; i < format.width; i++, maxlen--)
335                 *p++ = ' ';
336         switch(format.type)
337         {
338         case WPR_WCHAR:  /* No Unicode in Win16 */
339         case WPR_CHAR:
340             *p= cur_arg.char_view;
341             if (*p != '\0') p++;
342             else if (format.width > 1) *p++ = ' ';
343             else len = 0;
344             break;
345         case WPR_WSTRING:  /* No Unicode in Win16 */
346         case WPR_STRING:
347             if (len) memcpy( p, cur_arg.lpcstr_view, len );
348             p += len;
349             break;
350         case WPR_HEXA:
351             if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
352             {
353                 *p++ = '0';
354                 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
355                 maxlen -= 2;
356                 len -= 2;
357             }
358             /* fall through */
359         case WPR_SIGNED:
360         case WPR_UNSIGNED:
361             for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
362             if (len) memcpy( p, number, len );
363             p += len;
364             break;
365         case WPR_UNKNOWN:
366             continue;
367         }
368         if (format.flags & WPRINTF_LEFTALIGN)
369             for (i = format.precision; i < format.width; i++, maxlen--)
370                 *p++ = ' ';
371         maxlen -= len;
372     }
373     *p = 0;
374     return (maxlen > 1) ? (INT)(p - buffer) : -1;
375 }
376
377
378 /***********************************************************************
379  *           wvsnprintfA   (Not a Windows API)
380  */
381 INT WINAPI wvsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec,
382                             va_list args )
383 {
384     WPRINTF_FORMAT format;
385     LPSTR p = buffer;
386     UINT i, len;
387     CHAR number[20];
388     WPRINTF_DATA argData;
389
390     while (*spec && (maxlen > 1))
391     {
392         if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
393         spec++;
394         if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
395         spec += WPRINTF_ParseFormatA( spec, &format );
396         argData = WPRINTF_ExtractVAPtr( &format, &args );
397         len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 );
398         if (!(format.flags & WPRINTF_LEFTALIGN))
399             for (i = format.precision; i < format.width; i++, maxlen--)
400                 *p++ = ' ';
401         switch(format.type)
402         {
403         case WPR_WCHAR:
404             *p = argData.wchar_view;
405             if (*p != '\0') p++;
406             else if (format.width > 1) *p++ = ' ';
407             else len = 0;
408             break;
409         case WPR_CHAR:
410             *p = argData.char_view;
411             if (*p != '\0') p++;
412             else if (format.width > 1) *p++ = ' ';
413             else len = 0;
414             break;
415         case WPR_STRING:
416             memcpy( p, argData.lpcstr_view, len );
417             p += len;
418             break;
419         case WPR_WSTRING:
420             {
421                 LPCWSTR ptr = argData.lpcwstr_view;
422                 for (i = 0; i < len; i++) *p++ = (CHAR)*ptr++;
423             }
424             break;
425         case WPR_HEXA:
426             if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
427             {
428                 *p++ = '0';
429                 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
430                 maxlen -= 2;
431                 len -= 2;
432             }
433             /* fall through */
434         case WPR_SIGNED:
435         case WPR_UNSIGNED:
436             for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
437             memcpy( p, number, len );
438             p += len;
439             break;
440         case WPR_UNKNOWN:
441             continue;
442         }
443         if (format.flags & WPRINTF_LEFTALIGN)
444             for (i = format.precision; i < format.width; i++, maxlen--)
445                 *p++ = ' ';
446         maxlen -= len;
447     }
448     *p = 0;
449     TRACE("%s\n",buffer);
450     return (maxlen > 1) ? (INT)(p - buffer) : -1;
451 }
452
453
454 /***********************************************************************
455  *           wvsnprintfW   (Not a Windows API)
456  */
457 INT WINAPI wvsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec,
458                             va_list args )
459 {
460     WPRINTF_FORMAT format;
461     LPWSTR p = buffer;
462     UINT i, len;
463     CHAR number[20];
464     WPRINTF_DATA argData;
465
466     TRACE("%p %u %s\n", buffer, maxlen, debugstr_w(spec));
467
468     while (*spec && (maxlen > 1))
469     {
470         if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
471         spec++;
472         if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
473         spec += WPRINTF_ParseFormatW( spec, &format );
474         argData = WPRINTF_ExtractVAPtr( &format, &args );
475         len = WPRINTF_GetLen( &format, &argData, number, maxlen - 1 );
476         if (!(format.flags & WPRINTF_LEFTALIGN))
477             for (i = format.precision; i < format.width; i++, maxlen--)
478                 *p++ = ' ';
479         switch(format.type)
480         {
481         case WPR_WCHAR:
482             *p = argData.wchar_view;
483             if (*p != '\0') p++;
484             else if (format.width > 1) *p++ = ' ';
485             else len = 0;
486             break;
487         case WPR_CHAR:
488             *p = argData.char_view;
489             if (*p != '\0') p++;
490             else if (format.width > 1) *p++ = ' ';
491             else len = 0;
492             break;
493         case WPR_STRING:
494             {
495                 LPCSTR ptr = argData.lpcstr_view;
496                 for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++;
497             }
498             break;
499         case WPR_WSTRING:
500             if (len) memcpy( p, argData.lpcwstr_view, len * sizeof(WCHAR) );
501             p += len;
502             break;
503         case WPR_HEXA:
504             if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
505             {
506                 *p++ = '0';
507                 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
508                 maxlen -= 2;
509                 len -= 2;
510             }
511             /* fall through */
512         case WPR_SIGNED:
513         case WPR_UNSIGNED:
514             for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
515             for (i = 0; i < len; i++) *p++ = (WCHAR)number[i];
516             break;
517         case WPR_UNKNOWN:
518             continue;
519         }
520         if (format.flags & WPRINTF_LEFTALIGN)
521             for (i = format.precision; i < format.width; i++, maxlen--)
522                 *p++ = ' ';
523         maxlen -= len;
524     }
525     *p = 0;
526     return (maxlen > 1) ? (INT)(p - buffer) : -1;
527 }
528
529
530 /***********************************************************************
531  *           wvsprintf16   (USER.421)
532  */
533 INT16 WINAPI wvsprintf16( LPSTR buffer, LPCSTR spec, LPCVOID args )
534 {
535     INT16 res;
536
537     TRACE("for %p got:\n",buffer);
538     res = wvsnprintf16( buffer, 1024, spec, args );
539     return ( res == -1 ) ? 1024 : res;
540 }
541
542
543 /***********************************************************************
544  *           wvsprintfA   (USER32.587)
545  */
546 INT WINAPI wvsprintfA( LPSTR buffer, LPCSTR spec, va_list args )
547 {
548     INT res;
549
550     TRACE("for %p got:\n",buffer);
551     res = wvsnprintfA( buffer, 1024, spec, args );
552     return ( res == -1 ) ? 1024 : res;
553 }
554
555
556 /***********************************************************************
557  *           wvsprintfW   (USER32.588)
558  */
559 INT WINAPI wvsprintfW( LPWSTR buffer, LPCWSTR spec, va_list args )
560 {
561     INT res;
562
563     TRACE("for %p got:\n",buffer);
564         /* FIXME: in w*printfW, */
565         /*        is maximum buffer size 1024-bytes? (or 1024-wchars?) */
566         res = wvsnprintfW( buffer, 1024, spec, args );
567     return ( res == -1 ) ? 1024 : res;
568 }
569
570
571 /***********************************************************************
572  *           wsprintf16   (USER.420)
573  */
574 /* Winelib version */
575 INT16 WINAPIV wsprintf16( LPSTR buffer, LPCSTR spec, ... )
576 {
577     va_list valist;
578     INT16 res;
579
580     TRACE("for %p got:\n",buffer);
581     va_start( valist, spec );
582     /* Note: we call the 32-bit version, because the args are 32-bit */
583     res = (INT16)wvsnprintfA( buffer, 1024, spec, valist );
584     va_end( valist );
585     return ( res == -1 ) ? 1024 : res;
586 }
587
588 /* Emulator version */
589 INT16 WINAPIV WIN16_wsprintf16(void)
590 {
591     VA_LIST16 valist;
592     INT16 res;
593     SEGPTR buffer, spec;
594
595     VA_START16( valist );
596     buffer = VA_ARG16( valist, SEGPTR );
597     spec   = VA_ARG16( valist, SEGPTR );
598     TRACE("got:\n");
599     res = wvsnprintf16( (LPSTR)PTR_SEG_TO_LIN(buffer), 1024,
600                         (LPCSTR)PTR_SEG_TO_LIN(spec), valist );
601     VA_END16( valist );
602     return ( res == -1 ) ? 1024 : res;
603 }
604
605
606 /***********************************************************************
607  *           wsprintfA   (USER32.585)
608  */
609 INT WINAPIV wsprintfA( LPSTR buffer, LPCSTR spec, ... )
610 {
611     va_list valist;
612     INT res;
613
614     TRACE("for %p got:\n",buffer);
615     va_start( valist, spec );
616     res = wvsnprintfA( buffer, 1024, spec, valist );
617     va_end( valist );
618     return ( res == -1 ) ? 1024 : res;
619 }
620
621
622 /***********************************************************************
623  *           wsprintfW   (USER32.586)
624  */
625 INT WINAPIV wsprintfW( LPWSTR buffer, LPCWSTR spec, ... )
626 {
627     va_list valist;
628     INT res;
629
630     TRACE("wsprintfW for %p\n",buffer);
631     va_start( valist, spec );
632     res = wvsnprintfW( buffer, 1024, spec, valist );
633     va_end( valist );
634     return ( res == -1 ) ? 1024 : res;
635 }
636
637
638 /***********************************************************************
639  *           wsnprintfA   (Not a Windows API)
640  */
641 INT WINAPIV wsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec, ... )
642 {
643     va_list valist;
644     INT res;
645
646     va_start( valist, spec );
647     res = wvsnprintfA( buffer, maxlen, spec, valist );
648     va_end( valist );
649     return res;
650 }
651
652
653 /***********************************************************************
654  *           wsnprintfW   (Not a Windows API)
655  */
656 INT WINAPIV wsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec, ... )
657 {
658     va_list valist;
659     INT res;
660
661     va_start( valist, spec );
662     res = wvsnprintfW( buffer, maxlen, spec, valist );
663     va_end( valist );
664     return res;
665 }
666
667 /***********************************************************************
668  *           _DebugOutput                    (KERNEL.328)
669  */
670 void WINAPIV _DebugOutput( void )
671 {
672     VA_LIST16 valist;
673     WORD flags;
674     SEGPTR spec;
675     int i, nSeg = 0;
676     NE_MODULE *pModule;
677     char caller[101], temp[512];
678
679     /* Decode caller address */
680     pModule = NE_GetPtr( CURRENT_STACK16->cs );
681     if ( pModule )
682     {
683         SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule );
684         for ( i = 0; i < pModule->seg_count; i++, pSeg++ )
685             if ( GlobalHandleToSel16( pSeg->hSeg ) == CURRENT_STACK16->cs )
686             {
687                 nSeg = i+1;
688                 break;
689             }
690     }
691     if ( nSeg )
692         sprintf( caller, "%s %02X:%04X", NE_MODULE_NAME( pModule ), 
693                                          nSeg, CURRENT_STACK16->ip );
694     else
695         sprintf( caller, "%04X:%04X", CURRENT_STACK16->cs, CURRENT_STACK16->ip );
696
697     /* Build debug message string */
698     VA_START16( valist );
699     flags = VA_ARG16( valist, WORD );
700     spec  = VA_ARG16( valist, SEGPTR );
701     wvsnprintf16( temp, sizeof(temp), (LPCSTR)PTR_SEG_TO_LIN(spec), valist );
702
703     /* Output */
704     DPRINTF( "_DebugOutput: %s %04X %s\n", 
705              caller, flags, debugstr_an(temp, sizeof(temp)) );
706 }
707