[INTERPRETER]
* BUG: Fix a possible crash in String.Code(). [GB.FORM.TERMINAL] * OPT: Compress the attribute array associated with each line. * OPT: Drawing line routine uses the JIT compiler. git-svn-id: svn://localhost/gambas/trunk@7701 867c0c6c-44f3-4631-809d-bfa615b0a4ec
This commit is contained in:
parent
0c158f7788
commit
d7e88bf641
6 changed files with 271 additions and 160 deletions
|
@ -7,7 +7,7 @@ VersionFile=1
|
|||
Component=gb.image
|
||||
Component=gb.gui
|
||||
Component=gb.form
|
||||
Environment="GB_GUI=gb.qt5"
|
||||
Environment="GB_GUI=gb.gtk3"
|
||||
TabSize=2
|
||||
Language=fr
|
||||
Type=Component
|
||||
|
|
|
@ -4,38 +4,102 @@ Public Text As String
|
|||
Public Length As Integer
|
||||
Public Attr As New Integer[]
|
||||
|
||||
Enum FLAG_BG, FLAG_FG, FLAG_BOLD, FLAG_DIM, FLAG_REV, FLAG_UND, FLAG_BLK
|
||||
Private Enum FLAG_BG, FLAG_FG, FLAG_BOLD, FLAG_DIM, FLAG_REV, FLAG_UND, FLAG_BLK
|
||||
|
||||
Public Sub GetAttr(hAttr As TerminalAttr, X As Integer)
|
||||
|
||||
Private Sub Uncompress() As Integer[]
|
||||
|
||||
Dim I As Integer
|
||||
Dim iAttr As Integer
|
||||
|
||||
Try iAttr = Attr[X]
|
||||
|
||||
If BTst(iAttr, FLAG_BG) Then
|
||||
hAttr.Background = Lsr(iAttr, 16) And 255
|
||||
Else
|
||||
hAttr.Background = Color.Default
|
||||
Endif
|
||||
Dim iCount As Integer
|
||||
Dim aAttr As New Integer[]
|
||||
Dim aTemp As Integer[]
|
||||
|
||||
If BTst(iAttr, FLAG_FG) Then
|
||||
hAttr.Foreground = Lsr(iAttr, 24) And 255
|
||||
Else
|
||||
hAttr.Foreground = Color.Default
|
||||
Endif
|
||||
For I = 0 To Attr.Max
|
||||
iAttr = Attr[I]
|
||||
iCount = (Lsr(iAttr, 8) And 255) + 1
|
||||
iAttr = iAttr And &HFFFF00FF
|
||||
aTemp = New Integer[iCount]
|
||||
aTemp.Fill(iAttr)
|
||||
aAttr.Insert(aTemp)
|
||||
Next
|
||||
|
||||
hAttr.Bold = BTst(iAttr, FLAG_BOLD)
|
||||
hAttr.Dim = BTst(iAttr, FLAG_DIM)
|
||||
hAttr.Reverse = BTst(iAttr, FLAG_REV)
|
||||
hAttr.Underscore = BTst(iAttr, FLAG_UND)
|
||||
hAttr.Blink = BTst(iAttr, FLAG_BLK)
|
||||
'If aAttr.Count > String.Len(Text) Then Stop
|
||||
|
||||
Return aAttr
|
||||
|
||||
End
|
||||
|
||||
Private Sub Compress(aAttr As Integer[])
|
||||
|
||||
Dim I As Integer
|
||||
Dim iAttr As Integer
|
||||
Dim iOldAttr As Integer
|
||||
Dim iCount As Integer
|
||||
Dim N As Integer
|
||||
|
||||
Attr.Clear
|
||||
|
||||
For I = 0 To aAttr.Max
|
||||
|
||||
iAttr = aAttr[I]
|
||||
If iAttr = iOldAttr And If iCount < 256 Then
|
||||
Inc iCount
|
||||
Continue
|
||||
Endif
|
||||
|
||||
GoSub ADD_ATTR
|
||||
iCount = 1
|
||||
iOldAttr = iAttr
|
||||
|
||||
Next
|
||||
|
||||
GoSub ADD_ATTR
|
||||
'Debug aAttr.Count; " -> "; N;; "/";; String.Len(Text)
|
||||
'If N > String.Len(Text) Then Stop
|
||||
Return
|
||||
|
||||
ADD_ATTR:
|
||||
|
||||
If iCount Then
|
||||
N += iCount
|
||||
Attr.Add(iOldAttr Or Lsl(iCount - 1, 8))
|
||||
Endif
|
||||
Return
|
||||
|
||||
End
|
||||
|
||||
|
||||
' Public Sub GetAttr(hAttr As TerminalAttr, X As Integer)
|
||||
'
|
||||
' Dim iAttr As Integer
|
||||
'
|
||||
' Try iAttr = Attr[X]
|
||||
'
|
||||
' If BTst(iAttr, FLAG_BG) Then
|
||||
' hAttr.Background = Lsr(iAttr, 16) And 255
|
||||
' Else
|
||||
' hAttr.Background = Color.Default
|
||||
' Endif
|
||||
'
|
||||
' If BTst(iAttr, FLAG_FG) Then
|
||||
' hAttr.Foreground = Lsr(iAttr, 24) And 255
|
||||
' Else
|
||||
' hAttr.Foreground = Color.Default
|
||||
' Endif
|
||||
'
|
||||
' hAttr.Bold = BTst(iAttr, FLAG_BOLD)
|
||||
' hAttr.Dim = BTst(iAttr, FLAG_DIM)
|
||||
' hAttr.Reverse = BTst(iAttr, FLAG_REV)
|
||||
' hAttr.Underscore = BTst(iAttr, FLAG_UND)
|
||||
' hAttr.Blink = BTst(iAttr, FLAG_BLK)
|
||||
'
|
||||
' End
|
||||
'
|
||||
Public Sub SetAttr(hAttr As TerminalAttr, X As Integer, Optional L As Integer = 1, Optional bInsert As Boolean)
|
||||
|
||||
Dim iAttr As Integer
|
||||
Dim aAttr As Integer[]
|
||||
Dim aTemp As Integer[]
|
||||
|
||||
If hAttr.Background <> Color.Default Then iAttr = BSet(iAttr, FLAG_BG) + Lsl(hAttr.Background And 255, 16)
|
||||
If hAttr.Foreground <> Color.Default Then iAttr = BSet(iAttr, FLAG_FG) + Lsl(hAttr.Foreground And 255, 24)
|
||||
|
@ -46,18 +110,30 @@ Public Sub SetAttr(hAttr As TerminalAttr, X As Integer, Optional L As Integer =
|
|||
If hAttr.Underscore Then iAttr = BSet(iAttr, FLAG_UND)
|
||||
If hAttr.Blink Then iAttr = BSet(iAttr, FLAG_BLK)
|
||||
|
||||
If iAttr = 0 And If X + L >= Attr.Count Then
|
||||
Attr.Resize(X)
|
||||
aAttr = Uncompress()
|
||||
|
||||
If iAttr = 0 And If X >= aAttr.Count Then
|
||||
'aAttr.Resize(X)
|
||||
Else
|
||||
If bInsert Then
|
||||
aAttr = New Integer[L]
|
||||
aAttr.Fill(iAttr)
|
||||
Attr.Insert(aAttr, X)
|
||||
If aAttr.Count < X Then aAttr.Resize(X)
|
||||
aTemp = New Integer[L]
|
||||
aTemp.Fill(iAttr)
|
||||
aAttr.Insert(aTemp, X)
|
||||
Else
|
||||
If Attr.Count < X + L Then Attr.Resize(X + L)
|
||||
Attr.Fill(iAttr, X, L)
|
||||
If aAttr.Count < X + L Then aAttr.Resize(X + L)
|
||||
aAttr.Fill(iAttr, X, L)
|
||||
Endif
|
||||
Endif
|
||||
|
||||
Compress(aAttr)
|
||||
|
||||
End
|
||||
|
||||
Public Sub Clear()
|
||||
|
||||
Text = ""
|
||||
Length = 0
|
||||
Attr.Clear
|
||||
|
||||
End
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
Export
|
||||
|
||||
Private Enum FLAG_BG, FLAG_FG, FLAG_BOLD, FLAG_DIM, FLAG_REV, FLAG_UND, FLAG_BLK
|
||||
|
||||
Public Foreground As Integer = -1
|
||||
Public Background As Integer = -1
|
||||
Public Bold As Boolean
|
||||
|
@ -31,3 +33,24 @@ Public Sub IsVoid() As Boolean
|
|||
|
||||
End
|
||||
|
||||
Public Sub FillFrom(iAttr As Integer)
|
||||
|
||||
If BTst(iAttr, FLAG_BG) Then
|
||||
Background = Lsr(iAttr, 16) And 255
|
||||
Else
|
||||
Background = Color.Default
|
||||
Endif
|
||||
|
||||
If BTst(iAttr, FLAG_FG) Then
|
||||
Foreground = Lsr(iAttr, 24) And 255
|
||||
Else
|
||||
Foreground = Color.Default
|
||||
Endif
|
||||
|
||||
Bold = BTst(iAttr, FLAG_BOLD)
|
||||
{Dim} = BTst(iAttr, FLAG_DIM)
|
||||
Reverse = BTst(iAttr, FLAG_REV)
|
||||
Underscore = BTst(iAttr, FLAG_UND)
|
||||
Blink = BTst(iAttr, FLAG_BLK)
|
||||
|
||||
End
|
||||
|
|
|
@ -170,9 +170,8 @@ Private Sub ClearLine(Y As Integer)
|
|||
If Y > Lines.Max Then Return
|
||||
hLine = Lines[Y]
|
||||
If Not hLine Then Return
|
||||
hLine.Text = ""
|
||||
hLine.Length = 0
|
||||
hLine.Attr.Clear
|
||||
|
||||
hLine.Clear()
|
||||
|
||||
End
|
||||
|
||||
|
@ -202,17 +201,19 @@ Private Sub Insert(sText As String, Optional X As Integer = $X)
|
|||
|
||||
If hLine.Length < X Then
|
||||
hLine.Text &= Space$(X - hLine.Length) & sText & String.Mid(hLine.Text, X + iLen)
|
||||
hLine.Length = String.Len(hLine.Text)
|
||||
hLine.SetAttr($hAttr, X, iLen)
|
||||
Else
|
||||
If InsertMode Then
|
||||
hLine.Text = String.Left(String.Left(hLine.Text, X) & sText & String.Mid(hLine.Text, X + 1), $W)
|
||||
hLine.Length = String.Len(hLine.Text)
|
||||
hLine.SetAttr($hAttr, X, iLen, True)
|
||||
Else
|
||||
hLine.Text = String.Left(hLine.Text, X) & sText & String.Mid(hLine.Text, X + iLen + 1)
|
||||
hLine.Length = String.Len(hLine.Text)
|
||||
hLine.SetAttr($hAttr, X, iLen)
|
||||
Endif
|
||||
Endif
|
||||
hLine.Length = String.Len(hLine.Text)
|
||||
|
||||
GetView()._RefreshLine($Y)
|
||||
|
||||
|
@ -454,8 +455,7 @@ Public Sub EraseStartOfLine()
|
|||
|
||||
hLine = GetLine($Y)
|
||||
If hLine.Length <= $X Then
|
||||
hLine.Text = ""
|
||||
hLine.Length = 0
|
||||
hLine.Clear()
|
||||
GetView()._RefreshLine($Y)
|
||||
Else
|
||||
hLine.Text = Space$($X + 1) & String.Mid$(hLine.Text, $X + 1)
|
||||
|
@ -470,8 +470,7 @@ Public Sub EraseLine()
|
|||
|
||||
hLine = GetLine($Y)
|
||||
If $hAttr.IsVoid() Then
|
||||
hLine.Text = ""
|
||||
hLine.Length = 0
|
||||
hLine.Clear()
|
||||
Else
|
||||
Insert(Space$($W), 0)
|
||||
Endif
|
||||
|
@ -664,8 +663,6 @@ Fast Private Sub DrawLine(L As Integer, X As Float, Y As Integer, LH As Integer,
|
|||
Dim I As Integer
|
||||
'Dim sText As String
|
||||
Dim aAttr As Integer[]
|
||||
Dim iAttr As Integer
|
||||
Dim iOldAttr As Integer
|
||||
Dim hAttr As New TerminalAttr
|
||||
Dim iFg As Integer = hView.Foreground
|
||||
Dim iBg As Integer = hView.Background
|
||||
|
@ -688,137 +685,137 @@ Fast Private Sub DrawLine(L As Integer, X As Float, Y As Integer, LH As Integer,
|
|||
aAttr = hLine.Attr
|
||||
|
||||
P = 1
|
||||
For I = 1 To hLine.Length
|
||||
|
||||
If aAttr.Count >= I Then
|
||||
iAttr = aAttr[I - 1]
|
||||
|
||||
For I = 0 To aAttr.Max
|
||||
|
||||
If P > hLine.Length Then Break
|
||||
|
||||
hAttr.FillFrom(aAttr[I])
|
||||
iLen = Min((Lsr(aAttr[I], 8) And 255), hLine.Length - P) + 1
|
||||
|
||||
iBg = hAttr.Background
|
||||
If iBg >= 0 Then
|
||||
iBg = $aColor[iBg]
|
||||
Else
|
||||
iAttr = 0
|
||||
iBg = hView.Background
|
||||
Endif
|
||||
|
||||
If iAttr <> iOldAttr Then
|
||||
|
||||
GoSub DRAW_TEXT
|
||||
|
||||
iOldAttr = iAttr
|
||||
|
||||
hLine.GetAttr(hAttr, I - 1)
|
||||
|
||||
iBg = hAttr.Background
|
||||
If iBg >= 0 Then
|
||||
iBg = $aColor[iBg]
|
||||
Else
|
||||
iBg = hView.Background
|
||||
Endif
|
||||
|
||||
iFg = hAttr.Foreground
|
||||
If iFg >= 0 Then
|
||||
'Debug iFg
|
||||
iFg = $aColor[iFg]
|
||||
Else
|
||||
iFg = hView.Foreground
|
||||
Endif
|
||||
|
||||
If hAttr.Reverse Then Swap iBg, iFg
|
||||
|
||||
If hAttr.Dim Then iFg = Color.Merge(iFg, hView.Background)
|
||||
|
||||
Paint.Background = Color.White
|
||||
|
||||
If hAttr.Bold Then
|
||||
HC = LH
|
||||
Else
|
||||
HC = 0
|
||||
Endif
|
||||
|
||||
iFg = hAttr.Foreground
|
||||
If iFg >= 0 Then
|
||||
'Debug iFg
|
||||
iFg = $aColor[iFg]
|
||||
Else
|
||||
iFg = hView.Foreground
|
||||
Endif
|
||||
|
||||
' Paint.FillRect(X, Y, $CW, $LH, iBg)
|
||||
' If iFg = $hView.Foreground And If String.Code(sCar) <= 255 Then
|
||||
' hRect = Rect(String.Code(sCar) * $CW, 0, $CW, $LH)
|
||||
' Paint.DrawImage($hCacheFont, X, Y, $CW, $LH,, hRect)
|
||||
' If hAttr.Bold Then Paint.DrawImage($hCacheFont, X + 1, Y, $CW, $LH,, hRect)
|
||||
' Else
|
||||
' Paint.DrawText(sCar, X, Y + $iAscent)
|
||||
' If hAttr.Bold Then Paint.DrawText(sCar, X + 1, Y + $iAscent)
|
||||
' Endif
|
||||
' X += $CW
|
||||
If hAttr.Reverse Then Swap iBg, iFg
|
||||
|
||||
If hAttr.Dim Then iFg = Color.Merge(iFg, hView.Background)
|
||||
|
||||
Paint.Background = Color.White
|
||||
|
||||
If hAttr.Bold Then
|
||||
HC = LH
|
||||
Else
|
||||
HC = 0
|
||||
Endif
|
||||
|
||||
GoSub DRAW_TEXT
|
||||
|
||||
Next
|
||||
|
||||
GoSub DRAW_TEXT
|
||||
|
||||
Paint.Operator = Paint.OperatorOver
|
||||
If P <= hLine.Length Then
|
||||
iLen = hLine.Length - P + 1
|
||||
iFg = hView.Foreground
|
||||
iBg = hView.Background
|
||||
HC = 0
|
||||
hAttr.FillFrom(0)
|
||||
GoSub DRAW_TEXT
|
||||
Endif
|
||||
|
||||
Return
|
||||
|
||||
DRAW_TEXT:
|
||||
|
||||
iLen = I - P
|
||||
If iLen <= 0 Then Return
|
||||
|
||||
W = iLen * CW
|
||||
|
||||
Paint.Begin($hLineCache)
|
||||
If hFontCache Then
|
||||
|
||||
Paint.FillRect(0, 0, W, LH, iFg)
|
||||
|
||||
XT = 0
|
||||
|
||||
hRect = Rect(0, 0, CW, LH)
|
||||
|
||||
Paint.Operator = Paint.OperatorDestATop
|
||||
For J = P To P + iLen - 1
|
||||
'sCar = String.Mid$(hLine.Text, J, 1)
|
||||
C = String.Code(hLine.Text, J)
|
||||
If C <= 255 Then
|
||||
hRect.Move(C * CW, HC)
|
||||
Paint.DrawImage(hFontCache, XT, 0, CW, LH,, hRect)
|
||||
Else
|
||||
|
||||
If $cCharCache.Exist(C) Then
|
||||
|
||||
C = $cCharCache[C]
|
||||
hRect.Move(C * CW, 0)
|
||||
Paint.Begin($hLineCache)
|
||||
|
||||
Paint.FillRect(0, 0, W, LH, iFg)
|
||||
|
||||
XT = 0
|
||||
|
||||
hRect = Rect(0, 0, CW, LH)
|
||||
|
||||
Paint.Operator = Paint.OperatorDestATop
|
||||
For J = P To P + iLen - 1
|
||||
'sCar = String.Mid$(hLine.Text, J, 1)
|
||||
C = String.Code(hLine.Text, J)
|
||||
If C = 0 Then Stop
|
||||
If C <= 255 Then
|
||||
hRect.Move(C * CW, HC)
|
||||
Paint.DrawImage(hFontCache, XT, 0, CW, LH,, hRect)
|
||||
|
||||
Else
|
||||
|
||||
If $cCharCache.Count < 32 Then
|
||||
XC = $cCharCache.Count * CW
|
||||
YC = 0
|
||||
If $cCharCache.Exist(C) Then
|
||||
|
||||
C = $cCharCache[C]
|
||||
hRect.Move(C * CW, 0)
|
||||
Paint.DrawImage(hFontCache, XT, 0, CW, LH,, hRect)
|
||||
|
||||
Else
|
||||
XC = 0
|
||||
YC = LH
|
||||
|
||||
If $cCharCache.Count < 32 Then
|
||||
XC = $cCharCache.Count * CW
|
||||
YC = 0
|
||||
Else
|
||||
XC = 0
|
||||
YC = LH
|
||||
Endif
|
||||
|
||||
Paint.Begin(hFontCache)
|
||||
Paint.Operator = Paint.OperatorSource
|
||||
Paint.FillRect(XC, YC, CW, LH, Color.Transparent)
|
||||
Paint.Font = hFont
|
||||
Paint.DrawText(String.Chr$(C), XC, YC, CW, LH, Align.Center)
|
||||
If hAttr.Bold Then Paint.DrawText(String.Chr$(C), XC + 1, YC, CW, LH, Align.Center)
|
||||
Paint.End
|
||||
hRect.Move(XC, YC)
|
||||
Paint.DrawImage(hFontCache, XT, 0, CW, LH,, hRect)
|
||||
|
||||
If YC = 0 Then $cCharCache[C] = $cCharCache.Count
|
||||
|
||||
Endif
|
||||
|
||||
Paint.Begin(hFontCache)
|
||||
Paint.Operator = Paint.OperatorSource
|
||||
Paint.FillRect(XC, YC, CW, LH, Color.Transparent)
|
||||
Paint.Font = hFont
|
||||
Paint.DrawText(String.Chr$(C), XC, YC, CW, LH, Align.Center)
|
||||
If hAttr.Bold Then Paint.DrawText(String.Chr$(C), XC + 1, YC, CW, LH, Align.Center)
|
||||
Paint.End
|
||||
hRect.Move(XC, YC)
|
||||
Paint.DrawImage(hFontCache, XT, 0, CW, LH,, hRect)
|
||||
|
||||
If YC = 0 Then $cCharCache[C] = $cCharCache.Count
|
||||
|
||||
Endif
|
||||
Endif
|
||||
XT += CW
|
||||
Next
|
||||
|
||||
Paint.End
|
||||
|
||||
XT = X
|
||||
|
||||
Paint.FillRect(XT, Y, W, LH, iBg)
|
||||
Paint.DrawImage($hLineCache, XT, Y, W, LH,, Rect(0, 0, W, LH))
|
||||
XT += CW
|
||||
Next
|
||||
|
||||
Paint.End
|
||||
|
||||
XT = X
|
||||
|
||||
Paint.FillRect(XT, Y, W, LH, iBg)
|
||||
Paint.DrawImage($hLineCache, XT, Y, W, LH,, Rect(0, 0, W, LH))
|
||||
|
||||
Else
|
||||
|
||||
XT = X
|
||||
|
||||
Paint.FillRect(XT, Y, W, LH, iBg)
|
||||
Paint.Background = iFg
|
||||
Paint.DrawText(String.Mid$(hLine.Text, P, iLen), XT, Y + LA)
|
||||
If hAttr.Bold Then Paint.DrawText(String.Mid$(hLine.Text, P, iLen), XT + 1, Y + LA)
|
||||
|
||||
Endif
|
||||
|
||||
If hAttr.Underscore Then Paint.FillRect(XT, Y + LH - 1, W, 1, Color.SetAlpha(iFg, 64))
|
||||
|
||||
X += W
|
||||
P = I
|
||||
P += iLen
|
||||
Return
|
||||
|
||||
End
|
||||
|
|
|
@ -155,25 +155,33 @@ Private Sub UpdateFont()
|
|||
'Debug $CW
|
||||
$CW = Ceil($CW)
|
||||
|
||||
' If .Fixed Then
|
||||
'
|
||||
' $hCacheFont = Null
|
||||
'
|
||||
' Else
|
||||
|
||||
$hCacheFont = New Image($CW * 256, $LH * 2, Color.Transparent)
|
||||
Paint.Begin($hCacheFont)
|
||||
Paint.Background = Color.White
|
||||
Paint.Font = $hView.Font
|
||||
For I = 33 To 126
|
||||
Paint.DrawText(String.Chr(I), I * $CW, 0, $CW, $LH, Align.Center)
|
||||
Next
|
||||
For I = 160 To 255
|
||||
Paint.DrawText(String.Chr(I), I * $CW, 0, $CW, $LH, Align.Center)
|
||||
Next
|
||||
Paint.End
|
||||
|
||||
Paint.Begin($hCacheFont)
|
||||
Paint.DrawImage($hCacheFont, 0, $LH, $hCacheFont.W, $LH,, Rect(0, 0, $hCacheFont.W, $LH))
|
||||
Paint.DrawImage($hCacheFont, 1, $LH, $hCacheFont.W, $LH, 0.8, Rect(0, 0, $hCacheFont.W, $LH))
|
||||
Paint.End
|
||||
|
||||
' Endif
|
||||
|
||||
End With
|
||||
|
||||
$hCacheFont = New Image($CW * 256, $LH * 2, Color.Transparent)
|
||||
Paint.Begin($hCacheFont)
|
||||
Paint.Background = Color.White
|
||||
Paint.Font = $hView.Font
|
||||
For I = 33 To 126
|
||||
Paint.DrawText(String.Chr(I), I * $CW, 0, $CW, $LH, Align.Center)
|
||||
Next
|
||||
For I = 160 To 255
|
||||
Paint.DrawText(String.Chr(I), I * $CW, 0, $CW, $LH, Align.Center)
|
||||
Next
|
||||
Paint.End
|
||||
|
||||
Paint.Begin($hCacheFont)
|
||||
Paint.DrawImage($hCacheFont, 0, $LH, $hCacheFont.W, $LH,, Rect(0, 0, $hCacheFont.W, $LH))
|
||||
Paint.DrawImage($hCacheFont, 1, $LH, $hCacheFont.W, $LH, 0.8, Rect(0, 0, $hCacheFont.W, $LH))
|
||||
Paint.End
|
||||
|
||||
' For I = 33 To 255
|
||||
' Paint.DrawText(String.Chr(I), I * $CW, $LH, $CW, $LH, Align.Center)
|
||||
' Paint.DrawText(String.Chr(I), I * $CW + 1, $LH, $CW, $LH, Align.Center)
|
||||
|
|
|
@ -747,6 +747,13 @@ BEGIN_METHOD(String_Code, GB_STRING str; GB_INTEGER index)
|
|||
|
||||
str = STRING(str);
|
||||
len = LENGTH(str);
|
||||
|
||||
if (index > len)
|
||||
{
|
||||
GB_ReturnInteger(0);
|
||||
return;
|
||||
}
|
||||
|
||||
pos = utf8_get_pos(VARG(str).addr, str, len, index - 1);
|
||||
lc = STRING_utf8_get_char_length(str[pos]);
|
||||
|
||||
|
|
Loading…
Reference in a new issue