Release 0.4.7
[wine] / windows / utility.c
1 /*      utility.c       Utility functions for Wine
2  *                      Author:         acb
3  *                      Commenced:      10-9-1993
4  *
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  */
10
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <ctype.h>
14 #include "windows.h"
15
16 static char Copyright[] = "Copyright Andrew C. Bulhak, 1993";
17
18 /*#define debug_utility*/
19
20 /*      MulDiv is a simple function that may as well have been
21  *      implemented as a macro; however Microsoft, in their infinite
22  *      wisdom, have implemented it as a DLL function and therefore
23  *      so should we. 
24  *      Basically, it takes two 16-bit integers, multiplies them
25  *      and divides by a third integer.
26  */
27
28 int MulDiv(int foo, int bar, int baz)
29 {
30         return (long)(((int)foo*bar)/baz);
31 };
32
33 /*      UTILITY_strip015() removes \015 (^M, CR) from a string;
34  *      this is done to convert a MS-DOS-style string to a more
35  *      UNIX-friendly format. Replacement is done in-place.
36  */
37
38 void UTILITY_strip015(char *dest) {
39         char *src = dest;
40
41         while(*src) {
42                 while(*src == '\015') src++;    /* Skip \015s */
43                 while((*src) && (*src != '\015')) *(dest++) = *(src++);
44         };
45         *dest = '\0';   /* Add null terminator */
46 };
47
48 /*
49  *      OutputDebugString strips CRs from its (string) parameter and
50  *      calls DebugPrintString(), which was written by someone else. 
51  *      Since this is part of the standard Windows API, it needs no 
52  *      references to nonstandard DLLs.
53  */
54
55 void OutputDebugString(LPSTR foo)
56 {
57         UTILITY_strip015(foo);
58         DebugPrintString(foo);
59 };
60
61 /*      UTILITY_qualify(source, dest) takes the format string source and
62  *      changes all the parameters to correspond to Linux integer sizes
63  *      rather than Windows sizes. For example, it converts %i to %hi
64  *      and %lx to %x. No array size checking is done at present.
65  */
66
67 static void UTILITY_qualify(const char *source, char *dest)
68 {
69 #ifdef debug_utility
70         printf("UTILITY_qualify(\"%s\", \"%s\");\n", source, dest);
71 #endif
72         if(!source) return;     /* Dumbass attack! */
73         while(*source) {
74                 /* Find next format code. */
75                 while((*source != '%') && (*source)) {
76                         *(dest++) = *(source++);
77                 }
78                 /* Yeah, I know I shouldn't use gotos.... */
79                 if (!(*source)) goto loop_end;
80                 /* skip the '%' */
81                 *(dest++) = *(source++);
82                 /* Now insert a size qualifier, if needed. */
83                 switch(*source) {
84                         case 'i':
85                         case 'd':
86                         case 'x':
87                         case 'X':
88                         case 'u':
89                         case 'o':
90                                 /* We have a 16-bit value here. */
91                                 *(dest++) = 'h';
92                                 break;
93                 };
94                 /* Here we go 'round the mulberry bush... */
95 loop_end:
96         };
97         *dest = '\0';
98 };
99
100 /*      UTILITY_argsize() evaluates the size of the argument list that
101  *      accompanies a vsprintf() or wvsprintf() call.
102  *      Arguments:
103  *              char *format;   printf-style format string.
104  *              BOOL windows;   if this is TRUE, we assume that ints are
105  *                              16 bits in size; otherwise we deal with
106  *                              32-bit variables.
107  *      Returns:
108  *              size (in bytes) of the arguments that follow the call.
109  */
110
111 size_t UTILITY_argsize(const char *format, BOOL windows)
112 {
113         size_t size = 0;
114
115 #define INT_SIZE (windows ? 2 : 4)
116
117         while(*format) {
118                 while((*format) && (*format != '%')) format++;  /* skip ahead */
119                 if(*format) {
120                         char modifier = ' ';
121 #ifdef debug_utility
122                         printf("found:\t\"%%");
123 #endif
124                         format++;               /* skip past '%' */
125                         /* First skip the flags, field width, etc. */
126                         /* First the flags */
127                         if ((*format == '#') || (*format == '-') || (*format == '+')
128                                 || (*format == ' ')) {
129 #ifdef debug_utility
130                                 printf("%c", *format);
131 #endif
132                                 format++;
133                         }
134                         /* Now the field width, etc. */
135                         while(isdigit(*format)) {
136 #ifdef debug_utility
137                                 printf("%c", *format);
138 #endif
139                                 format++;
140                         }
141                         if(*format == '.') {
142 #ifdef debug_utility
143                                 printf("%c", *format);
144 #endif
145                                 format++;
146                         }
147                         while(isdigit(*format)) {
148 #ifdef debug_utility
149                                 printf("%c", *format);
150 #endif
151                                 format++;
152                         }
153                         /* Now we handle the rest */
154                         if((*format == 'h') || (*format == 'l') || (*format == 'L')) {
155 #ifdef debug_utility
156                                 printf("%c", modifier);
157 #endif
158                                 modifier = *(format++);
159                         }
160                         /* Handle the actual type. */
161 #ifdef debug_utility
162                                 printf("%c\"\n", *format);
163 #endif
164                         switch(*format) {
165                                 case 'd':
166                                 case 'i':
167                                 case 'o':
168                                 case 'x':
169                                 case 'X':
170                                 case 'u':
171                                 case 'c':
172                                         size += ((modifier == 'l') ? 4 : INT_SIZE);
173                                         break;
174                                 case 's': size += sizeof(char *); break;
175                                 case 'e':
176                                 case 'E':
177                                 case 'f':
178                                 case 'g':
179                                 case 'G':
180                                         /* It doesn't look as if Windows' wvsprintf()
181                                            supports floating-point arguments. However,
182                                            I'll leave this code here just in case. */
183                                         size += (modifier == 'L') ? sizeof(long double) : sizeof(double);
184                                         break;
185                                 case 'p': size += sizeof(void *); break;
186                                 case 'n': size += sizeof(int *); break;
187                         };
188                 };
189         };
190 #undef INT_SIZE
191 #ifdef debug_utility
192         printf("UTILITY_argsize: returning %i\n", size);
193 #endif
194         return size;
195 };
196
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().
200  *
201  *      Arguments:
202  *              char *fmt;      format string
203  *              char *winarg;   Windows-style arguments
204  *      
205  *      Returns:
206  *              malloc()ed pointer to new argument list. This should
207  *              be free()d as soon as it is finished with.
208  */
209
210 char *UTILITY_convertArgs(char *format, char *winarg)
211 {
212         char *result = (char *)malloc(UTILITY_argsize(format, 0));
213         char *rptr = result;
214
215         while(*format) {
216                 while((*format) && (*format != '%')) format++;  /* skip ahead */
217                 if(*format) {
218                         char modifier = ' ';
219 #ifdef debug_utility
220                         printf("found:\t\"%%");
221 #endif
222                         format++;               /* skip past '%' */
223                         /* First skip the flags, field width, etc. */
224                         /* First the flags */
225                         if ((*format == '#') || (*format == '-') || (*format == '+')
226                                 || (*format == ' ')) format++;
227                         /* Now the field width, etc. */
228                         while(isdigit(*format)) format++;
229                         if(*format == '.') format++;
230                         while(isdigit(*format)) format++;
231                         /* Now we handle the rest */
232                         if((*format == 'h') || (*format == 'l') || (*format == 'L'))
233                                 modifier = *(format++);
234                         /* Handle the actual type. */
235 #ifdef debug_utility
236                                 printf("%c\"\n", *format);
237 #endif
238                         switch(*format) {
239                                 case 'd':
240                                 case 'i':
241                                         *(((int *)rptr)++) = (modifier=='l') ? *(((int *)winarg)++) : *(((short *)winarg)++);
242                                         break;
243                                 case 'o':
244                                 case 'x':
245                                 case 'X':
246                                 case 'u':
247                                 case 'c':
248                                         *(((unsigned int *)rptr)++) = (modifier=='l') ? *(((unsigned int *)winarg)++) 
249                                                 : *(((unsigned short *)winarg)++);
250                                         break;
251                                 case 's':
252                                 case 'p':
253                                 case 'n':       /* A pointer, is a pointer, is a pointer... */
254                                         *(((char **)rptr)++) = *(((char **)winarg)++);
255                                         break;
256                                 case 'e':
257                                 case 'E':
258                                 case 'f':
259                                 case 'g':
260                                 case 'G':
261                                         /* It doesn't look as if Windows' wvsprintf()
262                                            supports floating-point arguments. However,
263                                            I'll leave this code here just in case. */
264                                         if(modifier=='L')
265                                                 *(((long double *)rptr)++) = *(((long double *)winarg)++);
266                                         else *(((double *)rptr)++) = *(((double *)winarg)++);
267                                         break;
268                         }
269                 }
270         }
271         return result;
272 };
273
274
275 /**************************************************************************
276  *                wsprintf        [USER.420]
277  */
278 int wsprintf(LPSTR lpOutput, LPSTR lpFormat, ...)
279 {
280 va_list  valist;
281 int      ArgCnt;
282 va_start(valist, lpFormat);
283 ArgCnt = vsprintf(lpOutput, lpFormat, valist);
284 va_end(valist);
285 return (ArgCnt);
286 }
287
288
289 /*      wvsprintf() is an implementation of vsprintf(). This
290  *      implementation converts the arguments to 32-bit integers and
291  *      calls the standard library function vsprintf().
292  *
293  *      Known shortcomings:
294  *              wvsprintf() doesn't yet convert the arguments back after
295  *              calling vsprintf(), so if Windows implements %n and a
296  *              program depends on it, we're in trouble.
297  */
298
299 int wvsprintf(LPSTR buf, LPSTR format, LPSTR args)
300 {
301         char qualified_fmt[1536];
302         char *newargs;
303         int result;
304
305         /* 1.5K is a safe value as wvsprintf can only handle buffers up to
306         1K and in a worst case such a buffer would look like "%i%i%i..." */
307
308         if(!buf || !format) return 0;
309
310         /* Change the format string so that ints are handled as short by
311            default */
312         UTILITY_qualify(format, qualified_fmt);
313
314         /* Convert agruments to 32-bit values */
315         newargs = UTILITY_convertArgs(format, args);
316
317         result = vsprintf(buf, qualified_fmt, newargs);
318         free(newargs);
319         return result;
320 };