Updated license
[anna.git] / source / core / util / Tokenizer.cpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #include <anna/core/util/Tokenizer.hpp>
38 #include <anna/core/functions.hpp>
39 #include <anna/config/defines.hpp>
40
41 using namespace std;
42 using namespace anna;
43
44 //static
45 const int Tokenizer::MaxItem = 64;
46
47 Tokenizer::Tokenizer() :
48   a_dataBlock(true),
49   a_activateStrip(false) {
50   a_items = new char* [MaxItem];
51   anna_memset(a_items, 0, sizeof(char*) * MaxItem);
52   a_maxItem = 0;
53 }
54
55 Tokenizer::Tokenizer(const char* str, const char* separator) :
56   a_dataBlock(true),
57   a_activateStrip(false) {
58   a_items = new char* [MaxItem];
59   anna_memset(a_items, 0, sizeof(char*) * MaxItem);
60   a_maxItem = 0;
61
62   try {
63     apply(str, separator);
64   } catch(Exception&) {
65   }
66 }
67
68 Tokenizer::Tokenizer(const string& str, const char* separator) :
69   a_dataBlock(true),
70   a_activateStrip(false) {
71   a_items = new char* [MaxItem];
72   anna_memset(a_items, 0, sizeof(char*) * MaxItem);
73
74   try {
75     apply(str.c_str(), separator);
76   } catch(Exception&) {
77   }
78 }
79
80 Tokenizer::~Tokenizer() {
81   delete [] a_items;
82 }
83
84 int Tokenizer::apply(const char* str, const char* separator)
85 throw(RuntimeException) {
86   a_maxItem = 0;
87
88   if(str == NULL)
89     return 0;
90
91   DataBlock mb(str, anna_strlen(str) + 1, false);
92   a_dataBlock = mb;
93   const char* buffer = a_dataBlock.getData();
94   char *token = const_cast <char*>(buffer);
95   char* last;
96
97   while((token = strtok_r(token, separator, &last)) != NULL) {
98     if(a_activateStrip == true)
99       token = strip(token);
100
101     a_items [a_maxItem ++] = token;
102     token = NULL;
103
104     if(a_maxItem == MaxItem) {
105       string msg("Tokenizer::apply | String: ");
106       msg += str;
107       msg += " | Separator: ";
108       msg += separator;
109       msg += " | Tokenizer has not enough space";
110       throw RuntimeException(msg, ANNA_FILE_LOCATION);
111     }
112   }
113
114   return a_maxItem;
115 }
116
117 const char* Tokenizer::at(const int i)
118 throw(RuntimeException) {
119   if(i >= a_maxItem)
120     indexException(i, ANNA_FILE_LOCATION);
121
122   return data(begin() + i);
123 }
124
125 const char* Tokenizer::at(const int i) const
126 throw(RuntimeException) {
127   if(i >= a_maxItem)
128     indexException(i, ANNA_FILE_LOCATION);
129
130   return data(begin() + i);
131 }
132
133 const char* Tokenizer::last() const
134 throw(RuntimeException) {
135   if(a_maxItem == 0)
136     throw RuntimeException("There is any token to select", ANNA_FILE_LOCATION);
137
138   return data(begin() + a_maxItem - 1);
139 }
140
141 char* Tokenizer::strip(char* str)
142 throw() {
143   char* result(str);
144
145   if(str != NULL) {
146     while(*result != 0 && *result == ' ')
147       result ++;
148
149     if(*result != 0) {
150       char* final = result + anna_strlen(result) - 1;
151
152       while(final > result && *final == ' ') {
153         *final = 0;
154         final --;
155       }
156     }
157   }
158
159   return result;
160 }
161
162 void Tokenizer::indexException(const int index, const char* fromFile, const int fromLine) const
163 throw(RuntimeException) {
164   string msg(functions::asString("Index %d out of range [0,%d] | Items: ", index, a_maxItem));
165
166   for(const_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
167     msg += data(ii);
168     msg += ' ';
169   }
170
171   throw RuntimeException(msg, fromFile, fromLine);
172 }