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 */