FOSSology  4.4.0
Open Source License Compliance by Open Source Software
string_operations.c
1 /*
2  Author: Daniele Fognini, Andreas Wuerl
3  SPDX-FileCopyrightText: © 2013-2015 Siemens AG
4 
5  SPDX-License-Identifier: GPL-2.0-only
6 */
7 
8 #define _GNU_SOURCE
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include <stdarg.h>
14 
15 #include "string_operations.h"
16 #include "hash.h"
17 #include "monk.h"
18 
19 #define MAX_TOKENS_ARRAY_SIZE 4194304
20 #define MAX_DELIMIT_LEN 255
21 
22 unsigned splittingDelim(char a, const char* delimiters) {
23  if (a == '\0')
24  return 1;
25  const char * ptr = delimiters;
26  while (*ptr) {
27  if (*ptr == a)
28  return 1;
29  ptr++;
30  }
31 
32  return 0;
33 }
34 
35 unsigned specialDelim(const char* z){
36  char a, b, c;
37  a = *z;
38  b = *(z+1);
39  c = *(z+2);
40  if( a=='/') {
41  if (b=='/' || b=='*')
42  return 2;
43  }
44  else if( a=='*') {
45  if (b=='/')
46  return 2;
47  return 1;
48  }
49  else if( a==':' && b==':') {
50  return 2;
51  }
52  else if ((a==b && b==c) && (a=='"' || a=='\'')) {
53  return 3;
54  }
55  else if (a=='d' && b=='n' && c=='l') {
56  // dnl comments
57  return 3;
58  }
59  return 0;
60 }
61 
62 static inline void initStateToken(Token* stateToken) {
63  stateToken->hashedContent = hash_init();
64  stateToken->length = 0;
65  stateToken->removedBefore = 0;
66 }
67 
68 static int isIgnoredToken(Token* token) {
69  Token remToken;
70 
71 #ifndef MONK_CASE_INSENSITIVE
72  remToken.hashedContent = hash("REM");
73 #else
74  remToken.hashedContent = hash("rem");
75 #endif
76  remToken.length = 3;
77  remToken.removedBefore = 0;
78 
79  return tokenEquals(token, &remToken);
80 }
81 
82 int streamTokenize(const char* inputChunk, size_t inputSize, const char* delimiters, GArray** output, Token** remainder) {
83  GArray* tokens = *output;
84  Token* stateToken;
85 
86  unsigned int initialTokenCount = tokens->len;
87 
88  if (!inputChunk) {
89  if ((stateToken = *remainder)) {
90  if ((stateToken->length > 0) && !isIgnoredToken(stateToken)) {
91  g_array_append_val(tokens, *stateToken);
92  }
93  free(stateToken);
94  }
95  *remainder = NULL;
96  return 0;
97  }
98 
99  if (!*remainder) {
100  //initialize state
101  stateToken = malloc(sizeof (Token));
102  *remainder = stateToken;
103  initStateToken(stateToken);
104  } else {
105  stateToken = *remainder;
106  }
107 
108  if (tokens->len >= MAX_TOKENS_ARRAY_SIZE) {
109  printf("WARNING: stream has more tokens than maximum allowed\n");
110  return -1;
111  }
112 
113  const char* ptr = inputChunk;
114 
115  size_t readBytes = 0;
116  while (readBytes < inputSize) {
117  unsigned delimLen = 0;
118  if (inputSize - readBytes >= 2) {
119  delimLen = specialDelim(ptr);
120  }
121  if (!delimLen) {
122  delimLen = splittingDelim(*ptr, delimiters);
123  }
124 
125  if (delimLen > 0) {
126  if (stateToken->length > 0) {
127  if (isIgnoredToken(stateToken)) {
128  stateToken->removedBefore += stateToken->length;
129  stateToken->length = 0;
130  stateToken->hashedContent = hash_init();
131  } else {
132  g_array_append_val(tokens, *stateToken);
133  initStateToken(stateToken);
134  }
135  }
136 
137  stateToken->removedBefore += delimLen;
138 
139  ptr += delimLen;
140  readBytes += delimLen;
141  } else {
142 #ifndef MONK_CASE_INSENSITIVE
143  const char* newCharPtr = ptr;
144 #else
145  char newChar = g_ascii_tolower(*ptr);
146  const char* newCharPtr = &newChar;
147 #endif
148  hash_add(newCharPtr, &(stateToken->hashedContent));
149 
150  stateToken->length++;
151 
152  ptr += 1;
153  readBytes += 1;
154  }
155  }
156 
157  return tokens->len - initialTokenCount;
158 }
159 
160 GArray* tokenize(const char* inputString, const char* delimiters) {
161  GArray* tokenArray = tokens_new();
162 
163  Token* remainder = NULL;
164 
165  size_t inputLength = strlen(inputString);
166 
167 #define CHUNKS 4096
168  size_t chunksCount = inputLength / CHUNKS;
169  for (size_t i = 0; i < chunksCount; i++) {
170  int addedTokens = streamTokenize(inputString + i * CHUNKS, CHUNKS, delimiters, &tokenArray, &remainder);
171  if (addedTokens < 0) {
172  printf("WARNING: can not complete tokenizing of '%.30s...'\n", inputString);
173  break;
174  }
175  }
176  streamTokenize(inputString + chunksCount * CHUNKS, MIN(CHUNKS, inputLength - chunksCount * CHUNKS),
177  delimiters, &tokenArray, &remainder);
178  streamTokenize(NULL, 0, NULL, &tokenArray, &remainder);
179 #undef CHUNKS
180 
181  return tokenArray;
182 }
183 
184 int tokensEquals(const GArray* a, const GArray* b) {
185  if (b->len != a->len)
186  return 0;
187 
188  for (size_t i = 0; i < a->len; i++) {
189  Token* aToken = tokens_index(a, i);
190  Token* bToken = tokens_index(b, i);
191 
192  if (!tokenEquals(aToken, bToken))
193  return 0;
194  }
195 
196  return 1;
197 }
198 
199 size_t token_position_of(size_t index, const GArray* tokens) {
200  size_t result = 0;
201  size_t previousLength = 0;
202 
203  size_t limit = MIN(index + 1, tokens->len);
204 
205  for (size_t i = 0; i < limit; i++) {
206  Token* token = tokens_index(tokens, i);
207  result += token->removedBefore + previousLength;
208  previousLength = token_length(*token);
209  }
210 
211  if (index == tokens->len) {
212  result += previousLength;
213  }
214 
215  if (index > tokens->len) {
216  result += previousLength;
217  printf("WARNING: requested calculation of token index after the END token\n");
218  }
219 
220  return result;
221 }
222 
223 inline char* normalize_escape_string(char* input)
224 {
225  char* p = input;
226  char* q;
227  char ret[MAX_DELIMIT_LEN];
228  int i = 0;
229  bool flag = false;
230  bool space = false;
231  while (*p)
232  {
233  if (*p == ' ')
234  {
235  space = true;
236  }
237  if (*p == '\\')
238  {
239  q = p + 1;
240  if (*q == 'a')
241  {
242  ret[i] = '\a';
243  flag = true;
244  }
245  else if (*q == 'b')
246  {
247  ret[i] = '\b';
248  flag = true;
249  }
250  else if (*q == 'f')
251  {
252  ret[i] = '\f';
253  flag = true;
254  }
255  else if (*q == 'n')
256  {
257  ret[i] = '\n';
258  flag = true;
259  }
260  else if (*q == 'r')
261  {
262  ret[i] = '\r';
263  flag = true;
264  }
265  else if (*q == 't')
266  {
267  ret[i] = '\t';
268  flag = true;
269  }
270  else if (*q == 'v')
271  {
272  ret[i] = '\v';
273  flag = true;
274  }
275  else if (*q == '\\')
276  {
277  ret[i] = '\\';
278  flag = true;
279  }
280  if (flag == true)
281  {
282  flag = false;
283  p = q + 1;
284  i++;
285  continue;
286  }
287  }
288  ret[i++] = *p;
289  p++;
290  }
291  if (space != true)
292  {
293  ret[i++] = ' ';
294  }
295  ret[i] = '\0';
296  return g_strdup(ret);
297 }
#define MIN(a, b)
Min of two.
Definition: licenses.c:64