2 /******************************************************************************
4 * DESCRIPTION: Properties of characters and strings
5 * COPYRIGHT : (C) 1999 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
12 #include "analyze.hpp"
13 #include "merge_sort.hpp"
14 #include "converter.hpp"
15 #include "Scheme/object.hpp"
17 /******************************************************************************
19 ******************************************************************************/
22 is_alpha (register char c
) {
23 return ((c
>='a') && (c
<='z')) || ((c
>='A') && (c
<='Z'));
27 is_iso_alpha (register char c
) {
28 int i
= ((int) ((unsigned char) c
));
30 ((c
>='a') && (c
<='z')) ||
31 ((c
>='A') && (c
<='Z')) ||
32 ((i
>= 128) && (i
!= 159) && (i
!= 189) && (i
!= 190) && (i
!= 191));
36 is_locase (register char c
) {
37 int code
= (int) ((unsigned char) c
);
39 ((c
>='a') && (c
<='z')) ||
40 ((code
>= 160) && (code
< 189)) ||
45 is_upcase (register char c
) {
46 int code
= (int) ((unsigned char) c
);
48 ((c
>='A') && (c
<='Z')) ||
49 ((code
>= 128) && (code
< 159)) ||
50 ((code
>= 192) && (code
< 224));
54 is_digit (register char c
) {
55 return (c
>='0') && (c
<='9');
59 is_numeric (register char c
) {
60 return ((c
>='0') && (c
<='9')) || (c
=='.');
64 is_punctuation (register char c
) {
66 (c
=='.') || (c
==',') || (c
==':') || (c
=='\'') || (c
=='`') ||
67 (c
==';') || (c
=='!') || (c
=='?');
71 is_space (register char c
) {
72 return (c
== ' ') || (c
== '\11') || (c
== '\12') || (c
== '\15');\
75 /******************************************************************************
77 ******************************************************************************/
82 if (N(s
)==0) return false;
83 for (i
=0; i
<N(s
); i
++)
84 if (!is_alpha (s
[i
])) return false;
89 is_locase_alpha (string s
) {
91 if (N(s
)==0) return false;
92 for (i
=0; i
<N(s
); i
++)
93 if (s
[i
]<'a' || s
[i
]>'z') return false;
98 is_iso_alpha (string s
) {
100 if (N(s
)==0) return false;
101 for (i
=0; i
<N(s
); i
++)
102 if (!is_iso_alpha (s
[i
])) return false;
107 is_numeric (string s
) {
109 if (N(s
)==0) return false;
110 for (i
=0; i
<N(s
); i
++)
111 if (!is_numeric (s
[i
])) return false;
115 /******************************************************************************
117 ******************************************************************************/
122 return (char) (((int) ((unsigned char) c
)) - 32);
129 return (char) (((int) ((unsigned char) c
)) + 32);
134 upcase_first (string s
) {
135 if ((N(s
)==0) || (!is_locase (s
[0]))) return s
;
136 return string ((char) (((int) ((unsigned char) s
[0]))-32)) * s (1, N(s
));
140 locase_first (string s
) {
141 if ((N(s
)==0) || (!is_upcase (s
[0]))) return s
;
142 return string ((char) (((int) ((unsigned char) s
[0]))+32)) * s (1, N(s
));
146 upcase_all (string s
) {
149 for (i
=0; i
<N(s
); i
++)
150 if (!is_locase (s
[i
])) r
[i
]= s
[i
];
151 else r
[i
]= (char) (((int) ((unsigned char) s
[i
]))-32);
156 locase_all (string s
) {
159 for (i
=0; i
<N(s
); i
++)
160 if (!is_upcase (s
[i
])) r
[i
]= s
[i
];
161 else r
[i
]= (char) (((int) ((unsigned char) s
[i
]))+32);
165 /******************************************************************************
166 * Inserting or removing a character into a string as a set of characters
167 ******************************************************************************/
170 string_union (string s1
, string s2
) {
171 return string_minus (s1
, s2
) * s2
;
175 string_minus (string s1
, string s2
) {
177 int i1
, n1
= N(s1
), i2
, n2
= N(s2
);
178 for (i1
=0; i1
<n1
; i1
++) {
179 for (i2
=0; i2
<n2
; i2
++)
180 if (s1
[i1
] == s2
[i2
]) break;
181 if (i2
==n2
) r
<< s1
[i1
];
186 /******************************************************************************
187 * Spanish in relation with ispell
188 ******************************************************************************/
191 ispanish_to_spanish (string s
) {
195 if ((s
[i
] == '\'') && ((i
+1)<n
)) {
197 case 'A': r
<< 'Á'; break;
198 case 'E': r
<< 'É'; break;
199 case 'I': r
<< 'Í'; break;
200 case 'N': r
<< 'Ñ'; break;
201 case 'O': r
<< 'Ó'; break;
202 case 'U': r
<< 'Ú'; break;
203 case 'Y': r
<< 'Ý'; break;
204 case 'a': r
<< 'á'; break;
205 case 'e': r
<< 'é'; break;
206 case 'i': r
<< 'í'; break;
207 case 'n': r
<< 'ñ'; break;
208 case 'o': r
<< 'ó'; break;
209 case 'u': r
<< 'ú'; break;
210 case 'y': r
<< 'ý'; break;
211 default : r
<< '\'' << s
[i
+1];
220 spanish_to_ispanish (string s
) {
225 case 'Á': r
<< "'A"; break;
226 case 'É': r
<< "'E"; break;
227 case 'Í': r
<< "'I"; break;
228 case 'Ñ': r
<< "'N"; break;
229 case 'Ó': r
<< "'O"; break;
230 case 'Ú': r
<< "'U"; break;
231 case 'Ý': r
<< "'Y"; break;
232 case 'á': r
<< "'a"; break;
233 case 'é': r
<< "'e"; break;
234 case 'í': r
<< "'i"; break;
235 case 'ñ': r
<< "'n"; break;
236 case 'ó': r
<< "'o"; break;
237 case 'ú': r
<< "'u"; break;
238 case 'ý': r
<< "'y"; break;
245 igerman_to_german (string s
) {
249 if (s
[i
] == 'ß') r
<< 'ÿ';
255 german_to_igerman (string s
) {
259 if (s
[i
] == 'ÿ') r
<< 'ß';
264 /******************************************************************************
265 * Iso latin 2 encoding for polish and czech
266 ******************************************************************************/
268 static string il2_to_cork_string
=
269 "€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ �\bŠ ‰‘Ÿ\x04’“”™\x7fš› ¡\fª\x01©±\a\v²³´¹\x05º»�Á€Ĉ‚ǃɆ˅Í΄ЋŒÓÔŽÖ.�—Ú–ÜÝ•ÿ¯áâ 䨢ç£é¦ë¥í«¬óô®ö/°·ú¶üýµ ";
270 static string cork_to_il2_string
=
271 "áÆÈÏÌÊGÅ¥£ÑÒ ÕÀئ©ª«ÞÛÙY¬®¯IIð§ã±æèïìêgåµ³ñò õàø¶¹º»þûùy¼¾¿i!?LAÁÂAÄAAÇEÉEËIÍÎIÐNOÓÔOÖOOUÚUÜÝ Saáâaäaaçeéeëiíîiðnoóôoöoouúuüý ß";
274 il2_to_cork (char c
) {
275 int i
= (int) ((unsigned char) c
);
277 return il2_to_cork_string
[i
-128];
281 cork_to_il2 (char c
) {
282 int i
= (int) ((unsigned char) c
);
284 return cork_to_il2_string
[i
-128];
288 il2_to_cork (string s
) {
292 r
[i
]= il2_to_cork (s
[i
]);
297 cork_to_il2 (string s
) {
301 r
[i
]= cork_to_il2 (s
[i
]);
305 /******************************************************************************
306 * Koi8 encoding for russian
307 ******************************************************************************/
309 static string koi8_to_iso_string
=
310 "áâ÷çäåöúéêëìíîïðòóôõæèãþûýÿùøüàñÁÂ×ÇÄÅÖÚÉÊËÌÍÎÏÐÒÓÔÕÆÈÃÞÛÝßÙØÜÀÑ";
311 static string iso_to_koi8_string
=
312 "þàáöäåôãõèéêëìíîïÿðñòóæâüûçøýù÷úÞÀÁÖÄÅÔÃÕÈÉÊËÌÍÎÏßÐÑÒÓÆÂÜÛÇØÝÙ×Ú";
315 koi8_to_iso (char c
, bool ukrainian
) {
316 int i
= (int) ((unsigned char) c
);
317 if (i
==156) return '³';
318 if (i
==188) return '£';
334 return koi8_to_iso_string
[i
-192];
338 iso_to_koi8 (char c
, bool ukrainian
) {
339 int i
= (int) ((unsigned char) c
);
340 if (c
=='³') return (char) 156;
341 if (c
=='£') return (char) 188;
357 return iso_to_koi8_string
[i
-192];
361 koi8_to_iso (string s
) {
365 r
[i
]= koi8_to_iso (s
[i
], false);
370 iso_to_koi8 (string s
) {
374 r
[i
]= iso_to_koi8 (s
[i
], false);
379 koi8uk_to_iso (string s
) {
383 r
[i
]= koi8_to_iso (s
[i
], true);
388 iso_to_koi8uk (string s
) {
392 r
[i
]= iso_to_koi8 (s
[i
], true);
396 /******************************************************************************
397 * Convert between TeXmacs and XML strings
398 ******************************************************************************/
401 is_xml_name (char c
) {
403 is_alpha (c
) || is_numeric (c
) ||
404 (c
== '.') || (c
== '-') || (c
== ':');
408 tm_to_xml_name (string s
) {
412 if (is_xml_name (s
[i
])) r
<< s
[i
];
413 else r
<< "_" << as_string ((int) ((unsigned char) s
[i
])) << "_";
418 xml_name_to_tm (string s
) {
422 if (s
[i
] != '_') r
<< s
[i
];
425 while ((i
<n
) && (s
[i
]!='_')) i
++;
426 r
<< (char) ((unsigned char) as_int (s (start
, i
)));
432 old_tm_to_xml_cdata (string s
) {
436 if (s
[i
] == '&') r
<< "&";
437 else if (s
[i
] == '>') r
<< ">";
438 else if (s
[i
] != '<') r
<< s
[i
];
441 while ((i
<n
) && (s
[i
]!='>')) i
++;
442 r
<< "&" << tm_to_xml_name (s (start
, i
)) << ";";
448 tm_to_xml_cdata (string s
) {
450 a
<< symbol_object ("!concat");
454 if (s
[i
] == '&') r
<< "&";
455 else if (s
[i
] == '>') r
<< ">";
456 else if (s
[i
] == '\\') r
<< "\\";
457 else if (s
[i
] != '<') r
<< cork_to_utf8 (s (i
, i
+1));
460 while ((i
<n
) && (s
[i
]!='>')) i
++;
461 string ss
= s (start
, i
+1);
462 string rr
= cork_to_utf8 (ss
);
463 string qq
= utf8_to_cork (rr
);
464 if (rr
!= ss
&& qq
== ss
) r
<< rr
;
466 if (r
!= "") a
<< object (r
);
467 a
<< cons (symbol_object ("tm-sym"),
468 cons (ss (1, N(ss
)-1),
473 if (r
!= "") a
<< object (r
);
474 if (N(a
) == 1) return object ("");
475 else if (N(a
) == 2) return a
[1];
476 else return call ("list", a
);
480 old_xml_cdata_to_tm (string s
) {
484 if (s
[i
] == '<') r
<< "<less>";
485 else if (s
[i
] == '>') r
<< "<gtr>";
486 else if (s
[i
] != '&') r
<< s
[i
];
489 while ((i
<n
) && (s
[i
]!=';')) i
++;
490 string x
= "<" * xml_name_to_tm (s (start
, i
)) * ">";
491 if (x
== "<amp>") r
<< "&";
498 xml_unspace (string s
, bool first
, bool last
) {
501 if (first
) while ((i
<n
) && is_space (s
[i
])) i
++;
503 if (!is_space (s
[i
])) r
<< s
[i
++];
505 while ((i
<n
) && is_space (s
[i
])) i
++;
506 if ((i
<n
) || (!last
)) r
<< ' ';
512 contains_unicode_char (string s
) {
515 if (s
[i
] == '<' && s
[i
+1] == '#') return true;
516 tm_char_forwards (s
, i
);
521 /******************************************************************************
522 * Roman and alpha numbers
523 ******************************************************************************/
525 static string ones
[10]= {
526 "", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix" };
527 static string tens
[10]= {
528 "", "x", "xx", "xxx", "xl", "l", "lx", "lxx", "lxxx", "xc" };
529 static string hundreds
[10]= {
530 "", "c", "cc", "ccc", "cd", "d", "dc", "dcc", "dccc", "cm" };
534 if (nr
<0) return "-" * roman_nr (nr
);
535 if (nr
==0) return "o";
536 if (nr
>1000) return "m" * roman_nr (nr
-1000);
537 if (nr
==1000) return "m";
538 if (nr
==999) return "im";
539 if (nr
==499) return "id";
540 if ((nr
%100)==99) return hundreds
[nr
/100] * "ic";
541 if ((nr
%100)==49) return hundreds
[nr
/100] * "il";
542 return hundreds
[nr
/100] * tens
[(nr
%100)/10] * ones
[nr
%10];
547 return upcase_all (roman_nr (nr
));
552 if (nr
<0) return "-" * alpha_nr (nr
);
553 if (nr
==0) return "0";
554 if (nr
<=26) return string ((char) (((int) 'a')+ nr
-1));
555 return alpha_nr ((nr
-1)/26) * alpha_nr (((nr
-1)%26)+1);
560 return upcase_all (alpha_nr (nr
));
564 fnsymbol_nr (int nr
) {
566 int i
, m
= (nr
-1)%3, n
= ((nr
-1)/3)+1;
568 case 0: sym
= "<ast>"; break;
569 case 1: sym
= "<dag>"; break;
570 case 2: sym
= "<ddag>"; break;
572 for (i
=0; i
<n
; i
++) r
<< sym
;
576 /******************************************************************************
577 * Conversions to and from hexadecimal
578 ******************************************************************************/
580 static const char* hex_string
= "0123456789ABCDEF";
583 as_hexadecimal (int i
) {
584 if (i
<0) return "-" * as_hexadecimal (-i
);
585 if (i
<16) return hex_string
[i
& 15];
586 return as_hexadecimal (i
>> 4) * hex_string
[i
& 15];
590 as_hexadecimal (pointer ptr
) {
591 intptr_t i
= (intptr_t) ptr
;
592 if (i
<0) return "-" * as_hexadecimal (-i
);
593 if (i
<16) return hex_string
[i
& 15];
594 return as_hexadecimal (i
>> 4) * hex_string
[i
& 15];
598 as_hexadecimal (int i
, int len
) {
599 if (len
==1) return hex_string
[i
& 15];
600 else return as_hexadecimal (i
>> 4, len
-1) * hex_string
[i
& 15];
604 from_hexadecimal (string s
) {
605 int i
, n
= N(s
), res
= 0;
606 if ((n
>0) && (s
[0]=='-'))
607 return -from_hexadecimal (s (1, n
));
608 for (i
=0; i
<n
; i
++) {
610 if ((s
[i
] >= '0') && (s
[i
] <= '9')) res
+= (int) (s
[i
] - '0');
611 if ((s
[i
] >= 'A') && (s
[i
] <= 'F')) res
+= (int) (s
[i
] + 10 - 'A');
612 if ((s
[i
] >= 'a') && (s
[i
] <= 'f')) res
+= (int) (s
[i
] + 10 - 'a');
617 /******************************************************************************
618 * Routines for the TeXmacs encoding
619 ******************************************************************************/
622 tm_encode (string s
) {
623 // verbatim to TeXmacs encoding
626 for (i
=0; i
<N(s
); i
++) {
627 if (s
[i
]=='<') r
<< "<less>";
628 else if (s
[i
]=='>') r
<< "<gtr>";
635 tm_decode (string s
) {
636 // TeXmacs encoding to verbatim
639 for (i
=0; i
<N(s
); i
++) {
642 for (j
=i
+1; j
<N(s
); j
++)
643 if (s
[j
]=='>') break;
645 if (s(i
,j
) == "<less>") r
<< "<";
646 else if (s(i
,j
) == "<gtr>") r
<< ">";
648 if (s
[i
]!='>') return r
;
650 else if (s
[i
]!='>') r
<< s
[i
];
656 tm_var_encode (string s
) {
657 register int i
, n
= N(s
);
659 for (i
=0; i
<n
; i
++) {
661 if (i
+1 < n
&& s
[i
+1] == '#') {
662 while (i
<n
&& s
[i
] != '>') r
<< s
[i
++];
667 else if (s
[i
]=='>') r
<< "<gtr>";
674 tm_correct (string s
) {
677 for (i
=0; i
<N(s
); i
++) {
679 register bool flag
= true;
681 for (j
=i
+1; j
<N(s
); j
++)
682 if (s
[j
]=='>') break;
683 if (j
==N(s
)) return r
;
684 for (k
=i
+1; k
<j
; k
++)
685 if (s
[k
]=='<') flag
= false;
686 if (flag
) r
<< s(i
,j
+1);
689 else if (s
[i
]!='>') r
<< s
[i
];
695 tm_char_forwards (string s
, int& pos
) {
696 ASSERT (pos
>= 0 && pos
<= N(s
), "out of range");
699 else if (s
[pos
] != '<') pos
++;
701 while (pos
<n
&& s
[pos
] != '>') pos
++;
707 tm_char_backwards (string s
, int& pos
) {
708 ASSERT (pos
>= 0 && pos
<= N(s
), "out of range");
710 else if (s
[pos
-1] != '>') pos
--;
712 while (pos
>0 && s
[pos
-1] != '<') pos
--;
717 /******************************************************************************
719 ******************************************************************************/
722 scm_quote (string s
) {
723 // R5RS compliant external string representation.
741 scm_unquote (string s
) {
742 if ((N(s
)>=2) && (s
[0]=='\"') && (s
[N(s
)-1]=='\"')) {
745 for (i
=1; i
<n
-1; i
++)
746 if (s
[i
] == '\\' && (s
[i
+1] == '\"' || s
[i
+1] == '\\')) r
<< s
[++i
];
754 raw_quote (string s
) {
755 // Mark the label of a STRING tree as representing a string and not a symbol.
756 return "\"" * s
* "\"";
760 raw_unquote (string s
) {
761 // Get the string value of a STRING tree label representing a string.
762 if ((N(s
)>=2) && (s
[0]=='\"') && (s
[N(s
)-1]=='\"'))
763 return s (1, N(s
)-1);
767 /******************************************************************************
768 * Handling escape characters
769 ******************************************************************************/
772 escape_sh (string s
) {
773 #if defined (__MINGW__) || defined (__MINGW32__) || defined (OS_WIN32)
774 return raw_quote (s
);
797 escape_generic (string s
) {
800 for (i
=0; i
<n
; i
++) {
801 if ((s
[i
] == '\2') || (s
[i
] == '\5') || (s
[i
] == '\33')) r
<< '\33';
808 escape_verbatim (string s
) {
811 for (i
=0; i
<n
; i
++) {
812 unsigned char c
= (unsigned char) s
[i
];
813 if ((c
== '\n') || (c
== '\t')) r
<< ' ';
814 else if (((int) c
) >= 32) r
<< s
[i
];
820 escape_spaces (string s
) {
823 for (i
=0; i
<n
; i
++) {
824 unsigned char c
= (unsigned char) s
[i
];
825 if (c
== ' ') r
<< '\\';
832 dos_to_better (string s
) {
841 /******************************************************************************
842 * Reading input from a string
843 ******************************************************************************/
846 test (string s
, int i
, const char* test
) {
848 while (test
[j
]!='\0') {
849 if (i
>=n
) return false;
850 if (s
[i
]!=test
[j
]) return false;
857 test (string s
, int i
, string test
) {
858 int n
= N(s
), m
= N(test
), j
=0;
860 if (i
>=n
) return false;
861 if (s
[i
]!=test
[j
]) return false;
868 starts (string s
, const char* what
) {
869 return test (s
, 0, what
);
873 starts (string s
, const string what
) {
874 return test (s
, 0, what
);
878 ends (string s
, const char* what
) {
880 if (N(r
) > N(s
)) return false;
881 return s (N(s
)-N(r
), N(s
)) == r
;
885 ends (string s
, const string r
) {
886 if (N(r
) > N(s
)) return false;
887 return s (N(s
)-N(r
), N(s
)) == r
;
891 read (string s
, int& i
, const char* test
) {
892 int n
= N(s
), j
=0, k
=i
;
893 while (test
[j
]!='\0') {
894 if (k
>=n
) return false;
895 if (s
[k
]!=test
[j
]) return false;
903 read (string s
, int& i
, string test
) {
904 int n
= N(s
), m
= N(test
), j
=0, k
=i
;
906 if (k
>=n
) return false;
907 if (s
[k
]!=test
[j
]) return false;
915 read_line (string s
, int& i
, string
& result
) {
917 for (; i
<N(s
); i
++) {
919 result
= s(start
,i
++);
928 read_int (string s
, int& i
, int& result
) {
929 int n
= N(s
), start
= i
;
931 if (i
==n
) return false;
933 if (i
+1==n
) return false;
934 if (!is_digit (s
[i
+1])) return false;
937 else if (!is_digit (s
[i
])) return false;
938 while ((i
<n
) && is_digit (s
[i
])) i
++;
939 result
= as_int (s(start
,i
));
944 read_double (string s
, int& i
, double& result
) {
945 int n
= N(s
), start
= i
;
947 if (i
==n
) return false;
949 if (i
+1==n
) return false;
950 if (!is_numeric (s
[i
+1])) return false;
953 else if (!is_numeric (s
[i
])) return false;
954 while ((i
<n
) && is_digit (s
[i
])) i
++;
955 if ((i
<n
) && (s
[i
]=='.')) i
++;
956 while ((i
<n
) && is_digit (s
[i
])) i
++;
957 if ((i
<n
) && ((s
[i
]=='e') || (s
[i
]=='E'))) {
959 if ((i
<n
) && (s
[i
]=='-')) i
++;
960 if ((i
==n
) || (!is_digit (s
[i
]))) { i
=start
; return false; }
961 while ((i
<n
) && is_digit (s
[i
])) i
++;
963 result
= as_double (s(start
,i
));
968 skip_spaces (string s
, int& i
) {
970 while ((i
<n
) && ((s
[i
]==' ') || (s
[i
]=='\t'))) i
++;
974 skip_line (string s
, int& i
) {
976 while ((i
<n
) && (s
[i
]!='\n')) i
++;
981 skip_symbol (string s
, int& i
) {
986 if (s
[i
-1]=='>') break;
992 /******************************************************************************
993 * Parsing binary data
994 ******************************************************************************/
997 parse (string s
, int& pos
, QI
& ret
) {
1002 parse (string s
, int& pos
, QN
& ret
) {
1007 parse (string s
, int& pos
, HI
& ret
) {
1008 QI c1
= (QI
) s
[pos
++];
1009 QN c2
= (QN
) s
[pos
++];
1010 ret
= (((HI
) c1
)<<8)+ c2
;
1014 parse (string s
, int& pos
, HN
& ret
) {
1015 QN c1
= (QN
) s
[pos
++];
1016 QN c2
= (QN
) s
[pos
++];
1017 ret
= (((HN
) c1
)<<8)+ c2
;
1021 parse (string s
, int& pos
, SI
& ret
) {
1022 QI c1
= (QI
) s
[pos
++];
1023 QN c2
= (QN
) s
[pos
++];
1024 QN c3
= (QN
) s
[pos
++];
1025 QN c4
= (QN
) s
[pos
++];
1026 ret
= (((((((SI
) c1
)<<8)+ ((SI
) c2
))<<8)+ ((SI
) c3
))<<8)+ c4
;
1030 parse (string s
, int& pos
, SI
*& a
, int len
) {
1032 a
= tm_new_array
<int> (len
);
1033 for (i
=0; i
<len
; i
++) parse (s
, pos
, a
[i
]);
1036 /******************************************************************************
1037 * Searching, replacing and pattern matching
1038 ******************************************************************************/
1041 search_forwards (string s
, int pos
, string in
) {
1042 int k
= N(s
), n
= N(in
);
1043 if (k
== 0) return pos
;
1045 while (pos
+k
<= n
) {
1046 if (in
[pos
] == c
&& test (in
, pos
, s
)) return pos
;
1053 search_forwards (string s
, string in
) {
1054 return search_forwards (s
, 0, in
);
1058 search_backwards (string s
, int pos
, string in
) {
1060 if (test (in
, pos
, s
)) return pos
;
1067 search_backwards (string s
, string in
) {
1068 return search_backwards (s
, N(in
)-N(s
), in
);
1072 count_occurrences (string s
, string in
) {
1074 int i
=0, next
, n
= N(s
);
1076 next
= search_forwards (s
, i
, in
);
1077 if (next
== -1) break;
1085 replace (string s
, string what
, string by
) {
1089 if (test (s
, i
, what
)) {
1101 match_wildcard (string s
, int spos
, string w
, int wpos
) {
1102 if (wpos
== N(w
)) return spos
== N(s
);
1104 return (spos
< N(s
)) && (s
[spos
] == w
[wpos
]) &&
1105 match_wildcard (s
, spos
+1, w
, wpos
+1);
1106 while ((wpos
<N(w
)) && (w
[wpos
]=='*')) wpos
++;
1107 while (spos
<= N(s
)) {
1108 if (match_wildcard (s
, spos
, w
, wpos
)) return true;
1115 match_wildcard (string s
, string w
) {
1116 return match_wildcard (s
, 0, w
, 0);
1119 /******************************************************************************
1120 * Computations with completions
1121 ******************************************************************************/
1124 as_completions (hashset
<string
> h
) {
1127 array
<string
> a (n
);
1128 for (i
=0; i
<n
; i
++) a
[i
]= t
[i
]->label
;
1135 close_completions (hashset<string>& h) {
1136 array<string> a= as_completions (h);
1138 for (i=1; i<n; i++) {
1139 for (j=0; j < min (N(a[i-1]), N(a[i])); j++)
1140 if (a[i-1][j] != a[i][j]) break;
1141 if (j < min (N(a[i-1]), N(a[i])))
1142 h->insert (a[i](0,j));
1147 close_completions (array<string> a) {
1150 for (i=0; i<n; i++) h->insert (a[i]);
1151 close_completions (h);
1152 return as_completions (h);
1157 close_completions (array
<string
> a
) {
1158 if (N(a
) == 0) return a
;
1160 int i
, j
, n
= N(a
), l
= N(a
[0]);
1161 for (i
=1; i
<n
; i
++) {
1162 for (j
=0; j
<l
&& j
<N(a
[i
]); j
++)
1163 if (a
[i
-1][j
] != a
[i
][j
]) break;
1169 if (a
[i
] != r
[N(r
)-1])
1175 strip_completions (array
<string
> a
, string prefix
) {
1179 if (starts (a
[i
], prefix
))
1180 b
<< a
[i
] (N(prefix
), N(a
[i
]));