;     Last revision: January 14, 1988 at 18:07

For some time I have been wondering how Clipper UDFs written in the new
Microsoft C-5 would compare with the same UDF written in assembly language.
So, I wrote the heart of a simple but typical Clipper UDF in C and using
the /Fa option, compiled it with MS C-5 and inspected the assembly language
to see how it compares with what I might write myself. To make life simple,
I left out the Clipper parameter passing and return routines. As presented
the routine gets its parameters off the stack as a C function.

As you can see, the results are rather good and maybe could be considered
readable. The code is reasonably efficient with a few extra instructions
added that are strictly not needed. Both the size and speed of the code
is not too far different than manually written assembly code. 

I did look at the code written by the Quick C compiler and it is not quit
as efficient or compact, but still good enough for most purposes. If you
don't have lots of cash, just buy Quick C and not worry about the full C-5
package.

Based on this one exercise, I conclude that for most of my own programs, 
the extra time spent on manually coded assembly language UDF routines
does not justify the extra care and time spent. For those folk who don't
do assembly language, you may be just as well off as us folk that can
do a little of both or even one of those highly skilled ASM gurus.

/*  WILDCARD.C  by: H.M. Van Tassell, Watchung, NJ 07060
*
*  Add the Clipper parameter passing and return functions to generate 
*  a Clipper UDF for wildcard string comparisons.
*
*  Syntax:  WildCard(<expC1>, <expC2>)
*  Return:  True if expC1 matches expC2; '?' and '*' allowed in expC1.
*  Example: WildCard("He??o", "Hello")  returns True
*           WildCard("He*",   "Hello")  returns True
*           WildCard("he*",   "Hello")  returns False (case sensitive)
*
## <---- line numbers referenced in assembly language listing below */

17  int wildcard(str1,str2)
18  unsigned char *str1, *str2;
19  {
20      register int char1, char2;
21	int   ret = 1;
22	while (*str1) {
23		char1 = *str1++; char2 = *str2++;
24		if (char1 == '*') {
25			break;
26		}
27		if (char1 == '?') {
28			continue;
29		}
30		if (char1 != char2) {
31			ret = 0;
32			break;
33      	}
34      }
35  }

NOTE: comments starting with ;* have been added, otherwise the listing
      below is the same as produced by MS C-5.00 with /Fa option.

; Line 18
	PUBLIC	_wildcard
_wildcard	PROC FAR
	push	bp
	mov	bp,sp           ;* setup frame pointer
	sub	sp,6            ;* make room for local variables
	push	di
	push	si
; Line 19
;	str1 = 6                ;* this is where parameters are stored
;	str2 = 8
;	register si = char1     ;* store in registers, quick/compact
;	register di = char2
;	ret = -4                ;* this is where variable ret is stored
; Line 21
	mov	WORD PTR [bp-4],1	;ret * set variable to TRUE
; Line 22
$I112:
	mov	bx,WORD PTR [bp+6]	;* setup while loop, get pointer
	cmp	BYTE PTR [bx],0         ;* if '\0', it is end of string1
	je	$FB109                  ;* so jump to exit
; Line 23
	mov	al,BYTE PTR [bx]        ;* get char1
	sub	ah,ah                   ;* clear AH
	mov	si,ax                   ;* store char1 in SI
	inc	WORD PTR [bp+6]	        ;* inc string1 pointer
	mov	bx,WORD PTR [bp+8]	;* get string2 pointer
	mov	al,BYTE PTR [bx]        ;* get char2
	mov	di,ax                   ;* store char2 in DI
	inc	WORD PTR [bp+8]	;str2   ;* and inc string2 pointer
; Line 24
	cmp	si,42                   ;* is char1 = '*'
	jne	$I110                   ;* no, go to next compare
; Line 25
$FB109:                 ;* this exits the function and returns variable ret
; Line 35
	mov	ax,WORD PTR [bp-4]	;* put ret value into AX
	pop	si                      
	pop	di                      ;* restore registers
	mov	sp,bp                   ;* fixup stack
	pop	bp
	ret	                        ;* return to caller
$I110:
	cmp	si,63                   ;* is char1 = "?"
	je	$I112                   ;* yes, jump to the while loop
; Line 28
	cmp	si,di                   ;* is char1 = char2
	je	$I112                   ;* yes, jump to the while loop
; Line 31
	mov	WORD PTR [bp-4],0	;* no, set ret to FALSE
; Line 32
	jmp	SHORT $FB109            ;* and jump to function exit 

_wildcard	ENDP


[end of file]

