
#include <string.h>

#define BCC_ASM		/* Use 16 bit BCC assembler */
#define PARANOID	/* Include extra code for cld and ES register */

/* This is a basic string package; it includes the most used functions

   strlen strcat strcpy strcmp strncat strncpy strncmp strchr strrchr strdup
   memcpy memccpy memchr memset memcmp memmove

   These functions are in seperate files.
    strpbrk.o strsep.o strstr.o strtok.o strcspn.o
    strspn.o strcasecmp.o strncasecmp.o
 */

/********************** Function strlen ************************************/

#ifdef L_strlen
size_t strlen(str)
char * str;
{
#ifdef BCC_ASM
#asm
  mov	bx,sp
  push	di

#ifdef PARANOID
  push	es
  push	ds	; Im not sure if this is needed, so just in case.
  pop	es
  cld
#endif

  mov	di,[bx+2]	! This is almost the same as memchr, but it can
  mov	cx,#-1		! stay as a special.
  xor	ax,ax
  repne
  scasb
  not	cx
  dec	cx
  mov	ax,cx

#ifdef PARANOID
  pop	es
#endif
  pop	di
#endasm
#else
   register char * p = str;
   while(*p) p++;
   return p-str;
#endif
}
#endif

/********************** Function strcat ************************************/

#ifdef L_strcat
char * strcat(d, s)
char *d; char * s;
{
   (void) strcpy(d+strlen(d), s);
   return d;
}
#endif

/********************** Function strcpy ************************************/

#ifdef L_strcpy
char * strcpy(d, s)
char *d; char * s;
{
   /* This is probably the quickest on an 8086 but a CPU with a cache will
    * prefer to do this in one pass */
   return memcpy(d, s, strlen(s)+1);
}
#endif

/********************** Function strcmp ************************************/

#ifdef L_strcmp
int strcmp(d, s)
char *d; char * s;
{
  /* There are a number of ways to do this and it really does depend on the
     types of strings given as to which is better, nevertheless the Glib
     method is quite reasonable so we'll take that */

#ifdef BCC_ASM
#asm
  mov	bx,sp
  push	di
  push	si

#ifdef PARANOID
  push	es
  push	ds	; Im not sure if this is needed, so just in case.
  pop	es
#endif

  mov	di,[bx+2]	; dest
  mov	si,[bx+4]	; source
sc_1:
  lodsb
  scasb
  jne	sc_2		; If bytes are diff skip out.
  testb	al,al
  jne	sc_1		; If this byte in str1 is nul the strings are equal
  xor	ax,ax		; so return zero
  jmp	sc_3
sc_2:
  sbb	ax,ax		; Collect correct val (-1,1).
  orb	al,#1
sc_3:

#ifdef PARANOID
  pop	es
#endif
  pop	si
  pop	di
#endasm
#else
   register char *s1=d, *s2=s, c1,c2;
   while((c1= *s1++) == (c2= *s2++) && c1 );
   return c1 - c2;
#endif
}
#endif

/********************** Function strncat ************************************/

#ifdef L_strncat
char * strncat(d, s, l)
char *d, *s;
size_t l;
{
   register char *s1=d+strlen(d), *s2;
   
   s2 = memchr(s, l, 0);
   if( s2 )
      memcpy(s1, s, s2-s+1);
   else
   {
      memcpy(s1, s, l);
      s1[l] = '\0';
   }
   return d;
}
#endif

/********************** Function strncpy ************************************/

#ifdef L_strncpy
char * strncpy(d, s, l)		/* FIXME need the fast version of this */
char *d, *s;
size_t l;
{
   register char *s1=d, *s2=s;
   while(l > 0)
   {
      l--;
      if( (*s1++ = *s2++) == '\0')
         break;
   }

   /* This _is_ correct strncpy is supposed to zap */
   for(; l>0; l--) *s1++ = '\0';
   return d;
}
#endif

/********************** Function strncmp ************************************/

#ifdef L_strncmp
int strncmp(d, s, l)		/* FIXME need the fast version of this */
char *d, *s;
size_t l;
{
   register char c1=0, c2=0;
   while(l-- >0)
      if( (c1= *d++) != (c2= *s++) || c1 == '\0' )
         break;
   return c1-c2;
}
#endif

/********************** Function strchr ************************************/

#ifdef L_strchr
char *
strchr(s, c)		/* FIXME need the fast version of this */
char * s;
int c;
{
   register char ch;
   for(;;)
   {
     if( (ch= *s) == c ) return s;
     if( ch == 0 ) return 0;
     s++;
   }
}
#endif

/********************** Function strrchr ************************************/

#ifdef L_strrchr
char * strrchr(s, c)
char * s;
int c;
{
   register char * prev = 0;
   /* For null it's just like strchr */
   if( c == '\0' ) return strchr(s, c);

   /* everything else just step along the string. */
   while( (s=strchr(s, c)) != 0 )
   {
      prev = s; s++;
   }
   return prev;
}
#endif

/********************** Function strdup ************************************/

#ifdef L_strdup
char * strdup(s)
char * s;
{
   register size_t len;
   register char * p;

   len = strlen(s)+1;
   p = malloc(s);
   if(p) memcpy(p, s, len);
   return p;
}
#endif

/********************** Function memcpy ************************************/

#ifdef L_memcpy
void *
memcpy(d, s, l)
void *d, *s;
size_t l;
{
#ifdef BCC_ASM
#asm
  mov	bx,sp
  push	di
  push	si

#ifdef PARANOID
  push	es
  push	ds	; Im not sure if this is needed, so just in case.
  pop	es
#endif

  mov	di,[bx+2]	; dest
  mov	si,[bx+4]	; source
  mov	cx,[bx+6]	; count

  mov	ax,di
  		; FIXME, if di is odd mov 1 byte before doing word move
		; this will speed slightly but
		; NB 8086 has no problem with mis-aligned access.

  shr	cx,#1	; Do this faster by doing a mov word
  rep
  movsw
  adc	cx,cx	; Retrieve the leftover 1 bit from cflag.
  rep
  movsb

#ifdef PARANOID
  pop	es
#endif
  pop	si
  pop	di
#endasm
#else
   register char *s1=d, *s2=s;
   for( ; l>0; l--) *((unsigned char*)s1++) = *((unsigned char*)s2++);
   return d;
#endif
}
#endif

/********************** Function memccpy ************************************/

#ifdef L_memccpy
void * memccpy(d, s, c, l)	/* Do we need a fast one ? */
void *s, *d;
int c;
size_t l;
{
   register char *s1=d, *s2=s;
   while(l-- > 0)
      if((*s1++ = *s2++) == c )
         return s1;
   return 0;
}
#endif

/********************** Function memchr ************************************/

#ifdef L_memchr
void * memchr(str, c, l)
void * str;
int c;
size_t l;
{
#ifdef BCC_ASM
#asm
  mov	bx,sp
  push	di

#ifdef PARANOID
  push	es
  push	ds	; Im not sure if this is needed, so just in case.
  pop	es
  cld
#endif

  mov	di,[bx+2]
  mov	ax,[bx+4]
  mov	cx,[bx+6]
  test	cx,cx
  je	is_z	! Zero length, do not find.

  repne		! Scan
  scasb
  jne	is_z	! Not found, ret zero
  dec	di	! Adjust ptr
  mov	ax,di	! return
  jmp	xit
is_z:
  xor	ax,ax
xit:

#ifdef PARANOID
  pop	es
#endif
  pop	di
#endasm
#else
   register char *p=str;
   while(l-- > 0)
   {
      if(*p == c) return p;
      p++;
   }
   return 0;
#endif
}
#endif

/********************** Function memset ************************************/

#ifdef L_memset
void * memset(str, c, l)
void * str;
int c;
size_t l;
{
#ifdef BCC_ASM
#asm
  mov	bx,sp
  push	di

#ifdef PARANOID
  push	es
  push	ds	; Im not sure if this is needed, so just in case.
  pop	es
  cld
#endif

  mov	di,[bx+2]	; Fetch
  mov	ax,[bx+4]
  mov	cx,[bx+6]

  test	cx,cx		; Zero size - skip
  je	xit

  test	di,#1		; Line it up
  je	s_1
  stosb
  dec	cx
s_1:

  mov	ah,al		; Replicate byte
  shr	cx,#1		; Do this faster by doing a mov word
  rep			; Bzzzzz
  stosw
  adc	cx,cx		; Retrieve the leftover 1 bit from cflag.

  rep			; Bzzzzz
  stosb

xit:
  mov	ax,[bx+2]
#ifdef PARANOID
  pop	es
#endif
  pop	di
#endasm
#else
   register char *s1=str;
   while(l-->0) *s1++ = c;
   return str;
#endif
}
#endif

/********************** Function memcmp ************************************/

#ifdef L_memcmp
int memcmp(s, d, l)
void *s, *d;
size_t l;
{
#ifdef BCC_ASM
#asm
  mov	bx,sp
  push	di
  push	si

#ifdef PARANOID
  push	es
  push	ds	! Im not sure if this is needed, so just in case.
  pop	es
  cld
#endif

  mov	si,[bx+2]	! Fetch
  mov	di,[bx+4]
  mov	cx,[bx+6]
  xor	ax,ax

  rep			! Bzzzzz
  cmpsb
  je	xit		! All the same!
  sbb	ax,ax
  sbb	ax,#-1		! choose +/-1
xit:
#ifdef PARANOID
  pop	es
#endif
  pop	si
  pop	di
#endasm
#else
   register char *s1=d, *s2=s, c1=0, c2=0;
   while(l-- > 0)
      if( (c1= *s1++) != (c2= *s2++) )
         break;
   return c1-c2;
#endif
}
#endif

/********************** Function memmove ************************************/

#ifdef L_memmove
void *
memmove(d, s, l)
void *d, *s;
size_t l;
{
   register char *s1=d, *s2=s;
   /* This bit of sneakyness c/o Glibc, it assumes the test is unsigned */
   if( s1-s2 >= l ) return memcpy(d,s,l);

   /* This reverse copy only used if we absolutly have to */
   s1+=l; s2+=l;
   while(l-- >0)
      *(--s1) = *(--s2);
   return d;
}
#endif

/********************** THE END ********************************************/

