1 /* utility.c Utility functions for Wine
2 * Author: Andrew Bulhak
5 * This unit contains the implementations of
6 * various Windows API functions that perform
7 * utility tasks; i.e., that do not fit into
8 * any major category but perform useful tasks.
17 #include "stackframe.h"
23 /* MulDiv is a simple function that may as well have been
24 * implemented as a macro; however Microsoft, in their infinite
25 * wisdom, have implemented it as a DLL function and therefore
27 * Basically, it takes two 16-bit integers, multiplies them
28 * and divides by a third integer.
31 int MulDiv(int foo
, int bar
, int baz
)
34 if (!baz
) return -32768;
35 ret
= (foo
* bar
) / baz
;
36 if ((ret
> 32767) || (ret
< -32767)) return -32768;
40 /* UTILITY_strip015() removes \015 (^M, CR) from a string;
41 * this is done to convert a MS-DOS-style string to a more
42 * UNIX-friendly format. Replacement is done in-place.
45 void UTILITY_strip015(char *dest
) {
49 while(*src
== '\015') src
++; /* Skip \015s */
50 while((*src
) && (*src
!= '\015')) *(dest
++) = *(src
++);
52 *dest
= '\0'; /* Add null terminator */
55 /**********************************************************************
59 DebugPrintString(char *str
)
61 fprintf(stderr
, "%s\n", str
);
66 * OutputDebugString strips CRs from its (string) parameter and
67 * calls DebugPrintString(), which was written by someone else.
68 * Since this is part of the standard Windows API, it needs no
69 * references to nonstandard DLLs.
72 void OutputDebugString(LPSTR foo
)
74 UTILITY_strip015(foo
);
75 DebugPrintString(foo
);
79 /* UTILITY_qualify(source, dest) takes the format string source and
80 * changes all the parameters to correspond to Linux integer sizes
81 * rather than Windows sizes. For example, it converts %i to %hi
82 * and %lx to %x. No array size checking is done at present.
85 static void UTILITY_qualify(const char *source
, char *dest
)
87 dprintf_utility(stddeb
, "UTILITY_qualify(\"%s\", \"%s\");\n",
89 if(!source
) return; /* Dumbass attack! */
91 /* Find next format code. */
92 while((*source
!= '%') && (*source
)) {
93 *(dest
++) = *(source
++);
95 /* Yeah, I know I shouldn't use gotos.... */
96 if (!(*source
)) goto loop_end
;
98 *(dest
++) = *(source
++);
99 /* Now insert a size qualifier, if needed. */
107 /* We have a 16-bit value here. */
111 /* Here we go 'round the mulberry bush... */
118 /* UTILITY_argsize() evaluates the size of the argument list that
119 * accompanies a vsprintf() or wvsprintf() call.
121 * char *format; printf-style format string.
122 * BOOL windows; if this is TRUE, we assume that ints are
123 * 16 bits in size; otherwise we deal with
126 * size (in bytes) of the arguments that follow the call.
129 size_t UTILITY_argsize(const char *format
, BOOL windows
)
133 #define INT_SIZE (windows ? 2 : 4)
136 while((*format
) && (*format
!= '%')) format
++; /* skip ahead */
139 dprintf_utility(stddeb
, "found:\t\"%%");
140 format
++; /* skip past '%' */
141 /* First skip the flags, field width, etc. */
142 /* First the flags */
143 if ((*format
== '#') || (*format
== '-') || (*format
== '+')
144 || (*format
== ' ')) {
145 dprintf_utility(stddeb
, "%c", *format
);
148 /* Now the field width, etc. */
149 while(isdigit(*format
)) {
150 dprintf_utility(stddeb
, "%c", *format
);
154 dprintf_utility(stddeb
, "%c", *format
);
157 while(isdigit(*format
)) {
158 dprintf_utility(stddeb
, "%c", *format
);
161 /* Now we handle the rest */
162 if((*format
== 'h') || (*format
== 'l') || (*format
== 'L')) {
163 dprintf_utility(stddeb
, "%c", modifier
);
164 modifier
= *(format
++);
166 /* Handle the actual type. */
167 dprintf_utility(stddeb
, "%c\"\n", *format
);
176 size
+= ((modifier
== 'l') ? 4 : INT_SIZE
);
178 case 's': size
+= sizeof(char *); break;
184 /* It doesn't look as if Windows' wvsprintf()
185 supports floating-point arguments. However,
186 I'll leave this code here just in case. */
187 size
+= (modifier
== 'L') ? sizeof(long double) : sizeof(double);
189 case 'p': size
+= sizeof(void *); break;
190 case 'n': size
+= sizeof(int *); break;
195 dprintf_utility(stddeb
, "UTILITY_argsize: returning %i\n", size
);
199 /* UTILITY_convertArgs() creates a 32-bit argument list from a 16-bit list.
200 * This is used to allow wvsprintf() arguments to be fed through
204 * char *fmt; format string
205 * char *winarg; Windows-style arguments
208 * malloc()ed pointer to new argument list. This should
209 * be free()d as soon as it is finished with.
212 char *UTILITY_convertArgs(char *format
, char *winarg
)
214 char *result
= (char *)malloc(UTILITY_argsize(format
, 0));
216 short *wptr
= (short *)winarg
;
217 long *dptr
= (long *)result
;
220 while((*format
) && (*format
!= '%')) format
++; /* skip ahead */
223 dprintf_utility(stddeb
, "found:\t\"%%");
224 format
++; /* skip past '%' */
226 /* First skip the flags, field width, etc. */
227 /* First the flags */
228 if (*format
== '#' || *format
== '-' || *format
== '+'
229 || *format
== ' ') format
++;
231 /* Now the field width, etc. */
232 while (isdigit(*format
)) format
++;
233 if (*format
== '.') format
++;
234 while (isdigit(*format
)) format
++;
236 /* Now we handle the rest */
237 if(*format
== 'h' || *format
== 'l' || *format
== 'L')
238 modifier
= *format
++;
240 /* Handle the actual type. */
241 dprintf_utility(stddeb
, "%c\"\n", *format
);
246 if (modifier
== 'l') {
247 *((int *)rptr
)++ = *((int *)winarg
)++;
249 *((int *)rptr
)++ = *((short *)winarg
)++;
257 if (modifier
== 'l') {
258 *((unsigned int *)rptr
)++ = *((unsigned int *)winarg
)++;
260 *((unsigned int *)rptr
)++ = *((unsigned short *)winarg
)++;
265 case 'n': /* A pointer, is a pointer, is a pointer... */
266 *((char **)rptr
)++ = (char *)PTR_SEG_TO_LIN(*(SEGPTR
*)winarg
);
267 ((SEGPTR
*)winarg
)++;
274 /* It doesn't look as if Windows' wvsprintf()
275 supports floating-point arguments. However,
276 I'll leave this code here just in case. */
278 *((long double *)rptr
)++ = *((long double *)winarg
)++;
280 *((double *)rptr
)++ = *((double *)winarg
)++;
285 for(; (char *)dptr
< rptr
; dptr
++)
286 dprintf_utility( stddeb
, "%08lx ", *dptr
);
287 dprintf_utility( stddeb
, "\n" );
288 for(; (char *)wptr
< winarg
; wptr
++)
289 dprintf_utility( stddeb
, "%04x ", *wptr
);
290 dprintf_utility( stddeb
, "\n" );
295 INT
windows_wsprintf(void)
297 LPSTR lpOutput
, lpFormat
, ptr
;
298 BYTE new_stack
[1024], *stack_ptr
;
301 BYTE
*win_stack
= (BYTE
*)CURRENT_STACK16
->args
;
303 lpOutput
= (LPSTR
) PTR_SEG_TO_LIN(*(DWORD
*)win_stack
);
304 win_stack
+= sizeof(DWORD
);
305 lpFormat
= (LPSTR
) PTR_SEG_TO_LIN(*(DWORD
*)win_stack
);
306 win_stack
+= sizeof(DWORD
);
308 /* create 32-bit stack for libc's vsprintf() */
310 for (ptr
= lpFormat
, stack_ptr
= new_stack
; *ptr
; ptr
++)
312 if (*ptr
!= '%' || *++ptr
== '%')
315 /* skip width/precision */
316 while (*ptr
== '-' || *ptr
== '+' || *ptr
== '.' ||
317 *ptr
== ' ' || isdigit(*ptr
) || *ptr
== '#')
320 /* handle modifier */
321 fLarge
= ((*ptr
== 'l') || (*ptr
== 'L'));
327 *(char**)stack_ptr
= (char *)PTR_SEG_TO_LIN(*(DWORD
*)win_stack
);
328 stack_ptr
+= sizeof(char *);
329 win_stack
+= sizeof(DWORD
);
334 /* windows' wsprintf() %c ignores 0's, we replace 0 with SPACE to make sure
335 that the remaining part of the string isn't ignored by the winapp */
337 if (*(WORD
*)win_stack
)
338 *(DWORD
*)stack_ptr
= *(WORD
*)win_stack
;
340 *(DWORD
*)stack_ptr
= ' ';
341 stack_ptr
+= sizeof(DWORD
);
342 win_stack
+= sizeof(WORD
);
349 *(int*)stack_ptr
= *(INT
*)win_stack
;
350 stack_ptr
+= sizeof(int);
351 win_stack
+= sizeof(INT
);
354 /* else fall through */
360 *(DWORD
*)stack_ptr
= *(DWORD
*)win_stack
;
361 win_stack
+= sizeof(DWORD
);
365 *(DWORD
*)stack_ptr
= *(WORD
*)win_stack
;
366 win_stack
+= sizeof(WORD
);
368 stack_ptr
+= sizeof(DWORD
);
372 *(DWORD
*)stack_ptr
= 0;
373 stack_ptr
+= sizeof(DWORD
);
374 win_stack
+= sizeof(WORD
);
375 fprintf(stderr
, "wsprintf: oops, unknown formattype %c used!\n", *ptr
);
380 return vsprintf(lpOutput
, lpFormat
, new_stack
);
384 /**************************************************************************
385 * wsprintf [USER.420] (not used by relay)
387 int wsprintf(LPSTR lpOutput
, LPSTR lpFormat
, ...)
392 va_start(valist
, lpFormat
);
393 ArgCnt
= vsprintf(lpOutput
, lpFormat
, valist
);
400 /* wvsprintf() is an implementation of vsprintf(). This
401 * implementation converts the arguments to 32-bit integers and
402 * calls the standard library function vsprintf().
404 * Known shortcomings:
405 * wvsprintf() doesn't yet convert the arguments back after
406 * calling vsprintf(), so if Windows implements %n and a
407 * program depends on it, we're in trouble.
410 int wvsprintf(LPSTR buf
, LPSTR format
, LPSTR args
)
415 if(!buf
|| !format
) return 0;
417 /* Convert agruments to 32-bit values */
418 newargs
= UTILITY_convertArgs(format
, args
);
419 result
= vsprintf(buf
, format
, newargs
);