Edinburgh Speech Tools  2.4-release
 All Classes Functions Variables Typedefs Enumerations Enumerator Friends 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  memcpy(p, from+at, size-at);
333 
334  p += size-at;
335  *p = '\0';
336 
337  if (change > 0)
338  memory = new_memory;
339 
340 
341  size += change;
342  }
343 
344  // cout << "gsub n=" << memory.count() << "\n";
345 
346 #if __GSUB_REENTRANT__
347  if (substitutions)
348  wfree(substitutions);
349 #endif
350 
351  return n;
352 
353 }
354 
355 int EST_String::gsub_internal (EST_Regex &ex, const char *s, int length)
356 {
357 
358  int bracket_num=-1;
359 
360  if (s==NULL)
361  bracket_num = length;
362 
363  int pos=0, n=0, change=0;
364  EST_ChunkPtr new_memory;
365 
366  const char *from;
367  char *to;
368 
369 #if __GSUB_REENTRANT__
370  struct subst *substitutions=NULL;
371 
372  int num_substitutions=0;
373 #endif
374 
375  // printf("match '%s'\n", (const char *)(*this));
376 
377  if (size > 0)
378  {
379  {
380  int start, starts[EST_Regex_max_subexpressions], ends[EST_Regex_max_subexpressions], mlen;
381  while ((start = search(ex, mlen, pos, starts, ends))>=0)
382  {
383  // printf("match %d-%d, %d-%d, %d-%d\n", start, start+mlen, starts[0], ends[0], starts[1], ends[1]);
384  if (num_substitutions <= n)
385  substitutions = wrealloc(substitutions, struct subst, (num_substitutions +=10));
386 
387  substitutions[n].start = start;
388  substitutions[n].end = start+mlen;
389 
390  if (s)
391  change += length - mlen;
392  else
393  {
394  int slen = ends[bracket_num]-starts[bracket_num];
395  change += slen - mlen;
396  substitutions[n].slen = slen;
397  substitutions[n].s = walloc(char, slen);
398  memcpy(substitutions[n].s, (const char *)memory+starts[bracket_num], slen);
399 
400  }
401 
402  n++;
403  pos=start+mlen;
404  }
405  }
406 
407  // dubious dealings with the inside of the string
408 
409  from = (const char *)memory;
410 
411  if (change > 0)
412  {
413  // Spurious braces make temporary ref to chunk go away
414  {new_memory = chunk_allocate(size+change+1);}
415  to = new_memory;
416  }
417  else
418  {
419  cp_make_updatable(memory, size);
420  to = memory;
421  }
422 
423  int i, at=0;
424  char *p=to;
425 
426  for(i=0; i<n; i++)
427  {
428  int start = substitutions[i].start;
429  int end = substitutions[i].end;
430  memcpy(p, from+at, start-at);
431  p += start-at;
432  if (s)
433  {
434  memcpy(p, s, length);
435  p += length;
436  }
437  else
438  {
439  memcpy(p, substitutions[i].s, substitutions[i].slen);
440  wfree(substitutions[i].s);
441  substitutions[i].s=NULL;
442  p += substitutions[i].slen;
443  }
444  at=end;
445  }
446  memcpy(p, from+at, size-at);
447 
448  p += size-at;
449  *p = '\0';
450 
451  if (change > 0)
452  memory = new_memory;
453 
454  size += change;
455  }
456 
457 #if __GSUB_REENTRANT__
458  if (substitutions)
459  wfree(substitutions);
460 #endif
461 
462  return n;
463 
464 }
465 
467  int (&starts)[EST_Regex_max_subexpressions],
468  int (&ends)[EST_Regex_max_subexpressions])
469 {
470  int n=0, change=0;
471  EST_ChunkPtr new_memory;
472 
473  const char *from;
474  char *to;
475 
476 #if __GSUB_REENTRANT__
477  struct subst *substitutions=NULL;
478 
479  int num_substitutions=0;
480 #endif
481 
482  // printf("match '%s'\n", (const char *)(*this));
483 
484  int i;
485  if (size > 0)
486  {
487  int escaped=0;
488 
489  for(i=0; i<size; i++)
490  {
491  if (escaped)
492  {
493  if (memory[i] >= '0' &&memory[i] <= '9')
494  {
495  int snum = memory[i] - '0';
496  if (ends[snum] >= 0 && starts[snum] >=0)
497  {
498  if (num_substitutions <= n)
499  substitutions = wrealloc(substitutions, struct subst, (num_substitutions +=10));
500 
501  substitutions[n].start = i-1;
502  substitutions[n].end = i+1;
503  substitutions[n].s = ((char *)(void *)(const char *)source.memory) + starts[snum];
504  substitutions[n].slen = ends[snum] - starts[snum];
505  change += substitutions[n].slen - 2;
506 
507  n++;
508  }
509  }
510  escaped=0;
511  }
512  else if (memory[i] == '\\')
513  escaped=1;
514  }
515 
516 
517  // dubious dealings with the inside of the string
518 
519  from = (const char *)memory;
520 
521  if (change > 0)
522  {
523  // Spurious braces make temporary ref to chunk go away
524  {new_memory = chunk_allocate(size+change+1);}
525  to = new_memory;
526  }
527  else
528  {
529  cp_make_updatable(memory, size);
530  to = memory;
531  }
532 
533  int at=0;
534  char *p=to;
535 
536  for(i=0; i<n; i++)
537  {
538  int start = substitutions[i].start;
539  int end = substitutions[i].end;
540  memcpy(p, from+at, start-at);
541  p += start-at;
542 
543  memcpy(p, substitutions[i].s, substitutions[i].slen);
544  substitutions[i].s=NULL;
545  p += substitutions[i].slen;
546  at=end;
547  }
548  memcpy(p, from+at, size-at);
549 
550  p += size-at;
551  *p = '\0';
552 
553  if (change > 0)
554  memory = new_memory;
555 
556  size += change;
557  }
558 
559 #if __GSUB_REENTRANT__
560  if (substitutions)
561  wfree(substitutions);
562 #endif
563 
564  return n;
565 }
566 
567 // Pass in the two possible separators as pointers so we don't have to
568 // duplicate all the code. Inline definitions of the friend functions
569 // takes care of the pretty interface.
570 
571 int EST_String::split_internal(EST_String result[], int max,
572  const char *s_seperator, int slen,
573  EST_Regex *re_seperator,
574  char quote) const
575 {
576  int n=0;
577  int pos=0;
578  int start, end;
579  int lastspace=0;
580 
581  if (size>0)
582  {
583  while (pos < length())
584  {
585  start= -1;
586  end= -1;
587  if ((*this)(pos) == quote)
588  {
589  start=pos;
590  pos++;
591  while (pos < length())
592  {
593  if ((*this)(pos) == quote)
594  {
595  pos++;
596  if ((*this)(pos) != quote)
597  break;
598  else
599  pos++;
600  }
601  else
602  pos++;
603  }
604  end=pos;
605  }
606  else
607  {
608  int mstart, mend, matched;
609  if (s_seperator)
610  matched = locate(s_seperator, slen, pos, mstart, mend);
611  else
612  matched = locate(*re_seperator, pos, mstart, mend);
613 
614  if (matched)
615  if (mstart != pos)
616  {
617  start=pos;
618  end=mstart;
619  pos=mend;
620  lastspace=mend;
621  }
622  else if (pos ==lastspace)
623  {
624  start=pos;
625  end=pos;
626  pos=mend;
627  lastspace=mend;
628  }
629  else
630  {
631  pos=mend;
632  lastspace=mend;
633  }
634  else
635  {
636  start=pos;
637  end=length();
638  pos=end;
639  }
640  }
641  if (start>=0)
642  result[n++] = EST_String(*this, start, end-start);
643  if (n==max)
644  break;
645  }
646  }
647 
648  return n;
649 }
650 
651 int EST_String::matches(const char *s, int pos) const
652 {
653  CHECK_STRING_ARG(s);
654 
655  int start, end;
656 
657  if (!s)
658  return 0;
659 
660  int len=safe_strlen(s);
661 
662  if (extract(s, len, pos, start, end))
663  return start==pos && end==len;
664  else
665  return 0;
666 }
667 
668 int EST_String::matches(const EST_String &s, int pos) const
669 {
670  int start, end;
671 
672  if (extract(s.str(), s.size, pos, start, end))
673  return start==pos && end==s.size;
674  else
675  return 0;
676 }
677 
678 int EST_String::matches(EST_Regex &e, int pos, int *starts, int *ends) const
679 {
680  if (size==0)
681  return e.run_match("", pos, starts, ends) >0;
682  else
683  return e.run_match(str(), pos, starts, ends) >0;
684 }
685 
686 
687 EST_String operator + (const EST_String &a, const char *b)
688 {
689  CHECK_STRING_ARG(b);
690 
691  int al = a.size;
692  int bl = safe_strlen(b);
693 
694  if (al == 0)
695  return EST_String(b, 0, bl);
696  if (bl == 0)
697  return EST_String(a);
698 
699  EST_ChunkPtr c = chunk_allocate(al+bl+1, a.str(), al);
700 
701  if (bl>0)
702  memmove((char *)c + al, b, bl);
703  c(al+bl)='\0';
704 
705  return EST_String(al+bl, c);
706 }
707 
708 EST_String operator + (const EST_String &a, const EST_String &b)
709 {
710  int al = a.size;
711  int bl = b.size;
712 
713  if (al == 0)
714  return EST_String(b);
715  if (bl == 0)
716  return EST_String(a);
717 
718  EST_ChunkPtr c = chunk_allocate(al+bl+1, a.str(), al);
719 
720  memmove((char *)c+al,b.str(),bl);
721  c(al+bl)='\0';
722 
723  return EST_String(al+bl, c);
724 }
725 
726 EST_String operator + (const char *a, const EST_String &b)
727 {
728  CHECK_STRING_ARG(a);
729 
730  int al = safe_strlen(a);
731  int bl = b.size;
732 
733  if (bl == 0)
734  return EST_String(a, 0, al);
735  if (al == 0)
736  return EST_String(b);
737 
738  EST_ChunkPtr c = chunk_allocate(al+bl+1, a, al);
739 
740  memmove((char *)c + al, b.str(), bl);
741 
742  c(al+bl)='\0';
743 
744  return EST_String(al+bl, c);
745 }
746 
747 EST_String operator * (const EST_String &s, int n)
748 {
749 
750  if (n<1)
751  return "";
752 
753  int l = s.length();
754  int sz = n * l;
755 
756  EST_String it(NULL, 0, sz);
757 
758  for(int j=0; j<n; j++)
759  strncpy(((char *)it)+j*l, (const char *)s, l);
760 
761  return it;
762 }
763 
765 
766 {
767  CHECK_STRING_ARG(b);
768 
769  int bl = safe_strlen(b);
770 
771  if (size == 0)
772  {
773  memory = chunk_allocate(bl+1, b, bl);
774  size = bl;
775  return *this;
776  }
777 
778  grow_chunk(memory, size, size+bl+1);
779 
780  memmove((char *)memory + size,b,bl);
781  memory(size+bl)='\0';
782  size += bl;
783 
784  return *this;
785 }
786 
788 
789 {
790  int bl = b.size;
791 
792  if (size == 0)
793  {
794  memory = NON_CONST_CHUNKPTR(b.memory);
795  size = b.size;
796  return *this;
797  }
798 
799  grow_chunk(memory, size, size+bl+1);
800 
801  if (bl >0)
802  memmove((char *)memory + size,b.str(),bl);
803 
804  memory(size+bl)='\0';
805  size += bl;
806 
807  return *this;
808 }
809 
810 EST_String::EST_String(const char *s)
811 {
812  CHECK_STRING_ARG(s);
813 
814  size=safe_strlen(s);
815 
816  if (size != 0)
817  memory = chunk_allocate(size+1, s, size);
818  else
819  memory=NULL;
820  }
821 
822 
823 EST_String::EST_String(const char *s, int start_or_fill, int len)
824 {
825 
826  if (s)
827  {
828  int start= start_or_fill;
829  if (len <0)
830  len=safe_strlen(s)-start;
831 
832  size=len;
833  if (size != 0)
834  memory = chunk_allocate(len+1, s+start, len);
835  else
836  memory=NULL;
837  }
838  else
839  {
840  char fill = start_or_fill;
841  if (len<0) len=0;
842  size=len;
843  if (size != 0)
844  {
845  memory = chunk_allocate(len+1);
846  char *p = memory;
847  for(int j=0; j<len;j++)
848  p[j] = fill;
849  p[len]='\0';
850  }
851  else
852  memory=NULL;
853  }
854 }
855 
856 EST_String::EST_String(const char *s, int s_size, int start, int len)
857 {
858  CHECK_STRING_ARG(s);
859 
860  if (len <0)
861  len=s_size-start;
862 
863  size=len;
864  if (size != 0)
865  memory = chunk_allocate(len+1, s+start, len);
866  else
867  memory=NULL;
868 }
869 
870 EST_String::EST_String(const EST_String &s, int start, int len)
871 {
872  if (len <0)
873  len=s.size-start;
874 
875  size=len;
876 
877  if (start == 0 && len == s.size)
878  memory = NON_CONST_CHUNKPTR(s.memory);
879  else if (size != 0)
880  memory = chunk_allocate(len+1, s.memory, start, len);
881  else
882  memory = NULL;
883 }
884 
885 /*
886 EST_String::EST_String(const EST_String &s)
887 {
888 #if 1
889  static EST_ChunkPtr hack = NON_CONST_CHUNKPTR(s.memory);
890  memory = NON_CONST_CHUNKPTR(s.memory);
891  size = s.size;
892 #else
893  *(struct EST_dumb_string *)this = *(struct EST_dumb_string *)(&s);
894 #endif
895 }
896 */
897 
898 #if __FSF_COMPATIBILITY__
899 EST_String::EST_String(const char c)
900 {
901  size=1;
902  memory= chunk_allocate(2, &c, 1);
903 }
904 #endif
905 
907 {
908  CHECK_STRING_ARG(str);
909  int len = safe_strlen(str);
910  if (!len)
911  memory = NULL;
912  else if (!shareing() && len < size)
913  memcpy((char *)memory, str, len+1);
914  else if (len)
915  memory = chunk_allocate(len+1, str, len);
916  size=len;
917  return *this;
918 }
919 
921 {
922  memory = chunk_allocate(2, &c, 1);
923  size=1;
924  return *this;
925 }
926 
928 {
929 #if 1
930 /* static EST_ChunkPtr hack = s.memory; */
931  memory = NON_CONST_CHUNKPTR(s.memory);
932  size = s.size;
933 #else
934  *(struct EST_dumb_string *)this = *(struct EST_dumb_string *)(&s);
935 #endif
936  return *this;
937 }
938 
939 EST_String downcase(const EST_String &s)
940 {
941  EST_String t = EST_String(s.size, chunk_allocate(s.size+1, s.str(), s.size));
942  int i;
943 
944  for (i=0; i < s.length(); i++)
945  if (isupper(s(i)))
946  t[i] = tolower(s(i));
947  else
948  t[i] = s(i);
949  return t;
950 }
951 
952 EST_String upcase(const EST_String &s)
953 {
954  EST_String t = EST_String(s.size, chunk_allocate(s.size+1, s.str(), s.size));
955  int i;
956 
957  for (i=0; i < s.length(); i++)
958  if (islower(s(i)))
959  t[i] = toupper(s(i));
960  else
961  t[i] = s(i);
962  return t;
963 }
964 
965 
966 int
968 {
969  int pos=0;
970  int n=0;
971  int start, end;
972 
973  while (locate(s, pos, start, end))
974  {
975  n++;
976  pos=end;
977  }
978  return n;
979 }
980 
981 int
982 EST_String::freq(const char *s) const
983 {
984  CHECK_STRING_ARG(s);
985 
986  int pos=0;
987  int n=0;
988  int start, end;
989  int len=safe_strlen(s);
990 
991  while (locate(s, len, pos, start, end))
992  {
993  n++;
994  pos=end;
995  }
996  return n;
997 }
998 
999 int
1001 {
1002  int pos=0;
1003  int n=0;
1004  int start, end=0;
1005 
1006  while (locate(ex, pos, start, end))
1007  {
1008  n++;
1009  pos=end;
1010  }
1011  return n;
1012 }
1013 
1014 EST_String EST_String::quote(const char quotec) const
1015 {
1016 
1017  const char quotequote[3] = {quotec, quotec, '\0'};
1018 
1019  EST_String result(*this);
1020 
1021  result.gsub(quotequote+1, quotequote+0);
1022 
1023  return EST_String::cat(quotequote+1, result, quotequote+1);
1024 }
1025 
1026 EST_String EST_String::unquote(const char quotec) const
1027 {
1028 
1029  const char quotequote[3] = {quotec, quotec, '\0'};
1030 
1031  EST_String result(*this);
1032 
1033  // cout << "before unqote '" << result << "'\n";
1034 
1035  result.gsub(quotequote+0, quotequote+1);
1036 
1037  // cout << "after unqote '" << result << "'\n";
1038 
1039  if (result[0] == quotec && result[result.length()-1] == quotec )
1040  {
1041 #if 1
1042  /* Spurious local variable to get arounf SunCC 4.0 being broken */
1043  EST_String res= result.at(1, result.length()-2);
1044  return res;
1045 #else
1046  return result.at(1, result.length()-2);
1047 #endif
1048  }
1049  else
1050  return result;
1051 }
1052 
1053 EST_String EST_String::quote_if_needed(const char quotec) const
1054 {
1055 
1056  if (contains(RXwhite) || contains(quotec))
1057  return quote(quotec);
1058 
1059  return *this;
1060 }
1061 
1062 
1064 {
1065 
1066  if ((*this)(0) == quotec && (*this)(length()-1) == quotec )
1067  return unquote(quotec);
1068 
1069  return *this;
1070 }
1071 
1072 ostream &operator << (ostream &s, const EST_String &str)
1073 
1074 {
1075  if (str.size > 0)
1076  return (s << str.str());
1077  else
1078  return (s << "");
1079 }
1080 
1082  const EST_String s2,
1083  const EST_String s3,
1084  const EST_String s4,
1085  const EST_String s5,
1086  const EST_String s6,
1087  const EST_String s7,
1088  const EST_String s8,
1089  const EST_String s9
1090  )
1091 {
1092  int len=(s1.length()+s2.length()+s3.length()+s4.length()+s5.length() +
1093  s6.length()+s7.length()+s8.length()+s9.length());
1094 
1095  EST_String result;
1096 
1097  result.size=len;
1098  result.memory= chunk_allocate(len+1, (const char *)s1, s1.length());
1099 
1100  int p = s1.length();
1101  if (s2.length())
1102  { strncpy((char *)result.memory + p, (const char *)s2, s2.length()); p += s2.length(); }
1103  if (s3.length())
1104  { strncpy((char *)result.memory + p, (const char *)s3, s3.length()); p += s3.length(); }
1105  if (s4.length())
1106  { strncpy((char *)result.memory + p, (const char *)s4, s4.length()); p += s4.length(); }
1107  if (s5.length())
1108  { strncpy((char *)result.memory + p, (const char *)s5, s5.length()); p += s5.length(); }
1109  if (s6.length())
1110  { strncpy((char *)result.memory + p, (const char *)s6, s6.length()); p += s6.length(); }
1111  if (s7.length())
1112  { strncpy((char *)result.memory + p, (const char *)s7, s7.length()); p += s7.length(); }
1113  if (s8.length())
1114  { strncpy((char *)result.memory + p, (const char *)s8, s8.length()); p += s8.length(); }
1115  if (s9.length())
1116  { strncpy((char *)result.memory + p, (const char *)s9, s9.length()); p += s9.length(); }
1117 
1118  result.memory(p) = '\0';
1119 
1120  return result;
1121 }
1122 
1123 int compare(const EST_String &a, const EST_String &b)
1124 {
1125  if (a.size == 0 && b.size == 0)
1126  return 0;
1127  else if (a.size == 0)
1128  return -1;
1129  else if (b.size == 0)
1130  return 1;
1131  else
1132  return strcmp(a.str(), b.str());
1133 }
1134 
1135 int compare(const EST_String &a, const char *b)
1136 {
1137  if (a.size == 0 && (b==NULL || *b == '\0'))
1138  return 0;
1139  else if (a.size == 0)
1140  return -1;
1141  else if (b == NULL || *b == '\0')
1142  return 1;
1143  else
1144  return strcmp(a.str(), b);
1145 }
1146 
1147 int fcompare(const EST_String &a, const EST_String &b,
1148  const unsigned char *table)
1149 {
1150  if (a.size == 0 && b.size == 0)
1151  return 0;
1152  else if (a.size == 0)
1153  return -1;
1154  else if (b.size == 0)
1155  return 1;
1156  else
1157  return EST_strcasecmp(a.str(), b.str(), table);
1158 }
1159 
1160 int fcompare(const EST_String &a, const char *b,
1161  const unsigned char *table)
1162 {
1163  int bsize = (b ? strlen((const char *)b) : 0);
1164  if (a.size == 0 && bsize == 0)
1165  return 0;
1166  else if (a.size == 0)
1167  return -1;
1168  else if (bsize == 0)
1169  return 1;
1170  else
1171  return EST_strcasecmp(a.str(), (const char *)b, table);
1172 }
1173 
1174 int operator == (const char *a, const EST_String &b)
1175 {
1176  CHECK_STRING_ARG(a);
1177 
1178  if (!a)
1179  return 0;
1180  else if (b.size==0)
1181  return *a == '\0';
1182  else
1183  return (*a == b(0)) && strcmp(a, b.str())==0;
1184 }
1185 
1186 int operator == (const EST_String &a, const EST_String &b)
1187 {
1188  if (a.size==0)
1189  return b.size == 0;
1190  else if (b.size == 0)
1191  return 0;
1192  else
1193  return a.size == b.size && a(0) == b(0) && memcmp(a.str(),b.str(),a.size)==0;
1194 };
1195 
1197 {
1198  char buf[64];
1199  const char *format;
1200 
1201  switch (b)
1202  {
1203  case 8:
1204  format="0%o";
1205  break;
1206  case 10:
1207  format="%d";
1208  break;
1209  case 16:
1210  format="0x%x";
1211  break;
1212  default:
1213  format="??%d??";
1214  break;
1215  }
1216  sprintf(buf, format, i);
1217 
1218  return EST_String(buf);
1219 }
1220 
1222 {
1223  char buf[64];
1224  const char *format;
1225 
1226  switch (b)
1227  {
1228  case 8:
1229  format="0%lo";
1230  break;
1231  case 10:
1232  format="%ld";
1233  break;
1234  case 16:
1235  format="0x%lx";
1236  break;
1237  default:
1238  format="??%ld??";
1239  break;
1240  }
1241  sprintf(buf, format, i);
1242 
1243  return EST_String(buf);
1244 }
1245 
1247 {
1248  char buf[64];
1249 
1250  sprintf(buf, "%f", f);
1251 
1252  return EST_String(buf);
1253 }
1254 
1256 {
1257  char buf[64];
1258 
1259  sprintf(buf, "%f", d);
1260 
1261  return EST_String(buf);
1262 }
1263 
1264 long EST_String::Long(bool *valid) const
1265 {
1266  char *end;
1267 
1268  long val = strtol(str(), &end, 10);
1269 
1270  if (end==NULL|| *end != '\0')
1271  {
1272  if (valid != NULL)
1273  {
1274  *valid=0;
1275  return 0L;
1276  }
1277  else
1278  {
1279  printf("bad integer number format '%s'\n",
1280  (const char *)str());
1281  exit(0);
1282  }
1283  }
1284 
1285  if (valid)
1286  *valid=1;
1287 
1288  return val;
1289 }
1290 
1291 int EST_String::Int(bool *valid) const
1292 {
1293  long val = Long(valid);
1294 
1295  if (valid && !*valid)
1296  return 0L;
1297 
1298  if (val > INT_MAX || val < INT_MIN)
1299  {
1300  if (valid != NULL)
1301  {
1302  *valid=0;
1303  return 0L;
1304  }
1305  else
1306  {
1307  printf("number out of range for integer %ld",
1308  val);
1309  exit(0);
1310  }
1311  }
1312 
1313  return val;
1314 }
1315 
1316 double EST_String::Double(bool *valid) const
1317 {
1318  char *end;
1319 
1320  double val = strtod(str(), &end);
1321 
1322  if (end==NULL|| *end != '\0')
1323  {
1324  if (valid != NULL)
1325  {
1326  *valid=0;
1327  return 0.0;
1328  }
1329  else
1330  {
1331  printf("bad decimal number format '%s'",
1332  (const char *)str());
1333  exit(0);
1334  }
1335  }
1336 
1337  if (valid)
1338  *valid=1;
1339 
1340  return val;
1341 }
1342 
1343 float EST_String::Float(bool *valid) const
1344 {
1345  double val = Double(valid);
1346 
1347  if (valid && !*valid)
1348  return 0.0;
1349 
1350  if (val > FLT_MAX || val < -FLT_MAX)
1351  {
1352  if (valid != NULL)
1353  {
1354  *valid=0;
1355  return 0.0;
1356  }
1357  else
1358  {
1359  printf("number out of range for float %f",
1360  val);
1361  exit(0);
1362  }
1363  }
1364 
1365  return val;
1366 }
1367 
1368 
1369