13
// ************* String.h replacement code:
14
int min(int i, int j){return i<j ? i : j;}
16
Regex::Regex(const char *s){
17
patt=(struct re_pattern_buffer*)
18
malloc(sizeof(struct re_pattern_buffer));
23
re_compile_pattern(s,strlen(s),patt);
26
String upcase(const String &x){
28
for(string::size_type i=0;i< (string::size_type)x.length(); i++)
29
s+=char(toupper(x[i]));
34
const char* String::chrstr() const{
35
//This assumes vector doesn't free the memory for the last element.
36
//I believe (but am not sure) that this is true.
38
((vector<char> &)buf).push_back('\0');
39
((vector<char> &)buf).pop_back();
44
int readline(istream& s, String& x,
45
char terminator = '\n'){
49
ret=s.get(buf,sizeof(buf), terminator);
55
// ************* "own" string handling code:
58
except_pi::except_pi(parsestream *p){
62
except_pi_String::except_pi_String(parsestream *p, String s):except_pi(p){
66
parseinfo::~parseinfo(void){
69
void except_pi::report(){
71
string::size_type startpos=0;
75
_("In file \"%s\", at (or in the definition that ends at) line %i:\n"),
76
pi->filename().c_str(),
80
startpos=pi->pos - 50;
84
cerr<<pi->buffer.substr(startpos)<<endl;
88
for(i=1+startpos;i<pi->pos;i++)
93
_("Somewhere in input file:\n"));
95
cerr<<message()<<endl;
97
void parsestream::preprocess(String &s){
98
//disregards lines that start with a #
99
//set filename if line starts with "!F"
104
while((i<s.length())&&isspace(s[i]))
121
set_filename(s.after(3));
122
//cerr<<"filename="<<filename()<<", s.after="<<s.after(2)<<endl;
126
set_linenumber(Stringtoi(s.after(2))-1);
127
//cerr<<"filename="<<filename()<<", s.after="<<s.after(2)<<endl;
132
if(compat == "menu-1")
133
seteolmode(eol_newline);
134
else if(compat == "menu-2")
135
seteolmode(eol_semicolon);
137
throw unknown_compat(this, compat);
141
if(s.contains("!include",0)){
142
String t(s.after(strlen("!include ")));
143
//cerr<<"HOI, t="<<t<<", filename()[0]="<<filename()[0]<<endl;
148
String name=String_parent(filename()) + "/" + t;
149
if(ifstream(name.c_str()))
152
new_file(otherdir+'/'+t);
156
//(s==buffer now!) s="";
164
void parsestream::close_file(){
165
//should delete i.back(), but only if !=stdin!
168
if(nu || !stdin_file)
176
throw endoffile(this);
179
void parsestream::new_file(const String &s){
180
ifstream *f=new ifstream(s.c_str());
185
void parsestream::new_line(){
187
if(!current_istr()||current_istr()->eof()){
193
while(current_istr()->good()&&
194
!(current_istr()->eof())&&
196
readline(*current_istr(),buffer);
197
set_linenumber(linenumber()+1);
199
buffer=rmtrailingspace(buffer);
201
while(current_istr()->good()&&
202
!(current_istr()->eof())&&
203
(((eolmode==eol_newline)&&(buffer[buffer.length()-1]=='\\'))||
204
((eolmode==eol_semicolon)&&(buffer[buffer.length()-1]!=';')))){
206
readline(*current_istr(),s);
207
set_linenumber(linenumber()+1);
210
buffer=buffer.substr(0,buffer.length()-1)+" "+rmtrailingspace(s);
213
buffer=buffer+" "+rmtrailingspace(s);
217
if(!buffer.length()){
221
if(current_istr()->eof()&&
223
(((eolmode==eol_newline)&&(buffer[buffer.length()-1]=='\\'))||
224
((eolmode==eol_semicolon)&&(buffer[buffer.length()-1]!=';')))){
225
//a "\" at the end of a file: unconditional error (don't unwind etc)
226
//(or no ; at eof, when eolmode=; . Same unconditional error.
227
throw endoffile(this);
229
if(eolmode==eol_semicolon)
230
if(buffer[buffer.length()-1]==';')
231
buffer.erase(buffer.length()-1, 1);
237
throw endoffile(this);
240
char parsestream::get_char(){
242
throw endoffile(this);
243
if(pos>=buffer.length())
244
throw endofline(this);
246
return buffer[pos++];
249
char parsestream::put_back(char c){
253
// buffer.at(pos,1)=String(c);
254
buffer.replace(pos,1,c);
262
String parsestream::get_line(){
266
throw endofline(this);
275
String parsestream::get_name(){
280
while((c=get_char())&&
281
(isalnum(c)||(c=='_')||(c=='-')||(c=='+')||(c=='.')))
285
} catch(endofline d){};
289
String parsestream::get_name(const Regex &r){
295
while((c=get_char())){
296
if(re_match(r.pattern(), str, 1, 0, 0) > 0)
303
} catch(endofline){};
306
String parsestream::get_eq_name(){
311
throw char_expected(this, "=");
316
String parsestream::get_Stringconst(){
323
while((c=get_char())&&(c!='\"')){
327
case 't': c='\t'; break;
328
case 'b': c='\b'; break;
329
case 'n': c='\n'; break;
336
throw char_expected(this, "\"");
337
} else{ //no " at begining
339
while((c=get_char())&&!isspace(c))
342
}catch(endofline p){};
346
String parsestream::get_eq_Stringconst(){
351
throw char_expected(this, "=");
352
return get_Stringconst();
355
bool parsestream::get_boolean(){
359
if(s==String("true"))
361
else if(s==String("false"))
364
throw boolean_expected(this, s);
366
bool parsestream::get_eq_boolean(){
371
throw char_expected(this,"=");
372
return get_boolean();
374
int parsestream::get_integer(){
380
while((c=get_char())&&((isdigit(c)||(c=='-'))))
382
} catch(endofline d){};
384
return atoi(s.c_str());
387
int parsestream::get_eq_integer(){
393
throw char_expected(this, "=");
394
return get_integer();
397
double parsestream::get_double(){
403
while((c=get_char())&&
405
(c=='.')||(c=='E')||(c=='e')||(c=='+')||(c=='-')))
407
} catch(endofline d){};
409
return atof(s.c_str());
411
double parsestream::get_eq_double(){
417
throw char_expected(this, "=");
421
void parsestream::skip_line(){
426
catch(endoffile d){};
428
void parsestream::skip_space(){
430
while(isspace(c=get_char()));
434
void parsestream::skip_char(char expect){
440
throw char_expected(this, buf);
443
void parsestream::seteolmode(eol_type mode){
447
String rmtrailingspace(String &s){
448
while(s.length()&&(isspace(s[s.length()-1])))
449
s.erase(s.length()-1,1);
455
String escape_doublequotes(const String &s){
458
for(i=0;i!=s.length();i++){
466
String escapewith_String(const String &s, const String &esc,
468
// call with: escape_String("hello $world, %dir", "$%", "\\")
469
// returns: "hello \$world, \%dir"
472
for(i=0;i!=s.length();i++){
473
if(esc.find(s[i])!=string::npos)
480
String escape_String(const String &s, const String &esc){
481
// call with: escape_String("hello $world, %dir", "$%")
482
// returns: "hello \$world, \%dir"
483
return escapewith_String(s,esc,"\\");
485
String cppesc_String(const String &s){
488
for(i=0;i!=s.length();i++){
489
if(!(isalnum(s[i])||(s[i]=='_')))
490
t+='$'+itohexString(int(s[i]));
496
String tolower_String(const String &s){
498
for(string::size_type i=0; i<s.length(); i++)
499
t+=char(tolower(s[i]));
502
String toupper_String(const String &s){
504
for(string::size_type i=0; i<s.length(); i++)
505
t+=char(toupper(s[i]));
508
String replacewith_String(const String &s, const String &replace,
510
// call with: replacewith_String("hello $world, %dir", "$% ", "123")
511
// returns: "hello31world,32dir"
513
string::size_type i,j;
514
for(i=0;i!=s.length();i++){
515
if((string::size_type)(j=replace.find(s[i]))!=string::npos)
516
t+=with[j % with.length()];
523
String replace(String s,char match, char replace){
525
for(i=0;i!=s.length();i++)
527
s.replace(i,i+1,replace);
530
String sort_hotkey(String str){
533
string::size_type l=str.length();
534
char *s=strdup(str.c_str());
542
if((isspace(s[i-1])||ispunct(s[i-1]))&&isupper(s[i])){
547
if((isspace(s[i-1])||ispunct(s[i-1]))&&isalnum(s[i])){
575
int Stringtoi(const String &s){
576
return atoi(s.c_str());
579
String itoString(int i){
581
ostrstream str(s,sizeof(s));
586
String itohexString(int i){
588
ostrstream str(s,sizeof(s));
589
str<<setbase(16)<<i<<ends;
594
String String_parent(String s){
595
// String_parent("/Debian/Apps/Editors/Emacs") = "/Debian/Apps/Editors
596
string::size_type i,p;
598
for(i=0,p=string::npos;(string::size_type)i!=s.length();i++)
604
return s.substr(0,p);
607
String String_basename(String s){
610
string::size_type p; //points to last encountered '/'
611
string::size_type q; //points to last-but-one encountered '/'.
613
for(i=0,p=string::npos,q=0;i!=s.length();i++)
621
return s.substr(q+1,p);
623
String String_stripdir(String s){
626
string::size_type p; //points to last encountered '/'
628
for(i=0,p=string::npos;(string::size_type)i!=s.length();i++)
634
return s.substr(p+1,s.length());
637
String String_lastname(String s){
638
//what `basename' in the shell returns...
641
string::size_type p; //points at last encountered '/'
646
if(s[s.size()-1] == '/')
647
s.erase(s.size()+1,1);
649
for(i=0,p=string::npos;(string::size_type)i!=s.length();i++)
655
return s.substr(p+1);
658
void break_char(const String &sec,
662
string::size_type i,j;
667
if(sec[0]==breakchar) /* ignore first occurence of breachar */
672
while((i<sec.size())&&(isspace(sec[i])))
674
j=sec.find(breakchar,i);
676
sec_vec.push_back(sec.substr(i,j-i));
679
sec_vec.push_back(sec.substr(i));
687
void break_slashes(const String &sec,
689
break_char(sec,sec_vec,'/');
691
void break_commas(const String &sec,
693
break_char(sec,sec_vec,',');
697
String Sprintf(const char *s, String &str){
699
snprintf(buf, sizeof(buf), s, str.c_str());
703
const char *ldgettext(const char *language,
706
/* this code comes from the gettext info page. It looks
707
very inefficient (as though for every language change a new
708
catalog file is opened), but tests show adding a language
709
change like this doesn't get performance down very much
710
(runtime goes `only' about 70% up, if switching between 2
711
languages, as compared to no swiching at all).
713
/* Change language. */
714
setenv ("LANGUAGE", language, 1);
715
/* Make change known. */
717
extern int _nl_msg_cat_cntr;
720
return dgettext(domain, msgid);