pick up CXXFLAGS passed on commandline
[rofl0r-df-libgraphics.git] / g_src / basics.cpp
bloba56145dcfcd255b67361ebd4cc7a205667478c94
1 #include "platform.h"
2 #include <string.h>
3 #include <math.h>
4 #include <iosfwd>
5 #include <iostream>
6 #include <ios>
7 #include <streambuf>
8 #include <istream>
9 #include <ostream>
10 #include <iomanip>
11 #include <sstream>
12 #include <cstdlib>
13 #include <fstream>
14 #include <zlib.h>
16 #include "svector.h"
17 using std::string;
18 using std::endl;
19 using std::ofstream;
21 #include "endian.h"
23 #ifdef WIN32
25 #ifndef INTEGER_TYPES
26 #define INTEGER_TYPES
27 typedef short int16_t;
28 typedef int int32_t;
29 typedef long long int64_t;
30 typedef unsigned short uint16_t;
31 typedef unsigned int uint32_t;
32 typedef unsigned long long uint64_t;
33 #endif
35 typedef int32_t VIndex;
36 typedef int32_t Ordinal;
38 #endif
40 #include "ttf_manager.hpp"
41 #include "init.h"
42 #include "basics.h"
44 extern string errorlog_prefix;
46 void errorlog_string(const string &str)
48 if(str.empty())return;
50 //SAVE AN ERROR TO THE LOG FILE
51 std::ofstream fseed("errorlog.txt", std::ios::out | std::ios::app);
52 if(fseed.is_open())
54 if(!errorlog_prefix.empty())
56 fseed<<errorlog_prefix.c_str()<<std::endl;
57 errorlog_prefix.clear();
59 fseed<<str.c_str()<<std::endl;
61 fseed.close();
64 void gamelog_string(const string &str)
66 if(str.empty())return;
68 //SAVE AN ERROR TO THE LOG FILE
69 std::ofstream fseed("gamelog.txt",std::ios::out | std::ios::app);
70 if(fseed.is_open())
72 fseed<<str.c_str()<<std::endl;
74 fseed.close();
77 void errorlog_string(const char *ptr)
79 if(ptr==NULL)return;
81 //SAVE AN ERROR TO THE LOG FILE
82 std::ofstream fseed("errorlog.txt", std::ios::out | std::ios::app);
83 if(fseed.is_open())
85 if(!errorlog_prefix.empty())
87 fseed<<errorlog_prefix.c_str()<<std::endl;
88 errorlog_prefix.clear();
90 fseed<<ptr<<std::endl;
92 fseed.close();
95 int32_t convert_string_to_long(string &str)
97 return atoi(str.c_str());
100 uint32_t convert_string_to_ulong(string &str)
102 return strtoul(str.c_str(),NULL,0);
105 void add_long_to_string(int32_t n,string &str)
107 string str2;
108 convert_long_to_string(n,str2);
109 str+=str2;
112 void convert_long_to_string(int32_t n,string &str)
114 std::ostringstream o;
115 o << n;
116 str = o.str();
119 void convert_ulong_to_string(uint32_t n,string &str)
121 std::ostringstream o;
122 o << n;
123 str = o.str();
126 char grab_variable_token(string &str,string &token,char sec_comp,int32_t &pos,int32_t i_pos)
128 token.erase();
130 for(pos=i_pos;pos<str.length();pos++)
132 if((str[pos]=='['&&pos+1<str.length())||sec_comp)
134 if(str[pos]=='['&&!sec_comp)pos++;
135 grab_token_string_pos(token,str,pos,':');
136 pos--;
138 if(token.length()>0)return 1;
142 return 0;
145 bool grab_token_expression(string &dest,string &source,int32_t &pos,char compc)
147 dest.erase();
148 dest+="[";
150 string token1;
151 while(grab_token_string(token1,source,pos))
153 if(dest.length()>1)dest+=":";
154 dest+=token1;
156 if(pos<source.length())
158 if(source[pos]==']')break;//grab_token_string CAN'T HANDLE THESE
161 dest+="]";
163 return (dest.length()>2);
166 bool grab_token_list_as_string(string &dest,string &source,int32_t &pos,char compc)
168 dest.erase();
170 string token1;
171 while(grab_token_string(token1,source,pos))
173 if(dest.length()>0)dest+=":";
174 dest+=token1;
176 if(pos<source.length())
178 if(source[pos]==']')break;//grab_token_string CAN'T HANDLE THESE
182 return (dest.length()>0);
185 bool grab_token_string(string &dest,string &source,int32_t &pos,char compc)
187 dest.erase();
188 if(source.length()==0)return false;
190 pos++;//GET RID OF FIRST [ OR compc THAT IS ASSUMED TO BE THERE
191 if(pos>source.size())return false;
193 //GO UNTIL YOU HIT A compc, ], or the end
194 auto s=source.begin(),e=source.end();
195 s+=pos;
196 for(;s<e;++s)
198 if((*s)==compc||(*s)==']')break;
199 dest+=(*s);
200 pos++;
202 return (dest.length()>0);
205 bool grab_token_string(string &dest,string &source,char compc)
207 dest.erase();
208 if(source.length()==0)return false;
210 //GO UNTIL YOU HIT A :, ], or the end
211 auto s=source.begin(),e=source.end();
212 for(;s<e;++s)
214 if((*s)==compc||(*s)==']')break;
215 dest+=(*s);
217 return (dest.length()>0);
220 bool grab_token_string_pos(string &dest,string &source,int32_t pos,char compc)
222 dest.erase();
223 if(source.length()==0)return false;
224 if(pos>source.length())return false;
226 //GO UNTIL YOU HIT A :, ], or the end
227 auto s=source.begin(),e=source.end();
228 s+=pos;
229 for(;s<e;++s)
231 if((*s)==compc||(*s)==']')break;
232 dest+=(*s);
234 return (dest.length()>0);
237 bool grab_token_string(string &dest,const char *source,char compc)
239 dest.erase();
240 int32_t sz=strlen(source);
241 if(sz==0)return false;
243 //GO UNTIL YOU HIT A :, ], or the end
244 int32_t s;
245 for(s=0;s<sz;s++)
247 if(source[s]==compc||source[s]==']')break;
248 dest+=source[s];
250 return (dest.length()>0);
254 void replace_token_string(string &token,string &str,int32_t pos,char compc,string &nw,char repc)
256 string rep;
257 if(repc!=0)rep=repc;
258 rep+=token;
259 if(compc!=0)rep+=compc;
261 string::size_type wpos;
263 if ((wpos = str.find(rep)) != string::npos)
265 str.replace(wpos,rep.size(),nw);
269 void simplify_string(string &str)
271 int32_t s;
272 for(s=0;s<str.length();s++)
274 //CAPITALIZE
275 if(str[s]>='A'&&str[s]<='Z')
277 str[s]-='A';
278 str[s]+='a';
280 switch(str[s])
282 case (char)129:
283 case (char)150:
284 case (char)151:
285 case (char)154:
286 case (char)163:
287 str[s]='u';
288 break;
289 case (char)152:
290 str[s]='y';
291 break;
292 case (char)164:
293 case (char)165:
294 str[s]='n';
295 break;
296 case (char)131:
297 case (char)132:
298 case (char)133:
299 case (char)134:
300 case (char)142:
301 case (char)143:
302 case (char)145:
303 case (char)146:
304 case (char)160:
305 str[s]='a';
306 break;
307 case (char)130:
308 case (char)136:
309 case (char)137:
310 case (char)138:
311 case (char)144:
312 str[s]='e';
313 break;
314 case (char)139:
315 case (char)140:
316 case (char)141:
317 case (char)161:
318 str[s]='i';
319 break;
320 case (char)147:
321 case (char)148:
322 case (char)149:
323 case (char)153:
324 case (char)162:
325 str[s]='o';
326 break;
327 case (char)128:
328 case (char)135:
329 str[s]='c';
330 break;
335 void lower_case_string(string &str)
337 int32_t s;
338 for(s=0;s<str.length();s++)
340 //CAPITALIZE
341 if(str[s]>='A'&&str[s]<='Z')
343 str[s]-='A';
344 str[s]+='a';
346 switch(str[s])
348 case (char)154:str[s]=(char)129;break;
349 case (char)165:str[s]=(char)164;break;
350 case (char)142:str[s]=(char)132;break;
351 case (char)143:str[s]=(char)134;break;
352 case (char)144:str[s]=(char)130;break;
353 case (char)153:str[s]=(char)148;break;
354 case (char)128:str[s]=(char)135;break;
355 case (char)146:str[s]=(char)145;break;
360 void upper_case_string(string &str)
362 int32_t s;
363 for(s=0;s<str.length();s++)
365 //CAPITALIZE
366 if(str[s]>='a'&&str[s]<='z')
368 str[s]-='a';
369 str[s]+='A';
371 switch(str[s])
373 case (char)129:str[s]=(char)154;break;
374 case (char)164:str[s]=(char)165;break;
375 case (char)132:str[s]=(char)142;break;
376 case (char)134:str[s]=(char)143;break;
377 case (char)130:str[s]=(char)144;break;
378 case (char)148:str[s]=(char)153;break;
379 case (char)135:str[s]=(char)128;break;
380 case (char)145:str[s]=(char)146;break;
385 void capitalize_string_words(string &str)
387 char conf;
388 int32_t s;
389 for(s=0;s<str.length();s++)
391 conf=0;
392 if(s>0)
394 if(str[s-1]==' '||
395 str[s-1]=='\"')conf=1;
396 if(str[s-1]=='\'')
398 //DISCOUNT SINGLE QUOTE IF IT ISN'T PRECEDED BY SPACE, COMMA OR NOTHING
399 if(s<=0)conf=1;
400 else if(s>=2)
402 if(str[s-2]==' '||
403 str[s-2]==',')conf=1;
407 if(s==0||conf)
409 //CAPITALIZE
410 if(str[s]>='a'&&str[s]<='z')
412 str[s]-='a';
413 str[s]+='A';
415 switch(str[s])
417 case (char)129:str[s]=(char)154;break;
418 case (char)164:str[s]=(char)165;break;
419 case (char)132:str[s]=(char)142;break;
420 case (char)134:str[s]=(char)143;break;
421 case (char)130:str[s]=(char)144;break;
422 case (char)148:str[s]=(char)153;break;
423 case (char)135:str[s]=(char)128;break;
424 case (char)145:str[s]=(char)146;break;
430 void capitalize_string_first_word(string &str)
432 char conf;
433 int32_t s;
434 for(s=0;s<str.length();s++)
436 conf=0;
437 if(s>0)
439 if(str[s-1]==' '||
440 str[s-1]=='\"')conf=1;
441 if(str[s-1]=='\'')
443 //DISCOUNT SINGLE QUOTE IF IT ISN'T PRECEDED BY SPACE, COMMA OR NOTHING
444 if(s<=0)conf=1;
445 else if(s>=2)
447 if(str[s-2]==' '||
448 str[s-2]==',')conf=1;
452 if(s==0||conf)
454 //CAPITALIZE
455 if(str[s]>='a'&&str[s]<='z')
457 str[s]-='a';
458 str[s]+='A';
459 return;
461 switch(str[s])
463 case (char)129:str[s]=(char)154;return;
464 case (char)164:str[s]=(char)165;return;
465 case (char)132:str[s]=(char)142;return;
466 case (char)134:str[s]=(char)143;return;
467 case (char)130:str[s]=(char)144;return;
468 case (char)148:str[s]=(char)153;return;
469 case (char)135:str[s]=(char)128;return;
470 case (char)145:str[s]=(char)146;return;
472 if(str[s]!=' '&&str[s]!='\"')return;
477 static void abbreviate_string_helper(string &str, int len) {
478 if(str.length()>=2)
480 if((str[0]=='A'||str[0]=='a')&&
481 str[1]==' ')
483 str.erase(str.begin()+1);
484 str.erase(str.begin());
486 if(str.length()<=len)return;
489 if(str.length()>=3)
491 if((str[0]=='A'||str[0]=='a')&&
492 (str[1]=='N'||str[1]=='n')&&
493 str[2]==' ')
495 str.erase(str.begin()+2);
496 str.erase(str.begin()+1);
497 str.erase(str.begin());
499 if(str.length()<=len)return;
502 if(str.length()>=4)
504 if((str[0]=='T'||str[0]=='t')&&
505 (str[1]=='H'||str[1]=='h')&&
506 (str[2]=='E'||str[2]=='e')&&
507 str[3]==' ')
509 str.erase(str.begin()+3);
510 str.erase(str.begin()+2);
511 str.erase(str.begin()+1);
512 str.erase(str.begin());
514 if(str.length()<=len)return;
520 int32_t l;
521 for(l=(int32_t)str.length()-1;l>=1;l--)
523 if(str[l-1]==' ')continue;
525 if(str[l]=='a'||
526 str[l]=='e'||
527 str[l]=='i'||
528 str[l]=='o'||
529 str[l]=='u'||
530 str[l]=='A'||
531 str[l]=='E'||
532 str[l]=='I'||
533 str[l]=='O'||
534 str[l]=='U')
536 str.erase(str.begin()+l);
537 if(str.length()<=len)return;
541 if(str.length()>len)str.resize(len);
545 void abbreviate_string(string &str, int32_t len)
547 if (ttf_manager.ttf_active()) {
548 // We'll need to use TTF-aware text shrinking.
549 while (ttf_manager.size_text(str) > len)
550 abbreviate_string_helper(str, str.length() - 1);
551 } else if(str.length()>len){
552 // 1 letter = 1 tile.
553 abbreviate_string_helper(str, len);
559 void get_number(int32_t number,string &str)
561 str.erase();
563 if(number<0)
565 number*=-1;
566 str="negative ";
568 switch(number)
570 case 0:str="zero";break;
571 case 1:str="one";break;
572 case 2:str="two";break;
573 case 3:str="three";break;
574 case 4:str="four";break;
575 case 5:str="five";break;
576 case 6:str="six";break;
577 case 7:str="seven";break;
578 case 8:str="eight";break;
579 case 9:str="nine";break;
580 case 10:str="ten";break;
581 case 11:str="eleven";break;
582 case 12:str="twelve";break;
583 case 13:str="thirteen";break;
584 case 14:str="fourteen";break;
585 case 15:str="fifteen";break;
586 case 16:str="sixteen";break;
587 case 17:str="seventeen";break;
588 case 18:str="eighteen";break;
589 case 19:str="nineteen";break;
590 default:
592 if(number>=1000000000)
594 string nm;
595 get_number(number/1000000000,nm);
596 str+=nm;
597 str+=" billion";
598 if(number%1000000000!=0)
600 str+=" ";
601 get_number(number%1000000000,nm);
602 str+=nm;
604 return;
606 if(number>=1000000&&number<1000000000)
608 string nm;
609 get_number(number/1000000,nm);
610 str+=nm;
611 str+=" million";
612 if(number%1000000!=0)
614 str+=" ";
615 get_number(number%1000000,nm);
616 str+=nm;
618 return;
620 if(number>=1000&&number<1000000)
622 string nm;
623 get_number(number/1000,nm);
624 str+=nm;
625 str+=" thousand";
626 if(number%1000!=0)
628 str+=" ";
629 get_number(number%1000,nm);
630 str+=nm;
632 return;
634 if(number>=100&&number<1000)
636 string nm;
637 get_number(number/100,nm);
638 str+=nm;
639 str+=" hundred";
640 if(number%100!=0)
642 str+=" ";
643 get_number(number%100,nm);
644 str+=nm;
646 return;
648 if(number>=20&&number<100)
650 switch(number/10)
652 case 2:str="twenty";break;
653 case 3:str="thirty";break;
654 case 4:str="forty";break;
655 case 5:str="fifty";break;
656 case 6:str="sixty";break;
657 case 7:str="seventy";break;
658 case 8:str="eighty";break;
659 case 9:str="ninety";break;
661 if(number%10!=0)
663 str+="-";
664 string nm;
665 get_number(number%10,nm);
666 str+=nm;
668 return;
670 add_long_to_string(number,str);
671 break;
676 void get_ordinal(int32_t number,string &str,bool shorten)
678 str.erase();
680 if(shorten)
682 if(number<0)
684 number*=-1;
685 str="-";
687 add_long_to_string(number,str);
688 switch(number%10)
690 case 1:
691 if(number%100==11)str+="th";
692 else str+="st";
693 break;
694 case 2:
695 if(number%100==12)str+="th";
696 else str+="nd";
697 break;
698 case 3:
699 if(number%100==13)str+="th";
700 else str+="rd";
701 break;
702 default:
703 str+="th";
704 break;
706 return;
710 if(number<0)
712 number*=-1;
713 str="Negative ";
715 switch(number)
717 case 0:str="Zeroth";break;
718 case 1:str="First";break;
719 case 2:str="Second";break;
720 case 3:str="Third";break;
721 case 4:str="Fourth";break;
722 case 5:str="Fifth";break;
723 case 6:str="Sixth";break;
724 case 7:str="Seventh";break;
725 case 8:str="Eighth";break;
726 case 9:str="Ninth";break;
727 case 10:str="Tenth";break;
728 case 11:str="Eleventh";break;
729 case 12:str="Twelfth";break;
730 case 13:str="Thirteenth";break;
731 case 14:str="Fourteenth";break;
732 case 15:str="Fifteenth";break;
733 case 16:str="Sixteenth";break;
734 case 17:str="Seventeenth";break;
735 case 18:str="Eighteenth";break;
736 case 19:str="Nineteenth";break;
737 default:
738 add_long_to_string(number,str);
739 switch(number%10)
741 case 1:
742 if(number%100==11)str+="th";
743 else str+="st";
744 break;
745 case 2:
746 if(number%100==12)str+="th";
747 else str+="nd";
748 break;
749 case 3:
750 if(number%100==13)str+="th";
751 else str+="rd";
752 break;
753 default:
754 str+="th";
755 break;
757 break;
761 // Map DF's CP437 to Unicode
762 // see: http://dwarffortresswiki.net/index.php/Character_table
763 int charmap[256] = {
764 ' ', 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
765 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
766 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8,
767 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC,
768 /* 0x20 */
769 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
770 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
771 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
772 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
773 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
774 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x2302,
775 /* 0x80 */
776 0xC7, 0xFC, 0xE9, 0xE2, 0xE4, 0xE0, 0xE5, 0xE7,
777 0xEA, 0xEB, 0xE8, 0xEF, 0xEE, 0xEC, 0xC4, 0xC5,
778 0xC9, 0xE6, 0xC6, 0xF4, 0xF6, 0xF2, 0xFB, 0xF9,
779 0xFF, 0xD6, 0xDC, 0xA2, 0xA3, 0xA5, 0x20A7, 0x192,
780 0xE1, 0xED, 0xF3, 0xFA, 0xF1, 0xD1, 0xAA, 0xBA,
781 0xBF, 0x2310, 0xAC, 0xBD, 0xBC, 0xA1, 0xAB, 0xBB,
782 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
783 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
784 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
785 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
786 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
787 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
788 0x3B1, 0xDF/*yay*/, 0x393, 0x3C0, 0x3A3, 0x3C3, 0xB5, 0x3C4,
789 0x3A6, 0x398, 0x3A9, 0x3B4, 0x221E, 0x3C6, 0x3B5, 0x2229,
790 0x2261, 0xB1, 0x2265, 0x2264, 0x2320, 0x2321, 0xF7, 0x2248,
791 0xB0, 0x2219, 0xB7, 0x221A, 0x207F, 0xB2, 0x25A0, 0xA0