Edinburgh Speech Tools  2.1-release
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
EST_String.cc
1  /*************************************************************************/
2  /* */
3  /* Centre for Speech Technology Research */
4  /* University of Edinburgh, UK */
5  /* Copyright (c) 1997 */
6  /* All Rights Reserved. */
7  /* */
8  /* Permission is hereby granted, free of charge, to use and distribute */
9  /* this software and its documentation without restriction, including */
10  /* without limitation the rights to use, copy, modify, merge, publish, */
11  /* distribute, sublicense, and/or sell copies of this work, and to */
12  /* permit persons to whom this work is furnished to do so, subject to */
13  /* the following conditions: */
14  /* 1. The code must retain the above copyright notice, this list of */
15  /* conditions and the following disclaimer. */
16  /* 2. Any modifications must be clearly marked as such. */
17  /* 3. Original authors' names are not deleted. */
18  /* 4. The authors' names are not used to endorse or promote products */
19  /* derived from this software without specific prior written */
20  /* permission. */
21  /* */
22  /* THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK */
23  /* DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING */
24  /* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT */
25  /* SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE */
26  /* FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES */
27  /* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN */
28  /* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, */
29  /* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF */
30  /* THIS SOFTWARE. */
31  /* */
32  /*************************************************************************/
33  /* Authors : Alan W Black (awb@cstr.ed.ac.uk) */
34  /* Date : January, February 1997 */
35  /* -------------------------------------------------------------------- */
36  /* */
37  /* A non-GNU implementation of a EST_String class to use with non-G++ */
38  /* compilers. */
39  /* */
40  /* Note this is not a full implementation of libg++'s EST_String class */
41  /* just the bits we need */
42  /* */
43  /*************************************************************************/
44 
45 
46 #include <iostream>
47 #include <cstring>
48 #include <cstdio>
49 #include <cctype>
50 #include "EST_String.h"
51 // #include "EST_error.h"
52 #include "string_version.h"
53 #include "EST_math.h"
54 
55 extern "C" {
56 #include "regexp.h"
57 }
58 
59 const char *EST_String::version = "CSTR String Class " STRING_VERSION " " STRING_DATE;
60 
62 
63 EST_String EST_String_nullString = "";
64 
65 struct subst {
66  EST_String::EST_string_size start, end;
67  char *s;
68  int slen;
69 } ;
70 
71 #if !__GSUB_REENTRANT__
72 static struct subst *substitutions=NULL;
73 int num_substitutions=0;
74 #endif
75 
76 
77  /********************************************************************\
78  * *
79  * Locate is the basic utility method behind many of the *
80  * manipulations, it finds something in a EST_String, returns a *
81  * success or failure flag and sets start and end to where it was. *
82  * *
83  \********************************************************************/
84 
85 int EST_String::locate(const char *s, int len, int from, int &start, int &end) const
86 {
87  CHECK_STRING_ARG(s);
88 
89  const char *sub=NULL;
90 
91  if (!s)
92  return 0;
93 
94  if (from < 0 && -from < size)
95  {
96  int endpos=size+from+1;
97  int p=0;
98  const char *nextsub;
99 
100  while ((nextsub=strstr(str()+p, s)))
101  {
102  p=nextsub-str()+1;
103  if (p > endpos)
104  break;
105  sub=nextsub;
106  }
107  }
108  else if (from>=0 && from <= size)
109  sub= strstr(str()+from, s);
110 
111  if (sub != NULL)
112  {
113  start = sub-str();
114  end = start + len;
115  return 1;
116  }
117  else
118  {
119  return 0;
120  }
121 
122 }
123 
124 int EST_String::locate(EST_Regex &ex, int from, int &start, int &end, int *starts, int *ends) const
125 {
126  int match_start, match_end;
127 
128  if (from < 0 && -from < size)
129  {
130  int endpos=size+from+1;
131  int p=0;
132  int found=0;
133 
134  while (ex.run(str(), p, match_start, match_end, starts, ends))
135  {
136  found++;
137  start=match_start;
138  end=match_end;
139  p = match_start+1;
140  if (p > endpos)
141  break;
142  }
143  return found >0;
144  }
145  else if (from >=0 && from <= size)
146  {
147  if (ex.run(str(), from, match_start, match_end, starts, ends))
148  {
149  start = match_start;
150  end=match_end;
151  return 1;
152  }
153  else
154  return 0;
155  }
156  else
157  return 0;
158 }
159 
160 int EST_String::extract(const char *s, int len, int pos, int &start, int &end) const
161 {
162  CHECK_STRING_ARG(s);
163 
164  if (!s)
165  return 0;
166 
167  if (pos < 0)
168  return locate(s, len, 0, start, end);
169 
170  if (pos <= size-len && memcmp(str()+pos, s, len)==0)
171  {
172  start = pos;
173  end = pos + len;
174  return 1;
175  }
176  else
177  return 0;
178 }
179 
180 int EST_String::extract(EST_Regex &ex, int pos, int &start, int &end) const
181 {
182  int match_start, match_end;
183 
184  if (pos < 0)
185  return locate(ex, 0, start, end);
186 
187  if (pos < size && ex.run(str(), pos, match_start, match_end) && match_start == pos)
188  {
189  start = match_start;
190  end = match_end;
191  return 1;
192  }
193  else
194  return 0;
195 }
196 
197 EST_String EST_String::chop_internal(int from, int len, EST_chop_direction mode) const
198 {
199  int start, end;
200 
201  if (from < 0)
202  {
203  start = size+from;
204  }
205  else
206  {
207  start = from;
208  }
209 
210  end=start+len;
211 
212  if (start >=0 && end <=size && size > 0)
213  switch (mode)
214  {
215  case Chop_Before:
216  return EST_String(str(), size, 0, start); break;
217  case Chop_At:
218  return EST_String(str(), size, start, end-start); break;
219  case Chop_After:
220  return EST_String(str(), size, end, -1);
221  }
222  return EST_String();
223 
224 }
225 
226 EST_String EST_String::chop_internal(const char *it, int len, int from, EST_chop_direction mode) const
227 {
228  CHECK_STRING_ARG(it);
229 
230  int start, end;
231 
232  if (it && locate(it, len, from, start, end))
233  switch (mode)
234  {
235  case Chop_Before:
236  return EST_String(str(), size, 0, start); break;
237  case Chop_At:
238  return EST_String(str(), size, start, end-start); break;
239  case Chop_After:
240  return EST_String(str(), size, end, -1);
241  }
242  return EST_String();
243 
244 }
245 
246 EST_String EST_String::chop_internal (EST_Regex &it, int from, EST_chop_direction mode) const
247 {
248  int start=0, end=0;
249 
250  if (locate(it, from, start, end))
251  switch (mode)
252  {
253  case Chop_Before:
254  return EST_String(str(), size, 0, start); break;
255  case Chop_At:
256  return EST_String(str(), size, start, end-start); break;
257  case Chop_After:
258  return EST_String(str(), size, end, -1);
259  }
260  return EST_String();
261 
262 }
263 
264 
265 int EST_String::gsub_internal (const char *os, int olength, const char *s, int length)
266 {
267  CHECK_STRING_ARG(os);
268  CHECK_STRING_ARG(s);
269 
270  int pos=0, n=0, change=0;
271  EST_ChunkPtr new_memory;
272 
273  const char *from;
274  char *to;
275 
276 #if __GSUB_REENTRANT__
277  struct subst {
278  EST_String::EST_string_size start, end;
279  } *substitutions=NULL;
280 
281  int num_substitutions=0;
282 #endif
283 
284  if (s && os && size > 0 && *os != '\0')
285  {
286  {
287  int start, end;
288  while (locate(os, olength, pos, start, end))
289  {
290  if (num_substitutions <= n)
291  substitutions = wrealloc(substitutions, struct subst, (num_substitutions +=10));
292 
293  substitutions[n].start = start;
294  substitutions[n].end = end;
295 
296  change += length - (end-start);
297 
298  n++;
299  pos=end;
300  }
301  }
302 
303  // dubious dealings with the inside of the string
304 
305  from = (const char *)memory;
306 
307  if (change > 0)
308  {
309  // Spurious braces make temporary ref to chunk go away
310  {new_memory = chunk_allocate(size+change+1);}
311  to = new_memory;
312  }
313  else
314  {
315  cp_make_updatable(memory, size);
316  to = memory;
317  }
318 
319  int i, at=0;
320  char *p=to;
321 
322  for(i=0; i<n; i++)
323  {
324  int start = substitutions[i].start;
325  int end = substitutions[i].end;
326  memcpy(p, from+at, start-at);
327  p += start-at;
328  memcpy(p, s, length);
329  p += length;
330  at=end;
331  }
332  if (p != from+at)
333  memcpy(p, from+at, size-at);
334 
335  p += size-at;
336  *p = '\0';
337 
338  if (change > 0)
339  memory = new_memory;
340 
341 
342  size += change;
343  }
344 
345  // cout << "gsub n=" << memory.count() << "\n";
346 
347 #if __GSUB_REENTRANT__
348  if (substitutions)
349  wfree(substitutions);
350 #endif
351 
352  return n;
353 
354 }
355 
356 int EST_String::gsub_internal (EST_Regex &ex, const char *s, int length)
357 {
358 
359  int bracket_num=-1;
360 
361  if (s==NULL)
362  bracket_num = length;
363 
364  int pos=0, n=0, change=0;
365  EST_ChunkPtr new_memory;
366 
367  const char *from;
368  char *to;
369 
370 #if __GSUB_REENTRANT__
371  struct subst *substitutions=NULL;
372 
373  int num_substitutions=0;
374 #endif
375 
376  // printf("match '%s'\n", (const char *)(*this));
377 
378  if (size > 0)
379  {
380  {
381  int start, starts[EST_Regex_max_subexpressions], ends[EST_Regex_max_subexpressions], mlen;
382  while ((start = search(ex, mlen, pos, starts, ends))>=0)
383  {
384  // printf("match %d-%d, %d-%d, %d-%d\n", start, start+mlen, starts[0], ends[0], starts[1], ends[1]);
385  if (num_substitutions <= n)
386  substitutions = wrealloc(substitutions, struct subst, (num_substitutions +=10));
387 
388  substitutions[n].start = start;
389  substitutions[n].end = start+mlen;
390 
391  if (s)
392  change += length - mlen;
393  else
394  {
395  int slen = ends[bracket_num]-starts[bracket_num];
396  change += slen - mlen;
397  substitutions[n].slen = slen;
398  substitutions[n].s = walloc(char, slen);
399  memcpy(substitutions[n].s, (const char *)memory+starts[bracket_num], slen);
400 
401  }
402 
403  n++;
404  pos=start+mlen;
405  }
406  }
407 
408  // dubious dealings with the inside of the string
409 
410  from = (const char *)memory;
411 
412  if (change > 0)
413  {
414  // Spurious braces make temporary ref to chunk go away
415  {new_memory = chunk_allocate(size+change+1);}
416  to = new_memory;
417  }
418  else
419  {
420  cp_make_updatable(memory, size);
421  to = memory;
422  }
423 
424  int i, at=0;
425  char *p=to;
426 
427  for(i=0; i<n; i++)
428  {
429  int start = substitutions[i].start;
430  int end = substitutions[i].end;
431  memcpy(p, from+at, start-at);
432  p += start-at;
433  if (s)
434  {
435  memcpy(p, s, length);
436  p += length;
437  }
438  else
439  {
440  memcpy(p, substitutions[i].s, substitutions[i].slen);
441  wfree(substitutions[i].s);
442  substitutions[i].s=NULL;
443  p += substitutions[i].slen;
444  }
445  at=end;
446  }
447  memcpy(p, from+at, size-at);
448 
449  p += size-at;
450  *p = '\0';
451 
452  if (change > 0)
453  memory = new_memory;
454 
455  size += change;
456  }
457 
458 #if __GSUB_REENTRANT__
459  if (substitutions)
460  wfree(substitutions);
461 #endif
462 
463  return n;
464 
465 }
466 
468  int (&starts)[EST_Regex_max_subexpressions],
469  int (&ends)[EST_Regex_max_subexpressions])
470 {
471  int n=0, change=0;
472  EST_ChunkPtr new_memory;
473 
474  const char *from;
475  char *to;
476 
477 #if __GSUB_REENTRANT__
478  struct subst *substitutions=NULL;
479 
480  int num_substitutions=0;
481 #endif
482 
483  // printf("match '%s'\n", (const char *)(*this));
484 
485  int i;
486  if (size > 0)
487  {
488  int escaped=0;
489 
490  for(i=0; i<size; i++)
491  {
492  if (escaped)
493  {
494  if (memory[i] >= '0' &&memory[i] <= '9')
495  {
496  int snum = memory[i] - '0';
497  if (ends[snum] >= 0 && starts[snum] >=0)
498  {
499  if (num_substitutions <= n)
500  substitutions = wrealloc(substitutions, struct subst, (num_substitutions +=10));
501 
502  substitutions[n].start = i-1;
503  substitutions[n].end = i+1;
504  substitutions[n].s = ((char *)(void *)(const char *)source.memory) + starts[snum];
505  substitutions[n].slen = ends[snum] - starts[snum];
506  change += substitutions[n].slen - 2;
507 
508  n++;
509  }
510  }
511  escaped=0;
512  }
513  else if (memory[i] == '\\')
514  escaped=1;
515  }
516 
517 
518  // dubious dealings with the inside of the string
519 
520  from = (const char *)memory;
521 
522  if (change > 0)
523  {
524  // Spurious braces make temporary ref to chunk go away
525  {new_memory = chunk_allocate(size+change+1);}
526  to = new_memory;
527  }
528  else
529  {
530  cp_make_updatable(memory, size);
531  to = memory;
532  }
533 
534  int at=0;
535  char *p=to;
536 
537  for(i=0; i<n; i++)
538  {
539  int start = substitutions[i].start;
540  int end = substitutions[i].end;
541  memcpy(p, from+at, start-at);
542  p += start-at;
543 
544  memcpy(p, substitutions[i].s, substitutions[i].slen);
545  substitutions[i].s=NULL;
546  p += substitutions[i].slen;
547  at=end;
548  }
549  memcpy(p, from+at, size-at);
550 
551  p += size-at;
552  *p = '\0';
553 
554  if (change > 0)
555  memory = new_memory;
556 
557  size += change;
558  }
559 
560 #if __GSUB_REENTRANT__
561  if (substitutions)
562  wfree(substitutions);
563 #endif
564 
565  return n;
566 }
567 
568 // Pass in the two possible separators as pointers so we don't have to
569 // duplicate all the code. Inline definitions of the friend functions
570 // takes care of the pretty interface.
571 
572 int EST_String::split_internal(EST_String result[], int max,
573  const char *s_seperator, int slen,
574  EST_Regex *re_seperator,
575  char quote) const
576 {
577  int n=0;
578  int pos=0;
579  int start, end;
580  int lastspace=0;
581 
582  if (size>0)
583  {
584  while (pos < length())
585  {
586  start= -1;
587  end= -1;
588  if ((*this)(pos) == quote)
589  {
590  start=pos;
591  pos++;
592  while (pos < length())
593  {
594  if ((*this)(pos) == quote)
595  {
596  pos++;
597  if ((*this)(pos) != quote)
598  break;
599  else
600  pos++;
601  }
602  else
603  pos++;
604  }
605  end=pos;
606  }
607  else
608  {
609  int mstart, mend, matched;
610  if (s_seperator)
611  matched = locate(s_seperator, slen, pos, mstart, mend);
612  else
613  matched = locate(*re_seperator, pos, mstart, mend);
614 
615  if (matched)
616  if (mstart != pos)
617  {
618  start=pos;
619  end=mstart;
620  pos=mend;
621  lastspace=mend;
622  }
623  else if (pos ==lastspace)
624  {
625  start=pos;
626  end=pos;
627  pos=mend;
628  lastspace=mend;
629  }
630  else
631  {
632  pos=mend;
633  lastspace=mend;
634  }
635  else
636  {
637  start=pos;
638  end=length();
639  pos=end;
640  }
641  }
642  if (start>=0)
643  result[n++] = EST_String(*this, start, end-start);
644  if (n==max)
645  break;
646  }
647  }
648 
649  return n;
650 }
651 
652 int EST_String::matches(const char *s, int pos) const
653 {
654  CHECK_STRING_ARG(s);
655 
656  int start, end;
657 
658  if (!s)
659  return 0;
660 
661  int len=safe_strlen(s);
662 
663  if (extract(s, len, pos, start, end))
664  return start==pos && end==len;
665  else
666  return 0;
667 }
668 
669 int EST_String::matches(const EST_String &s, int pos) const
670 {
671  int start, end;
672 
673  if (extract(s.str(), s.size, pos, start, end))
674  return start==pos && end==s.size;
675  else
676  return 0;
677 }
678 
679 int EST_String::matches(EST_Regex &e, int pos, int *starts, int *ends) const
680 {
681  if (size==0)
682  return e.run_match("", pos, starts, ends) >0;
683  else
684  return e.run_match(str(), pos, starts, ends) >0;
685 }
686 
687 
688 EST_String operator + (const EST_String &a, const char *b)
689 {
690  CHECK_STRING_ARG(b);
691 
692  int al = a.size;
693  int bl = safe_strlen(b);
694 
695  if (al == 0)
696  return EST_String(b, 0, bl);
697  if (bl == 0)
698  return EST_String(a);
699 
700  EST_ChunkPtr c = chunk_allocate(al+bl+1, a.str(), al);
701 
702  if (bl>0)
703  memmove((char *)c + al, b, bl);
704  c(al+bl)='\0';
705 
706  return EST_String(al+bl, c);
707 }
708 
709 EST_String operator + (const EST_String &a, const EST_String &b)
710 {
711  int al = a.size;
712  int bl = b.size;
713 
714  if (al == 0)
715  return EST_String(b);
716  if (bl == 0)
717  return EST_String(a);
718 
719  EST_ChunkPtr c = chunk_allocate(al+bl+1, a.str(), al);
720 
721  memmove((char *)c+al,b.str(),bl);
722  c(al+bl)='\0';
723 
724  return EST_String(al+bl, c);
725 }
726 
727 EST_String operator + (const char *a, const EST_String &b)
728 {
729  CHECK_STRING_ARG(a);
730 
731  int al = safe_strlen(a);
732  int bl = b.size;
733 
734  if (bl == 0)
735  return EST_String(a, 0, al);
736  if (al == 0)
737  return EST_String(b);
738 
739  EST_ChunkPtr c = chunk_allocate(al+bl+1, a, al);
740 
741  memmove((char *)c + al, b.str(), bl);
742 
743  c(al+bl)='\0';
744 
745  return EST_String(al+bl, c);
746 }
747 
748 EST_String operator * (const EST_String &s, int n)
749 {
750 
751  if (n<1)
752  return "";
753 
754  int l = s.length();
755  int sz = n * l;
756 
757  EST_String it(NULL, 0, sz);
758 
759  for(int j=0; j<n; j++)
760  strncpy(((char *)it)+j*l, (const char *)s, l);
761 
762  return it;
763 }
764 
766 
767 {
768  CHECK_STRING_ARG(b);
769 
770  int bl = safe_strlen(b);
771 
772  if (size == 0)
773  {
774  memory = chunk_allocate(bl+1, b, bl);
775  size = bl;
776  return *this;
777  }
778 
779  grow_chunk(memory, size, size+bl+1);
780 
781  memmove((char *)memory + size,b,bl);
782  memory(size+bl)='\0';
783  size += bl;
784 
785  return *this;
786 }
787 
789 
790 {
791  int bl = b.size;
792 
793  if (size == 0)
794  {
795  memory = NON_CONST_CHUNKPTR(b.memory);
796  size = b.size;
797  return *this;
798  }
799 
800  grow_chunk(memory, size, size+bl+1);
801 
802  if (bl >0)
803  memmove((char *)memory + size,b.str(),bl);
804 
805  memory(size+bl)='\0';
806  size += bl;
807 
808  return *this;
809 }
810 
811 EST_String::EST_String(const char *s)
812 {
813  CHECK_STRING_ARG(s);
814 
815  size=safe_strlen(s);
816 
817  if (size != 0)
818  memory = chunk_allocate(size+1, s, size);
819  else
820  memory=NULL;
821  }
822 
823 
824 EST_String::EST_String(const char *s, int start_or_fill, int len)
825 {
826 
827  if (s)
828  {
829  int start= start_or_fill;
830  if (len <0)
831  len=safe_strlen(s)-start;
832 
833  size=len;
834  if (size != 0)
835  memory = chunk_allocate(len+1, s+start, len);
836  else
837  memory=NULL;
838  }
839  else
840  {
841  char fill = start_or_fill;
842  if (len<0) len=0;
843  size=len;
844  if (size != 0)
845  {
846  memory = chunk_allocate(len+1);
847  char *p = memory;
848  for(int j=0; j<len;j++)
849  p[j] = fill;
850  p[len]='\0';
851  }
852  else
853  memory=NULL;
854  }
855 }
856 
857 EST_String::EST_String(const char *s, int s_size, int start, int len)
858 {
859  CHECK_STRING_ARG(s);
860 
861  if (len <0)
862  len=s_size-start;
863 
864  size=len;
865  if (size != 0)
866  memory = chunk_allocate(len+1, s+start, len);
867  else
868  memory=NULL;
869 }
870 
871 EST_String::EST_String(const EST_String &s, int start, int len)
872 {
873  if (len <0)
874  len=s.size-start;
875 
876  size=len;
877 
878  if (start == 0 && len == s.size)
879  memory = NON_CONST_CHUNKPTR(s.memory);
880  else if (size != 0)
881  memory = chunk_allocate(len+1, s.memory, start, len);
882  else
883  memory = NULL;
884 }
885 
886 /*
887 EST_String::EST_String(const EST_String &s)
888 {
889 #if 1
890  static EST_ChunkPtr hack = NON_CONST_CHUNKPTR(s.memory);
891  memory = NON_CONST_CHUNKPTR(s.memory);
892  size = s.size;
893 #else
894  *(struct EST_dumb_string *)this = *(struct EST_dumb_string *)(&s);
895 #endif
896 }
897 */
898 
899 #if __FSF_COMPATIBILITY__
900 EST_String::EST_String(const char c)
901 {
902  size=1;
903  memory= chunk_allocate(2, &c, 1);
904 }
905 #endif
906 
908 {
909  CHECK_STRING_ARG(str);
910  int len = safe_strlen(str);
911  if (!len)
912  memory = NULL;
913  else if (!shareing() && len < size)
914  memcpy((char *)memory, str, len+1);
915  else if (len)
916  memory = chunk_allocate(len+1, str, len);
917  size=len;
918  return *this;
919 }
920 
922 {
923  memory = chunk_allocate(2, &c, 1);
924  size=1;
925  return *this;
926 }
927 
929 {
930 #if 1
931 /* static EST_ChunkPtr hack = s.memory; */
932  memory = NON_CONST_CHUNKPTR(s.memory);
933  size = s.size;
934 #else
935  *(struct EST_dumb_string *)this = *(struct EST_dumb_string *)(&s);
936 #endif
937  return *this;
938 }
939 
940 EST_String downcase(const EST_String &s)
941 {
942  EST_String t = EST_String(s.size, chunk_allocate(s.size+1, s.str(), s.size));
943  int i;
944 
945  for (i=0; i < s.length(); i++)
946  if (isupper(s(i)))
947  t[i] = tolower(s(i));
948  else
949  t[i] = s(i);
950  return t;
951 }
952 
953 EST_String upcase(const EST_String &s)
954 {
955  EST_String t = EST_String(s.size, chunk_allocate(s.size+1, s.str(), s.size));
956  int i;
957 
958  for (i=0; i < s.length(); i++)
959  if (islower(s(i)))
960  t[i] = toupper(s(i));
961  else
962  t[i] = s(i);
963  return t;
964 }
965 
966 
967 int
969 {
970  int pos=0;
971  int n=0;
972  int start, end;
973 
974  while (locate(s, pos, start, end))
975  {
976  n++;
977  pos=end;
978  }
979  return n;
980 }
981 
982 int
983 EST_String::freq(const char *s) const
984 {
985  CHECK_STRING_ARG(s);
986 
987  int pos=0;
988  int n=0;
989  int start, end;
990  int len=safe_strlen(s);
991 
992  while (locate(s, len, pos, start, end))
993  {
994  n++;
995  pos=end;
996  }
997  return n;
998 }
999 
1000 int
1002 {
1003  int pos=0;
1004  int n=0;
1005  int start, end=0;
1006 
1007  while (locate(ex, pos, start, end))
1008  {
1009  n++;
1010  pos=end;
1011  }
1012  return n;
1013 }
1014 
1015 EST_String EST_String::quote(const char quotec) const
1016 {
1017 
1018  const char quotequote[3] = {quotec, quotec, '\0'};
1019 
1020  EST_String result(*this);
1021 
1022  result.gsub(quotequote+1, quotequote+0);
1023 
1024  return EST_String::cat(quotequote+1, result, quotequote+1);
1025 }
1026 
1027 EST_String EST_String::unquote(const char quotec) const
1028 {
1029 
1030  const char quotequote[3] = {quotec, quotec, '\0'};
1031 
1032  EST_String result(*this);
1033 
1034  // cout << "before unqote '" << result << "'\n";
1035 
1036  result.gsub(quotequote+0, quotequote+1);
1037 
1038  // cout << "after unqote '" << result << "'\n";
1039 
1040  if (result[0] == quotec && result[result.length()-1] == quotec )
1041  {
1042 #if 1
1043  /* Spurious local variable to get arounf SunCC 4.0 being broken */
1044  EST_String res= result.at(1, result.length()-2);
1045  return res;
1046 #else
1047  return result.at(1, result.length()-2);
1048 #endif
1049  }
1050  else
1051  return result;
1052 }
1053 
1054 EST_String EST_String::quote_if_needed(const char quotec) const
1055 {
1056 
1057  if (contains(RXwhite) || contains(quotec))
1058  return quote(quotec);
1059 
1060  return *this;
1061 }
1062 
1063 
1065 {
1066 
1067  if ((*this)(0) == quotec && (*this)(length()-1) == quotec )
1068  return unquote(quotec);
1069 
1070  return *this;
1071 }
1072 
1073 ostream &operator << (ostream &s, const EST_String &str)
1074 
1075 {
1076  if (str.size > 0)
1077  return (s << str.str());
1078  else
1079  return (s << "");
1080 }
1081 
1083  const EST_String s2,
1084  const EST_String s3,
1085  const EST_String s4,
1086  const EST_String s5,
1087  const EST_String s6,
1088  const EST_String s7,
1089  const EST_String s8,
1090  const EST_String s9
1091  )
1092 {
1093  int len=(s1.length()+s2.length()+s3.length()+s4.length()+s5.length() +
1094  s6.length()+s7.length()+s8.length()+s9.length());
1095 
1096  EST_String result;
1097 
1098  result.size=len;
1099  result.memory= chunk_allocate(len+1, (const char *)s1, s1.length());
1100 
1101  int p = s1.length();
1102  if (s2.length())
1103  { strncpy((char *)result.memory + p, (const char *)s2, s2.length()); p += s2.length(); }
1104  if (s3.length())
1105  { strncpy((char *)result.memory + p, (const char *)s3, s3.length()); p += s3.length(); }
1106  if (s4.length())
1107  { strncpy((char *)result.memory + p, (const char *)s4, s4.length()); p += s4.length(); }
1108  if (s5.length())
1109  { strncpy((char *)result.memory + p, (const char *)s5, s5.length()); p += s5.length(); }
1110  if (s6.length())
1111  { strncpy((char *)result.memory + p, (const char *)s6, s6.length()); p += s6.length(); }
1112  if (s7.length())
1113  { strncpy((char *)result.memory + p, (const char *)s7, s7.length()); p += s7.length(); }
1114  if (s8.length())
1115  { strncpy((char *)result.memory + p, (const char *)s8, s8.length()); p += s8.length(); }
1116  if (s9.length())
1117  { strncpy((char *)result.memory + p, (const char *)s9, s9.length()); p += s9.length(); }
1118 
1119  result.memory(p) = '\0';
1120 
1121  return result;
1122 }
1123 
1124 int compare(const EST_String &a, const EST_String &b)
1125 {
1126  if (a.size == 0 && b.size == 0)
1127  return 0;
1128  else if (a.size == 0)
1129  return -1;
1130  else if (b.size == 0)
1131  return 1;
1132  else
1133  return strcmp(a.str(), b.str());
1134 }
1135 
1136 int compare(const EST_String &a, const char *b)
1137 {
1138  if (a.size == 0 && (b==NULL || *b == '\0'))
1139  return 0;
1140  else if (a.size == 0)
1141  return -1;
1142  else if (b == NULL || *b == '\0')
1143  return 1;
1144  else
1145  return strcmp(a.str(), b);
1146 }
1147 
1148 int fcompare(const EST_String &a, const EST_String &b,
1149  const unsigned char *table)
1150 {
1151  if (a.size == 0 && b.size == 0)
1152  return 0;
1153  else if (a.size == 0)
1154  return -1;
1155  else if (b.size == 0)
1156  return 1;
1157  else
1158  return EST_strcasecmp(a.str(), b.str(), table);
1159 }
1160 
1161 int fcompare(const EST_String &a, const char *b,
1162  const unsigned char *table)
1163 {
1164  int bsize = (b ? strlen((const char *)b) : 0);
1165  if (a.size == 0 && bsize == 0)
1166  return 0;
1167  else if (a.size == 0)
1168  return -1;
1169  else if (bsize == 0)
1170  return 1;
1171  else
1172  return EST_strcasecmp(a.str(), (const char *)b, table);
1173 }
1174 
1175 int operator == (const char *a, const EST_String &b)
1176 {
1177  CHECK_STRING_ARG(a);
1178 
1179  if (!a)
1180  return 0;
1181  else if (b.size==0)
1182  return *a == '\0';
1183  else
1184  return (*a == b(0)) && strcmp(a, b.str())==0;
1185 }
1186 
1187 int operator == (const EST_String &a, const EST_String &b)
1188 {
1189  if (a.size==0)
1190  return b.size == 0;
1191  else if (b.size == 0)
1192  return 0;
1193  else
1194  return a.size == b.size && a(0) == b(0) && memcmp(a.str(),b.str(),a.size)==0;
1195 };
1196 
1198 {
1199  char buf[64];
1200  const char *format;
1201 
1202  switch (b)
1203  {
1204  case 8:
1205  format="0%o";
1206  break;
1207  case 10:
1208  format="%d";
1209  break;
1210  case 16:
1211  format="0x%x";
1212  break;
1213  default:
1214  format="??%d??";
1215  break;
1216  }
1217  sprintf(buf, format, i);
1218 
1219  return EST_String(buf);
1220 }
1221 
1223 {
1224  char buf[64];
1225  const char *format;
1226 
1227  switch (b)
1228  {
1229  case 8:
1230  format="0%lo";
1231  break;
1232  case 10:
1233  format="%ld";
1234  break;
1235  case 16:
1236  format="0x%lx";
1237  break;
1238  default:
1239  format="??%ld??";
1240  break;
1241  }
1242  sprintf(buf, format, i);
1243 
1244  return EST_String(buf);
1245 }
1246 
1248 {
1249  char buf[64];
1250 
1251  sprintf(buf, "%f", f);
1252 
1253  return EST_String(buf);
1254 }
1255 
1257 {
1258  char buf[64];
1259 
1260  sprintf(buf, "%f", d);
1261 
1262  return EST_String(buf);
1263 }
1264 
1265 long EST_String::Long(bool *valid) const
1266 {
1267  char *end;
1268 
1269  long val = strtol(str(), &end, 10);
1270 
1271  if (end==NULL|| *end != '\0')
1272  {
1273  if (valid != NULL)
1274  {
1275  *valid=0;
1276  return 0L;
1277  }
1278  else
1279  {
1280  printf("bad integer number format '%s'\n",
1281  (const char *)str());
1282  exit(0);
1283  }
1284  }
1285 
1286  if (valid)
1287  *valid=1;
1288 
1289  return val;
1290 }
1291 
1292 int EST_String::Int(bool *valid) const
1293 {
1294  long val = Long(valid);
1295 
1296  if (valid && !*valid)
1297  return 0L;
1298 
1299  if (val > INT_MAX || val < INT_MIN)
1300  {
1301  if (valid != NULL)
1302  {
1303  *valid=0;
1304  return 0L;
1305  }
1306  else
1307  {
1308  printf("number out of range for integer %ld",
1309  val);
1310  exit(0);
1311  }
1312  }
1313 
1314  return val;
1315 }
1316 
1317 double EST_String::Double(bool *valid) const
1318 {
1319  char *end;
1320 
1321  double val = strtod(str(), &end);
1322 
1323  if (end==NULL|| *end != '\0')
1324  {
1325  if (valid != NULL)
1326  {
1327  *valid=0;
1328  return 0.0;
1329  }
1330  else
1331  {
1332  printf("bad decimal number format '%s'",
1333  (const char *)str());
1334  exit(0);
1335  }
1336  }
1337 
1338  if (valid)
1339  *valid=1;
1340 
1341  return val;
1342 }
1343 
1344 float EST_String::Float(bool *valid) const
1345 {
1346  double val = Double(valid);
1347 
1348  if (valid && !*valid)
1349  return 0.0;
1350 
1351  if (val > FLT_MAX || val < -FLT_MAX)
1352  {
1353  if (valid != NULL)
1354  {
1355  *valid=0;
1356  return 0.0;
1357  }
1358  else
1359  {
1360  printf("number out of range for float %f",
1361  val);
1362  exit(0);
1363  }
1364  }
1365 
1366  return val;
1367 }
1368 
1369 
1370 
EST_String unquote(const char quotec) const
Remove quotes and unprotect internal quotes.
Definition: EST_String.cc:1027
EST_String(void)
Construct an empty string.
Definition: EST_String.h:206
int subst(EST_String source, int(&starts)[EST_Regex_max_subexpressions], int(&ends)[EST_Regex_max_subexpressions])
Substitute the result of a match into a string.
Definition: EST_String.cc:467
EST_String quote_if_needed(const char quotec) const
Return in quotes if there is something to protect (e.g. spaces)
Definition: EST_String.cc:1054
static EST_String Number(int i, int base=10)
Build string from an integer.
Definition: EST_String.cc:1197
A Regular expression class to go with the CSTR EST_String class.
Definition: EST_Regex.h:56
static const char * version
Global version string.
Definition: EST_String.h:113
static EST_String cat(const EST_String s1, const EST_String s2=Empty, const EST_String s3=Empty, const EST_String s4=Empty, const EST_String s5=Empty, const EST_String s6=Empty, const EST_String s7=Empty, const EST_String s8=Empty, const EST_String s9=Empty)
Definition: EST_String.cc:1082
int freq(const char *s) const
Number of occurrences of substring.
Definition: EST_String.cc:983
int gsub(const char *os, const EST_String &s)
Substitute one string for another.
Definition: EST_String.h:404
int EST_string_size
Type of string size field.
Definition: EST_String.h:119
int length(void) const
Length of string ({not} length of underlying chunk)
Definition: EST_String.h:244
EST_String & operator+=(const char *b)
Add C string to end of EST_String.
Definition: EST_String.cc:765
int run(const char *on, int from, int &start, int &end, int *starts=NULL, int *ends=NULL)
Run to find a matching substring.
Definition: EST_Regex.cc:242
int contains(const char *s, int pos=-1) const
Does it contain this substring?
Definition: EST_String.h:378
EST_String & operator=(const char *str)
Assign C string to EST_String.
Definition: EST_String.cc:907
const char * str(void) const
Get a const-pointer to the actual memory.
Definition: EST_String.h:248
EST_String unquote_if_needed(const char quotec) const
Remove quotes if any.
Definition: EST_String.cc:1064
int run_match(const char *on, int from=0, int *starts=NULL, int *ends=NULL)
Run to see if it matches the entire string.
Definition: EST_Regex.cc:275
int search(const char *s, int len, int &mlen, int pos=0) const
Find a substring.
Definition: EST_String.h:337
EST_String at(int from, int len=0) const
Return part at position.
Definition: EST_String.h:305
EST_String quote(const char quotec) const
Return the string in quotes with internal quotes protected.
Definition: EST_String.cc:1015
int matches(const char *e, int pos=0) const
Exactly match this string?
Definition: EST_String.cc:652
static const EST_String Empty
Constant empty string.
Definition: EST_String.h:116