Release 951226
[wine/gsoc-2012-control.git] / windows / utility.c
blobd0cb29948a154b8108a0dc024c2f911c4a79f839
1 /* utility.c Utility functions for Wine
2 * Author: Andrew Bulhak
3 * Commenced: 10-9-1993
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.
9 */
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <ctype.h>
14 #include <stdlib.h>
15 #include "windows.h"
16 #include "ldt.h"
17 #include "stackframe.h"
18 #include "stddebug.h"
19 #include "debug.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
26 * so should we.
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)
33 int ret;
34 if (!baz) return -32768;
35 ret = (foo * bar) / baz;
36 if ((ret > 32767) || (ret < -32767)) return -32768;
37 return ret;
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) {
46 char *src = dest;
48 while(*src) {
49 while(*src == '\015') src++; /* Skip \015s */
50 while((*src) && (*src != '\015')) *(dest++) = *(src++);
52 *dest = '\0'; /* Add null terminator */
55 /**********************************************************************
56 * DebugPrintString
58 int
59 DebugPrintString(char *str)
61 fprintf(stderr, "%s\n", str);
62 return 0;
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);
78 #if 0
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",
88 source, dest);
89 if(!source) return; /* Dumbass attack! */
90 while(*source) {
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;
97 /* skip the '%' */
98 *(dest++) = *(source++);
99 /* Now insert a size qualifier, if needed. */
100 switch(*source) {
101 case 'i':
102 case 'd':
103 case 'x':
104 case 'X':
105 case 'u':
106 case 'o':
107 /* We have a 16-bit value here. */
108 *(dest++) = 'h';
109 break;
111 /* Here we go 'round the mulberry bush... */
112 loop_end:
114 *dest = '\0';
116 #endif
118 /* UTILITY_argsize() evaluates the size of the argument list that
119 * accompanies a vsprintf() or wvsprintf() call.
120 * Arguments:
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
124 * 32-bit variables.
125 * Returns:
126 * size (in bytes) of the arguments that follow the call.
129 size_t UTILITY_argsize(const char *format, BOOL windows)
131 size_t size = 0;
133 #define INT_SIZE (windows ? 2 : 4)
135 while(*format) {
136 while((*format) && (*format != '%')) format++; /* skip ahead */
137 if(*format) {
138 char modifier = ' ';
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);
146 format++;
148 /* Now the field width, etc. */
149 while(isdigit(*format)) {
150 dprintf_utility(stddeb, "%c", *format);
151 format++;
153 if(*format == '.') {
154 dprintf_utility(stddeb, "%c", *format);
155 format++;
157 while(isdigit(*format)) {
158 dprintf_utility(stddeb, "%c", *format);
159 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);
168 switch(*format) {
169 case 'd':
170 case 'i':
171 case 'o':
172 case 'x':
173 case 'X':
174 case 'u':
175 case 'c':
176 size += ((modifier == 'l') ? 4 : INT_SIZE);
177 break;
178 case 's': size += sizeof(char *); break;
179 case 'e':
180 case 'E':
181 case 'f':
182 case 'g':
183 case 'G':
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);
188 break;
189 case 'p': size += sizeof(void *); break;
190 case 'n': size += sizeof(int *); break;
194 #undef INT_SIZE
195 dprintf_utility(stddeb, "UTILITY_argsize: returning %i\n", size);
196 return 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
201 * vsprintf().
203 * Arguments:
204 * char *fmt; format string
205 * char *winarg; Windows-style arguments
207 * Returns:
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));
215 char *rptr = result;
216 short *wptr = (short *)winarg;
217 long *dptr = (long *)result;
219 while(*format) {
220 while((*format) && (*format != '%')) format++; /* skip ahead */
221 if(*format) {
222 char modifier = ' ';
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);
243 switch(*format) {
244 case 'd':
245 case 'i':
246 if (modifier == 'l') {
247 *((int *)rptr)++ = *((int *)winarg)++;
248 } else {
249 *((int *)rptr)++ = *((short *)winarg)++;
251 break;
252 case 'o':
253 case 'x':
254 case 'X':
255 case 'u':
256 case 'c':
257 if (modifier == 'l') {
258 *((unsigned int *)rptr)++ = *((unsigned int *)winarg)++;
259 } else {
260 *((unsigned int *)rptr)++ = *((unsigned short *)winarg)++;
262 break;
263 case 's':
264 case 'p':
265 case 'n': /* A pointer, is a pointer, is a pointer... */
266 *((char **)rptr)++ = (char *)PTR_SEG_TO_LIN(*(SEGPTR *)winarg);
267 ((SEGPTR *)winarg)++;
268 break;
269 case 'e':
270 case 'E':
271 case 'f':
272 case 'g':
273 case 'G':
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. */
277 if(modifier=='L')
278 *((long double *)rptr)++ = *((long double *)winarg)++;
279 else
280 *((double *)rptr)++ = *((double *)winarg)++;
281 break;
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" );
291 return result;
294 #ifndef WINELIB
295 INT windows_wsprintf(void)
297 LPSTR lpOutput, lpFormat, ptr;
298 BYTE new_stack[1024], *stack_ptr;
299 BOOL fLarge;
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 == '%')
313 continue;
315 /* skip width/precision */
316 while (*ptr == '-' || *ptr == '+' || *ptr == '.' ||
317 *ptr == ' ' || isdigit(*ptr) || *ptr == '#')
318 ptr++;
320 /* handle modifier */
321 fLarge = ((*ptr == 'l') || (*ptr == 'L'));
322 if (fLarge) ptr++;
324 switch (*ptr)
326 case 's':
327 *(char**)stack_ptr = (char *)PTR_SEG_TO_LIN(*(DWORD*)win_stack);
328 stack_ptr += sizeof(char *);
329 win_stack += sizeof(DWORD);
330 break;
332 case 'c':
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;
339 else
340 *(DWORD*)stack_ptr = ' ';
341 stack_ptr += sizeof(DWORD);
342 win_stack += sizeof(WORD);
343 break;
345 case 'd':
346 case 'i':
347 if (!fLarge)
349 *(int*)stack_ptr = *(INT*)win_stack;
350 stack_ptr += sizeof(int);
351 win_stack += sizeof(INT);
352 break;
354 /* else fall through */
355 case 'u':
356 case 'x':
357 case 'X':
358 if (fLarge)
360 *(DWORD*)stack_ptr = *(DWORD*)win_stack;
361 win_stack += sizeof(DWORD);
363 else
365 *(DWORD*)stack_ptr = *(WORD*)win_stack;
366 win_stack += sizeof(WORD);
368 stack_ptr += sizeof(DWORD);
369 break;
371 default:
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);
376 break;
380 return vsprintf(lpOutput, lpFormat, new_stack);
382 #endif
384 /**************************************************************************
385 * wsprintf [USER.420] (not used by relay)
387 int wsprintf(LPSTR lpOutput, LPSTR lpFormat, ...)
389 va_list valist;
390 int ArgCnt;
392 va_start(valist, lpFormat);
393 ArgCnt = vsprintf(lpOutput, lpFormat, valist);
394 va_end(valist);
396 return ArgCnt;
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)
412 char *newargs;
413 int result;
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);
421 free(newargs);
422 return result;