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/unix.h>			/* storeStringFile() prototype */
37 
38 static CharArray	stringToCharArray(PceString s);
39 
40 		/********************************
41 		*         CREATE/CONVERT	*
42 		********************************/
43 
44 
45 status
initialiseCharArray(CharArray n,CharArray value)46 initialiseCharArray(CharArray n, CharArray value)
47 { str_cphdr(&n->data, &value->data);
48   str_alloc(&n->data);
49   if ( value->data.s_readonly )
50     n->data.s_textA = value->data.s_textA;
51   else
52     memcpy(n->data.s_textA, value->data.s_textA, str_datasize(&n->data));
53 
54   succeed;
55 }
56 
57 
58 static status
unlinkCharArray(CharArray n)59 unlinkCharArray(CharArray n)
60 { str_unalloc(&n->data);
61 
62   succeed;
63 }
64 
65 
66 static status
cloneCharArray(CharArray str,CharArray clone)67 cloneCharArray(CharArray str, CharArray clone)
68 { clonePceSlots(str, clone);
69   clone->data = str->data;
70   str_alloc(&clone->data);
71   memcpy(clone->data.s_textA, str->data.s_textA, str_datasize(&str->data));
72 
73   succeed;
74 }
75 
76 
77 static status
storeCharArray(CharArray s,FileObj file)78 storeCharArray(CharArray s, FileObj file)
79 { TRY(storeSlotsObject(s, file));
80 
81   return storeStringFile(file, &s->data);
82 }
83 
84 
85 static status
loadCharArray(CharArray s,IOSTREAM * fd,ClassDef def)86 loadCharArray(CharArray s, IOSTREAM *fd, ClassDef def)
87 { TRY(loadSlotsObject(s, fd, def));
88 
89   return loadStringFile(fd, &s->data);
90 }
91 
92 
93 static CharArray
getConvertCharArray(Any ctx,Any val)94 getConvertCharArray(Any ctx, Any val)
95 { string s;
96 
97   TRY(toString(val, &s));
98   answer(stringToCharArray(&s));
99 }
100 
101 
102 Name
getValueCharArray(CharArray n)103 getValueCharArray(CharArray n)
104 { answer(StringToName(&n->data));
105 }
106 
107 
108 		/********************************
109 		*             TESTS		*
110 		********************************/
111 
112 status
equalCharArray(CharArray n1,CharArray n2,BoolObj ign_case)113 equalCharArray(CharArray n1, CharArray n2, BoolObj ign_case)
114 { if ( ign_case == ON )
115     return str_icase_eq(&n1->data, &n2->data);
116   else
117     return str_eq(&n1->data, &n2->data);
118 }
119 
120 
121 /* n2 is prefix of n1 */
122 
123 status
prefixCharArray(CharArray n1,CharArray n2,BoolObj ign_case)124 prefixCharArray(CharArray n1, CharArray n2, BoolObj ign_case)
125 { if ( ign_case == ON )
126     return str_icase_prefix(&n1->data, &n2->data);
127   else
128     return str_prefix(&n1->data, &n2->data);
129 }
130 
131 
132 status
suffixCharArray(CharArray n,CharArray s,BoolObj ign_case)133 suffixCharArray(CharArray n, CharArray s, BoolObj ign_case)
134 { if ( ign_case == ON )
135     return str_icase_suffix(&n->data, &s->data);
136   else
137     return str_suffix(&n->data, &s->data);
138 }
139 
140 
141 static status
largerCharArray(CharArray n1,CharArray n2)142 largerCharArray(CharArray n1, CharArray n2)
143 { if ( str_cmp(&n1->data, &n2->data) > 0 )
144     succeed;
145   fail;
146 }
147 
148 
149 static status
smallerCharArray(CharArray n1,CharArray n2)150 smallerCharArray(CharArray n1, CharArray n2)
151 { if ( str_cmp(&n1->data, &n2->data) < 0 )
152     succeed;
153   fail;
154 }
155 
156 
157 static status
subCharArray(CharArray n1,CharArray n2,BoolObj ign_case)158 subCharArray(CharArray n1, CharArray n2, BoolObj ign_case)
159 { if ( ign_case != ON )
160   { if ( str_sub(&n1->data, &n2->data) )
161       succeed;
162   } else
163   { if ( str_icasesub(&n1->data, &n2->data) )
164       succeed;
165   }
166 
167   fail;
168 }
169 
170 
171 status
isWideCharArray(Any s)172 isWideCharArray(Any s)
173 { CharArray ca = s;
174 
175   return str_iswide(&ca->data);
176 }
177 
178 
179 		/********************************
180 		*         MODIFICATIONS		*
181 		********************************/
182 
183 static CharArray
getModifyCharArray(CharArray n,CharArray n2)184 getModifyCharArray(CharArray n, CharArray n2)
185 { answer(answerObject(classOfObject(n), n2, EAV));
186 }
187 
188 
189 static CharArray
ModifiedCharArray(CharArray n,PceString buf)190 ModifiedCharArray(CharArray n, PceString buf)
191 {
192   Class class = classOfObject(n);
193 
194   if ( class == ClassName )
195     return (CharArray) StringToName(buf);
196   else if ( class == ClassString)
197     return (CharArray) StringToString(buf);	/* ??? */
198   else
199   { CharArray scratch = StringToScratchCharArray(buf);
200     CharArray rval = get(n, NAME_modify, scratch, EAV);
201 
202     doneScratchCharArray(scratch);
203     answer(rval);
204   }
205 }
206 
207 
208 CharArray
getCopyCharArray(CharArray n)209 getCopyCharArray(CharArray n)
210 { answer(ModifiedCharArray(n, &n->data));
211 }
212 
213 
214 /* This assumes the capitalised version of an ISO Latin-1 string always
215    fits in an ISO Latin-1 string.  Is this true for all accented characters?
216  */
217 
218 CharArray
getCapitaliseCharArray(CharArray n)219 getCapitaliseCharArray(CharArray n)
220 { if ( n->data.s_size == 0 )
221     answer(n);
222   else
223   { PceString d = &n->data;
224     int size = d->s_size;
225     LocalString(buf, d->s_iswide, size);
226     int i=1, o=1;
227 
228     str_store(buf, 0, towupper(str_fetch(d, 0)));
229 
230     for(; i < size; i++, o++)
231     { wint_t c = str_fetch(d, i);
232 
233       if ( iswordsep(c) )
234       { if ( ++i < size )
235 	  str_store(buf, o, towupper(str_fetch(d, i)));
236 	else
237 	  break;
238       } else
239 	str_store(buf, o, towlower(c));
240     }
241 
242     buf->s_size = o;
243     answer(ModifiedCharArray(n, buf));
244   }
245 }
246 
247 
248 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
249 Upcase first letter, downcase the rest  and replace word separators (-_)
250 by spaces.
251 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
252 
253 CharArray
getLabelNameCharArray(CharArray n)254 getLabelNameCharArray(CharArray n)
255 { PceString s = &n->data;
256   int size = s->s_size;
257   int i;
258 
259   if ( size == 0 )
260     return n;
261 
262   { LocalString(buf, s->s_iswide, size);
263     int o = 0;
264     wint_t c = str_fetch(s, 0);
265 
266     i = 0;
267     str_store(buf, o, towupper(c));
268     i++, o++;
269 
270     for( ; i < size; i++, o++ )
271     { c = str_fetch(s, i);
272 
273       if ( iswordsep(c) )
274 	str_store(buf, o, ' ');
275       else
276 	str_store(buf, o, c);
277     }
278     buf->s_size = o;
279 
280     answer(ModifiedCharArray(n, buf));
281   }
282 }
283 
284 
285 CharArray
getDowncaseCharArray(CharArray n)286 getDowncaseCharArray(CharArray n)
287 { PceString s = &n->data;
288   int size = s->s_size;
289   LocalString(buf, s->s_iswide, size);
290   int i;
291 
292   for(i=0; i<size; i++)
293     str_store(buf, i, tolower(str_fetch(s, i)));
294   buf->s_size = size;
295 
296   answer(ModifiedCharArray(n, buf));
297 }
298 
299 
300 static CharArray
getUpcaseCharArray(CharArray n)301 getUpcaseCharArray(CharArray n)
302 { PceString s = &n->data;
303   int size = s->s_size;
304   LocalString(buf, s->s_iswide, size);
305   int i;
306 
307   for(i=0; i<size; i++)
308     str_store(buf, i, towupper(str_fetch(s, i)));
309   buf->s_size = size;
310 
311   answer(ModifiedCharArray(n, buf));
312 }
313 
314 
315 static CharArray
getStripCharArray(CharArray n,Name how)316 getStripCharArray(CharArray n, Name how)
317 { PceString s = &n->data;
318   int size = s->s_size;
319   LocalString(buf, s->s_iswide, size);
320   int i=0, o=0, lnb=0;
321 
322   if ( isDefault(how) )
323     how = NAME_canonicalise;
324 
325   if ( how == NAME_canonicalise || how == NAME_leading || how == NAME_both )
326   { for(; i<size && iswspace(str_fetch(s, i)); i++)
327       ;
328   }
329   for( ; i<size; i++)
330   { wint_t c = str_fetch(s, i);
331 
332     str_store(buf, o++, c);
333     if ( !iswspace(c) )
334       lnb = o;
335     else if ( how == NAME_canonicalise )
336     { for( ; i+1<size && iswspace(str_fetch(s, i+1)); i++)
337 	;
338     }
339   }
340   if ( how == NAME_canonicalise || how == NAME_trailing || how == NAME_both )
341     buf->s_size = lnb;
342   else
343     buf->s_size = o;
344 
345   answer(ModifiedCharArray(n, buf));
346 }
347 
348 
349 static Chain
getSplitCharArray(CharArray in,CharArray br)350 getSplitCharArray(CharArray in, CharArray br)
351 { PceString s1 = &in->data;
352   int size = s1->s_size;
353   int i=0, last=0;
354   Chain ch = answerObject(ClassChain, EAV);
355   string buf;
356 
357   str_cphdr(&buf, s1);
358 
359   if ( notDefault(br) )			/* given pattern */
360   { PceString b = &br->data;
361 
362     while( i<=size-b->s_size )
363     { if ( str_prefix_offset(s1, i, b) )
364       { if ( isstrA(s1) )
365 	  buf.s_textA = s1->s_textA+last;
366 	else
367 	  buf.s_textW = s1->s_textW+last;
368 
369 	buf.s_size = i-last;
370 	appendChain(ch, ModifiedCharArray(in, &buf));
371 
372 	i = last = i+b->s_size;
373       } else
374 	i++;
375     }
376   } else
377   { for(; i<size && iswspace(str_fetch(s1, i)); i++) /* strip leading */
378       ;
379     last = i;
380 
381     while( i<size )
382     { if ( iswspace(str_fetch(s1, i)) )
383       { if ( isstrA(s1) )
384 	  buf.s_textA = s1->s_textA+last;
385 	else
386 	  buf.s_textW = s1->s_textW+last;
387 
388 	buf.s_size = i-last;
389 	appendChain(ch, ModifiedCharArray(in, &buf));
390 
391 	while(i < size && iswspace(str_fetch(s1, i)))
392 	  i++;
393 	last = i;
394 	if ( i == size )		/* trailing blanks */
395 	  answer(ch);
396       } else
397 	i++;
398     }
399   }
400 
401   if ( isstrA(s1) )
402     buf.s_textA = s1->s_textA+last;
403   else
404     buf.s_textW = s1->s_textW+last;
405 
406   buf.s_size = size-last;
407   appendChain(ch, ModifiedCharArray(in, &buf));
408 
409   answer(ch);
410 }
411 
412 
413 CharArray
getAppendCharArray(CharArray n1,CharArray n2)414 getAppendCharArray(CharArray n1, CharArray n2)
415 { PceString s1 = &n1->data;
416   PceString s2 = &n2->data;
417   int iswide = (s1->s_iswide || s2->s_iswide);
418   LocalString(buf, iswide, s1->s_size + s2->s_size);
419 
420   buf->s_size = s1->s_size + s2->s_size;
421   str_ncpy(buf, 0, s1, 0, s1->s_size);
422   str_ncpy(buf, s1->s_size, s2, 0, s2->s_size);
423 
424   answer(ModifiedCharArray(n1, buf));
425 }
426 
427 
428 static CharArray
getAppendCharArrayv(CharArray ca,int argc,CharArray * argv)429 getAppendCharArrayv(CharArray ca, int argc, CharArray *argv)
430 { int l = ca->data.s_size;
431   int iswide = ca->data.s_iswide;
432   int i;
433 
434   for( i=0; i<argc; i++ )
435   { l += argv[i]->data.s_size;
436     if ( argv[i]->data.s_iswide )
437       iswide = TRUE;
438   }
439 
440   { LocalString(buf, iswide, l);
441     int d;
442 
443     str_ncpy(buf, 0, &ca->data, 0, ca->data.s_size);
444     d = ca->data.s_size;
445 
446     for( i=0; i<argc; i++ )
447     { str_ncpy(buf, d, &argv[i]->data, 0, argv[i]->data.s_size);
448       d += argv[i]->data.s_size;
449     }
450 
451     buf->s_size = l;
452     answer(ModifiedCharArray(ca, buf));
453   }
454 }
455 
456 
457 CharArray
getDeleteSuffixCharArray(CharArray n,CharArray s)458 getDeleteSuffixCharArray(CharArray n, CharArray s)
459 { if ( suffixCharArray(n, s, OFF) )
460   { string buf;
461 
462     str_cphdr(&buf, &n->data);
463     buf.s_text = n->data.s_text;
464     buf.s_size = n->data.s_size - s->data.s_size;
465 
466     answer(ModifiedCharArray(n, &buf));
467   }
468 
469   fail;
470 }
471 
472 
473 CharArray
getEnsureSuffixCharArray(CharArray n,CharArray s)474 getEnsureSuffixCharArray(CharArray n, CharArray s)
475 { if ( suffixCharArray(n, s, OFF) )
476     answer(n);
477 
478   answer(getAppendCharArray(n, s));
479 }
480 
481 
482 static CharArray
getDeletePrefixCharArray(CharArray n,CharArray s)483 getDeletePrefixCharArray(CharArray n, CharArray s)
484 { if ( prefixCharArray(n, s, OFF) )
485   { string buf;
486 
487     str_cphdr(&buf, &n->data);
488     buf.s_size = n->data.s_size - s->data.s_size;
489     if ( isstrA(&buf) )
490       buf.s_textA = &n->data.s_textA[s->data.s_size];
491     else
492       buf.s_textW = &n->data.s_textW[s->data.s_size];
493 
494     answer(ModifiedCharArray(n, &buf));
495   }
496 
497   fail;
498 }
499 
500 
501 CharArray
getSubCharArray(CharArray n,Int start,Int end)502 getSubCharArray(CharArray n, Int start, Int end)
503 { string s;
504   int x, y;
505   int len = n->data.s_size;
506 
507   x = valInt(start);
508   y = (isDefault(end) ? len : valInt(end));
509   if ( x < 0 || y > len || x > y )
510     fail;
511 
512   str_cphdr(&s, &n->data);
513   s.s_size = y-x;
514   if ( isstrA(&n->data) )
515     s.s_textA = &n->data.s_textA[x];
516   else
517     s.s_textW = &n->data.s_textW[x];
518 
519   answer(ModifiedCharArray(n, &s));
520 }
521 
522 
523 		 /*******************************
524 		 *	 BASE-64 ENCODING	*
525 		 *******************************/
526 
527 static int
base64_char(unsigned int in)528 base64_char(unsigned int in)
529 { if ( in < 26 ) return 'A'+in;
530   if ( in < 52 ) return 'a'+in-26;
531   if ( in < 62 ) return '0'+in-52;
532   if ( in == 62 ) return '+';
533   assert(in == 63);
534   return '/';
535 }
536 
537 
538 static unsigned long
base64_code(unsigned int in)539 base64_code(unsigned int in)
540 { if ( in == '+' ) return 62;
541   if ( in == '/' ) return 63;
542   if ( in <  '0' ) return ~0L;
543   if ( in <= '9' ) return in - '0' + 52;
544   if ( in <  'A' ) return ~0L;
545   if ( in <= 'Z' ) return in - 'A';
546   if ( in <  'a' ) return ~0L;
547   if ( in <= 'z' ) return in - 'a' + 26;
548   return ~0L;
549 }
550 
551 
552 static CharArray
getBase64EncodeCharArray(CharArray in)553 getBase64EncodeCharArray(CharArray in)
554 { PceString s = &in->data;
555   int size = s->s_size;
556   int triples = (size+2)/3;
557   LocalString(buf, FALSE, triples*4);
558   int i, o=0;
559   unsigned long v;
560 
561   for(i=0; i+2<size;)
562   { v = (str_fetch(s, i)<<16) + (str_fetch(s, i+1)<<8) + str_fetch(s, i+2);
563     i += 3;
564     str_store(buf, o++, base64_char((v>>18)&0x3f));
565     str_store(buf, o++, base64_char((v>>12)&0x3f));
566     str_store(buf, o++, base64_char((v>> 6)&0x3f));
567     str_store(buf, o++, base64_char((v>> 0)&0x3f));
568   }
569 
570   if ( size - i == 2 )
571   { v = (str_fetch(s, i)<<16) + (str_fetch(s, i+1)<<8);
572     str_store(buf, o++, base64_char((v>>18)&0x3f));
573     str_store(buf, o++, base64_char((v>>12)&0x3f));
574     str_store(buf, o++, base64_char((v>> 6)&0x3f));
575     str_store(buf, o++, '=');
576   } else if ( size - i == 1)
577   { v = (str_fetch(s, i)<<16);
578     str_store(buf, o++, base64_char((v>>18)&0x3f));
579     str_store(buf, o++, base64_char((v>>12)&0x3f));
580     str_store(buf, o++, '=');
581     str_store(buf, o++, '=');
582   }
583 
584   buf->s_size = o;
585   answer(ModifiedCharArray(in, buf));
586 }
587 
588 
589 static CharArray
getBase64DecodeCharArray(CharArray in)590 getBase64DecodeCharArray(CharArray in)
591 { PceString s = &in->data;
592   int size = s->s_size;
593   LocalString(buf, FALSE, (size/4)*3);
594   int i, o = 0;
595   unsigned long v = 0L;
596 
597   for(i=0; i+3<size; )
598   { int c;
599 
600     v = (base64_code(str_fetch(s, i)) << 18) |
601 	(base64_code(str_fetch(s, i+1)) << 12);
602     i += 2;
603     c = str_fetch(s, i++);
604     if ( c == '=' )
605     { i++;				/* skip last (must be =) */
606       str_store(buf, o++, (v>>16) & 0xff);
607       break;
608     }
609     v |= base64_code(c) << 6;
610     c = str_fetch(s, i++);
611     if ( c == '=' )
612     { str_store(buf, o++, (v>>16) & 0xff);
613       str_store(buf, o++, (v>>8) & 0xff);
614       break;
615     }
616     v |= base64_code(c);
617     if ( v == ~(unsigned long)0 )
618       fail;
619     str_store(buf, o++, (v>>16) & 0xff);
620     str_store(buf, o++, (v>>8) & 0xff);
621     str_store(buf, o++, (v>>0) & 0xff);
622   }
623 
624   if ( i != size || v == ~(unsigned long)0 )
625     fail;
626 
627   buf->s_size = o;
628   answer(ModifiedCharArray(in, buf));
629 }
630 
631 
632 		 /*******************************
633 		 *	      AS-FILE		*
634 		 *******************************/
635 
636 static CharArray
getReadAsFileCharArray(CharArray n,Int from,Int size)637 getReadAsFileCharArray(CharArray n, Int from, Int size)
638 { int f = valInt(from);
639   int s = valInt(size);
640 
641   if ( f < 0 || s < 0 || f > n->data.s_size )
642     fail;
643 
644   if ( f == 0 && s >= n->data.s_size )
645     answer(n);
646   else
647   { string str;
648 
649     if ( f+s > n->data.s_size )
650       s = n->data.s_size - f;
651 
652     str_cphdr(&str, &n->data);
653     str.s_size = s;
654     if ( isstrA(&n->data) )
655       str.s_textA = &n->data.s_textA[f];
656     else
657       str.s_textW = &n->data.s_textW[f];
658 
659     answer((CharArray)StringToString(&str));
660   }
661 }
662 
663 
664 		/********************************
665 		*          READING GETS		*
666 		********************************/
667 
668 Int
getSizeCharArray(Any n)669 getSizeCharArray(Any n)
670 { CharArray c = n;
671 
672   answer(toInt(c->data.s_size));
673 }
674 
675 
676 static Int
getCharacterCharArray(CharArray n,Int idx)677 getCharacterCharArray(CharArray n, Int idx)
678 { int i = valInt(idx);
679 
680   if ( i < 0 || i >= n->data.s_size )
681     fail;
682 
683   answer(toInt(str_fetch(&n->data, i)));
684 }
685 
686 
687 static Int
getIndexCharArray(CharArray n,Int chr,Int here)688 getIndexCharArray(CharArray n, Int chr, Int here)
689 { wint_t c = valInt(chr);
690   int h;
691 
692   h = (isDefault(here) ? 0 : valInt(here));
693   if ( (h = str_next_index(&n->data, h, c)) >= 0 )
694     answer(toInt(h));
695 
696   fail;
697 }
698 
699 
700 static Int
getRindexCharArray(CharArray n,Int chr,Int here)701 getRindexCharArray(CharArray n, Int chr, Int here)
702 { wint_t c = valInt(chr);
703   int h, len = n->data.s_size;
704 
705   h = (isDefault(here) ? (len - 1) : valInt(here));
706   if ( (h = str_next_rindex(&n->data, h, c)) >= 0 )
707     answer(toInt(h));
708 
709   fail;
710 }
711 
712 
713 static Int
getLineNoCharArray(CharArray name,Int caret)714 getLineNoCharArray(CharArray name, Int caret)
715 { int here = (isDefault(caret) ? name->data.s_size : valInt(caret));
716 
717   answer(toInt(str_lineno(&name->data, here)));
718 }
719 
720 
721 static Vector
getScanCharArray(CharArray n,CharArray fmt)722 getScanCharArray(CharArray n, CharArray fmt)
723 { if ( isstrA(&n->data) && isstrA(&fmt->data) )
724   { Any argv[SCAN_MAX_ARGS];
725     Int argc;
726 
727     TRY(argc = scanstr((char *)n->data.s_textA,
728 		       (char *)fmt->data.s_textA,
729 		       argv));
730 
731     answer(answerObjectv(ClassVector, valInt(argc), argv));
732   } else
733   { errorPce(n, NAME_notSupportedForChar16);
734     fail;
735   }
736 }
737 
738 
739 static Name
getCompareCharArray(CharArray n1,CharArray n2,BoolObj ignore_case)740 getCompareCharArray(CharArray n1, CharArray n2, BoolObj ignore_case)
741 { int rval;
742 
743   if ( ignore_case == ON )
744     rval = str_icase_cmp(&n1->data, &n2->data);
745   else
746     rval = str_cmp(&n1->data, &n2->data);
747 
748   if ( rval < 0 )
749     answer(NAME_smaller);
750   else if ( rval == 0 )
751     answer(NAME_equal);
752   else
753     answer(NAME_larger);
754 
755   assert(0);				/* should not get here! */
756   fail;
757 }
758 
759 
760 		/********************************
761 		*          C-CONVERSIONS	*
762 		********************************/
763 
764 #define SCRATCH_CHAR_ARRAYS	(10)
765 
766 static CharArray scratch_char_arrays;
767 
768 void
initCharArrays(void)769 initCharArrays(void)
770 { CharArray ca;
771   int n;
772   int size = sizeof(struct char_array) * SCRATCH_CHAR_ARRAYS;
773 
774   scratch_char_arrays = alloc(size);
775   memset(scratch_char_arrays, 0, size);
776 
777   for(ca=scratch_char_arrays, n = 0; n < SCRATCH_CHAR_ARRAYS; ca++, n++)
778   { initHeaderObj(ca, ClassCharArray);
779     setProtectedObj(ca);
780     createdObject(ca, NAME_new);
781   }
782 }
783 
784 
785 CharArray
CtoScratchCharArray(const char * s)786 CtoScratchCharArray(const char *s)
787 { CharArray name = scratch_char_arrays;
788   size_t len = strlen(s);
789   int n;
790 
791   for(n = 0; n < SCRATCH_CHAR_ARRAYS; n++, name++)
792   { if ( name->data.s_textA == NULL )
793     { str_set_n_ascii(&name->data, len, (char *)s);
794 
795       return name;
796     }
797   }
798 
799   initCharArrays();			/* handle the crash better */
800   NOTREACHED;
801   fail;
802 }
803 
804 
805 CharArray
StringToScratchCharArray(const PceString s)806 StringToScratchCharArray(const PceString s)
807 { CharArray name = scratch_char_arrays;
808   int n;
809 
810   for(n = 0; n < SCRATCH_CHAR_ARRAYS; n++, name++)
811   { if ( name->data.s_textA == NULL )
812     { str_cphdr(&name->data, s);
813       name->data.s_text = s->s_text;
814       return name;
815     }
816   }
817 
818   initCharArrays();			/* handle the crash better */
819   NOTREACHED;
820   fail;
821 }
822 
823 
824 void
doneScratchCharArray(CharArray n)825 doneScratchCharArray(CharArray n)
826 { n->data.s_text = NULL;
827 }
828 
829 
830 CharArray
CtoCharArray(char * s)831 CtoCharArray(char *s)
832 { CharArray name = CtoScratchCharArray(s);
833   CharArray rval = answerObject(ClassCharArray, name, EAV);
834 
835   doneScratchCharArray(name);
836   return rval;
837 }
838 
839 
840 static CharArray
stringToCharArray(PceString s)841 stringToCharArray(PceString s)
842 { CharArray name = StringToScratchCharArray(s);
843   CharArray rval = answerObject(ClassCharArray, name, EAV);
844 
845   doneScratchCharArray(name);
846   return rval;
847 }
848 
849 
850 		 /*******************************
851 		 *	 CLASS DECLARATION	*
852 		 *******************************/
853 
854 /* Type declarations */
855 
856 static char *T_ofAchar_fromADintD[] =
857         { "of=char", "from=[int]" };
858 static char *T_gsub[] =
859         { "start=int", "end=[int]" };
860 static char *T_match[] =
861         { "text=char_array", "ignore_case=[bool]" };
862 static char *T_readAsFile[] =
863         { "from=int", "size=int" };
864 
865 /* Instance Variables */
866 
867 static vardecl var_charArray[] =
868 { IV(NAME_header, "alien:str_h", IV_NONE,
869      NAME_internal, "Header info (packed)"),
870   IV(NAME_text, "alien:wint_t *", IV_NONE,
871      NAME_internal, "Text represented (8- or 16-bits chars)")
872 };
873 
874 /* Send Methods */
875 
876 static senddecl send_charArray[] =
877 { SM(NAME_initialise, 1, "text=char_array", initialiseCharArray,
878      DEFAULT, "Create from other char_array"),
879   SM(NAME_unlink, 0, NULL, unlinkCharArray,
880      DEFAULT, "Free the char *"),
881   SM(NAME_equal, 2, T_match, equalCharArray,
882      NAME_compare, "Test if names represent same text"),
883   SM(NAME_larger, 1, "than=char_array", largerCharArray,
884      NAME_compare, "Test if I'm alphabetically after arg"),
885   SM(NAME_smaller, 1, "than=char_array", smallerCharArray,
886      NAME_compare, "Test if I'm alphabetically before arg"),
887   SM(NAME_prefix, 2, T_match, prefixCharArray,
888      NAME_test, "Test if receiver has prefix argument"),
889   SM(NAME_sub, 2, T_match, subCharArray,
890      NAME_test, "Test if argument is a substring"),
891   SM(NAME_suffix, 2, T_match, suffixCharArray,
892      NAME_test, "Test if receiver has suffix argument"),
893   SM(NAME_isWide, 0, NULL, isWideCharArray,
894      NAME_encoding, "Test if text contains non ISO-Latin-1 characters")
895 };
896 
897 /* Get Methods */
898 
899 static getdecl get_charArray[] =
900 { GM(NAME_printName, 0, "char_array", NULL, getSelfObject,
901      DEFAULT, "Equivalent to <-self"),
902   GM(NAME_size, 0, "int", NULL, getSizeCharArray,
903      NAME_cardinality, "Number of characters in the text"),
904   GM(NAME_capitalise, 0, "char_array", NULL, getCapitaliseCharArray,
905      NAME_case, "Capitalised version of name"),
906   GM(NAME_downcase, 0, "char_array", NULL, getDowncaseCharArray,
907      NAME_case, "Map all uppercase letters to lowercase"),
908   GM(NAME_labelName, 0, "char_array", NULL, getLabelNameCharArray,
909      NAME_case, "Default name used for labels"),
910   GM(NAME_upcase, 0, "char_array", NULL, getUpcaseCharArray,
911      NAME_case, "Map all lowercase letters to uppercase"),
912   GM(NAME_strip, 1, "char_array", "[{canonicalise,leading,trailing,both}]", getStripCharArray,
913      NAME_content, "Strip leading/trailing blanks"),
914   GM(NAME_compare, 2, "{smaller,equal,larger}", T_match, getCompareCharArray,
915      NAME_compare, "Alphabetical comparison"),
916   GM(NAME_append, 1, "char_array", "char_array ...", getAppendCharArrayv,
917      NAME_content, "Concatenation of me and the argument(s)"),
918   GM(NAME_character, 1, "char", "int", getCharacterCharArray,
919      NAME_content, "Character code of 0-based nth character"),
920   GM(NAME_deletePrefix, 1, "char_array", "prefix=char_array", getDeletePrefixCharArray,
921      NAME_content, "Delete specified prefix"),
922   GM(NAME_deleteSuffix, 1, "char_array", "suffix=char_array", getDeleteSuffixCharArray,
923      NAME_content, "Delete specified suffix"),
924   GM(NAME_ensureSuffix, 1, "char_array", "suffix=char_array", getEnsureSuffixCharArray,
925      NAME_content, "Append suffix if not already there"),
926   GM(NAME_sub, 2, "char_array", T_gsub, getSubCharArray,
927      NAME_content, "Get substring from 0-based start and end"),
928   GM(NAME_convert, 1, "char_array", "any", getConvertCharArray,
929      NAME_conversion, "Convert `text-convertible'"),
930   GM(NAME_value, 0, "name", NULL, getValueCharArray,
931      NAME_conversion, "Value as a name"),
932   GM(NAME_copy, 0, "char_array", NULL, getCopyCharArray,
933      NAME_copy, "Copy representing the same text"),
934   GM(NAME_split, 1, "chain", "separator=[char_array]", getSplitCharArray,
935      NAME_content, "Split text using separator"),
936   GM(NAME_modify, 1, "char_array", "char_array", getModifyCharArray,
937      NAME_internal, "New instance of my class"),
938   GM(NAME_lineNo, 1, "line=int", "index=[int]", getLineNoCharArray,
939      NAME_line, "Get 1-based line number at which index is"),
940   GM(NAME_index, 2, "int", T_ofAchar_fromADintD, getIndexCharArray,
941      NAME_parse, "Get 0-based index starting at pos (forwards)"),
942   GM(NAME_rindex, 2, "int", T_ofAchar_fromADintD, getRindexCharArray,
943      NAME_parse, "Get 0-based index starting at pos (backwards)"),
944   GM(NAME_scan, 1, "vector", "format=char_array", getScanCharArray,
945      NAME_parse, "C-scanf like parsing of string"),
946   GM(NAME_base64Encode, 0, "char_array", NULL, getBase64EncodeCharArray,
947      NAME_mime, "Perform base-64 encoding on the argument"),
948   GM(NAME_base64Decode, 0, "char_array", NULL, getBase64DecodeCharArray,
949      NAME_mime, "Perform base-64 decoding on the argument"),
950   GM(NAME_readAsFile, 2, "char_array", T_readAsFile, getReadAsFileCharArray,
951      NAME_stream, "Read data from object using pce_open/3"),
952   GM(NAME_sizeAsFile, 0, "characters=int", NULL, getSizeCharArray,
953      NAME_stream, "Support pce_open/3")
954 };
955 
956 /* Resources */
957 
958 #define rc_charArray NULL
959 /*
960 static classvardecl rc_charArray[] =
961 {
962 };
963 */
964 
965 /* Class Declaration */
966 
967 static Name charArray_termnames[] = { NAME_value };
968 
969 ClassDecl(charArray_decls,
970           var_charArray, send_charArray, get_charArray, rc_charArray,
971           1, charArray_termnames,
972           "$Rev$");
973 
974 status
makeClassCharArray(Class class)975 makeClassCharArray(Class class)
976 { declareClass(class, &charArray_decls);
977 
978   setCloneFunctionClass(class, cloneCharArray);
979   setLoadStoreFunctionClass(class, loadCharArray, storeCharArray);
980 
981   initCharArrays();
982 
983   succeed;
984 }
985