/* * gawkmisc.c --- miscellaneous gawk routines that are OS specific. */ /* * Copyright (C) 1986, 1988, 1989, 1991 - 2003 the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Progamming Language. * * GAWK is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * GAWK is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ char quote = '\''; char envsep = ';'; # ifdef DEFPATH char *defpath = DEFPATH; # else char *defpath = ".;c:\\lib\\awk;c:\\gnu\\lib\\awk"; # endif /* the Makefile should define DEFLIBPATH */ char *deflibpath = DEFLIBPATH; #ifdef __EMX__ #include static int _os2_is_abs_path(const char *dirname); static char* _os2_unixroot(const char *path); static const char* _os2_unixroot_path(const char *path); #endif /* gawk_name --- pull out the "gawk" part from how the OS called us */ char * gawk_name(filespec) const char *filespec; { char *p, *q; p = (char *) filespec; /* Sloppy... */ /* OS/2 allows / for directory separator too */ if ((q = strrchr(p, '\\')) != NULL) p = q + 1; if ((q = strrchr(p, '/')) != NULL && (p == NULL || q > p)) /* support mixed d:\foo/bar\gawk.exe */ p = q + 1; if ((q = strchr(p, '.')) != NULL) *q = '\0'; return strlwr(p); } /* * memcpy_long() & memset_ulong() are 32-bit replacements for MSC which * has a 16-bit size_t. */ char * memcpy_ulong (dest, src, l) register char *dest; register const char *src; register unsigned long l; { register char *ret = dest; while (l--) *dest++ = *src++; return ret; } void * memset_ulong(dest, val, l) void *dest; register int val; register unsigned long l; { register char *ret = dest; register char *d = dest; while (l--) *d++ = val; return ((void *) ret); } /* os_arg_fixup --- fixup the command line */ void os_arg_fixup(argcp, argvp) int *argcp; char ***argvp; { #ifdef __EMX__ # ifdef initialize_main initialize_main(argcp, argvp); # else _wildcard(argcp, argvp); _response(argcp, argvp); # endif setvbuf(stdout, NULL, _IOLBF, BUFSIZ); defpath = (char*) _os2_unixroot_path(defpath); #endif /* __EMX__ */ return; } /* os_devopen --- open special per-OS devices */ int os_devopen(name, flag) const char *name; int flag; { #ifdef __EMX__ /* do not use open(name, flag) here !!! */ return -1; #else if (strcmp(name, "/dev/null") == 0) return open("NUL", flag); /* FIXME: */ /* else if (strcmp(name, "/dev/tty") == 0) * return open("???", flag); */ return -1; #endif } /* optimal_bufsize --- determine optimal buffer size */ size_t optimal_bufsize(fd, stb) int fd; struct stat *stb; { /* force all members to zero in case OS doesn't use all of them. */ memset(stb, '\0', sizeof(struct stat)); /* * DOS doesn't have the file system block size in the * stat structure. So we have to make some sort of reasonable * guess. We use stdio's BUFSIZ, since that is what it was * meant for in the first place. */ #define DEFBLKSIZE BUFSIZ if (fstat(fd, stb) == -1) fatal("can't stat fd %d (%s)", fd, strerror(errno)); if (S_ISREG(stb->st_mode) && 0 < stb->st_size && stb->st_size < DEFBLKSIZE) /* small file */ return stb->st_size; return DEFBLKSIZE; } /* ispath --- return true if path has directory components */ int ispath(file) const char *file; { #ifdef __EMX__ return (strpbrk(file, "/\\") != NULL || (toupper(file[0]) >= 'A' && toupper(file[0]) <= 'Z' && file[1] == ':')); #else for (; *file; file++) { switch (*file) { case '/': case '\\': case ':': return 1; } } return 0; #endif } /* isdirpunct --- return true if char is a directory separator */ int isdirpunct(c) int c; { return (strchr(":\\/", c) != NULL); } /* os_close_on_exec --- set close on exec flag, print warning if fails */ void os_close_on_exec(fd, name, what, dir) int fd; const char *name, *what, *dir; { #if ! defined(_MSC_VER) && ! defined(__MINGW32__) # if (defined(__DJGPP__) && (__DJGPP__ > 2 || __DJGPP_MINOR__ >= 4)) || defined __EMX__ if (fd <= 2) /* sanity */ return; if (fcntl(fd, F_SETFD, 1) < 0) warning("%s %s `%s': could not set close-on-exec: %s", what, dir, name, strerror(errno)); # endif #endif } /* os_isdir --- is this an fd on a directory? */ #if ! defined(S_ISDIR) && defined(S_IFDIR) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif int os_isdir(fd) int fd; { struct stat sbuf; return (fstat(fd, &sbuf) == 0 && S_ISDIR(sbuf.st_mode)); } /* os_is_setuid --- true if running setuid root */ int os_is_setuid() { #ifdef __EMX__ long uid, euid; uid = getuid(); euid = geteuid(); return (euid == 0 && euid != uid); #else return 0; #endif } /* os_setbinmode --- set binary mode on file */ #ifdef __DJGPP__ #include #endif static int orig_tty_mode = -1; int os_setbinmode(fd, mode) int fd, mode; { int prev_mode = setmode(fd, mode); #ifdef __DJGPP__ if ((mode & O_BINARY) != 0) __djgpp_set_ctrl_c(1); /* allow to interrupt with Ctrl-C */ #endif /* Save the original tty mode as we found it. */ if (orig_tty_mode == -1 && fd >= 0 && fd <= 2) orig_tty_mode = prev_mode; return prev_mode; } /* os_restore_mode --- restore the original mode of the console device */ void os_restore_mode (fd) int fd; { if (orig_tty_mode != -1) { setmode(fd, orig_tty_mode); } } /* os_isatty --- return true if fd is a tty */ int os_isatty(int fd) { #if defined(__MINGW32__) || defined(_MSC_VER) return (isatty(fd) && lseek(fd, SEEK_CUR, 0) == -1); #else return isatty(fd); #endif } /* files_are_same --- return true if files are identical */ int files_are_same(char *path, SRCFILE *src) { struct stat st; size_t pathlen; char *p, *s; if (stat (path, & st) == 0) { /* If they have a working `stat', honor that. */ if (!(st.st_dev == src->sbuf.st_dev && st.st_ino == src->sbuf.st_ino)) return 0; /* Compare modification times. */ if (st.st_mtime != src->mtime) return 0; /* Compare absolute file names case-insensitively, and treat forward- and back-slashes as equal. */ pathlen = strlen(path); for (p = path, s = src->fullpath; p <= path + pathlen; p++, s++) { if (tolower(*p) != tolower(*s) && !((*p == '/' || *p == '\\') && (*s == '/' || *s == '\\'))) return 0; } return 1; } return 0; } #ifdef __EMX__ # ifndef PATH_SEPARATOR # define PATH_SEPARATOR ';' # endif /* result is 0 if dirname is no absolute path, 1 otherwise */ static int _os2_is_abs_path(const char *dirname) { int result = 0; if (dirname != NULL && dirname[0] != '\0') { /* if dirname contains a valid drive letter like "c:" */ if (((dirname[0] >= 'A' && dirname[0] <= 'Z') || (dirname[0] >= 'a' && dirname[0] <= 'z')) && dirname[1] == ':') dirname += 2; /* remove the drive letter */ if (dirname[0] == '/' || dirname[0] == '\\') result = 1; /* asbolute path */ } return result; } /* path is assumed to be a list of directories separated by PATH_SEPARATOR. This function determines if the first directory of path is on the drive specified by the environment variable UNIXROOT. If it is the case, NULL is returned, otherwise a new directory name is allocated using the drive letter from UNIXROOT and returned as result. If the first directory is a relative path NULL is returned, too. The new directory name is allocated by malloc(). Example (UNIXROOT is set to "e:"): "c:/usr/share" -> "e:/usr/share" "e:/usr/share" -> NULL (already on the $UNIXROOT drive) "/usr/share" -> "e:/usr/share" "." -> NULL (not an absolute path) "usr/share" -> NULL (not an absolute path) "c:usr/share" -> NULL (not an absolute path) "c:/usr/share;d:/etc" -> "e:/usr/share" (only the first directory in path is used) */ static char* _os2_unixroot(const char *path) { static const char *unixroot = NULL; static int unixroot_init = 0; char *result = NULL; if (unixroot_init == 0) { /* get $UNIXROOT only one time */ unixroot = getenv("UNIXROOT"); /* check whether unixroot is valid (must be "x:") */ if (unixroot != NULL) { int drive = toupper(unixroot[0]); if (drive < 'A' || drive > 'Z' || unixroot[1] != ':' || unixroot[2] != '\0') unixroot = NULL; /* unixroot not valid */ } unixroot_init = 1; /* initialized */ } /* note: if unixroot != NULL then it contains a valid drive letter */ if (unixroot != NULL && _os2_is_abs_path(path)) { /* dirname is an absolute path and unixroot is a drive letter, "c:" for example */ size_t old_path_len = strlen(path); /* end points to the first ';' in path or to NULL */ const char *end = strchr(path, PATH_SEPARATOR); /* dir_len is the length of the first directory in path */ size_t dir_len = (end) ? end - path : old_path_len; if (toupper(unixroot[0]) != toupper(path[0]) || path[1] != ':') { /* the first directory of path does not start with the string $UNIXROOT */ if (path[1] == ':') { /* if there is a drive letter remove it */ dir_len -= 2; path += 2; } result = malloc(dir_len + 3); if (result) { /* do nothing if we are out of memory */ result[0] = unixroot[0]; result[1] = unixroot[1]; memcpy(result + 2, path, dir_len); result[dir_len + 2] = '\0'; } } } return result; } /* path is assumed to be a list of directories separated by PATH_SEPARATOR. Every directory is processed. _os2_unixroot() is used to find out whether these directories are on the drive specified by the environment variable UNIXROOT. If this is not the case the same directory on the UNIXROOT drive is added to the end of path. If path is a valid path this function returns a valid path, too. Example ($UNIXROOT is set to "e:"): ".;c:/usr/local;d:/usr/local;d:/etc;e:/etc" -> ".;c:/usr/local;d:/usr/local;d:/etc;e:/etc;e:/usr/local;e:/usr/local;e:/etc" */ static const char* _os2_unixroot_path(const char *path) { char *result = NULL; const char *p = path; unsigned dir_count = 1; if (path == NULL || path[0] == '\0') return NULL; /* empty path */ /* save number of path components in dir_count */ while(*p) { if (*p++ == PATH_SEPARATOR && *p != '\0' && *p != PATH_SEPARATOR) dir_count += 1; } { const char *list[dir_count]; /* list of char pointers */ size_t dir_len[dir_count]; /* the according directory length */ size_t old_path_len = strlen(path); /* the old path length */ size_t total_len; unsigned i = 0; if (path[old_path_len - 1] == PATH_SEPARATOR) /* last character is ';' */ old_path_len--; list[0] = p = path; /* first directory */ while(*p) { if (*p++ == PATH_SEPARATOR && *p != '\0' && *p != PATH_SEPARATOR) list[++i] = p; } /* now list[i] contains the ith directory of path (no 0-terminated strings!!!) */ /* determine the total length for the new path */ total_len = old_path_len; for(i = 0; i < dir_count; i++) { list[i] = _os2_unixroot(list[i]); if (list[i] != NULL) { dir_len[i] = strlen(list[i]); total_len += dir_len[i] + 1; /* one character for ';' or '\0' */ } else dir_len[i] = 0; } /* now list[] contains the according directories on the UNIXROOT drive or NULL total_len contains the total length for the new path */ result = malloc(total_len + 1); if (result) { /* copy the old path and the new directories into the new path */ char *q = result; memcpy(q, path, old_path_len); q += old_path_len; for(i = 0; i < dir_count; i++) { if (dir_len[i] != 0) { *q++ = PATH_SEPARATOR; memcpy(q, list[i], dir_len[i]); q += dir_len[i]; } } *q = '\0'; /* terminating '\0' */ } for(i = 0; i < dir_count; i++) free((void*) list[i]); } return (result) ? (const char*) result : path; } #endif /* __EMX__ */ #ifdef __MINGW32__ extern void *xmalloc (size_t); int setenv (const char *name, const char *value, int rewrite) { char *entry; if (*value == '=') ++value; if (getenv (name) && !rewrite) return 0; entry = xmalloc (strlen (name) + 1 + strlen (value) + 1); strcat (strcat (strcpy (entry, name), "="), value); if (putenv (entry) != 0) { free (entry); return -1; } return 0; } int unsetenv (const char *name) { if (!name || !*name || strchr (name, '=') != NULL) return -1; return setenv (name, "", 1); } #include int usleep(unsigned int usec) { double msecf = usec / 1000.0; Sleep ((DWORD)msecf); return usec - msecf * 1000 < 0 ? 0 : (int)(usec - msecf * 1000); } /* The implementation of wctob in the MS runtime is problematic because it doesn't allow to distinguish between WEOF and 0xff, due to integer sign extension. It also causes failures in dfa.c when characters with the 8th bit set are involved. This replacement version fixes that. */ #include int wctob (wint_t wc) { char buf[64]; if (!(MB_CUR_MAX <= sizeof (buf))) abort (); /* Handle the case where WEOF is a value that does not fit in a wchar_t. */ if (wc == (wchar_t)wc) if (wctomb (buf, (wchar_t)wc) == 1) return (unsigned char) buf[0]; return EOF; } #endif /* __MINGW32__ */ #ifdef __DJGPP__ int unsetenv (const char *name) { if (!name || !*name || strchr (name, '=') != NULL) return -1; return putenv (name); } #endif /* __DJGPP__ */