Remove dynamic exceptions
[anna.git] / source / core / util / Tokenizer.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #include <anna/core/util/Tokenizer.hpp>
10 #include <anna/core/functions.hpp>
11 #include <anna/config/defines.hpp>
12
13 // temporary
14 #include <iostream>
15
16 using namespace std;
17 using namespace anna;
18
19 //static
20 const int Tokenizer::MaxItem = 64;
21
22
23 Tokenizer::Tokenizer() :
24   a_dataBlock(true),
25   a_activateStrip(false) {
26   a_items = new char* [MaxItem];
27   anna_memset(a_items, 0, sizeof(char*) * MaxItem);
28   a_maxItem = 0;
29 }
30
31 Tokenizer::Tokenizer(const char* str, const char* separator) :
32   a_dataBlock(true),
33   a_activateStrip(false) {
34   a_items = new char* [MaxItem];
35   anna_memset(a_items, 0, sizeof(char*) * MaxItem);
36   a_maxItem = 0;
37
38   try {
39     apply(str, separator);
40   } catch(Exception&) {
41   }
42 }
43
44 Tokenizer::Tokenizer(const string& str, const char* separator) :
45   a_dataBlock(true),
46   a_activateStrip(false) {
47   a_items = new char* [MaxItem];
48   anna_memset(a_items, 0, sizeof(char*) * MaxItem);
49
50   try {
51     apply(str.c_str(), separator);
52   } catch(Exception&) {
53   }
54 }
55
56 Tokenizer::~Tokenizer() {
57   delete [] a_items;
58 }
59
60 int Tokenizer::_apply(const char* str, const char* separator)
61 noexcept(false) {
62
63   a_maxItem = 0;
64
65   //if(str == NULL)
66   //  return 0;
67
68   DataBlock mb(str, anna_strlen(str) + 1, false);
69   a_dataBlock = mb;
70   const char* buffer = a_dataBlock.getData();
71   char *token = const_cast <char*>(buffer);
72   char* last;
73
74   while((token = strtok_r(token, separator, &last)) != NULL) {
75     if(a_activateStrip == true)
76       token = strip(token);
77
78     a_items [a_maxItem ++] = token;
79     token = NULL;
80
81     if(a_maxItem == MaxItem) {
82       string msg("Tokenizer::apply | String: ");
83       msg += str;
84       msg += " | Separator: ";
85       msg += separator;
86       msg += " | Tokenizer has not enough space";
87       throw RuntimeException(msg, ANNA_FILE_LOCATION);
88     }
89   }
90
91   return a_maxItem;
92 }
93
94 int Tokenizer::apply(const char *str, const char* separator, const char *tokenizeContiguous) noexcept(false) {
95
96   if(str == NULL)
97     return 0;
98
99   if (!separator)
100     throw RuntimeException("Cannot tokenize with a NULL separator", ANNA_FILE_LOCATION);
101
102   if (!tokenizeContiguous) return _apply(str, separator);
103
104   std::string _str = str;
105   std::string _sep = separator;
106   std::string _tok = tokenizeContiguous;
107   if (_sep == _tok)
108     throw RuntimeException("Using the separator as artifial token is a nonsense (original behaviour)", ANNA_FILE_LOCATION);
109   if (_tok == "")
110     throw RuntimeException("Use another artifial token. Empty is a nonsense (original behaviour)", ANNA_FILE_LOCATION);
111
112   std::string seps = _sep + _sep;
113   std::size_t pos, sepsL = seps.size();
114   std::string artificialToken = _sep + _tok + _sep;
115
116   while ((pos = _str.find(seps)) != std::string::npos) _str.replace(pos, sepsL, artificialToken); 
117   return _apply(_str.c_str(), separator);
118 }
119
120 const char* Tokenizer::at(const int i)
121 noexcept(false) {
122   if(i >= a_maxItem)
123     indexException(i, ANNA_FILE_LOCATION);
124
125   return data(begin() + i);
126 }
127
128 const char* Tokenizer::at(const int i) const
129 noexcept(false) {
130   if(i >= a_maxItem)
131     indexException(i, ANNA_FILE_LOCATION);
132
133   return data(begin() + i);
134 }
135
136 const char* Tokenizer::last() const
137 noexcept(false) {
138   if(a_maxItem == 0)
139     throw RuntimeException("There is any token to select", ANNA_FILE_LOCATION);
140
141   return data(begin() + a_maxItem - 1);
142 }
143
144 char* Tokenizer::strip(char* str)
145 {
146   char* result(str);
147
148   if(str != NULL) {
149     while(*result != 0 && *result == ' ')
150       result ++;
151
152     if(*result != 0) {
153       char* final = result + anna_strlen(result) - 1;
154
155       while(final > result && *final == ' ') {
156         *final = 0;
157         final --;
158       }
159     }
160   }
161
162   return result;
163 }
164
165 void Tokenizer::indexException(const int index, const char* fromFile, const int fromLine) const
166 noexcept(false) {
167   string msg(functions::asString("Index %d out of range [0,%d] | Items: ", index, a_maxItem));
168
169   for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
170     msg += data(ii);
171     msg += ' ';
172   }
173
174   throw RuntimeException(msg, fromFile, fromLine);
175 }