Store config file contents in the registry so we only have to load it
[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             /* Go to the next arg */
440             break;
441         case WPR_UNKNOWN:
442             continue;
443         }
444         if (format.flags & WPRINTF_LEFTALIGN)
445             for (i = format.precision; i < format.width; i++, maxlen--)
446                 *p++ = ' ';
447         maxlen -= len;
448     }
449     *p = 0;
450     TRACE("%s\n",buffer);
451     return (maxlen > 1) ? (INT)(p - buffer) : -1;
452 }
453
454
455 /***********************************************************************
456  *           wvsnprintfW   (Not a Windows API)
457  */
458 INT WINAPI wvsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec,
459                             va_list args )
460 {
461     WPRINTF_FORMAT format;
462     LPWSTR p = buffer;
463     UINT i, len;
464     CHAR number[20];
465
466     while (*spec && (maxlen > 1))
467     {
468         if (*spec != '%') { *p++ = *spec++; maxlen--; continue; }
469         spec++;
470         if (*spec == '%') { *p++ = *spec++; maxlen--; continue; }
471         spec += WPRINTF_ParseFormatW( spec, &format );
472         len = WPRINTF_GetLen( &format, args, number, maxlen - 1 );
473         if (!(format.flags & WPRINTF_LEFTALIGN))
474             for (i = format.precision; i < format.width; i++, maxlen--)
475                 *p++ = ' ';
476         switch(format.type)
477         {
478         case WPR_WCHAR:
479             *p = va_arg( args, WCHAR );
480             if (*p != '\0') p++;
481             else if (format.width > 1) *p++ = ' ';
482             else len = 0;
483             break;
484         case WPR_CHAR:
485             *p = (WCHAR)va_arg( args, CHAR );
486             if (*p != '\0') p++;
487             else if (format.width > 1) *p++ = ' ';
488             else len = 0;
489             break;
490         case WPR_STRING:
491             {
492                 LPCSTR ptr = va_arg( args, LPCSTR );
493                 for (i = 0; i < len; i++) *p++ = (WCHAR)*ptr++;
494             }
495             break;
496         case WPR_WSTRING:
497             if (len) memcpy( p, va_arg( args, LPCWSTR ), len * sizeof(WCHAR) );
498             p += len;
499             break;
500         case WPR_HEXA:
501             if ((format.flags & WPRINTF_PREFIX_HEX) && (maxlen > 3))
502             {
503                 *p++ = '0';
504                 *p++ = (format.flags & WPRINTF_UPPER_HEX) ? 'X' : 'x';
505                 maxlen -= 2;
506                 len -= 2;
507             }
508             /* fall through */
509         case WPR_SIGNED:
510         case WPR_UNSIGNED:
511             for (i = len; i < format.precision; i++, maxlen--) *p++ = '0';
512             for (i = 0; i < len; i++) *p++ = (WCHAR)number[i];
513             (void)va_arg( args, INT ); /* Go to the next arg */
514             break;
515         case WPR_UNKNOWN:
516             continue;
517         }
518         if (format.flags & WPRINTF_LEFTALIGN)
519             for (i = format.precision; i < format.width; i++, maxlen--)
520                 *p++ = ' ';
521         maxlen -= len;
522     }
523     *p = 0;
524     return (maxlen > 1) ? (INT)(p - buffer) : -1;
525 }
526
527
528 /***********************************************************************
529  *           wvsprintf16   (USER.421)
530  */
531 INT16 WINAPI wvsprintf16( LPSTR buffer, LPCSTR spec, LPCVOID args )
532 {
533     INT16 res;
534
535     TRACE("for %p got:\n",buffer);
536     res = wvsnprintf16( buffer, 1024, spec, args );
537     return ( res == -1 ) ? 1024 : res;
538 }
539
540
541 /***********************************************************************
542  *           wvsprintfA   (USER32.587)
543  */
544 INT WINAPI wvsprintfA( LPSTR buffer, LPCSTR spec, va_list args )
545 {
546     INT res;
547
548     TRACE("for %p got:\n",buffer);
549     res = wvsnprintfA( buffer, 1024, spec, args );
550     return ( res == -1 ) ? 1024 : res;
551 }
552
553
554 /***********************************************************************
555  *           wvsprintfW   (USER32.588)
556  */
557 INT WINAPI wvsprintfW( LPWSTR buffer, LPCWSTR spec, va_list args )
558 {
559     INT res;
560
561     TRACE("for %p got:\n",buffer);
562         /* FIXME: in w*printfW, */
563         /*        is maximum buffer size 1024-bytes? (or 1024-wchars?) */
564         res = wvsnprintfW( buffer, 1024, spec, args );
565     return ( res == -1 ) ? 1024 : res;
566 }
567
568
569 /***********************************************************************
570  *           wsprintf16   (USER.420)
571  */
572 /* Winelib version */
573 INT16 WINAPIV wsprintf16( LPSTR buffer, LPCSTR spec, ... )
574 {
575     va_list valist;
576     INT16 res;
577
578     TRACE("for %p got:\n",buffer);
579     va_start( valist, spec );
580     /* Note: we call the 32-bit version, because the args are 32-bit */
581     res = (INT16)wvsnprintfA( buffer, 1024, spec, valist );
582     va_end( valist );
583     return ( res == -1 ) ? 1024 : res;
584 }
585
586 /* Emulator version */
587 INT16 WINAPIV WIN16_wsprintf16(void)
588 {
589     VA_LIST16 valist;
590     INT16 res;
591     SEGPTR buffer, spec;
592
593     VA_START16( valist );
594     buffer = VA_ARG16( valist, SEGPTR );
595     spec   = VA_ARG16( valist, SEGPTR );
596     TRACE("got:\n");
597     res = wvsnprintf16( (LPSTR)PTR_SEG_TO_LIN(buffer), 1024,
598                         (LPCSTR)PTR_SEG_TO_LIN(spec), valist );
599     VA_END16( valist );
600     return ( res == -1 ) ? 1024 : res;
601 }
602
603
604 /***********************************************************************
605  *           wsprintfA   (USER32.585)
606  */
607 INT WINAPIV wsprintfA( LPSTR buffer, LPCSTR spec, ... )
608 {
609     va_list valist;
610     INT res;
611
612     TRACE("for %p got:\n",buffer);
613     va_start( valist, spec );
614     res = wvsnprintfA( buffer, 1024, spec, valist );
615     va_end( valist );
616     return ( res == -1 ) ? 1024 : res;
617 }
618
619
620 /***********************************************************************
621  *           wsprintfW   (USER32.586)
622  */
623 INT WINAPIV wsprintfW( LPWSTR buffer, LPCWSTR spec, ... )
624 {
625     va_list valist;
626     INT res;
627
628     TRACE("wsprintfW for %p\n",buffer);
629     va_start( valist, spec );
630     res = wvsnprintfW( buffer, 1024, spec, valist );
631     va_end( valist );
632     return ( res == -1 ) ? 1024 : res;
633 }
634
635
636 /***********************************************************************
637  *           wsnprintfA   (Not a Windows API)
638  */
639 INT WINAPIV wsnprintfA( LPSTR buffer, UINT maxlen, LPCSTR spec, ... )
640 {
641     va_list valist;
642     INT res;
643
644     va_start( valist, spec );
645     res = wvsnprintfA( buffer, maxlen, spec, valist );
646     va_end( valist );
647     return res;
648 }
649
650
651 /***********************************************************************
652  *           wsnprintfW   (Not a Windows API)
653  */
654 INT WINAPIV wsnprintfW( LPWSTR buffer, UINT maxlen, LPCWSTR spec, ... )
655 {
656     va_list valist;
657     INT res;
658
659     va_start( valist, spec );
660     res = wvsnprintfW( buffer, maxlen, spec, valist );
661     va_end( valist );
662     return res;
663 }
664
665 /***********************************************************************
666  *           _DebugOutput                    (KERNEL.328)
667  */
668 void WINAPIV _DebugOutput( void )
669 {
670     VA_LIST16 valist;
671     WORD flags;
672     SEGPTR spec;
673     int i, nSeg = 0;
674     NE_MODULE *pModule;
675     char caller[101], temp[512];
676
677     /* Decode caller address */
678     pModule = NE_GetPtr( CURRENT_STACK16->cs );
679     if ( pModule )
680     {
681         SEGTABLEENTRY *pSeg = NE_SEG_TABLE( pModule );
682         for ( i = 0; i < pModule->seg_count; i++, pSeg++ )
683             if ( GlobalHandleToSel16( pSeg->hSeg ) == CURRENT_STACK16->cs )
684             {
685                 nSeg = i+1;
686                 break;
687             }
688     }
689     if ( nSeg )
690         sprintf( caller, "%s %02X:%04X", NE_MODULE_NAME( pModule ), 
691                                          nSeg, CURRENT_STACK16->ip );
692     else
693         sprintf( caller, "%04X:%04X", CURRENT_STACK16->cs, CURRENT_STACK16->ip );
694
695     /* Build debug message string */
696     VA_START16( valist );
697     flags = VA_ARG16( valist, WORD );
698     spec  = VA_ARG16( valist, SEGPTR );
699     wvsnprintf16( temp, sizeof(temp), (LPCSTR)PTR_SEG_TO_LIN(spec), valist );
700
701     /* Output */
702     DPRINTF( "_DebugOutput: %s %04X %s\n", 
703              caller, flags, debugstr_an(temp, sizeof(temp)) );
704 }
705