mittens 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/Gemfile +1 -0
  4. data/README.md +2 -2
  5. data/Rakefile +10 -3
  6. data/lib/mittens/version.rb +1 -1
  7. data/vendor/snowball/.github/workflows/ci.yml +144 -17
  8. data/vendor/snowball/.github/workflows/coverage.yml +117 -0
  9. data/vendor/snowball/.github/workflows/runtime-tests.yml +26 -0
  10. data/vendor/snowball/.gitignore +33 -7
  11. data/vendor/snowball/CONTRIBUTING.rst +7 -0
  12. data/vendor/snowball/COPYING +1 -1
  13. data/vendor/snowball/GNUmakefile +736 -298
  14. data/vendor/snowball/NEWS +1394 -7
  15. data/vendor/snowball/README.rst +8 -8
  16. data/vendor/snowball/ada/generate/generate.adb +5 -5
  17. data/vendor/snowball/ada/src/stemmer.adb +177 -188
  18. data/vendor/snowball/ada/src/stemmer.ads +86 -89
  19. data/vendor/snowball/ada/src/stemwords.adb +21 -5
  20. data/vendor/snowball/algorithms/czech.sbl +255 -0
  21. data/vendor/snowball/algorithms/danish.sbl +22 -10
  22. data/vendor/snowball/algorithms/english.sbl +7 -4
  23. data/vendor/snowball/algorithms/esperanto.sbl +6 -7
  24. data/vendor/snowball/algorithms/estonian.sbl +9 -4
  25. data/vendor/snowball/algorithms/finnish.sbl +33 -21
  26. data/vendor/snowball/algorithms/german.sbl +5 -0
  27. data/vendor/snowball/algorithms/indonesian.sbl +115 -96
  28. data/vendor/snowball/algorithms/italian.sbl +26 -1
  29. data/vendor/snowball/algorithms/lithuanian.sbl +13 -13
  30. data/vendor/snowball/algorithms/norwegian.sbl +17 -6
  31. data/vendor/snowball/algorithms/persian.sbl +387 -0
  32. data/vendor/snowball/algorithms/polish.sbl +177 -0
  33. data/vendor/snowball/algorithms/sesotho.sbl +115 -0
  34. data/vendor/snowball/algorithms/turkish.sbl +4 -4
  35. data/vendor/snowball/compiler/analyser.c +2002 -711
  36. data/vendor/snowball/compiler/driver.c +460 -298
  37. data/vendor/snowball/compiler/generator.c +439 -1965
  38. data/vendor/snowball/compiler/generator_ada.c +605 -430
  39. data/vendor/snowball/compiler/generator_c.c +2227 -0
  40. data/vendor/snowball/compiler/generator_csharp.c +365 -274
  41. data/vendor/snowball/compiler/generator_dart.c +1476 -0
  42. data/vendor/snowball/compiler/generator_go.c +348 -270
  43. data/vendor/snowball/compiler/generator_java.c +330 -233
  44. data/vendor/snowball/compiler/generator_js.c +534 -385
  45. data/vendor/snowball/compiler/generator_pascal.c +361 -320
  46. data/vendor/snowball/compiler/generator_php.c +1445 -0
  47. data/vendor/snowball/compiler/generator_python.c +399 -299
  48. data/vendor/snowball/compiler/generator_rust.c +370 -261
  49. data/vendor/snowball/compiler/generator_zig.c +1474 -0
  50. data/vendor/snowball/compiler/header.h +153 -86
  51. data/vendor/snowball/compiler/space.c +121 -63
  52. data/vendor/snowball/compiler/tokeniser.c +286 -182
  53. data/vendor/snowball/compiler/tokens.h +71 -0
  54. data/vendor/snowball/csharp/Snowball/Among.cs +14 -26
  55. data/vendor/snowball/csharp/Snowball/AssemblyInfo.cs +3 -3
  56. data/vendor/snowball/csharp/Snowball/Stemmer.cs +41 -45
  57. data/vendor/snowball/csharp/Stemwords/Program.cs +20 -14
  58. data/vendor/snowball/cxx/.gitignore +4 -0
  59. data/vendor/snowball/cxx/generate_algorithms.pl +87 -0
  60. data/vendor/snowball/cxx/stemmer.h +12 -0
  61. data/vendor/snowball/cxx/stemwords.cxx +176 -0
  62. data/vendor/snowball/cxx/utilities.cxx +2 -0
  63. data/vendor/snowball/dart/.gitignore +4 -0
  64. data/vendor/snowball/dart/analysis_options.yaml +1 -0
  65. data/vendor/snowball/dart/example/test_app.dart +65 -0
  66. data/vendor/snowball/dart/generate_algorithms.pl +21 -0
  67. data/vendor/snowball/dart/lib/snowball.dart +18 -0
  68. data/vendor/snowball/dart/lib/src/snowball.dart +339 -0
  69. data/vendor/snowball/dart/pubspec.yaml +17 -0
  70. data/vendor/snowball/doc/libstemmer_dart_README +37 -0
  71. data/vendor/snowball/doc/libstemmer_js_README +2 -2
  72. data/vendor/snowball/doc/libstemmer_php_README +38 -0
  73. data/vendor/snowball/doc/libstemmer_python_README +3 -3
  74. data/vendor/snowball/examples/stemwords.c +18 -3
  75. data/vendor/snowball/go/README.md +12 -4
  76. data/vendor/snowball/go/env.go +12 -14
  77. data/vendor/snowball/go/stemwords/main.go +2 -1
  78. data/vendor/snowball/java/org/tartarus/snowball/CharArraySequence.java +36 -0
  79. data/vendor/snowball/java/org/tartarus/snowball/SnowballProgram.java +17 -34
  80. data/vendor/snowball/java/org/tartarus/snowball/SnowballStemmer.java +0 -2
  81. data/vendor/snowball/javascript/base-stemmer.js +219 -252
  82. data/vendor/snowball/javascript/stemwords.js +86 -58
  83. data/vendor/snowball/libstemmer/mkmodules.pl +1 -1
  84. data/vendor/snowball/libstemmer/modules.txt +4 -0
  85. data/vendor/snowball/pascal/SnowballProgram.pas +18 -31
  86. data/vendor/snowball/php/base-stemmer.php +453 -0
  87. data/vendor/snowball/php/stemwords.php +25 -0
  88. data/vendor/snowball/python/create_init.py +16 -21
  89. data/vendor/snowball/python/pyproject.toml +3 -0
  90. data/vendor/snowball/python/setup.py +5 -7
  91. data/vendor/snowball/python/snowballstemmer/among.py +1 -2
  92. data/vendor/snowball/python/snowballstemmer/basestemmer.py +24 -33
  93. data/vendor/snowball/python/stemwords.py +72 -63
  94. data/vendor/snowball/runtime/api.c +11 -42
  95. data/vendor/snowball/runtime/api.h +11 -9
  96. data/vendor/snowball/runtime/snowball_runtime.h +110 -0
  97. data/vendor/snowball/runtime/utilities.c +282 -106
  98. data/vendor/snowball/rust/src/main.rs +2 -2
  99. data/vendor/snowball/rust/src/snowball/snowball_env.rs +7 -9
  100. data/vendor/snowball/tests/compilertest +62 -0
  101. data/vendor/snowball/tests/errors/ae-errors.sbl +53 -0
  102. data/vendor/snowball/tests/errors/ae-errors.stderr +8 -0
  103. data/vendor/snowball/tests/errors/bad-dollar.sbl +14 -0
  104. data/vendor/snowball/tests/errors/bad-dollar.stderr +4 -0
  105. data/vendor/snowball/tests/errors/bad-grouping-definition.sbl +9 -0
  106. data/vendor/snowball/tests/errors/bad-grouping-definition.stderr +6 -0
  107. data/vendor/snowball/tests/errors/missing-bra.sbl +6 -0
  108. data/vendor/snowball/tests/errors/missing-bra.stderr +3 -0
  109. data/vendor/snowball/tests/errors/missing-command.sbl +9 -0
  110. data/vendor/snowball/tests/errors/missing-command.stderr +1 -0
  111. data/vendor/snowball/tests/errors/missing-ket-backwardmode.sbl +3 -0
  112. data/vendor/snowball/tests/errors/missing-ket-backwardmode.stderr +1 -0
  113. data/vendor/snowball/tests/errors/missing-ket.sbl +7 -0
  114. data/vendor/snowball/tests/errors/missing-ket.stderr +6 -0
  115. data/vendor/snowball/tests/errors/notdefined.sbl +4 -0
  116. data/vendor/snowball/tests/errors/notdefined.stderr +2 -0
  117. data/vendor/snowball/tests/errors/string-omitted.sbl +5 -0
  118. data/vendor/snowball/tests/errors/string-omitted.stderr +1 -0
  119. data/vendor/snowball/tests/errors/undeclared.sbl +20 -0
  120. data/vendor/snowball/tests/errors/undeclared.stderr +9 -0
  121. data/vendor/snowball/tests/errors/unexpected-token.sbl +24 -0
  122. data/vendor/snowball/tests/errors/unexpected-token.stderr +17 -0
  123. data/vendor/snowball/tests/errors/wrongdirection.sbl +14 -0
  124. data/vendor/snowball/tests/errors/wrongdirection.stderr +1 -0
  125. data/vendor/snowball/tests/runtime/among.sbl +19 -0
  126. data/vendor/snowball/tests/runtime/arithmeticexpr.sbl +86 -0
  127. data/vendor/snowball/tests/runtime/attachinsert.sbl +47 -0
  128. data/vendor/snowball/tests/runtime/booleans.sbl +19 -0
  129. data/vendor/snowball/tests/runtime/externals.sbl +22 -0
  130. data/vendor/snowball/tests/runtime/hop.sbl +12 -0
  131. data/vendor/snowball/tests/runtime/integertests.sbl +60 -0
  132. data/vendor/snowball/tests/runtime/intlimits.sbl +25 -0
  133. data/vendor/snowball/tests/runtime/naming.sbl +20 -0
  134. data/vendor/snowball/tests/runtime/not.sbl +30 -0
  135. data/vendor/snowball/tests/runtime/or.sbl +17 -0
  136. data/vendor/snowball/tests/runtime/repeat.sbl +16 -0
  137. data/vendor/snowball/tests/runtime/setlimit.sbl +24 -0
  138. data/vendor/snowball/tests/runtime/sizelen.sbl +56 -0
  139. data/vendor/snowball/tests/runtime/slice.sbl +27 -0
  140. data/vendor/snowball/tests/runtime/stringdollar.sbl +39 -0
  141. data/vendor/snowball/tests/runtime/strings.sbl +66 -0
  142. data/vendor/snowball/tests/runtime/test.sbl +19 -0
  143. data/vendor/snowball/tests/stemtest.c +41 -1
  144. data/vendor/snowball/tests/syntax/canon.sbl +32 -0
  145. data/vendor/snowball/tests/syntax/canon.stderr +0 -0
  146. data/vendor/snowball/tests/syntax/canon.syntax +57 -0
  147. data/vendor/snowball/tests/syntax/emptyprogram.sbl +2 -0
  148. data/vendor/snowball/tests/syntax/emptyprogram.syntax +0 -0
  149. data/vendor/snowball/tests/syntax/groupings.sbl +11 -0
  150. data/vendor/snowball/tests/syntax/inline.sbl +144 -0
  151. data/vendor/snowball/tests/syntax/inline.stderr +0 -0
  152. data/vendor/snowball/tests/syntax/inline.syntax +121 -0
  153. data/vendor/snowball/tests/syntax/legacy.sbl +17 -0
  154. data/vendor/snowball/tests/syntax/legacy.stderr +5 -0
  155. data/vendor/snowball/tests/syntax/legacy.syntax +19 -0
  156. data/vendor/snowball/tests/syntax/loops.sbl +14 -0
  157. data/vendor/snowball/tests/syntax/loops.stderr +9 -0
  158. data/vendor/snowball/tests/syntax/loops.syntax +29 -0
  159. data/vendor/snowball/tests/syntax/noops.sbl +76 -0
  160. data/vendor/snowball/tests/syntax/noops.stderr +27 -0
  161. data/vendor/snowball/tests/syntax/noops.syntax +135 -0
  162. data/vendor/snowball/tests/syntax/simplifyae.sbl +21 -0
  163. data/vendor/snowball/tests/syntax/simplifyae.stderr +0 -0
  164. data/vendor/snowball/tests/syntax/simplifyae.syntax +39 -0
  165. data/vendor/snowball/tests/syntax/unused.sbl +18 -0
  166. data/vendor/snowball/tests/syntax/unused.stderr +7 -0
  167. data/vendor/snowball/tests/syntax/unused.syntax +3 -0
  168. data/vendor/snowball/zig/env.zig +599 -0
  169. data/vendor/snowball/zig/generate_algorithms.pl +19 -0
  170. data/vendor/snowball/zig/stemwords.zig +123 -0
  171. metadata +102 -4
  172. data/vendor/snowball/compiler/syswords.h +0 -86
  173. data/vendor/snowball/runtime/header.h +0 -62
@@ -1,15 +1,17 @@
1
1
 
2
+ #include <limits.h>
3
+ #include <stdarg.h>
2
4
  #include <stdio.h> /* for printf */
3
5
  #include <stdlib.h> /* malloc, free */
4
6
  #include <string.h> /* memmove */
5
7
 
6
8
  #include "header.h"
7
9
 
8
- #define HEAD 2*sizeof(int)
10
+ #define HEAD (2 * sizeof(int))
9
11
  #define EXTENDER 40
10
12
 
11
13
 
12
- /* This modules provides a simple mechanism for arbitrary length writable
14
+ /* This module provides a simple mechanism for arbitrary length writable
13
15
  strings, called 'blocks'. They are 'symbol *' items rather than 'char *'
14
16
  items however.
15
17
 
@@ -31,10 +33,8 @@
31
33
  For example:
32
34
 
33
35
  symbol * b = create_b(0);
34
- { symbol i;
35
- for (i = 'A'; i <= 'Z'; i++) {
36
- add_symbol_to_b(b, i);
37
- }
36
+ for (symbol i = 'A'; i <= 'Z'; i++) {
37
+ add_symbol_to_b(b, i);
38
38
  }
39
39
 
40
40
  After running the above code b contains:
@@ -52,13 +52,12 @@
52
52
  extern symbol * create_b(int n) {
53
53
  symbol * p = (symbol *) (HEAD + (char *) MALLOC(HEAD + (n + 1) * sizeof(symbol)));
54
54
  CAPACITY(p) = n;
55
- SIZE(p) = 0;
55
+ SET_SIZE(p, 0);
56
56
  return p;
57
57
  }
58
58
 
59
59
  extern void report_b(FILE * out, const symbol * p) {
60
- int i;
61
- for (i = 0; i < SIZE(p); i++) {
60
+ for (int i = 0; i < SIZE(p); i++) {
62
61
  if (p[i] > 255) {
63
62
  printf("In report_b, can't convert p[%d] to char because it's 0x%02x\n", i, (int)p[i]);
64
63
  exit(1);
@@ -79,14 +78,16 @@ extern void lose_b(symbol * p) {
79
78
  extern symbol * increase_capacity_b(symbol * p, int n) {
80
79
  symbol * q = create_b(CAPACITY(p) + n + EXTENDER);
81
80
  memmove(q, p, CAPACITY(p) * sizeof(symbol));
82
- SIZE(q) = SIZE(p);
81
+ SET_SIZE(q, SIZE(p));
83
82
  lose_b(p); return q;
84
83
  }
85
84
 
86
85
  extern symbol * add_to_b(symbol * p, const symbol * q, int n) {
87
86
  int x = SIZE(p) + n - CAPACITY(p);
88
87
  if (x > 0) p = increase_capacity_b(p, x);
89
- memmove(p + SIZE(p), q, n * sizeof(symbol)); SIZE(p) += n; return p;
88
+ memmove(p + SIZE(p), q, n * sizeof(symbol));
89
+ ADD_TO_SIZE(p, n);
90
+ return p;
90
91
  }
91
92
 
92
93
  extern symbol * copy_b(const symbol * p) {
@@ -113,49 +114,74 @@ extern void * check_malloc(size_t n) {
113
114
  }
114
115
 
115
116
  extern void check_free(void * p) {
116
- space_count--;
117
+ if (p) space_count--;
117
118
  free(p);
118
119
  }
119
120
 
120
- /* To convert a block to a zero terminated string: */
121
+ extern int checked_snprintf(char *str, size_t size,
122
+ const char *restrict format, ...) {
123
+ va_list ap;
124
+ va_start(ap, format);
125
+ int r = vsnprintf(str, size, format, ap);
126
+ va_end(ap);
127
+ // Some pre-C99 snprintf implementations return -1 if the buffer is too
128
+ // small so cast to unsigned for a simpler test (we require C99, but better
129
+ // to be robust if we encounter a C99 compiler with pre-C99 quirks in its
130
+ // runtime library).
131
+ if ((unsigned)r >= size) {
132
+ fprintf(stderr, "snprintf(buf, %zu, \"%s\", ...) would overflow\n",
133
+ size, format);
134
+ exit(1);
135
+ }
136
+ return r;
137
+ }
121
138
 
139
+ /* Convert a block to a zero terminated string. */
122
140
  extern char * b_to_sz(const symbol * p) {
123
141
  int n = SIZE(p);
124
142
  char * s = (char *)xmalloc(n + 1);
125
- {
126
- int i;
127
- for (i = 0; i < n; i++) {
128
- if (p[i] > 255) {
129
- printf("In b_to_s, can't convert p[%d] to char because it's 0x%02x\n", i, (int)p[i]);
130
- exit(1);
131
- }
132
- s[i] = (char)p[i];
143
+ for (int i = 0; i < n; i++) {
144
+ if (p[i] > 255) {
145
+ printf("In b_to_s, can't convert p[%d] to char because it's 0x%02x\n", i, (int)p[i]);
146
+ exit(1);
133
147
  }
148
+ s[i] = (char)p[i];
134
149
  }
135
150
  s[n] = 0;
136
151
  return s;
137
152
  }
138
153
 
139
- /* Add a single symbol to a block. If p = 0 the
140
- block is created. */
141
-
154
+ /* Add a single symbol to a block. If p = 0 the block is created. */
142
155
  extern symbol * add_symbol_to_b(symbol * p, symbol ch) {
143
- int k;
144
156
  if (p == NULL) p = create_b(1);
145
- k = SIZE(p);
146
- {
147
- int x = k + 1 - CAPACITY(p);
148
- if (x > 0) p = increase_capacity_b(p, x);
149
- }
157
+ int k = SIZE(p);
158
+ int x = k + 1 - CAPACITY(p);
159
+ if (x > 0) p = increase_capacity_b(p, x);
150
160
  p[k] = ch;
151
- SIZE(p)++;
161
+ ADD_TO_SIZE(p, 1);
152
162
  return p;
153
163
  }
154
164
 
155
165
  extern byte * create_s(int n) {
156
166
  byte * p = (byte *) (HEAD + (byte *) MALLOC(HEAD + (n + 1)));
157
167
  CAPACITY(p) = n;
158
- SIZE(p) = 0;
168
+ SET_SIZE(p, 0);
169
+ return p;
170
+ }
171
+
172
+ extern byte * create_s_from_sz(const char * s) {
173
+ int n = strlen(s);
174
+ byte * p = create_s(n);
175
+ memcpy(p, s, n + 1);
176
+ SET_SIZE(p, n);
177
+ return p;
178
+ }
179
+
180
+ extern byte * create_s_from_data(const char * s, int n) {
181
+ byte * p = create_s(n);
182
+ memcpy(p, s, n);
183
+ p[n] = '\0';
184
+ SET_SIZE(p, n);
159
185
  return p;
160
186
  }
161
187
 
@@ -169,53 +195,66 @@ extern void lose_s(byte * p) {
169
195
  }
170
196
 
171
197
  extern byte * increase_capacity_s(byte * p, int n) {
172
- byte * q = create_s(CAPACITY(p) + n + EXTENDER);
198
+ int new_size = CAPACITY(p) + n + EXTENDER;
199
+ // Switch to exponential growth for large strings.
200
+ if (new_size > 512) new_size *= 2;
201
+ byte * q = create_s(new_size);
173
202
  memmove(q, p, CAPACITY(p));
174
- SIZE(q) = SIZE(p);
203
+ SET_SIZE(q, SIZE(p));
175
204
  lose_s(p);
176
205
  return q;
177
206
  }
178
207
 
208
+ extern byte * ensure_capacity_s(byte * p, int n) {
209
+ int x = SIZE(p) + n - CAPACITY(p);
210
+ if (x > 0) p = increase_capacity_s(p, x);
211
+ return p;
212
+ }
213
+
179
214
  extern byte * copy_s(const byte * p) {
180
- return add_s_to_s(NULL, (const char*)p, SIZE(p));
215
+ return add_s_to_s(NULL, p);
181
216
  }
182
217
 
183
218
  /* Add a string with given length to a byte block. If p = 0 the
184
219
  block is created. */
185
220
 
186
- extern byte * add_s_to_s(byte * p, const char * s, int n) {
187
- int k;
188
- if (p == NULL) p = create_s(n);
189
- k = SIZE(p);
190
- {
191
- int x = k + n - CAPACITY(p);
192
- if (x > 0) p = increase_capacity_s(p, x);
221
+ extern byte * add_slen_to_s(byte * p, const char * s, int n) {
222
+ if (p == NULL) {
223
+ p = create_s(n);
224
+ } else {
225
+ p = ensure_capacity_s(p, n);
193
226
  }
227
+ int k = SIZE(p);
194
228
  memcpy(p + k, s, n);
195
- SIZE(p) += n;
229
+ SET_SIZE(p, k + n);
196
230
  return p;
197
231
  }
198
232
 
233
+ /* Add a byte block to a byte block. If p = 0 the
234
+ block is created. */
235
+
236
+ extern byte * add_s_to_s(byte * p, const byte * s) {
237
+ return add_slen_to_s(p, (const char *)s, SIZE(s));
238
+ }
239
+
199
240
  /* Add a zero terminated string to a byte block. If p = 0 the
200
241
  block is created. */
201
242
 
202
243
  extern byte * add_sz_to_s(byte * p, const char * s) {
203
- return add_s_to_s(p, s, strlen(s));
244
+ return add_slen_to_s(p, s, strlen(s));
204
245
  }
205
246
 
206
247
  /* Add a single character to a byte block. If p = 0 the
207
248
  block is created. */
208
249
 
209
250
  extern byte * add_char_to_s(byte * p, char ch) {
210
- int k;
211
- if (p == NULL) p = create_s(1);
212
- k = SIZE(p);
213
- {
214
- int x = k + 1 - CAPACITY(p);
215
- if (x > 0) p = increase_capacity_s(p, x);
251
+ if (p == NULL) {
252
+ p = create_s(1);
253
+ } else {
254
+ p = ensure_capacity_s(p, 1);
216
255
  }
217
- p[k] = ch;
218
- SIZE(p)++;
256
+ p[SIZE(p)] = ch;
257
+ ADD_TO_SIZE(p, 1);
219
258
  return p;
220
259
  }
221
260
 
@@ -242,8 +281,7 @@ extern void str_delete(struct str * str) {
242
281
 
243
282
  /* Append a str to this str. */
244
283
  extern void str_append(struct str * str, const struct str * add) {
245
- byte * q = add->data;
246
- str->data = add_s_to_s(str->data, (char *)q, SIZE(q));
284
+ str->data = add_s_to_s(str->data, add->data);
247
285
  }
248
286
 
249
287
  /* Append a character to this str. */
@@ -253,7 +291,7 @@ extern void str_append_ch(struct str * str, char add) {
253
291
 
254
292
  /* Append a low level byte block to a str. */
255
293
  extern void str_append_s(struct str * str, const byte * q) {
256
- str->data = add_s_to_s(str->data, (const char *)q, SIZE(q));
294
+ str->data = add_s_to_s(str->data, q);
257
295
  }
258
296
 
259
297
  /* Append a (char *, null terminated) string to a str. */
@@ -263,9 +301,18 @@ extern void str_append_string(struct str * str, const char * s) {
263
301
 
264
302
  /* Append an integer to a str. */
265
303
  extern void str_append_int(struct str * str, int i) {
266
- char s[30];
267
- sprintf(s, "%d", i);
268
- str_append_string(str, s);
304
+ // Most calls are for integers 0 to 9 (~72%).
305
+ if (i >= 0 && i <= 9) {
306
+ str_append_ch(str, '0' + i);
307
+ return;
308
+ }
309
+
310
+ // Ensure there's enough space then snprintf() directly onto the end.
311
+ int max_size = (CHAR_BIT * sizeof(int) + 5) / 3;
312
+ str->data = ensure_capacity_s(str->data, max_size);
313
+ int r = checked_snprintf((char*)str->data + SIZE(str->data), max_size,
314
+ "%d", i);
315
+ ADD_TO_SIZE(str->data, r);
269
316
  }
270
317
 
271
318
  /* Append wide character to a string as UTF-8. */
@@ -286,7 +333,7 @@ extern void str_append_wchar_as_utf8(struct str * str, symbol ch) {
286
333
 
287
334
  /* Clear a string */
288
335
  extern void str_clear(struct str * str) {
289
- SIZE(str->data) = 0;
336
+ SET_SIZE(str->data, 0);
290
337
  }
291
338
 
292
339
  /* Set a string */
@@ -325,16 +372,27 @@ extern int str_back(const struct str *str) {
325
372
  * Or do nothing if the string is empty.
326
373
  */
327
374
  extern void str_pop(const struct str *str) {
328
- if (SIZE(str->data)) --SIZE(str->data);
375
+ if (SIZE(str->data)) ADD_TO_SIZE(str->data, -1);
376
+ }
377
+
378
+ /* Remove the last n characters of the str.
379
+ *
380
+ * Or make the string empty if its length is less than n.
381
+ */
382
+ extern void str_pop_n(const struct str *str, int n) {
383
+ if (SIZE(str->data) > n) {
384
+ ADD_TO_SIZE(str->data, -n);
385
+ } else {
386
+ SET_SIZE(str->data, 0);
387
+ }
329
388
  }
330
389
 
331
390
  extern int get_utf8(const symbol * p, int * slot) {
332
- int b0, b1;
333
- b0 = *p++;
391
+ int b0 = *p++;
334
392
  if (b0 < 0xC0) { /* 1100 0000 */
335
393
  * slot = b0; return 1;
336
394
  }
337
- b1 = *p++;
395
+ int b1 = *p++;
338
396
  if (b0 < 0xE0) { /* 1110 0000 */
339
397
  * slot = (b0 & 0x1F) << 6 | (b1 & 0x3F); return 2;
340
398
  }