more ProOpen and PostOpen hook points
[nedit-bw.git] / macroSplit.diff
blob4e4c326a48f5e770c24314d235cf449b7df42b6c
1 From: Tony Balinski <ajbj@free.fr>
2 Subject: Extending the split() macro built-in
4 This patch extends split()'s functionality. It allows limited splitting,
5 where only a certain number of elements should be retrieved, and also
6 allows the dropping of the last element found if it is empty.
8 The limited count avoids the perhaps unnecessary overhead of generating a
9 large array if only the first few elements are to be used. The dropping of
10 the empty last element allows simple reconstruction after simple splits,
11 very useful for lines. For example, given:
13 a = get_range(0, $text_length)
14 lines = split(a, "\n", "lastnotnull")
15 b = ""
16 for (i = 0; i < lines[]; i++)
17 b = b lines[i] "\n"
19 assuming that all lines are '\n' terminated, b == a at the end. Otherwise
20 we have to resort to something like:
22 a = get_range(0, $text_length)
23 lines = split(a, "\n")
24 b = ""
25 sep = ""
26 for (i = 0; i < lines[]; i++) {
27 b = b sep lines[i]
28 sep = "\n"
31 to make a == b at the end. which is trickier (albeit more general).
33 ---
35 source/macro.c | 109 +++++++++++++++++++++++++++++++++++++++++++--------------
36 1 file changed, 84 insertions(+), 25 deletions(-)
38 diff --quilt old/source/macro.c new/source/macro.c
39 --- old/source/macro.c
40 +++ new/source/macro.c
41 @@ -3585,14 +3585,39 @@ static int stringCompareMS(WindowInfo *w
45 -** This function is intended to split strings into an array of substrings
46 -** Importatnt note: It should always return at least one entry with key 0
47 -** split("", ",") result[0] = ""
48 -** split("1,2", ",") result[0] = "1" result[1] = "2"
49 -** split("1,2,", ",") result[0] = "1" result[1] = "2" result[2] = ""
50 -**
51 -** This behavior is specifically important when used to break up
52 -** array sub-scripts
53 +** This function is intended to split strings into an array of substrings.
54 +**
55 +** array = split(string, separator[, searchType][, count][, "lastnotnull"])
56 +**
57 +** Mandatory arguments:
58 +** string: string to split,
59 +** string: separator string or pattern marking where to split
60 +** Optional arguments:
61 +** searchType: separator search type (default is "literal") to use to find
62 +** occurrences of separator in string.
63 +** count: maximum number of pieces in the returned array (default is
64 +** infinite, must be greater than zero); if smaller than or equal to
65 +** the number of separators found in string, the last piece will
66 +** contain the remainder of the string to split (a count of 1 produces
67 +** a single result in the returned array, equal to the original
68 +** string).
69 +** keyword "lastnotnull": if present, this stops an empty string being
70 +** returned in the last entry of the array if the string to split ends
71 +** with the separator. This has the effect of returning an empty array
72 +** if the string to split is originally empty. Otherwise, the returned
73 +** array will always contain at least one element.
74 +**
75 +** Important note: It should always return at least one entry with key 0
76 +** unless "lastnotnull" is present.
77 +**
78 +** eg
79 +** split("", ",") result[0] = ""
80 +** split(",", ",") result[0] = "" result[1] = ""
81 +** split("1,2", ",") result[0] = "1" result[1] = "2"
82 +** split("1,2,", ",") result[0] = "1" result[1] = "2" result[2] = ""
83 +**
84 +** This behavior is specifically important when used to break up
85 +** array sub-scripts (unless "lastnotnull" is present)
88 static int splitMS(WindowInfo *window, DataValue *argList, int nArgs,
89 @@ -3605,8 +3630,12 @@ static int splitMS(WindowInfo *window, D
90 char indexStr[TYPE_INT_STR_SIZE(int)], *allocIndexStr;
91 DataValue element;
92 int elementLen;
94 - if (nArgs < 2) {
95 + int haveSearchType = False;
96 + int haveCount = False;
97 + int count = 0;
98 + int lastnotnull = False;
100 + if (nArgs < 2 || nArgs > 4) {
101 return(wrongNArgsErr(errMsg));
103 if (!readStringArg(argList[0], &sourceStr, stringStorage[0], errMsg)) {
104 @@ -3625,16 +3654,40 @@ static int splitMS(WindowInfo *window, D
105 *errMsg = "second argument must be a non-empty string: %s";
106 return(False);
108 - if (nArgs > 2 && readStringArg(argList[2], &typeSplitStr, stringStorage[2], errMsg)) {
109 - if (!StringToSearchType(typeSplitStr, &searchType)) {
111 + /* get the search type and maximum element count */
112 + searchType = SEARCH_LITERAL;
113 + for (indexNum = 2; indexNum < nArgs; indexNum++) {
114 + if (!readStringArg(argList[indexNum], &typeSplitStr,
115 + stringStorage[indexNum], errMsg)) {
116 + *errMsg = "non-scalar arguments not allowed: %s";
117 + return(False);
119 + if (strcmp(typeSplitStr, "lastnotnull") == 0) {
120 + if (lastnotnull) {
121 + *errMsg = "\"lastnotnull\" specified more than once: %s";
122 + return(False);
124 + lastnotnull = True;
125 + } else if (StringToSearchType(typeSplitStr, &searchType)) {
126 + if (haveSearchType) {
127 + *errMsg = "split search type supplied more than once: %s";
128 + return(False);
130 + haveSearchType = True;
131 + } else if (!haveCount &&
132 + readIntArg(argList[indexNum], &count, errMsg)) {
133 + haveCount = True;
134 + if (count < 1) {
135 + *errMsg = "split maximum count must be greater than 0: %s";
136 + return(False);
138 + } else {
139 *errMsg = "unrecognized argument to %s";
140 return(False);
143 - else {
144 - searchType = SEARCH_LITERAL;
148 result->tag = ARRAY_TAG;
149 result->val.arrayPtr = ArrayNew();
151 @@ -3651,9 +3704,13 @@ static int splitMS(WindowInfo *window, D
152 return(False);
154 strcpy(allocIndexStr, indexStr);
155 - found = SearchString(sourceStr, splitStr, SEARCH_FORWARD, searchType,
156 - False, beginPos, &foundStart, &foundEnd,
157 - NULL, NULL, GetWindowDelimiters(window));
158 + if (haveCount && --count == 0) {
159 + found = 0;
160 + } else {
161 + found = SearchString(sourceStr, splitStr, SEARCH_FORWARD,
162 + searchType, False, beginPos, &foundStart, &foundEnd,
163 + NULL, NULL, GetWindowDelimiters(window));
165 elementEnd = found ? foundStart : strLength;
166 elementLen = elementEnd - lastEnd;
167 element.tag = STRING_TAG;
168 @@ -3688,12 +3745,14 @@ static int splitMS(WindowInfo *window, D
169 strcpy(allocIndexStr, indexStr);
170 element.tag = STRING_TAG;
171 if (lastEnd == strLength) {
172 - /* The pattern mathed the end of the string. Add an empty chunk. */
173 - element.val.str.rep = PERM_ALLOC_STR("");
174 - element.val.str.len = 0;
175 + if (!lastnotnull) {
176 + /* The pattern matched the end of the string. Add an empty chunk. */
177 + element.val.str.rep = PERM_ALLOC_STR("");
178 + element.val.str.len = 0;
180 - if (!ArrayInsert(result, allocIndexStr, &element)) {
181 - M_ARRAY_INSERT_FAILURE();
182 + if (!ArrayInsert(result, allocIndexStr, &element)) {
183 + M_ARRAY_INSERT_FAILURE();
186 } else {
187 /* We skipped the last character to prevent an endless loop.
188 @@ -3719,7 +3778,7 @@ static int splitMS(WindowInfo *window, D
189 found = SearchString(sourceStr, splitStr, SEARCH_FORWARD,
190 searchType, False, strLength, &foundStart, &foundEnd,
191 NULL, NULL, GetWindowDelimiters(window));
192 - if (found) {
193 + if (found && !lastnotnull) {
194 ++indexNum;
195 sprintf(indexStr, "%d", indexNum);
196 allocIndexStr = AllocString(strlen(indexStr) + 1);