[comp.sys.atari.st] TOS C string functions

RDROYA01@ULKYVX.BITNET (05/08/87)

Date:          Fri, 8 May 87 09:16 EDT
From:          <RDROYA01@ULKYVX.BITNET> (Robert Royar)
Organization:  University of Louisville
Subject:       TOS C string functions
To:            info-atari16@score.stanford.edu
X-Original-To: info-atari16@score.stanford.edu


I would have sent this to atari.sources but send it to info-atari16 instead
because nothing I have sent to atari.sources has gotten through.  The
routines in this file serve three purposes.  They give Alcyon programmers
who don't need all of the GEMLIB startup stuff or other baggage some useful
string routines.  Many are in GEMLIB already, but you can use these in very
small TOS programs, such as auto folder programs.  The second purpose is to
provide the additional routines strpos, strrpos, strpbrk, strrpbrk, strscn,
and strcscn which are not part of the Alcyon distribution.  The last purpose
is to fix a bug in the Atari/DRI index strchr routine.  As written in the
startup.s file, it does not return a pointer to the end of string when given
the following:
index("hello",'\0');
Harbison and Steele say that index/strchr should return a pointer to the
NULL at the end of "hello" rather than a NULL pointer in this case.  The bug
was added by DRI and perpetuated by Atari.  The Alcyon library's versions of
strchr and strrchr both return pointers to the NULL at the end of "hello"
when given the input above.  I wonder if Atari can spell hermeneutics?

And now, a question.  Does anyone have the proper definition of the __fds
structure that the Alcyon file ops use for each file?  I know there is a
definition in OSIF.H, but it refers to CP/M specific stuff like user numbers
and passwords which don't seem to correspond to anything under GEM.  Under
the CP/M system you can get at the low level file handle for streams by
working with the fds (note that fileno(fp) != file handle of the file).
Note also that the Atari written low level C open routine fails to check for
the file type (i.e. RO RW).  If you've used the stack a bit and try to open
a RO file for reading, the open will fail, simply because xopen fails to
push the mode onto the stack.  It would be relatively easy to replace xopen
knowing the real __fds structure, a lot easier than rewriting the entire
stream package.

Anyway here's the string manipulation code:

                           O O
                            x (cut here)
---------------------------/-\------------------------------------------


#include <string.h>

/* return length of str excluding the NULL */
strlen(str)
register char *str;
{
        register int len;

        len = 0;
        while(*str)
                {
                ++str;
                ++len;
                }
        return(len);
}

/* append str2 to str1, returning the beginning of str1 */
char *
strcat(str1,str2)
register char *str1, *str2;
{
        register char *sptr;

        sptr = str1;
        while(*str1)
                ++str1;
        while(*str2)
                *str1++ = *str2++;
        *str1 = '\0';
        return(sptr);
}

/* copy str2 to str1, returning the beginning of str1 */
char *
strcpy(dest,src)
register char *dest, *src;
{
        register char *sptr;

        sptr = dest;
        while(*src)
                *dest++ = *src++;
        *dest = '\0';
        return(sptr);
}

/* is str1 == str2? 0==yes; -#== str2 > str1; +#== str1 > str2 */
strcmp(str1,str2)
register char *str1, *str2;
{

        while(*str1)
                {
                if(*str1 != *str2)
                        return(*str1-*str2);
                ++str1;
                ++str2;
                }
        if(*str2=='\0')
                return(0);
        else
                return(-1);
}

/* not in GEMLIB */
/* index 0 position of first occurence c in string str. -1 if c is not in str */
strpos(str, c)
register char *str;
register char c;
{
        register int pos;

        pos = 0;
        while(*str)
                {
                if (*str++ == c)
                        return(pos);
                ++pos;
                }
        if (c == '\0')
                return(pos);
        else
                return(-1);
}

/* Not in GEMLIB */
/* index 0 of position of last occurence of c in str.  -1 if c not in str */
strrpos(str, c)
register char *str;
register char c;
{
        register int pos;

        pos = 0;
        while(*str)
                {
                ++str;
                ++pos;
                }
        if (c == '\0')
                return(pos);
        while(pos >= 0)
                {
                if (*str-- == c)
                        return(pos);
                --pos;
                }
        return(-1);
}

/* Not in GEMLIB */
/* find first occurence (in str) of one of the characters in set.  Return
 * a pointer to it or NULL on failure.
 */
char *
strpbrk(str, set)
register char *str, *set;
{
        register char *ptr;

        while(*set)
                if ((ptr=index(str,*set++))!=NULL)
                        return(ptr);
        return(NULL);
}

/* Not in GEMLIB */
/* same as strpbrk, but find last occurence */
char *
strrpbrk(str, set)
register char *str, *set;
{
        register char *rptr;

        while(*set)
                if ((rptr=rindex(str,*set++))!=NULL)
                        return(rptr);
        return(NULL);
}

/* Not in GEMLIB */
/* search str for the first occurence of a character not in set.  Return
 * the position of the last character in str in the set, or strlen if
 * all of set are in str.
 */
strspn(str, set)
register char *str, *set;
{
        register char *ptr;
        /* set is empty so the first char of str will not be in it */
        if (*set == '\0')
                return(0);
        ptr = str;
        while(*str)
                {
                if (index(set,*str)==NULL)
                        return(strpos(ptr,*str));
                ++str;
                }
        return(strlen(ptr));
}

/* Not in GEMLIB */
/* find first occurence of char in str that is included in set. Return
 * its position.
 */
strcspn(str, set)
register char *str, *set;
{
        register char *ptr;

        ptr = str;
        while(*str)
                {
                if (index(set,*str))
                        return(strpos(ptr,*str));
                ++str;
                }
        return(strlen(ptr));
}

/* return pointer to last occurence of c in str.  (AKA strrchr). */
char *
rindex(str, c)
register char *str;
register char c;
{
        register char *sptr;

        sptr = str;
        while(*sptr)
                ++sptr;
        if (c == '\0')
                return(sptr);
        while(str != sptr)
                if (*sptr-- == c)
                        return(++sptr);
        return(NULL);
}

/* strcat with max */
char *
strncat(str1,str2,len)
register char *str1, *str2;
register int len;
{
        register char *sptr;

        if (len <= 0)
                return(str1);
        sptr = str1;
        while(*sptr)
                ++sptr;
        while(*str2)
                {
                *sptr++ = *str2++;
                if (!--len)
                        break;
                }
        *sptr = '\0';
        return(str1);
}

/* strcpy with MAX */
char *
strncpy(dest,src,len)
register char *dest, *src;
register int len;
{
        register char *sptr;

        if (len <= 0)
                return(dest);
        sptr = dest;
        while(*src)
                {
                *sptr++ = *src++;
                if (!--len)
                        break;
                }
        if (len)
                while(len-- > 0)
                        *sptr++ = '\0';
        return(dest);
}

/* compare len chars of str1 to len chars of str2 */
strncmp(str1,str2,len)
register char *str1, *str2;
register int len;
{

        if (len <= 0)
                return(0);
        while(*str1)
                {
                if(*str1 != *str2)
                        return(*str1-*str2);
                ++str1;
                ++str2;
                if (!--len)
                        break;
                }
        if (!len)
                return(0);
        if(*str2=='\0')
                return(0);
        else
                return(-1);
}

/*      As supplied the index function does not return a pointer to
*       the EOS when the requested character (in d0) was a '\0'.
*       Harbison and Steele (p. 262) say that a pointer to the NULL
*       should return if the indexed character is a '\0'.  Replace
*       the index routine in your startup file with this routine.
*       Index function to find out if a particular character is in a string.
*
        .globl  _index
        .globl  _strchr
_index:
_strchr:
        move.l  4(a7),a0        * a0 -> String
        move.w  8(a7),d0        * D0 = desired character
xindex: tst.b   (a0)            * EOS?
        bne     notend          * No, continue to look
        clr.l   d0              * Not found
        rts                     * Quit
notend: cmp.b   (a0)+,d0        * check for character
        bne     xindex          *
        move.l  a0,d0           * Found it
        subq.l  #1,d0           * set return pointer
        rts

*/