mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2024-12-28 08:16:31 +00:00
db32fdb367
Reformatted DolDoc files, adjusted sprites in documentation to reflect naming changes, corrected keybinding labels in AutoComplete window, fixed formatting error in Tips.DD. Added DVD Boot AHCI prototyping into Kernel, displays detected AHCI configuration and halts mid-boot. Small modifications to standard font, slight increase to mouse X and Y speed.
761 lines
15 KiB
HolyC
Executable file
761 lines
15 KiB
HolyC
Executable file
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
|
|
_STRCOPY::
|
|
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
|
|
_STRCOMPARE::
|
|
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
|
|
_STRICOMPARE::
|
|
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
|
|
_STRNCOMPARE::
|
|
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
|
|
_STRNICOMPARE::
|
|
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 _STRCOMPARE I64 StrCompare(U8 *st1, U8 *st2); //Compare two strings.
|
|
_extern _STRICOMPARE I64 StrICompare(U8 *st1, U8 *st2); //Compare two strings, ignoring case.
|
|
_extern _STRNCOMPARE I64 StrNCompare(U8 *st1, U8 *st2, I64 n); //Compare N bytes in two strings.
|
|
_extern _STRNICOMPARE I64 StrNICompare(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 _STRCOPY U0 StrCopy(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 *ListSub(I64 sub, U8 *list)
|
|
{//Point to list entry.
|
|
//Not efficient. Use an array of U8 ptrs for efficiency.
|
|
if (!list)
|
|
return NULL;
|
|
while (*list && sub > 0)
|
|
{
|
|
while (*list) //Advance to end of cur entry.
|
|
list++;
|
|
list++; //Skip trailing zero.
|
|
if (*list == '@') //Check for '@' alias list entry.
|
|
list++;
|
|
else
|
|
sub--;
|
|
}
|
|
if (sub || !*list)
|
|
return NULL;
|
|
else
|
|
return list;
|
|
}
|
|
|
|
I64 ListMatch(U8 *needle, U8 *haystack_list, 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_list)
|
|
return -1;
|
|
|
|
n = StrLen(needle);
|
|
while (*haystack_list)
|
|
{
|
|
if (*haystack_list == '@')
|
|
{ //Check for '@' alias haystack_list entry
|
|
sub--;
|
|
haystack_list++;
|
|
}
|
|
ptr = needle;
|
|
if (flags & LMF_IGNORE_CASE)
|
|
while (*ptr && ToUpper(*ptr) == ToUpper(*haystack_list))
|
|
{
|
|
ptr++;
|
|
haystack_list++;
|
|
}
|
|
else
|
|
while (*ptr && *ptr == *haystack_list)
|
|
{
|
|
ptr++;
|
|
haystack_list++;
|
|
}
|
|
if (!*ptr)
|
|
{ //Did we reach end of needle?
|
|
if (!*haystack_list) //Did we reach end of haystack_list?
|
|
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_list) //Advance to end of cur entry.
|
|
haystack_list++;
|
|
haystack_list++; //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_count, space_count2, col = 0;
|
|
|
|
if (*src)
|
|
while (TRUE)
|
|
{
|
|
src2 = src;
|
|
while (*src2 == CH_SPACE)
|
|
src2++;
|
|
space_count = src2 - src;
|
|
while (col + space_count >= 4)
|
|
{
|
|
space_count2 = 4 - col;
|
|
if (space_count2 == 1)
|
|
*dst++ = CH_SPACE;
|
|
else
|
|
{
|
|
*dst++ = '\t';
|
|
chged += space_count2 - 1;
|
|
}
|
|
space_count -= space_count2;
|
|
col = 0;
|
|
}
|
|
if (*src2 == '\t')
|
|
{
|
|
if (space_count == 1 && col == 3)
|
|
*dst++ = CH_SPACE;
|
|
else
|
|
chged += space_count;
|
|
*dst++ = '\t';
|
|
col = 0;
|
|
}
|
|
else
|
|
{
|
|
while (space_count--)
|
|
{
|
|
*dst++ = CH_SPACE;
|
|
if (++col == 4)
|
|
col = 0;
|
|
}
|
|
if (*src2)
|
|
{
|
|
*dst++ = *src2;
|
|
if (++col == 4)
|
|
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_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 *StrFirstRemove(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)
|
|
StrCopy(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 *StrLastRemove(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)
|
|
StrCopy(dst, ptr + 1);
|
|
*ptr = 0;
|
|
}
|
|
else
|
|
{
|
|
if (dst)
|
|
StrCopy(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;
|
|
}
|
|
|
|
U8 *StrReplace(U8 *str, U8 *old, U8 *new, I64 sff_flags=NONE, Bool free_str=FALSE)
|
|
{//Replace all instances of old with new in str. New MAlloc()ed string. free_str aids in chain replacement.
|
|
U8 *str_start, *str_end = str, *str_loc, *tmpm = NULL;
|
|
|
|
if (!*old)
|
|
{
|
|
str_start = StrNew(new);
|
|
goto sr_end2;
|
|
}
|
|
|
|
if (!StrCompare(old, new))
|
|
goto sr_end;
|
|
|
|
while (str_loc = str_end = StrFind(old, str_end, sff_flags))
|
|
{
|
|
str_start = str;
|
|
str_end += StrLen(old); //Move start marker past old str, cutting it out
|
|
str_start[StrLen(str_start) - StrLen(str_loc)] = '\0'; //End str_start right before where old was
|
|
Free(tmpm);
|
|
tmpm = MStrPrint("%s%s%s", str_start, new, str_end);
|
|
str = tmpm;
|
|
}
|
|
sr_end:
|
|
str_start = StrNew(str);
|
|
sr_end2:
|
|
if (free_str)
|
|
Free(str);
|
|
return str_start;
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|