Release 950620
[wine/multimedia.git] / windows / utility.c
blob61df0cb6f1770d53de519ba81cf3c36f27b3dde6
1 /* utility.c Utility functions for Wine
2 * Author: acb
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"
22 /* static char Copyright[] = "Copyright Andrew C. Bulhak, 1993"; */
25 /* MulDiv is a simple function that may as well have been
26 * implemented as a macro; however Microsoft, in their infinite
27 * wisdom, have implemented it as a DLL function and therefore
28 * so should we.
29 * Basically, it takes two 16-bit integers, multiplies them
30 * and divides by a third integer.
33 int MulDiv(int foo, int bar, int baz)
35 int ret;
36 if (!baz) return -32768;
37 ret = (foo * bar) / baz;
38 if ((ret > 32767) || (ret < -32767)) return -32768;
39 return ret;
42 /* UTILITY_strip015() removes \015 (^M, CR) from a string;
43 * this is done to convert a MS-DOS-style string to a more
44 * UNIX-friendly format. Replacement is done in-place.
47 void UTILITY_strip015(char *dest) {
48 char *src = dest;
50 while(*src) {
51 while(*src == '\015') src++; /* Skip \015s */
52 while((*src) && (*src != '\015')) *(dest++) = *(src++);
54 *dest = '\0'; /* Add null terminator */
57 /**********************************************************************
58 * DebugPrintString
60 int
61 DebugPrintString(char *str)
63 fprintf(stderr, "%s\n", str);
64 return 0;
68 * OutputDebugString strips CRs from its (string) parameter and
69 * calls DebugPrintString(), which was written by someone else.
70 * Since this is part of the standard Windows API, it needs no
71 * references to nonstandard DLLs.
74 void OutputDebugString(LPSTR foo)
76 UTILITY_strip015(foo);
77 DebugPrintString(foo);
80 #if 0
81 /* UTILITY_qualify(source, dest) takes the format string source and
82 * changes all the parameters to correspond to Linux integer sizes
83 * rather than Windows sizes. For example, it converts %i to %hi
84 * and %lx to %x. No array size checking is done at present.
87 static void UTILITY_qualify(const char *source, char *dest)
89 dprintf_utility(stddeb, "UTILITY_qualify(\"%s\", \"%s\");\n",
90 source, dest);
91 if(!source) return; /* Dumbass attack! */
92 while(*source) {
93 /* Find next format code. */
94 while((*source != '%') && (*source)) {
95 *(dest++) = *(source++);
97 /* Yeah, I know I shouldn't use gotos.... */
98 if (!(*source)) goto loop_end;
99 /* skip the '%' */
100 *(dest++) = *(source++);
101 /* Now insert a size qualifier, if needed. */
102 switch(*source) {
103 case 'i':
104 case 'd':
105 case 'x':
106 case 'X':
107 case 'u':
108 case 'o':
109 /* We have a 16-bit value here. */
110 *(dest++) = 'h';
111 break;
113 /* Here we go 'round the mulberry bush... */
114 loop_end:
116 *dest = '\0';
118 #endif
120 /* UTILITY_argsize() evaluates the size of the argument list that
121 * accompanies a vsprintf() or wvsprintf() call.
122 * Arguments:
123 * char *format; printf-style format string.
124 * BOOL windows; if this is TRUE, we assume that ints are
125 * 16 bits in size; otherwise we deal with
126 * 32-bit variables.
127 * Returns:
128 * size (in bytes) of the arguments that follow the call.
131 size_t UTILITY_argsize(const char *format, BOOL windows)
133 size_t size = 0;
135 #define INT_SIZE (windows ? 2 : 4)
137 while(*format) {
138 while((*format) && (*format != '%')) format++; /* skip ahead */
139 if(*format) {
140 char modifier = ' ';
141 dprintf_utility(stddeb, "found:\t\"%%");
142 format++; /* skip past '%' */
143 /* First skip the flags, field width, etc. */
144 /* First the flags */
145 if ((*format == '#') || (*format == '-') || (*format == '+')
146 || (*format == ' ')) {
147 dprintf_utility(stddeb, "%c", *format);
148 format++;
150 /* Now the field width, etc. */
151 while(isdigit(*format)) {
152 dprintf_utility(stddeb, "%c", *format);
153 format++;
155 if(*format == '.') {
156 dprintf_utility(stddeb, "%c", *format);
157 format++;
159 while(isdigit(*format)) {
160 dprintf_utility(stddeb, "%c", *format);
161 format++;
163 /* Now we handle the rest */
164 if((*format == 'h') || (*format == 'l') || (*format == 'L')) {
165 dprintf_utility(stddeb, "%c", modifier);
166 modifier = *(format++);
168 /* Handle the actual type. */
169 dprintf_utility(stddeb, "%c\"\n", *format);
170 switch(*format) {
171 case 'd':
172 case 'i':
173 case 'o':
174 case 'x':
175 case 'X':
176 case 'u':
177 case 'c':
178 size += ((modifier == 'l') ? 4 : INT_SIZE);
179 break;
180 case 's': size += sizeof(char *); break;
181 case 'e':
182 case 'E':
183 case 'f':
184 case 'g':
185 case 'G':
186 /* It doesn't look as if Windows' wvsprintf()
187 supports floating-point arguments. However,
188 I'll leave this code here just in case. */
189 size += (modifier == 'L') ? sizeof(long double) : sizeof(double);
190 break;
191 case 'p': size += sizeof(void *); break;
192 case 'n': size += sizeof(int *); break;
196 #undef INT_SIZE
197 dprintf_utility(stddeb, "UTILITY_argsize: returning %i\n", size);
198 return size;
201 /* UTILITY_convertArgs() creates a 32-bit argument list from a 16-bit list.
202 * This is used to allow wvsprintf() arguments to be fed through
203 * vsprintf().
205 * Arguments:
206 * char *fmt; format string
207 * char *winarg; Windows-style arguments
209 * Returns:
210 * malloc()ed pointer to new argument list. This should
211 * be free()d as soon as it is finished with.
214 char *UTILITY_convertArgs(char *format, char *winarg)
216 char *result = (char *)malloc(UTILITY_argsize(format, 0));
217 char *rptr = result;
218 short *wptr = (short *)winarg;
219 long *dptr = (long *)result;
221 while(*format) {
222 while((*format) && (*format != '%')) format++; /* skip ahead */
223 if(*format) {
224 char modifier = ' ';
225 dprintf_utility(stddeb, "found:\t\"%%");
226 format++; /* skip past '%' */
228 /* First skip the flags, field width, etc. */
229 /* First the flags */
230 if (*format == '#' || *format == '-' || *format == '+'
231 || *format == ' ') format++;
233 /* Now the field width, etc. */
234 while (isdigit(*format)) format++;
235 if (*format == '.') format++;
236 while (isdigit(*format)) format++;
238 /* Now we handle the rest */
239 if(*format == 'h' || *format == 'l' || *format == 'L')
240 modifier = *format++;
242 /* Handle the actual type. */
243 dprintf_utility(stddeb, "%c\"\n", *format);
245 switch(*format) {
246 case 'd':
247 case 'i':
248 if (modifier == 'l') {
249 *((int *)rptr)++ = *((int *)winarg)++;
250 } else {
251 *((int *)rptr)++ = *((short *)winarg)++;
253 break;
254 case 'o':
255 case 'x':
256 case 'X':
257 case 'u':
258 case 'c':
259 if (modifier == 'l') {
260 *((unsigned int *)rptr)++ = *((unsigned int *)winarg)++;
261 } else {
262 *((unsigned int *)rptr)++ = *((unsigned short *)winarg)++;
264 break;
265 case 's':
266 case 'p':
267 case 'n': /* A pointer, is a pointer, is a pointer... */
268 *((char **)rptr)++ = (char *)PTR_SEG_TO_LIN(*(SEGPTR *)winarg);
269 ((SEGPTR *)winarg)++;
270 break;
271 case 'e':
272 case 'E':
273 case 'f':
274 case 'g':
275 case 'G':
276 /* It doesn't look as if Windows' wvsprintf()
277 supports floating-point arguments. However,
278 I'll leave this code here just in case. */
279 if(modifier=='L')
280 *((long double *)rptr)++ = *((long double *)winarg)++;
281 else
282 *((double *)rptr)++ = *((double *)winarg)++;
283 break;
287 for(; (char *)dptr < rptr; dptr ++)
288 dprintf_utility( stddeb, "%08lx ", *dptr );
289 dprintf_utility( stddeb, "\n" );
290 for(; (char *)wptr < winarg; wptr ++)
291 dprintf_utility( stddeb, "%04x ", *wptr );
292 dprintf_utility( stddeb, "\n" );
293 return result;
296 #ifndef WINELIB
297 INT windows_wsprintf(void)
299 LPSTR lpOutput, lpFormat, ptr;
300 BYTE new_stack[1024], *stack_ptr;
301 BOOL fLarge;
303 BYTE *win_stack = (BYTE *)CURRENT_STACK16->args;
305 lpOutput = (LPSTR) PTR_SEG_TO_LIN(*(DWORD*)win_stack);
306 win_stack += sizeof(DWORD);
307 lpFormat = (LPSTR) PTR_SEG_TO_LIN(*(DWORD*)win_stack);
308 win_stack += sizeof(DWORD);
310 /* create 32-bit stack for libc's vsprintf() */
312 for (ptr = lpFormat, stack_ptr = new_stack; *ptr; ptr++)
314 if (*ptr != '%' || *++ptr == '%')
315 continue;
317 /* skip width/precision */
318 while (*ptr == '-' || *ptr == '+' || *ptr == '.' ||
319 *ptr == ' ' || isdigit(*ptr) || *ptr == '#')
320 ptr++;
322 /* handle modifier */
323 fLarge = ((*ptr == 'l') || (*ptr == 'L'));
324 if (fLarge) ptr++;
326 switch (*ptr)
328 case 's':
329 *(char**)stack_ptr = (char *)PTR_SEG_TO_LIN(*(DWORD*)win_stack);
330 stack_ptr += sizeof(char *);
331 win_stack += sizeof(DWORD);
332 break;
334 case 'c':
336 /* windows' wsprintf() %c ignores 0's, we replace 0 with SPACE to make sure
337 that the remaining part of the string isn't ignored by the winapp */
339 if (*(WORD*)win_stack)
340 *(DWORD*)stack_ptr = *(WORD*)win_stack;
341 else
342 *(DWORD*)stack_ptr = ' ';
343 stack_ptr += sizeof(DWORD);
344 win_stack += sizeof(WORD);
345 break;
347 case 'd':
348 case 'i':
349 if (!fLarge)
351 *(int*)stack_ptr = *(INT*)win_stack;
352 stack_ptr += sizeof(int);
353 win_stack += sizeof(INT);
354 break;
356 /* else fall through */
357 case 'u':
358 case 'x':
359 case 'X':
360 if (fLarge)
362 *(DWORD*)stack_ptr = *(DWORD*)win_stack;
363 win_stack += sizeof(DWORD);
365 else
367 *(DWORD*)stack_ptr = *(WORD*)win_stack;
368 win_stack += sizeof(WORD);
370 stack_ptr += sizeof(DWORD);
371 break;
373 default:
374 *(DWORD*)stack_ptr = 0;
375 stack_ptr += sizeof(DWORD);
376 win_stack += sizeof(WORD);
377 fprintf(stderr, "wsprintf: oops, unknown formattype %c used!\n", *ptr);
378 break;
382 return vsprintf(lpOutput, lpFormat, new_stack);
384 #endif
386 /**************************************************************************
387 * wsprintf [USER.420] (not used by relay)
389 int wsprintf(LPSTR lpOutput, LPSTR lpFormat, ...)
391 va_list valist;
392 int ArgCnt;
394 va_start(valist, lpFormat);
395 ArgCnt = vsprintf(lpOutput, lpFormat, valist);
396 va_end(valist);
398 return ArgCnt;
402 /* wvsprintf() is an implementation of vsprintf(). This
403 * implementation converts the arguments to 32-bit integers and
404 * calls the standard library function vsprintf().
406 * Known shortcomings:
407 * wvsprintf() doesn't yet convert the arguments back after
408 * calling vsprintf(), so if Windows implements %n and a
409 * program depends on it, we're in trouble.
412 int wvsprintf(LPSTR buf, LPSTR format, LPSTR args)
414 char *newargs;
415 int result;
417 if(!buf || !format) return 0;
419 /* Convert agruments to 32-bit values */
420 newargs = UTILITY_convertArgs(format, args);
421 result = vsprintf(buf, format, newargs);
423 free(newargs);
424 return result;