U8 *StrPrintHex(U8 *dst,I64 num;I64 width) { U8 *res=dst+width; dst=res; while (width--) { *--dst="0123456789ABCDEF"(U8 *)[num&15]; num>>=4; } return res; } U0 PutHex(I64 num,I64 width) { U8 buf[17]; if (width>16) width=16; *StrPrintHex(buf,num,width)=0; "%s",buf; } asm { // IN: RAX=NUM TO PRINT PUT_HEX_U64:: PUSH_C_REGS PUSH 16 PUSH RAX CALL &PutHex POP_C_REGS RET PUT_HEX_U32:: PUSH_C_REGS PUSH 8 PUSH RAX CALL &PutHex POP_C_REGS RET PUT_HEX_U16:: PUSH_C_REGS PUSH 4 PUSH RAX CALL &PutHex POP_C_REGS RET PUT_HEX_U8:: PUSH_C_REGS PUSH 2 PUSH RAX CALL &PutHex POP_C_REGS RET PUT_CHARS:: // IN: RAX=Char PUSH_C_REGS PUSH RAX CALL &PutChars POP_C_REGS RET PUT_STR:: // IN: RSI=String PUSH_C_REGS PUSH RSI CALL &PutS POP_C_REGS RET _STRCPY:: PUSH RBP MOV RBP,RSP PUSH RSI PUSH RDI MOV RDI,U64 SF_ARG1[RBP] TEST RDI,RDI JZ @@15 MOV RSI,U64 SF_ARG2[RBP] TEST RSI,RSI JNZ @@05 XOR RAX,RAX JMP @@10 @@05: LODSB @@10: STOSB TEST AL,AL JNZ @@05 @@15: POP RDI POP RSI POP RBP RET1 16 _STRCMP:: PUSH RBP MOV RBP,RSP PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG2[RBP] MOV RDI,U64 SF_ARG1[RBP] @@05: LODSB TEST AL,AL JZ @@20 SCASB JE @@05 JA @@15 @@10: MOV RAX,1 JMP @@25 @@15: MOV RAX,-1 JMP @@25 @@20: SCASB JNE @@10 XOR RAX,RAX @@25: POP RDI POP RSI POP RBP RET1 16 TO_UPPER:: CMP AL,'a' JB @@05 CMP AL,'z' JA @@05 ADD AL,'A'-'a' @@05: RET _STRICMP:: PUSH RBP MOV RBP,RSP PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG2[RBP] MOV RDI,U64 SF_ARG1[RBP] @@05: LODSB TEST AL,AL JZ @@30 CMP AL,'a' JB @@10 CMP AL,'z' JA @@10 ADD AL,'A'-'a' @@10: MOV BL,U8 [RDI] INC RDI CMP BL,'a' JB @@15 CMP BL,'z' JA @@15 ADD BL,'A'-'a' @@15: CMP AL,BL JE @@05 JA @@25 @@20: MOV RAX,1 JMP @@35 @@25: MOV RAX,-1 JMP @@35 @@30: MOV BL,U8 [RDI] TEST BL,BL JNE @@20 XOR RAX,RAX @@35: POP RDI POP RSI POP RBP RET1 16 _STRNCMP:: PUSH RBP MOV RBP,RSP PUSH RSI PUSH RDI MOV RCX,U64 SF_ARG3[RBP] MOV RSI,U64 SF_ARG2[RBP] MOV RDI,U64 SF_ARG1[RBP] @@05: TEST RCX,RCX JZ @@25 DEC RCX LODSB TEST AL,AL JZ @@20 SCASB JE @@05 JA @@15 @@10: MOV RAX,1 JMP @@30 @@15: MOV RAX,-1 JMP @@30 @@20: MOV BL,U8 [RDI] TEST BL,BL JNE @@10 @@25: XOR RAX,RAX @@30: POP RDI POP RSI POP RBP RET1 24 _STRNICMP:: PUSH RBP MOV RBP,RSP PUSH RSI PUSH RDI MOV RCX,U64 SF_ARG3[RBP] MOV RSI,U64 SF_ARG2[RBP] MOV RDI,U64 SF_ARG1[RBP] @@05: TEST RCX,RCX JZ @@35 DEC RCX LODSB TEST AL,AL JZ @@30 CMP AL,'a' JB @@10 CMP AL,'z' JA @@10 ADD AL,'A'-'a' @@10: MOV BL,U8 [RDI] INC RDI CMP BL,'a' JB @@15 CMP BL,'z' JA @@15 ADD BL,'A'-'a' @@15: CMP AL,BL JE @@05 JA @@25 @@20: MOV RAX,1 JMP @@40 @@25: MOV RAX,-1 JMP @@40 @@30: SCASB JNE @@20 @@35: XOR RAX,RAX @@40: POP RDI POP RSI POP RBP RET1 24 _STRMATCH:: PUSH RBP MOV RBP,RSP PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG2[RBP] TEST RSI,RSI JZ @@25 MOV RDI,U64 SF_ARG1[RBP] TEST RDI,RDI JZ @@25 MOV DL,U8 [RDI] TEST DL,DL JZ @@20 JMP @@10 @@05: INC RSI @@10: LODSB TEST AL,AL JZ @@25 CMP AL,DL JNE @@10 DEC RSI MOV RCX,1 @@15: MOV AL,U8 [RDI+RCX] TEST AL,AL JZ @@20 CMP AL,U8 [RSI+RCX] JNE @@05 INC RCX JMP @@15 DEC RSI @@20: MOV RAX,RSI JMP @@30 @@25: XOR RAX,RAX @@30: POP RDI POP RSI POP RBP RET1 16 _STRIMATCH:: PUSH RBP MOV RBP,RSP PUSH RSI PUSH RDI MOV RSI,U64 SF_ARG2[RBP] TEST RSI,RSI JZ @@25 MOV RDI,U64 SF_ARG1[RBP] TEST RDI,RDI JZ @@25 MOV AL,U8 [RDI] CALL TO_UPPER MOV DL,AL TEST DL,DL JZ @@20 JMP @@10 @@05: INC RSI @@10: LODSB CALL TO_UPPER TEST AL,AL JZ @@25 CMP AL,DL JNE @@10 DEC RSI MOV RCX,1 @@15: MOV AL,U8 [RDI+RCX] CALL TO_UPPER TEST AL,AL JZ @@20 MOV BL,U8 [RSI+RCX] XCHG AL,BL CALL TO_UPPER CMP AL,BL JNE @@05 INC RCX JMP @@15 DEC RSI @@20: MOV RAX,RSI JMP @@30 @@25: XOR RAX,RAX @@30: POP RDI POP RSI POP RBP RET1 16 } _extern _STRCMP I64 StrCmp( U8 *st1,U8 *st2); //Compare two strings. _extern _STRICMP I64 StrICmp( U8 *st1,U8 *st2); //Compare two strings, ignoring case. _extern _STRNCMP I64 StrNCmp( U8 *st1,U8 *st2,I64 n); //Compare N bytes in two strings. _extern _STRNICMP I64 StrNICmp( U8 *st1,U8 *st2,I64 n); //Compare N bytes in two strings, ignoring case. _extern _STRMATCH U8 *StrMatch( U8 *needle,U8 *haystack_str); //Scan for string in string. _extern _STRIMATCH U8 *StrIMatch( U8 *needle,U8 *haystack_str);//Scan for string in string, ignoring case. _extern _STRCPY U0 StrCpy( U8 *dst,U8 *src); //Copy string. //These bitmaps go to 0-511 so that $LK,"Lex",A="MN:Lex"$() can use them with $LK,"Token Codes",A="MN:TK_EOF"$. U32 char_bmp_alpha[16]= {0x0000000,0x00000000,0x87FFFFFF,0x07FFFFFE, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}, char_bmp_alpha_numeric[16]= {0x0000000,0x03FF0000,0x87FFFFFF,0x07FFFFFE, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}, char_bmp_alpha_numeric_no_at[16]= {0x0000000,0x03FF0000,0x87FFFFFE,0x07FFFFFE, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}, char_bmp_word[16]= {0x0000000,0x03FF0080,0x87FFFFFE,0x07FFFFFE, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}, char_bmp_filename[16]= {0x0000000,0x03FF73FB,0xEFFFFFFF,0x6FFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}, char_bmp_dec_numeric[16]= {0x0000000,0x03FF0000,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, char_bmp_hex_numeric[16]= {0x0000000,0x03FF0000,0x7E,0x7E,0,0,0,0,0,0,0,0,0,0,0,0}, char_bmp_white_space[16]= {0x80002600,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, char_bmp_non_eol_white_space[16]= {0x80000200,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, char_bmp_zero_cr_nl_cursor[16]= {0x00002421,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, char_bmp_zero_tab_cr_nl_cursor[16]= {0x00002621,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, char_bmp_zero_tab_cr_nl_cursor_dollar[16]= {0x00002621,0x10,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, char_bmp_macro[16]= {0x80002600,0xFFFFFFDF,0xFFFFFFFF,0x7FFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}, char_bmp_printable[16]= {0x80002600,0xFFFFFFFF,0xFFFFFFFF,0x7FFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}, char_bmp_displayable[16]= {0x80000000,0xFFFFFFFF,0xFFFFFFFF,0x7FFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0}, char_bmp_safe_dollar[16]= {0x80000000,0xFFFFFFEF,0xFFFFFFFF,0x7FFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0,0,0,0,0,0,0,0},//same but no dollar sign char_bmp_non_eol[16]= {0xFFFFDBFE,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, 0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; U8 *LstSub(I64 sub, U8 *lst) {//Point to lst entry. //Not efficient.Use an array of U8 ptrs for efficiency. if (!lst) return NULL; while (*lst && sub>0) { while (*lst) //Advance to end of cur entry. lst++; lst++; //Skip trailing zero. if (*lst=='@') //Check for '@' alias lst entry. lst++; else sub--; } if (sub||!*lst) return NULL; else return lst; } I64 LstMatch(U8 *needle, U8 *haystack_lst,I64 flags=0) {//-2 if Ambiguous // -1 if not found // Not efficient. Use hash tables for efficiency. I64 n,sub=0,res=-1; U8 *ptr; Bool exact_match=FALSE; if (!haystack_lst) return -1; n=StrLen(needle); while (*haystack_lst) { if (*haystack_lst=='@') { //Check for '@' alias haystack_lst entry sub--; haystack_lst++; } ptr=needle; if (flags & LMF_IGNORE_CASE) while (*ptr && ToUpper(*ptr)==ToUpper(*haystack_lst)) { ptr++; haystack_lst++; } else while (*ptr && *ptr==*haystack_lst) { ptr++; haystack_lst++; } if (!*ptr) { //Did we reach end of needle? if (!*haystack_lst) //Did we reach end of haystack_lst? return sub; //Found Exact match else { if (res!=-1) { if (!exact_match) res=-2; //Ambiguous unless later exact match. } else { if (!(flags & LMF_EXACT)) res=sub; } } } while (*haystack_lst) //Advance to end of cur entry. haystack_lst++; haystack_lst++; //Skip trailing zero sub++; } return res; } I64 StrOcc(U8 *src, I64 ch) {//Count occurrences of a char. I64 i=0; if (!src) return 0; while (*src) if (*src++==ch) i++; return i; } I64 Spaces2Tabs(U8 *dst,U8 *src) {//Src buf with spaces to dst buf without. U8 *src2; I64 chged=0,space_cnt,space_cnt2,col=0; if (*src) while (TRUE) { src2=src; while (*src2==CH_SPACE) src2++; space_cnt=src2-src; while (col+space_cnt>=8) { space_cnt2=8-col; if (space_cnt2==1) *dst++=CH_SPACE; else { *dst++='\t'; chged+=space_cnt2-1; } space_cnt-=space_cnt2; col=0; } if (*src2=='\t') { if (space_cnt==1 && col==7) *dst++=CH_SPACE; else chged+=space_cnt; *dst++='\t'; col=0; } else { while (space_cnt--) { *dst++=CH_SPACE; if (++col==8) col=0; } if (*src2) { *dst++=*src2; if (++col==8) col=0; } else break; } src=++src2; } *dst=0; return chged; } U8 *StrUtil(U8 *_src,I64 flags) {//Modifies in place. See $LK,"flags",A="MN:SUF_REM_SPACES"$ for all the options. U8 *src=_src,*dst=_src; I64 ch; if (flags & SUF_REM_LEADING) while (Bt(char_bmp_white_space,*src)) src++; while (ch=*src++) if (Bt(char_bmp_white_space,ch)) { if (!(flags & SUF_REM_SPACES)) { if (flags & SUF_SINGLE_SPACE) { *dst++ = CH_SPACE; while ((ch=*src++) && Bt(char_bmp_white_space,ch)); src--; } else *dst++ = ch; } } else if (!(flags & SUF_REM_CTRL_CHARS) || ch>=CH_SHIFT_SPACE) *dst++=ch; *dst=0; if (flags & SUF_REM_TRAILING) while (dst!=_src && (!*dst || Bt(char_bmp_white_space,*dst))) *dst-- =0; if (flags & SUF_TO_UPPER) for (dst=_src;*dst;dst++) { ch=*dst; if ('a'<=ch<='z') *dst=ch-0x20; } if (flags & SUF_TO_LOWER) for (dst=_src;*dst;dst++) { ch=*dst; if ('A'<=ch<='Z') *dst=ch+0x20; } if (flags & SUF_SAFE_DOLLAR) for (dst=_src;*dst;dst++) { ch=*dst; if (!Bt(char_bmp_safe_dollar,*dst)) *dst='.'; } if (flags & SUF_S2T) Spaces2Tabs(_src,_src); return _src; } U8 *StrFirstOcc(U8 *src,U8 *marker) {//Point to 1st occurrence of marker set in str. I64 ch; while ((ch=*src++) && !StrOcc(marker,ch)); if (ch) return src-1; else return NULL; } U8 *StrFirstRem(U8 *src,U8 *marker,U8 *dst=NULL) {//Remove first str segment and place in dst buf or NULL. I64 ch; U8 *ptr=src,*res=dst; if (dst) { while ((ch=*ptr++) && !StrOcc(marker,ch)) *dst++=ch; *dst=0; } else while ((ch=*ptr++) && !StrOcc(marker,ch)); if (ch) StrCpy(src,ptr); else *src=0; return res; } U8 *StrLastOcc(U8 *src,U8 *marker) {//Point to last occurrence of market set in str. I64 ch; U8 *res=NULL; while (ch=*src++) if (StrOcc(marker,ch)) res=src-1; return res; } U8 *StrLastRem(U8 *src,U8 *marker,U8 *dst=NULL) {//Remove last str segment and place in dst buf or NULL. U8 *ptr; if (ptr=StrLastOcc(src,marker)) { if (dst) StrCpy(dst,ptr+1); *ptr=0; } else { if (dst) StrCpy(dst,src); *src=0; } return dst; } U8 *StrFind(U8 *needle,U8 *haystack_str,I64 flags=0) {//Find needle_str in haystack_str with options. Bool cont; U8 *saved_haystack_str=haystack_str; I64 plen=StrLen(needle); do { cont=FALSE; if (flags & SFF_IGNORE_CASE) haystack_str=StrIMatch(needle,haystack_str); else haystack_str=StrMatch(needle,haystack_str); if (haystack_str && flags & SFF_WHOLE_LABELS_BEFORE && haystack_str!=saved_haystack_str && Bt(char_bmp_alpha_numeric,*(haystack_str-1))) { haystack_str++; if (*haystack_str) cont=TRUE; else haystack_str=NULL; } if (haystack_str && flags & SFF_WHOLE_LABELS_AFTER && Bt(char_bmp_alpha_numeric,*(haystack_str+plen))) { haystack_str++; if (*haystack_str) cont=TRUE; else haystack_str=NULL; } } while (cont); return haystack_str; } Bool WildMatch(U8 *test_str,U8 *wild_str) {//Wildcard match with '*' and '?'. I64 ch1,ch2; U8 *fall_back_src=NULL,*fall_back_wild=NULL; while (TRUE) { if (!(ch1=*test_str++)) { if (*wild_str && *wild_str!='*') return FALSE; else return TRUE; } else { if (!(ch2=*wild_str++)) return FALSE; else { if (ch2=='*') { fall_back_wild=wild_str-1; fall_back_src=test_str; if (!(ch2=*wild_str++)) return TRUE; while (ch2!=ch1) if (!(ch1=*test_str++)) return FALSE; } else if (ch2!='?' && ch1!=ch2) { if (fall_back_wild) { wild_str=fall_back_wild; test_str=fall_back_src; fall_back_wild=NULL; fall_back_src=NULL; } else return FALSE; } } } } }