-/* $RCSfile: util.c,v $$Revision: 4.1 $$Date: 92/08/07 18:29:00 $
+/* util.c
*
- * Copyright (c) 1991, Larry Wall
+ * Copyright (c) 1991-1994, Larry Wall
*
* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
*
- * $Log: util.c,v $
- * Revision 4.1 92/08/07 18:29:00 lwall
- *
- * Revision 4.0.1.6 92/06/11 21:18:47 lwall
- * patch34: boneheaded typo in my_bcopy()
- *
- * Revision 4.0.1.5 92/06/08 16:08:37 lwall
- * patch20: removed implicit int declarations on functions
- * patch20: Perl now distinguishes overlapped copies from non-overlapped
- * patch20: fixed confusion between a *var's real name and its effective name
- * patch20: bcopy() and memcpy() now tested for overlap safety
- * patch20: added Atari ST portability
- *
- * Revision 4.0.1.4 91/11/11 16:48:54 lwall
- * patch19: study was busted by 4.018
- * patch19: added little-endian pack/unpack options
- *
- * Revision 4.0.1.3 91/11/05 19:18:26 lwall
- * patch11: safe malloc code now integrated into Perl's malloc when possible
- * patch11: strchr("little", "longer string") could visit faraway places
- * patch11: warn '-' x 10000 dumped core
- * patch11: forked exec on non-existent program now issues a warning
- *
- * Revision 4.0.1.2 91/06/07 12:10:42 lwall
- * patch4: new copyright notice
- * patch4: made some allowances for "semi-standard" C
- * patch4: strchr() could blow up searching for null string
- * patch4: taintchecks could improperly modify parent in vfork()
- * patch4: exec would close files even if you cleared close-on-exec flag
- *
- * Revision 4.0.1.1 91/04/12 09:19:25 lwall
- * patch1: random cleanup in cpp namespace
- *
- * Revision 4.0 91/03/20 01:56:39 lwall
- * 4.0 baseline.
- *
*/
-/*SUPPRESS 112*/
+
+/*
+ * "Very useful, no doubt, that was to Saruman; yet it seems that he was
+ * not content." --Gandalf
+ */
#include "EXTERN.h"
#include "perl.h"
#include <signal.h>
#endif
-#ifdef I_VFORK
-# include <vfork.h>
+/* Omit this -- it causes too much grief on mixed systems.
+#ifdef I_UNISTD
+# include <unistd.h>
#endif
+*/
-#ifdef I_VARARGS
-# include <varargs.h>
+#ifdef I_VFORK
+# include <vfork.h>
#endif
#ifdef I_FCNTL
#define FLUSH
+#ifdef LEAKTEST
+static void xstat _((void));
+#endif
+
#ifndef safemalloc
/* paranoid version of malloc */
MEM_SIZE size;
#endif /* MSDOS */
{
- char *ptr;
-#ifndef STANDARD_C
- char *malloc();
-#endif /* ! STANDARD_C */
-
+ char *ptr;
#ifdef MSDOS
if (size > 0xffff) {
fprintf(stderr, "Allocation too large: %lx\n", size) FLUSH;
#endif /* MSDOS */
{
char *ptr;
-#ifndef STANDARD_C
+#if !defined(STANDARD_C) && !defined(HAS_REALLOC_PROTOTYPE)
char *realloc();
-#endif /* ! STANDARD_C */
+#endif /* !defined(STANDARD_C) && !defined(HAS_REALLOC_PROTOTYPE) */
#ifdef MSDOS
if (size > 0xffff) {
char *where;
MEM_SIZE size;
{
- return saferealloc(where - ALIGN, size + ALIGN) + ALIGN;
+ register char *new = saferealloc(where - ALIGN, size + ALIGN);
+ return new + ALIGN;
}
void
register char *to;
register char *from;
register char *fromend;
-register I32 delim;
+register int delim;
I32 *retlen;
{
char *origto = to;
register I32 first = *little;
register char *littleend = lend;
- if (!first && little > littleend)
+ if (!first && little >= littleend)
return big;
if (bigend - big < littleend - little)
return Nullch;
register I32 first = *little;
register char *littleend = lend;
- if (!first && little > littleend)
+ if (!first && little >= littleend)
return bigend;
bigbeg = big;
big = bigend - (littleend - little++);
s--,i++;
}
sv_upgrade(sv, SVt_PVBM);
- sv_magic(sv, 0, 'B', 0, 0); /* deep magic */
+ sv_magic(sv, Nullsv, 'B', Nullch, 0); /* deep magic */
SvVALID_on(sv);
s = (unsigned char*)(SvPVX(sv)); /* deeper magic */
register unsigned char *oldlittle;
if (SvTYPE(littlestr) != SVt_PVBM || !SvVALID(littlestr)) {
- if (!SvPOK(littlestr) || !SvPVX(littlestr))
+ STRLEN len;
+ char *l = SvPV(littlestr,len);
+ if (!len)
return (char*)big;
- return ninstr((char*)big,(char*)bigend,
- SvPVX(littlestr), SvPVX(littlestr) + SvCUR(littlestr));
+ return ninstr((char*)big,(char*)bigend, l, l + len);
}
littlelen = SvCUR(littlestr);
}
else {
s = bigend - littlelen;
- if (*s == *little && bcmp(s,little,littlelen)==0)
+ if (*s == *little && bcmp((char*)s,(char*)little,littlelen)==0)
return (char*)s; /* how sweet it is */
else if (bigend[-1] == '\n' && little[littlelen-1] != '\n'
&& s > big) {
s--;
- if (*s == *little && bcmp(s,little,littlelen)==0)
+ if (*s == *little && bcmp((char*)s,(char*)little,littlelen)==0)
return (char*)s;
}
return Nullch;
I32
ibcmp(a,b,len)
-register char *a;
-register char *b;
+register U8 *a;
+register U8 *b;
register I32 len;
{
while (len--) {
/* copy a string to a safe spot */
char *
-savestr(sv)
+savepv(sv)
char *sv;
{
register char *newaddr;
/* same thing but with a known length */
char *
-nsavestr(sv, len)
+savepvn(sv, len)
char *sv;
register I32 len;
{
return newaddr;
}
-/* grow a static string to at least a certain length */
+#if !defined(I_STDARG) && !defined(I_VARARGS)
-void
-pv_grow(strptr,curlen,newlen)
-char **strptr;
-I32 *curlen;
-I32 newlen;
-{
- if (newlen > *curlen) { /* need more room? */
- if (*curlen)
- Renew(*strptr,newlen,char);
- else
- New(905,*strptr,newlen,char);
- *curlen = newlen;
- }
-}
+/*
+ * Fallback on the old hackers way of doing varargs
+ */
-#ifndef I_VARARGS
/*VARARGS1*/
char *
mess(pat,a1,a2,a3,a4)
s = buf;
if (usermess) {
- tmpstr = sv_mortalcopy(&sv_undef);
+ tmpstr = sv_newmortal();
sv_setpv(tmpstr, (char*)a1);
*s++ = SvPVX(tmpstr)[SvCUR(tmpstr)-1];
}
}
if (s[-1] != '\n') {
- if (curcop->cop_line) {
- (void)sprintf(s," at %s line %ld",
- SvPVX(GvSV(curcop->cop_filegv)), (long)curcop->cop_line);
- s += strlen(s);
- }
- if (last_in_gv &&
- GvIO(last_in_gv) &&
- GvIO(last_in_gv)->lines ) {
- (void)sprintf(s,", <%s> %s %ld",
- last_in_gv == argvgv ? "" : GvENAME(last_in_gv),
- strEQ(rs,"\n") ? "line" : "chunk",
- (long)GvIO(last_in_gv)->lines);
- s += strlen(s);
+ if (dirty)
+ strcpy(s, " during global destruction.\n");
+ else {
+ if (curcop->cop_line) {
+ (void)sprintf(s," at %s line %ld",
+ SvPVX(GvSV(curcop->cop_filegv)), (long)curcop->cop_line);
+ s += strlen(s);
+ }
+ if (GvIO(last_in_gv) &&
+ IoLINES(GvIOp(last_in_gv)) ) {
+ (void)sprintf(s,", <%s> %s %ld",
+ last_in_gv == argvgv ? "" : GvENAME(last_in_gv),
+ strEQ(rs,"\n") ? "line" : "chunk",
+ (long)IoLINES(GvIOp(last_in_gv)));
+ s += strlen(s);
+ }
+ (void)strcpy(s,".\n");
}
- (void)strcpy(s,".\n");
if (usermess)
sv_catpv(tmpstr,buf+1);
}
char *message;
message = mess(pat,a1,a2,a3,a4);
+ if (in_eval) {
+ restartop = die_where(message);
+ longjmp(top_env, 3);
+ }
fputs(message,stderr);
(void)fflush(stderr);
if (e_fp)
#endif
(void)fflush(stderr);
}
+
+#else /* !defined(I_STDARG) && !defined(I_VARARGS) */
+
+#ifdef I_STDARG
+char *
+mess(char *pat, va_list *args)
#else
/*VARARGS0*/
char *
-mess(args)
-va_list args;
-{
+mess(pat, args)
char *pat;
+ va_list *args;
+#endif
+{
char *s;
SV *tmpstr;
I32 usermess;
#ifndef HAS_VPRINTF
-#ifdef CHARVSPRINTF
+#ifdef USE_CHAR_VSPRINTF
char *vsprintf();
#else
I32 vsprintf();
#endif
#endif
- pat = va_arg(args, char *);
s = buf;
usermess = strEQ(pat, "%s");
if (usermess) {
- tmpstr = sv_mortalcopy(&sv_undef);
- sv_setpv(tmpstr, va_arg(args, char *));
+ tmpstr = sv_newmortal();
+ sv_setpv(tmpstr, va_arg(*args, char *));
*s++ = SvPVX(tmpstr)[SvCUR(tmpstr)-1];
}
else {
- (void) vsprintf(s,pat,args);
+ (void) vsprintf(s,pat,*args);
s += strlen(s);
}
+ va_end(*args);
if (s[-1] != '\n') {
- if (curcop->cop_line) {
- (void)sprintf(s," at %s line %ld",
- SvPVX(GvSV(curcop->cop_filegv)), (long)curcop->cop_line);
- s += strlen(s);
- }
- if (last_in_gv &&
- GvIO(last_in_gv) &&
- GvIO(last_in_gv)->lines ) {
- (void)sprintf(s,", <%s> %s %ld",
- last_in_gv == argvgv ? "" : GvNAME(last_in_gv),
- strEQ(rs,"\n") ? "line" : "chunk",
- (long)GvIO(last_in_gv)->lines);
- s += strlen(s);
+ if (dirty)
+ strcpy(s, " during global destruction.\n");
+ else {
+ if (curcop->cop_line) {
+ (void)sprintf(s," at %s line %ld",
+ SvPVX(GvSV(curcop->cop_filegv)), (long)curcop->cop_line);
+ s += strlen(s);
+ }
+ if (GvIO(last_in_gv) &&
+ IoLINES(GvIOp(last_in_gv)) ) {
+ (void)sprintf(s,", <%s> %s %ld",
+ last_in_gv == argvgv ? "" : GvNAME(last_in_gv),
+ strEQ(rs,"\n") ? "line" : "chunk",
+ (long)IoLINES(GvIOp(last_in_gv)));
+ s += strlen(s);
+ }
+ (void)strcpy(s,".\n");
}
- (void)strcpy(s,".\n");
if (usermess)
sv_catpv(tmpstr,buf+1);
}
return buf;
}
-/*VARARGS0*/
+#ifdef I_STDARG
void
-#ifdef __STDC__
-croak(char* pat,...)
+croak(char* pat, ...)
#else
-croak(va_alist)
-va_dcl
+/*VARARGS0*/
+void
+croak(pat, va_alist)
+ char *pat;
+ va_dcl
#endif
{
va_list args;
- char *tmps;
char *message;
+#ifdef I_STDARG
+ va_start(args, pat);
+#else
va_start(args);
- message = mess(args);
+#endif
+ message = mess(pat, &args);
va_end(args);
- if (restartop = die_where(message))
+ if (in_eval) {
+ restartop = die_where(message);
longjmp(top_env, 3);
+ }
fputs(message,stderr);
(void)fflush(stderr);
if (e_fp)
my_exit((I32)((errno&255)?errno:((statusvalue&255)?statusvalue:255)));
}
-/*VARARGS0*/
-#ifdef __STDC__
-void warn(char* pat,...)
+void
+#ifdef I_STDARG
+warn(char* pat,...)
#else
-void warn(va_alist)
-va_dcl
+/*VARARGS0*/
+warn(pat,va_alist)
+ char *pat;
+ va_dcl
#endif
{
va_list args;
char *message;
+#ifdef I_STDARG
+ va_start(args, pat);
+#else
va_start(args);
- message = mess(args);
+#endif
+ message = mess(pat, &args);
va_end(args);
fputs(message,stderr);
#endif
(void)fflush(stderr);
}
-#endif
+#endif /* !defined(I_STDARG) && !defined(I_VARARGS) */
+#ifndef VMS /* VMS' my_setenv() is in VMS.c */
void
my_setenv(nam,val)
char *nam, *val;
for (max = i; environ[max]; max++) ;
New(901,tmpenv, max+2, char*);
for (j=0; j<max; j++) /* copy environment */
- tmpenv[j] = savestr(environ[j]);
+ tmpenv[j] = savepv(environ[j]);
tmpenv[max] = Nullch;
environ = tmpenv; /* tell exec where it is now */
}
} /* potential SEGV's */
return i;
}
+#endif /* !VMS */
#ifdef EUNICE
I32
}
#endif
-#if !defined(HAS_BCOPY) || !defined(SAFE_BCOPY)
+#if !defined(HAS_BCOPY) || !defined(HAS_SAFE_BCOPY)
char *
my_bcopy(from,to,len)
register char *from;
#ifdef I_VARARGS
#ifndef HAS_VPRINTF
-#ifdef CHARVSPRINTF
+#ifdef USE_CHAR_VSPRINTF
char *
#else
int
fakebuf._flag = _IOWRT|_IOSTRG;
_doprnt(pat, args, &fakebuf); /* what a kludge */
(void)putc('\0', &fakebuf);
-#ifdef CHARVSPRINTF
+#ifdef USE_CHAR_VSPRINTF
return(dest);
#else
return 0; /* perl doesn't use return value */
VTOH(vtohl,long)
#endif
-#ifndef DOSISH
+#if !defined(DOSISH) && !defined(VMS) /* VMS' my_popen() is in VMS.c */
FILE *
my_popen(cmd,mode)
char *cmd;
close(p[THIS]);
}
if (doexec) {
-#if !defined(HAS_FCNTL) || !defined(FFt_SETFD)
+#if !defined(HAS_FCNTL) || !defined(F_SETFD)
int fd;
#ifndef NOFILE
close(fd);
#endif
do_exec(cmd); /* may or may not use the shell */
- warn("Can't exec \"%s\": %s", cmd, strerror(errno));
_exit(1);
}
/*SUPPRESS 560*/
- if (tmpgv = gv_fetchpv("$",TRUE))
+ if (tmpgv = gv_fetchpv("$",TRUE, SVt_PV))
sv_setiv(GvSV(tmpgv),(I32)getpid());
forkprocess = 0;
hv_clear(pidstatus); /* we have no children */
p[this] = p[that];
}
sv = *av_fetch(fdpid,p[this],TRUE);
- SvUPGRADE(sv,SVt_IV);
+ (void)SvUPGRADE(sv,SVt_IV);
SvIVX(sv) = pid;
forkprocess = pid;
return fdopen(p[this], mode);
fprintf(stderr,"%s", s);
for (fd = 0; fd < 32; fd++) {
- if (fstat(fd,&tmpstatbuf) >= 0)
+ if (Fstat(fd,&tmpstatbuf) >= 0)
fprintf(stderr," %d",fd);
}
fprintf(stderr,"\n");
int oldfd;
int newfd;
{
-#if defined(HAS_FCNTL) && defined(FFt_DUPFD)
+#if defined(HAS_FCNTL) && defined(F_DUPFD)
close(newfd);
- fcntl(oldfd, FFt_DUPFD, newfd);
+ fcntl(oldfd, F_DUPFD, newfd);
#else
int fdtmp[256];
I32 fdx = 0;
#endif
#ifndef DOSISH
+#ifndef VMS /* VMS' my_pclose() is in VMS.c */
I32
my_pclose(ptr)
FILE *ptr;
{
-#ifdef VOIDSIG
- void (*hstat)(), (*istat)(), (*qstat)();
-#else
- int (*hstat)(), (*istat)(), (*qstat)();
-#endif
+ Signal_t (*hstat)(), (*istat)(), (*qstat)();
int status;
- SV *sv;
+ SV **svp;
int pid;
- sv = *av_fetch(fdpid,fileno(ptr),TRUE);
- pid = SvIVX(sv);
- av_store(fdpid,fileno(ptr),Nullsv);
+ svp = av_fetch(fdpid,fileno(ptr),TRUE);
+ pid = SvIVX(*svp);
+ SvREFCNT_dec(*svp);
+ *svp = &sv_undef;
fclose(ptr);
#ifdef UTS
if(kill(pid, 0) < 0) { return(pid); } /* HOM 12/23/91 */
signal(SIGQUIT, qstat);
return(pid < 0 ? pid : status);
}
-
+#endif /* !VMS */
I32
wait4pid(pid,statusp,flags)
int pid;
int *statusp;
int flags;
{
- I32 result;
SV *sv;
SV** svp;
char spid[16];
hv_iterinit(pidstatus);
if (entry = hv_iternext(pidstatus)) {
- pid = atoi(hv_iterkey(entry,statusp));
+ pid = atoi(hv_iterkey(entry,(I32*)statusp));
sv = hv_iterval(pidstatus,entry);
*statusp = SvIVX(sv);
sprintf(spid, "%d", pid);
return pid;
}
}
-#ifdef HAS_WAIT4
- return wait4((pid==-1)?0:pid,statusp,flags,Null(struct rusage *));
-#else
#ifdef HAS_WAITPID
return waitpid(pid,statusp,flags);
#else
- if (flags)
- croak("Can't do waitpid with flags");
- else {
- while ((result = wait(statusp)) != pid && pid > 0 && result >= 0)
- pidgone(result,*statusp);
- if (result < 0)
- *statusp = -1;
+#ifdef HAS_WAIT4
+ return wait4((pid==-1)?0:pid,statusp,flags,Null(struct rusage *));
+#else
+ {
+ I32 result;
+ if (flags)
+ croak("Can't do waitpid with flags");
+ else {
+ while ((result = wait(statusp)) != pid && pid > 0 && result >= 0)
+ pidgone(result,*statusp);
+ if (result < 0)
+ *statusp = -1;
+ }
+ return result;
}
- return result;
#endif
#endif
}
sprintf(spid, "%d", pid);
sv = *hv_fetch(pidstatus,spid,strlen(spid),TRUE);
- SvUPGRADE(sv,SVt_IV);
+ (void)SvUPGRADE(sv,SVt_IV);
SvIVX(sv) = status;
return;
}
along = (long)f;
return (unsigned long)along;
}
+# undef BIGDOUBLE
+#endif
+
+#ifndef CASTI32
+I32
+cast_i32(f)
+double f;
+{
+# define BIGDOUBLE 2147483648.0 /* Assume 32 bit int's ! */
+# define BIGNEGDOUBLE (-2147483648.0)
+ if (f >= BIGDOUBLE)
+ return (I32)fmod(f, BIGDOUBLE);
+ if (f <= BIGNEGDOUBLE)
+ return (I32)fmod(f, BIGNEGDOUBLE);
+ return (I32) f;
+}
+# undef BIGDOUBLE
+# undef BIGNEGDOUBLE
+
+IV
+cast_iv(f)
+double f;
+{
+ /* XXX This should be fixed. It assumes 32 bit IV's. */
+# define BIGDOUBLE 2147483648.0 /* Assume 32 bit IV's ! */
+# define BIGNEGDOUBLE (-2147483648.0)
+ if (f >= BIGDOUBLE)
+ return (IV)fmod(f, BIGDOUBLE);
+ if (f <= BIGNEGDOUBLE)
+ return (IV)fmod(f, BIGNEGDOUBLE);
+ return (IV) f;
+}
+# undef BIGDOUBLE
+# undef BIGNEGDOUBLE
#endif
#ifndef HAS_RENAME
strcpy(tmpbuf,".");
else
strncpy(tmpbuf, a, fa - a);
- if (stat(tmpbuf, &tmpstatbuf1) < 0)
+ if (Stat(tmpbuf, &tmpstatbuf1) < 0)
return FALSE;
if (fb == b)
strcpy(tmpbuf,".");
else
strncpy(tmpbuf, b, fb - b);
- if (stat(tmpbuf, &tmpstatbuf2) < 0)
+ if (Stat(tmpbuf, &tmpstatbuf2) < 0)
return FALSE;
return tmpstatbuf1.st_dev == tmpstatbuf2.st_dev &&
tmpstatbuf1.st_ino == tmpstatbuf2.st_ino;
*retlen = s - start;
return retval;
}
+
+/* Amazingly enough, some systems (e.g. Dynix 3) don't have fmod.
+ This is a slow, stupid, but working emulation. (AD)
+*/
+#ifdef USE_MY_FMOD
+double
+my_fmod(x, y)
+double x, y;
+{
+ double i = 0.0; /* Can't use int because it can overflow */
+ if ((x == 0) || (y == 0))
+ return 0;
+ /* The sign of fmod is the same as the sign of x. */
+ if ( (x < 0 && y > 0) || (x > 0 && y < 0) )
+ y = -y;
+ if (x > 0) {
+ while (x - i*y > y)
+ i++;
+ } else {
+ while (x - i*y < y)
+ i++;
+ }
+ return x - i * y;
+}
+#endif