diff options
Diffstat (limited to 'compat')
-rw-r--r-- | compat/README | 8 | ||||
-rw-r--r-- | compat/dirent.h | 23 | ||||
-rw-r--r-- | compat/dirent2.h | 59 | ||||
-rw-r--r-- | compat/dlfcn.h | 65 | ||||
-rw-r--r-- | compat/fixstrtod.c | 38 | ||||
-rw-r--r-- | compat/float.h | 16 | ||||
-rw-r--r-- | compat/gettod.c | 32 | ||||
-rw-r--r-- | compat/limits.h | 24 | ||||
-rw-r--r-- | compat/opendir.c | 108 | ||||
-rw-r--r-- | compat/stdlib.h | 45 | ||||
-rw-r--r-- | compat/strftime.c | 385 | ||||
-rw-r--r-- | compat/string.h | 66 | ||||
-rw-r--r-- | compat/strncasecmp.c | 142 | ||||
-rw-r--r-- | compat/strstr.c | 68 | ||||
-rw-r--r-- | compat/strtod.c | 257 | ||||
-rw-r--r-- | compat/strtol.c | 83 | ||||
-rw-r--r-- | compat/strtoul.c | 183 | ||||
-rw-r--r-- | compat/tclErrno.h | 100 | ||||
-rw-r--r-- | compat/tmpnam.c | 42 | ||||
-rw-r--r-- | compat/unistd.h | 84 | ||||
-rw-r--r-- | compat/waitpid.c | 170 |
21 files changed, 1998 insertions, 0 deletions
diff --git a/compat/README b/compat/README new file mode 100644 index 0000000..4ed8e54 --- /dev/null +++ b/compat/README @@ -0,0 +1,8 @@ +This directory contains various header and code files that are +used make Tcl compatible with various releases of UNIX and UNIX-like +systems. Typically, files from this directory are used to compile +Tcl when a system doesn't contain the corresponding files or when +they are known to be incorrect. When the whole world becomes POSIX- +compliant this directory should be unnecessary. + +sccsid = SCCS: @(#) README 1.3 96/02/16 08:56:51 diff --git a/compat/dirent.h b/compat/dirent.h new file mode 100644 index 0000000..081376b --- /dev/null +++ b/compat/dirent.h @@ -0,0 +1,23 @@ +/* + * dirent.h -- + * + * This file is a replacement for <dirent.h> in systems that + * support the old BSD-style <sys/dir.h> with a "struct direct". + * + * Copyright (c) 1991 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) dirent.h 1.4 96/02/15 14:43:50 + */ + +#ifndef _DIRENT +#define _DIRENT + +#include <sys/dir.h> + +#define dirent direct + +#endif /* _DIRENT */ diff --git a/compat/dirent2.h b/compat/dirent2.h new file mode 100644 index 0000000..585a7e8 --- /dev/null +++ b/compat/dirent2.h @@ -0,0 +1,59 @@ +/* + * dirent.h -- + * + * Declarations of a library of directory-reading procedures + * in the POSIX style ("struct dirent"). + * + * Copyright (c) 1991 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) dirent2.h 1.4 96/02/15 14:43:51 + */ + +#ifndef _DIRENT +#define _DIRENT + +#ifndef _TCL +#include <tcl.h> +#endif + +/* + * Dirent structure, which holds information about a single + * directory entry. + */ + +#define MAXNAMLEN 255 +#define DIRBLKSIZ 512 + +struct dirent { + long d_ino; /* Inode number of entry */ + short d_reclen; /* Length of this record */ + short d_namlen; /* Length of string in d_name */ + char d_name[MAXNAMLEN + 1]; /* Name must be no longer than this */ +}; + +/* + * State that keeps track of the reading of a directory (clients + * should never look inside this structure; the fields should + * only be accessed by the library procedures). + */ + +typedef struct _dirdesc { + int dd_fd; + long dd_loc; + long dd_size; + char dd_buf[DIRBLKSIZ]; +} DIR; + +/* + * Procedures defined for reading directories: + */ + +extern void closedir _ANSI_ARGS_((DIR *dirp)); +extern DIR * opendir _ANSI_ARGS_((char *name)); +extern struct dirent * readdir _ANSI_ARGS_((DIR *dirp)); + +#endif /* _DIRENT */ diff --git a/compat/dlfcn.h b/compat/dlfcn.h new file mode 100644 index 0000000..cf02fb9 --- /dev/null +++ b/compat/dlfcn.h @@ -0,0 +1,65 @@ +/* + * dlfcn.h -- + * + * This file provides a replacement for the header file "dlfcn.h" + * on systems where dlfcn.h is missing. It's primary use is for + * AIX, where Tcl emulates the dl library. + * + * This file is subject to the following copyright notice, which is + * different from the notice used elsewhere in Tcl but rougly + * equivalent in meaning. + * + * Copyright (c) 1992,1993,1995,1996, Jens-Uwe Mager, Helios Software GmbH + * Not derived from licensed software. + * + * Permission is granted to freely use, copy, modify, and redistribute + * this software, provided that the author is not construed to be liable + * for any results of using the software, alterations are clearly marked + * as such, and this notice is not modified. + * + * SCCS: @(#) dlfcn.h 1.4 96/09/17 09:05:59 + */ + +/* + * @(#)dlfcn.h 1.4 revision of 95/04/25 09:36:52 + * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH + * 30159 Hannover, Germany + */ + +#ifndef __dlfcn_h__ +#define __dlfcn_h__ + +#ifndef _TCL +#include <tcl.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Mode flags for the dlopen routine. + */ +#define RTLD_LAZY 1 /* lazy function call binding */ +#define RTLD_NOW 2 /* immediate function call binding */ +#define RTLD_GLOBAL 0x100 /* allow symbols to be global */ + +/* + * To be able to intialize, a library may provide a dl_info structure + * that contains functions to be called to initialize and terminate. + */ +struct dl_info { + void (*init) _ANSI_ARGS_((void)); + void (*fini) _ANSI_ARGS_((void)); +}; + +VOID *dlopen _ANSI_ARGS_((const char *path, int mode)); +VOID *dlsym _ANSI_ARGS_((void *handle, const char *symbol)); +char *dlerror _ANSI_ARGS_((void)); +int dlclose _ANSI_ARGS_((void *handle)); + +#ifdef __cplusplus +} +#endif + +#endif /* __dlfcn_h__ */ diff --git a/compat/fixstrtod.c b/compat/fixstrtod.c new file mode 100644 index 0000000..2655767 --- /dev/null +++ b/compat/fixstrtod.c @@ -0,0 +1,38 @@ +/* + * fixstrtod.c -- + * + * Source code for the "fixstrtod" procedure. This procedure is + * used in place of strtod under Solaris 2.4, in order to fix + * a bug where the "end" pointer gets set incorrectly. + * + * Copyright (c) 1995 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) fixstrtod.c 1.5 96/02/15 12:08:21 + */ + +#include <stdio.h> + +#undef strtod + +/* + * Declare strtod explicitly rather than including stdlib.h, since in + * somes systems (e.g. SunOS 4.1.4) stdlib.h doesn't declare strtod. + */ + +extern double strtod(); + +double +fixstrtod(string, endPtr) + char *string; + char **endPtr; +{ + double d; + d = strtod(string, endPtr); + if ((endPtr != NULL) && (*endPtr != string) && ((*endPtr)[-1] == 0)) { + *endPtr -= 1; + } + return d; +} diff --git a/compat/float.h b/compat/float.h new file mode 100644 index 0000000..06db4fd --- /dev/null +++ b/compat/float.h @@ -0,0 +1,16 @@ +/* + * float.h -- + * + * This is a dummy header file to #include in Tcl when there + * is no float.h in /usr/include. Right now this file is empty: + * Tcl contains #ifdefs to deal with the lack of definitions; + * all it needs is for the #include statement to work. + * + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) float.h 1.3 96/02/15 14:43:52 + */ diff --git a/compat/gettod.c b/compat/gettod.c new file mode 100644 index 0000000..4110262 --- /dev/null +++ b/compat/gettod.c @@ -0,0 +1,32 @@ +/* + * gettod.c -- + * + * This file provides the gettimeofday function on systems + * that only have the System V ftime function. + * + * Copyright (c) 1995 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) gettod.c 1.2 96/02/15 12:08:26 + */ + +#include "tcl.h" +#include "tclPort.h" +#include <sys/timeb.h> + +#undef timezone + +int +gettimeofday(tp, tz) +struct timeval *tp; +struct timezone *tz; +{ + struct timeb t; + ftime(&t); + tp->tv_sec = t.time; + tp->tv_usec = t. millitm * 1000; + return 0; +} + diff --git a/compat/limits.h b/compat/limits.h new file mode 100644 index 0000000..ec7a909 --- /dev/null +++ b/compat/limits.h @@ -0,0 +1,24 @@ +/* + * limits.h -- + * + * This is a dummy header file to #include in Tcl when there + * is no limits.h in /usr/include. There are only a few + * definitions here; also see tclPort.h, which already + * #defines some of the things here if they're not arleady + * defined. + * + * Copyright (c) 1991 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) limits.h 1.8 96/07/08 18:00:13 + */ + +#define LONG_MIN 0x80000000 +#define LONG_MAX 0x7fffffff +#define INT_MIN 0x80000000 +#define INT_MAX 0x7fffffff +#define SHRT_MIN 0x8000 +#define SHRT_MAX 0x7fff diff --git a/compat/opendir.c b/compat/opendir.c new file mode 100644 index 0000000..b1a47ff --- /dev/null +++ b/compat/opendir.c @@ -0,0 +1,108 @@ +/* + * opendir.c -- + * + * This file provides dirent-style directory-reading procedures + * for V7 Unix systems that don't have such procedures. The + * origin of this code is unclear, but it seems to have come + * originally from Larry Wall. + * + * + * SCCS: @(#) opendir.c 1.3 96/02/15 12:08:21 + */ + +#include "tclInt.h" +#include "tclPort.h" + +#undef DIRSIZ +#define DIRSIZ(dp) \ + ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) + +/* + * open a directory. + */ +DIR * +opendir(name) +char *name; +{ + register DIR *dirp; + register int fd; + char *myname; + + myname = ((*name == '\0') ? "." : name); + if ((fd = open(myname, 0, 0)) == -1) + return NULL; + if ((dirp = (DIR *)ckalloc(sizeof(DIR))) == NULL) { + close (fd); + return NULL; + } + dirp->dd_fd = fd; + dirp->dd_loc = 0; + return dirp; +} + +/* + * read an old style directory entry and present it as a new one + */ +#ifndef pyr +#define ODIRSIZ 14 + +struct olddirect { + ino_t od_ino; + char od_name[ODIRSIZ]; +}; +#else /* a Pyramid in the ATT universe */ +#define ODIRSIZ 248 + +struct olddirect { + long od_ino; + short od_fill1, od_fill2; + char od_name[ODIRSIZ]; +}; +#endif + +/* + * get next entry in a directory. + */ +struct dirent * +readdir(dirp) +register DIR *dirp; +{ + register struct olddirect *dp; + static struct dirent dir; + + for (;;) { + if (dirp->dd_loc == 0) { + dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, + DIRBLKSIZ); + if (dirp->dd_size <= 0) + return NULL; + } + if (dirp->dd_loc >= dirp->dd_size) { + dirp->dd_loc = 0; + continue; + } + dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); + dirp->dd_loc += sizeof(struct olddirect); + if (dp->od_ino == 0) + continue; + dir.d_ino = dp->od_ino; + strncpy(dir.d_name, dp->od_name, ODIRSIZ); + dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ + dir.d_namlen = strlen(dir.d_name); + dir.d_reclen = DIRSIZ(&dir); + return (&dir); + } +} + +/* + * close a directory. + */ +void +closedir(dirp) +register DIR *dirp; +{ + close(dirp->dd_fd); + dirp->dd_fd = -1; + dirp->dd_loc = 0; + ckfree((char *) dirp); +} diff --git a/compat/stdlib.h b/compat/stdlib.h new file mode 100644 index 0000000..059ea29 --- /dev/null +++ b/compat/stdlib.h @@ -0,0 +1,45 @@ +/* + * stdlib.h -- + * + * Declares facilities exported by the "stdlib" portion of + * the C library. This file isn't complete in the ANSI-C + * sense; it only declares things that are needed by Tcl. + * This file is needed even on many systems with their own + * stdlib.h (e.g. SunOS) because not all stdlib.h files + * declare all the procedures needed here (such as strtod). + * + * Copyright (c) 1991 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) stdlib.h 1.10 96/02/15 14:43:54 + */ + +#ifndef _STDLIB +#define _STDLIB + +#include <tcl.h> + +extern void abort _ANSI_ARGS_((void)); +extern double atof _ANSI_ARGS_((CONST char *string)); +extern int atoi _ANSI_ARGS_((CONST char *string)); +extern long atol _ANSI_ARGS_((CONST char *string)); +extern char * calloc _ANSI_ARGS_((unsigned int numElements, + unsigned int size)); +extern void exit _ANSI_ARGS_((int status)); +extern int free _ANSI_ARGS_((char *blockPtr)); +extern char * getenv _ANSI_ARGS_((CONST char *name)); +extern char * malloc _ANSI_ARGS_((unsigned int numBytes)); +extern void qsort _ANSI_ARGS_((VOID *base, int n, int size, + int (*compar)(CONST VOID *element1, CONST VOID + *element2))); +extern char * realloc _ANSI_ARGS_((char *ptr, unsigned int numBytes)); +extern double strtod _ANSI_ARGS_((CONST char *string, char **endPtr)); +extern long strtol _ANSI_ARGS_((CONST char *string, char **endPtr, + int base)); +extern unsigned long strtoul _ANSI_ARGS_((CONST char *string, + char **endPtr, int base)); + +#endif /* _STDLIB */ diff --git a/compat/strftime.c b/compat/strftime.c new file mode 100644 index 0000000..7c72557 --- /dev/null +++ b/compat/strftime.c @@ -0,0 +1,385 @@ +/* + * strftime.c -- + * + * This file contains a modified version of the BSD 4.4 strftime + * function. + * + * This file is a modified version of the strftime.c file from the BSD 4.4 + * source. See the copyright notice below for details on redistribution + * restrictions. The "license.terms" file does not apply to this file. + * + * SCCS: @(#) strftime.c 1.4 97/08/07 17:17:02 + */ + +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)strftime.c 5.11 (Berkeley) 2/24/91";*/ +static char *rcsid = "$Id: strftime.c,v 1.1 1998/03/26 14:46:31 rjohnson Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <time.h> +#include <string.h> +#include <locale.h> +#include "tclInt.h" +#include "tclPort.h" + +#define TM_YEAR_BASE 1900 + +typedef struct { + const char *abday[7]; + const char *day[7]; + const char *abmon[12]; + const char *mon[12]; + const char *am_pm[2]; + const char *d_t_fmt; + const char *d_fmt; + const char *t_fmt; + const char *t_fmt_ampm; +} _TimeLocale; + +static const _TimeLocale _DefaultTimeLocale = +{ + { + "Sun","Mon","Tue","Wed","Thu","Fri","Sat", + }, + { + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", + "Friday", "Saturday" + }, + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }, + { + "January", "February", "March", "April", "May", "June", "July", + "August", "September", "October", "November", "December" + }, + { + "AM", "PM" + }, + "%a %b %d %H:%M:%S %Y", + "%m/%d/%y", + "%H:%M:%S", + "%I:%M:%S %p" +}; + +static const _TimeLocale *_CurrentTimeLocale = &_DefaultTimeLocale; + +static size_t gsize; +static char *pt; +static int _add _ANSI_ARGS_((const char* str)); +static int _conv _ANSI_ARGS_((int n, int digits, int pad)); +static int _secs _ANSI_ARGS_((const struct tm *t)); +static size_t _fmt _ANSI_ARGS_((const char *format, + const struct tm *t)); + +size_t +TclStrftime(s, maxsize, format, t) + char *s; + size_t maxsize; + const char *format; + const struct tm *t; +{ + tzset(); + + pt = s; + if ((gsize = maxsize) < 1) + return(0); + if (_fmt(format, t)) { + *pt = '\0'; + return(maxsize - gsize); + } + return(0); +} + +#define SUN_WEEK(t) (((t)->tm_yday + 7 - \ + ((t)->tm_wday)) / 7) +#define MON_WEEK(t) (((t)->tm_yday + 7 - \ + ((t)->tm_wday ? (t)->tm_wday - 1 : 6)) / 7) + +static size_t +_fmt(format, t) + const char *format; + const struct tm *t; +{ + for (; *format; ++format) { + if (*format == '%') { + ++format; + if (*format == 'E') { + /* Alternate Era */ + ++format; + } else if (*format == 'O') { + /* Alternate numeric symbols */ + ++format; + } + switch(*format) { + case '\0': + --format; + break; + case 'A': + if (t->tm_wday < 0 || t->tm_wday > 6) + return(0); + if (!_add(_CurrentTimeLocale->day[t->tm_wday])) + return(0); + continue; + case 'a': + if (t->tm_wday < 0 || t->tm_wday > 6) + return(0); + if (!_add(_CurrentTimeLocale->abday[t->tm_wday])) + return(0); + continue; + case 'B': + if (t->tm_mon < 0 || t->tm_mon > 11) + return(0); + if (!_add(_CurrentTimeLocale->mon[t->tm_mon])) + return(0); + continue; + case 'b': + case 'h': + if (t->tm_mon < 0 || t->tm_mon > 11) + return(0); + if (!_add(_CurrentTimeLocale->abmon[t->tm_mon])) + return(0); + continue; + case 'C': + if (!_conv((t->tm_year + TM_YEAR_BASE) / 100, + 2, '0')) + return(0); + continue; + case 'c': + if (!_fmt(_CurrentTimeLocale->d_t_fmt, t)) + return(0); + continue; + case 'D': + if (!_fmt("%m/%d/%y", t)) + return(0); + continue; + case 'd': + if (!_conv(t->tm_mday, 2, '0')) + return(0); + continue; + case 'e': + if (!_conv(t->tm_mday, 2, ' ')) + return(0); + continue; + case 'H': + if (!_conv(t->tm_hour, 2, '0')) + return(0); + continue; + case 'I': + if (!_conv(t->tm_hour % 12 ? + t->tm_hour % 12 : 12, 2, '0')) + return(0); + continue; + case 'j': + if (!_conv(t->tm_yday + 1, 3, '0')) + return(0); + continue; + case 'k': + if (!_conv(t->tm_hour, 2, ' ')) + return(0); + continue; + case 'l': + if (!_conv(t->tm_hour % 12 ? + t->tm_hour % 12: 12, 2, ' ')) + return(0); + continue; + case 'M': + if (!_conv(t->tm_min, 2, '0')) + return(0); + continue; + case 'm': + if (!_conv(t->tm_mon + 1, 2, '0')) + return(0); + continue; + case 'n': + if (!_add("\n")) + return(0); + continue; + case 'p': + if (!_add(_CurrentTimeLocale->am_pm[t->tm_hour >= 12])) + return(0); + continue; + case 'R': + if (!_fmt("%H:%M", t)) + return(0); + continue; + case 'r': + if (!_fmt(_CurrentTimeLocale->t_fmt_ampm, t)) + return(0); + continue; + case 'S': + if (!_conv(t->tm_sec, 2, '0')) + return(0); + continue; + case 's': + if (!_secs(t)) + return(0); + continue; + case 'T': + if (!_fmt("%H:%M:%S", t)) + return(0); + continue; + case 't': + if (!_add("\t")) + return(0); + continue; + case 'U': + if (!_conv(SUN_WEEK(t), 2, '0')) + return(0); + continue; + case 'u': + if (!_conv(t->tm_wday ? t->tm_wday : 7, 1, '0')) + return(0); + continue; + case 'V': + { + /* ISO 8601 Week Of Year: + If the week (Monday - Sunday) containing + January 1 has four or more days in the new + year, then it is week 1; otherwise it is + week 53 of the previous year and the next + week is week one. */ + + int week = MON_WEEK(t); + + int days = (((t)->tm_yday + 7 - \ + ((t)->tm_wday ? (t)->tm_wday - 1 : 6)) % 7); + + + if (days >= 4) { + week++; + } else if (week == 0) { + week = 53; + } + + if (!_conv(week, 2, '0')) + return(0); + continue; + } + case 'W': + if (!_conv(MON_WEEK(t), 2, '0')) + return(0); + continue; + case 'w': + if (!_conv(t->tm_wday, 1, '0')) + return(0); + continue; + case 'x': + if (!_fmt(_CurrentTimeLocale->d_fmt, t)) + return(0); + continue; + case 'X': + if (!_fmt(_CurrentTimeLocale->t_fmt, t)) + return(0); + continue; + case 'y': + if (!_conv((t->tm_year + TM_YEAR_BASE) % 100, + 2, '0')) + return(0); + continue; + case 'Y': + if (!_conv((t->tm_year + TM_YEAR_BASE), 4, '0')) + return(0); + continue; +#ifndef MAC_TCL + case 'Z': { + char *name = TclpGetTZName(); + if (name && !_add(name)) { + return 0; + } + continue; + } +#endif + case '%': + /* + * X311J/88-090 (4.12.3.5): if conversion char is + * undefined, behavior is undefined. Print out the + * character itself as printf(3) does. + */ + default: + break; + } + } + if (!gsize--) + return(0); + *pt++ = *format; + } + return(gsize); +} + +static int +_secs(t) + const struct tm *t; +{ + static char buf[15]; + register time_t s; + register char *p; + struct tm tmp; + + /* Make a copy, mktime(3) modifies the tm struct. */ + tmp = *t; + s = mktime(&tmp); + for (p = buf + sizeof(buf) - 2; s > 0 && p > buf; s /= 10) + *p-- = (char)(s % 10 + '0'); + return(_add(++p)); +} + +static int +_conv(n, digits, pad) + int n, digits; + int pad; +{ + static char buf[10]; + register char *p; + + for (p = buf + sizeof(buf) - 2; n > 0 && p > buf; n /= 10, --digits) + *p-- = (char)(n % 10 + '0'); + while (p > buf && digits-- > 0) + *p-- = (char) pad; + return(_add(++p)); +} + +static int +_add(str) + const char *str; +{ + for (;; ++pt, --gsize) { + if (!gsize) + return(0); + if (!(*pt = *str++)) + return(1); + } +} diff --git a/compat/string.h b/compat/string.h new file mode 100644 index 0000000..541e159 --- /dev/null +++ b/compat/string.h @@ -0,0 +1,66 @@ +/* + * string.h -- + * + * Declarations of ANSI C library procedures for string handling. + * + * Copyright (c) 1991-1993 The Regents of the University of California. + * Copyright (c) 1994-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) string.h 1.13 96/04/09 22:14:53 + */ + +#ifndef _STRING +#define _STRING + +#include <tcl.h> + +/* + * The following #include is needed to define size_t. (This used to + * include sys/stdtypes.h but that doesn't exist on older versions + * of SunOS, e.g. 4.0.2, so I'm trying sys/types.h now.... hopefully + * it exists everywhere) + */ + +#ifndef MAC_TCL +#include <sys/types.h> +#endif + +extern char * memchr _ANSI_ARGS_((CONST VOID *s, int c, size_t n)); +extern int memcmp _ANSI_ARGS_((CONST VOID *s1, CONST VOID *s2, + size_t n)); +extern char * memcpy _ANSI_ARGS_((VOID *t, CONST VOID *f, size_t n)); +extern char * memmove _ANSI_ARGS_((VOID *t, CONST VOID *f, + size_t n)); +extern char * memset _ANSI_ARGS_((VOID *s, int c, size_t n)); + +extern int strcasecmp _ANSI_ARGS_((CONST char *s1, + CONST char *s2)); +extern char * strcat _ANSI_ARGS_((char *dst, CONST char *src)); +extern char * strchr _ANSI_ARGS_((CONST char *string, int c)); +extern int strcmp _ANSI_ARGS_((CONST char *s1, CONST char *s2)); +extern char * strcpy _ANSI_ARGS_((char *dst, CONST char *src)); +extern size_t strcspn _ANSI_ARGS_((CONST char *string, + CONST char *chars)); +extern char * strdup _ANSI_ARGS_((CONST char *string)); +extern char * strerror _ANSI_ARGS_((int error)); +extern size_t strlen _ANSI_ARGS_((CONST char *string)); +extern int strncasecmp _ANSI_ARGS_((CONST char *s1, + CONST char *s2, size_t n)); +extern char * strncat _ANSI_ARGS_((char *dst, CONST char *src, + size_t numChars)); +extern int strncmp _ANSI_ARGS_((CONST char *s1, CONST char *s2, + size_t nChars)); +extern char * strncpy _ANSI_ARGS_((char *dst, CONST char *src, + size_t numChars)); +extern char * strpbrk _ANSI_ARGS_((CONST char *string, char *chars)); +extern char * strrchr _ANSI_ARGS_((CONST char *string, int c)); +extern size_t strspn _ANSI_ARGS_((CONST char *string, + CONST char *chars)); +extern char * strstr _ANSI_ARGS_((CONST char *string, + CONST char *substring)); +extern char * strtok _ANSI_ARGS_((CONST char *s, CONST char *delim)); + +#endif /* _STRING */ diff --git a/compat/strncasecmp.c b/compat/strncasecmp.c new file mode 100644 index 0000000..749c1da --- /dev/null +++ b/compat/strncasecmp.c @@ -0,0 +1,142 @@ +/* + * strncasecmp.c -- + * + * Source code for the "strncasecmp" library routine. + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1995-1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) strncasecmp.c 1.7 96/10/24 15:23:36 + */ + +#include "tclPort.h" + +/* + * This array is designed for mapping upper and lower case letter + * together for a case independent comparison. The mappings are + * based upon ASCII character sequences. + */ + +static unsigned char charmap[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xe1, 0xe2, 0xe3, 0xe4, 0xc5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, +}; + +/* + * Here are the prototypes just in case they are not included + * in tclPort.h. + */ +int strncasecmp _ANSI_ARGS_((CONST char *s1, + CONST char *s2, size_t n)); + +int strcasecmp _ANSI_ARGS_((CONST char *s1, + CONST char *s2)); + +/* + *---------------------------------------------------------------------- + * + * strcasecmp -- + * + * Compares two strings, ignoring case differences. + * + * Results: + * Compares two null-terminated strings s1 and s2, returning -1, 0, + * or 1 if s1 is lexicographically less than, equal to, or greater + * than s2. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +strcasecmp(s1, s2) + CONST char *s1; /* First string. */ + CONST char *s2; /* Second string. */ +{ + unsigned char u1, u2; + + for ( ; ; s1++, s2++) { + u1 = (unsigned char) *s1; + u2 = (unsigned char) *s2; + if ((u1 == '\0') || (charmap[u1] != charmap[u2])) { + break; + } + } + return charmap[u1] - charmap[u2]; +} + +/* + *---------------------------------------------------------------------- + * + * strncasecmp -- + * + * Compares two strings, ignoring case differences. + * + * Results: + * Compares up to length chars of s1 and s2, returning -1, 0, or 1 + * if s1 is lexicographically less than, equal to, or greater + * than s2 over those characters. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +int +strncasecmp(s1, s2, length) + CONST char *s1; /* First string. */ + CONST char *s2; /* Second string. */ + size_t length; /* Maximum number of characters to compare + * (stop earlier if the end of either string + * is reached). */ +{ + unsigned char u1, u2; + + for (; length != 0; length--, s1++, s2++) { + u1 = (unsigned char) *s1; + u2 = (unsigned char) *s2; + if (charmap[u1] != charmap[u2]) { + return charmap[u1] - charmap[u2]; + } + if (u1 == '\0') { + return 0; + } + } + return 0; +} diff --git a/compat/strstr.c b/compat/strstr.c new file mode 100644 index 0000000..59296db --- /dev/null +++ b/compat/strstr.c @@ -0,0 +1,68 @@ +/* + * strstr.c -- + * + * Source code for the "strstr" library routine. + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) strstr.c 1.4 96/02/15 12:08:22 + */ + +/* + *---------------------------------------------------------------------- + * + * strstr -- + * + * Locate the first instance of a substring in a string. + * + * Results: + * If string contains substring, the return value is the + * location of the first matching instance of substring + * in string. If string doesn't contain substring, the + * return value is 0. Matching is done on an exact + * character-for-character basis with no wildcards or special + * characters. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +strstr(string, substring) + register char *string; /* String to search. */ + char *substring; /* Substring to try to find in string. */ +{ + register char *a, *b; + + /* First scan quickly through the two strings looking for a + * single-character match. When it's found, then compare the + * rest of the substring. + */ + + b = substring; + if (*b == 0) { + return string; + } + for ( ; *string != 0; string += 1) { + if (*string != *b) { + continue; + } + a = string; + while (1) { + if (*b == 0) { + return string; + } + if (*a++ != *b++) { + break; + } + } + b = substring; + } + return (char *) 0; +} diff --git a/compat/strtod.c b/compat/strtod.c new file mode 100644 index 0000000..0a26163 --- /dev/null +++ b/compat/strtod.c @@ -0,0 +1,257 @@ +/* + * strtod.c -- + * + * Source code for the "strtod" library procedure. + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) strtod.c 1.9 96/12/13 15:02:46 + */ + +#include "tcl.h" +#ifdef NO_STDLIB_H +# include "../compat/stdlib.h" +#else +# include <stdlib.h> +#endif +#include <ctype.h> + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif +#ifndef NULL +#define NULL 0 +#endif + +static int maxExponent = 511; /* Largest possible base 10 exponent. Any + * exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. + */ +static double powersOf10[] = { /* Table giving binary powers of 10. Entry */ + 10., /* is 10^2^i. Used to convert decimal */ + 100., /* exponents into floating-point numbers. */ + 1.0e4, + 1.0e8, + 1.0e16, + 1.0e32, + 1.0e64, + 1.0e128, + 1.0e256 +}; + +/* + *---------------------------------------------------------------------- + * + * strtod -- + * + * This procedure converts a floating-point number from an ASCII + * decimal representation to internal double-precision format. + * + * Results: + * The return value is the double-precision floating-point + * representation of the characters in string. If endPtr isn't + * NULL, then *endPtr is filled in with the address of the + * next character after the last one that was part of the + * floating-point number. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +double +strtod(string, endPtr) + CONST char *string; /* A decimal ASCII floating-point number, + * optionally preceded by white space. + * Must have form "-I.FE-X", where I is the + * integer part of the mantissa, F is the + * fractional part of the mantissa, and X + * is the exponent. Either of the signs + * may be "+", "-", or omitted. Either I + * or F may be omitted, or both. The decimal + * point isn't necessary unless F is present. + * The "E" may actually be an "e". E and X + * may both be omitted (but not just one). + */ + char **endPtr; /* If non-NULL, store terminating character's + * address here. */ +{ + int sign, expSign = FALSE; + double fraction, dblExp, *d; + register CONST char *p; + register int c; + int exp = 0; /* Exponent read from "EX" field. */ + int fracExp = 0; /* Exponent that derives from the fractional + * part. Under normal circumstatnces, it is + * the negative of the number of digits in F. + * However, if I is very long, the last digits + * of I get dropped (otherwise a long I with a + * large negative exponent could cause an + * unnecessary overflow on I alone). In this + * case, fracExp is incremented one for each + * dropped digit. */ + int mantSize; /* Number of digits in mantissa. */ + int decPt; /* Number of mantissa digits BEFORE decimal + * point. */ + CONST char *pExp; /* Temporarily holds location of exponent + * in string. */ + + /* + * Strip off leading blanks and check for a sign. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + if (*p == '-') { + sign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + sign = FALSE; + } + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + + decPt = -1; + for (mantSize = 0; ; mantSize += 1) + { + c = *p; + if (!isdigit(c)) { + if ((c != '.') || (decPt >= 0)) { + break; + } + decPt = mantSize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + + pExp = p; + p -= mantSize; + if (decPt < 0) { + decPt = mantSize; + } else { + mantSize -= 1; /* One of the digits was the point. */ + } + if (mantSize > 18) { + fracExp = decPt - 18; + mantSize = 18; + } else { + fracExp = decPt - mantSize; + } + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + frac1 = 0; + for ( ; mantSize > 9; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac1 = 10*frac1 + (c - '0'); + } + frac2 = 0; + for (; mantSize > 0; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac2 = 10*frac2 + (c - '0'); + } + fraction = (1.0e9 * frac1) + frac2; + } + + /* + * Skim off the exponent. + */ + + p = pExp; + if ((*p == 'E') || (*p == 'e')) { + p += 1; + if (*p == '-') { + expSign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + expSign = FALSE; + } + while (isdigit(*p)) { + exp = exp * 10 + (*p - '0'); + p += 1; + } + } + if (expSign) { + exp = fracExp - exp; + } else { + exp = fracExp + exp; + } + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + + if (exp < 0) { + expSign = TRUE; + exp = -exp; + } else { + expSign = FALSE; + } + if (exp > maxExponent) { + exp = maxExponent; + } + dblExp = 1.0; + for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { + if (exp & 01) { + dblExp *= *d; + } + } + if (expSign) { + fraction /= dblExp; + } else { + fraction *= dblExp; + } + +done: + if (endPtr != NULL) { + *endPtr = (char *) p; + } + + if (sign) { + return -fraction; + } + return fraction; +} diff --git a/compat/strtol.c b/compat/strtol.c new file mode 100644 index 0000000..c781bd6 --- /dev/null +++ b/compat/strtol.c @@ -0,0 +1,83 @@ +/* + * strtol.c -- + * + * Source code for the "strtol" library procedure. + * + * Copyright (c) 1988 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) strtol.c 1.4 96/02/15 12:08:23 + */ + +#include <ctype.h> + + +/* + *---------------------------------------------------------------------- + * + * strtol -- + * + * Convert an ASCII string into an integer. + * + * Results: + * The return value is the integer equivalent of string. If endPtr + * is non-NULL, then *endPtr is filled in with the character + * after the last one that was part of the integer. If string + * doesn't contain a valid integer value, then zero is returned + * and *endPtr is set to string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +long int +strtol(string, endPtr, base) + char *string; /* String of ASCII digits, possibly + * preceded by white space. For bases + * greater than 10, either lower- or + * upper-case digits may be used. + */ + char **endPtr; /* Where to store address of terminating + * character, or NULL. */ + int base; /* Base for conversion. Must be less + * than 37. If 0, then the base is chosen + * from the leading characters of string: + * "0x" means hex, "0" means octal, anything + * else means decimal. + */ +{ + register char *p; + int result; + + /* + * Skip any leading blanks. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + + /* + * Check for a sign. + */ + + if (*p == '-') { + p += 1; + result = -(strtoul(p, endPtr, base)); + } else { + if (*p == '+') { + p += 1; + } + result = strtoul(p, endPtr, base); + } + if ((result == 0) && (endPtr != 0) && (*endPtr == p)) { + *endPtr = string; + } + return result; +} diff --git a/compat/strtoul.c b/compat/strtoul.c new file mode 100644 index 0000000..37fe490 --- /dev/null +++ b/compat/strtoul.c @@ -0,0 +1,183 @@ +/* + * strtoul.c -- + * + * Source code for the "strtoul" library procedure. + * + * Copyright (c) 1988 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) strtoul.c 1.5 96/02/15 12:08:24 + */ + +#include <ctype.h> + +/* + * The table below is used to convert from ASCII digits to a + * numerical equivalent. It maps from '0' through 'z' to integers + * (100 for non-digit characters). + */ + +static char cvtIn[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, /* '0' - '9' */ + 100, 100, 100, 100, 100, 100, 100, /* punctuation */ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' - 'Z' */ + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, + 100, 100, 100, 100, 100, 100, /* punctuation */ + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'a' - 'z' */ + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35}; + +/* + *---------------------------------------------------------------------- + * + * strtoul -- + * + * Convert an ASCII string into an integer. + * + * Results: + * The return value is the integer equivalent of string. If endPtr + * is non-NULL, then *endPtr is filled in with the character + * after the last one that was part of the integer. If string + * doesn't contain a valid integer value, then zero is returned + * and *endPtr is set to string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +unsigned long int +strtoul(string, endPtr, base) + char *string; /* String of ASCII digits, possibly + * preceded by white space. For bases + * greater than 10, either lower- or + * upper-case digits may be used. + */ + char **endPtr; /* Where to store address of terminating + * character, or NULL. */ + int base; /* Base for conversion. Must be less + * than 37. If 0, then the base is chosen + * from the leading characters of string: + * "0x" means hex, "0" means octal, anything + * else means decimal. + */ +{ + register char *p; + register unsigned long int result = 0; + register unsigned digit; + int anyDigits = 0; + + /* + * Skip any leading blanks. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + + /* + * If no base was provided, pick one from the leading characters + * of the string. + */ + + if (base == 0) + { + if (*p == '0') { + p += 1; + if (*p == 'x') { + p += 1; + base = 16; + } else { + + /* + * Must set anyDigits here, otherwise "0" produces a + * "no digits" error. + */ + + anyDigits = 1; + base = 8; + } + } + else base = 10; + } else if (base == 16) { + + /* + * Skip a leading "0x" from hex numbers. + */ + + if ((p[0] == '0') && (p[1] == 'x')) { + p += 2; + } + } + + /* + * Sorry this code is so messy, but speed seems important. Do + * different things for base 8, 10, 16, and other. + */ + + if (base == 8) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > 7) { + break; + } + result = (result << 3) + digit; + anyDigits = 1; + } + } else if (base == 10) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > 9) { + break; + } + result = (10*result) + digit; + anyDigits = 1; + } + } else if (base == 16) { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > ('z' - '0')) { + break; + } + digit = cvtIn[digit]; + if (digit > 15) { + break; + } + result = (result << 4) + digit; + anyDigits = 1; + } + } else { + for ( ; ; p += 1) { + digit = *p - '0'; + if (digit > ('z' - '0')) { + break; + } + digit = cvtIn[digit]; + if (digit >= base) { + break; + } + result = result*base + digit; + anyDigits = 1; + } + } + + /* + * See if there were any digits at all. + */ + + if (!anyDigits) { + p = string; + } + + if (endPtr != 0) { + *endPtr = p; + } + + return result; +} diff --git a/compat/tclErrno.h b/compat/tclErrno.h new file mode 100644 index 0000000..bc45481 --- /dev/null +++ b/compat/tclErrno.h @@ -0,0 +1,100 @@ +/* + * tclErrno.h -- + * + * This header file contains the various POSIX errno definitions that + * are used by Tcl. This file is derived from the spec POSIX 2.4 and + * previous implementations for Berkeley UNIX. + * + * Copyright (c) 1982, 1986, 1989 Regents of the University of California. + * Copyright (c) 1996 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) tclErrno.h 1.1 96/04/29 15:25:31 + */ + +extern int errno; /* global error number */ + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* Input/output error */ +#define ENXIO 6 /* Device not configured */ +#define E2BIG 7 /* Argument list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file descriptor */ +#define ECHILD 10 /* No child processes */ +#define EDEADLK 11 /* Resource deadlock avoided */ + /* 11 was EAGAIN */ +#define ENOMEM 12 /* Cannot allocate memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* Operation not supported by device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Inappropriate ioctl for device */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Numerical argument out of domain */ +#define ERANGE 34 /* Result too large */ +#define EAGAIN 35 /* Resource temporarily unavailable */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define EINPROGRESS 36 /* Operation now in progress */ +#define EALREADY 37 /* Operation already in progress */ +#define ENOTSOCK 38 /* Socket operation on non-socket */ +#define EDESTADDRREQ 39 /* Destination address required */ +#define EMSGSIZE 40 /* Message too long */ +#define EPROTOTYPE 41 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 42 /* Protocol not available */ +#define EPROTONOSUPPORT 43 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 44 /* Socket type not supported */ +#define EOPNOTSUPP 45 /* Operation not supported on socket */ +#define EPFNOSUPPORT 46 /* Protocol family not supported */ +#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ +#define EADDRINUSE 48 /* Address already in use */ +#define EADDRNOTAVAIL 49 /* Can't assign requested address */ +#define ENETDOWN 50 /* Network is down */ +#define ENETUNREACH 51 /* Network is unreachable */ +#define ENETRESET 52 /* Network dropped connection on reset */ +#define ECONNABORTED 53 /* Software caused connection abort */ +#define ECONNRESET 54 /* Connection reset by peer */ +#define ENOBUFS 55 /* No buffer space available */ +#define EISCONN 56 /* Socket is already connected */ +#define ENOTCONN 57 /* Socket is not connected */ +#define ESHUTDOWN 58 /* Can't send after socket shutdown */ +#define ETOOMANYREFS 59 /* Too many references: can't splice */ +#define ETIMEDOUT 60 /* Connection timed out */ +#define ECONNREFUSED 61 /* Connection refused */ +#define ELOOP 62 /* Too many levels of symbolic links */ +#define ENAMETOOLONG 63 /* File name too long */ +#define EHOSTDOWN 64 /* Host is down */ +#define EHOSTUNREACH 65 /* No route to host */ +#define ENOTEMPTY 66 /* Directory not empty */ +#define EPROCLIM 67 /* Too many processes */ +#define EUSERS 68 /* Too many users */ +#define EDQUOT 69 /* Disc quota exceeded */ +#define ESTALE 70 /* Stale NFS file handle */ +#define EREMOTE 71 /* Too many levels of remote in path */ +#define EBADRPC 72 /* RPC struct is bad */ +#define ERPCMISMATCH 73 /* RPC version wrong */ +#define EPROGUNAVAIL 74 /* RPC prog. not avail */ +#define EPROGMISMATCH 75 /* Program version wrong */ +#define EPROCUNAVAIL 76 /* Bad procedure for program */ +#define ENOLCK 77 /* No locks available */ +#define ENOSYS 78 /* Function not implemented */ +#define EFTYPE 79 /* Inappropriate file type or format */ + diff --git a/compat/tmpnam.c b/compat/tmpnam.c new file mode 100644 index 0000000..c29a1e3 --- /dev/null +++ b/compat/tmpnam.c @@ -0,0 +1,42 @@ +/* + * Copyright (c) 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific written prior permission. This software + * is provided ``as is'' without express or implied warranty. + * + * SCCS: @(#) tmpnam.c 1.3 96/02/15 12:08:25 + */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <stdio.h> + +/* + * Use /tmp instead of /usr/tmp, because L_tmpname is only 14 chars + * on some machines (like NeXT machines) and /usr/tmp will cause + * buffer overflows. + */ + +#ifdef P_tmpdir +# undef P_tmpdir +#endif +#define P_tmpdir "/tmp" + +char * +tmpnam(s) + char *s; +{ + static char name[50]; + char *mktemp(); + + if (!s) + s = name; + (void)sprintf(s, "%s/XXXXXX", P_tmpdir); + return(mktemp(s)); +} diff --git a/compat/unistd.h b/compat/unistd.h new file mode 100644 index 0000000..3af430c --- /dev/null +++ b/compat/unistd.h @@ -0,0 +1,84 @@ +/* + * unistd.h -- + * + * Macros, CONSTants and prototypes for Posix conformance. + * + * Copyright 1989 Regents of the University of California + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * SCCS: @(#) unistd.h 1.7 96/02/15 14:43:57 + */ + +#ifndef _UNISTD +#define _UNISTD + +#include <sys/types.h> +#ifndef _TCL +# include "tcl.h" +#endif + +#ifndef NULL +#define NULL 0 +#endif + +/* + * Strict POSIX stuff goes here. Extensions go down below, in the + * ifndef _POSIX_SOURCE section. + */ + +extern void _exit _ANSI_ARGS_((int status)); +extern int access _ANSI_ARGS_((CONST char *path, int mode)); +extern int chdir _ANSI_ARGS_((CONST char *path)); +extern int chown _ANSI_ARGS_((CONST char *path, uid_t owner, gid_t group)); +extern int close _ANSI_ARGS_((int fd)); +extern int dup _ANSI_ARGS_((int oldfd)); +extern int dup2 _ANSI_ARGS_((int oldfd, int newfd)); +extern int execl _ANSI_ARGS_((CONST char *path, ...)); +extern int execle _ANSI_ARGS_((CONST char *path, ...)); +extern int execlp _ANSI_ARGS_((CONST char *file, ...)); +extern int execv _ANSI_ARGS_((CONST char *path, char **argv)); +extern int execve _ANSI_ARGS_((CONST char *path, char **argv, char **envp)); +extern int execvp _ANSI_ARGS_((CONST char *file, char **argv)); +extern pid_t fork _ANSI_ARGS_((void)); +extern char *getcwd _ANSI_ARGS_((char *buf, size_t size)); +extern gid_t getegid _ANSI_ARGS_((void)); +extern uid_t geteuid _ANSI_ARGS_((void)); +extern gid_t getgid _ANSI_ARGS_((void)); +extern int getgroups _ANSI_ARGS_((int bufSize, int *buffer)); +extern pid_t getpid _ANSI_ARGS_((void)); +extern uid_t getuid _ANSI_ARGS_((void)); +extern int isatty _ANSI_ARGS_((int fd)); +extern long lseek _ANSI_ARGS_((int fd, long offset, int whence)); +extern int pipe _ANSI_ARGS_((int *fildes)); +extern int read _ANSI_ARGS_((int fd, char *buf, size_t size)); +extern int setgid _ANSI_ARGS_((gid_t group)); +extern int setuid _ANSI_ARGS_((uid_t user)); +extern unsigned sleep _ANSI_ARGS_ ((unsigned seconds)); +extern char *ttyname _ANSI_ARGS_((int fd)); +extern int unlink _ANSI_ARGS_((CONST char *path)); +extern int write _ANSI_ARGS_((int fd, CONST char *buf, size_t size)); + +#ifndef _POSIX_SOURCE +extern char *crypt _ANSI_ARGS_((CONST char *, CONST char *)); +extern int fchown _ANSI_ARGS_((int fd, uid_t owner, gid_t group)); +extern int flock _ANSI_ARGS_((int fd, int operation)); +extern int ftruncate _ANSI_ARGS_((int fd, unsigned long length)); +extern int ioctl _ANSI_ARGS_((int fd, int request, ...)); +extern int readlink _ANSI_ARGS_((CONST char *path, char *buf, int bufsize)); +extern int setegid _ANSI_ARGS_((gid_t group)); +extern int seteuid _ANSI_ARGS_((uid_t user)); +extern int setreuid _ANSI_ARGS_((int ruid, int euid)); +extern int symlink _ANSI_ARGS_((CONST char *, CONST char *)); +extern int ttyslot _ANSI_ARGS_((void)); +extern int truncate _ANSI_ARGS_((CONST char *path, unsigned long length)); +extern int vfork _ANSI_ARGS_((void)); +#endif /* _POSIX_SOURCE */ + +#endif /* _UNISTD */ + diff --git a/compat/waitpid.c b/compat/waitpid.c new file mode 100644 index 0000000..179d5de --- /dev/null +++ b/compat/waitpid.c @@ -0,0 +1,170 @@ +/* + * waitpid.c -- + * + * This procedure emulates the POSIX waitpid kernel call on + * BSD systems that don't have waitpid but do have wait3. + * This code is based on a prototype version written by + * Mark Diekhans and Karl Lehenbauer. + * + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * SCCS: @(#) waitpid.c 1.9 96/02/15 12:08:26 + */ + +#include "tclInt.h" +#include "tclPort.h" + +/* + * A linked list of the following structures is used to keep track + * of processes for which we received notification from the kernel, + * but the application hasn't waited for them yet (this can happen + * because wait may not return the process we really want). We + * save the information here until the application finally does + * wait for the process. + */ + +typedef struct WaitInfo { + int pid; /* Pid of process that exited. */ + WAIT_STATUS_TYPE status; /* Status returned when child exited + * or suspended. */ + struct WaitInfo *nextPtr; /* Next in list of exited processes. */ +} WaitInfo; + +static WaitInfo *deadList = NULL; /* First in list of all dead + * processes. */ + +/* + *---------------------------------------------------------------------- + * + * waitpid -- + * + * This procedure emulates the functionality of the POSIX + * waitpid kernel call, using the BSD wait3 kernel call. + * Note: it doesn't emulate absolutely all of the waitpid + * functionality, in that it doesn't support pid's of 0 + * or < -1. + * + * Results: + * -1 is returned if there is an error in the wait kernel call. + * Otherwise the pid of an exited or suspended process is + * returned and *statusPtr is set to the status value of the + * process. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +#ifdef waitpid +# undef waitpid +#endif + +int +waitpid(pid, statusPtr, options) + int pid; /* The pid to wait on. Must be -1 or + * greater than zero. */ + int *statusPtr; /* Where to store wait status for the + * process. */ + int options; /* OR'ed combination of WNOHANG and + * WUNTRACED. */ +{ + register WaitInfo *waitPtr, *prevPtr; + int result; + WAIT_STATUS_TYPE status; + + if ((pid < -1) || (pid == 0)) { + errno = EINVAL; + return -1; + } + + /* + * See if there's a suitable process that has already stopped or + * exited. If so, remove it from the list of exited processes and + * return its information. + */ + + for (waitPtr = deadList, prevPtr = NULL; waitPtr != NULL; + prevPtr = waitPtr, waitPtr = waitPtr->nextPtr) { + if ((pid != waitPtr->pid) && (pid != -1)) { + continue; + } + if (!(options & WUNTRACED) && (WIFSTOPPED(waitPtr->status))) { + continue; + } + result = waitPtr->pid; + *statusPtr = *((int *) &waitPtr->status); + if (prevPtr == NULL) { + deadList = waitPtr->nextPtr; + } else { + prevPtr->nextPtr = waitPtr->nextPtr; + } + ckfree((char *) waitPtr); + return result; + } + + /* + * Wait for any process to stop or exit. If it's an acceptable one + * then return it to the caller; otherwise store information about it + * in the list of exited processes and try again. On systems that + * have only wait but not wait3, there are several situations we can't + * handle, but we do the best we can (e.g. can still handle some + * combinations of options by invoking wait instead of wait3). + */ + + while (1) { +#if NO_WAIT3 + if (options & WNOHANG) { + return 0; + } + if (options != 0) { + errno = EINVAL; + return -1; + } + result = wait(&status); +#else + result = wait3(&status, options, 0); +#endif + if ((result == -1) && (errno == EINTR)) { + continue; + } + if (result <= 0) { + return result; + } + + if ((pid != result) && (pid != -1)) { + goto saveInfo; + } + if (!(options & WUNTRACED) && (WIFSTOPPED(status))) { + goto saveInfo; + } + *statusPtr = *((int *) &status); + return result; + + /* + * Can't return this info to caller. Save it in the list of + * stopped or exited processes. Tricky point: first check for + * an existing entry for the process and overwrite it if it + * exists (e.g. a previously stopped process might now be dead). + */ + + saveInfo: + for (waitPtr = deadList; waitPtr != NULL; waitPtr = waitPtr->nextPtr) { + if (waitPtr->pid == result) { + waitPtr->status = status; + goto waitAgain; + } + } + waitPtr = (WaitInfo *) ckalloc(sizeof(WaitInfo)); + waitPtr->pid = result; + waitPtr->status = status; + waitPtr->nextPtr = deadList; + deadList = waitPtr; + + waitAgain: continue; + } +} |