'===========================================================================
' Subject: MATCH STRING W/WILDCARD PATTERN    Date: 09-01-98 (15:11)       
'  Author: Dave Navarro, Jr.                  Code: PB                     
'  Origin: dave@powerbasic.com              Packet: PB.ABC
'===========================================================================
'===========================================================================
'                   Source code snippet: PowerBASIC for DOS
'
'           Author: Dave Navarro, Jr. (dave@powerbasic.com)
' Copyright status: Public Domain
'
' Source code for matching a text string against a given wildcard pattern.
'
'===========================================================================

%FALSE = 0
%TRUE  = NOT %FALSE

'===========================================================================
'Example code:

DIM Pattern       AS STRING
DIM Text(1 to 5)  AS STRING
DIM x             AS INTEGER

Pattern = "da[vn]*"

Text(1) = "Dave"
Text(2) = "Dale"
Text(3) = "Danny"
Text(4) = "David"
Text(5) = "Dan"

FOR x = 1 TO 5
  PRINT Text(x); " = "; Pattern; " is ";
  IF Like(Text(x), Pattern, %FALSE) THEN
    PRINT "True"
  ELSE
    PRINT "False"
  END IF
NEXT x

END

'===========================================================================
'
' ** Like Function **
'   Used to compare a source string with a string expression.
'
' ** Syntax **
'   result = Like(source_string, expression_pattern, case_sensitivity)
'
' ** Parameters **
'   source_string       Target string to compare pattern against.
'   expression_pattern  Wildcard expression pattern:
'       ?               Any single character
'       *               Zero or more characters
'       #               Any single digit (0-9)
'       [charlist]      Any single character in 'charlist'
'       [!charlist]     Any single character not in 'charlist'
'   case_sensitivity    Toggle for case sensitivity (true or false).
'
FUNCTION Like(BYVAL a AS STRING, BYVAL b AS STRING, _
              BYVAL lCase AS INTEGER) AS INTEGER

  DIM x        AS BYTE PTR
  DIM y        AS BYTE PTR
  DIM match    AS INTEGER
  DIM PrevChar AS BYTE
  DIM NextChar AS BYTE

  IF lCase THEN
    a        = a + CHR$(0)
    b        = b + CHR$(0)
  ELSE
    a        = UCASE$(a + CHR$(0))
    b        = UCASE$(b + CHR$(0))
  END IF

  x        = STRPTR32(a)
  y        = STRPTR32(b)

  FUNCTION = %FALSE

  DO

    IF @x = 0 THEN
      IF @y = 0 THEN
        FUNCTION = %TRUE
      END IF
      EXIT FUNCTION
    END IF

    SELECT CASE @y

      CASE 0  'NUL  pre-mature end
        EXIT FUNCTION

      CASE 35 '#    match a single numeric digit
        IF (@x < 48) OR (@x > 57) THEN
          EXIT FUNCTION
        END IF

      CASE 42 '*
        INCR y                 ' next char in expression
        DO
          IF @x = @y THEN      ' do they match?
            EXIT DO            ' yes exit
          ELSEIF @x = 0 THEN   ' end of source string?
            EXIT DO            ' yes exit
          END IF
          INCR x               ' next char in source string
        LOOP
        IF @x = 0 THEN         ' end of source string?
          IF @y = 0 THEN       ' also end of expression?
            FUNCTION = %TRUE
          END IF
          EXIT FUNCTION
        END IF

      CASE 63 '?    match any single char
              '     nothing to do, it's a match

      CASE 91 '[
        Match = %TRUE          ' assume we have to match chars
        INCR y                 ' next char in expression
        IF @y = 33 THEN        ' ! indicates do not match
          Match = %FALSE
          INCR y
        END IF
        DO
          IF @y = 93 THEN      ' ]
            EXIT FUNCTION
          ELSEIF @y = 0 THEN   ' NUL
            EXIT FUNCTION
          ELSEIF @y = 45 THEN  ' -
            DECR y             ' move to previous char in expression
            PrevChar = @y      ' save previous char
            y = y + 2          ' move to next char in expression
            NextChar = @y      ' save next char
            DECR y             ' restore current char in expression
            IF (PrevChar = 91) OR (PrevChar = 33) OR (NextChar = 93) THEN
              IF @y = @x THEN
                IF Match = %FALSE THEN  'if matching is false, exit
                  EXIT FUNCTION
                ELSE
                  EXIT DO
                END IF
              END IF
            ELSE
              IF (@x >= PrevChar) AND (@x =< NextChar) THEN
                IF Match = %FALSE THEN
                  EXIT FUNCTION
                ELSE
                  EXIT DO
                END IF
              ELSE
                INCR y
              END IF
            END IF
          ELSEIF @y = @x THEN       ' do they match?
            IF Match = %FALSE THEN  ' if matching is false, exit
              EXIT FUNCTION
            ELSE
              EXIT DO
            END IF
          END IF
          INCR y                    ' next char in expression
        LOOP
        DO                          ' find the closing bracket
          IF @y = 93 THEN
            EXIT DO
          ELSEIF @y = 0 THEN
            EXIT FUNCTION
          END IF
          INCR y
        LOOP

      CASE ELSE                     ' chars must match
        IF @x <> @y THEN
          EXIT DO
        END IF

    END SELECT

    INCR x    ' next char in source string
    INCR y    ' next char in expression

  LOOP

END FUNCTION
