@simonklee/opentui-tex-native-source 0.2.0 → 0.3.0

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.
@@ -1 +1 @@
1
- zigtex=fda2819e45f57ca2071810c47249a46bfc782cdf microtex=74e8fee9e47edc3a777e64fb2eff9a85a01defac nanosvg=239e102ec2c691f2902e20ace2ed36ee4a35cfe6 zig=0.16-v5
1
+ zigtex=fda2819e45f57ca2071810c47249a46bfc782cdf microtex=74e8fee9e47edc3a777e64fb2eff9a85a01defac nanosvg=239e102ec2c691f2902e20ace2ed36ee4a35cfe6 zig=0.16-v8
@@ -1,11 +1,13 @@
1
1
  #include "atom/atom_matrix.h"
2
2
 
3
+ #include <charconv>
3
4
  #include <memory>
4
5
 
5
6
  #include "atom/atom_basic.h"
6
7
  #include "atom/atom_row.h"
7
8
  #include "core/formula.h"
8
9
  #include "core/glue.h"
10
+ #include "core/parse_limits.h"
9
11
  #include "env/env.h"
10
12
  #include "utils/exceptions.h"
11
13
  #include "utils/string_utils.h"
@@ -31,6 +33,8 @@ void MatrixAtom::defineColumnSpecifier(const string& rep, const string& spe) {
31
33
  }
32
34
 
33
35
  void MatrixAtom::parsePositions(string opt, vector<Alignment>& lpos) {
36
+ ParseDepth depth;
37
+ parse_limits.input(opt.size());
34
38
  int len = opt.length();
35
39
  int pos = 0;
36
40
  char ch;
@@ -39,6 +43,7 @@ void MatrixAtom::parsePositions(string opt, vector<Alignment>& lpos) {
39
43
  // clear first
40
44
  lpos.clear();
41
45
  while (pos < len) {
46
+ parse_limits.spend();
42
47
  ch = opt[pos];
43
48
  switch (ch) {
44
49
  case 'l': lpos.push_back(Alignment::left); break;
@@ -79,11 +84,22 @@ void MatrixAtom::parsePositions(string opt, vector<Alignment>& lpos) {
79
84
  vector<string> args;
80
85
  tp->getOptsArgs(2, 0, args);
81
86
  pos += tp->getPos();
82
- int nrep = 0;
83
- valueOf(args[1], nrep);
87
+ size_t nrep = 0;
88
+ const auto& count = trim(args[1]);
89
+ auto first = count.data();
90
+ if (!count.empty() && count.front() == '+') ++first;
91
+ const auto parsed = from_chars(first, count.data() + count.size(), nrep);
92
+ if (parsed.ec != errc{} || parsed.ptr != count.data() + count.size() ||
93
+ nrep > ParseLimits::bytes_max ||
94
+ (!args[2].empty() && nrep > (ParseLimits::bytes_max - opt.size()) / args[2].size())) {
95
+ throw ParseLimitExceeded{};
96
+ }
97
+ const auto bytes = nrep * args[2].size();
98
+ parse_limits.spend(nrep + bytes);
84
99
  string str;
85
- for (int j = 0; j < nrep; j++) str += args[2];
86
- opt.insert(pos, str);
100
+ str.reserve(bytes);
101
+ for (size_t j = 0; j < nrep; j++) str += args[2];
102
+ parse_limits.replace(opt, pos, 0, str);
87
103
  len = opt.length();
88
104
  pos--;
89
105
  } break;
@@ -102,10 +118,11 @@ void MatrixAtom::parsePositions(string opt, vector<Alignment>& lpos) {
102
118
  int spos = len + 1;
103
119
  bool hasrep = false;
104
120
  while (--spos > pos) {
121
+ parse_limits.spend(spos - pos);
105
122
  auto it = _colspeReplacement.find(opt.substr(pos, spos - pos));
106
123
  if (it != _colspeReplacement.end()) {
107
124
  hasrep = true;
108
- opt.insert(spos, it->second);
125
+ parse_limits.replace(opt, spos, 0, it->second);
109
126
  len = opt.length();
110
127
  pos = spos - 1;
111
128
  break;
@@ -127,9 +144,9 @@ void MatrixAtom::parsePositions(string opt, vector<Alignment>& lpos) {
127
144
  if (lpos.empty()) lpos.push_back(Alignment::center);
128
145
  }
129
146
 
130
- float* MatrixAtom::getColumnSep(Env& env, float width) {
147
+ vector<float> MatrixAtom::getColumnSep(Env& env, float width) {
131
148
  const int cols = _matrix->cols();
132
- auto* arr = new float[cols + 1]();
149
+ vector<float> arr(cols + 1);
133
150
  sptr<Box> Align, AlignSep, Hsep;
134
151
  float h, w = env.textWidth();
135
152
  int i = 0;
@@ -234,7 +251,7 @@ float* MatrixAtom::getColumnSep(Env& env, float width) {
234
251
 
235
252
  void MatrixAtom::recalculateLine(
236
253
  const int rows,
237
- sptr<Box>** boxarr,
254
+ vector<vector<sptr<Box>>>& boxarr,
238
255
  vector<sptr<Atom>>& multiRows,
239
256
  float* height,
240
257
  float* depth,
@@ -406,11 +423,11 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
406
423
  const int rows = _matrix->rows();
407
424
  const int cols = _matrix->cols();
408
425
 
409
- auto lineDepth = new float[rows]();
410
- auto lineHeight = new float[rows]();
411
- auto colWidth = new float[cols]();
412
- auto boxarr = new sptr<Box>*[rows]();
413
- for (int i = 0; i < rows; i++) boxarr[i] = new sptr<Box>[cols]();
426
+ vector<float> lineDepth(rows);
427
+ vector<float> lineHeight(rows);
428
+ vector<float> colWidth(cols);
429
+ vector<vector<sptr<Box>>> boxarr(rows);
430
+ for (auto& row : boxarr) row.resize(cols);
414
431
 
415
432
  float matW = 0;
416
433
  const auto drt = env.ruleThickness();
@@ -459,7 +476,7 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
459
476
  for (int j = 0; j < cols; j++) matW += colWidth[j];
460
477
 
461
478
  // The horizontal separator's width
462
- float* Hsep = getColumnSep(env, matW);
479
+ auto Hsep = getColumnSep(env, matW);
463
480
 
464
481
  for (auto& i : multiCols) {
465
482
  auto* multi = (MulticolumnAtom*)i.get();
@@ -486,9 +503,9 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
486
503
 
487
504
  auto Vsep = _vsep_in.createBox(env);
488
505
  // Recalculate the height of the row
489
- recalculateLine(rows, boxarr, multiRows, lineHeight, lineDepth, drt, Vsep->_height);
506
+ recalculateLine(rows, boxarr, multiRows, lineHeight.data(), lineDepth.data(), drt, Vsep->_height);
490
507
 
491
- auto* vb = new VBox();
508
+ auto vb = sptrOf<VBox>();
492
509
  float totalHeight = 0;
493
510
  float Vspace = Vsep->_height / 2;
494
511
 
@@ -511,11 +528,11 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
511
528
 
512
529
  bool isLastVline = true;
513
530
 
514
- WrapperBox* wb = nullptr;
531
+ sptr<WrapperBox> wb;
515
532
  int tj = j;
516
533
  float l = j == 0 ? Hsep[j] : Hsep[j] / 2;
517
534
  if (boxarr[i][j]->_type == AtomType::none) {
518
- wb = new WrapperBox(
535
+ wb = sptrOf<WrapperBox>(
519
536
  boxarr[i][j],
520
537
  colWidth[j],
521
538
  lineHeight[i],
@@ -523,18 +540,17 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
523
540
  _position[j] //
524
541
  );
525
542
  } else {
526
- auto b = generateMulticolumn(env, boxarr[i][j], Hsep, colWidth, i, j);
543
+ auto b = generateMulticolumn(env, boxarr[i][j], Hsep.data(), colWidth.data(), i, j);
527
544
  auto* matom = (MulticolumnAtom*)_matrix->_array[i][j].get();
528
545
  j += matom->skipped() - 1;
529
- wb = new WrapperBox(b, b->_width, lineHeight[i], lineDepth[i], Alignment::left);
546
+ wb = sptrOf<WrapperBox>(b, b->_width, lineHeight[i], lineDepth[i], Alignment::left);
530
547
  isLastVline = matom->hasRightVline();
531
548
  }
532
549
  float r = j == cols - 1 ? Hsep[j + 1] : Hsep[j + 1] / 2;
533
550
  wb->addInsets(l, Vspace, r, Vspace);
534
551
  applyCell(*wb, i, j);
535
- sptr<Box> swb(wb);
536
- boxarr[i][tj] = swb;
537
- hb->add(swb);
552
+ boxarr[i][tj] = wb;
553
+ hb->add(wb);
538
554
 
539
555
  auto it = _vlines.find(j + 1);
540
556
  if (isLastVline && it != _vlines.end()) {
@@ -582,14 +598,7 @@ sptr<Box> MatrixAtom::createBoxInner(Env& env) {
582
598
  vb->_height = totalHeight / 2 + axis;
583
599
  vb->_depth = totalHeight / 2 - axis;
584
600
 
585
- delete[] Hsep;
586
- delete[] lineDepth;
587
- delete[] lineHeight;
588
- delete[] colWidth;
589
- for (int i = 0; i < rows; i++) delete[] boxarr[i];
590
- delete[] boxarr;
591
-
592
- return sptr<Box>(vb);
601
+ return vb;
593
602
  }
594
603
 
595
604
  sptr<Box> MatrixAtom::createBox(Env& env) {
@@ -709,13 +718,13 @@ sptr<Box> VlineAtom::createBox(Env& env) {
709
718
  const auto drt = env.ruleThickness();
710
719
  auto rb = sptrOf<RuleBox>(_height, drt, _shift, MatrixAtom::LINE_COLOR, true);
711
720
  auto sep = sptrOf<StrutBox>(2 * drt, 0.f, 0.f, 0.f);
712
- auto hb = new HBox();
721
+ auto hb = sptrOf<HBox>();
713
722
  for (int i = 0; i < _n - 1; i++) {
714
723
  hb->add(rb);
715
724
  hb->add(sep);
716
725
  }
717
726
  if (_n > 0) hb->add(rb);
718
- return sptr<Box>(hb);
727
+ return hb;
719
728
  }
720
729
 
721
730
  SpaceAtom MultlineAtom::_vsep_in(UnitType::ex, 0.f, 1.f, 0.f);
@@ -725,7 +734,7 @@ sptr<Box> MultlineAtom::createBox(Env& env) {
725
734
  if (tw == POS_INF || _lineType == MultiLineType::gathered)
726
735
  return MatrixAtom(_isPartial, _column, "").createBox(env);
727
736
 
728
- auto* vb = new VBox();
737
+ auto vb = sptrOf<VBox>();
729
738
  auto atom = _column->_array[0][0];
730
739
  Alignment alignment = _lineType == MultiLineType::gather ? Alignment::center : Alignment::left;
731
740
  if (atom->_alignment != Alignment::none) alignment = atom->_alignment;
@@ -752,5 +761,5 @@ sptr<Box> MultlineAtom::createBox(Env& env) {
752
761
  vb->_height = h / 2;
753
762
  vb->_depth = h / 2;
754
763
 
755
- return sptr<Box>(vb);
764
+ return vb;
756
765
  }
@@ -87,7 +87,7 @@ private:
87
87
 
88
88
  static void recalculateLine(
89
89
  int rows,
90
- sptr<Box>** boxarr,
90
+ std::vector<std::vector<sptr<Box>>>& boxarr,
91
91
  std::vector<sptr<Atom>>& multiRows,
92
92
  float* height,
93
93
  float* depth,
@@ -95,7 +95,7 @@ private:
95
95
  float vspace
96
96
  );
97
97
 
98
- float* getColumnSep(Env& env, float width);
98
+ std::vector<float> getColumnSep(Env& env, float width);
99
99
 
100
100
  void applyCell(WrapperBox& box, int i, int j);
101
101
 
@@ -172,7 +172,7 @@ sptr<TextAtom> RowAtom::processContinues(int& i, bool isMathMode) {
172
172
  }
173
173
 
174
174
  sptr<Box> RowAtom::createBox(Env& env) {
175
- auto hbox = new HBox();
175
+ auto hbox = sptrOf<HBox>();
176
176
  // convert atoms to boxes and add to the horizontal box
177
177
  const int end = _elements.size() - 1;
178
178
  for (int i = -1; i < end;) {
@@ -326,7 +326,7 @@ sptr<Box> RowAtom::createBox(Env& env) {
326
326
  }
327
327
  // reset previous atom
328
328
  _previousAtom = nullptr;
329
- return sptr<Box>(hbox);
329
+ return hbox;
330
330
  }
331
331
 
332
332
  void RowAtom::setPreviousAtom(const sptr<AtomDecor>& prev) {
@@ -0,0 +1,54 @@
1
+ #ifndef MICROTEX_PARSE_LIMITS_H
2
+ #define MICROTEX_PARSE_LIMITS_H
3
+
4
+ #include <cstddef>
5
+ #include <string>
6
+
7
+ namespace microtex {
8
+
9
+ // Deliberately not std::exception: partial parsing must not swallow limit failures.
10
+ struct ParseLimitExceeded {};
11
+
12
+ struct ParseLimits {
13
+ // Allow expansion beyond the 4 KiB public input limit, but bound synchronous work.
14
+ static constexpr size_t bytes_max = 64 * 1024;
15
+ size_t work_left = 1024 * 1024;
16
+ size_t replacements_left = 1024;
17
+ size_t depth = 0;
18
+
19
+ void spend(size_t work = 1) {
20
+ if (work > work_left) throw ParseLimitExceeded{};
21
+ work_left -= work;
22
+ }
23
+
24
+ void input(size_t bytes) {
25
+ if (bytes > bytes_max) throw ParseLimitExceeded{};
26
+ spend(bytes);
27
+ }
28
+
29
+ void replace(std::string& source, size_t pos, size_t count, const std::string& text) {
30
+ if (replacements_left == 0 || text.size() > bytes_max ||
31
+ source.size() > bytes_max - text.size()) throw ParseLimitExceeded{};
32
+ --replacements_left;
33
+ spend(source.size() + text.size());
34
+ source.replace(pos, count, text);
35
+ }
36
+ };
37
+
38
+ // Nested parsers and macro argument substitutions share the caller's budget.
39
+ inline thread_local ParseLimits parse_limits;
40
+
41
+ struct ParseDepth {
42
+ ParseDepth() {
43
+ parse_limits.spend();
44
+ if (parse_limits.depth >= 64) throw ParseLimitExceeded{};
45
+ ++parse_limits.depth;
46
+ }
47
+ ~ParseDepth() { --parse_limits.depth; }
48
+ ParseDepth(const ParseDepth&) = delete;
49
+ ParseDepth& operator=(const ParseDepth&) = delete;
50
+ };
51
+
52
+ } // namespace microtex
53
+
54
+ #endif
@@ -1,4 +1,5 @@
1
1
  #include "core/parser.h"
2
+ #include "core/parse_limits.h"
2
3
 
3
4
  #include "atom/atom.h"
4
5
  #include "atom/atom_basic.h"
@@ -39,6 +40,7 @@ static constexpr char BACKPRIME = '`';
39
40
  } // namespace
40
41
 
41
42
  void Parser::init(bool isPartial, const string& latex, Formula* formula, bool firstPass) {
43
+ parse_limits.input(latex.size());
42
44
  _pos = _spos = _len = 0;
43
45
  _group = 0;
44
46
  _atIsLetter = 0;
@@ -62,6 +64,7 @@ void Parser::init(bool isPartial, const string& latex, Formula* formula, bool fi
62
64
  }
63
65
 
64
66
  void Parser::reset(const string& latex) {
67
+ parse_limits.input(latex.size());
65
68
  _latex = latex;
66
69
  _len = latex.length();
67
70
  _formula->_root = nullptr;
@@ -284,7 +287,7 @@ string Parser::getCmd() {
284
287
  }
285
288
 
286
289
  void Parser::insert(int beg, int end, const string& formula) {
287
- _latex.replace(beg, end - beg, formula);
290
+ parse_limits.replace(_latex, beg, end - beg, formula);
288
291
  _len = _latex.length();
289
292
  _pos = beg;
290
293
  _insertion = true;
@@ -363,6 +366,8 @@ string Parser::forward(std::function<bool(char)>&& f) {
363
366
  }
364
367
 
365
368
  void Parser::getOptsArgs(int argc, int opts, Args& args) {
369
+ ParseDepth depth;
370
+ if (argc < 0 || argc > 10) throw ParseLimitExceeded{};
366
371
  // A maximum of 10 options can be passed to a command,
367
372
  // the value will be added at the tail of the args if found any,
368
373
  // the last (maximum to 12th) value is reserved for returned value
@@ -536,6 +541,7 @@ sptr<Atom> Parser::getScripts(char first) {
536
541
  }
537
542
 
538
543
  sptr<Atom> Parser::getArgument() {
544
+ ParseDepth depth;
539
545
  skipWhiteSpace();
540
546
  char ch;
541
547
  if (_pos < _len)
@@ -619,7 +625,7 @@ void Parser::preprocessNewCmd(string& cmd, Args& args, int& pos) {
619
625
  auto mac = MacroInfo::get(cmd);
620
626
  getOptsArgs(mac->argc, mac->opt, args);
621
627
  mac->invoke(*this, args);
622
- _latex.erase(pos, _pos - pos);
628
+ parse_limits.replace(_latex, pos, _pos - pos, "");
623
629
  _len = _latex.length();
624
630
  _pos = pos;
625
631
  }
@@ -632,7 +638,7 @@ void Parser::inflateNewCmd(string& cmd, Args& args, int& pos) {
632
638
  try {
633
639
  mac->invoke(*this, args);
634
640
  // The last element is the returned value (after inflated macro)
635
- _latex.replace(pos, _pos - pos, args.back());
641
+ parse_limits.replace(_latex, pos, _pos - pos, args.back());
636
642
  } catch (ex_parse& e) {
637
643
  if (!_isPartial) throw e;
638
644
  pos += cmd.length() + 1;
@@ -654,7 +660,7 @@ void Parser::inflateEnv(string& cmd, Args& args, int& pos) {
654
660
  string expr = "{\\makeatletter \\" + args[1] + "@env";
655
661
  for (int i = 1; i <= mac->argc - 1; i++) expr += "{" + optargs[i] + "}";
656
662
  expr += "{" + grp + "}\\makeatother}";
657
- _latex.replace(pos, _pos - pos, expr);
663
+ parse_limits.replace(_latex, pos, _pos - pos, expr);
658
664
  _len = _latex.length();
659
665
  _pos = pos;
660
666
  }
@@ -666,6 +672,7 @@ void Parser::preprocess() {
666
672
  int spos;
667
673
  vector<string> args;
668
674
  while (_pos < _len) {
675
+ parse_limits.spend();
669
676
  ch = _latex[_pos];
670
677
  switch (ch) {
671
678
  case ESCAPE: {
@@ -687,7 +694,7 @@ void Parser::preprocess() {
687
694
  if (chr == '\r' || chr == '\n') break;
688
695
  }
689
696
  if (_pos < _len) _pos--;
690
- _latex.replace(spos, _pos - spos, "");
697
+ parse_limits.replace(_latex, spos, _pos - spos, "");
691
698
  _len = _latex.length();
692
699
  _pos = spos;
693
700
  break;
@@ -700,6 +707,7 @@ void Parser::preprocess() {
700
707
  }
701
708
 
702
709
  void Parser::parse() {
710
+ ParseDepth depth;
703
711
  if (_len == 0) {
704
712
  if (_formula->_root == nullptr && !_arrayMode) _formula->add(sptrOf<EmptyAtom>());
705
713
  return;
@@ -707,6 +715,7 @@ void Parser::parse() {
707
715
 
708
716
  char ch;
709
717
  while (_pos < _len) {
718
+ parse_limits.spend();
710
719
  ch = _latex[_pos];
711
720
 
712
721
  switch (ch) {
@@ -13,18 +13,18 @@ macro(xarrow) {
13
13
  StackArgs::autoSpace(Formula(tp, args[1], false, tp.isMathMode())._root, false);
14
14
  const auto& under =
15
15
  StackArgs::autoSpace(Formula(tp, args[2], false, tp.isMathMode())._root, false);
16
- const auto stack = new StackAtom(nullptr, over, under);
16
+ const auto stack = sptrOf<StackAtom>(nullptr, over, under);
17
17
  const auto& arrow = sptrOf<ExtensibleAtom>(
18
18
  name,
19
19
  // capture raw pointer to avoid cycle reference
20
- [stack](const Env& env) -> float {
20
+ [stack = stack.get()](const Env& env) -> float {
21
21
  return stack->getMaxWidth() + Units::fsize(UnitType::ex, 1.f, env);
22
22
  },
23
23
  false
24
24
  );
25
25
  arrow->_type = AtomType::relation;
26
26
  stack->setBaseAtom(arrow);
27
- return sptr<StackAtom>(stack);
27
+ return stack;
28
28
  }
29
29
 
30
30
  macro(left) {
@@ -45,12 +45,12 @@ macro(left) {
45
45
  return sptrOf<FencedAtom>(tf._root, sl->name(), sr->name(), tf.middle());
46
46
  }
47
47
 
48
- auto* ra = new RowAtom();
48
+ auto ra = sptrOf<RowAtom>();
49
49
  ra->add(left);
50
50
  ra->add(Formula(tp, grep, false)._root);
51
51
  ra->add(right);
52
52
 
53
- return sptr<Atom>(ra);
53
+ return ra;
54
54
  }
55
55
 
56
56
  } // namespace microtex
@@ -11,68 +11,68 @@
11
11
  namespace microtex {
12
12
 
13
13
  inline macro(smallmatrixATATenv) {
14
- auto* arr = new ArrayFormula();
15
- Parser parser(tp.isPartial(), args[1], arr, false);
14
+ auto arr = sptrOf<ArrayFormula>();
15
+ Parser parser(tp.isPartial(), args[1], arr.get(), false);
16
16
  parser.parse();
17
17
  arr->checkDimensions();
18
- return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::smallMatrix);
18
+ return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::smallMatrix);
19
19
  }
20
20
 
21
21
  inline macro(matrixATATenv) {
22
- auto* arr = new ArrayFormula();
23
- Parser parser(tp.isPartial(), args[1], arr, false);
22
+ auto arr = sptrOf<ArrayFormula>();
23
+ Parser parser(tp.isPartial(), args[1], arr.get(), false);
24
24
  parser.parse();
25
25
  arr->checkDimensions();
26
- return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::matrix);
26
+ return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::matrix);
27
27
  }
28
28
 
29
29
  inline macro(arrayATATenv) {
30
- auto* arr = new ArrayFormula();
31
- Parser parser(tp.isPartial(), args[2], arr, false);
30
+ auto arr = sptrOf<ArrayFormula>();
31
+ Parser parser(tp.isPartial(), args[2], arr.get(), false);
32
32
  parser.parse();
33
33
  arr->checkDimensions();
34
- return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), args[1], true);
34
+ return sptrOf<MatrixAtom>(tp.isPartial(), arr, args[1], true);
35
35
  }
36
36
 
37
37
  inline macro(alignATATenv) {
38
- auto* arr = new ArrayFormula();
39
- Parser parser(tp.isPartial(), args[1], arr, false);
38
+ auto arr = sptrOf<ArrayFormula>();
39
+ Parser parser(tp.isPartial(), args[1], arr.get(), false);
40
40
  parser.parse();
41
41
  arr->checkDimensions();
42
- return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::align);
42
+ return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::align);
43
43
  }
44
44
 
45
45
  inline macro(flalignATATenv) {
46
- auto* arr = new ArrayFormula();
47
- Parser parser(tp.isPartial(), args[1], arr, false);
46
+ auto arr = sptrOf<ArrayFormula>();
47
+ Parser parser(tp.isPartial(), args[1], arr.get(), false);
48
48
  parser.parse();
49
49
  arr->checkDimensions();
50
- return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::flAlign);
50
+ return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::flAlign);
51
51
  }
52
52
 
53
53
  inline macro(alignatATATenv) {
54
- auto* arr = new ArrayFormula();
55
- Parser par(tp.isPartial(), args[2], arr, false);
54
+ auto arr = sptrOf<ArrayFormula>();
55
+ Parser par(tp.isPartial(), args[2], arr.get(), false);
56
56
  par.parse();
57
57
  arr->checkDimensions();
58
58
  size_t n = 0;
59
59
  valueOf(args[1], n);
60
60
  if (arr->cols() != 2 * n) throw ex_parse("Bad number of equations in alignat environment!");
61
61
 
62
- return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::alignAt);
62
+ return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::alignAt);
63
63
  }
64
64
 
65
65
  inline macro(alignedATATenv) {
66
- auto* arr = new ArrayFormula();
67
- Parser p(tp.isPartial(), args[1], arr, false);
66
+ auto arr = sptrOf<ArrayFormula>();
67
+ Parser p(tp.isPartial(), args[1], arr.get(), false);
68
68
  p.parse();
69
69
  arr->checkDimensions();
70
- return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::aligned);
70
+ return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::aligned);
71
71
  }
72
72
 
73
73
  inline macro(alignedatATATenv) {
74
- auto* arr = new ArrayFormula();
75
- Parser p(tp.isPartial(), args[2], arr, false);
74
+ auto arr = sptrOf<ArrayFormula>();
75
+ Parser p(tp.isPartial(), args[2], arr.get(), false);
76
76
  p.parse();
77
77
  arr->checkDimensions();
78
78
  size_t n = 0;
@@ -81,12 +81,12 @@ inline macro(alignedatATATenv) {
81
81
  throw ex_parse("Bad number of equations in alignedat environment!");
82
82
  }
83
83
 
84
- return sptrOf<MatrixAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MatrixType::alignedAt);
84
+ return sptrOf<MatrixAtom>(tp.isPartial(), arr, MatrixType::alignedAt);
85
85
  }
86
86
 
87
87
  inline macro(multlineATATenv) {
88
- auto* arr = new ArrayFormula();
89
- Parser p(tp.isPartial(), args[1], arr, false);
88
+ auto arr = sptrOf<ArrayFormula>();
89
+ Parser p(tp.isPartial(), args[1], arr.get(), false);
90
90
  p.parse();
91
91
  arr->checkDimensions();
92
92
  if (arr->cols() > 1) {
@@ -94,29 +94,29 @@ inline macro(multlineATATenv) {
94
94
  }
95
95
  if (arr->cols() == 0) return nullptr;
96
96
 
97
- return sptrOf<MultlineAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MultiLineType::multiline);
97
+ return sptrOf<MultlineAtom>(tp.isPartial(), arr, MultiLineType::multiline);
98
98
  }
99
99
 
100
100
  inline macro(gatherATATenv) {
101
- auto* arr = new ArrayFormula();
102
- Parser p(tp.isPartial(), args[1], arr, false);
101
+ auto arr = sptrOf<ArrayFormula>();
102
+ Parser p(tp.isPartial(), args[1], arr.get(), false);
103
103
  p.parse();
104
104
  arr->checkDimensions();
105
105
  if (arr->cols() > 1) throw ex_parse("Requires exact one column in gather environment!");
106
106
  if (arr->cols() == 0) return nullptr;
107
107
 
108
- return sptrOf<MultlineAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MultiLineType::gather);
108
+ return sptrOf<MultlineAtom>(tp.isPartial(), arr, MultiLineType::gather);
109
109
  }
110
110
 
111
111
  inline macro(gatheredATATenv) {
112
- auto* arr = new ArrayFormula();
113
- Parser p(tp.isPartial(), args[1], arr, false);
112
+ auto arr = sptrOf<ArrayFormula>();
113
+ Parser p(tp.isPartial(), args[1], arr.get(), false);
114
114
  p.parse();
115
115
  arr->checkDimensions();
116
116
  if (arr->cols() > 1) throw ex_parse("Requires exact one column in gathered environment!");
117
117
  if (arr->cols() == 0) return nullptr;
118
118
 
119
- return sptrOf<MultlineAtom>(tp.isPartial(), sptr<ArrayFormula>(arr), MultiLineType::gathered);
119
+ return sptrOf<MultlineAtom>(tp.isPartial(), arr, MultiLineType::gathered);
120
120
  }
121
121
 
122
122
  inline macro(multicolumn) {
@@ -8,6 +8,7 @@
8
8
  #include <map>
9
9
  #include <string>
10
10
  #include <vector>
11
+ #include "core/parse_limits.h"
11
12
 
12
13
  namespace microtex {
13
14
 
@@ -119,7 +120,7 @@ inline std::string& replaceAll(std::string& src, const std::string& from, const
119
120
  if (from.empty()) return src;
120
121
  size_t start = 0;
121
122
  while ((start = src.find(from, start)) != std::string::npos) {
122
- src.replace(start, from.length(), to);
123
+ parse_limits.replace(src, start, from.length(), to);
123
124
  start += to.length();
124
125
  }
125
126
  return src;
@@ -3,6 +3,7 @@
3
3
  #include "wrapper/byte_seq.h"
4
4
 
5
5
  #include <cstdlib>
6
+ #include <new>
6
7
 
7
8
  #include "utils/log.h"
8
9
 
@@ -10,11 +11,16 @@ namespace microtex {
10
11
 
11
12
  ByteSeq::ByteSeq() {
12
13
  _data = malloc(CHUNK_SIZE);
14
+ if (_data == nullptr) throw std::bad_alloc();
13
15
  // the first 4 bytes is the bytes size used
14
16
  _index = 4;
15
17
  _capacity = CHUNK_SIZE;
16
18
  }
17
19
 
20
+ ByteSeq::~ByteSeq() {
21
+ free(_data);
22
+ }
23
+
18
24
  void ByteSeq::_put(const char* str) {
19
25
  auto l = sizeOf(str);
20
26
  strcpy((char*)_data + _index, str);
@@ -28,8 +34,11 @@ void ByteSeq::ensureCapacity(len_t required) {
28
34
  #ifdef HAVE_LOG
29
35
  logv("grow buffer, _capacity: %u, to be add: %u\n", _capacity, required);
30
36
  #endif
31
- _data = realloc(_data, _capacity + CHUNK_SIZE);
32
- _capacity += CHUNK_SIZE;
37
+ const auto capacity = _index + required + CHUNK_SIZE;
38
+ auto data = realloc(_data, capacity);
39
+ if (data == nullptr) throw std::bad_alloc();
40
+ _data = data;
41
+ _capacity = capacity;
33
42
  }
34
43
 
35
44
  void* ByteSeq::finish() {
@@ -38,7 +47,8 @@ void* ByteSeq::finish() {
38
47
  #endif
39
48
  auto ptr = (unsigned int*)_data;
40
49
  *ptr = _index;
41
- return _data;
50
+ _data = nullptr;
51
+ return ptr;
42
52
  }
43
53
 
44
54
  } // namespace microtex
@@ -52,6 +52,7 @@ public:
52
52
  no_copy_assign(ByteSeq);
53
53
 
54
54
  ByteSeq();
55
+ ~ByteSeq();
55
56
 
56
57
  template <typename T, typename... Ts>
57
58
  void put(T t, Ts... ts) {