/***************************************************************************
 *                                                                         *
 *   SCANCH.C                                                              *
 *                                                                         *
 *   Copyright (c) 1994-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   This is the GCOMM.LIB routine for scanning a binary byte string       *
 *   searching for a specific byte.  The function returns the total        *
 *   number of non-target bytes that it skipped.  Therefore, if the        *
 *   byte was found in the string, scanch() returns its position, 0        *
 *   to limit-1.  If the byte was not found, scanch() returns limit.       *
 *                                                                         *
 *                                            - R. Stein   5/19/94         *
 *   scanstg() and scanmem()                  - R. Stein   7/10/96         *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"

#define FILREV "$Revision: 5 $"

                                   /*   rets # contiguous non-target bytes */
                                   /*   rets 0 to limit-1 => byte found    */
UINT                               /*   rets limit => byte not found       */
scanch(                            /* fast scan a byte string for a byte   */
const CHAR *bytes,                 /*   byte string                        */
CHAR target,                       /*   target byte                        */
INT limit)                         /*   max number of bytes to scan        */
{
#ifdef GCDOS
     asm  les  di,bytes
     asm  mov  al,target
     asm  mov  cx,limit
     asm  jcxz cantfind            /* if limit == 0, return 0              */
     asm  cld
     asm repne scasb               /* scan until targ skipped or limit hit */
     asm  jne  cantfind
     asm  inc  cx                  /* if found, return 0..limit-1          */
     cantfind:                     /* if not found, return limit           */
     asm  mov  ax,limit
     asm  sub  ax,cx
     return(_AX);
#else
     INT i;

     for (i=0 ; (i < limit) && (bytes[i] != target) ; i++) {
     }
     return(i);
#endif // GCDOS
}

                                   /*   returns index of 1st occurrence    */
UINT                               /*   or returns limit if none found     */
scanstg(                           /* scan block of bytes for a string     */
const CHAR *bytes,                 /*   bytes to scan                      */
const CHAR *target,                /*   string sought ('\0' terminated)    */
INT limit)                         /*   number of bytes to scan            */
{
     return(scanmem(bytes,target,limit,strlen(target)));
}
                                   /*   returns index of 1st occurrence    */
UINT                               /*   or returns limit if none found     */
scanmem(                           /* scan one block of bytes for another  */
const CHAR *bytes,                 /*   bytes to scan                      */
const CHAR *target,                /*   bytes sought                       */
INT limit,                         /*   number of bytes to scan            */
INT ntarget)                       /*   number of bytes sought             */
{
     CHAR ch;                      /*   1st byte of target, if any         */
     INT offs;                     /*   ruled-out positions for ch         */
     const CHAR *bp;               /*   where to look for more ch's        */
     INT nlook;                    /*   number of positions ch could be    */
     INT cand;                     /*   candidate location for ch          */

     if (ntarget == 0 || limit == 0) {
          return(0);             /* empty's everywhere, nothing's in empty */
     }
     ch=target[0];
     nlook=limit-ntarget+1;
     for (offs=0 ; offs < nlook ; offs+=cand+1) {
          bp=bytes+offs;
          cand=scanch(bp,ch,nlook-offs);
          if (cand == nlook-offs) {
               break;
          }
          if (memcmp(bp+cand,target,ntarget) == 0) {
               return(offs+cand);
          }
     }
     return(limit);
}
