rmultimarkdown 6.2.2.1 → 6.4.0.1

Sign up to get free protection for your applications and to get access to all the features.
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