1 /////////////////////////////////////////////////////////////////////////
2 // $Id: osdep.cc 13297 2017-09-14 16:18:12Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // Copyright (C) 2001-2017 The Bochs Project
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Lesser General Public
9 // License as published by the Free Software Foundation; either
10 // version 2 of the License, or (at your option) any later version.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public
18 // License along with this library; if not, write to the Free Software
19 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 /////////////////////////////////////////////////////////////////////////
21
22 //
23 // osdep.cc
24 //
25 // Provide definition of library functions that are missing on various
26 // systems. The only reason this is a .cc file rather than a .c file
27 // is so that it can include bochs.h. Bochs.h includes all the required
28 // system headers, with appropriate #ifdefs for different compilers and
29 // platforms.
30 //
31
32 #include "bochs.h"
33 #include "bxthread.h"
34
35 //////////////////////////////////////////////////////////////////////
36 // Missing library functions. These should work on any platform
37 // that needs them.
38 //////////////////////////////////////////////////////////////////////
39
40 #if !BX_HAVE_SNPRINTF
41 /* XXX use real snprintf */
42 /* if they don't have snprintf, just use sprintf */
bx_snprintf(char * s,size_t maxlen,const char * format,...)43 int bx_snprintf (char *s, size_t maxlen, const char *format, ...)
44 {
45 va_list arg;
46 int done;
47
48 va_start (arg, format);
49 done = vsprintf (s, format, arg);
50 va_end (arg);
51
52 return done;
53 }
54
55 #endif /* !BX_HAVE_SNPRINTF */
56
57 #if !BX_HAVE_VSNPRINTF
bx_vsnprintf(char * s,size_t maxlen,const char * format,va_list arg)58 int bx_vsnprintf (char *s, size_t maxlen, const char *format, va_list arg)
59 {
60 return vsprintf (s, format, arg);
61 }
62 #endif /* !BX_HAVE_VSNPRINTF*/
63
64 #if (!BX_HAVE_STRTOULL && !BX_HAVE_STRTOUQ)
65 /* taken from glibc-2.2.2: strtod.c, and stripped down a lot. There are
66 still a few leftover references to decimal points and exponents,
67 but it works for bases 10 and 16 */
68
69 #define RETURN(val,end) \
70 do { if (endptr != NULL) *endptr = (char *) (end); \
71 return val; } while (0)
72
bx_strtoull(const char * nptr,char ** endptr,int baseignore)73 Bit64u bx_strtoull (const char *nptr, char **endptr, int baseignore)
74 {
75 int negative; /* The sign of the number. */
76 int exponent; /* Exponent of the number. */
77
78 /* Numbers starting `0X' or `0x' have to be processed with base 16. */
79 int base = 10;
80
81 /* Number of bits currently in result value. */
82 int bits;
83
84 /* Running pointer after the last character processed in the string. */
85 const char *cp, *tp;
86 /* Start of significant part of the number. */
87 const char *startp, *start_of_digits;
88 /* Total number of digit and number of digits in integer part. */
89 int dig_no;
90 /* Contains the last character read. */
91 char c;
92
93 Bit64s n = 0;
94 char const *p;
95
96 /* Prepare number representation. */
97 exponent = 0;
98 negative = 0;
99 bits = 0;
100
101 /* Parse string to get maximal legal prefix. We need the number of
102 characters of the integer part, the fractional part and the exponent. */
103 cp = nptr - 1;
104 /* Ignore leading white space. */
105 do
106 c = *++cp;
107 while (isspace (c));
108
109 /* Get sign of the result. */
110 if (c == '-')
111 {
112 negative = 1;
113 c = *++cp;
114 }
115 else if (c == '+')
116 c = *++cp;
117
118 if (c < '0' || c > '9')
119 {
120 /* It is really a text we do not recognize. */
121 RETURN (0, nptr);
122 }
123
124 /* First look whether we are faced with a hexadecimal number. */
125 if (c == '0' && tolower (cp[1]) == 'x')
126 {
127 /* Okay, it is a hexa-decimal number. Remember this and skip
128 the characters. BTW: hexadecimal numbers must not be
129 grouped. */
130 base = 16;
131 cp += 2;
132 c = *cp;
133 }
134
135 /* Record the start of the digits, in case we will check their grouping. */
136 start_of_digits = startp = cp;
137
138 /* Ignore leading zeroes. This helps us to avoid useless computations. */
139 while (c == '0')
140 c = *++cp;
141
142 /* If no other digit but a '0' is found the result is 0.0.
143 Return current read pointer. */
144 if ((c < '0' || c > '9')
145 && (base == 16 && (c < tolower ('a') || c > tolower ('f')))
146 && (base == 16 && (cp == start_of_digits || tolower (c) != 'p'))
147 && (base != 16 && tolower (c) != 'e'))
148 {
149 tp = start_of_digits;
150 /* If TP is at the start of the digits, there was no correctly
151 grouped prefix of the string; so no number found. */
152 RETURN (0, tp == start_of_digits ? (base == 16 ? cp - 1 : nptr) : tp);
153 }
154
155 /* Remember first significant digit and read following characters until the
156 decimal point, exponent character or any non-FP number character. */
157 startp = cp;
158 dig_no = 0;
159 while (1)
160 {
161 if ((c >= '0' && c <= '9')
162 || (base == 16 && tolower (c) >= 'a' && tolower (c) <= 'f'))
163 ++dig_no;
164 else
165 break;
166 c = *++cp;
167 }
168
169 /* The whole string is parsed. Store the address of the next character. */
170 if (endptr)
171 *endptr = (char *) cp;
172
173 if (dig_no == 0)
174 return 0;
175
176 for (p=start_of_digits; p!=cp; p++) {
177 n = n * (Bit64s)base;
178 c = tolower (*p);
179 c = (c >= 'a') ? (10+c-'a') : c-'0';
180 n = n + (Bit64s)c;
181 //printf ("after shifting in digit %c, n is %lld\n", *p, n);
182 }
183 return negative? -n : n;
184 }
185 #endif /* !BX_HAVE_STRTOULL */
186
187 #if BX_TEST_STRTOULL_MAIN
188 /* test driver for strtoull. Do not compile by default. */
main(int argc,char ** argv)189 int main (int argc, char **argv)
190 {
191 char buf[256], *endbuf;
192 long l;
193 Bit64s ll;
194 while (1) {
195 printf ("Enter a long int: ");
196 fgets (buf, sizeof(buf), stdin);
197 l = strtoul (buf, &endbuf, 10);
198 printf ("As a long, %ld\n", l);
199 printf ("Endbuf is at buf[%d]\n", endbuf-buf);
200 ll = bx_strtoull(buf, &endbuf, 10);
201 printf ("As a long long, %lld\n", ll);
202 printf ("Endbuf is at buf[%d]\n", endbuf-buf);
203 }
204 return 0;
205 }
206 #endif /* BX_TEST_STRTOULL_MAIN */
207
208 #if !BX_HAVE_STRDUP
209 /* XXX use real strdup */
bx_strdup(const char * s)210 char *bx_strdup(const char *s)
211 {
212 char *p = malloc (strlen (s) + 1); // allocate memory
213 if (p != NULL)
214 strcpy (p,s); // copy string
215 return p; // return the memory
216 }
217 #endif /* !BX_HAVE_STRDUP */
218
219 #if !BX_HAVE_STRREV
bx_strrev(char * str)220 char *bx_strrev(char *str)
221 {
222 char *p1, *p2;
223
224 if (! str || ! *str)
225 return str;
226
227 for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) {
228 *p1 ^= *p2;
229 *p2 ^= *p1;
230 *p1 ^= *p2;
231 }
232 return str;
233 }
234 #endif /* !BX_HAVE_STRREV */
235
236 #if BX_WITH_MACOS
237 namespace std{extern "C" {char *mktemp(char *tpl);}}
238 #endif
239 #if !BX_HAVE_MKSTEMP
bx_mkstemp(char * tpl)240 int bx_mkstemp(char *tpl)
241 {
242 mktemp(tpl);
243 return ::open(tpl, O_RDWR | O_CREAT | O_TRUNC
244 # ifdef O_BINARY
245 | O_BINARY
246 # endif
247 , S_IWUSR | S_IRUSR | S_IRGRP | S_IWGRP);
248 }
249 #endif // !BX_HAVE_MKSTEMP
250
251 //////////////////////////////////////////////////////////////////////
252 // Missing library functions, implemented for MacOS only
253 //////////////////////////////////////////////////////////////////////
254
255 #if BX_WITH_MACOS
256 // these functions are part of MacBochs. They are not intended to be
257 // portable!
258 #include <Devices.h>
259 #include <Files.h>
260 #include <Disks.h>
261
fd_read(char * buffer,Bit32u offset,Bit32u bytes)262 int fd_read(char *buffer, Bit32u offset, Bit32u bytes)
263 {
264 OSErr err;
265 IOParam param;
266
267 param.ioRefNum=-5; // Refnum of the floppy disk driver
268 param.ioVRefNum=1;
269 param.ioPosMode=fsFromStart;
270 param.ioPosOffset=offset;
271 param.ioBuffer=buffer;
272 param.ioReqCount=bytes;
273 err = PBReadSync((union ParamBlockRec *)(¶m));
274 return param.ioActCount;
275 }
276
fd_write(char * buffer,Bit32u offset,Bit32u bytes)277 int fd_write(char *buffer, Bit32u offset, Bit32u bytes)
278 {
279 OSErr err;
280 IOParam param;
281
282 param.ioRefNum=-5; // Refnum of the floppy disk driver
283 param.ioVRefNum=1;
284 param.ioPosMode=fsFromStart;
285 param.ioPosOffset=offset;
286 param.ioBuffer=buffer;
287 param.ioReqCount=bytes;
288 err = PBWriteSync((union ParamBlockRec *)(¶m));
289 return param.ioActCount;
290 }
291
fd_stat(struct stat * buf)292 int fd_stat(struct stat *buf)
293 {
294 OSErr err;
295 DrvSts status;
296 int result = 0;
297
298 err = DriveStatus(1, &status);
299 if (status.diskInPlace <1 || status.diskInPlace > 2)
300 result = -1;
301 buf->st_mode = S_IFCHR;
302 return result;
303 }
304 #endif /* BX_WITH_MACOS */
305
306 //////////////////////////////////////////////////////////////////////
307 // Missing library functions, implemented for MorphOS only
308 //////////////////////////////////////////////////////////////////////
309
310 #ifdef __MORPHOS__
311 #include <stdio.h>
312 #include <time.h>
313 typedef unsigned int u_int32_t;
314 typedef unsigned short u_int16_t;
315 typedef unsigned char u_int8_t;
316
fseeko(FILE * stream,off_t offset,int whence)317 int fseeko(FILE *stream, off_t offset, int whence)
318 {
319 while(offset != (long) offset)
320 {
321 long pos = (offset < 0) ? LONG_MIN : LONG_MAX;
322 if(fseek(stream, pos, whence) != 0)
323 return -1;
324 offset -= pos;
325 whence = SEEK_CUR;
326 }
327 return fseek(stream, (long) offset, whence);
328 }
329
localtime_r(const time_t * timep,struct tm * result)330 struct tm *localtime_r(const time_t *timep, struct tm *result)
331 {
332 struct tm *s = localtime(timep);
333 if(s == NULL)
334 return NULL;
335 *result = *s;
336 return(result);
337 }
338 #endif
339
340 //////////////////////////////////////////////////////////////////////
341 // New functions to replace library functions
342 // with OS-independent versions
343 //////////////////////////////////////////////////////////////////////
344
345 #if BX_HAVE_REALTIME_USEC
346 #if defined(WIN32)
347 static Bit64u last_realtime64_top = 0;
348 static Bit64u last_realtime64_bottom = 0;
349
bx_get_realtime64_usec(void)350 Bit64u bx_get_realtime64_usec(void)
351 {
352 Bit64u new_bottom = ((Bit64u) GetTickCount()) & BX_CONST64(0x0FFFFFFFF);
353 if(new_bottom < last_realtime64_bottom) {
354 last_realtime64_top += BX_CONST64(0x0000000100000000);
355 }
356 last_realtime64_bottom = new_bottom;
357 Bit64u interim_realtime64 =
358 (last_realtime64_top & BX_CONST64(0xFFFFFFFF00000000)) |
359 (new_bottom & BX_CONST64(0x00000000FFFFFFFF));
360 return interim_realtime64*(BX_CONST64(1000));
361 }
362 #elif BX_HAVE_GETTIMEOFDAY
bx_get_realtime64_usec(void)363 Bit64u bx_get_realtime64_usec(void)
364 {
365 timeval thetime;
366 gettimeofday(&thetime,0);
367 Bit64u mytime;
368 mytime=(Bit64u)thetime.tv_sec*(Bit64u)1000000+(Bit64u)thetime.tv_usec;
369 return mytime;
370 }
371 #endif
372 #endif
373