perl5.000 patch.0j: fix minor portability and build problems remaining even after...
[p5sagit/p5-mst-13.2.git] / util.c
diff --git a/util.c b/util.c
index f528cd5..d4920eb 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1,48 +1,16 @@
-/* $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 */
@@ -85,11 +59,7 @@ unsigned long size;
 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;
@@ -129,9 +99,9 @@ unsigned long size;
 #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) {
@@ -212,7 +182,8 @@ safexrealloc(where,size)
 char *where;
 MEM_SIZE size;
 {
-    return saferealloc(where - ALIGN, size + ALIGN) + ALIGN;
+    register char *new = saferealloc(where - ALIGN, size + ALIGN);
+    return new + ALIGN;
 }
 
 void
@@ -251,7 +222,7 @@ cpytill(to,from,fromend,delim,retlen)
 register char *to;
 register char *from;
 register char *fromend;
-register I32 delim;
+register int delim;
 I32 *retlen;
 {
     char *origto = to;
@@ -318,7 +289,7 @@ char *lend;
     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;
@@ -352,7 +323,7 @@ char *lend;
     register I32 first = *little;
     register char *littleend = lend;
 
-    if (!first && little > littleend)
+    if (!first && little >= littleend)
        return bigend;
     bigbeg = big;
     big = bigend - (littleend - little++);
@@ -410,7 +381,7 @@ I32 iflag;
        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 */
@@ -455,10 +426,11 @@ SV *littlestr;
     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);
@@ -473,12 +445,12 @@ SV *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;
@@ -661,8 +633,8 @@ SV *littlestr;
 
 I32
 ibcmp(a,b,len)
-register char *a;
-register char *b;
+register U8 *a;
+register U8 *b;
 register I32 len;
 {
     while (len--) {
@@ -680,7 +652,7 @@ register I32 len;
 /* copy a string to a safe spot */
 
 char *
-savestr(sv)
+savepv(sv)
 char *sv;
 {
     register char *newaddr;
@@ -693,7 +665,7 @@ char *sv;
 /* same thing but with a known length */
 
 char *
-nsavestr(sv, len)
+savepvn(sv, len)
 char *sv;
 register I32 len;
 {
@@ -705,24 +677,12 @@ 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)
@@ -735,7 +695,7 @@ long 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];
     }
@@ -745,21 +705,24 @@ long a1, a2, a3, a4;
     }
 
     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);
     }
@@ -778,6 +741,10 @@ long a1, a2, a3, a4;
     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)
@@ -800,53 +767,63 @@ long a1, a2, a3, a4;
 #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);
     }
@@ -857,24 +834,31 @@ va_list args;
        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)
@@ -883,19 +867,25 @@ va_dcl
     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);
@@ -904,8 +894,9 @@ va_dcl
 #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;
@@ -921,7 +912,7 @@ 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 */
     }
@@ -964,6 +955,7 @@ char *nam;
     }                                  /* potential SEGV's */
     return i;
 }
+#endif /* !VMS */
 
 #ifdef EUNICE
 I32
@@ -977,7 +969,7 @@ char *f;
 }
 #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;
@@ -1034,7 +1026,7 @@ register I32 len;
 #ifdef I_VARARGS
 #ifndef HAS_VPRINTF
 
-#ifdef CHARVSPRINTF
+#ifdef USE_CHAR_VSPRINTF
 char *
 #else
 int
@@ -1052,7 +1044,7 @@ char *dest, *pat, *args;
     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 */
@@ -1216,7 +1208,7 @@ VTOH(vtohs,short)
 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;
@@ -1258,7 +1250,7 @@ char      *mode;
            close(p[THIS]);
        }
        if (doexec) {
-#if !defined(HAS_FCNTL) || !defined(FFt_SETFD)
+#if !defined(HAS_FCNTL) || !defined(F_SETFD)
            int fd;
 
 #ifndef NOFILE
@@ -1268,11 +1260,10 @@ char    *mode;
                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 */
@@ -1288,7 +1279,7 @@ char      *mode;
        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);
@@ -1316,7 +1307,7 @@ char *s;
 
     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");
@@ -1328,9 +1319,9 @@ dup2(oldfd,newfd)
 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;
@@ -1348,22 +1339,20 @@ int newfd;
 #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 */
@@ -1377,14 +1366,13 @@ FILE *ptr;
     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];
@@ -1405,7 +1393,7 @@ int flags;
 
        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);
@@ -1413,21 +1401,24 @@ int flags;
            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
 }
@@ -1444,7 +1435,7 @@ int status;
 
     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;
 }
@@ -1518,6 +1509,22 @@ double 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
@@ -1549,13 +1556,13 @@ char *b;
        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;
@@ -1597,3 +1604,28 @@ I32 *retlen;
     *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