delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/2001/03/01/09:12:59

Date: Thu, 1 Mar 2001 16:06:43 +0200 (IST)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
X-Sender: eliz AT is
To: Rafael García <rafael AT geninfor DOT com>
cc: djgpp AT delorie DOT com
Subject: RE: atoi() with 8 bit chars
In-Reply-To: <3a9e528a$1@filemon.telecable.es>
Message-ID: <Pine.SUN.3.91.1010301155459.7052D-100000@is>
MIME-Version: 1.0
Reply-To: djgpp AT delorie DOT com
Errors-To: nobody AT delorie DOT com
X-Mailing-List: djgpp AT delorie DOT com
X-Unsubscribes-To: listserv AT delorie DOT com

On Thu, 1 Mar 2001, Rafael Garc=EDa wrote:

> > It's a bug in the library; thanks for reporting it.  Here's a patch
> > for the strtol function which is responsible for this bug:
> > .........
>=20
> I don't know how to aply that. I only have binary version of the compiler=
.

The patch is for the library, not for the compiler.

All you need to do is download v2/djlsr203.zip (1.5MB), extract strtol.c=20
from there, apply the patch to it, compile it, and put it into libc.a. =20
The DJGPP FAQ explains how to do that in section 21.4.  I am attaching=20
below a patched version of strtol.c, so that you could bypass the first=20
step entirely.

> Nor I am interested in substitute all the compiler instalations I can use=
.

Are you interested in having a library that can be trusted?  The version=20
of strtol below was thoroughly tested and improved over the years.  While=
=20
you did find a bug there, feeding 8-bit characters to strtol is not a=20
very frequent operation; most of the time, strtol and atoi have to deal
with numeric strings, and the library version works very well for those,=20
including some very difficult and subtle cases (take a look at the source=
=20
below, and you will see it).

> #undef atol        // now I have to call original ones
> #undef atoi
> #undef strtol
>=20
> long myatol(const char *s) {
>    while (isspace(*s)) s++;
>    if (*s & 0x80) return 0;
>    else return atol(s);
>    }

This will not work reliably, because some library functions call strtol=20
internally.  They will bypass these macros.

> 1) How can I remove "assignment discards qualifiers from pointer target
> type" warning at
> "*endp=3Ds" line?

Use `unconst'.  See the source below for an example.

> 2) Is it possible to know library version, to not use this patch when not
> necessary?...
> Something like #if defined(__DJGPP__) && (__DJGPPVER__<XXX)

See section 8.7 of the DJGPP FAQ list.

Here's the patched strtol:

/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */
#include <limits.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <libc/unconst.h>

long
strtol(const char *nptr, char **endptr, int base)
{
  const char *s =3D nptr;
  unsigned long acc;
  int c;
  unsigned long cutoff;
  int neg =3D 0, any, cutlim;

  /*
   * Skip white space and pick up leading +/- sign if any.
   * If base is 0, allow 0x for hex and 0 for octal, else
   * assume decimal; if base is already 16, allow 0x.
   */
  do {
    c =3D *s++;
  } while (isspace(c & 0xff));
  if (c =3D=3D '-')
  {
    neg =3D 1;
    c =3D *s++;
  }
  else if (c =3D=3D '+')
    c =3D *s++;
  if ((base =3D=3D 0 || base =3D=3D 16) &&
      c =3D=3D '0' && (*s =3D=3D 'x' || *s =3D=3D 'X'))
  {
    c =3D s[1];
    s +=3D 2;
    base =3D 16;
  }
  if (base =3D=3D 0)
    base =3D c =3D=3D '0' ? 8 : 10;

  /*
   * Compute the cutoff value between legal numbers and illegal
   * numbers.  That is the largest legal value, divided by the
   * base.  An input number that is greater than this value, if
   * followed by a legal input character, is too big.  One that
   * is equal to this value may be valid or not; the limit
   * between valid and invalid numbers is then based on the last
   * digit.  For instance, if the range for longs is
   * [-2147483648..2147483647] and the input base is 10,
   * cutoff will be set to 214748364 and cutlim to either
   * 7 (neg=3D=3D0) or 8 (neg=3D=3D1), meaning that if we have accumulated
   * a value > 214748364, or equal but the next digit is > 7 (or 8),
   * the number is too big, and we will return a range error.
   *
   * Set any if any `digits' consumed; make it negative to indicate
   * overflow.
   */
  cutoff =3D neg ? -(unsigned long)LONG_MIN : LONG_MAX;
  cutlim =3D cutoff % (unsigned long)base;
  cutoff /=3D (unsigned long)base;
  for (acc =3D 0, any =3D 0, c &=3D 0xff;; c =3D *s++, c &=3D 0xff)
  {
    if (isdigit(c))
      c -=3D '0';
    else if (isalpha(c))
      c -=3D isupper(c) ? 'A' - 10 : 'a' - 10;
    else
      break;
    if (c >=3D base)
      break;
    if (any < 0 || acc > cutoff || (acc =3D=3D cutoff && c > cutlim))
      any =3D -1;
    else
    {
      any =3D 1;
      acc *=3D base;
      acc +=3D c;
    }
  }
  if (any < 0)
  {
    acc =3D neg ? LONG_MIN : LONG_MAX;
    errno =3D ERANGE;
  }
  else if (neg)
    acc =3D -acc;
  if (endptr !=3D 0)
    *endptr =3D any ? unconst(s, char *) - 1 : unconst(nptr, char *);
  return acc;
}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019