Release 950319
[wine/hacks.git] / windows / utility.c
blob385848735f2928624d355b53f58acdb21b30f8c1
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 "stddebug.h"
18 /* #define DEBUG_UTILITY */
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 return (long)(((int)foo*bar)/baz);
38 /* UTILITY_strip015() removes \015 (^M, CR) from a string;
39 * this is done to convert a MS-DOS-style string to a more
40 * UNIX-friendly format. Replacement is done in-place.
43 void UTILITY_strip015(char *dest) {
44 char *src = dest;
46 while(*src) {
47 while(*src == '\015') src++; /* Skip \015s */
48 while((*src) && (*src != '\015')) *(dest++) = *(src++);
50 *dest = '\0'; /* Add null terminator */
53 /**********************************************************************
54 * DebugPrintString
56 int
57 DebugPrintString(char *str)
59 fprintf(stderr, "%s", str);
60 return 0;
64 * OutputDebugString strips CRs from its (string) parameter and
65 * calls DebugPrintString(), which was written by someone else.
66 * Since this is part of the standard Windows API, it needs no
67 * references to nonstandard DLLs.
70 void OutputDebugString(LPSTR foo)
72 UTILITY_strip015(foo);
73 DebugPrintString(foo);
76 #if 0
77 /* UTILITY_qualify(source, dest) takes the format string source and
78 * changes all the parameters to correspond to Linux integer sizes
79 * rather than Windows sizes. For example, it converts %i to %hi
80 * and %lx to %x. No array size checking is done at present.
83 static void UTILITY_qualify(const char *source, char *dest)
85 dprintf_utility(stddeb, "UTILITY_qualify(\"%s\", \"%s\");\n",
86 source, dest);
87 if(!source) return; /* Dumbass attack! */
88 while(*source) {
89 /* Find next format code. */
90 while((*source != '%') && (*source)) {
91 *(dest++) = *(source++);
93 /* Yeah, I know I shouldn't use gotos.... */
94 if (!(*source)) goto loop_end;
95 /* skip the '%' */
96 *(dest++) = *(source++);
97 /* Now insert a size qualifier, if needed. */
98 switch(*source) {
99 case 'i':
100 case 'd':
101 case 'x':
102 case 'X':
103 case 'u':
104 case 'o':
105 /* We have a 16-bit value here. */
106 *(dest++) = 'h';
107 break;
109 /* Here we go 'round the mulberry bush... */
110 loop_end:
112 *dest = '\0';
114 #endif
116 /* UTILITY_argsize() evaluates the size of the argument list that
117 * accompanies a vsprintf() or wvsprintf() call.
118 * Arguments:
119 * char *format; printf-style format string.
120 * BOOL windows; if this is TRUE, we assume that ints are
121 * 16 bits in size; otherwise we deal with
122 * 32-bit variables.
123 * Returns:
124 * size (in bytes) of the arguments that follow the call.
127 size_t UTILITY_argsize(const char *format, BOOL windows)
129 size_t size = 0;
131 #define INT_SIZE (windows ? 2 : 4)
133 while(*format) {
134 while((*format) && (*format != '%')) format++; /* skip ahead */
135 if(*format) {
136 char modifier = ' ';
137 dprintf_utility(stddeb, "found:\t\"%%");
138 format++; /* skip past '%' */
139 /* First skip the flags, field width, etc. */
140 /* First the flags */
141 if ((*format == '#') || (*format == '-') || (*format == '+')
142 || (*format == ' ')) {
143 dprintf_utility(stddeb, "%c", *format);
144 format++;
146 /* Now the field width, etc. */
147 while(isdigit(*format)) {
148 dprintf_utility(stddeb, "%c", *format);
149 format++;
151 if(*format == '.') {
152 dprintf_utility(stddeb, "%c", *format);
153 format++;
155 while(isdigit(*format)) {
156 dprintf_utility(stddeb, "%c", *format);
157 format++;
159 /* Now we handle the rest */
160 if((*format == 'h') || (*format == 'l') || (*format == 'L')) {
161 dprintf_utility(stddeb, "%c", modifier);
162 modifier = *(format++);
164 /* Handle the actual type. */
165 dprintf_utility(stddeb, "%c\"\n", *format);
166 switch(*format) {
167 case 'd':
168 case 'i':
169 case 'o':
170 case 'x':
171 case 'X':
172 case 'u':
173 case 'c':
174 size += ((modifier == 'l') ? 4 : INT_SIZE);
175 break;
176 case 's': size += sizeof(char *); break;
177 case 'e':
178 case 'E':
179 case 'f':
180 case 'g':
181 case 'G':
182 /* It doesn't look as if Windows' wvsprintf()
183 supports floating-point arguments. However,
184 I'll leave this code here just in case. */
185 size += (modifier == 'L') ? sizeof(long double) : sizeof(double);
186 break;
187 case 'p': size += sizeof(void *); break;
188 case 'n': size += sizeof(int *); break;
192 #undef INT_SIZE
193 dprintf_utility(stddeb, "UTILITY_argsize: returning %i\n", size);
194 return size;
197 /* UTILITY_convertArgs() creates a 32-bit argument list from a 16-bit list.
198 * This is used to allow wvsprintf() arguments to be fed through
199 * vsprintf().
201 * Arguments:
202 * char *fmt; format string
203 * char *winarg; Windows-style arguments
205 * Returns:
206 * malloc()ed pointer to new argument list. This should
207 * be free()d as soon as it is finished with.
210 char *UTILITY_convertArgs(char *format, char *winarg)
212 char *result = (char *)malloc(UTILITY_argsize(format, 0));
213 char *rptr = result;
215 while(*format) {
216 while((*format) && (*format != '%')) format++; /* skip ahead */
217 if(*format) {
218 char modifier = ' ';
219 dprintf_utility(stddeb, "found:\t\"%%");
220 format++; /* skip past '%' */
221 /* First skip the flags, field width, etc. */
222 /* First the flags */
223 if ((*format == '#') || (*format == '-') || (*format == '+')
224 || (*format == ' ')) format++;
225 /* Now the field width, etc. */
226 while(isdigit(*format)) format++;
227 if(*format == '.') format++;
228 while(isdigit(*format)) format++;
229 /* Now we handle the rest */
230 if((*format == 'h') || (*format == 'l') || (*format == 'L'))
231 modifier = *(format++);
232 /* Handle the actual type. */
233 dprintf_utility(stddeb, "%c\"\n", *format);
234 switch(*format) {
235 case 'd':
236 case 'i':
237 *(((int *)rptr)++) = (modifier=='l') ? *(((int *)winarg)++) : *(((short *)winarg)++);
238 break;
239 case 'o':
240 case 'x':
241 case 'X':
242 case 'u':
243 case 'c':
244 *(((unsigned int *)rptr)++) = (modifier=='l') ? *(((unsigned int *)winarg)++)
245 : *(((unsigned short *)winarg)++);
246 break;
247 case 's':
248 case 'p':
249 case 'n': /* A pointer, is a pointer, is a pointer... */
250 *(((char **)rptr)++) = (char *)PTR_SEG_TO_LIN(*(((char **)winarg)++));
251 break;
252 case 'e':
253 case 'E':
254 case 'f':
255 case 'g':
256 case 'G':
257 /* It doesn't look as if Windows' wvsprintf()
258 supports floating-point arguments. However,
259 I'll leave this code here just in case. */
260 if(modifier=='L')
261 *(((long double *)rptr)++) = *(((long double *)winarg)++);
262 else *(((double *)rptr)++) = *(((double *)winarg)++);
263 break;
267 return result;
270 #ifndef WINELIB
271 INT windows_wsprintf(BYTE *win_stack)
273 LPSTR lpOutput, lpFormat, ptr;
274 BYTE new_stack[1024], *stack_ptr;
275 BOOL fLarge;
277 lpOutput = (LPSTR) PTR_SEG_TO_LIN(*(DWORD*)win_stack);
278 win_stack += sizeof(DWORD);
279 lpFormat = (LPSTR) PTR_SEG_TO_LIN(*(DWORD*)win_stack);
280 win_stack += sizeof(DWORD);
282 /* create 32-bit stack for libc's vsprintf() */
284 for (ptr = lpFormat, stack_ptr = new_stack; *ptr; ptr++)
286 if (*ptr != '%' || *++ptr == '%')
287 continue;
289 /* skip width/precision */
290 while (*ptr == '-' || *ptr == '+' || *ptr == '.' ||
291 *ptr == ' ' || isdigit(*ptr) || *ptr == '#')
292 ptr++;
294 /* handle modifier */
295 fLarge = ((*ptr == 'l') || (*ptr == 'L'));
296 if (fLarge) ptr++;
298 switch (*ptr)
300 case 's':
301 *(char**)stack_ptr = (char *)PTR_SEG_TO_LIN(*(DWORD*)win_stack);
302 stack_ptr += sizeof(char *);
303 win_stack += sizeof(DWORD);
304 break;
306 case 'c':
308 /* windows' wsprintf() %c ignores 0's, we replace 0 with SPACE to make sure
309 that the remaining part of the string isn't ignored by the winapp */
311 if (*(WORD*)win_stack)
312 *(DWORD*)stack_ptr = *(WORD*)win_stack;
313 else
314 *(DWORD*)stack_ptr = ' ';
315 stack_ptr += sizeof(DWORD);
316 win_stack += sizeof(WORD);
317 break;
319 case 'd':
320 case 'i':
321 if (!fLarge)
323 *(int*)stack_ptr = *(INT*)win_stack;
324 stack_ptr += sizeof(int);
325 win_stack += sizeof(INT);
326 break;
328 /* else fall through */
329 case 'u':
330 case 'x':
331 case 'X':
332 if (fLarge)
334 *(DWORD*)stack_ptr = *(DWORD*)win_stack;
335 win_stack += sizeof(DWORD);
337 else
339 *(DWORD*)stack_ptr = *(WORD*)win_stack;
340 win_stack += sizeof(WORD);
342 stack_ptr += sizeof(DWORD);
343 break;
345 default:
346 *(DWORD*)stack_ptr = 0;
347 stack_ptr += sizeof(DWORD);
348 win_stack += sizeof(WORD);
349 fprintf(stderr, "wsprintf: oops, unknown formattype %c used!\n", *ptr);
350 break;
354 return vsprintf(lpOutput, lpFormat, new_stack);
356 #endif
358 /**************************************************************************
359 * wsprintf [USER.420] (not used by relay)
361 int wsprintf(LPSTR lpOutput, LPSTR lpFormat, ...)
363 va_list valist;
364 int ArgCnt;
366 va_start(valist, lpFormat);
367 ArgCnt = vsprintf(lpOutput, lpFormat, valist);
368 va_end(valist);
370 return ArgCnt;
374 /* wvsprintf() is an implementation of vsprintf(). This
375 * implementation converts the arguments to 32-bit integers and
376 * calls the standard library function vsprintf().
378 * Known shortcomings:
379 * wvsprintf() doesn't yet convert the arguments back after
380 * calling vsprintf(), so if Windows implements %n and a
381 * program depends on it, we're in trouble.
384 int wvsprintf(LPSTR buf, LPSTR format, LPSTR args)
386 char *newargs;
387 int result;
389 if(!buf || !format) return 0;
391 /* Convert agruments to 32-bit values */
392 newargs = UTILITY_convertArgs(format, args);
393 result = vsprintf(buf, format, newargs);
395 free(newargs);
396 return result;