Advance counter v20040306
Added on 3/6/2004
the normal repeat loop can only handle a continue sequence but "Advance counter" can handle more like:
"1,3,5,7,10-100" (mixed, non-continue sequence)
"A-Z" (letter sequence)
or mixed them all:
"1-10, 12,14,n,o,d,X-Z"
since it is not base on a pre-bulid Linear list, it is especially suitable for very long sequence.
Download PC Source
--sAdvCounter v20040306
-- Copyright 2004 Ivan Leung, Gamerise Multimedia Studio
-- ivan.leung@gamerise.com
-- interface summary:
-- mParse() - parse the counter sequence string
-- mGet() - get the counter value
-- mStep() - step to next value and get the new value
-- mOver() - restart counter
-- mLinkTo() - link this counter to a target counter so that the target
-- counter will step forward while this counter has restart
-- = new(script"sAdvCounter" ,)
-- : #instance - script Instance
-- : #string - (optional) parsing string for the counter
-- = .mParse()
-- parse the counter sequence string
-- : #symbol - #sOk / #sError
-- : #string - parsing string for the counter
-- = .mGet()
-- get the counter value
-- : #string/#integer - counter value
-- = .mStep()
-- step to next value and get the new value
-- : #string/#integer - counter value
-- .mOver()
-- restart counter
-- .mLinkTo()
-- link to a target counter
-- : #instance - target counter instance
-- parsing string format:
-- =
-- "1-5" = 1,2,3,4,5 (continue sequence)
-- "1->" = 1,2,3... (infinity sequence)
-- "1,3,5" = 1,3,5 (breaked sequence)
-- "1,3-5" = 1,3,4,5 (mixed sequence)
-- "a, c-e" = "a","c","d","e" (a-z letters)
-- "X-Z" = "X","Y","Z" (both caps or small letter support)
-- "1,3-5,a,c,X-Z" = 1,3,4,5,"a","c","X","Y","Z" (mixed no. and a-z)
property pCounter, pUnitList, pUnitCounter, pLinkCounter
on new me, aString
if ilk(aString) = #string then
if me.mParse(aString) <> #sOk then
alert "sAdvCounter : parsing error!"
abort
end if
end if
return me
end
on mParse me, aString
pUnitList = [ ]
the itemDelimiter = ","
c = aString.item.count
repeat with i = 1 to c
the itemDelimiter = ","
tSubString = aString.item[i]
if tSubString <> EMPTY then
tUnit = me.mGetUnit(tSubString)
if not voidP(tUnit) then
pUnitList[i] = tUnit
else
pUnitList = [ ]
return #sError
end if
end if
end repeat
me.mReset()
return #sOk
end
on mGet me
if pUnitList <> [ ] then
return pCounter
else
return VOID
end if
end
on mStep me
if pUnitList = [ ] then return VOID
tCurUnit = pUnitList[pUnitCounter]
if ilk(tCurUnit) = #propList then
if pCounter = pUnitList[pUnitCounter].pTo then
me.mStepUnit()
else
me.mCounterIncrease()
end if
else
me.mStepUnit()
end if
return pCounter
end
on mOver me
if pUnitList = [ ] then return VOID
me.mReset()
if not voidP(pLinkCounter) then
pLinkCounter.mStep()
end if
end
on mLinkTo me, aInstance
if pUnitList = [ ] then return VOID
pLinkCounter = aInstance
end
-- internal
on mReset me
if pUnitList = [ ] then return VOID
pUnitCounter = 1
if ilk(pUnitList[pUnitCounter]) = #propList then
pCounter = pUnitList[pUnitCounter].pFrom
else
pCounter = pUnitList[pUnitCounter]
end if
end
on mGetUnit me, aString
the itemDelimiter = "-"
if aString.item.count = 2 then
tFrom = me.mGetValid(aString.item[1])
if aString.item[2] = ">" and ilk(tFrom) = #integer then
tTo = the maxInteger
else if aString.item[2] = ">" and ilk(tFrom) = #string then
tTo = "Z"
else
tTo = me.mGetValid(aString.item[2])
end if
if (ilk(tFrom) <> ilk(tTo)) or voidP(tFrom) or voidP(tTo) then return VOID
if tFrom > tTo then return VOID
return [#pFrom:tFrom, #pTo:tTo]
else if aString.item.count = 1 then
return me.mGetValid(aString)
end if
end
on mStepUnit me
if pUnitCounter < pUnitList.count then
pUnitCounter = pUnitCounter + 1
tNextUnit = pUnitList[pUnitCounter]
if ilk(tNextUnit) = #propList then
pCounter = tNextUnit.pFrom
else
pCounter = tNextUnit
end if
else
me.mOver()
end if
end
on mCounterIncrease me
if ilk(pCounter) = #integer then
pCounter = pCounter + 1
else if ilk(pCounter) = #string then
pCounter = numToChar(charToNum(pCounter) + 1)
end if
end
on mGetValid me, aString
tString = me.mTrim(aString)
tInteger = integer(tString)
if not voidP(tInteger) then return tInteger
if tString = EMPTY or tString.length > 1 then return VOID
tCharNum = charToNum(tString)
if (tCharNum >= 65 and tCharNum <= 90) or (tCharNum >= 97 and tCharNum <= 122) then return tString
end
on mTrim me, aText
c = length(aText)
if c = 0 then return EMPTY
tPre = 0
tPost = 0
repeat with i = 1 to c
if aText.char[i] <> SPACE and aText.char[i] <> TAB then
tPre = i
exit repeat
end if
end repeat
if tPre <> 0 then
repeat with i = c down to 1
if aText.char[i] <> SPACE and aText.char[i] <> TAB then
tPost = i
exit repeat
end if
end repeat
end if
if tPre = 0 or tPost = 0 then
return EMPTY
else
return aText.char[tPre..tPost]
end if
end
-- version history:
-- v20040306: add a-z / A-Z syntax
-- v20040120: add comma syntax
-- v20030109: add stepping