1 /* utility.c Utility functions for Wine
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 static char Copyright[] = "Copyright Andrew C. Bulhak, 1993";
19 /*#define debug_utility*/
21 /* MulDiv is a simple function that may as well have been
22 * implemented as a macro; however Microsoft, in their infinite
23 * wisdom, have implemented it as a DLL function and therefore
25 * Basically, it takes two 16-bit integers, multiplies them
26 * and divides by a third integer.
29 int MulDiv(int foo, int bar, int baz)
31 return (long)(((int)foo*bar)/baz);
34 /* UTILITY_strip015() removes \015 (^M, CR) from a string;
35 * this is done to convert a MS-DOS-style string to a more
36 * UNIX-friendly format. Replacement is done in-place.
39 void UTILITY_strip015(char *dest) {
43 while(*src == '\015') src++; /* Skip \015s */
44 while((*src) && (*src != '\015')) *(dest++) = *(src++);
46 *dest = '\0'; /* Add null terminator */
49 /**********************************************************************
53 DebugPrintString(char *str)
55 fprintf(stderr, "%s", str);
60 * OutputDebugString strips CRs from its (string) parameter and
61 * calls DebugPrintString(), which was written by someone else.
62 * Since this is part of the standard Windows API, it needs no
63 * references to nonstandard DLLs.
66 void OutputDebugString(LPSTR foo)
68 UTILITY_strip015(foo);
69 DebugPrintString(foo);
72 /* UTILITY_qualify(source, dest) takes the format string source and
73 * changes all the parameters to correspond to Linux integer sizes
74 * rather than Windows sizes. For example, it converts %i to %hi
75 * and %lx to %x. No array size checking is done at present.
78 static void UTILITY_qualify(const char *source, char *dest)
81 fprintf(stderr, "UTILITY_qualify(\"%s\", \"%s\");\n", source, dest);
83 if(!source) return; /* Dumbass attack! */
85 /* Find next format code. */
86 while((*source != '%') && (*source)) {
87 *(dest++) = *(source++);
89 /* Yeah, I know I shouldn't use gotos.... */
90 if (!(*source)) goto loop_end;
92 *(dest++) = *(source++);
93 /* Now insert a size qualifier, if needed. */
101 /* We have a 16-bit value here. */
105 /* Here we go 'round the mulberry bush... */
111 /* UTILITY_argsize() evaluates the size of the argument list that
112 * accompanies a vsprintf() or wvsprintf() call.
114 * char *format; printf-style format string.
115 * BOOL windows; if this is TRUE, we assume that ints are
116 * 16 bits in size; otherwise we deal with
119 * size (in bytes) of the arguments that follow the call.
122 size_t UTILITY_argsize(const char *format, BOOL windows)
126 #define INT_SIZE (windows ? 2 : 4)
129 while((*format) && (*format != '%')) format++; /* skip ahead */
133 fprintf(stderr, "found:\t\"%%");
135 format++; /* skip past '%' */
136 /* First skip the flags, field width, etc. */
137 /* First the flags */
138 if ((*format == '#') || (*format == '-') || (*format == '+')
139 || (*format == ' ')) {
141 fprintf(stderr, "%c", *format);
145 /* Now the field width, etc. */
146 while(isdigit(*format)) {
148 fprintf(stderr, "%c", *format);
154 fprintf(stderr, "%c", *format);
158 while(isdigit(*format)) {
160 fprintf(stderr, "%c", *format);
164 /* Now we handle the rest */
165 if((*format == 'h') || (*format == 'l') || (*format == 'L')) {
167 fprintf(stderr, "%c", modifier);
169 modifier = *(format++);
171 /* Handle the actual type. */
173 fprintf(stderr, "%c\"\n", *format);
183 size += ((modifier == 'l') ? 4 : INT_SIZE);
185 case 's': size += sizeof(char *); break;
191 /* It doesn't look as if Windows' wvsprintf()
192 supports floating-point arguments. However,
193 I'll leave this code here just in case. */
194 size += (modifier == 'L') ? sizeof(long double) : sizeof(double);
196 case 'p': size += sizeof(void *); break;
197 case 'n': size += sizeof(int *); break;
203 fprintf(stderr, "UTILITY_argsize: returning %i\n", size);
208 /* UTILITY_convertArgs() creates a 32-bit argument list from a 16-bit list.
209 * This is used to allow wvsprintf() arguments to be fed through
213 * char *fmt; format string
214 * char *winarg; Windows-style arguments
217 * malloc()ed pointer to new argument list. This should
218 * be free()d as soon as it is finished with.
221 char *UTILITY_convertArgs(char *format, char *winarg)
223 char *result = (char *)malloc(UTILITY_argsize(format, 0));
227 while((*format) && (*format != '%')) format++; /* skip ahead */
231 fprintf(stderr, "found:\t\"%%");
233 format++; /* skip past '%' */
234 /* First skip the flags, field width, etc. */
235 /* First the flags */
236 if ((*format == '#') || (*format == '-') || (*format == '+')
237 || (*format == ' ')) format++;
238 /* Now the field width, etc. */
239 while(isdigit(*format)) format++;
240 if(*format == '.') format++;
241 while(isdigit(*format)) format++;
242 /* Now we handle the rest */
243 if((*format == 'h') || (*format == 'l') || (*format == 'L'))
244 modifier = *(format++);
245 /* Handle the actual type. */
247 fprintf(stderr, "%c\"\n", *format);
252 *(((int *)rptr)++) = (modifier=='l') ? *(((int *)winarg)++) : *(((short *)winarg)++);
259 *(((unsigned int *)rptr)++) = (modifier=='l') ? *(((unsigned int *)winarg)++)
260 : *(((unsigned short *)winarg)++);
264 case 'n': /* A pointer, is a pointer, is a pointer... */
265 *(((char **)rptr)++) = *(((char **)winarg)++);
272 /* It doesn't look as if Windows' wvsprintf()
273 supports floating-point arguments. However,
274 I'll leave this code here just in case. */
276 *(((long double *)rptr)++) = *(((long double *)winarg)++);
277 else *(((double *)rptr)++) = *(((double *)winarg)++);
286 INT windows_wsprintf(BYTE *win_stack)
288 LPSTR lpOutput, lpFormat;
289 BYTE *new_stack, *stack_ptr, *ptr;
290 int stacklength, result;
292 lpOutput = (LPSTR) *(DWORD*)win_stack;
294 lpFormat = (LPSTR) *(DWORD*)win_stack;
297 /* determine # of bytes pushed on 16-bit stack by checking printf's
306 /* skip width/precision */
307 while ( *ptr == '-' || *ptr == '+' || *ptr == '.' ||
308 *ptr == ' ' || isdigit(*ptr))
312 case 'l': ptr++; /* skip next type character */
327 fprintf(stderr, "wsprintf: oops, unknown formattype `%c' used!\n", *ptr);
331 /* create 32-bit stack for libc's vsprintf() */
333 new_stack = malloc(2 * stacklength);
334 stack_ptr = new_stack + 2 * stacklength;
335 win_stack += stacklength;
341 /* skip width/precision */
342 while ( *ptr == '-' || *ptr == '+' || *ptr == '.' ||
343 *ptr == ' ' || isdigit(*ptr))
350 *(DWORD*)stack_ptr = *(DWORD*)win_stack;
355 *(DWORD*)stack_ptr = *(DWORD*)win_stack;
356 ptr++; /* skip next type character */
362 /* windows' wsprintf() %c ignores 0's, we replace 0 with 1 to make sure
363 that the remaining part of the string isn't ignored by the winapp */
365 if (*(WORD*)win_stack)
366 *(DWORD*)stack_ptr = *(WORD*)win_stack;
368 *(DWORD*)stack_ptr = 1;
374 *(int*)stack_ptr = *(INT*)win_stack;
381 *(DWORD*)stack_ptr = *(WORD*)win_stack;
386 *(DWORD*)stack_ptr = 0;
387 fprintf(stderr, "wsprintf: oops, unknown formattype %c used!\n", *ptr);
391 result = vsprintf(lpOutput, lpFormat, stack_ptr);
398 /**************************************************************************
399 * wsprintf [USER.420] (not used by relay)
401 int wsprintf(LPSTR lpOutput, LPSTR lpFormat, ...)
406 va_start(valist, lpFormat);
407 ArgCnt = vsprintf(lpOutput, lpFormat, valist);
414 /* wvsprintf() is an implementation of vsprintf(). This
415 * implementation converts the arguments to 32-bit integers and
416 * calls the standard library function vsprintf().
418 * Known shortcomings:
419 * wvsprintf() doesn't yet convert the arguments back after
420 * calling vsprintf(), so if Windows implements %n and a
421 * program depends on it, we're in trouble.
424 int wvsprintf(LPSTR buf, LPSTR format, LPSTR args)
426 char qualified_fmt[1536];
430 /* 1.5K is a safe value as wvsprintf can only handle buffers up to
431 1K and in a worst case such a buffer would look like "%i%i%i..." */
433 if(!buf || !format) return 0;
435 /* Change the format string so that ints are handled as short by
438 /* Convert agruments to 32-bit values */
439 newargs = UTILITY_convertArgs(format, args);
440 result = vsprintf(buf, qualified_fmt, newargs);