[comp.sys.amiga.programmer] C string library?

ben@epmooch.UUCP (Rev. Ben A. Mesander) (02/08/91)

>In article <874@cbmger.UUCP> peterk@cbmger.UUCP (Peter Kittel GERMANY) writes:

>Now it should be possible to have a set of functions which initialize
>a memory area and allocate dynamically all my strings in that space
>just as a Basic interpreter does. Plus a good and fast garbage collection.
>And plus all the nice string functions that make Basic programming such
>a fun. And if you would add further flexibility over the Basic approach,
>then one could add dynamic growth of the whole string area, where you
>in Basic once and for all must decide for a certain amount by CLEAR.
>
>So, is there such a beast out there?
>

Try creative use of the C libraries realloc() function call.

>BTW: Converting Basic to C by hand isn't that difficult! Just take any
>editor, do some global search and replace (":" --> ";", "IF " --> "if(",
>"END IF" --> "}", and so on), and do some recoding on things like
>OPEN or WINDOW, and you already have most of the work done. Worse is
>it with such simple things like INPUT or INKEY$ :-(. Yes, AND strings.

Sounds like you might be able to write a sed, awk, perl, or MicroEMACS
program to do most of the grunt work.

>-- 
>Best regards, Dr. Peter Kittel  // E-Mail to  \\  Only my personal opinions... 
>Commodore Frankfurt, Germany  \X/ {uunet|pyramid|rutgers}!cbmvax!cbmger!peterk

--
ben@epmooch.UUCP            ben%servalan.UUCP@uokmax.ecn.uoknor.edu
{chinet,uokmax}!servalan!epmooch!ben  (Ben Mesander)   War in gulf:
newpath 288 396 216 0 360 arc 288 612 moveto 288 180 lineto 288 396
moveto 136 244 lineto 288 396 moveto 440 244 lineto 36 setlinewidth
stroke showpage

peterk@cbmger.UUCP (Peter Kittel GERMANY) (02/09/91)

As a died-in-the-wool user of Basic (yes, AmigaBasic :-), who does
also a little in C by porting some of my Basic programs to C, I always
find it the most tedious thing to deal with strings. Well, I have
that article by Ralph Babel somewhere where he explains which
functions in C resemble which Basic string functions. But this doesn't
help with the principal problem of declaring and handling of dynamically
sized strings. You must know, in AmigaBasic a string can grow as big as
32 KB, and it is absolutely impossible to declare every C string by
default with 32 K elements.

Now it should be possible to have a set of functions which initialize
a memory area and allocate dynamically all my strings in that space
just as a Basic interpreter does. Plus a good and fast garbage collection.
And plus all the nice string functions that make Basic programming such
a fun. And if you would add further flexibility over the Basic approach,
then one could add dynamic growth of the whole string area, where you
in Basic once and for all must decide for a certain amount by CLEAR.

So, is there such a beast out there?

BTW: Converting Basic to C by hand isn't that difficult! Just take any
editor, do some global search and replace (":" --> ";", "IF " --> "if(",
"END IF" --> "}", and so on), and do some recoding on things like
OPEN or WINDOW, and you already have most of the work done. Worse is
it with such simple things like INPUT or INKEY$ :-(. Yes, AND strings.

-- 
Best regards, Dr. Peter Kittel  // E-Mail to  \\  Only my personal opinions... 
Commodore Frankfurt, Germany  \X/ {uunet|pyramid|rutgers}!cbmvax!cbmger!peterk

jbickers@templar.actrix.gen.nz (John Bickers) (02/11/91)

Quoted from <874@cbmger.UUCP> by peterk@cbmger.UUCP (Peter Kittel GERMANY):
> As a died-in-the-wool user of Basic (yes, AmigaBasic :-), who does
> also a little in C by porting some of my Basic programs to C, I always
> find it the most tedious thing to deal with strings. Well, I have

    You mean you don't consider moving character pointers around like
    crazy fun? :)

> Best regards, Dr. Peter Kittel  // E-Mail to  \\  Only my personal opinions... 
--
*** John Bickers, TAP, NZAmigaUG.        jbickers@templar.actrix.gen.nz ***
***         "Patterns multiplying, re-direct our view" - Devo.          ***

bernie@metapro.DIALix.oz.au (Bernd Felsche) (02/15/91)

In <874@cbmger.UUCP> peterk@cbmger.UUCP (Peter Kittel GERMANY) writes:

>Now it should be possible to have a set of functions which initialize
>a memory area and allocate dynamically all my strings in that space
>just as a Basic interpreter does. Plus a good and fast garbage collection.
>And plus all the nice string functions that make Basic programming such
>a fun. And if you would add further flexibility over the Basic approach,
>then one could add dynamic growth of the whole string area, where you
>in Basic once and for all must decide for a certain amount by CLEAR.

>So, is there such a beast out there?

This is what I use under UNIX, though it should work under AmigaDOS as
well. It doesn't do any garbage collection, but it's fast! Also, there
is no mechanism to grow a string, though that should be a bit easier
to implement (for somebody else :-)).

It works by having a linked list pointing to a cluster of malloc'd
memory chunks, the size of which can be "defined" at the start.

When addstring() is called, it stores the nominated string in an
allocated memory chunks, before returning a pointer to it. If there
is insufficient space in existing chunks, then a new one is
allocated, along with another linked-list element.

If the string to be stored is larger than the nominal chunks size,
then it is stored in its own chunk.

The bad news is that there is no garbage collection, or indeed code to
free up space. See my notes at the end of the listing. I'm relying on
malloc'd chunks being cleaned up automatically upon exit.


P.S. the missing fatal() and sysfatal() routines do nothing more than
displaying the error text somewhere convenient, and exiting with an
error condition.

___________________________________space.c_____________________________________

/*
 * Buffer some strings in dynamically allocated RAM chunks
 */

#define	NULL	0
#include <sys/types.h>
#include <string.h>

char *malloc();

/*
 * allocated in ALLOC_SPACE chunks, and expanded
 * dynamically, if it isn't eno...ugh
 */

#define ALLOC_SPACE 8000
#define ALLOC_LOW	16

struct p_space {
	char *free;		/* next free space in this chunk */
	int avail;		/* amount of available space in this chunk*/
	struct p_space *next; 	/* next p_space chunk */
	char *stuff;		/* this space chunk */
};

static struct p_space *MEMLIST;	/* the head of the linked list */
static struct p_space *MEMLAST;	/* the head of the mostly - free linked list */

char *addstring(string)
char *string;		/* text string */
{
	struct p_space *chunk;
	int length;
	char *place;

	length = strlen(string) + 1;	/* remember null! */

	if( MEMLIST == NULL ) {	/* no space yet allocated */
		if( !(MEMLIST = (struct p_space *)
				malloc(sizeof(struct p_space))) )
			sysfatal("cannot allocate space for string");
		MEMLIST->avail = (length < ALLOC_SPACE ? ALLOC_SPACE : length);
		if( !(MEMLIST->stuff = malloc(MEMLIST->avail)) )
			sysfatal("cannot allocate chunk");
		MEMLIST->free  = MEMLIST->stuff;
		MEMLIST->next  = NULL;
		MEMLAST = MEMLIST;
		chunk = MEMLAST;
	}
	chunk = MEMLAST;

	/* search for enough free space in any chunk */
	while ( length >= chunk->avail && chunk->next ) {
		if( chunk->avail < ALLOC_LOW )
			MEMLAST = chunk->next;
			/* speedup if low water reached */
		chunk = chunk->next;
	}

	if( !chunk->next && length >= chunk->avail ) {
		/* can't find enough space */
		if( !(chunk->next = (struct p_space *)
				malloc(sizeof(struct p_space))) )
			sysfatal("cannot allocate space for string");
		chunk = chunk->next;
		chunk->avail = (length < ALLOC_SPACE ? ALLOC_SPACE : length);
		if( !(chunk->stuff = malloc(chunk->avail)) )
			sysfatal("cannot allocate chunk");
		chunk->free  = chunk->stuff;
		chunk->next  = NULL;
	}

	/* copy string to chunk */
	place = strcpy(chunk->free, string);
	if ( place != chunk->free ) fatal("error in string copy");

	chunk->free  += length;
	chunk->avail -= length;

	return(place);
}

char *delstring(string)
char *string;
{	/* an exercise for the programmer :-) */ }

___________________________________the.end_____________________________________

How's that for some pointers in C?

-- 
 _--_|\  Bernd Felsche         #include <std/disclaimer.h>
/      \ Metapro Systems, 328 Albany Highway, Victoria Park,  Western Australia
\_.--._/ Fax: +61 9 472 3337   Phone: +61 9 362 9355  TZ=WST-8
      v  E-Mail: bernie@metapro.DIALix.oz.au | bernie@DIALix.oz.au

peterk@cbmger.UUCP (Peter Kittel GERMANY) (02/18/91)

In article <1991Feb15.050640.15436@metapro.DIALix.oz.au> bernie@metapro.DIALix.oz.au (Bernd Felsche) writes:
>In <874@cbmger.UUCP> peterk@cbmger.UUCP (Peter Kittel GERMANY) writes:
>
>>Now it should be possible to have a set of functions which initialize
>>a memory area and allocate dynamically all my strings in that space
>>just as a Basic interpreter does. Plus a good and fast garbage collection.
>
>This is what I use under UNIX, though it should work under AmigaDOS as
>well. It doesn't do any garbage collection, but it's fast! Also, there
>is no mechanism to grow a string, though that should be a bit easier
>to implement (for somebody else :-)).
>
>It works by having a linked list pointing to a cluster of malloc'd
>memory chunks, the size of which can be "defined" at the start.

Thanks for the code, I'll look into it. Well, being lazy, I already
thought about something similar, but the management of all those
linked lists together with string growing plus garbage collection
really frightens me. Now:

How about an approach similar to the one AmigaBasic takes it?
It has one heap space like any Basic interpreter from the old days.
This space is for prog + all variables, strings included. If you need
more space, you reserve some with the CLEAR statement. Now something
peculiar with this statement: It doesn't throw away the old space
and then allocates new one (it could, because it clears all variables
as the name implies), but first allocates the new area and only then
frees the old one. (So to get big chunks in tight memory situations
you have to use the trick to call it twice, once with the minimum
memory for your program (to free as much of system memory as possible),
and only then issue the real CLEAR statement.)

So I could do all this space reserving for my strings in a similar
manner: Initially reserve one big chunk of some arbitrary size, say
25 K, like in AmigaBasic. Like in an old Basic interpreter, store
your string pointers from the bottom of this area, the strings
themselves from the top. To speed up garbage collection, store a
back pointer into the pointer table with every string like in the
CBM 8032 Basic. Now when you run out of space, then allocate a
bigger chunk of memory in some arbitrary step, completely copy the
old area into the new one (you must do heavy pointer recalculations
then), and only thereafter free the old area. Well, this is not
extremely system and multitasking friendly and you risk to run out
of memory earlier, because you a) need it in contiguous chunks, and
b) need nearly twice the space temporarily, but it all appears much
easier to me. Any comments?

-- 
Best regards, Dr. Peter Kittel  // E-Mail to  \\  Only my personal opinions... 
Commodore Frankfurt, Germany  \X/ {uunet|pyramid|rutgers}!cbmvax!cbmger!peterk

andrew@teslab.lab.OZ (Andrew Phillips) (02/20/91)

In <874@cbmger.UUCP> by peterk@cbmger.UUCP (Peter Kittel) writes:
> [Idea to (re?)write C string routines to look like BASIC ones]

You couldn't rewrite the standard string routines (strcpy, strcat
etc) to work like the BASIC ones but you could write a new set of
routines to do exactly what BASIC does (I think I heard of someone
doing that a long time ago).

Actually you would be much better off using C++.  Then you could
use your own string type in code like:

	str a, b, c;

	a = "Name: ";	-- assign C string to "str" type
	putstr(a);	-- output of str
	b = getstr();	-- input of str
	c = a + b;	-- concatenation of str

by having a string type which would be a sort of pointer to a real
string and overloading operators "+", "=" etc.

Most C programmers prefer the standard C string routines because they
know what they are doing exactly internally whereas the BASIC ones
are a bit unknown/unpredictable, especially when they decide to do a
bit of garbage collection.  I have a whole lot of string routines
that I wrote that make using normal C strings a lot easier.  If
anybody is interested in them I could get them posted to c.s.a.

Andrew.
-- 
Andrew Phillips (andrew@teslab.lab.oz.au) Phone +61 (Aust) 2 (Sydney) 289 8712

peterk@cbmger.UUCP (Peter Kittel GERMANY) (02/21/91)

In article <1206@teslab.lab.OZ> andrew@teslab.lab.oz.au (Andrew Phillips) writes:
>
>  I have a whole lot of string routines
>that I wrote that make using normal C strings a lot easier.  If
>anybody is interested in them I could get them posted to c.s.a.

You guess: I *AM* interested :-)

-- 
Best regards, Dr. Peter Kittel  // E-Mail to  \\  Only my personal opinions... 
Commodore Frankfurt, Germany  \X/ {uunet|pyramid|rutgers}!cbmvax!cbmger!peterk

bernie@metapro.DIALix.oz.au (Bernd Felsche) (02/25/91)

In <900@cbmger.UUCP> peterk@cbmger.UUCP (Peter Kittel GERMANY) writes:

>In article <1991Feb15.050640.15436@metapro.DIALix.oz.au> bernie@metapro.DIALix.oz.au (Bernd Felsche) writes:
>>This is what I use under UNIX, though it should work under AmigaDOS as
>>well. It doesn't do any garbage collection, but it's fast! Also, there
>>is no mechanism to grow a string, though that should be a bit easier
>>to implement (for somebody else :-)).
>>
>>It works by having a linked list pointing to a cluster of malloc'd
>>memory chunks, the size of which can be "defined" at the start.

>Thanks for the code, I'll look into it. Well, being lazy, I already
>thought about something similar, but the management of all those
>linked lists together with string growing plus garbage collection
>really frightens me. Now:

Not that I'm really motivated to do it right now, but; the freeing up
and garbage collection routines can be handled by adding new (fake)
space headers, and coalescing these when appropriate. This is easier
said than done, unless you're drunk :-)

Regarding your pointer-angst; it's really not _that_ hard. Besides,
it's only ONE linked list of headers. You can add a new free header
list, or tag it on the end of the others.

>How about an approach similar to the one AmigaBasic takes it?
[stuff about AmigaBasic and others zapped]

Yuk.... A MicroSloth product!  Wash your mouth out! :-) 

This can be almost as complicated, if not more complicated. You will
notice that my code pre-allocates chunks of memory, the size of which
can be selected at compile time. The reason for this approach is that
a minimum of memory is pre-allocated, leaving as much as (reasonably)
possible, for other processes.

The mechanism for "growing" strings in the schemes you mentioned would
be just as complicated, virtually independent of how memory is
pre-allocated. (As far as I can tell.) Garbage collection might be
simpler.

Pointers to strings are stored in variables, in the calling routines.
There is no need to store them in the allocated space.

I'm still thinking about it, though.  Certainly worth a closer look.
All ideas gratefully accepted, as long as they're free.
-- 
Bernd Felsche,                 _--_|\   #include <std/disclaimer.h>
Metapro Systems,              / sale \  Fax:   +61 9 472 3337
328 Albany Highway,           \_.--._/  Phone: +61 9 362 9355
Victoria Park,  Western Australia   v   Email: bernie@metapro.DIALix.oz.au