source: vendor/emx/current/src/os2/utils.c

Last change on this file was 18, checked in by bird, 22 years ago

Initial revision

  • Property cvs2svn:cvs-rev set to 1.1
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 12.6 KB
Line 
1/* utils.c -- Miscellaneous utility functions
2 Copyright (c) 1994-1998 by Eberhard Mattes
3
4This file is part of emx.
5
6emx is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11emx is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with emx; see the file COPYING. If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA.
20
21As special exception, emx.dll can be distributed without source code
22unless it has been changed. If you modify emx.dll, this exception
23no longer applies and you must remove this paragraph from all source
24files for emx.dll. */
25
26
27#include <stdarg.h>
28#define INCL_DOSSEMAPHORES
29#define INCL_DOSMODULEMGR
30#define INCL_DOSMISC
31#define INCL_DOSNLS
32#define INCL_DOSERRORS
33#include <os2emx.h>
34#include <sys/nls.h>
35#include "emxdll.h"
36#include "clib.h"
37
38#define NULL ((void *)0)
39
40#define MAX_EVENT_SEM 16
41#define MAX_MUTEX_SEM 6
42#define MAX_MUXWAIT_SEM 2
43
44/* Mutex semaphore for protecting data in the COMMON32 segment. */
45
46static char const common_mutex_name[] = "/sem32/emx/common.mtx";
47HMTX common_mutex;
48static BYTE common_open;
49
50/* Table of event semaphores. */
51
52static ULONG event_sem_count;
53static HEV event_sem_table[MAX_EVENT_SEM];
54
55/* Table of Mutex semaphores. */
56
57static ULONG mutex_sem_count;
58static HMTX mutex_sem_table[MAX_MUTEX_SEM];
59
60/* Table of MuxWait semaphores. */
61
62static ULONG muxwait_sem_count;
63static HMUX muxwait_sem_table[MAX_MUXWAIT_SEM];
64
65/* Table identifying DBCS lead bytes. Note that our local copy of
66 c.lib no longer contains _nls_ctype_tab to avoid linking in
67 _dbcs_init(). This could also have been achieved by initializing
68 this variable; however, initializing any variable would add
69 non-shared pages to emx.dll, slowing down loading when it's already
70 loaded. */
71
72unsigned char _nls_ctype_tab[256];
73
74
75/* Convert a hexadecimal number consisting of 8 digits, for
76 init_fork() and init2_signal(). Return FALSE on failure. The
77 converted number is stored to *DST. Only lower-case letters are
78 supported. */
79
80int conv_hex8 (const char *s, ULONG *dst)
81{
82 int i;
83 ULONG n;
84 unsigned char c;
85
86 n = 0;
87 for (i = 0; i < 8; ++i)
88 {
89 c = (unsigned char)*s++;
90 if (c >= '0' && c <= '9')
91 c -= '0';
92 else if (c >= 'a' && c <= 'f')
93 c -= 'a' - 10;
94 else
95 return FALSE;
96 n = (n << 4) | c;
97 }
98 *dst = n;
99 return TRUE;
100}
101
102
103/* Convert the unsigned number X to a hexadecimal string of DIGITS
104 digits at DST. */
105
106static void hexn (char *dst, ULONG x, int digits)
107{
108 int i;
109
110 for (i = digits - 1; i >= 0; --i)
111 {
112 dst[i] = "0123456789abcdef"[x & 0x0f];
113 x >>= 4;
114 }
115}
116
117
118/* Convert the unsigned number X to a decimal string at DST. Return the
119 number of characters stored to DST. */
120
121static int udecn (char *dst, unsigned x)
122{
123 int i, j;
124 char digits[12];
125
126 i = 0;
127 do
128 {
129 digits[i++] = (char)(x % 10 + '0');
130 x /= 10;
131 } while (x != 0);
132 for (j = 1; j <= i; ++j)
133 *dst++ = digits[i-j];
134 return i;
135}
136
137
138/* Convert the signed number X to a decimal string at DST. Return the
139 number of characters stored to DST. */
140
141static int decn (char *dst, int x)
142{
143 if (x >= 0)
144 return udecn (dst, (unsigned)x);
145 else
146 {
147 *dst = '-';
148 return udecn (dst+1, (unsigned)(-x)) + 1;
149 }
150}
151
152
153/* Display a string on the error output. */
154
155void otext (const char *msg)
156{
157 ULONG written;
158
159 DosWrite (errout_handle, msg, strlen (msg), &written);
160}
161
162
163/* Handle an unexpected OS/2 error code by beeping and displaying a
164 message which shows the function name (a string pointed to by MSG)
165 and the return code (RC). */
166
167void error (ULONG rc, const char *msg)
168{
169 oprintf ("%s: 0x%.8x ", msg, (unsigned)rc);
170 DosBeep (698, 500);
171}
172
173
174/* Create an unnamed Mutex semaphore and store the handle to *PSEM.
175 Return the OS/2 error code.
176
177 Note: This function is not reentrant! */
178
179ULONG create_mutex_sem (HMTX *psem)
180{
181 ULONG rc;
182
183 /* This should not happen unless someone adds create_mutex_sem()
184 calls without updating MAX_MUTEX_SEM. Note that do_lock_common()
185 also increments mutex_sem_count. */
186
187 if (mutex_sem_count >= MAX_MUTEX_SEM)
188 {
189 oprintf ("Too many Mutex semaphores\r\n");
190 return ERROR_TOO_MANY_SEMAPHORES;
191 }
192
193 rc = DosCreateMutexSem (NULL, psem, 0, 0);
194 if (rc == 0)
195 mutex_sem_table[mutex_sem_count++] = *psem;
196 else
197 error (rc, "DosCreateMutexSem");
198 return rc;
199}
200
201
202/* Request the Mutex semaphore SEM. */
203
204void request_mutex (HMTX sem)
205{
206 ULONG rc;
207
208 do
209 {
210 rc = DosRequestMutexSem (sem, SEM_INDEFINITE_WAIT);
211 } while (rc == ERROR_SEM_OWNER_DIED || rc == ERROR_INTERRUPT);
212}
213
214
215/* Create an unnamed event semaphore and store the semaphore handle to
216 *PSEM. Attribute bits (such as DC_SEM_SHARED) are given in
217 ATTR. Return the OS/2 error code.
218
219 Note: This function is not reentrant! */
220
221ULONG create_event_sem (HEV *psem, ULONG attr)
222{
223 ULONG rc;
224
225 /* This should not happen unless someone adds create_event_sem()
226 calls without updating MAX_EVENT_SEM. */
227
228 if (event_sem_count >= MAX_EVENT_SEM)
229 {
230 oprintf ("Too many event semaphores\r\n");
231 return ERROR_TOO_MANY_SEMAPHORES;
232 }
233
234 rc = DosCreateEventSem (NULL, psem, attr, FALSE);
235 if (rc == 0)
236 event_sem_table[event_sem_count++] = *psem;
237 else
238 error (rc, "DosCreateEventSem");
239 return rc;
240}
241
242
243/* Close an event semaphore.
244
245 Note: This function is not reentrant! */
246
247void close_event_sem (HEV sem)
248{
249 ULONG i;
250
251 for (i = 0; i < event_sem_count; ++i)
252 if (event_sem_table[i] == sem)
253 {
254 event_sem_table[i] = event_sem_table[--event_sem_count];
255 break;
256 }
257 DosCloseEventSem (sem);
258}
259
260
261/* Create an unnamed MuxWait semaphore and store the semaphore handle
262 to *PSEM. Return the OS/2 error code.
263
264 Note: This function is not reentrant! */
265
266ULONG create_muxwait_sem (HMUX *psem, ULONG count, SEMRECORD *array,
267 ULONG attr)
268{
269 ULONG rc;
270
271 /* This should not happen unless someone adds create_muxwait_sem()
272 calls without updating MAX_MUXWAIT_SEM. */
273
274 if (muxwait_sem_count >= MAX_MUXWAIT_SEM)
275 {
276 oprintf ("Too many MuxWait semaphores\r\n");
277 return ERROR_TOO_MANY_SEMAPHORES;
278 }
279
280 rc = DosCreateMuxWaitSem (NULL, psem, count, array, attr);
281 if (rc == 0)
282 muxwait_sem_table[muxwait_sem_count++] = *psem;
283 else
284 error (rc, "DosCreateMuxWaitSem");
285 return rc;
286}
287
288
289/* Close an MuxWait semaphore.
290
291 Note: This function is not reentrant! */
292
293void close_muxwait_sem (HMUX sem)
294{
295 ULONG i;
296
297 for (i = 0; i < muxwait_sem_count; ++i)
298 if (muxwait_sem_table[i] == sem)
299 {
300 muxwait_sem_table[i] = muxwait_sem_table[--muxwait_sem_count];
301 break;
302 }
303 DosCloseMuxWaitSem (sem);
304}
305
306
307/* Close all semaphores. This function is called on termination of
308 emx.dll. */
309
310void term_semaphores (void)
311{
312 while (muxwait_sem_count != 0)
313 DosCloseMuxWaitSem (muxwait_sem_table[--muxwait_sem_count]);
314 while (event_sem_count != 0)
315 DosCloseEventSem (event_sem_table[--event_sem_count]);
316 while (mutex_sem_count != 0)
317 DosCloseMutexSem (mutex_sem_table[--mutex_sem_count]);
318}
319
320
321/* Reset the event semaphore SEM. It's no error if the semaphore is
322 already reset. Return the OS/2 error code. */
323
324ULONG reset_event_sem (HEV sem)
325{
326 ULONG rc, post_count;
327
328 rc = DosResetEventSem (sem, &post_count);
329 if (rc == ERROR_ALREADY_RESET)
330 rc = 0;
331 if (rc != 0)
332 error (rc, "DosResetEventSem");
333 return rc;
334}
335
336
337/* Lock the common data area. This creates or opens the semaphore if
338 not already done. */
339
340void do_lock_common (void)
341{
342 ULONG rc;
343
344 if (!common_open)
345 {
346 common_open = TRUE;
347 rc = DosCreateMutexSem (common_mutex_name, &common_mutex,
348 DC_SEM_SHARED, 0);
349 if (rc == ERROR_DUPLICATE_NAME)
350 rc = DosOpenMutexSem (common_mutex_name, &common_mutex);
351 if (rc == 0 && mutex_sem_count < MAX_MUTEX_SEM)
352 mutex_sem_table[mutex_sem_count++] = common_mutex;
353
354 }
355 request_mutex (common_mutex);
356}
357
358
359/* Terminate the process, returning RC. */
360
361void quit (ULONG rc)
362{
363 kbd_stop ();
364 DosExit (EXIT_PROCESS, rc);
365}
366
367
368/* Return the value of a static system variable. */
369
370ULONG querysysinfo (ULONG index)
371{
372 ULONG value;
373
374 DosQuerySysInfo (index, index, &value, sizeof (value));
375 return value;
376}
377
378
379/* This function implements a subset of ANSI vsprintf(). Supported
380 format specifications are %s, %d, %u and %x, with optional
381 precision. The default precision for %x is currently 8 (no caller
382 depends on this). */
383
384int vsprintf (char *dst, const char *fmt, va_list arg_ptr)
385{
386 char *d;
387 int prec, i;
388 unsigned u;
389 const char *s;
390
391 d = dst;
392 while (*fmt != 0)
393 if (*fmt != '%')
394 *d++ = *fmt++;
395 else if (fmt[1] == '%')
396 *d++ = '%', fmt += 2;
397 else
398 {
399 ++fmt; prec = -1;
400 if (*fmt == '.')
401 {
402 ++fmt; prec = 0;
403 while (*fmt >= '0' && *fmt <= '9')
404 prec = prec * 10 + (*fmt++ - '0');
405 }
406 switch (*fmt)
407 {
408 case 's':
409 s = va_arg (arg_ptr, char *);
410 if (prec == -1) prec = 1 << 30;
411 while (*s != 0 && prec > 0)
412 *d++ = *s++, --prec;
413 break;
414 case 'd':
415 i = va_arg (arg_ptr, int);
416 d += decn (d, i);
417 break;
418 case 'u':
419 u = va_arg (arg_ptr, unsigned);
420 d += udecn (d, u);
421 break;
422 case 'x':
423 u = va_arg (arg_ptr, unsigned);
424 if (prec == -1) prec = 8;
425 hexn (d, u, prec);
426 d += prec;
427 break;
428 }
429 ++fmt;
430 }
431 *d = 0;
432 return d - dst;
433}
434
435
436/* Simple version of sprintf(). See vsprintf() for supported format
437 specifications. */
438
439int sprintf (char *dst, const char *fmt, ...)
440{
441 int result;
442 va_list arg_ptr;
443
444 va_start (arg_ptr, fmt);
445 result = vsprintf (dst, fmt, arg_ptr);
446 va_end (arg_ptr);
447 return result;
448}
449
450
451/* Simple version of printf() with output to error output. See
452 vsprintf() for supported format specifications. */
453
454void oprintf (const char *fmt, ...)
455{
456 va_list arg_ptr;
457 char buf[1024];
458 int len;
459 ULONG written;
460
461 va_start (arg_ptr, fmt);
462 len = vsprintf (buf, fmt, arg_ptr);
463 DosWrite (errout_handle, buf, len, &written);
464 va_end (arg_ptr);
465}
466
467
468/* Mark in _nls_ctype_tab all DBCS lead bytes with _NLS_DBCS_LEAD.
469 Note that this must be compatible to the C library's
470 _nls_is_dbcs_lead macro. Return 0 or an OS/2 error code. */
471
472ULONG get_dbcs_lead (void)
473{
474 ULONG rc;
475 COUNTRYCODE cc;
476 BYTE lead[12];
477 unsigned i, j;
478
479 memset (_nls_ctype_tab, 0, 256);
480 cc.country = 0;
481 cc.codepage = 0;
482 rc = DosQueryDBCSEnv (sizeof (lead), &cc, (PCHAR)lead);
483 for (i = 0; i <= sizeof (lead) - 2; i += 2)
484 {
485 if (lead[i+0] == 0 && lead[i+1] == 0)
486 break;
487 for (j = lead[i+0]; j <= lead[i+1]; ++j)
488 _nls_ctype_tab[j] = _NLS_DBCS_LEAD;
489 }
490 return 0;
491}
492
493
494/* This version of stricmp() does not support locales. */
495
496int stricmp (const char *string1, const char *string2)
497{
498 int d;
499
500 for (;;)
501 {
502 d = tolower ((unsigned char)*string1)
503 - tolower ((unsigned char)*string2);
504 if (d != 0 || *string1 == 0 || *string2 == 0)
505 return d;
506 ++string1; ++string2;
507 }
508}
509
510
511/* Load a module. This is a wrapper for DosLoadModule, saving the
512 coprocessor state. The initialization code of SO32DLL.DLL and
513 TCP32DLL.DLL set the coprocessor control word to 0x362! */
514
515ULONG load_module (const char *mod_name, HMODULE *phmod)
516{
517 char state[108];
518 char obj[9];
519 ULONG rc;
520
521 __asm__ ("fnsave %0" : "=m"(state));
522 rc = DosLoadModule (obj, sizeof (obj), mod_name, phmod);
523 __asm__ ("frstor %0" : "=m"(state));
524 return rc;
525}
526
527
528/* Return TRUE iff the region of memory starting at START is
529 readable. */
530
531int verify_memory (ULONG start, ULONG size)
532{
533 ULONG rc, cb, flag;
534
535 while (size != 0)
536 {
537 cb = size;
538 rc = DosQueryMem ((PVOID)start, &cb, &flag);
539 if (rc != 0)
540 return FALSE;
541 if (!(flag & (PAG_COMMIT|PAG_SHARED)))
542 return FALSE;
543 if (flag & PAG_FREE)
544 return FALSE; /* Should not happen */
545 if (!(flag & PAG_READ))
546 return FALSE;
547 if (cb == 0 || cb > size)
548 return FALSE; /* Should not happen */
549 start += cb; size -= cb;
550 }
551 return TRUE;
552}
Note: See TracBrowser for help on using the repository browser.