rmultimarkdown 6.2.2.1 → 6.4.0.1

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/ext/Makefile +2 -2
  3. data/ext/mmd/aho-corasick.c +12 -8
  4. data/ext/mmd/beamer.c +29 -0
  5. data/ext/mmd/critic_markup.c +100 -4
  6. data/ext/mmd/critic_markup.h +7 -0
  7. data/ext/mmd/d_string.c +502 -119
  8. data/ext/mmd/epub.c +2 -4
  9. data/ext/mmd/file.c +436 -0
  10. data/ext/mmd/file.h +153 -0
  11. data/ext/mmd/html.c +130 -37
  12. data/ext/mmd/include/d_string.h +20 -19
  13. data/ext/mmd/include/libMultiMarkdown.h +42 -27
  14. data/ext/mmd/include/token.h +15 -15
  15. data/ext/mmd/latex.c +107 -30
  16. data/ext/mmd/lexer.c +19 -7
  17. data/ext/mmd/lexer.h +2 -2
  18. data/ext/mmd/memoir.c +29 -0
  19. data/ext/mmd/mmd.c +65 -39
  20. data/ext/mmd/object_pool.h +4 -4
  21. data/ext/mmd/opendocument-content.c +95 -13
  22. data/ext/mmd/opendocument.c +315 -313
  23. data/ext/mmd/opml-lexer.c +2183 -0
  24. data/ext/mmd/opml-lexer.h +157 -0
  25. data/ext/mmd/opml-parser.c +1193 -0
  26. data/ext/mmd/opml-parser.h +15 -0
  27. data/ext/mmd/opml-reader.c +435 -0
  28. data/ext/mmd/opml-reader.h +111 -0
  29. data/ext/mmd/opml.c +511 -0
  30. data/ext/mmd/opml.h +115 -0
  31. data/ext/mmd/parser.c +2 -0
  32. data/ext/mmd/rng.c +1 -1
  33. data/ext/mmd/scanners.c +51663 -24824
  34. data/ext/mmd/stack.c +4 -2
  35. data/ext/mmd/stack.h +8 -8
  36. data/ext/mmd/textbundle.c +2 -4
  37. data/ext/mmd/token.c +24 -12
  38. data/ext/mmd/token_pairs.c +2 -2
  39. data/ext/mmd/token_pairs.h +10 -10
  40. data/ext/mmd/transclude.c +1 -226
  41. data/ext/mmd/transclude.h +0 -8
  42. data/ext/mmd/uuid.c +3 -3
  43. data/ext/mmd/version.h +3 -3
  44. data/ext/mmd/writer.c +99 -30
  45. data/ext/mmd/writer.h +11 -0
  46. data/lib/multi_markdown.bundle +0 -0
  47. data/lib/multi_markdown/version.rb +1 -1
  48. metadata +13 -5
  49. data/ext/mmd/fodt.c +0 -2288
  50. data/ext/mmd/fodt.h +0 -81
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4f0aaf2e4578f029b57651048a9fe007addc2b7e
4
- data.tar.gz: 533529a83e637367139cd68245606400262d0296
3
+ metadata.gz: 1014dc60ab5f2b6f2a75676afb5277d454d85375
4
+ data.tar.gz: 95e5652fde10146a1b110674ae68065bd4967420
5
5
  SHA512:
6
- metadata.gz: 615409a10996e6a2720369e7b301cc07e24832b974944d73e899639c5cfb7c212aff6bcfd49247b1cf3625269e13f212e2142acd4f0c8d4a6f92e27c978a2e18
7
- data.tar.gz: b0a4b8f9e386eb5d9c0fe6581e27a5a1642c54a38462cb0ebc3dacb358ac7fab7892dca4330d7627c50b333458072844a3272e6464a5568b1f3ce2e6ca31470c
6
+ metadata.gz: 180941d10b28d4062792e8b1b448c2c3948969859f9e7f8aeab2f23f55e5d3c27eb3f7537c240fad3cc6f103431f14f6e1446ba63b7af1ed38e9d9eeff08d077
7
+ data.tar.gz: ffb6e4b40683fa51fc47673d2df9ab4716a9dc1d37f43a6670bb260abec10b9559ba56b2f3dbf5fcf08a29fcf92b0dfcc497af6098058d86fe51137b12102b2b
@@ -136,8 +136,8 @@ target_prefix =
136
136
  LOCAL_LIBS =
137
137
  LIBS = -lpthread -lgmp -ldl -lobjc
138
138
  ORIG_SRCS = ruby_multi_markdown.c
139
- SRCS = $(ORIG_SRCS) aho-corasick.c beamer.c char.c char_lookup.c critic_markup.c d_string.c epub.c fodt.c html.c latex.c lexer.c memoir.c miniz.c mmd.c object_pool.c opendocument-content.c opendocument.c parser.c rng.c scanners.c stack.c textbundle.c token.c token_pairs.c transclude.c uuid.c writer.c zip.c ruby_multi_markdown.c
140
- OBJS = mmd/aho-corasick.o mmd/beamer.o mmd/char.o mmd/char_lookup.o mmd/critic_markup.o mmd/d_string.o mmd/epub.o mmd/fodt.o mmd/html.o mmd/latex.o mmd/lexer.o mmd/memoir.o mmd/miniz.o mmd/mmd.o mmd/object_pool.o mmd/opendocument-content.o mmd/opendocument.o mmd/parser.o mmd/rng.o mmd/scanners.o mmd/stack.o mmd/textbundle.o mmd/token.o mmd/token_pairs.o mmd/transclude.o mmd/uuid.o mmd/writer.o mmd/zip.o ruby_multi_markdown.o
139
+ SRCS = $(ORIG_SRCS) memoir.c object_pool.c char_lookup.c textbundle.c miniz.c char.c writer.c beamer.c latex.c stack.c zip.c opendocument.c d_string.c lexer.c token.c transclude.c aho-corasick.c mmd.c uuid.c opml-reader.c html.c epub.c file.c critic_markup.c scanners.c opml-lexer.c parser.c opendocument-content.c opml-parser.c opml.c token_pairs.c rng.c ruby_multi_markdown.c
140
+ OBJS = mmd/memoir.o mmd/object_pool.o mmd/char_lookup.o mmd/textbundle.o mmd/miniz.o mmd/char.o mmd/writer.o mmd/beamer.o mmd/latex.o mmd/stack.o mmd/zip.o mmd/opendocument.o mmd/d_string.o mmd/lexer.o mmd/token.o mmd/transclude.o mmd/aho-corasick.o mmd/mmd.o mmd/uuid.o mmd/opml-reader.o mmd/html.o mmd/epub.o mmd/file.o mmd/critic_markup.o mmd/scanners.o mmd/opml-lexer.o mmd/parser.o mmd/opendocument-content.o mmd/opml-parser.o mmd/opml.o mmd/token_pairs.o mmd/rng.o ruby_multi_markdown.o
141
141
  HDRS = $(srcdir)/extconf.h
142
142
  TARGET = multi_markdown
143
143
  TARGET_NAME = multi_markdown
@@ -285,7 +285,7 @@ void ac_trie_node_prepare(trie * a, size_t s, char * buffer, unsigned short dept
285
285
  // Prepare children
286
286
  for (int i = 0; i < 256; ++i) {
287
287
  if ((n->child[i] != 0) &&
288
- (n->child[i] != s)) {
288
+ (n->child[i] != s)) {
289
289
  buffer[depth] = i;
290
290
 
291
291
  ac_trie_node_prepare(a, n->child[i], buffer, depth + 1, last_match_state);
@@ -403,7 +403,7 @@ match * ac_trie_search(trie * a, const char * source, size_t start, size_t len)
403
403
  }
404
404
 
405
405
  m = match_add(m, counter - a->node[temp_state].len,
406
- a->node[temp_state].len, a->node[temp_state].match_type);
406
+ a->node[temp_state].len, a->node[temp_state].match_type);
407
407
  }
408
408
 
409
409
  // Iterate to find shorter matches
@@ -445,7 +445,7 @@ int match_count(match * m) {
445
445
 
446
446
  void match_describe(match * m, const char * source) {
447
447
  fprintf(stderr, "'%.*s'(%d) at %lu:%lu\n", (int)m->len, &source[m->start],
448
- m->match_type, m->start, m->start + m->len);
448
+ m->match_type, m->start, m->start + m->len);
449
449
  }
450
450
 
451
451
 
@@ -475,14 +475,16 @@ void match_set_filter_leftmost_longest(match * header) {
475
475
  }
476
476
 
477
477
  while (m->next &&
478
- m->next->start > m->start &&
479
- m->next->start < m->start + m->len) {
478
+ m->next->start > m->start &&
479
+ m->next->start < m->start + m->len) {
480
480
  // This match is "lefter" than next
481
+ #ifndef __clang_analyzer__
481
482
  match_excise(m->next);
483
+ #endif
482
484
  }
483
485
 
484
486
  while (m->next &&
485
- m->next->start < m->start) {
487
+ m->next->start < m->start) {
486
488
  // Next match is "lefter" than us
487
489
  n = m;
488
490
  m = m->prev;
@@ -491,11 +493,13 @@ void match_set_filter_leftmost_longest(match * header) {
491
493
  }
492
494
 
493
495
  while (m->prev &&
494
- m->prev->len &&
495
- m->prev->start >= m->start) {
496
+ m->prev->len &&
497
+ m->prev->start >= m->start) {
496
498
  // We are "lefter" than previous
497
499
  n = m->prev;
500
+ #ifndef __clang_analyzer__
498
501
  match_excise(n);
502
+ #endif
499
503
  }
500
504
 
501
505
  m = m->next;
@@ -55,6 +55,7 @@
55
55
 
56
56
  #include "latex.h"
57
57
  #include "beamer.h"
58
+ #include "parser.h"
58
59
 
59
60
  #define print(x) d_string_append(out, x)
60
61
  #define print_const(x) d_string_append_c_array(out, x, sizeof(x) - 1)
@@ -173,6 +174,33 @@ void mmd_export_token_beamer(DString * out, const char * source, token * t, scra
173
174
  temp_char = get_fence_language_specifier(t->child->child, source);
174
175
 
175
176
  if (temp_char) {
177
+ if (strncmp("{=", temp_char, 2) == 0) {
178
+ // Raw source
179
+ if (raw_filter_text_matches(temp_char, FORMAT_BEAMER)) {
180
+ switch (t->child->tail->type) {
181
+ case LINE_FENCE_BACKTICK_3:
182
+ case LINE_FENCE_BACKTICK_4:
183
+ case LINE_FENCE_BACKTICK_5:
184
+ temp_token = t->child->tail;
185
+ break;
186
+
187
+ default:
188
+ temp_token = NULL;
189
+ }
190
+
191
+ if (temp_token) {
192
+ d_string_append_c_array(out, &source[t->child->next->start], temp_token->start - t->child->next->start);
193
+ scratch->padded = 1;
194
+ } else {
195
+ d_string_append_c_array(out, &source[t->child->start + t->child->len], t->start + t->len - t->child->next->start);
196
+ scratch->padded = 0;
197
+ }
198
+ }
199
+
200
+ free(temp_char);
201
+ break;
202
+ }
203
+
176
204
  printf("\\begin{lstlisting}[language=%s]\n", temp_char);
177
205
  } else {
178
206
  print_const("\\begin{verbatim}\n");
@@ -242,6 +270,7 @@ void mmd_export_token_beamer(DString * out, const char * source, token * t, scra
242
270
  }
243
271
 
244
272
  mmd_export_token_tree_beamer(out, source, t->child, scratch);
273
+ trim_trailing_whitespace_d_string(out);
245
274
 
246
275
  if (scratch->extensions & EXT_NO_LABELS) {
247
276
  print_const("}");
@@ -191,6 +191,8 @@ void accept_token(DString * d, token * t) {
191
191
  case CM_SUB_OPEN:
192
192
  case CM_ADD_OPEN:
193
193
  case CM_ADD_CLOSE:
194
+ case CM_HI_OPEN:
195
+ case CM_HI_CLOSE:
194
196
  if (!t->mate) {
195
197
  break;
196
198
  }
@@ -233,8 +235,9 @@ void accept_token_tree(DString * d, token * t) {
233
235
  }
234
236
  }
235
237
 
236
- void mmd_critic_markup_accept(DString * d) {
237
- token * t = critic_parse_substring(d->str, 0, d->currentStringLength);
238
+
239
+ void mmd_critic_markup_accept_range(DString * d, size_t start, size_t len) {
240
+ token * t = critic_parse_substring(d->str, start, len);
238
241
 
239
242
  if (t && t->child) {
240
243
  accept_token_tree(d, t->child->tail);
@@ -244,6 +247,11 @@ void mmd_critic_markup_accept(DString * d) {
244
247
  }
245
248
 
246
249
 
250
+ void mmd_critic_markup_accept(DString * d) {
251
+ mmd_critic_markup_accept_range(d, 0, d->currentStringLength);
252
+ }
253
+
254
+
247
255
  void reject_token_tree(DString * d, token * t);
248
256
  void reject_token(DString * d, token * t);
249
257
 
@@ -275,6 +283,8 @@ void reject_token(DString * d, token * t) {
275
283
  case CM_SUB_OPEN:
276
284
  case CM_DEL_OPEN:
277
285
  case CM_DEL_CLOSE:
286
+ case CM_HI_OPEN:
287
+ case CM_HI_CLOSE:
278
288
  if (!t->mate) {
279
289
  break;
280
290
  }
@@ -317,8 +327,9 @@ void reject_token_tree(DString * d, token * t) {
317
327
  }
318
328
  }
319
329
 
320
- void mmd_critic_markup_reject(DString * d) {
321
- token * t = critic_parse_substring(d->str, 0, d->currentStringLength);
330
+
331
+ void mmd_critic_markup_reject_range(DString * d, size_t start, size_t len) {
332
+ token * t = critic_parse_substring(d->str, start, len);
322
333
 
323
334
  if (t && t->child) {
324
335
  reject_token_tree(d, t->child->tail);
@@ -328,3 +339,88 @@ void mmd_critic_markup_reject(DString * d) {
328
339
 
329
340
  }
330
341
 
342
+
343
+ void mmd_critic_markup_reject(DString * d) {
344
+ mmd_critic_markup_reject_range(d, 0, d->currentStringLength);
345
+ }
346
+
347
+
348
+ #ifdef TEST
349
+ void Test_critic(CuTest* tc) {
350
+ #ifdef kUseObjectPool
351
+ token_pool_init();
352
+ #endif
353
+
354
+ DString * test = d_string_new("{--foo bar--}");
355
+ mmd_critic_markup_reject(test);
356
+ CuAssertStrEquals(tc, "foo bar", test->str);
357
+
358
+ d_string_erase(test, 0, -1);
359
+ d_string_append(test, "{++foo bar++}");
360
+ mmd_critic_markup_reject(test);
361
+ CuAssertStrEquals(tc, "", test->str);
362
+
363
+
364
+ d_string_erase(test, 0, -1);
365
+ d_string_append(test, "{--foo bar--}");
366
+ mmd_critic_markup_accept(test);
367
+ CuAssertStrEquals(tc, "", test->str);
368
+
369
+ d_string_erase(test, 0, -1);
370
+ d_string_append(test, "{++foo bar++}");
371
+ mmd_critic_markup_accept(test);
372
+ CuAssertStrEquals(tc, "foo bar", test->str);
373
+
374
+ d_string_erase(test, 0, -1);
375
+ d_string_append(test, "{++foo{--bat--}bar++}");
376
+ mmd_critic_markup_accept(test);
377
+ CuAssertStrEquals(tc, "foobar", test->str);
378
+
379
+ d_string_erase(test, 0, -1);
380
+ d_string_append(test, "{--foo{-- bat --}bar--}");
381
+ mmd_critic_markup_reject(test);
382
+ CuAssertStrEquals(tc, "foo bat bar", test->str);
383
+
384
+ d_string_erase(test, 0, -1);
385
+ d_string_append(test, "{--foo{++ bat ++}bar--}");
386
+ mmd_critic_markup_reject(test);
387
+ CuAssertStrEquals(tc, "foobar", test->str);
388
+
389
+ d_string_erase(test, 0, -1);
390
+ d_string_append(test, "{==foo bar==}");
391
+ mmd_critic_markup_reject(test);
392
+ CuAssertStrEquals(tc, "foo bar", test->str);
393
+
394
+ d_string_erase(test, 0, -1);
395
+ d_string_append(test, "{==foo bar==}");
396
+ mmd_critic_markup_accept(test);
397
+ CuAssertStrEquals(tc, "foo bar", test->str);
398
+
399
+ d_string_erase(test, 0, -1);
400
+ d_string_append(test, "{>>foo bar<<}");
401
+ mmd_critic_markup_reject(test);
402
+ CuAssertStrEquals(tc, "", test->str);
403
+
404
+ d_string_erase(test, 0, -1);
405
+ d_string_append(test, "{>>foo bar<<}");
406
+ mmd_critic_markup_accept(test);
407
+ CuAssertStrEquals(tc, "", test->str);
408
+
409
+ d_string_erase(test, 0, -1);
410
+ d_string_append(test, "{++foo++}{>>bar<<}");
411
+ mmd_critic_markup_accept(test);
412
+ CuAssertStrEquals(tc, "foo", test->str);
413
+
414
+ d_string_erase(test, 0, -1);
415
+ d_string_append(test, "{++foo++}{>>bar<<}");
416
+ mmd_critic_markup_reject(test);
417
+ CuAssertStrEquals(tc, "", test->str);
418
+
419
+ #ifdef kUseObjectPool
420
+ // Decrement counter and clean up token pool
421
+ token_pool_drain();
422
+
423
+ token_pool_free();
424
+ #endif
425
+ }
426
+ #endif
@@ -60,6 +60,11 @@
60
60
 
61
61
  #include "d_string.h"
62
62
 
63
+ #ifdef TEST
64
+ #include "CuTest.h"
65
+ #endif
66
+
67
+
63
68
  enum cm_types {
64
69
  CM_ADD_OPEN = 1, // Can't use type 0
65
70
  CM_ADD_CLOSE,
@@ -88,7 +93,9 @@ enum cm_types {
88
93
 
89
94
 
90
95
  void mmd_critic_markup_accept(DString * d);
96
+ void mmd_critic_markup_accept_range(DString * d, size_t start, size_t len);
91
97
 
92
98
  void mmd_critic_markup_reject(DString * d);
99
+ void mmd_critic_markup_reject_range(DString * d, size_t start, size_t len);
93
100
 
94
101
  #endif
@@ -17,7 +17,7 @@
17
17
  /*
18
18
 
19
19
  Copyright © 2011 Daniel Jalkut.
20
- Modifications by Fletcher T. Penney, Copyright © 2011-2017 Fletcher T. Penney.
20
+ Modifications by Fletcher T. Penney, Copyright © 2011-2018 Fletcher T. Penney.
21
21
  Modifications by Dan Lowe, Copyright © 2011 Dan Lowe.
22
22
 
23
23
 
@@ -64,6 +64,10 @@
64
64
 
65
65
  #include "d_string.h"
66
66
 
67
+ #ifdef TEST
68
+ #include "CuTest.h"
69
+ #endif
70
+
67
71
 
68
72
  /*
69
73
  * The following section came from:
@@ -145,6 +149,31 @@ DString* d_string_new(const char * startingString) {
145
149
  }
146
150
 
147
151
 
152
+ #ifdef TEST
153
+ void Test_d_string_new(CuTest* tc) {
154
+ char * test = "foo";
155
+
156
+ DString * result = d_string_new(test);
157
+
158
+ CuAssertIntEquals(tc, 3, result->currentStringLength);
159
+ CuAssertIntEquals(tc, kStringBufferStartingSize, result->currentStringBufferSize);
160
+ CuAssertStrEquals(tc, test, result->str);
161
+ CuAssertIntEquals(tc, '\0', result->str[strlen(test)]);
162
+
163
+ d_string_free(result, true);
164
+
165
+ result = d_string_new(NULL);
166
+
167
+ CuAssertIntEquals(tc, 0, result->currentStringLength);
168
+ CuAssertIntEquals(tc, kStringBufferStartingSize, result->currentStringBufferSize);
169
+ CuAssertStrEquals(tc, "", result->str);
170
+ CuAssertIntEquals(tc, '\0', 0);
171
+
172
+ d_string_free(result, true);
173
+ }
174
+ #endif
175
+
176
+
148
177
  /// Free dynamic string
149
178
  char* d_string_free(DString * ripString, bool freeCharacterData) {
150
179
  if (ripString == NULL) {
@@ -169,234 +198,588 @@ char* d_string_free(DString * ripString, bool freeCharacterData) {
169
198
 
170
199
  /// Ensure that dynamic string has specified capacity
171
200
  static void ensureStringBufferCanHold(DString * baseString, size_t newStringSize) {
172
- size_t newBufferSizeNeeded = newStringSize + 1;
201
+ if (baseString) {
202
+ size_t newBufferSizeNeeded = newStringSize + 1;
203
+
204
+ if (newBufferSizeNeeded > baseString->currentStringBufferSize) {
205
+ size_t newBufferSize = baseString->currentStringBufferSize;
206
+
207
+ while (newBufferSizeNeeded > newBufferSize) {
208
+ if (newBufferSize > kStringBufferMaxIncrement) {
209
+ newBufferSize += kStringBufferMaxIncrement;
210
+ } else {
211
+ newBufferSize *= kStringBufferGrowthMultiplier;
212
+ }
213
+ }
173
214
 
174
- if (newBufferSizeNeeded > baseString->currentStringBufferSize) {
175
- size_t newBufferSize = baseString->currentStringBufferSize;
215
+ char *temp;
216
+ temp = realloc(baseString->str, newBufferSize);
176
217
 
177
- while (newBufferSizeNeeded > newBufferSize) {
178
- if (newBufferSize > kStringBufferMaxIncrement) {
179
- newBufferSize += kStringBufferMaxIncrement;
180
- } else {
181
- newBufferSize *= kStringBufferGrowthMultiplier;
218
+ if (temp == NULL) {
219
+ /* realloc failed */
220
+ fprintf(stderr, "Error reallocating memory for d_string. Current buffer size %lu.\n", baseString->currentStringBufferSize);
221
+
222
+ exit(1);
182
223
  }
224
+
225
+ baseString->str = temp;
226
+ baseString->currentStringBufferSize = newBufferSize;
183
227
  }
228
+ }
229
+ }
184
230
 
185
- char *temp;
186
- temp = realloc(baseString->str, newBufferSize);
187
231
 
188
- if (temp == NULL) {
189
- /* realloc failed */
190
- fprintf(stderr, "Error reallocating memory for d_string. Current buffer size %lu.\n", baseString->currentStringBufferSize);
232
+ #ifdef TEST
233
+ void Test_ensureStringBufferCanHold(CuTest* tc) {
234
+ char * test = "foo";
191
235
 
192
- exit(1);
193
- }
236
+ DString * result = d_string_new(test);
194
237
 
195
- baseString->str = temp;
196
- baseString->currentStringBufferSize = newBufferSize;
197
- }
238
+ ensureStringBufferCanHold(result, 1024);
239
+ CuAssertIntEquals(tc, 2048, result->currentStringBufferSize);
240
+
241
+ ensureStringBufferCanHold(result, 1024);
242
+ CuAssertIntEquals(tc, 2048, result->currentStringBufferSize);
243
+
244
+ /* This becomes 0 after we add 1 for the '\0' */
245
+ ensureStringBufferCanHold(result, -1);
246
+ CuAssertIntEquals(tc, 2048, result->currentStringBufferSize);
247
+
248
+ ensureStringBufferCanHold(result, 1024 * 1024 - 1);
249
+ CuAssertIntEquals(tc, 1024 * 1024, result->currentStringBufferSize);
250
+
251
+ ensureStringBufferCanHold(result, 1024 * 1024 - 1);
252
+ CuAssertIntEquals(tc, 1024 * 1024, result->currentStringBufferSize);
253
+
254
+ ensureStringBufferCanHold(NULL, 1024);
255
+
256
+ d_string_free(result, true);
198
257
  }
258
+ #endif
199
259
 
200
260
 
201
261
  /// Append null-terminated string to end of dynamic string
202
262
  void d_string_append(DString * baseString, const char * appendedString) {
203
- size_t appendedStringLength = strlen(appendedString);
263
+ if (baseString && appendedString) {
264
+ size_t appendedStringLength = strlen(appendedString);
204
265
 
205
- if ((appendedString != NULL) && (appendedStringLength > 0)) {
206
- size_t newStringLength = baseString->currentStringLength + appendedStringLength;
207
- ensureStringBufferCanHold(baseString, newStringLength);
266
+ if (appendedStringLength > 0) {
267
+ size_t newStringLength = baseString->currentStringLength + appendedStringLength;
268
+ ensureStringBufferCanHold(baseString, newStringLength);
208
269
 
209
- /* We already know where the current string ends, so pass that as the starting address for strncat */
210
- strncat(baseString->str + baseString->currentStringLength, appendedString, appendedStringLength);
211
- baseString->currentStringLength = newStringLength;
270
+ /* We already know where the current string ends, so pass that as the starting address for strncat */
271
+ strncat(baseString->str + baseString->currentStringLength, appendedString, appendedStringLength);
272
+ baseString->currentStringLength = newStringLength;
273
+ }
212
274
  }
213
275
  }
214
276
 
215
277
 
278
+ #ifdef TEST
279
+ void Test_d_string_append(CuTest* tc) {
280
+ char * test = "foo";
281
+
282
+ DString * result = d_string_new(test);
283
+
284
+ d_string_append(result, "bar");
285
+ CuAssertStrEquals(tc, "foobar", result->str);
286
+
287
+ d_string_append(result, "");
288
+ CuAssertStrEquals(tc, "foobar", result->str);
289
+
290
+ d_string_append(result, NULL);
291
+ CuAssertStrEquals(tc, "foobar", result->str);
292
+
293
+ d_string_append(NULL, "foo");
294
+
295
+ d_string_free(result, true);
296
+ }
297
+ #endif
298
+
299
+
216
300
  /// Append single character to end of dynamic string
217
301
  void d_string_append_c(DString * baseString, char appendedCharacter) {
218
- size_t newSizeNeeded = baseString->currentStringLength + 1;
219
- ensureStringBufferCanHold(baseString, newSizeNeeded);
302
+ if (baseString && appendedCharacter) {
303
+ size_t newSizeNeeded = baseString->currentStringLength + 1;
304
+ ensureStringBufferCanHold(baseString, newSizeNeeded);
220
305
 
221
- baseString->str[baseString->currentStringLength] = appendedCharacter;
222
- baseString->currentStringLength++;
223
- baseString->str[baseString->currentStringLength] = '\0';
306
+ baseString->str[baseString->currentStringLength] = appendedCharacter;
307
+ baseString->currentStringLength++;
308
+ baseString->str[baseString->currentStringLength] = '\0';
309
+ }
224
310
  }
225
311
 
226
312
 
313
+ #ifdef TEST
314
+ void Test_d_string_append_c(CuTest* tc) {
315
+ char * test = "foo";
316
+
317
+ DString * result = d_string_new(test);
318
+
319
+ d_string_append_c(result, 'z');
320
+ CuAssertStrEquals(tc, "fooz", result->str);
321
+ CuAssertIntEquals(tc, 4, result->currentStringLength);
322
+
323
+ d_string_append_c(result, 0);
324
+ CuAssertStrEquals(tc, "fooz", result->str);
325
+ CuAssertIntEquals(tc, 4, result->currentStringLength);
326
+
327
+ d_string_append_c(NULL, 'f');
328
+
329
+ d_string_free(result, true);
330
+ }
331
+ #endif
332
+
333
+
227
334
  /// Append array of characters to end of dynamic string
228
335
  void d_string_append_c_array(DString * baseString, const char * appendedChars, size_t bytes) {
229
- size_t newSizeNeeded = baseString->currentStringLength + bytes;
230
- ensureStringBufferCanHold(baseString, newSizeNeeded);
336
+ if (baseString && appendedChars) {
337
+ if (bytes == -1) {
338
+ // This is the same as regular append
339
+ d_string_append(baseString, appendedChars);
340
+ } else {
341
+ if (appendedChars) {
342
+ size_t newSizeNeeded = baseString->currentStringLength + bytes;
343
+ ensureStringBufferCanHold(baseString, newSizeNeeded);
344
+
345
+ memcpy(baseString->str + baseString->currentStringLength, appendedChars, bytes);
346
+
347
+ baseString->currentStringLength = newSizeNeeded;
348
+ baseString->str[baseString->currentStringLength] = '\0';
349
+ }
350
+ }
351
+ }
352
+ }
353
+
354
+
355
+ #ifdef TEST
356
+ void Test_d_string_append_c_array(CuTest* tc) {
357
+ char * test = "foo";
358
+
359
+ DString * result = d_string_new(test);
231
360
 
232
- memcpy(baseString->str + baseString->currentStringLength, appendedChars, bytes);
361
+ d_string_append_c_array(result, "bar", 3);
362
+ CuAssertStrEquals(tc, "foobar", result->str);
363
+ CuAssertIntEquals(tc, 6, result->currentStringLength);
233
364
 
234
- baseString->currentStringLength = newSizeNeeded;
235
- baseString->str[baseString->currentStringLength] = '\0';
365
+ d_string_append_c_array(result, "baz", -1);
366
+ CuAssertStrEquals(tc, "foobarbaz", result->str);
367
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
368
+
369
+ d_string_append_c_array(result, NULL, 0);
370
+ CuAssertStrEquals(tc, "foobarbaz", result->str);
371
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
372
+
373
+ d_string_append_c_array(result, NULL, -1);
374
+ CuAssertStrEquals(tc, "foobarbaz", result->str);
375
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
376
+
377
+ d_string_append_c_array(NULL, "foo", -1);
378
+
379
+ d_string_free(result, true);
236
380
  }
381
+ #endif
237
382
 
238
383
 
239
384
  /// Append to end of dynamic string using format specifier
240
385
  void d_string_append_printf(DString * baseString, const char * format, ...) {
241
- va_list args;
242
- va_start(args, format);
386
+ if (baseString && format) {
387
+ va_list args;
388
+ va_start(args, format);
389
+
390
+ char* formattedString = NULL;
391
+ vasprintf(&formattedString, format, args);
243
392
 
244
- char* formattedString = NULL;
245
- vasprintf(&formattedString, format, args);
393
+ if (formattedString != NULL) {
394
+ d_string_append(baseString, formattedString);
395
+ free(formattedString);
396
+ }
246
397
 
247
- if (formattedString != NULL) {
248
- d_string_append(baseString, formattedString);
249
- free(formattedString);
398
+ va_end(args);
250
399
  }
400
+ }
401
+
402
+
403
+ #ifdef TEST
404
+ void Test_d_string_append_printf(CuTest* tc) {
405
+ char * test = "foo";
406
+
407
+ DString * result = d_string_new(test);
251
408
 
252
- va_end(args);
409
+ d_string_append_printf(result, "%dbar%d", 5, 7);
410
+ CuAssertStrEquals(tc, "foo5bar7", result->str);
411
+ CuAssertIntEquals(tc, 8, result->currentStringLength);
412
+
413
+ d_string_append_printf(result, NULL);
414
+ CuAssertStrEquals(tc, "foo5bar7", result->str);
415
+ CuAssertIntEquals(tc, 8, result->currentStringLength);
416
+
417
+ d_string_append_printf(result, NULL, 5, 7);
418
+ CuAssertStrEquals(tc, "foo5bar7", result->str);
419
+ CuAssertIntEquals(tc, 8, result->currentStringLength);
420
+
421
+ d_string_append_printf(NULL, "foo");
422
+
423
+ d_string_free(result, true);
253
424
  }
425
+ #endif
254
426
 
255
427
 
256
428
  /// Prepend null-terminated string to end of dynamic string
257
429
  void d_string_prepend(DString * baseString, const char * prependedString) {
258
- size_t prependedStringLength = strlen(prependedString);
430
+ if (baseString && prependedString) {
431
+ size_t prependedStringLength = strlen(prependedString);
259
432
 
260
- if ((prependedString != NULL) && (prependedStringLength > 0)) {
261
- size_t newStringLength = baseString->currentStringLength + prependedStringLength;
262
- ensureStringBufferCanHold(baseString, newStringLength);
433
+ if (prependedStringLength > 0) {
434
+ size_t newStringLength = baseString->currentStringLength + prependedStringLength;
435
+ ensureStringBufferCanHold(baseString, newStringLength);
263
436
 
264
- memmove(baseString->str + prependedStringLength, baseString->str, baseString->currentStringLength);
265
- strncpy(baseString->str, prependedString, prependedStringLength);
266
- baseString->currentStringLength = newStringLength;
267
- baseString->str[baseString->currentStringLength] = '\0';
437
+ memmove(baseString->str + prependedStringLength, baseString->str, baseString->currentStringLength);
438
+ strncpy(baseString->str, prependedString, prependedStringLength);
439
+ baseString->currentStringLength = newStringLength;
440
+ baseString->str[baseString->currentStringLength] = '\0';
441
+ }
268
442
  }
269
443
  }
270
444
 
271
445
 
446
+ #ifdef TEST
447
+ void Test_d_string_prepend(CuTest* tc) {
448
+ char * test = "foo";
449
+
450
+ DString * result = d_string_new(test);
451
+
452
+ d_string_prepend(result, "bar");
453
+ CuAssertStrEquals(tc, "barfoo", result->str);
454
+ CuAssertIntEquals(tc, 6, result->currentStringLength);
455
+
456
+ d_string_prepend(result, NULL);
457
+ CuAssertStrEquals(tc, "barfoo", result->str);
458
+ CuAssertIntEquals(tc, 6, result->currentStringLength);
459
+
460
+ d_string_prepend(NULL, "bar");
461
+
462
+ d_string_free(result, true);
463
+ }
464
+ #endif
465
+
466
+
272
467
  /// Insert null-terminated string inside dynamic string
273
468
  void d_string_insert(DString * baseString, size_t pos, const char * insertedString) {
274
- size_t insertedStringLength = strlen(insertedString);
469
+ if (baseString && insertedString) {
470
+ size_t insertedStringLength = strlen(insertedString);
471
+
472
+ if (insertedStringLength > 0) {
473
+ if (pos > baseString->currentStringLength) {
474
+ pos = baseString->currentStringLength;
475
+ }
476
+
477
+ size_t newStringLength = baseString->currentStringLength + insertedStringLength;
478
+ ensureStringBufferCanHold(baseString, newStringLength);
275
479
 
276
- if ((insertedString != NULL) && (insertedStringLength > 0)) {
480
+ /* Shift following string to 'right' */
481
+ memmove(baseString->str + pos + insertedStringLength, baseString->str + pos, baseString->currentStringLength - pos);
482
+ strncpy(baseString->str + pos, insertedString, insertedStringLength);
483
+ baseString->currentStringLength = newStringLength;
484
+ baseString->str[baseString->currentStringLength] = '\0';
485
+ }
486
+ }
487
+ }
488
+
489
+
490
+ #ifdef TEST
491
+ void Test_d_string_insert(CuTest* tc) {
492
+ char * test = "foo";
493
+
494
+ DString * result = d_string_new(test);
495
+
496
+ d_string_insert(result, 2, "bar");
497
+ CuAssertStrEquals(tc, "fobaro", result->str);
498
+ CuAssertIntEquals(tc, 6, result->currentStringLength);
499
+
500
+ d_string_insert(result, -1, "bar");
501
+ CuAssertStrEquals(tc, "fobarobar", result->str);
502
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
503
+
504
+ d_string_insert(result, -1, NULL);
505
+ CuAssertStrEquals(tc, "fobarobar", result->str);
506
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
507
+
508
+ d_string_insert(NULL, 0, NULL);
509
+
510
+ d_string_free(result, true);
511
+ }
512
+ #endif
513
+
514
+
515
+ /// Insert single character inside dynamic string
516
+ void d_string_insert_c(DString * baseString, size_t pos, char insertedCharacter) {
517
+ if (baseString && insertedCharacter) {
277
518
  if (pos > baseString->currentStringLength) {
278
519
  pos = baseString->currentStringLength;
279
520
  }
280
521
 
281
- size_t newStringLength = baseString->currentStringLength + insertedStringLength;
282
- ensureStringBufferCanHold(baseString, newStringLength);
522
+ size_t newSizeNeeded = baseString->currentStringLength + 1;
523
+ ensureStringBufferCanHold(baseString, newSizeNeeded);
283
524
 
284
525
  /* Shift following string to 'right' */
285
- memmove(baseString->str + pos + insertedStringLength, baseString->str + pos, baseString->currentStringLength - pos);
286
- strncpy(baseString->str + pos, insertedString, insertedStringLength);
287
- baseString->currentStringLength = newStringLength;
526
+ memmove(baseString->str + pos + 1, baseString->str + pos, baseString->currentStringLength - pos);
527
+
528
+ baseString->str[pos] = insertedCharacter;
529
+ baseString->currentStringLength++;
288
530
  baseString->str[baseString->currentStringLength] = '\0';
289
531
  }
290
532
  }
291
533
 
292
534
 
293
- /// Insert single character inside dynamic string
294
- void d_string_insert_c(DString * baseString, size_t pos, char insertedCharacter) {
295
- if (pos > baseString->currentStringLength) {
296
- pos = baseString->currentStringLength;
297
- }
535
+ #ifdef TEST
536
+ void Test_d_string_insert_c(CuTest* tc) {
537
+ char * test = "foo";
538
+
539
+ DString * result = d_string_new(test);
540
+
541
+ d_string_insert_c(result, 2, 'b');
542
+ CuAssertStrEquals(tc, "fobo", result->str);
543
+ CuAssertIntEquals(tc, 4, result->currentStringLength);
544
+
545
+ d_string_insert_c(result, -1, 'z');
546
+ CuAssertStrEquals(tc, "foboz", result->str);
547
+ CuAssertIntEquals(tc, 5, result->currentStringLength);
298
548
 
299
- size_t newSizeNeeded = baseString->currentStringLength + 1;
300
- ensureStringBufferCanHold(baseString, newSizeNeeded);
549
+ d_string_insert_c(result, 3, 0);
550
+ CuAssertStrEquals(tc, "foboz", result->str);
551
+ CuAssertIntEquals(tc, 5, result->currentStringLength);
301
552
 
302
- /* Shift following string to 'right' */
303
- memmove(baseString->str + pos + 1, baseString->str + pos, baseString->currentStringLength - pos);
553
+ d_string_insert_c(NULL, 0, 0);
304
554
 
305
- baseString->str[pos] = insertedCharacter;
306
- baseString->currentStringLength++;
307
- baseString->str[baseString->currentStringLength] = '\0';
555
+ d_string_free(result, true);
308
556
  }
557
+ #endif
309
558
 
310
559
 
311
560
  /// Insert inside dynamic string using format specifier
312
561
  void d_string_insert_printf(DString * baseString, size_t pos, const char * format, ...) {
313
- va_list args;
314
- va_start(args, format);
562
+ if (baseString && format) {
563
+ va_list args;
564
+ va_start(args, format);
315
565
 
316
- char* formattedString = NULL;
317
- vasprintf(&formattedString, format, args);
566
+ char* formattedString = NULL;
567
+ vasprintf(&formattedString, format, args);
318
568
 
319
- if (formattedString != NULL) {
320
- d_string_insert(baseString, pos, formattedString);
321
- free(formattedString);
569
+ if (formattedString != NULL) {
570
+ d_string_insert(baseString, pos, formattedString);
571
+ free(formattedString);
572
+ }
573
+
574
+ va_end(args);
322
575
  }
576
+ }
577
+
578
+
579
+ #ifdef TEST
580
+ void Test_d_string_insert_printf(CuTest* tc) {
581
+ char * test = "foo";
323
582
 
324
- va_end(args);
583
+ DString * result = d_string_new(test);
584
+
585
+ d_string_insert_printf(result, 2, "%dbar%d", 5, 7);
586
+ CuAssertStrEquals(tc, "fo5bar7o", result->str);
587
+ CuAssertIntEquals(tc, 8, result->currentStringLength);
588
+
589
+ d_string_insert_printf(result, -1, "z", 5, 7);
590
+ CuAssertStrEquals(tc, "fo5bar7oz", result->str);
591
+ CuAssertIntEquals(tc, 9, result->currentStringLength);
592
+
593
+ d_string_insert_printf(NULL, 0, NULL);
594
+
595
+ d_string_free(result, true);
325
596
  }
597
+ #endif
326
598
 
327
599
 
328
600
  /// Erase portion of dynamic string
329
601
  void d_string_erase(DString * baseString, size_t pos, size_t len) {
330
- if ((pos > baseString->currentStringLength) || (len <= 0)) {
331
- return;
332
- }
602
+ if (baseString) {
603
+ if ((pos > baseString->currentStringLength) || (len <= 0)) {
604
+ return;
605
+ }
333
606
 
334
- if ((pos + len) >= baseString->currentStringLength) {
335
- len = -1;
336
- }
607
+ if ((pos + len) >= baseString->currentStringLength) {
608
+ len = -1;
609
+ }
337
610
 
338
- if (len == -1) {
339
- baseString->currentStringLength = pos;
340
- } else {
341
- memmove(baseString->str + pos, baseString->str + pos + len, baseString->currentStringLength - pos - len);
342
- baseString->currentStringLength -= len;
611
+ if (len == -1) {
612
+ baseString->currentStringLength = pos;
613
+ } else {
614
+ memmove(baseString->str + pos, baseString->str + pos + len, baseString->currentStringLength - pos - len);
615
+ baseString->currentStringLength -= len;
616
+ }
617
+
618
+ baseString->str[baseString->currentStringLength] = '\0';
343
619
  }
620
+ }
621
+
622
+
623
+ #ifdef TEST
624
+ void Test_d_string_erase(CuTest* tc) {
625
+ char * test = "foobar";
344
626
 
345
- baseString->str[baseString->currentStringLength] = '\0';
627
+ DString * result = d_string_new(test);
628
+
629
+ d_string_erase(result, 2, 1);
630
+ CuAssertStrEquals(tc, "fobar", result->str);
631
+ CuAssertIntEquals(tc, 5, result->currentStringLength);
632
+
633
+ d_string_erase(result, -1, -1);
634
+ CuAssertStrEquals(tc, "fobar", result->str);
635
+ CuAssertIntEquals(tc, 5, result->currentStringLength);
636
+
637
+ d_string_erase(result, 2, -1);
638
+ CuAssertStrEquals(tc, "fo", result->str);
639
+ CuAssertIntEquals(tc, 2, result->currentStringLength);
640
+
641
+ d_string_erase(NULL, 0, 0);
642
+
643
+ d_string_free(result, true);
346
644
  }
645
+ #endif
646
+
347
647
 
348
648
  /// Copy a portion of dynamic string
349
649
  char * d_string_copy_substring(DString * d, size_t start, size_t len) {
350
- char * result;
650
+ if (d) {
651
+ char * result;
652
+
653
+ if (len == -1) {
654
+ if (start <= d->currentStringLength) {
655
+ len = d->currentStringLength - start;
656
+ } else {
657
+ len = 0;
658
+ }
659
+ }
351
660
 
352
- if (len == -1) {
353
- len = d->currentStringLength - start;
354
- } else {
355
661
  if (start + len > d->currentStringLength) {
356
662
  fprintf(stderr, "d_string: Asked to copy invalid substring range.\n");
357
663
  fprintf(stderr, "start: %lu len: %lu string: %lu\n", start, len,
358
- d->currentStringLength);
664
+ d->currentStringLength);
359
665
  return NULL;
360
666
  }
667
+
668
+ result = malloc(len + 1);
669
+ strncpy(result, &d->str[start], len);
670
+ result[len] = '\0';
671
+
672
+ return result;
673
+ } else {
674
+ return NULL;
361
675
  }
676
+ }
677
+
678
+
679
+ #ifdef TEST
680
+ void Test_d_string_copy_substring(CuTest* tc) {
681
+ char * test = "foobar";
682
+
683
+ DString * result = d_string_new(test);
684
+
685
+ test = d_string_copy_substring(result, 0, -1);
686
+ CuAssertStrEquals(tc, "foobar", test);
687
+ free(test);
362
688
 
363
- result = malloc(len + 1);
364
- strncpy(result, &d->str[start], len);
365
- result[len] = '\0';
689
+ test = d_string_copy_substring(result, 2, 3);
690
+ CuAssertStrEquals(tc, "oba", test);
691
+ free(test);
366
692
 
367
- return result;
693
+ test = d_string_copy_substring(result, 8, 2);
694
+ CuAssertStrEquals(tc, NULL, test);
695
+ free(test);
696
+
697
+ test = d_string_copy_substring(result, -1, -1);
698
+ CuAssertStrEquals(tc, NULL, test);
699
+ free(test);
700
+
701
+ test = d_string_copy_substring(NULL, -1, -1);
702
+ CuAssertStrEquals(tc, NULL, test);
703
+
704
+ d_string_free(result, true);
368
705
  }
706
+ #endif
369
707
 
370
708
 
371
709
  /// Replace occurences of "original" with "replace" inside the specified range
372
710
  /// Returns the change in overall length
373
711
  long d_string_replace_text_in_range(DString * d, size_t pos, size_t len, const char * original, const char * replace) {
374
- long delta = 0; // Overall change in length
712
+ if (d && original && replace) {
713
+ long delta = 0; // Overall change in length
714
+
715
+ long len_o = strlen(original);
716
+ long len_r = strlen(replace);
717
+ long change = len_r - len_o; // Change in length for each replacement
718
+
719
+ size_t stop;
720
+
721
+ if (len == -1) {
722
+ stop = d->currentStringLength;
723
+ } else {
724
+ stop = pos + len;
725
+
726
+ if (stop > d->currentStringLength) {
727
+ stop = d->currentStringLength;
728
+ }
729
+ }
730
+
731
+ char * match = strstr(&(d->str[pos]), original);
375
732
 
376
- long len_o = strlen(original);
377
- long len_r = strlen(replace);
378
- long change = len_r - len_o; // Change in length for each replacement
733
+ while (match && (match - d->str < stop)) {
734
+ pos = match - d->str;
735
+ d_string_erase(d, match - d->str, len_o);
736
+ d_string_insert(d, match - d->str, replace);
379
737
 
380
- size_t stop;
738
+ delta += change;
739
+ stop += change;
740
+ match = strstr(d->str + pos + len_r, original);
741
+ }
381
742
 
382
- if (len == -1) {
383
- stop = d->currentStringLength;
743
+ return delta;
384
744
  } else {
385
- stop = pos + len;
745
+ return 0;
386
746
  }
747
+ }
387
748
 
388
- char * match = strstr(&(d->str[pos]), original);
389
749
 
390
- while (match && (match - d->str < stop)) {
391
- pos = match - d->str;
392
- d_string_erase(d, match - d->str, len_o);
393
- d_string_insert(d, match - d->str, replace);
750
+ #ifdef TEST
751
+ void Test_d_string_replace_text_in_range(CuTest* tc) {
752
+ char * test = "foobarfoobarfoo";
753
+ long delta = 0;
394
754
 
395
- delta += change;
396
- stop += change;
397
- match = strstr(d->str + pos + len_r, original);
398
- }
755
+ DString * result = d_string_new(test);
399
756
 
400
- return delta;
401
- }
757
+ delta = d_string_replace_text_in_range(result, 100, 3, "foo", "zapz");
758
+ CuAssertIntEquals(tc, 15, result->currentStringLength);
759
+ CuAssertStrEquals(tc, "foobarfoobarfoo", result->str);
760
+ CuAssertIntEquals(tc, delta, 0);
761
+
762
+ delta = d_string_replace_text_in_range(result, 0, 3, "foo", "zapz");
763
+ CuAssertIntEquals(tc, 16, result->currentStringLength);
764
+ CuAssertStrEquals(tc, "zapzbarfoobarfoo", result->str);
765
+ CuAssertIntEquals(tc, delta, 1);
402
766
 
767
+ delta = d_string_replace_text_in_range(result, 0, 100, "foo", "zapz");
768
+ CuAssertIntEquals(tc, 18, result->currentStringLength);
769
+ CuAssertStrEquals(tc, "zapzbarzapzbarzapz", result->str);
770
+ CuAssertIntEquals(tc, delta, 2);
771
+
772
+ delta = d_string_replace_text_in_range(result, 0, -1, NULL, "zap");
773
+ CuAssertIntEquals(tc, 18, result->currentStringLength);
774
+ CuAssertStrEquals(tc, "zapzbarzapzbarzapz", result->str);
775
+ CuAssertIntEquals(tc, delta, 0);
776
+
777
+ d_string_replace_text_in_range(result, 0, -1, "foo", NULL);
778
+ CuAssertIntEquals(tc, 18, result->currentStringLength);
779
+ CuAssertStrEquals(tc, "zapzbarzapzbarzapz", result->str);
780
+
781
+ d_string_replace_text_in_range(NULL, 0, -1, "foo", NULL);
782
+
783
+ d_string_free(result, true);
784
+ }
785
+ #endif