]>
Commit | Line | Data |
---|---|---|
c90f71dd RD |
1 | /******************************************************************************* |
2 | * Simplified Wrapper and Interface Generator (SWIG) | |
3 | * | |
4 | * Author : David Beazley | |
5 | * | |
6 | * Department of Computer Science | |
7 | * University of Chicago | |
8 | * 1100 E 58th Street | |
9 | * Chicago, IL 60637 | |
10 | * beazley@cs.uchicago.edu | |
11 | * | |
12 | * Please read the file LICENSE for the copyright and terms by which SWIG | |
13 | * can be used and distributed. | |
14 | *******************************************************************************/ | |
15 | ||
16 | #include "internal.h" | |
17 | #include <ctype.h> | |
18 | ||
19 | //----------------------------------------------------------------------- | |
20 | // char *copy_string(char *str) | |
21 | // | |
22 | // Makes a copy of string str. Returns a pointer to it. | |
23 | //----------------------------------------------------------------------- | |
24 | ||
25 | char *copy_string(char *str) { | |
26 | char *res = 0; | |
27 | if (str) { | |
28 | res = new char[strlen(str)+1]; | |
29 | strcpy(res,str); | |
30 | } | |
31 | return res; | |
32 | } | |
33 | ||
34 | //----------------------------------------------------------------------- | |
35 | // void format_string(char *str) | |
36 | // | |
37 | // Replace all of the escape sequences in the string str. It is | |
38 | // assumed that the new string is smaller than the original! | |
39 | //----------------------------------------------------------------------- | |
40 | ||
41 | void format_string(char *str) { | |
42 | char *newstr, *c,*c1; | |
43 | int state; | |
44 | if (!str) return; | |
45 | newstr = copy_string(str); | |
46 | c = newstr; | |
47 | c1 = str; | |
48 | state = 0; | |
49 | while (*c) { | |
50 | switch(state) { | |
51 | case 0: | |
52 | if (*c == '\\') | |
53 | state = 1; | |
54 | else { | |
55 | *(c1++) = *c; | |
56 | state = 0; | |
57 | } | |
58 | break; | |
59 | case 1: | |
60 | // We're in a simple escape sequence figure out what to do | |
61 | switch(*c) { | |
62 | case 'n': | |
63 | *(c1++) = '\n'; | |
64 | break; | |
65 | case 'f': | |
66 | *(c1++) = '\f'; | |
67 | break; | |
68 | case 'r': | |
69 | *(c1++) = '\r'; | |
70 | break; | |
71 | case 't': | |
72 | *(c1++) = '\t'; | |
73 | break; | |
74 | case '\\': | |
75 | *(c1++) = '\\'; | |
76 | break; | |
77 | case '\"': | |
78 | *(c1++) = '\"'; | |
79 | break; | |
80 | case '\'': | |
81 | *(c1++) = '\''; | |
82 | break; | |
83 | default: | |
84 | *(c1++) = '\\'; | |
85 | *(c1++) = *c; | |
86 | } | |
87 | state = 0; | |
88 | break; | |
89 | default: | |
90 | *(c1++) = *c; | |
91 | state = 0; | |
92 | } | |
93 | c++; | |
94 | } | |
95 | *c1 = 0; | |
96 | delete newstr; | |
97 | } | |
98 | ||
99 | // --------------------------------------------------------------------------- | |
100 | // $Header$ | |
101 | // sstring.cxx | |
102 | // | |
103 | // SWIG String class. | |
104 | // This class is used to construct long strings when writing | |
105 | // wrapper functions. It also "mimicks" the C++ streams I/O | |
106 | // library for creating strings. For example : | |
107 | // | |
108 | // str << "hi there" << 3 << "\n"; | |
109 | // | |
110 | // Will append the given strings to str. | |
111 | // | |
112 | // The idea here is to provide a mechanism for writing wrapper | |
113 | // functions as strings before writing them out to a file. | |
114 | // | |
115 | // --------------------------------------------------------------------------- | |
116 | #define INIT_MAXSIZE 64 | |
117 | ||
118 | // --------------------------------------------------------------- | |
119 | // Pools. This is a list of available strings for memory allocation | |
120 | // and deletion. | |
121 | // --------------------------------------------------------------- | |
122 | ||
123 | struct StrMem { | |
124 | char *str; | |
125 | int len; | |
126 | }; | |
127 | ||
128 | #define POOLSIZE 100 | |
129 | ||
130 | static StrMem pool[POOLSIZE]; | |
131 | static int pool_index = 0; | |
132 | ||
133 | // Returns an item from the pool that can accomodate len | |
134 | static char *get_pool(int len, int &newlen) { | |
135 | int i,j; | |
136 | char *nc; | |
137 | if (pool_index < 1) { | |
138 | newlen = len; | |
139 | return new char[len]; | |
140 | } | |
141 | i = pool_index-1; | |
142 | j = 0; | |
143 | while(i >= 0) { | |
144 | if ((pool[i].len >= len) && (pool[i].len <= 4*len)) { | |
145 | nc = pool[i].str; | |
146 | newlen = pool[i].len; | |
147 | pool[i].str = pool[pool_index-1].str; | |
148 | pool[i].len = pool[pool_index-1].len; | |
149 | pool_index--; | |
150 | return nc; | |
151 | } | |
152 | j++; | |
153 | i--; | |
154 | } | |
155 | newlen = len; | |
156 | return new char[len]; | |
157 | } | |
158 | ||
159 | // Puts an item onto the pool | |
160 | ||
161 | static void put_pool(char *str, int len) { | |
162 | if (len < INIT_MAXSIZE) { | |
163 | delete [] str; | |
164 | return; | |
165 | } | |
166 | if (pool_index == POOLSIZE) { | |
167 | delete [] pool[pool_index-1].str; | |
168 | pool_index--; | |
169 | } | |
170 | pool[pool_index].str = str; | |
171 | pool[pool_index].len = len; | |
172 | if (pool_index != POOLSIZE) | |
173 | pool_index++; | |
174 | } | |
175 | ||
176 | // --------------------------------------------------------------- | |
177 | // String::String() | |
178 | // | |
179 | // Create a new string with nothing in it | |
180 | // --------------------------------------------------------------- | |
181 | ||
182 | String::String() { | |
183 | maxsize = INIT_MAXSIZE; | |
184 | str = get_pool(maxsize,maxsize); // May return a pool that is larger | |
185 | str[0] = 0; | |
186 | len = 0; | |
187 | } | |
188 | ||
189 | // --------------------------------------------------------------- | |
190 | // String::String(const char *s) | |
191 | // | |
192 | // Create a new string copied from a normal C-style string | |
193 | // --------------------------------------------------------------- | |
194 | ||
195 | String::String(const char *s) { | |
196 | int max = INIT_MAXSIZE; | |
197 | int l = 0; | |
198 | if (s) { | |
199 | l = (int) strlen(s); | |
200 | if ((l+1) > max) max = l+1; | |
201 | } | |
202 | str = get_pool(max,maxsize); | |
203 | if (s) { | |
204 | strcpy(str,s); | |
205 | len = l; | |
206 | } else { | |
207 | str[0] = 0; | |
208 | len = 0; | |
209 | } | |
210 | } | |
211 | ||
212 | // --------------------------------------------------------------- | |
213 | // String::~String(const char *s) | |
214 | // | |
215 | // Destroy a string | |
216 | // --------------------------------------------------------------- | |
217 | ||
218 | String::~String() { | |
219 | put_pool(str,maxsize); | |
220 | } | |
221 | ||
222 | // --------------------------------------------------------------- | |
223 | // String::add(const char *newstr) | |
224 | // | |
225 | // Concatenate newstr onto the current string | |
226 | // --------------------------------------------------------------- | |
227 | ||
228 | void String::add(const char *newstr) { | |
229 | int newlen; | |
230 | char *nstr = 0; | |
231 | int newmaxsize; | |
232 | int l; | |
233 | ||
234 | l = (int) strlen(newstr); | |
235 | newlen = len+l + 1; | |
236 | if (newlen >= maxsize-1) { | |
237 | newmaxsize = 2*maxsize; | |
238 | if (newlen >= newmaxsize -1) newmaxsize = newlen + 1; | |
239 | nstr = get_pool(newmaxsize,newmaxsize); | |
240 | strcpy(nstr,str); | |
241 | put_pool(str,maxsize); | |
242 | maxsize = newmaxsize; | |
243 | str = nstr; | |
244 | } | |
245 | strcpy(str+len,newstr); | |
246 | len += l; | |
247 | } | |
248 | ||
249 | // --------------------------------------------------------------- | |
250 | // String::add(char) | |
251 | // | |
252 | // Adds a single character to the current string | |
253 | // --------------------------------------------------------------- | |
254 | ||
255 | void String::add(char nc) { | |
256 | int newlen; | |
257 | char *nstr = 0; | |
258 | int newmaxsize; | |
259 | ||
260 | newlen = len+ 1; | |
261 | if (newlen >= maxsize-1) { | |
262 | newmaxsize = 2*maxsize; | |
263 | if (newlen >= newmaxsize -1) newmaxsize = newlen + 1; | |
264 | nstr = get_pool(newmaxsize,newmaxsize); | |
265 | strcpy(nstr,str); | |
266 | put_pool(str,maxsize); | |
267 | maxsize = newmaxsize; | |
268 | str = nstr; | |
269 | } | |
270 | str[len++] = nc; | |
271 | str[len] = 0; | |
272 | } | |
273 | ||
274 | // ----------------------------------------------------------------- | |
275 | // String::insert(const char *newstr) | |
276 | // | |
277 | // Inserts a string into the front of a string. (Primarily used | |
278 | // for documentation generation) | |
279 | // ----------------------------------------------------------------- | |
280 | ||
281 | void String::insert(const char *newstr) { | |
282 | int newlen; | |
283 | char *nstr = 0; | |
284 | int newmaxsize; | |
285 | int i,l; | |
286 | ||
287 | l = strlen(newstr); | |
288 | newlen = len + l + 1; | |
289 | if (newlen >= maxsize-1) { | |
290 | newmaxsize = 2*maxsize; | |
291 | if (newlen >= newmaxsize -1) newmaxsize = newlen + 1; | |
292 | nstr = get_pool(newmaxsize,newmaxsize); | |
293 | strcpy(nstr,str); | |
294 | put_pool(str,maxsize); | |
295 | maxsize = newmaxsize; | |
296 | str = nstr; | |
297 | } | |
298 | ||
299 | /* Shift all of the characters over */ | |
300 | ||
301 | for (i = len -1; i >= 0; i--) { | |
302 | str[i+l] = str[i]; | |
303 | } | |
304 | ||
305 | /* Now insert the new string */ | |
306 | ||
307 | strncpy(str,newstr,l); | |
308 | len += l; | |
309 | str[len] = 0; | |
310 | ||
311 | } | |
312 | ||
313 | // ----------------------------------------------------------------- | |
314 | // char *String::get() | |
315 | // | |
316 | // Get the current value of the string | |
317 | // ----------------------------------------------------------------- | |
318 | ||
319 | char *String::get() const { | |
320 | return str; | |
321 | } | |
322 | ||
323 | // ----------------------------------------------------------------- | |
324 | // String &operator<<(...) | |
325 | // | |
326 | // Shorthand for appending to the end of a string | |
327 | // ----------------------------------------------------------------- | |
328 | ||
329 | String &operator<<(String &t,const char *s) { | |
330 | t.add(s); | |
331 | return t; | |
332 | } | |
333 | ||
334 | ||
335 | String &operator<<(String &t,const char s) { | |
336 | t.add(s); | |
337 | return t; | |
338 | } | |
339 | ||
340 | String &operator<<(String &t,const int a) { | |
341 | char temp[64]; | |
342 | sprintf(temp,"%d",a); | |
343 | t.add(temp); | |
344 | return t; | |
345 | } | |
346 | ||
347 | String &operator<<(String &t, String &s) { | |
348 | t.add(s.get()); | |
349 | return t; | |
350 | } | |
351 | ||
352 | String &String::operator=(const char *s) { | |
353 | int newlen; | |
354 | ||
355 | if (s) { | |
356 | newlen = strlen(s); | |
357 | if ((newlen >= maxsize) && (str)) { | |
358 | put_pool(str,maxsize); | |
359 | str = get_pool(newlen+1,maxsize); | |
360 | maxsize = newlen+1; | |
361 | } | |
362 | strcpy(str,s); | |
363 | len = newlen; | |
364 | } else { | |
365 | str[0] = 0; | |
366 | len = 0; | |
367 | } | |
368 | return *this; | |
369 | } | |
370 | ||
371 | // ----------------------------------------------------------------- | |
372 | // String &operator>>(...) | |
373 | // | |
374 | // Shorthand for inserting into the beginning of a string | |
375 | // ----------------------------------------------------------------- | |
376 | ||
377 | String &operator>>(const char *s, String &t) { | |
378 | t.insert(s); | |
379 | return t; | |
380 | } | |
381 | ||
382 | String &operator>>(String &s, String &t) { | |
383 | t.insert(s.get()); | |
384 | return t; | |
385 | } | |
386 | ||
387 | // ----------------------------------------------------------------- | |
388 | // void String::untabify() | |
389 | // | |
390 | // Expand all tabs into spaces. This is useful for producing | |
391 | // documentation and other things. | |
392 | // ----------------------------------------------------------------- | |
393 | ||
394 | void String::untabify() { | |
395 | char *s; | |
396 | char *c; | |
397 | int pos; | |
398 | int i; | |
399 | int oldmaxsize; | |
400 | // Copy the current string representation | |
401 | ||
402 | s = str; | |
403 | oldmaxsize = maxsize; | |
404 | ||
405 | // Reset the internal state of this string | |
406 | ||
407 | len = 0; | |
408 | str = get_pool(maxsize,maxsize); | |
409 | str[0]= 0; | |
410 | ||
411 | // Now walk down the old string and expand tabs. Tabs are usually place | |
412 | // every 8 characters. | |
413 | ||
414 | pos = 0; | |
415 | c = s; | |
416 | while (*c) { | |
417 | if (*c == '\n') { | |
418 | pos = -1; | |
419 | } | |
420 | if (*c == '\t') { | |
421 | // Expand the character | |
422 | for (i = 0; i < (8 - (pos % 8)); i++) { | |
423 | this->add(' '); | |
424 | } | |
425 | pos+=(8-(pos % 8)); | |
426 | } else { | |
427 | this->add(*c); | |
428 | pos++; | |
429 | } | |
430 | c++; | |
431 | } | |
432 | ||
433 | // Blow away the old string | |
434 | put_pool(s,oldmaxsize); | |
435 | } | |
436 | ||
437 | ||
438 | // ----------------------------------------------------------------- | |
439 | // void String::replace(const char *token, const char *rep) | |
440 | // | |
441 | // Search for tokens in a string and replace them with rep. | |
442 | // This probably isn't the fastest implementation, but fortunately | |
443 | // SWIG rarely calls this function. | |
444 | // ----------------------------------------------------------------- | |
445 | ||
446 | void String::replace(const char *token, const char *rep) { | |
447 | char *s, *c, *t; | |
448 | int oldmaxsize = maxsize; | |
449 | // Copy the current string representation | |
450 | ||
451 | s = str; | |
452 | ||
453 | // Now walk down the old string and search for tokens | |
454 | ||
455 | c = s; | |
456 | t = strstr(c,token); | |
457 | if (t) { | |
458 | len = 0; | |
459 | str = get_pool(maxsize,maxsize); | |
460 | while (t) { | |
461 | // Found a token in string s | |
462 | // Dump characters into our string | |
463 | char temp; | |
464 | temp = *t; | |
465 | *t = 0; | |
466 | this->add(c); | |
467 | c = t; | |
468 | *t = temp; | |
469 | ||
470 | // Now dump the replacement string into place | |
471 | ||
472 | this->add(rep); | |
473 | ||
474 | // Jump over the token | |
475 | ||
476 | c+=strlen(token); | |
477 | t = strstr(c,token); | |
478 | } | |
479 | // Attach rest of the string | |
480 | if (*c) | |
481 | this->add(c); | |
482 | put_pool(s,oldmaxsize); | |
483 | } | |
484 | } | |
485 | ||
486 | ||
487 | // ----------------------------------------------------------------- | |
488 | // void String::replaceid(char *token, char *rep) | |
489 | // | |
490 | // Searches for valid identifiers matching token and replaces | |
491 | // them with rep. Unlike replace() tokens must be a valid C | |
492 | // identifier (surrounded by whitespace). | |
493 | // ----------------------------------------------------------------- | |
494 | ||
495 | void String::replaceid(const char *token, const char *rep) { | |
496 | char *s, *c, *t; | |
497 | int whitespace, tokenlen; | |
498 | int oldmaxsize = maxsize; | |
499 | // Copy the current string representation | |
500 | ||
501 | s = str; | |
502 | ||
503 | // Reset the internal state of this string | |
504 | ||
505 | tokenlen = strlen(token); | |
506 | ||
507 | // Now walk down the old string and search for tokens | |
508 | ||
509 | c = s; | |
510 | t = strstr(c,token); | |
511 | if (t) { | |
512 | len = 0; | |
513 | str = get_pool(maxsize,maxsize); | |
514 | while (t) { | |
515 | // Found a token in string s | |
516 | // Dump characters into our string | |
517 | ||
518 | whitespace = 1; | |
519 | while (c != t) { | |
520 | this->add(*c); | |
521 | if (!(isalpha(*c) || (*c == '_') || (*c == '$'))) whitespace = 1; | |
522 | else whitespace = 0; | |
523 | c++; | |
524 | } | |
525 | ||
526 | if (whitespace) { | |
527 | // Check to see if there is whitespace afterwards | |
528 | if ((!c[tokenlen]) || (!(isalnum(c[tokenlen]) || (c[tokenlen] == '_') || (c[tokenlen] == '$')))) { | |
529 | this->add(rep); | |
530 | } else { | |
531 | this->add(token); | |
532 | } | |
533 | c+=tokenlen; | |
534 | } else { | |
535 | this->add(*c); | |
536 | c++; | |
537 | } | |
538 | t = strstr(c,token); | |
539 | } | |
540 | ||
541 | // Attach rest of the string | |
542 | if (*c) | |
543 | this->add(c); | |
544 | ||
545 | // Delete the old string | |
546 | put_pool(s,oldmaxsize); | |
547 | } | |
548 | } | |
549 | ||
550 | ||
551 | // ----------------------------------------------------------------- | |
552 | // void String::strip() | |
553 | // | |
554 | // Intelligently strips whitespace from a string. Will not strip | |
555 | // whitespace if it is between two characters that are part of a | |
556 | // legal C identifier. For example 'unsigned int'. | |
557 | // ----------------------------------------------------------------- | |
558 | ||
559 | void String::strip() { | |
560 | char *s = str; // Old pointer value | |
561 | char *c, lastchar = 0; | |
562 | int whitespace = 0; | |
563 | int oldmaxsize = maxsize; | |
564 | ||
565 | str = get_pool(maxsize,maxsize); // Get a new string. | |
566 | len = 0; | |
567 | ||
568 | c = s; | |
569 | while(*c) { | |
570 | if (!isspace(*c)) { | |
571 | // See if this character doesn't violate our whitespace rules | |
572 | if (whitespace) { | |
573 | if (isalnum(lastchar) || (lastchar == '_') || (lastchar == '$')) { | |
574 | if (isalnum(*c) || (*c == '_') || (*c == '$')) | |
575 | this->add(' '); | |
576 | } | |
577 | } | |
578 | this->add(*c); | |
579 | lastchar = *c; | |
580 | whitespace = 0; | |
581 | } else { | |
582 | whitespace = 1; | |
583 | } | |
584 | c++; | |
585 | } | |
586 | put_pool(s,oldmaxsize); | |
587 | } |