[STEP,2] ctype changes for removing locale structures

Message ID 003d01d3a1b7$925a12a0$b70e37e0$@jasoon.nl
State New
Headers show
Series
  • [STEP,2] ctype changes for removing locale structures
Related show

Commit Message

Jaap de Wolff Feb. 9, 2018, 3:06 p.m.
modify ctype not to use __locale_ctype_ptr (== __CTYPE_PTR) or
__locale_ctype_ptr_l
To do this al inline functions are removed, and the source implementations
test hard coded values of the given characters

Comments

Craig Howland Feb. 9, 2018, 3:50 p.m. | #1
On 02/09/2018 10:06 AM, Jaap de Wolff wrote:
> modify ctype not to use __locale_ctype_ptr (== __CTYPE_PTR) or

> __locale_ctype_ptr_l

> To do this al inline functions are removed, and the source implementations

> test hard coded values of the given characters

>

>

> ================================== PATCH =================

> diff --git a/newlib/libc/ctype/isalnum.c b/newlib/libc/ctype/isalnum.c

> index d926f97b7..6d3864114 100644

> --- a/newlib/libc/ctype/isalnum.c

> +++ b/newlib/libc/ctype/isalnum.c

> @@ -46,5 +46,9 @@ No OS subroutines are required.

>   int

>   isalnum (int c)

>   {

> +#ifdef _REENT_SMALL

> +	return (isdigit(c) | islower(c) | isupper(c));

> +#else

>   	return(__CTYPE_PTR[c+1] & (_U|_L|_N));

> +#endif

>   }

I would think that we should be able to do better than this, as this method is 
taking a half step backwards for some of the functions, such as isalnum().  That 
is, it potentially loses the efficiency of doing one table lookup plus one OR, 
as it needs to do N table lookups and N+N-1 ORs (where N appears to be from 
1-3).  I say "potentially" because maybe the compiler would end up reducing it 
to the 1+1 case, but maybe not, too (depending on compiler, compiler settings).  
Before locale was added, isalnum(), for example, was

return(__ctype_ptr__[c+1] & (_U|_L));

I'm not sure what the right thing is now (still __ctype_ptr__?), but the same 
basic thing ought to work, knowing the right thing to put in.  But for that 
matter, why not in the REENT_SMALL case simply redefine __CTYPE_PTR to point to 
the right thing?  Then all these other source file changes become unnecessary.  
It seems reasonable to expect this to work, and it would be a cleaner solution 
(since the is*.c files remain untouched, without #ifs).  The stated purpose of 
the patch is to stop ctype from using __locale_ctype_ptr, but ctype.h is where 
it is defined to be __CTYPE_PTR--so just define it differently.

Craig
Jaap de Wolff Feb. 9, 2018, 6:09 p.m. | #2
-----Oorspronkelijk bericht-----
Van: Jaap de Wolff [mailto:info@jasoon.nl] 
Verzonden: vrijdag 9 februari 2018 18:15
Aan: 'Craig Howland' <howland@LGSInnovations.com>
Onderwerp: RE: [PATCH][STEP 2] ctype changes for removing locale structures



> -----Oorspronkelijk bericht-----

> Van: newlib-owner@sourceware.org [mailto:newlib-owner@sourceware.org]

> Namens Craig Howland

> Verzonden: vrijdag 9 februari 2018 16:51

> Aan: newlib@sourceware.org

> Onderwerp: Re: [PATCH][STEP 2] ctype changes for removing locale 

> structures

> 

> On 02/09/2018 10:06 AM, Jaap de Wolff wrote:

> > modify ctype not to use __locale_ctype_ptr (== __CTYPE_PTR) or 

> > __locale_ctype_ptr_l To do this al inline functions are removed, and 

> > the source implementations test hard coded values of the given 

> > characters

> >

> >

> > ================================== PATCH ================= diff --

> git

> > a/newlib/libc/ctype/isalnum.c b/newlib/libc/ctype/isalnum.c index

> > d926f97b7..6d3864114 100644

> > --- a/newlib/libc/ctype/isalnum.c

> > +++ b/newlib/libc/ctype/isalnum.c

> > @@ -46,5 +46,9 @@ No OS subroutines are required.

> >   int

> >   isalnum (int c)

> >   {

> > +#ifdef _REENT_SMALL

> > +	return (isdigit(c) | islower(c) | isupper(c)); #else

> >   	return(__CTYPE_PTR[c+1] & (_U|_L|_N));

> > +#endif

> >   }

> I would think that we should be able to do better than this, as this 

> method is taking a half step backwards for some of the functions, such 

> as isalnum().  That is, it potentially loses the efficiency of doing 

> one table lookup plus one OR, as it needs to do N table lookups and 

> N+N-1 ORs (where N appears to be from 1-3).  I say "potentially" 

> because maybe the compiler would end up reducing it to the

> 1+1 case, but maybe not, too (depending on compiler, compiler 

> 1+settings). Before

> locale was added, isalnum(), for example, was

> 

> return(__ctype_ptr__[c+1] & (_U|_L));

> 

> I'm not sure what the right thing is now (still __ctype_ptr__?), but 

> the same basic thing ought to work, knowing the right thing to put in.  

> But for that matter, why not in the REENT_SMALL case simply redefine 

> __CTYPE_PTR to point to the right thing?  Then all these other source 

> file changes become unnecessary. It seems reasonable to expect this to 

> work, and it would be a cleaner solution (since the is*.c files remain 

> untouched, without #ifs).  The stated purpose of the patch is to stop 

> ctype from using __locale_ctype_ptr, but ctype.h is where it is defined to be __CTYPE_PTR--so just define it differently.

> 

> Craig


Craig,
In basic the intention of my patches is to make to memory footprint for embedded environment small.
I talked about locale, and a part of the locale definition is a lookup table with the characteristics of each character.
Of course it is possible to move the lookup table outside the locale, but then the lookup table still takes 257 bytes of memory.

In the beginning my intention was just to move the __global_locale table from ram to rom, and a reaction was that that was not enough when using embedded processors with 2K or even 1K of ROM and 128 bytes of RAM.

I do think that for the intended users of the REENT_SMALL computation speed (efficiency) is less important as memory.
So I replaces all usage of a lookup table by a (kind of) computation.

Jaap
Freddie Chopin Feb. 9, 2018, 7:23 p.m. | #3
On Fri, 2018-02-09 at 19:09 +0100, Jaap de Wolff wrote:
> In basic the intention of my patches is to make to memory footprint

> for embedded environment small.

> I talked about locale, and a part of the locale definition is a

> lookup table with the characteristics of each character.

> Of course it is possible to move the lookup table outside the locale,

> but then the lookup table still takes 257 bytes of memory.

> 

> In the beginning my intention was just to move the __global_locale

> table from ram to rom, and a reaction was that that was not enough

> when using embedded processors with 2K or even 1K of ROM and 128

> bytes of RAM.

> 

> I do think that for the intended users of the REENT_SMALL computation

> speed (efficiency) is less important as memory.

> So I replaces all usage of a lookup table by a (kind of) computation.


I use REENT_SMALL on pretty decent ARM microcontrollers, so I would not
 fit that description. Anyway - your change won't work with a chip that
has 128 bytes of memory anyway, as small reent would take ~95% of it. I
don't think a chip that has 1 or 2 kB of flash and 128 bytes of RAM is
a good target for writing firmware in C using a generic library like
newlib. If newlib will try to please everybody, finally it won't be
good for anyone...

I'm for some sort of configurable locale removal, so I have nothing
against this particular patches, just don't make reent-small something
that is slow an inefficient. For me reent-small is about the amount of
RAM used, not speed - a difference between ~1 kB vs ~110 bytes is quite
significant, especially if you actually need almost nothing from reent,
even more so in case of multithreaded apps...

Regards,
FCh
Corinna Vinschen Feb. 9, 2018, 7:32 p.m. | #4
On Feb  9 19:09, Jaap de Wolff wrote:
> Van: Jaap de Wolff [mailto:info@jasoon.nl] 

> > Van: newlib-owner@sourceware.org [mailto:newlib-owner@sourceware.org]

> > On 02/09/2018 10:06 AM, Jaap de Wolff wrote:

> > > modify ctype not to use __locale_ctype_ptr (== __CTYPE_PTR) or 

> > > __locale_ctype_ptr_l To do this al inline functions are removed, and 

> > > the source implementations test hard coded values of the given 

> > > characters

> > >

> > >

> > > ================================== PATCH ================= diff --

> > git

> > > a/newlib/libc/ctype/isalnum.c b/newlib/libc/ctype/isalnum.c index

> > > d926f97b7..6d3864114 100644

> > > --- a/newlib/libc/ctype/isalnum.c

> > > +++ b/newlib/libc/ctype/isalnum.c

> > > @@ -46,5 +46,9 @@ No OS subroutines are required.

> > >   int

> > >   isalnum (int c)

> > >   {

> > > +#ifdef _REENT_SMALL

> > > +	return (isdigit(c) | islower(c) | isupper(c)); #else

> > >   	return(__CTYPE_PTR[c+1] & (_U|_L|_N));

> > > +#endif

> > >   }

> > I would think that we should be able to do better than this, as this 

> > method is taking a half step backwards for some of the functions, such 

> > as isalnum().  That is, it potentially loses the efficiency of doing 

> > one table lookup plus one OR, as it needs to do N table lookups and 

> > N+N-1 ORs (where N appears to be from 1-3).  I say "potentially" 

> > because maybe the compiler would end up reducing it to the

> > 1+1 case, but maybe not, too (depending on compiler, compiler 

> > 1+settings). Before

> > locale was added, isalnum(), for example, was

> > 

> > return(__ctype_ptr__[c+1] & (_U|_L));

> > 

> > I'm not sure what the right thing is now (still __ctype_ptr__?), but 

> > the same basic thing ought to work, knowing the right thing to put in.  

> > But for that matter, why not in the REENT_SMALL case simply redefine 

> > __CTYPE_PTR to point to the right thing?  Then all these other source 

> > file changes become unnecessary. It seems reasonable to expect this to 

> > work, and it would be a cleaner solution (since the is*.c files remain 

> > untouched, without #ifs).  The stated purpose of the patch is to stop 

> > ctype from using __locale_ctype_ptr, but ctype.h is where it is defined to be __CTYPE_PTR--so just define it differently.

> > 

> > Craig

> 

> Craig,

> In basic the intention of my patches is to make to memory footprint for embedded environment small.

> I talked about locale, and a part of the locale definition is a lookup table with the characteristics of each character.

> Of course it is possible to move the lookup table outside the locale, but then the lookup table still takes 257 bytes of memory.

> 

> In the beginning my intention was just to move the __global_locale table from ram to rom, and a reaction was that that was not enough when using embedded processors with 2K or even 1K of ROM and 128 bytes of RAM.

> 

> I do think that for the intended users of the REENT_SMALL computation speed (efficiency) is less important as memory.

> So I replaces all usage of a lookup table by a (kind of) computation.


I'm more with what Craig said.  A pointer to a character table has been
used since newlib started in the 90s.  We never had complaints for using
a single character table before.


Corinna

-- 
Corinna Vinschen
Cygwin Maintainer
Red Hat
Craig Howland Feb. 9, 2018, 8:54 p.m. | #5
On 02/09/2018 02:32 PM, Corinna Vinschen wrote:
> On Feb  9 19:09, Jaap de Wolff wrote:

>> Van: Jaap de Wolff [mailto:info@jasoon.nl]

>>> Van: newlib-owner@sourceware.org [mailto:newlib-owner@sourceware.org]

>>> On 02/09/2018 10:06 AM, Jaap de Wolff wrote:

>>>> modify ctype not to use __locale_ctype_ptr (== __CTYPE_PTR) or

>>>> __locale_ctype_ptr_l To do this al inline functions are removed, and

>>>> the source implementations test hard coded values of the given

>>>> characters

>>>>

>>>>

>>>> ================================== PATCH ================= diff --

>>> git

>>>> a/newlib/libc/ctype/isalnum.c b/newlib/libc/ctype/isalnum.c index

>>>> d926f97b7..6d3864114 100644

>>>> --- a/newlib/libc/ctype/isalnum.c

>>>> +++ b/newlib/libc/ctype/isalnum.c

>>>> @@ -46,5 +46,9 @@ No OS subroutines are required.

>>>>    int

>>>>    isalnum (int c)

>>>>    {

>>>> +#ifdef _REENT_SMALL

>>>> +	return (isdigit(c) | islower(c) | isupper(c)); #else

>>>>    	return(__CTYPE_PTR[c+1] & (_U|_L|_N));

>>>> +#endif

>>>>    }

>>> I would think that we should be able to do better than this, as this

>>> method is taking a half step backwards for some of the functions, such

>>> as isalnum().  That is, it potentially loses the efficiency of doing

>>> one table lookup plus one OR, as it needs to do N table lookups and

>>> N+N-1 ORs (where N appears to be from 1-3).  I say "potentially"

>>> because maybe the compiler would end up reducing it to the

>>> 1+1 case, but maybe not, too (depending on compiler, compiler

>>> 1+settings). Before

>>> locale was added, isalnum(), for example, was

>>>

>>> return(__ctype_ptr__[c+1] & (_U|_L));

>>>

>>> I'm not sure what the right thing is now (still __ctype_ptr__?), but

>>> the same basic thing ought to work, knowing the right thing to put in.

>>> But for that matter, why not in the REENT_SMALL case simply redefine

>>> __CTYPE_PTR to point to the right thing?  Then all these other source

>>> file changes become unnecessary. It seems reasonable to expect this to

>>> work, and it would be a cleaner solution (since the is*.c files remain

>>> untouched, without #ifs).  The stated purpose of the patch is to stop

>>> ctype from using __locale_ctype_ptr, but ctype.h is where it is defined to be __CTYPE_PTR--so just define it differently.

>>>

>>> Craig

>> Craig,

>> In basic the intention of my patches is to make to memory footprint for embedded environment small.

>> I talked about locale, and a part of the locale definition is a lookup table with the characteristics of each character.

>> Of course it is possible to move the lookup table outside the locale, but then the lookup table still takes 257 bytes of memory.

>>

>> In the beginning my intention was just to move the __global_locale table from ram to rom, and a reaction was that that was not enough when using embedded processors with 2K or even 1K of ROM and 128 bytes of RAM.

>>

>> I do think that for the intended users of the REENT_SMALL computation speed (efficiency) is less important as memory.

>> So I replaces all usage of a lookup table by a (kind of) computation.

> I'm more with what Craig said.  A pointer to a character table has been

> used since newlib started in the 90s.  We never had complaints for using

> a single character table before.

>

>

> Corinna

>

Jaap has a good point, since the patch does actually totally get rid of the 
table and uses comparisons.  So while we could get more instructions in a few 
functions, it seems unlikely they would add up to the table, and that size could 
be saved even for the most minimal application.  In addition, the macro table 
lookup plus operation is likely larger than a function call, so the more an app 
calls them it is likely that, relatively speaking, more size is saved.

But to continue the discussion, a big-picture question/issue.  Is coupling it to 
REENT_SMALL the best approach?  Would ditching the table based on 
PREFER_SIZE_OVER_SPEED, as is done for a number of the string functions, make 
more sense?  Or maybe REENT_SMALL && PREFER_SIZE_OVER_SPEED?  A new option?  (In 
case this were somehow considered too radical.  For example, you might want your 
speed and be able to put the table into ROM and so save RAM space (as long as 
there are not too many macor calls).)

Another possible approach would be to say that the table and the macros should 
be kept, at the same time that the functions use PREFER_SIZE_OVER_SPEED to not 
use the table.  The user then has complete control over what they get on an 
individual call basis rather than a library basis.  If you want some speed and 
can afford the size of the table, just default to getting the macros.  If you 
don't want that, use whatever method you want to defeat the macros (#undef, 
escaping, etc.).

Craig

Craig
Corinna Vinschen Feb. 12, 2018, 9:59 a.m. | #6
On Feb  9 15:54, Craig Howland wrote:
> On 02/09/2018 02:32 PM, Corinna Vinschen wrote:

> > On Feb  9 19:09, Jaap de Wolff wrote:

> > > In basic the intention of my patches is to make to memory footprint for embedded environment small.

> > > I talked about locale, and a part of the locale definition is a lookup table with the characteristics of each character.

> > > Of course it is possible to move the lookup table outside the locale, but then the lookup table still takes 257 bytes of memory.

> > > 

> > > In the beginning my intention was just to move the __global_locale table from ram to rom, and a reaction was that that was not enough when using embedded processors with 2K or even 1K of ROM and 128 bytes of RAM.

> > > 

> > > I do think that for the intended users of the REENT_SMALL computation speed (efficiency) is less important as memory.

> > > So I replaces all usage of a lookup table by a (kind of) computation.

> > I'm more with what Craig said.  A pointer to a character table has been

> > used since newlib started in the 90s.  We never had complaints for using

> > a single character table before.

> > 

> Jaap has a good point, since the patch does actually totally get rid of the

> table and uses comparisons.  So while we could get more instructions in a

> few functions, it seems unlikely they would add up to the table, and that

> size could be saved even for the most minimal application.  In addition, the

> macro table lookup plus operation is likely larger than a function call, so

> the more an app calls them it is likely that, relatively speaking, more size

> is saved.

> 

> But to continue the discussion, a big-picture question/issue.  Is coupling

> it to REENT_SMALL the best approach?  Would ditching the table based on

> PREFER_SIZE_OVER_SPEED, as is done for a number of the string functions,

> make more sense?  Or maybe REENT_SMALL && PREFER_SIZE_OVER_SPEED?


PREFER_SIZE_OVER_SPEED sounds like the way to go.


Corinna

-- 
Corinna Vinschen
Cygwin Maintainer
Red Hat

Patch

================================== PATCH =================
diff --git a/newlib/libc/ctype/isalnum.c b/newlib/libc/ctype/isalnum.c
index d926f97b7..6d3864114 100644
--- a/newlib/libc/ctype/isalnum.c
+++ b/newlib/libc/ctype/isalnum.c
@@ -46,5 +46,9 @@  No OS subroutines are required.
 int
 isalnum (int c)
 {
+#ifdef _REENT_SMALL
+	return (isdigit(c) | islower(c) | isupper(c));
+#else
 	return(__CTYPE_PTR[c+1] & (_U|_L|_N));
+#endif
 }
diff --git a/newlib/libc/ctype/isalnum_l.c b/newlib/libc/ctype/isalnum_l.c
index dcb7e3652..d924898a6 100644
--- a/newlib/libc/ctype/isalnum_l.c
+++ b/newlib/libc/ctype/isalnum_l.c
@@ -6,5 +6,9 @@ 
 int
 isalnum_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return isalnum(c);
+#else
   return __locale_ctype_ptr_l (locale)[c+1] & (_U|_L|_N);
+#endif
 }
diff --git a/newlib/libc/ctype/isalpha.c b/newlib/libc/ctype/isalpha.c
index 8b8e78a29..4b98d1d90 100644
--- a/newlib/libc/ctype/isalpha.c
+++ b/newlib/libc/ctype/isalpha.c
@@ -45,5 +45,9 @@  No supporting OS subroutines are required.
 int
 isalpha (int c)
 {
+#ifdef 	_REENT_SMALL
+	return (islower(c) | isupper(c));
+#else
 	return(__CTYPE_PTR[c+1] & (_U|_L));
+#endif
 }
diff --git a/newlib/libc/ctype/isalpha_l.c b/newlib/libc/ctype/isalpha_l.c
index dcae3ccb4..187d956b7 100644
--- a/newlib/libc/ctype/isalpha_l.c
+++ b/newlib/libc/ctype/isalpha_l.c
@@ -6,5 +6,9 @@ 
 int
 isalpha_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return isalpha(c);
+#else
   return __locale_ctype_ptr_l (locale)[c+1] & (_U|_L);
+#endif
 }
diff --git a/newlib/libc/ctype/isblank.c b/newlib/libc/ctype/isblank.c
index 0ebc2192c..4d8cceb6a 100644
--- a/newlib/libc/ctype/isblank.c
+++ b/newlib/libc/ctype/isblank.c
@@ -44,5 +44,9 @@  No supporting OS subroutines are required.
 int
 isblank (int c)
 {
+#ifdef _REENT_SMALL
+	return ((c == ' ') || (c == '\t'))?1:0;
+#else
 	return ((__CTYPE_PTR[c+1] & _B) || (c == '\t'));
+#endif
 }
diff --git a/newlib/libc/ctype/isblank_l.c b/newlib/libc/ctype/isblank_l.c
index 8bbb84e1f..b9b43fceb 100644
--- a/newlib/libc/ctype/isblank_l.c
+++ b/newlib/libc/ctype/isblank_l.c
@@ -6,5 +6,9 @@ 
 int
 isblank_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return isblank(c);
+#else
   return (__locale_ctype_ptr_l (locale)[c+1] & _B) || (c == '\t');
+#endif
 }
diff --git a/newlib/libc/ctype/iscntrl.c b/newlib/libc/ctype/iscntrl.c
index ebbdd7371..64abf7f07 100644
--- a/newlib/libc/ctype/iscntrl.c
+++ b/newlib/libc/ctype/iscntrl.c
@@ -48,5 +48,9 @@  No supporting OS subroutines are required.
 int
 iscntrl (int c)
 {
+#ifdef _REENT_SMALL
+	return ((c < 0x20) || (c == 0x7F))?1:0;
+#else
 	return(__CTYPE_PTR[c+1] & _C);
+#endif
 }
diff --git a/newlib/libc/ctype/iscntrl_l.c b/newlib/libc/ctype/iscntrl_l.c
index 0ae17c7f7..0186bfa4b 100644
--- a/newlib/libc/ctype/iscntrl_l.c
+++ b/newlib/libc/ctype/iscntrl_l.c
@@ -6,5 +6,9 @@ 
 int
 iscntrl_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return iscntrl(c);
+#else
   return __locale_ctype_ptr_l (locale)[c+1] & _C;
+#endif
 }
diff --git a/newlib/libc/ctype/isdigit.c b/newlib/libc/ctype/isdigit.c
index a5c511964..e5d033326 100644
--- a/newlib/libc/ctype/isdigit.c
+++ b/newlib/libc/ctype/isdigit.c
@@ -47,5 +47,9 @@  No supporting OS subroutines are required.
 int
 isdigit (int c)
 {
+#ifdef _REENT_SMALL
+	return ((c > 0x2F) && (c < 0x3A))?1:0;
+#else
 	return(__CTYPE_PTR[c+1] & _N);
+#endif
 }
diff --git a/newlib/libc/ctype/isdigit_l.c b/newlib/libc/ctype/isdigit_l.c
index 1fb79e000..6ca875d36 100644
--- a/newlib/libc/ctype/isdigit_l.c
+++ b/newlib/libc/ctype/isdigit_l.c
@@ -6,5 +6,9 @@ 
 int
 isdigit_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return isdigit(c);
+#else
   return __locale_ctype_ptr_l (locale)[c+1] & _N;
+#endif
 }
diff --git a/newlib/libc/ctype/islower.c b/newlib/libc/ctype/islower.c
index 2b3440489..d67cf8f3c 100644
--- a/newlib/libc/ctype/islower.c
+++ b/newlib/libc/ctype/islower.c
@@ -45,5 +45,9 @@  No supporting OS subroutines are required.
 int
 islower (int c)
 {
+#ifdef _REENT_SMALL
+	return ((c > 0x60) && (c < 0x7B))?1:0;
+#else
 	return ((__CTYPE_PTR[c+1] & (_U|_L)) == _L);
+#endif
 }
diff --git a/newlib/libc/ctype/islower_l.c b/newlib/libc/ctype/islower_l.c
index d1f3a82d8..2469ba453 100644
--- a/newlib/libc/ctype/islower_l.c
+++ b/newlib/libc/ctype/islower_l.c
@@ -6,5 +6,9 @@ 
 int
 islower_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return islower(c);
+#else
   return (__locale_ctype_ptr_l (locale)[c+1] & (_U|_L)) == _L;
+#endif
 }
diff --git a/newlib/libc/ctype/isprint.c b/newlib/libc/ctype/isprint.c
index e34fbe28a..7b5c4bb1f 100644
--- a/newlib/libc/ctype/isprint.c
+++ b/newlib/libc/ctype/isprint.c
@@ -59,7 +59,11 @@  No supporting OS subroutines are required.
 int
 isgraph (int c)
 {
+#ifdef _REENT_SMALL
+	return ((c > 0x20) && (c < 0x7F))?1:0;
+#else
 	return(__CTYPE_PTR[c+1] & (_P|_U|_L|_N));
+#endif
 }
 
 
@@ -67,5 +71,9 @@  isgraph (int c)
 int
 isprint (int c)
 {
+#ifdef _REENT_SMALL
+	return ((c > 0x1F) && (c < 0x7F))?1:0;
+#else
 	return(__CTYPE_PTR[c+1] & (_P|_U|_L|_N|_B));
+#endif
 }
diff --git a/newlib/libc/ctype/isprint_l.c b/newlib/libc/ctype/isprint_l.c
index 535504f14..297c83498 100644
--- a/newlib/libc/ctype/isprint_l.c
+++ b/newlib/libc/ctype/isprint_l.c
@@ -6,7 +6,11 @@ 
 int
 isgraph_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return isgraph(c);
+#else
   return __locale_ctype_ptr_l (locale)[c+1] & (_P|_U|_L|_N);
+#endif
 }
 
 #undef isprint_l
@@ -14,5 +18,9 @@  isgraph_l (int c, struct __locale_t *locale)
 int
 isprint_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return isprint(c);
+#else
   return __locale_ctype_ptr_l (locale)[c+1] & (_P|_U|_L|_N|_B);
+#endif
 }
diff --git a/newlib/libc/ctype/ispunct.c b/newlib/libc/ctype/ispunct.c
index 9c5a3fcca..d28172e3a 100644
--- a/newlib/libc/ctype/ispunct.c
+++ b/newlib/libc/ctype/ispunct.c
@@ -47,5 +47,11 @@  No supporting OS subroutines are required.
 int
 ispunct (int c)
 {
+#ifdef _REENT_SMALL
+	return ( ((c > 0x20) && (c < 0x30)) ||
+	         ((c > 0x5A) && (c < 0x60)) ||
+	         ((c > 0x7A) && (c < 0x7F)) )?1:0;
+#else
 	return(__CTYPE_PTR[c+1] & _P);
+#endif
 }
diff --git a/newlib/libc/ctype/ispunct_l.c b/newlib/libc/ctype/ispunct_l.c
index eeba1f5ae..aef30f057 100644
--- a/newlib/libc/ctype/ispunct_l.c
+++ b/newlib/libc/ctype/ispunct_l.c
@@ -6,6 +6,10 @@ 
 int
 ispunct_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return ispunct(c);
+#else
   return __locale_ctype_ptr_l (locale)[c+1] & _P;
+#endif
 }
 
diff --git a/newlib/libc/ctype/isspace.c b/newlib/libc/ctype/isspace.c
index 0def2c0ce..ad36a2ac9 100644
--- a/newlib/libc/ctype/isspace.c
+++ b/newlib/libc/ctype/isspace.c
@@ -46,5 +46,9 @@  No supporting OS subroutines are required.
 int
 isspace (int c)
 {
+#ifdef _REENT_SMALL
+	return (((c > 0x7) && (c < 0x0E)) || (c == ' '))?1:0;
+#else
 	return(__CTYPE_PTR[c+1] & _S);
+#endif
 }
diff --git a/newlib/libc/ctype/isspace_l.c b/newlib/libc/ctype/isspace_l.c
index bf4a36c3e..d83cd1658 100644
--- a/newlib/libc/ctype/isspace_l.c
+++ b/newlib/libc/ctype/isspace_l.c
@@ -6,6 +6,10 @@ 
 int
 isspace_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return isspace(c);
+#else
   return __locale_ctype_ptr_l (locale)[c+1] & _S;
+#endif
 }
 
diff --git a/newlib/libc/ctype/isupper.c b/newlib/libc/ctype/isupper.c
index aeed383ec..e7f121d0e 100644
--- a/newlib/libc/ctype/isupper.c
+++ b/newlib/libc/ctype/isupper.c
@@ -43,5 +43,9 @@  No supporting OS subroutines are required.
 int
 isupper (int c)
 {
+#ifdef _REENT_SMALL
+	return ((c > 0x40) && (c < 0x4B));
+#else
 	return ((__CTYPE_PTR[c+1] & (_U|_L)) == _U);
+#endif
 }
diff --git a/newlib/libc/ctype/isupper_l.c b/newlib/libc/ctype/isupper_l.c
index eb473a7a1..1d7068431 100644
--- a/newlib/libc/ctype/isupper_l.c
+++ b/newlib/libc/ctype/isupper_l.c
@@ -6,6 +6,10 @@ 
 int
 isupper_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return isupper(c);
+#else
   return (__locale_ctype_ptr_l (locale)[c+1] & (_U|_L)) == _U;
+#endif
 }
 
diff --git a/newlib/libc/ctype/isxdigit.c b/newlib/libc/ctype/isxdigit.c
index 2bfe18dbf..ff5248122 100644
--- a/newlib/libc/ctype/isxdigit.c
+++ b/newlib/libc/ctype/isxdigit.c
@@ -46,5 +46,11 @@  No supporting OS subroutines are required.
 int
 isxdigit (int c)
 {
+#ifdef _REENT_SMALL
+	return ( ((c > 0x2F) && (c < 0x3A)) ||
+                 ((c > 0x40) && (c < 0x48)) ||
+	         ((c > 0x60) && (c < 0x68)) )?1:0;
+#else
 	return(__CTYPE_PTR[c+1] & ((_X)|(_N)));
+#endif
 }
diff --git a/newlib/libc/ctype/isxdigit_l.c b/newlib/libc/ctype/isxdigit_l.c
index 726db3190..17d278070 100644
--- a/newlib/libc/ctype/isxdigit_l.c
+++ b/newlib/libc/ctype/isxdigit_l.c
@@ -6,6 +6,10 @@ 
 int
 isxdigit_l (int c, struct __locale_t *locale)
 {
+#ifdef _REENT_SMALL
+  return isxdigit(c);
+#else
   return __locale_ctype_ptr_l (locale)[c+1] & ((_X)|(_N));
+#endif
 }
 
diff --git a/newlib/libc/include/ctype.h b/newlib/libc/include/ctype.h
index f74b3499b..c21ad94da 100644
--- a/newlib/libc/include/ctype.h
+++ b/newlib/libc/include/ctype.h
@@ -66,10 +66,13 @@  extern int toascii_l (int __c, locale_t __l);
 #define _X	0100
 #define	_B	0200
 
+#ifndef _REENT_SMALL
 const char *__locale_ctype_ptr (void);
 # define __CTYPE_PTR	(__locale_ctype_ptr ())
 
-#ifndef __cplusplus
+#endif /* !_REENT_SMALL */
+
+#if !defined (__cplusplus) && !defined(_REENT_SMALL)
 /* These macros are intentionally written in a manner that will trigger
    a gcc -Wall warning if the user mistakenly passes a 'char' instead
    of an int containing an 'unsigned char'.  Note that the sizeof will