382
# ifndef PATH_SEPARATOR
383
# define PATH_SEPARATOR ';'
386
/* result is 0 if dirname is no absolute path, 1 otherwise */
389
_os2_is_abs_path(const char *dirname)
392
if (dirname != NULL && dirname[0] != '\0') {
393
/* if dirname contains a valid drive letter like "c:" */
394
if (((dirname[0] >= 'A' && dirname[0] <= 'Z') || (dirname[0] >= 'a' && dirname[0] <= 'z'))
395
&& dirname[1] == ':') dirname += 2; /* remove the drive letter */
397
if (dirname[0] == '/' || dirname[0] == '\\') result = 1; /* asbolute path */
404
/* path is assumed to be a list of directories separated by PATH_SEPARATOR.
405
This function determines if the first directory of path is on the
406
drive specified by the environment variable UNIXROOT.
407
If it is the case, NULL is returned, otherwise a new directory name
408
is allocated using the drive letter from UNIXROOT and returned as result.
409
If the first directory is a relative path NULL is returned, too.
410
The new directory name is allocated by malloc().
411
Example (UNIXROOT is set to "e:"):
412
"c:/usr/share" -> "e:/usr/share"
413
"e:/usr/share" -> NULL (already on the $UNIXROOT drive)
414
"/usr/share" -> "e:/usr/share"
415
"." -> NULL (not an absolute path)
416
"usr/share" -> NULL (not an absolute path)
417
"c:usr/share" -> NULL (not an absolute path)
418
"c:/usr/share;d:/etc" -> "e:/usr/share" (only the first directory in path is used) */
421
_os2_unixroot(const char *path)
423
static const char *unixroot = NULL;
424
static int unixroot_init = 0;
427
if (unixroot_init == 0) {
428
/* get $UNIXROOT only one time */
429
unixroot = getenv("UNIXROOT");
431
/* check whether unixroot is valid (must be "x:") */
432
if (unixroot != NULL) {
433
int drive = toupper(unixroot[0]);
434
if (drive < 'A' || drive > 'Z' || unixroot[1] != ':' || unixroot[2] != '\0')
435
unixroot = NULL; /* unixroot not valid */
438
unixroot_init = 1; /* initialized */
441
/* note: if unixroot != NULL then it contains a valid drive letter */
442
if (unixroot != NULL && _os2_is_abs_path(path)) {
443
/* dirname is an absolute path and unixroot is a drive letter, "c:" for example */
444
size_t old_path_len = strlen(path);
446
/* end points to the first ';' in path or to NULL */
447
const char *end = strchr(path, PATH_SEPARATOR);
449
/* dir_len is the length of the first directory in path */
450
size_t dir_len = (end) ? end - path : old_path_len;
452
if (toupper(unixroot[0]) != toupper(path[0]) || path[1] != ':') {
453
/* the first directory of path does not start with the string $UNIXROOT */
454
if (path[1] == ':') {
455
/* if there is a drive letter remove it */
460
result = malloc(dir_len + 3);
461
if (result) { /* do nothing if we are out of memory */
462
result[0] = unixroot[0];
463
result[1] = unixroot[1];
464
memcpy(result + 2, path, dir_len);
465
result[dir_len + 2] = '\0';
472
/* path is assumed to be a list of directories separated by PATH_SEPARATOR.
473
Every directory is processed. _os2_unixroot() is used to find out whether
474
these directories are on the drive specified by the environment variable
475
UNIXROOT. If this is not the case the same directory on the UNIXROOT drive
476
is added to the end of path. If path is a valid path this function returns a valid path, too.
477
Example ($UNIXROOT is set to "e:"):
478
".;c:/usr/local;d:/usr/local;d:/etc;e:/etc"
479
-> ".;c:/usr/local;d:/usr/local;d:/etc;e:/etc;e:/usr/local;e:/usr/local;e:/etc" */
482
_os2_unixroot_path(const char *path)
485
const char *p = path;
486
unsigned dir_count = 1;
488
if (path == NULL || path[0] == '\0') return NULL; /* empty path */
490
/* save number of path components in dir_count */
492
if (*p++ == PATH_SEPARATOR && *p != '\0' && *p != PATH_SEPARATOR)
497
const char *list[dir_count]; /* list of char pointers */
498
size_t dir_len[dir_count]; /* the according directory length */
499
size_t old_path_len = strlen(path); /* the old path length */
503
if (path[old_path_len - 1] == PATH_SEPARATOR) /* last character is ';' */
506
list[0] = p = path; /* first directory */
509
if (*p++ == PATH_SEPARATOR && *p != '\0' && *p != PATH_SEPARATOR)
512
/* now list[i] contains the ith directory of path (no 0-terminated strings!!!) */
514
/* determine the total length for the new path */
515
total_len = old_path_len;
517
for(i = 0; i < dir_count; i++) {
518
list[i] = _os2_unixroot(list[i]);
519
if (list[i] != NULL) {
520
dir_len[i] = strlen(list[i]);
521
total_len += dir_len[i] + 1; /* one character for ';' or '\0' */
525
/* now list[] contains the according directories on the UNIXROOT drive or NULL
526
total_len contains the total length for the new path */
527
result = malloc(total_len + 1);
530
/* copy the old path and the new directories into the new path */
532
memcpy(q, path, old_path_len);
535
for(i = 0; i < dir_count; i++) {
536
if (dir_len[i] != 0) {
537
*q++ = PATH_SEPARATOR;
538
memcpy(q, list[i], dir_len[i]);
543
*q = '\0'; /* terminating '\0' */
546
for(i = 0; i < dir_count; i++) free((void*) list[i]);
549
return (result) ? (const char*) result : path;
288
555
extern void *xmalloc (size_t);
290
/* Emulate setenv and unsetenv.
292
Note: this is only actually used in MinGW64 builds, since
293
mingw.org's MinGW has these functions as inlines in stdlib.h since
296
558
setenv (const char *name, const char *value, int rewrite)
365
/* On Posix systems, 'setlocale' looks at LC_* variables in the
366
environment, and Gawk users might expect that on Windows as well.
367
The replacement implementation below does that, and also fixes a
368
few additional quirks with locales on Windows. */
370
lc_var (int category)
372
static const char *loc_name[LC_MAX - LC_MIN + 1] = {
373
"LC_ALL", "LC_COLLATE", "LC_CTYPE", "LC_MONETARY", "LC_NUMERIC", "LC_TIME"
376
/* This function assumes LC_* categories are small numbers between 0
377
and 5, as shown above, so if that changes at some point, complain
379
if (LC_ALL != 0 || LC_CTYPE != 2 || LC_TIME != 5)
381
/* Ensured by the caller, so should never happen. */
382
if (category < LC_MIN || category > LC_MAX)
384
return loc_name[category];
388
w32_setlocale (int category, const char *value)
390
const char *new_locale = value;
392
if (LC_MIN <= category && category <= LC_MAX
393
&& value && *value == '\0')
395
const char *lc_val = getenv ("LC_ALL");
398
lc_val = getenv (lc_var (category));
400
lc_val = getenv ("LANG");
405
/* If VALUE includes a codeset, i.e. a Windows codepage number, we
406
must also set the LC_CTYPE locale to the same value, because
407
LC_CTYPE is the only category which is documented to be able to
408
change the codepage. */
409
if (category != LC_ALL && category != LC_CTYPE)
411
const char *p = strchr (new_locale, '.');
413
if (p && isdigit (p[1]))
414
setlocale (LC_CTYPE, new_locale);
416
return setlocale (category, new_locale);
419
/* Replacement for the missing nl_langinfo. Only CODESET is currently
421
#include <langinfo.h>
424
nl_langinfo (int item)
430
/* Shamelessly stolen from Gnulib's nl_langinfo.c. */
431
static char buf[2 + 10 + 1];
432
char const *locale = setlocale (LC_CTYPE, NULL);
437
if (locale && locale[0])
439
/* If the locale name contains an encoding after the
441
char *dot = strchr (locale, '.');
445
/* Look for the possible @... trailer and remove it,
447
char *codeset_start = dot + 1;
448
char const *modifier = strchr (codeset_start, '@');
451
codeset = codeset_start;
454
codesetlen = modifier - codeset_start;
455
if (codesetlen < sizeof buf)
457
codeset = memcpy (buf, codeset_start, codesetlen);
458
codeset[codesetlen] = '\0';
463
/* If setlocale is successful, it returns the number of the
464
codepage, as a string. Otherwise, fall back on Windows
465
API GetACP, which returns the locale's codepage as a
466
number (although this doesn't change according to what
467
the 'setlocale' call specified). Either way, prepend
468
"CP" to make it a valid codeset name. */
469
codesetlen = strlen (codeset);
470
if (0 < codesetlen && codesetlen < sizeof buf - 2)
471
memmove (buf + 2, codeset, codesetlen + 1);
473
sprintf (buf + 2, "%u", GetACP ());
474
codeset = memcpy (buf, "CP", 2);
483
/* Convert a Unicode codepoint UC to the corresponding multibyte string
484
STR in the current system codepage. Return the number of bytes in
485
STR, or -1 if the codepage does not support UC. */
486
size_t w32_wc_to_lc (int uc, char *str)
488
BOOL used_default = FALSE;
495
/* Convert UC to UTF-16. */
501
wc[0] = ((uc - 0x10000) >> 10) + 0xD800; /* high surrogate */
502
wc[1] = (uc & 0x3FF) + 0xDC00; /* low surrogate */
504
/* WideCharToMultiByte returns the number of bytes, including the
505
terminating null, written to STR on success, zero on falure. */
506
retval = WideCharToMultiByte (CP_ACP, 0, wc, -1,
507
str, MB_LEN_MAX, NULL, &used_default);
508
if (!retval || used_default)
510
return retval - 1; /* exclude the terminating null */
514
620
* On MS-Windows with MinGW, execvp causes the shell and the re-exec'ed
515
621
* dgawk to compete for the keyboard input.
517
623
* This will need work if we ever need a real version of execvp.
519
int w32_execvp(const char *file, char **argv)
625
int execvp(const char *file, const char *const *argv)
521
627
if (_spawnvp(_P_WAIT, file, (const char * const *)argv) != -1)
522
628
exit(EXIT_SUCCESS);
744
849
#endif /* HAVE_SOCKETS */
746
/* Translate abnormal exit status of Windows programs into the signal
747
that terminated the program. This is required to support scm_kill
752
struct signal_and_status {
757
static const struct signal_and_status sigtbl[] = {
758
{SIGSEGV, 0xC0000005}, /* access to invalid address */
759
{SIGSEGV, 0xC0000008}, /* invalid handle */
760
{SIGILL, 0xC000001D}, /* illegal instruction */
761
{SIGILL, 0xC0000025}, /* non-continuable instruction */
762
{SIGSEGV, 0xC000008C}, /* array bounds exceeded */
763
{SIGFPE, 0xC000008D}, /* float denormal */
764
{SIGFPE, 0xC000008E}, /* float divide by zero */
765
{SIGFPE, 0xC000008F}, /* float inexact */
766
{SIGFPE, 0xC0000090}, /* float invalid operation */
767
{SIGFPE, 0xC0000091}, /* float overflow */
768
{SIGFPE, 0xC0000092}, /* float stack check */
769
{SIGFPE, 0xC0000093}, /* float underflow */
770
{SIGFPE, 0xC0000094}, /* integer divide by zero */
771
{SIGFPE, 0xC0000095}, /* integer overflow */
772
{SIGILL, 0xC0000096}, /* privileged instruction */
773
{SIGSEGV, 0xC00000FD}, /* stack overflow */
774
{SIGTERM, 0xC000013A}, /* Ctrl-C exit */
779
w32_status_to_termsig (unsigned status)
783
for (i = 0; i < sizeof (sigtbl) / sizeof (sigtbl[0]); i++)
784
if (status == sigtbl[i].status)
785
return sigtbl[i].sig;
790
/* Emulate the missing strsignal. */
792
strsignal (int signo)
811
return "Unknown signal";
816
os_maybe_set_errno (void)
818
if (errno == 0 || errno == EINVAL) {
819
DWORD w32err = GetLastError ();
823
/* When stdout is redirected to a pipe, and the program that
824
reads the pipe (e.g., a pager) exits, Windows doesn't set
825
errno to a useful value. Help it DTRT. */
827
case ERROR_PIPE_BUSY:
829
case ERROR_PIPE_NOT_CONNECTED:
851
#endif /* __MINGW32__ */
853
#if defined(__DJGPP__) || defined(__MINGW32__)
840
856
init_sockets(void)
842
#if defined(HAVE_SOCKETS)
843
859
WSADATA winsockData;