1 /*  Part of XPCE --- The SWI-Prolog GUI toolkit
2 
3     Author:        Jan Wielemaker and Anjo Anjewierden
4     E-mail:        jan@swi.psy.uva.nl
5     WWW:           http://www.swi.psy.uva.nl/projects/xpce/
6     Copyright (c)  1985-2002, University of Amsterdam
7     All rights reserved.
8 
9     Redistribution and use in source and binary forms, with or without
10     modification, are permitted provided that the following conditions
11     are met:
12 
13     1. Redistributions of source code must retain the above copyright
14        notice, this list of conditions and the following disclaimer.
15 
16     2. Redistributions in binary form must reproduce the above copyright
17        notice, this list of conditions and the following disclaimer in
18        the documentation and/or other materials provided with the
19        distribution.
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
24     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25     COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32     POSSIBILITY OF SUCH DAMAGE.
33 */
34 
35 #include <h/kernel.h>
36 #include <h/str.h>
37 
38 #undef min
39 #define min(a, b) ((a) < (b) ? (a) : (b))
40 
41 #define sameEncoding(s1, s2) \
42 	if ( s1->iswide != s2->iswide ) \
43 	  return FALSE;
44 
45 
46 		 /*******************************
47 		 *	       ALLOC		*
48 		 *******************************/
49 
50 inline int
str_allocsize(PceString s)51 str_allocsize(PceString s)
52 { int len;
53 
54   len = isstrA(s) ? s->s_size : s->s_size*sizeof(charW);
55 
56   return ((len + sizeof(long))/sizeof(long))*sizeof(long);
57 }
58 
59 
60 inline void
str_pad(PceString s)61 str_pad(PceString s)			/* only 8-bit strings */
62 { if ( isstrA(s) )
63   { int from = s->s_size;
64     int len  = str_allocsize(s);
65 
66     while(from < len)
67       s->s_textA[from++] = '\0';
68   } else
69   { int from = s->s_size;
70     int len  = str_allocsize(s)/sizeof(charW);
71 
72     while(from < len)
73       s->s_textW[from++] = '\0';
74   }
75 }
76 
77 
78 void
str_alloc(PceString s)79 str_alloc(PceString s)
80 { s->s_textA  = alloc(str_allocsize(s));
81   s->s_readonly = FALSE;
82   str_pad(s);
83 }
84 
85 
86 #define STR_RING_SIZE 16
87 static char *str_ring[STR_RING_SIZE] = {NULL};
88 int    str_ring_ptr = 0;
89 
90 static void
str_ring_alloc(PceString s)91 str_ring_alloc(PceString s)
92 { int size = str_allocsize(s);
93 
94   if ( !str_ring[str_ring_ptr] )
95   { str_ring[str_ring_ptr] = pceMalloc(size);
96   } else
97   { str_ring[str_ring_ptr] = pceRealloc(str_ring[str_ring_ptr], size);
98   }
99   s->s_textA = (charA*)str_ring[str_ring_ptr];
100   s->s_readonly = TRUE;
101 
102   if ( ++str_ring_ptr == STR_RING_SIZE )
103     str_ring_ptr = 0;
104 }
105 
106 
107 void
str_unalloc(PceString s)108 str_unalloc(PceString s)
109 { if ( s->s_textA && !s->s_readonly )
110   { unalloc(str_allocsize(s), s->s_textA);
111     s->s_textA = NULL;
112   }
113 }
114 
115 
116 PceString
str_init(PceString s,PceString proto,charA * data)117 str_init(PceString s, PceString proto, charA *data)
118 { str_cphdr(s, proto);
119   s->s_text = data;
120 
121   return s;
122 }
123 
124 
125 PceString
fstr_inithdr(PceString s,int iswide,void * data,int len)126 fstr_inithdr(PceString s, int iswide, void *data, int len)
127 { str_inithdr(s, iswide);
128   s->s_text = data;
129   s->s_size = len;
130 
131   return s;
132 }
133 
134 
135 status
str_set_n_ascii(PceString str,size_t len,char * text)136 str_set_n_ascii(PceString str, size_t len, char *text)
137 { if ( len > STR_MAX_SIZE )
138     return errorPce(NIL, NAME_stringTooLong, toInt(len));
139 
140   str_inithdr(str, FALSE);
141   str->s_size = (int)len;
142   str->s_textA = (charA *) text;
143 
144   succeed;
145 }
146 
147 
148 status
str_set_n_wchar(PceString str,size_t len,wchar_t * text)149 str_set_n_wchar(PceString str, size_t len, wchar_t *text)
150 { if ( len > STR_MAX_SIZE )
151     return errorPce(NIL, NAME_stringTooLong, toInt(len));
152 
153   str_inithdr(str, TRUE);
154   str->s_size = (int)len;
155   str->s_textW = text;
156 
157   succeed;
158 }
159 
160 
161 status
str_set_ascii(PceString str,char * text)162 str_set_ascii(PceString str, char *text)
163 { size_t len = strlen(text);
164 
165   return str_set_n_ascii(str, len, text);
166 }
167 
168 
169 status
str_set_utf8(PceString str,const char * text)170 str_set_utf8(PceString str, const char *text)
171 { const char *s = text;
172   const char *e = &text[strlen(s)];
173   int iswide = FALSE;
174   int len = 0;
175 
176   while(s<e)
177   { int chr;
178 
179     s = utf8_get_char(s, &chr);
180     if ( chr > 0xff )
181       iswide = TRUE;
182     len++;
183   }
184 
185   str_inithdr(str, iswide);
186   str->s_size = len;
187   str_ring_alloc(str);			/* NOTE: temporary space */
188 
189   for(len=0, s=text; s<e; len++)
190   { int chr;
191 
192     s = utf8_get_char(s, &chr);
193     str_store(str, len, chr);
194   }
195 
196   succeed;
197 }
198 
199 
200 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
201 str_set_static(): initialise a string from a static C-string
202 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
203 
204 status
str_set_static(PceString str,const char * text)205 str_set_static(PceString str, const char *text)
206 { size_t len = strlen(text);
207 
208   if ( len > STR_MAX_SIZE )
209     return errorPce(NIL, NAME_stringTooLong, toInt(len));
210 
211   str_inithdr(str, FALSE);
212   str->s_readonly = TRUE;
213   str->s_size = (int)len;
214   str->s_textA = (charA *) text;
215 
216   succeed;
217 }
218 
219 
220 status
str_iswide(PceString s)221 str_iswide(PceString s)
222 { if ( s->s_iswide )
223   { const charW *w = s->s_textW;
224     const charW *e = &w[s->s_size];
225 
226     while(w<e)
227     { if ( *w++ > 0xff )
228 	succeed;
229     }
230   }
231 
232   fail;
233 }
234 
235 
236 
237 		 /*******************************
238 		 *	     COPY STUFF		*
239 		 *******************************/
240 
241 void
str_ncpy(PceString dest,int at,PceString src,int from,int len)242 str_ncpy(PceString dest, int at, PceString src, int from, int len)
243 { if ( dest->s_iswide == src->s_iswide )	/* same size */
244   { if ( isstrA(dest) )
245       memcpy(&dest->s_textA[at], &src->s_textA[from], len * sizeof(charA));
246     else
247       cpdata(&dest->s_textW[at], &src->s_textW[from], charW, len);
248   } else if ( dest->s_iswide )		/* 8bit --> wide */
249   { const charA *s = &src->s_textA[from];
250     const charA *e = &s[len];
251     charW *d = &dest->s_textW[at];
252 
253     while(s<e)
254       *d++ = *s++;
255   } else				/* wide --> 8bit (may truncate) */
256   { const charW *s = &src->s_textW[from];
257     const charW *e = &s[len];
258     charA *d = &dest->s_textA[at];
259 
260     while(s<e)
261       *d++ = *s++;
262   }
263 }
264 
265 
266 void
str_cpy(PceString dest,PceString src)267 str_cpy(PceString dest, PceString src)
268 { str_cphdr(dest, src);
269   str_ncpy(dest, 0, src, 0, src->s_size);
270 }
271 
272 
273 charA *
str_textp(PceString s,int i)274 str_textp(PceString s, int i)
275 { return isstrA(s) ? &s->s_textA[i] : (charA *)&s->s_textW[i];
276 }
277 
278 
279 		 /*******************************
280 		 *	CASE MANIPULATION	*
281 		 *******************************/
282 
283 void
str_upcase(PceString str,int from,int to)284 str_upcase(PceString str, int from, int to)
285 { if ( isstrA(str) )
286   { charA *s = &str->s_textA[from];
287 
288     for(; from < to; from++, s++)
289       *s = toupper(*s);
290   } else
291   { charW *s = &str->s_textW[from];
292 
293     for(; from < to; from++, s++)
294       *s = towupper(*s);
295   }
296 }
297 
298 
299 void
str_downcase(PceString str,int from,int to)300 str_downcase(PceString str, int from, int to)
301 { if ( isstrA(str) )
302   { charA *s = &str->s_textA[from];
303 
304     for(; from < to; from++, s++)
305       *s = tolower(*s);
306   } else
307   { charW *s = &str->s_textW[from];
308 
309     for(; from < to; from++, s++)
310       *s = towlower(*s);
311   }
312 }
313 
314 
315 		 /*******************************
316 		 *	      COMPARE		*
317 		 *******************************/
318 
319 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
320 int str_cmp(PceString s1, PceString s2)
321     returns < 0 if s1 is before s2, == 0 if equal and > 0 if s2 is
322     before s2.
323 
324 int str_eq(PceString s1, PceString s2)
325     returns != 0 if s1 equals s2.
326 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
327 
328 int
str_cmp(PceString s1,PceString s2)329 str_cmp(PceString s1, PceString s2)
330 { int n = min(s1->s_size, s2->s_size);
331 
332   if ( s1->s_iswide == s2->s_iswide )
333   { if ( isstrA(s1) )
334     { int d;
335 
336       if ( (d=strncmp((const char*)s1->s_textA, (const char*)s2->s_textA, n)) == 0 )
337 	return s1->s_size - s2->s_size;
338 
339       return d;
340     } else
341     { charW *d1 = s1->s_textW;
342       charW *d2 = s2->s_textW;
343       int d;
344 
345       while(n-- > 0)
346 	if ( (d = (*d1++ - *d2++)) )
347 	  return d;
348 
349       return s1->s_size - s2->s_size;
350     }
351   } else				/* inconsistent encoding */
352   { int i;
353 
354     for(i=0; i<n; i++)
355     { wint_t c1 = str_fetch(s1, i);
356       wint_t c2 = str_fetch(s2, i);
357 
358       if ( c1 != c2 )
359 	return c1 -c2;
360     }
361 
362     return s1->s_size - s2->s_size;
363   }
364 }
365 
366 
367 int
str_icase_cmp(PceString s1,PceString s2)368 str_icase_cmp(PceString s1, PceString s2)
369 { int n = min(s1->s_size, s2->s_size);
370 
371   if ( s1->s_iswide == s2->s_iswide )
372   { if ( isstrA(s1) )
373     { charA *d1 = s1->s_textA;
374       charA *d2 = s2->s_textA;
375       int d;
376 
377       for(; n-- > 0; d1++, d2++)
378 	if ( (d = (tolower(*d1) - tolower(*d2))) )
379 	  return d;
380 
381       return s1->s_size - s2->s_size;
382     } else
383     { charW *d1 = s1->s_textW;
384       charW *d2 = s2->s_textW;
385       int d;
386 
387       for(; n-- > 0; d1++, d2++)
388 	if ( (d = (towlower(*d1) - towlower(*d2))) )
389 	  return d;
390 
391       return s1->s_size - s2->s_size;
392     }
393   } else
394   { int i;
395 
396     for(i=0; i<n; i++)
397     { wint_t c1 = towlower(str_fetch(s1, i));
398       wint_t c2 = towlower(str_fetch(s2, i));
399 
400       if ( c1 != c2 )
401 	return c1 -c2;
402     }
403 
404     return s1->s_size - s2->s_size;
405   }
406 }
407 
408 
409 int
str_eq(PceString s1,PceString s2)410 str_eq(PceString s1, PceString s2)
411 { if ( s1->s_size == s2->s_size )
412     return str_cmp(s1, s2) == 0;
413 
414   return FALSE;
415 }
416 
417 
418 int
str_icase_eq(PceString s1,PceString s2)419 str_icase_eq(PceString s1, PceString s2)
420 { if ( s1->s_size == s2->s_size )
421     return str_icase_cmp(s1, s2) == 0;
422 
423   return FALSE;
424 }
425 
426 
427 int					/* s2 is prefix of s1+offset */
str_prefix_offset(PceString s1,unsigned int offset,PceString s2)428 str_prefix_offset(PceString s1, unsigned int offset, PceString s2)
429 { if ( s2->s_size <= s1->s_size-offset )
430   { int n = s2->s_size;
431 
432     if ( isstrA(s1) && isstrA(s2) )
433     { charA *d1 = s1->s_textA+offset;
434       charA *d2 = s2->s_textA;
435 
436       while(n-- > 0)
437 	if ( *d1++ != *d2++ )
438 	  return FALSE;
439 
440       return TRUE;
441     } else
442     { int i;
443 
444       for(i=0; i<n; i++)
445 	if ( str_fetch(s1, i+offset) != str_fetch(s2, i) )
446 	  return FALSE;
447     }
448 
449     return TRUE;
450   }
451 
452   return FALSE;
453 }
454 
455 
456 int
str_prefix(PceString s1,PceString s2)457 str_prefix(PceString s1, PceString s2)	/* s2 is prefix of s1 */
458 { return str_prefix_offset(s1, 0, s2);
459 }
460 
461 
462 int
str_icase_prefix(PceString s1,PceString s2)463 str_icase_prefix(PceString s1, PceString s2)	/* s2 is prefix of s1 */
464 { if ( s2->s_size <= s1->s_size )
465   { int n = s2->s_size;
466 
467     if ( isstrA(s1) && isstrA(s2) )
468     { charA *d1 = s1->s_textA;
469       charA *d2 = s2->s_textA;
470 
471       for(; n-- > 0; d1++, d2++)
472 	if ( tolower(*d1) != tolower(*d2) )
473 	  return FALSE;
474     } else
475     { int i = 0;
476 
477       for(; n-- > 0; i++)
478 	if ( towlower(str_fetch(s1, i)) != towlower(str_fetch(s2, i)) )
479 	  return FALSE;
480     }
481 
482     return TRUE;
483   }
484 
485   return FALSE;
486 }
487 
488 
489 int
str_suffix(PceString s1,PceString s2)490 str_suffix(PceString s1, PceString s2)	/* s2 is suffix of s1 */
491 { if ( s2->s_size <= s1->s_size )
492   { int n = s2->s_size;
493     int offset = s1->s_size - s2->s_size;
494 
495     if ( isstrA(s1) && isstrA(s2) )
496     { charA *d1 = &s1->s_textA[offset];
497       charA *d2 = s2->s_textA;
498 
499       while(n-- > 0)
500 	if ( *d1++ != *d2++ )
501 	  return FALSE;
502 
503       return TRUE;
504     } else
505     { while(--n >= 0)
506 	if ( str_fetch(s1, n+offset) != str_fetch(s2, n) )
507 	  return FALSE;
508 
509       return TRUE;
510     }
511   }
512 
513   return FALSE;
514 }
515 
516 
517 int
str_icase_suffix(PceString s1,PceString s2)518 str_icase_suffix(PceString s1, PceString s2)	/* s2 is suffix of s1 */
519 { if ( s2->s_size <= s1->s_size )
520   { int n = s2->s_size;
521     int offset = s1->s_size - s2->s_size;
522 
523     if ( isstrA(s1) && isstrA(s2) )
524     { charA *d1 = &s1->s_textA[offset];
525       charA *d2 = s2->s_textA;
526 
527       for( ; n-- > 0; d1++, d2++)
528       { if ( tolower(*d1) != tolower(*d2) )
529 	  return FALSE;
530       }
531 
532       return TRUE;
533     } else
534     { int i = 0;
535 
536       for( ; n-- > 0; i++)
537       { if ( towlower(str_fetch(s1, i)) != towlower(str_fetch(s2, i)) )
538 	  return FALSE;
539       }
540     }
541 
542     return TRUE;
543   }
544 
545   return FALSE;
546 }
547 
548 
549 int
str_sub(PceString s1,PceString s2)550 str_sub(PceString s1, PceString s2)		/* s2 is substring of s1 */
551 { if ( s2->s_size <= s1->s_size )
552   { int n = 0;
553     int m = s1->s_size - s2->s_size;
554 
555     if ( s1->s_iswide == s2->s_iswide )
556     { if ( isstrA(s1) )
557       { for(; n <= m; n++)
558 	{ charA *d1 = &s1->s_textA[n];
559 	  charA *d2 = s2->s_textA;
560 	  int i = s2->s_size;
561 
562 	  while( i-- > 0 )
563 	    if ( *d1++ != *d2++ )
564 	      goto next8;
565 
566 	  return TRUE;
567 	next8:;
568 	}
569       } else
570       { for(; n <= m; n++)
571 	{ charW *d1 = &s1->s_textW[n];
572 	  charW *d2 = s2->s_textW;
573 	  int i = s2->s_size;
574 
575 	  while( i-- > 0 )
576 	    if ( *d1++ != *d2++ )
577 	      goto next16;
578 
579 	  return TRUE;
580 	next16:;
581 	}
582       }
583     } else
584     { for(; n <= m; n++)
585       { int i1 = n;
586 	int i2 = 0;
587 	int i = s2->s_size;
588 
589 	for( ; i-- > 0; i1++, i2++ )
590 	  if ( str_fetch(s1, i1) != str_fetch(s2, i2) )
591 	    goto nextmixed;
592 
593 	return TRUE;
594       nextmixed:;
595       }
596     }
597   }
598 
599   return FALSE;
600 }
601 
602 
603 int
str_icasesub(PceString s1,PceString s2)604 str_icasesub(PceString s1, PceString s2)		/* s2 is substring of s1 */
605 { if ( s2->s_size <= s1->s_size )
606   { int n = 0;
607     int m = s1->s_size - s2->s_size;
608 
609     if ( s1->s_iswide == s2->s_iswide )
610     { if ( isstrA(s1) )
611       { for(; n <= m; n++)
612 	{ charA *d1 = &s1->s_textA[n];
613 	  charA *d2 = s2->s_textA;
614 	  int i;
615 
616 	  for(i=s2->s_size; i-- > 0; d1++, d2++ )
617 	  { if ( tolower(*d1) != tolower(*d2) )
618 	      goto next8;
619 	  }
620 
621 	  return TRUE;
622 	next8:;
623 	}
624       } else
625       { for(; n <= m; n++)
626 	{ charW *d1 = &s1->s_textW[n];
627 	  charW *d2 = s2->s_textW;
628 	  int i;
629 
630 	  for(i=s2->s_size; i-- > 0; d1++, d2++ )
631 	  { if ( towlower(*d1) != towlower(*d2) )
632 	      goto next16;
633 	  }
634 
635 	  return TRUE;
636 	next16:;
637 	}
638       }
639     } else
640     { for(; n <= m; n++)
641       { int i1 = n;
642 	int i2 = 0;
643 	int i = s2->s_size;
644 
645 	for( ; i-- > 0; i1++, i2++ )
646 	  if ( towlower(str_fetch(s1, i1)) != towlower(str_fetch(s2, i2)) )
647 	    goto nextmixed;
648 
649 	return TRUE;
650       nextmixed:;
651       }
652     }
653   }
654 
655   return FALSE;
656 }
657 
658 
659 int
str_next_index(PceString s,int from,wint_t chr)660 str_next_index(PceString s, int from, wint_t chr)
661 { int i, n = s->s_size;
662 
663   if ( isstrA(s) )
664   { charA *d = &s->s_textA[from];
665 
666     for(i=from; i<n; i++, d++)
667       if ( *d == chr )
668 	return i;
669   } else
670   { charW *d = &s->s_textW[from];
671 
672     for(i=from; i<n; i++, d++)
673       if ( (wint_t)*d == chr )
674 	return i;
675   }
676 
677   return -1;
678 }
679 
680 
681 int
str_next_rindex(PceString s,int from,wint_t chr)682 str_next_rindex(PceString s, int from, wint_t chr)
683 { int i;
684 
685   if ( isstrA(s) )
686   { charA *d = &s->s_textA[from];
687 
688     for(i=from; i >= 0; i--, d--)
689       if ( *d == chr )
690 	return i;
691   } else
692   { charW *d = &s->s_textW[from];
693 
694     for(i=from; i >= 0; i--, d--)
695       if ( (wint_t)*d == chr )
696 	return i;
697   }
698 
699   return -1;
700 }
701 
702 
703 int
str_index(PceString s,wint_t chr)704 str_index(PceString s, wint_t chr)
705 { return str_next_index(s, 0, chr);
706 }
707 
708 
709 int
str_rindex(PceString s,wint_t chr)710 str_rindex(PceString s, wint_t chr)
711 { return str_next_rindex(s, s->s_size, chr);
712 }
713 
714 /* count chr in [from,to) */
715 
716 int
str_count_chr(PceString s,int from,int to,wint_t chr)717 str_count_chr(PceString s, int from, int to, wint_t chr)
718 { int i, count = 0;
719 
720   if ( isstrA(s) )
721   { charA *d = &s->s_textA[from];
722 
723     for(i=from; i<to; i++, d++)
724       if ( *d == chr )
725 	count++;
726   } else
727   { charW *d = &s->s_textW[from];
728 
729     for(i=from; i<to; i++, d++)
730       if ( (wint_t)*d == chr )
731 	count++;
732   }
733 
734   return count;
735 }
736 
737 
738 int
str_lineno(PceString s,int at)739 str_lineno(PceString s, int at)
740 { return str_count_chr(s, 0, at, '\n') + 1;
741 }
742 
743 
744 wint_t
str_fetch(PceString s,int idx)745 str_fetch(PceString s, int idx)
746 { return s->s_iswide ? str_fetchW(s, idx)
747 		   : str_fetchA(s, idx) & 0xff;
748 }
749 
750 
751 int
str_store(PceString s,int idx,unsigned int chr)752 str_store(PceString s, int idx, unsigned int chr)
753 { return s->s_iswide ? str_storeW(s, idx, chr)
754 		   : str_storeA(s, idx, chr);
755 }
756 
757 		 /*******************************
758 		 *	       UTIL		*
759 		 *******************************/
760 
761 static void
str_from_char(PceString s,char c)762 str_from_char(PceString s, char c)
763 { unsigned char *text = alloc(sizeof(char)*2);
764   text[0] = c;
765   text[1] = '\0';
766 
767   str_inithdr(s, FALSE);
768   s->s_textA  = text;
769   s->s_size     = 1;
770 }
771 
772 
773 static void
str_from_char16(PceString s,int c)774 str_from_char16(PceString s, int c)
775 { charW *text = alloc(sizeof(charW)*2);
776   text[0] = c;
777   text[1] = '\0';
778 
779   str_inithdr(s, TRUE);
780   s->s_textW = text;
781   s->s_size     = 1;
782 }
783 
784 
785 PceString
str_nl(PceString proto)786 str_nl(PceString proto)
787 { static string nl8;
788   static string nl16;
789 
790   if ( !proto || !proto->s_iswide )
791   { if ( !nl8.s_size )
792       str_from_char(&nl8, '\n');
793 
794     return &nl8;
795   } else
796   { if ( !nl16.s_size )
797       str_from_char16(&nl16, '\n');
798 
799     return &nl16;
800   }
801 }
802 
803 
804 PceString
str_spc(PceString proto)805 str_spc(PceString proto)
806 { static string spc8;
807   static string spc16;
808 
809   if ( !proto || !proto->s_iswide )
810   { if ( !spc8.s_size )
811       str_from_char(&spc8, ' ');
812 
813     return &spc8;
814   } else
815   { if ( !spc16.s_size )
816       str_from_char16(&spc16, ' ');
817 
818     return &spc16;
819   }
820 }
821 
822 
823 PceString
str_tab(PceString proto)824 str_tab(PceString proto)
825 { static string tab8;
826   static string tab16;
827 
828   if ( !proto || !proto->s_iswide )
829   { if ( !tab8.s_size )
830       str_from_char(&tab8, '\t');
831 
832     return &tab8;
833   } else
834   { if ( !tab16.s_size )
835       str_from_char16(&tab16, '\t');
836 
837     return &tab16;
838   }
839 }
840 
841 
842 void
str_strip(PceString s)843 str_strip(PceString s)
844 { int size = s->s_size;
845 
846   if ( isstrA(s) )
847   { charA *f = s->s_textA;
848     charA *t = s->s_textA;
849     charA *e = &s->s_textA[size];
850 
851     while( f < e && iswspace(*f) )	/* ISO-Latin-1 */
852       f++;
853 
854     do
855     { while( f < e && !iswspace(*f) )
856 	*t++ = *f++;
857       while( f < e && iswspace(*f) )
858 	f++;
859       if ( f < e )
860 	*t++ = ' ';
861     } while( f < e );
862     s->s_size = t - s->s_textA;
863   } else
864   { charW *f = s->s_textW;
865     charW *t = s->s_textW;
866     charW *e = &s->s_textW[size];
867 
868     while( f < e && iswspace(*f) )
869       f++;
870 
871     do
872     { while( f < e && !iswspace(*f) )
873 	*t++ = *f++;
874       while( f < e && iswspace(*f) )
875 	f++;
876       if ( f < e )
877 	*t++ = ' ';
878     } while( f < e );
879     s->s_size = t - s->s_textW;
880   }
881 }
882 
883 
884 int
str_common_length(PceString s1,PceString s2)885 str_common_length(PceString s1, PceString s2)
886 { int i = 0;
887   int size = min(s1->s_size, s2->s_size);
888 
889   if ( s1->s_iswide == s2->s_iswide )
890   { if ( isstrA(s1) )
891     { charA *t1 = s1->s_textA;
892       charA *t2 = s2->s_textA;
893 
894       while( i < size && *t1++ == *t2++ )
895 	i++;
896     } else
897     { charW *t1 = s1->s_textW;
898       charW *t2 = s2->s_textW;
899 
900       while( i < size && *t1++ == *t2++ )
901 	i++;
902     }
903   }
904 
905   return i;
906 }
907 
908 
909 int
str_icase_common_length(PceString s1,PceString s2)910 str_icase_common_length(PceString s1, PceString s2)
911 { int i = 0;
912   int size = min(s1->s_size, s2->s_size);
913 
914   if ( s1->s_iswide == s2->s_iswide )
915   { if ( isstrA(s1) )
916     { charA *t1 = s1->s_textA;
917       charA *t2 = s2->s_textA;
918 
919       while( i < size && tolower(*t1) == tolower(*t2) )
920 	i++, t1++, t2++;
921     } else
922     { charW *t1 = s1->s_textW;
923       charW *t2 = s2->s_textW;
924 
925       while( i < size && towlower(*t1) == towlower(*t2) )
926 	i++, t1++, t2++;
927     }
928   }
929 
930   return i;
931 }
932 
933 
934 		 /*******************************
935 		 *	 TEMPORARY STRINGS	*
936 		 *******************************/
937 
938 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
939 Temporary strings are  designed  to   get  character  data  code-by-code
940 without knowing the size in advance or wether or not the data fits in an
941 ISO Latin-1 string or not.
942 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
943 
944 tmp_string *
str_tmp_init(tmp_string * tmp)945 str_tmp_init(tmp_string *tmp)
946 { str_inithdr(&tmp->s, FALSE);
947   tmp->s.s_textA = tmp->buffer;
948   tmp->allocated = sizeof(tmp->buffer);
949 
950   return tmp;
951 }
952 
953 
954 wint_t
str_tmp_put(tmp_string * tmp,wint_t c)955 str_tmp_put(tmp_string *tmp, wint_t c)
956 { PceString s = &tmp->s;
957 
958   if ( c > 0xff && !s->s_iswide )
959   { if ( s->s_textA == tmp->buffer &&
960 	 s->s_size*sizeof(charW) < sizeof(tmp->buffer) )
961     { charA b2[sizeof(tmp->buffer)];
962       const charA *f = b2;
963       const charA *e = &f[s->s_size];
964       charW *t = s->s_textW;
965 
966       memcpy(b2, tmp->buffer, s->s_size);
967       while(f<e)
968 	*t++ = *f++;
969       tmp->allocated /= sizeof(charW);
970     } else
971     { charW *new = pceMalloc(tmp->allocated * sizeof(charW));
972       const charA *f = tmp->buffer;
973       const charA *e = &f[s->s_size];
974       charW *t = new;
975 
976       while(f<e)
977 	*t++ = *f++;
978 
979       if ( s->s_textA != tmp->buffer )
980 	pceFree(s->s_textA);
981       s->s_textW = new;
982     }
983     s->s_iswide = TRUE;
984   }
985   if ( s->s_size >= tmp->allocated )
986   { if ( s->s_textA == tmp->buffer )
987     { long len = tmp->allocated*2;
988 
989       if ( isstrA(s) )
990       { s->s_textA = pceMalloc(len);
991 
992 	memcpy(s->s_textA, tmp->buffer, sizeof(tmp->buffer));
993       } else
994       { s->s_textW = pceMalloc(len*sizeof(charW));
995 
996 	memcpy(s->s_textA, tmp->buffer, sizeof(tmp->buffer));
997       }
998 
999       tmp->allocated = len;
1000     } else
1001     { tmp->allocated *= 2;
1002 
1003       if ( isstrA(s) )
1004 	s->s_textA = pceRealloc(s->s_textA, tmp->allocated);
1005       else
1006 	s->s_textW = pceRealloc(s->s_textW, tmp->allocated*sizeof(charW));
1007     }
1008   }
1009 
1010   if ( !s->s_iswide )
1011     s->s_textA[s->s_size++] = c;
1012   else
1013     s->s_textW[s->s_size++] = c;
1014 
1015   return c;
1016 }
1017 
1018 
1019 void
str_tmp_done(tmp_string * tmp)1020 str_tmp_done(tmp_string *tmp)
1021 { if ( tmp->s.s_textA != tmp->buffer )
1022     pceFree(tmp->s.s_textA);
1023 }
1024