1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
| *
* Creates next string key from the passed one using specified set of characters
*
* Parameters
* 1 - Current Key
* 2 - Defines the list of allowed characters
* BASEnn - See DO CASE in the body of the program
* CUSTOM - the list of character as parameter 3
* 3 - List of characters
*
* Returns Next key
*
* Note 1 Routine ignores (doesn't change) positions with the characters not in the specified list
* Note 2 When max possible value is reached, the next return value will be the min possible value
*
FUNCTION NextKey
LPARAMETERS tcOldVal, tcOpt, tcCharList
LOCAL lcNewVal, i, lcDigits, lcLetters, lnCharListLen, lcOldChar, lcNewChar, lcCharList, lnPos, lcOpt
LOCAL lnNextPos
lcOpt = IIF(EMPTY(tcOpt), "BASE10", UPPER(tcOpt))
* Get the list of appropriate characters
lcCharList = NextKeyFillCharList(lcOpt, tcCharList)
lnCharListLen = LEN(lcCharList)
lcNewVal = tcOldVal
* Scan string from the right to the left
FOR i = LEN(lcNewVal) TO 1 STEP -1
lcOldChar = SUBSTR(tcOldVal, i, 1)
* Is the current charater in the list?
lnPos = AT(lcOldChar, lcCharList)
IF lnPos = 0
* Not in the list, keep it
LOOP
ENDIF
* Get the next character position
lnNextPos = (lnPos % lnCharListLen) + 1
* Get the next character
lcNewChar = SUBSTR(lcCharList,lnNextPos,1)
* Stuff it back in the string
lcNewVal = STUFF(lcNewVal, i, 1, lcNewChar)
* Check if we have to carry over to the next position
IF lnNextPos > 1
* We are done
EXIT
ENDIF
ENDFOR
RETURN lcNewVal
*------------------------------------------------------------
* Fill the list of characters based on character set requested
FUNCTION NextKeyFillCharList
LPARAMETERS tcCharSet, tcCharList
LOCAL lcCharList, lcDigits, lcLetters
* Fill string 'lcCharList' with appropriate characters
lcDigits = "0123456789"
lcLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
DO CASE
CASE tcCharSet = "CUSTOM"
lcCharList = tcCharList
CASE tcCharSet == "BASE10"
* Just Digits
lcCharList = lcDigits
CASE tcCharSet == "BASE16L"
* Hexadecimal in lower case
lcCharList = lcDigits + "abcdef"
CASE tcCharSet == "BASE16"
* Hexadecimal in upper case
lcCharList = lcDigits + "ABCDEF"
CASE tcCharSet == "BASE26L"
* Lower case letters
lcCharList = LOWER(lcLetters)
CASE tcCharSet == "BASE26"
* Upper case letters
lcCharList = lcLetters
CASE tcCharSet == "BASE36L"
* Digits + Lower case letters
lcCharList = lcDigits + LOWER(lcLetters)
CASE tcCharSet == "BASE36"
* Digits + Upper case letters
lcCharList = lcDigits + lcLetters
CASE tcCharSet == "BASE52"
* All letters
lcCharList = lcLetters + LOWER(lcLetters)
CASE tcCharSet == "BASE62"
* Digits + All letters
lcCharList = lcDigits + lcLetters + LOWER(lcLetters)
OTHERWISE
* The same as BASE10
lcCharList = lcDigits
ENDCASE
RETURN lcCharList |