]> git.lizzy.rs Git - dragonfireclient.git/blob - src/utility.h
9e47a5dacbdecbb3083138724392e39838c3d39a
[dragonfireclient.git] / src / utility.h
1 /*
2 Minetest-c55
3 Copyright (C) 2010 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifndef UTILITY_HEADER
21 #define UTILITY_HEADER
22
23 #include <iostream>
24 #include <fstream>
25 #include <string>
26 #include <sstream>
27 #include <jthread.h>
28 #include <jmutex.h>
29 #include <jmutexautolock.h>
30
31 #include "common_irrlicht.h"
32 #include "debug.h"
33 #include "strfnd.h"
34 #include "exceptions.h"
35 #include "porting.h"
36
37 extern const v3s16 g_26dirs[26];
38
39 // 26th is (0,0,0)
40 extern const v3s16 g_27dirs[27];
41
42 inline void writeU32(u8 *data, u32 i)
43 {
44         data[0] = ((i>>24)&0xff);
45         data[1] = ((i>>16)&0xff);
46         data[2] = ((i>> 8)&0xff);
47         data[3] = ((i>> 0)&0xff);
48 }
49
50 inline void writeU16(u8 *data, u16 i)
51 {
52         data[0] = ((i>> 8)&0xff);
53         data[1] = ((i>> 0)&0xff);
54 }
55
56 inline void writeU8(u8 *data, u8 i)
57 {
58         data[0] = ((i>> 0)&0xff);
59 }
60
61 inline u32 readU32(u8 *data)
62 {
63         return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
64 }
65
66 inline u16 readU16(u8 *data)
67 {
68         return (data[0]<<8) | (data[1]<<0);
69 }
70
71 inline u8 readU8(u8 *data)
72 {
73         return (data[0]<<0);
74 }
75
76 // Signed variants of the above
77
78 inline void writeS32(u8 *data, s32 i){
79         writeU32(data, (u32)i);
80 }
81 inline s32 readS32(u8 *data){
82         return (s32)readU32(data);
83 }
84
85 inline void writeS16(u8 *data, s16 i){
86         writeU16(data, (u16)i);
87 }
88 inline s16 readS16(u8 *data){
89         return (s16)readU16(data);
90 }
91
92 inline void writeV3S32(u8 *data, v3s32 p)
93 {
94         writeS32(&data[0], p.X);
95         writeS32(&data[4], p.Y);
96         writeS32(&data[8], p.Z);
97 }
98
99 inline v3s32 readV3S32(u8 *data)
100 {
101         v3s32 p;
102         p.X = readS32(&data[0]);
103         p.Y = readS32(&data[4]);
104         p.Z = readS32(&data[8]);
105         return p;
106 }
107
108 inline void writeV2S16(u8 *data, v2s16 p)
109 {
110         writeS16(&data[0], p.X);
111         writeS16(&data[2], p.Y);
112 }
113
114 inline v2s16 readV2S16(u8 *data)
115 {
116         v2s16 p;
117         p.X = readS16(&data[0]);
118         p.Y = readS16(&data[2]);
119         return p;
120 }
121
122 inline void writeV2S32(u8 *data, v2s32 p)
123 {
124         writeS32(&data[0], p.X);
125         writeS32(&data[2], p.Y);
126 }
127
128 inline v2s32 readV2S32(u8 *data)
129 {
130         v2s32 p;
131         p.X = readS32(&data[0]);
132         p.Y = readS32(&data[2]);
133         return p;
134 }
135
136 inline void writeV3S16(u8 *data, v3s16 p)
137 {
138         writeS16(&data[0], p.X);
139         writeS16(&data[2], p.Y);
140         writeS16(&data[4], p.Z);
141 }
142
143 inline v3s16 readV3S16(u8 *data)
144 {
145         v3s16 p;
146         p.X = readS16(&data[0]);
147         p.Y = readS16(&data[2]);
148         p.Z = readS16(&data[4]);
149         return p;
150 }
151
152 /*
153         None of these are used at the moment
154 */
155
156 template <typename T>
157 class SharedPtr
158 {
159 public:
160         SharedPtr(T *t=NULL)
161         {
162                 refcount = new int;
163                 *refcount = 1;
164                 ptr = t;
165         }
166         SharedPtr(SharedPtr<T> &t)
167         {
168                 //*this = t;
169                 drop();
170                 refcount = t.refcount;
171                 (*refcount)++;
172                 ptr = t.ptr;
173         }
174         ~SharedPtr()
175         {
176                 drop();
177         }
178         SharedPtr<T> & operator=(T *t)
179         {
180                 drop();
181                 refcount = new int;
182                 *refcount = 1;
183                 ptr = t;
184                 return *this;
185         }
186         SharedPtr<T> & operator=(SharedPtr<T> &t)
187         {
188                 drop();
189                 refcount = t.refcount;
190                 (*refcount)++;
191                 ptr = t.ptr;
192                 return *this;
193         }
194         T* operator->()
195         {
196                 return ptr;
197         }
198         T & operator*()
199         {
200                 return *ptr;
201         }
202         bool operator!=(T *t)
203         {
204                 return ptr != t;
205         }
206         bool operator==(T *t)
207         {
208                 return ptr == t;
209         }
210         T & operator[](unsigned int i)
211         {
212                 return ptr[i];
213         }
214 private:
215         void drop()
216         {
217                 assert((*refcount) > 0);
218                 (*refcount)--;
219                 if(*refcount == 0)
220                 {
221                         delete refcount;
222                         if(ptr != NULL)
223                                 delete ptr;
224                 }
225         }
226         T *ptr;
227         int *refcount;
228 };
229
230 template <typename T>
231 class Buffer
232 {
233 public:
234         Buffer(unsigned int size)
235         {
236                 m_size = size;
237                 data = new T[size];
238         }
239         Buffer(const Buffer &buffer)
240         {
241                 m_size = buffer.m_size;
242                 data = new T[buffer.m_size];
243                 memcpy(data, buffer.data, buffer.m_size);
244         }
245         Buffer(T *t, unsigned int size)
246         {
247                 m_size = size;
248                 data = new T[size];
249                 memcpy(data, t, size);
250         }
251         ~Buffer()
252         {
253                 delete[] data;
254         }
255         T & operator[](unsigned int i) const
256         {
257                 return data[i];
258         }
259         T * operator*() const
260         {
261                 return data;
262         }
263         unsigned int getSize() const
264         {
265                 return m_size;
266         }
267 private:
268         T *data;
269         unsigned int m_size;
270 };
271
272 template <typename T>
273 class SharedBuffer
274 {
275 public:
276         SharedBuffer(unsigned int size)
277         {
278                 m_size = size;
279                 data = new T[size];
280                 refcount = new unsigned int;
281                 (*refcount) = 1;
282         }
283         SharedBuffer(const SharedBuffer &buffer)
284         {
285                 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
286                 m_size = buffer.m_size;
287                 data = buffer.data;
288                 refcount = buffer.refcount;
289                 (*refcount)++;
290         }
291         SharedBuffer & operator=(const SharedBuffer & buffer)
292         {
293                 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
294                 if(this == &buffer)
295                         return *this;
296                 drop();
297                 m_size = buffer.m_size;
298                 data = buffer.data;
299                 refcount = buffer.refcount;
300                 (*refcount)++;
301                 return *this;
302         }
303         /*
304                 Copies whole buffer
305         */
306         SharedBuffer(T *t, unsigned int size)
307         {
308                 m_size = size;
309                 data = new T[size];
310                 memcpy(data, t, size);
311                 refcount = new unsigned int;
312                 (*refcount) = 1;
313         }
314         /*
315                 Copies whole buffer
316         */
317         SharedBuffer(const Buffer<T> &buffer)
318         {
319                 m_size = buffer.m_size;
320                 data = new T[buffer.getSize()];
321                 memcpy(data, *buffer, buffer.getSize());
322                 refcount = new unsigned int;
323                 (*refcount) = 1;
324         }
325         ~SharedBuffer()
326         {
327                 drop();
328         }
329         T & operator[](unsigned int i) const
330         {
331                 return data[i];
332         }
333         T * operator*() const
334         {
335                 return data;
336         }
337         unsigned int getSize() const
338         {
339                 return m_size;
340         }
341 private:
342         void drop()
343         {
344                 assert((*refcount) > 0);
345                 (*refcount)--;
346                 if(*refcount == 0)
347                 {
348                         delete[] data;
349                         delete refcount;
350                 }
351         }
352         T *data;
353         unsigned int m_size;
354         unsigned int *refcount;
355 };
356
357 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
358 {
359         SharedBuffer<u8> b((u8*)string, strlen(string)+1);
360         return b;
361 }
362
363 template<typename T>
364 class MutexedVariable
365 {
366 public:
367         MutexedVariable(T value):
368                 m_value(value)
369         {
370                 m_mutex.Init();
371         }
372
373         T get()
374         {
375                 JMutexAutoLock lock(m_mutex);
376                 return m_value;
377         }
378
379         void set(T value)
380         {
381                 JMutexAutoLock lock(m_mutex);
382                 m_value = value;
383         }
384         
385         // You'll want to grab this in a SharedPtr
386         JMutexAutoLock * getLock()
387         {
388                 return new JMutexAutoLock(m_mutex);
389         }
390         
391         // You pretty surely want to grab the lock when accessing this
392         T m_value;
393
394 private:
395         JMutex m_mutex;
396 };
397
398 /*
399         TimeTaker
400 */
401
402 class IrrlichtWrapper;
403
404 class TimeTaker
405 {
406 public:
407         TimeTaker(const char *name, u32 *result=NULL);
408
409         ~TimeTaker()
410         {
411                 stop();
412         }
413
414         u32 stop(bool quiet=false);
415
416         u32 getTime();
417
418 private:
419         const char *m_name;
420         u32 m_time1;
421         bool m_running;
422         u32 *m_result;
423 };
424
425 // Calculates the borders of a "d-radius" cube
426 inline void getFacePositions(core::list<v3s16> &list, u16 d)
427 {
428         if(d == 0)
429         {
430                 list.push_back(v3s16(0,0,0));
431                 return;
432         }
433         if(d == 1)
434         {
435                 /*
436                         This is an optimized sequence of coordinates.
437                 */
438                 list.push_back(v3s16( 0, 1, 0)); // top
439                 list.push_back(v3s16( 0, 0, 1)); // back
440                 list.push_back(v3s16(-1, 0, 0)); // left
441                 list.push_back(v3s16( 1, 0, 0)); // right
442                 list.push_back(v3s16( 0, 0,-1)); // front
443                 list.push_back(v3s16( 0,-1, 0)); // bottom
444                 // 6
445                 list.push_back(v3s16(-1, 0, 1)); // back left
446                 list.push_back(v3s16( 1, 0, 1)); // back right
447                 list.push_back(v3s16(-1, 0,-1)); // front left
448                 list.push_back(v3s16( 1, 0,-1)); // front right
449                 list.push_back(v3s16(-1,-1, 0)); // bottom left
450                 list.push_back(v3s16( 1,-1, 0)); // bottom right
451                 list.push_back(v3s16( 0,-1, 1)); // bottom back
452                 list.push_back(v3s16( 0,-1,-1)); // bottom front
453                 list.push_back(v3s16(-1, 1, 0)); // top left
454                 list.push_back(v3s16( 1, 1, 0)); // top right
455                 list.push_back(v3s16( 0, 1, 1)); // top back
456                 list.push_back(v3s16( 0, 1,-1)); // top front
457                 // 18
458                 list.push_back(v3s16(-1, 1, 1)); // top back-left
459                 list.push_back(v3s16( 1, 1, 1)); // top back-right
460                 list.push_back(v3s16(-1, 1,-1)); // top front-left
461                 list.push_back(v3s16( 1, 1,-1)); // top front-right
462                 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
463                 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
464                 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
465                 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
466                 // 26
467                 return;
468         }
469
470         // Take blocks in all sides, starting from y=0 and going +-y
471         for(s16 y=0; y<=d-1; y++)
472         {
473                 // Left and right side, including borders
474                 for(s16 z=-d; z<=d; z++)
475                 {
476                         list.push_back(v3s16(d,y,z));
477                         list.push_back(v3s16(-d,y,z));
478                         if(y != 0)
479                         {
480                                 list.push_back(v3s16(d,-y,z));
481                                 list.push_back(v3s16(-d,-y,z));
482                         }
483                 }
484                 // Back and front side, excluding borders
485                 for(s16 x=-d+1; x<=d-1; x++)
486                 {
487                         list.push_back(v3s16(x,y,d));
488                         list.push_back(v3s16(x,y,-d));
489                         if(y != 0)
490                         {
491                                 list.push_back(v3s16(x,-y,d));
492                                 list.push_back(v3s16(x,-y,-d));
493                         }
494                 }
495         }
496
497         // Take the bottom and top face with borders
498         // -d<x<d, y=+-d, -d<z<d
499         for(s16 x=-d; x<=d; x++)
500         for(s16 z=-d; z<=d; z++)
501         {
502                 list.push_back(v3s16(x,-d,z));
503                 list.push_back(v3s16(x,d,z));
504         }
505 }
506
507 class IndentationRaiser
508 {
509 public:
510         IndentationRaiser(u16 *indentation)
511         {
512                 m_indentation = indentation;
513                 (*m_indentation)++;
514         }
515         ~IndentationRaiser()
516         {
517                 (*m_indentation)--;
518         }
519 private:
520         u16 *m_indentation;
521 };
522
523 inline s16 getContainerPos(s16 p, s16 d)
524 {
525         return (p>=0 ? p : p-d+1) / d;
526 }
527
528 inline v2s16 getContainerPos(v2s16 p, s16 d)
529 {
530         return v2s16(
531                 getContainerPos(p.X, d),
532                 getContainerPos(p.Y, d)
533         );
534 }
535
536 inline v3s16 getContainerPos(v3s16 p, s16 d)
537 {
538         return v3s16(
539                 getContainerPos(p.X, d),
540                 getContainerPos(p.Y, d),
541                 getContainerPos(p.Z, d)
542         );
543 }
544
545 inline v2s16 getContainerPos(v2s16 p, v2s16 d)
546 {
547         return v2s16(
548                 getContainerPos(p.X, d.X),
549                 getContainerPos(p.Y, d.Y)
550         );
551 }
552
553 inline v3s16 getContainerPos(v3s16 p, v3s16 d)
554 {
555         return v3s16(
556                 getContainerPos(p.X, d.X),
557                 getContainerPos(p.Y, d.Y),
558                 getContainerPos(p.Z, d.Z)
559         );
560 }
561
562 inline bool isInArea(v3s16 p, s16 d)
563 {
564         return (
565                 p.X >= 0 && p.X < d &&
566                 p.Y >= 0 && p.Y < d &&
567                 p.Z >= 0 && p.Z < d
568         );
569 }
570
571 inline bool isInArea(v2s16 p, s16 d)
572 {
573         return (
574                 p.X >= 0 && p.X < d &&
575                 p.Y >= 0 && p.Y < d
576         );
577 }
578
579 inline bool isInArea(v3s16 p, v3s16 d)
580 {
581         return (
582                 p.X >= 0 && p.X < d.X &&
583                 p.Y >= 0 && p.Y < d.Y &&
584                 p.Z >= 0 && p.Z < d.Z
585         );
586 }
587
588 inline s16 rangelim(s16 i, s16 max)
589 {
590         if(i < 0)
591                 return 0;
592         if(i > max)
593                 return max;
594         return i;
595 }
596
597 #define rangelim(d, min, max) ((d) < (min) ? (min) : ((d)>(max)?(max):(d)))
598
599 inline v3s16 arealim(v3s16 p, s16 d)
600 {
601         if(p.X < 0)
602                 p.X = 0;
603         if(p.Y < 0)
604                 p.Y = 0;
605         if(p.Z < 0)
606                 p.Z = 0;
607         if(p.X > d-1)
608                 p.X = d-1;
609         if(p.Y > d-1)
610                 p.Y = d-1;
611         if(p.Z > d-1)
612                 p.Z = d-1;
613         return p;
614 }
615
616 inline std::wstring narrow_to_wide(const std::string& mbs)
617 {
618         size_t wcl = mbs.size();
619         SharedBuffer<wchar_t> wcs(wcl+1);
620         size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
621         wcs[l] = 0;
622         return *wcs;
623 }
624
625 inline std::string wide_to_narrow(const std::wstring& wcs)
626 {
627         size_t mbl = wcs.size()*4;
628         SharedBuffer<char> mbs(mbl+1);
629         size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
630         if((int)l == -1)
631                 mbs[0] = 0;
632         else
633                 mbs[l] = 0;
634         return *mbs;
635 }
636
637 /*
638         See test.cpp for example cases.
639         wraps degrees to the range of -360...360
640         NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
641 */
642 inline float wrapDegrees(float f)
643 {
644         // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
645         // This results in
646         // 10, 720, -1, -361
647         int i = floor(f);
648         // 0, 2, 0, -1
649         int l = i / 360;
650         // NOTE: This would be used for wrapping to 0...360
651         // 0, 2, -1, -2
652         /*if(i < 0)
653                 l -= 1;*/
654         // 0, 720, 0, -360
655         int k = l * 360;
656         // 10, 0.5, -0.5, -0.5
657         f -= float(k);
658         return f;
659 }
660
661 inline std::string lowercase(const std::string &s)
662 {
663         std::string s2;
664         for(size_t i=0; i<s.size(); i++)
665         {
666                 char c = s[i];
667                 if(c >= 'A' && c <= 'Z')
668                         c -= 'A' - 'a';
669                 s2 += c;
670         }
671         return s2;
672 }
673
674 inline bool is_yes(const std::string &s)
675 {
676         std::string s2 = lowercase(trim(s));
677         if(s2 == "y" || s2 == "yes" || s2 == "true" || s2 == "1")
678                 return true;
679         return false;
680 }
681
682 inline s32 stoi(const std::string &s, s32 min, s32 max)
683 {
684         s32 i = atoi(s.c_str());
685         if(i < min)
686                 i = min;
687         if(i > max)
688                 i = max;
689         return i;
690 }
691
692 inline s32 stoi(std::string s)
693 {
694         return atoi(s.c_str());
695 }
696
697 inline float stof(std::string s)
698 {
699         float f;
700         std::istringstream ss(s);
701         ss>>f;
702         return f;
703 }
704
705 inline std::string itos(s32 i)
706 {
707         std::ostringstream o;
708         o<<i;
709         return o.str();
710 }
711
712 inline std::string ftos(float f)
713 {
714         std::ostringstream o;
715         o<<f;
716         return o.str();
717 }
718
719 inline void str_replace(std::string & str, std::string const & pattern,
720                 std::string const & replacement)
721 {
722         std::string::size_type start = str.find(pattern, 0);
723         while(start != str.npos)
724         {
725                 str.replace(start, pattern.size(), replacement);
726                 start = str.find(pattern, start+replacement.size());
727         }
728 }
729
730 inline void str_replace_char(std::string & str, char from, char to)
731 {
732         for(unsigned int i=0; i<str.size(); i++)
733         {
734                 if(str[i] == from)
735                         str[i] = to;
736         }
737 }
738
739 /*
740         A base class for simple background thread implementation
741 */
742
743 class SimpleThread : public JThread
744 {
745         bool run;
746         JMutex run_mutex;
747
748 public:
749
750         SimpleThread():
751                 JThread(),
752                 run(true)
753         {
754                 run_mutex.Init();
755         }
756
757         virtual ~SimpleThread()
758         {}
759
760         virtual void * Thread() = 0;
761
762         bool getRun()
763         {
764                 JMutexAutoLock lock(run_mutex);
765                 return run;
766         }
767         void setRun(bool a_run)
768         {
769                 JMutexAutoLock lock(run_mutex);
770                 run = a_run;
771         }
772
773         void stop()
774         {
775                 setRun(false);
776                 while(IsRunning())
777                         sleep_ms(100);
778         }
779 };
780
781 /*
782         Config stuff
783 */
784
785 enum ValueType
786 {
787         VALUETYPE_STRING,
788         VALUETYPE_FLAG // Doesn't take any arguments
789 };
790
791 struct ValueSpec
792 {
793         ValueSpec(ValueType a_type, const char *a_help=NULL)
794         {
795                 type = a_type;
796                 help = a_help;
797         }
798         ValueType type;
799         const char *help;
800 };
801
802 class Settings
803 {
804 public:
805
806         void writeLines(std::ostream &os)
807         {
808                 for(core::map<std::string, std::string>::Iterator
809                                 i = m_settings.getIterator();
810                                 i.atEnd() == false; i++)
811                 {
812                         std::string name = i.getNode()->getKey();
813                         std::string value = i.getNode()->getValue();
814                         os<<name<<" = "<<value<<"\n";
815                 }
816         }
817
818         bool parseConfigLine(const std::string &line)
819         {
820                 std::string trimmedline = trim(line);
821                 
822                 // Ignore comments
823                 if(trimmedline[0] == '#')
824                         return true;
825
826                 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
827
828                 Strfnd sf(trim(line));
829
830                 std::string name = sf.next("=");
831                 name = trim(name);
832
833                 if(name == "")
834                         return true;
835                 
836                 std::string value = sf.next("\n");
837                 value = trim(value);
838
839                 /*dstream<<"Config name=\""<<name<<"\" value=\""
840                                 <<value<<"\""<<std::endl;*/
841                 
842                 m_settings[name] = value;
843                 
844                 return true;
845         }
846
847         // Returns false on EOF
848         bool parseConfigObject(std::istream &is)
849         {
850                 if(is.eof())
851                         return false;
852                 
853                 /*
854                         NOTE: This function might be expanded to allow multi-line
855                               settings.
856                 */
857                 std::string line;
858                 std::getline(is, line);
859                 //dstream<<"got line: \""<<line<<"\""<<std::endl;
860
861                 return parseConfigLine(line);
862         }
863
864         /*
865                 Read configuration file
866
867                 Returns true on success
868         */
869         bool readConfigFile(const char *filename)
870         {
871                 std::ifstream is(filename);
872                 if(is.good() == false)
873                 {
874                         dstream<<"Error opening configuration file \""
875                                         <<filename<<"\""<<std::endl;
876                         return false;
877                 }
878
879                 dstream<<"Parsing configuration file: \""
880                                 <<filename<<"\""<<std::endl;
881                                 
882                 while(parseConfigObject(is));
883                 
884                 return true;
885         }
886
887         /*
888                 Reads a configuration object from stream (usually a single line)
889                 and adds it to dst.
890                 
891                 Preserves comments and empty lines.
892
893                 Settings that were added to dst are also added to updated.
894                 key of updated is setting name, value of updated is dummy.
895
896                 Returns false on EOF
897         */
898         bool getUpdatedConfigObject(std::istream &is,
899                         core::list<std::string> &dst,
900                         core::map<std::string, bool> &updated)
901         {
902                 if(is.eof())
903                         return false;
904                 
905                 // NOTE: This function will be expanded to allow multi-line settings
906                 std::string line;
907                 std::getline(is, line);
908
909                 std::string trimmedline = trim(line);
910
911                 std::string line_end = "";
912                 if(is.eof() == false)
913                         line_end = "\n";
914                 
915                 // Ignore comments
916                 if(trimmedline[0] == '#')
917                 {
918                         dst.push_back(line+line_end);
919                         return true;
920                 }
921
922                 Strfnd sf(trim(line));
923
924                 std::string name = sf.next("=");
925                 name = trim(name);
926
927                 if(name == "")
928                 {
929                         dst.push_back(line+line_end);
930                         return true;
931                 }
932                 
933                 std::string value = sf.next("\n");
934                 value = trim(value);
935                 
936                 if(m_settings.find(name))
937                 {
938                         std::string newvalue = m_settings[name];
939                         
940                         if(newvalue != value)
941                         {
942                                 dstream<<"Changing value of \""<<name<<"\" = \""
943                                                 <<value<<"\" -> \""<<newvalue<<"\""
944                                                 <<std::endl;
945                         }
946
947                         dst.push_back(name + " = " + newvalue + line_end);
948
949                         updated[name] = true;
950                 }
951                 
952                 return true;
953         }
954
955         /*
956                 Updates configuration file
957
958                 Returns true on success
959         */
960         bool updateConfigFile(const char *filename)
961         {
962                 dstream<<"Updating configuration file: \""
963                                 <<filename<<"\""<<std::endl;
964                 
965                 core::list<std::string> objects;
966                 core::map<std::string, bool> updated;
967                 
968                 // Read and modify stuff
969                 {
970                         std::ifstream is(filename);
971                         if(is.good() == false)
972                         {
973                                 dstream<<"Error opening configuration file"
974                                                 " for reading: \""
975                                                 <<filename<<"\""<<std::endl;
976                                 return false;
977                         }
978
979                         while(getUpdatedConfigObject(is, objects, updated));
980                 }
981                 
982                 // Write stuff back
983                 {
984                         std::ofstream os(filename);
985                         if(os.good() == false)
986                         {
987                                 dstream<<"Error opening configuration file"
988                                                 " for writing: \""
989                                                 <<filename<<"\""<<std::endl;
990                                 return false;
991                         }
992                         
993                         /*
994                                 Write updated stuff
995                         */
996                         for(core::list<std::string>::Iterator
997                                         i = objects.begin();
998                                         i != objects.end(); i++)
999                         {
1000                                 os<<(*i);
1001                         }
1002
1003                         /*
1004                                 Write stuff that was not already in the file
1005                         */
1006                         for(core::map<std::string, std::string>::Iterator
1007                                         i = m_settings.getIterator();
1008                                         i.atEnd() == false; i++)
1009                         {
1010                                 if(updated.find(i.getNode()->getKey()))
1011                                         continue;
1012                                 std::string name = i.getNode()->getKey();
1013                                 std::string value = i.getNode()->getValue();
1014                                 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
1015                                                 <<std::endl;
1016                                 os<<name<<" = "<<value<<"\n";
1017                         }
1018                 }
1019                 
1020                 return true;
1021         }
1022
1023         /*
1024                 NOTE: Types of allowed_options are ignored
1025
1026                 returns true on success
1027         */
1028         bool parseCommandLine(int argc, char *argv[],
1029                         core::map<std::string, ValueSpec> &allowed_options)
1030         {
1031                 int i=1;
1032                 for(;;)
1033                 {
1034                         if(i >= argc)
1035                                 break;
1036                         std::string argname = argv[i];
1037                         if(argname.substr(0, 2) != "--")
1038                         {
1039                                 dstream<<"Invalid command-line parameter \""
1040                                                 <<argname<<"\": --<option> expected."<<std::endl;
1041                                 return false;
1042                         }
1043                         i++;
1044
1045                         std::string name = argname.substr(2);
1046
1047                         core::map<std::string, ValueSpec>::Node *n;
1048                         n = allowed_options.find(name);
1049                         if(n == NULL)
1050                         {
1051                                 dstream<<"Unknown command-line parameter \""
1052                                                 <<argname<<"\""<<std::endl;
1053                                 return false;
1054                         }
1055
1056                         ValueType type = n->getValue().type;
1057
1058                         std::string value = "";
1059                         
1060                         if(type == VALUETYPE_FLAG)
1061                         {
1062                                 value = "true";
1063                         }
1064                         else
1065                         {
1066                                 if(i >= argc)
1067                                 {
1068                                         dstream<<"Invalid command-line parameter \""
1069                                                         <<name<<"\": missing value"<<std::endl;
1070                                         return false;
1071                                 }
1072                                 value = argv[i];
1073                                 i++;
1074                         }
1075                         
1076
1077                         dstream<<"Valid command-line parameter: \""
1078                                         <<name<<"\" = \""<<value<<"\""
1079                                         <<std::endl;
1080                         set(name, value);
1081                 }
1082
1083                 return true;
1084         }
1085
1086         void set(std::string name, std::string value)
1087         {
1088                 m_settings[name] = value;
1089         }
1090
1091         void setDefault(std::string name, std::string value)
1092         {
1093                 m_defaults[name] = value;
1094         }
1095
1096         bool exists(std::string name)
1097         {
1098                 return (m_settings.find(name) || m_defaults.find(name));
1099         }
1100
1101         std::string get(std::string name)
1102         {
1103                 core::map<std::string, std::string>::Node *n;
1104                 n = m_settings.find(name);
1105                 if(n == NULL)
1106                 {
1107                         n = m_defaults.find(name);
1108                         if(n == NULL)
1109                         {
1110                                 dstream<<"INFO: Settings: Setting not found: \""
1111                                                 <<name<<"\""<<std::endl;
1112                                 throw SettingNotFoundException("Setting not found");
1113                         }
1114                 }
1115
1116                 return n->getValue();
1117         }
1118
1119         bool getBool(std::string name)
1120         {
1121                 return is_yes(get(name));
1122         }
1123         
1124         bool getFlag(std::string name)
1125         {
1126                 try
1127                 {
1128                         return getBool(name);
1129                 }
1130                 catch(SettingNotFoundException &e)
1131                 {
1132                         return false;
1133                 }
1134         }
1135
1136         // Asks if empty
1137         bool getBoolAsk(std::string name, std::string question, bool def)
1138         {
1139                 // If it is in settings
1140                 if(m_settings.find(name))
1141                         return getBool(name);
1142                 
1143                 std::string s;
1144                 char templine[10];
1145                 std::cout<<question<<" [y/N]: ";
1146                 std::cin.getline(templine, 10);
1147                 s = templine;
1148
1149                 if(s == "")
1150                         return def;
1151
1152                 return is_yes(s);
1153         }
1154
1155         float getFloat(std::string name)
1156         {
1157                 return stof(get(name));
1158         }
1159
1160         u16 getU16(std::string name)
1161         {
1162                 return stoi(get(name), 0, 65535);
1163         }
1164
1165         u16 getU16Ask(std::string name, std::string question, u16 def)
1166         {
1167                 // If it is in settings
1168                 if(m_settings.find(name))
1169                         return getU16(name);
1170                 
1171                 std::string s;
1172                 char templine[10];
1173                 std::cout<<question<<" ["<<def<<"]: ";
1174                 std::cin.getline(templine, 10);
1175                 s = templine;
1176
1177                 if(s == "")
1178                         return def;
1179
1180                 return stoi(s, 0, 65535);
1181         }
1182
1183         s16 getS16(std::string name)
1184         {
1185                 return stoi(get(name), -32768, 32767);
1186         }
1187
1188         s32 getS32(std::string name)
1189         {
1190                 return stoi(get(name));
1191         }
1192
1193         v3f getV3F(std::string name)
1194         {
1195                 v3f value;
1196                 Strfnd f(get(name));
1197                 f.next("(");
1198                 value.X = stof(f.next(","));
1199                 value.Y = stof(f.next(","));
1200                 value.Z = stof(f.next(")"));
1201                 return value;
1202         }
1203
1204         u64 getU64(std::string name)
1205         {
1206                 u64 value = 0;
1207                 std::string s = get(name);
1208                 std::istringstream ss(s);
1209                 ss>>value;
1210                 return value;
1211         }
1212
1213         void setS32(std::string name, s32 value)
1214         {
1215                 set(name, itos(value));
1216         }
1217
1218         void setFloat(std::string name, float value)
1219         {
1220                 set(name, ftos(value));
1221         }
1222
1223         void setV3F(std::string name, v3f value)
1224         {
1225                 std::ostringstream os;
1226                 os<<"("<<value.X<<","<<value.Y<<","<<value.Z<<")";
1227                 set(name, os.str());
1228         }
1229
1230         void setU64(std::string name, u64 value)
1231         {
1232                 std::ostringstream os;
1233                 os<<value;
1234                 set(name, os.str());
1235         }
1236
1237         void clear()
1238         {
1239                 m_settings.clear();
1240                 m_defaults.clear();
1241         }
1242
1243         Settings & operator+=(Settings &other)
1244         {
1245                 if(&other == this)
1246                         return *this;
1247
1248                 for(core::map<std::string, std::string>::Iterator
1249                                 i = other.m_settings.getIterator();
1250                                 i.atEnd() == false; i++)
1251                 {
1252                         m_settings.insert(i.getNode()->getKey(),
1253                                         i.getNode()->getValue());
1254                 }
1255                 
1256                 for(core::map<std::string, std::string>::Iterator
1257                                 i = other.m_defaults.getIterator();
1258                                 i.atEnd() == false; i++)
1259                 {
1260                         m_defaults.insert(i.getNode()->getKey(),
1261                                         i.getNode()->getValue());
1262                 }
1263
1264         }
1265
1266         Settings & operator=(Settings &other)
1267         {
1268                 if(&other == this)
1269                         return *this;
1270
1271                 clear();
1272                 (*this) += other;
1273                 
1274                 return *this;
1275         }
1276
1277 private:
1278         core::map<std::string, std::string> m_settings;
1279         core::map<std::string, std::string> m_defaults;
1280 };
1281
1282 /*
1283         FIFO queue
1284 */
1285 template<typename T>
1286 class Queue
1287 {
1288 public:
1289         void push_back(T t)
1290         {
1291                 m_list.push_back(t);
1292         }
1293         
1294         T pop_front()
1295         {
1296                 if(m_list.size() == 0)
1297                         throw ItemNotFoundException("MutexedQueue: queue is empty");
1298
1299                 typename core::list<T>::Iterator begin = m_list.begin();
1300                 T t = *begin;
1301                 m_list.erase(begin);
1302                 return t;
1303         }
1304
1305         u32 size()
1306         {
1307                 return m_list.size();
1308         }
1309
1310 protected:
1311         core::list<T> m_list;
1312 };
1313
1314 /*
1315         Thread-safe FIFO queue
1316 */
1317
1318 template<typename T>
1319 class MutexedQueue
1320 {
1321 public:
1322         MutexedQueue()
1323         {
1324                 m_mutex.Init();
1325         }
1326         u32 size()
1327         {
1328                 return m_list.size();
1329         }
1330         void push_back(T t)
1331         {
1332                 JMutexAutoLock lock(m_mutex);
1333                 m_list.push_back(t);
1334         }
1335         T pop_front(u32 wait_time_max_ms=0)
1336         {
1337                 u32 wait_time_ms = 0;
1338
1339                 for(;;)
1340                 {
1341                         {
1342                                 JMutexAutoLock lock(m_mutex);
1343
1344                                 if(m_list.size() > 0)
1345                                 {
1346                                         typename core::list<T>::Iterator begin = m_list.begin();
1347                                         T t = *begin;
1348                                         m_list.erase(begin);
1349                                         return t;
1350                                 }
1351
1352                                 if(wait_time_ms >= wait_time_max_ms)
1353                                         throw ItemNotFoundException("MutexedQueue: queue is empty");
1354                         }
1355
1356                         // Wait a while before trying again
1357                         sleep_ms(10);
1358                         wait_time_ms += 10;
1359                 }
1360         }
1361
1362         JMutex & getMutex()
1363         {
1364                 return m_mutex;
1365         }
1366
1367         core::list<T> & getList()
1368         {
1369                 return m_list;
1370         }
1371
1372 protected:
1373         JMutex m_mutex;
1374         core::list<T> m_list;
1375 };
1376
1377 template<typename Caller, typename Data>
1378 class CallerInfo
1379 {
1380 public:
1381         Caller caller;
1382         Data data;
1383 };
1384
1385 template<typename Key, typename T, typename Caller, typename CallerData>
1386 class GetResult
1387 {
1388 public:
1389         Key key;
1390         T item;
1391         core::list<CallerInfo<Caller, CallerData> > callers;
1392 };
1393
1394 template<typename Key, typename T, typename Caller, typename CallerData>
1395 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1396 {
1397 };
1398
1399 template<typename Key, typename T, typename Caller, typename CallerData>
1400 class GetRequest
1401 {
1402 public:
1403         GetRequest()
1404         {
1405                 dest = NULL;
1406         }
1407         GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1408         {
1409                 dest = a_dest;
1410         }
1411         GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1412                         Key a_key)
1413         {
1414                 dest = a_dest;
1415                 key = a_key;
1416         }
1417         ~GetRequest()
1418         {
1419         }
1420         
1421         Key key;
1422         ResultQueue<Key, T, Caller, CallerData> *dest;
1423         core::list<CallerInfo<Caller, CallerData> > callers;
1424 };
1425
1426 /*
1427         Quickhands for typical request-result queues.
1428         Used for distributing work between threads.
1429 */
1430
1431 template<typename Key, typename T, typename Caller, typename CallerData>
1432 class RequestQueue
1433 {
1434 public:
1435         u32 size()
1436         {
1437                 return m_queue.size();
1438         }
1439
1440         void add(Key key, Caller caller, CallerData callerdata,
1441                         ResultQueue<Key, T, Caller, CallerData> *dest)
1442         {
1443                 JMutexAutoLock lock(m_queue.getMutex());
1444                 
1445                 /*
1446                         If the caller is already on the list, only update CallerData
1447                 */
1448                 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1449                                 i = m_queue.getList().begin();
1450                                 i != m_queue.getList().end(); i++)
1451                 {
1452                         GetRequest<Key, T, Caller, CallerData> &request = *i;
1453
1454                         if(request.key == key)
1455                         {
1456                                 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1457                                                 i = request.callers.begin();
1458                                                 i != request.callers.end(); i++)
1459                                 {
1460                                         CallerInfo<Caller, CallerData> &ca = *i;
1461                                         if(ca.caller == caller)
1462                                         {
1463                                                 ca.data = callerdata;
1464                                                 return;
1465                                         }
1466                                 }
1467                                 CallerInfo<Caller, CallerData> ca;
1468                                 ca.caller = caller;
1469                                 ca.data = callerdata;
1470                                 request.callers.push_back(ca);
1471                                 return;
1472                         }
1473                 }
1474
1475                 /*
1476                         Else add a new request to the queue
1477                 */
1478
1479                 GetRequest<Key, T, Caller, CallerData> request;
1480                 request.key = key;
1481                 CallerInfo<Caller, CallerData> ca;
1482                 ca.caller = caller;
1483                 ca.data = callerdata;
1484                 request.callers.push_back(ca);
1485                 request.dest = dest;
1486                 
1487                 m_queue.getList().push_back(request);
1488         }
1489
1490         GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1491         {
1492                 return m_queue.pop_front(wait_if_empty);
1493         }
1494
1495 private:
1496         MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
1497 };
1498
1499 /*
1500         Pseudo-random (VC++ rand() sucks)
1501 */
1502 int myrand(void);
1503 void mysrand(unsigned seed);
1504 #define MYRAND_MAX 32767
1505
1506 inline int myrand_range(int min, int max)
1507 {
1508         if(min > max)
1509         {
1510                 assert(0);
1511                 return max;
1512         }
1513         return (myrand()%(max-min+1))+min;
1514 }
1515
1516 /*
1517         Miscellaneous functions
1518 */
1519
1520 bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range,
1521                 f32 *distance_ptr=NULL);
1522
1523 /*
1524         Queue with unique values with fast checking of value existence
1525 */
1526
1527 template<typename Value>
1528 class UniqueQueue
1529 {
1530 public:
1531         
1532         /*
1533                 Does nothing if value is already queued.
1534                 Return value:
1535                         true: value added
1536                         false: value already exists
1537         */
1538         bool push_back(Value value)
1539         {
1540                 // Check if already exists
1541                 if(m_map.find(value) != NULL)
1542                         return false;
1543
1544                 // Add
1545                 m_map.insert(value, 0);
1546                 m_list.push_back(value);
1547                 
1548                 return true;
1549         }
1550
1551         Value pop_front()
1552         {
1553                 typename core::list<Value>::Iterator i = m_list.begin();
1554                 Value value = *i;
1555                 m_map.remove(value);
1556                 m_list.erase(i);
1557                 return value;
1558         }
1559
1560         u32 size()
1561         {
1562                 assert(m_list.size() == m_map.size());
1563                 return m_list.size();
1564         }
1565
1566 private:
1567         core::map<Value, u8> m_map;
1568         core::list<Value> m_list;
1569 };
1570
1571 #if 0
1572 template<typename Key, typename Value>
1573 class MutexedCache
1574 {
1575 public:
1576         MutexedCache()
1577         {
1578                 m_mutex.Init();
1579                 assert(m_mutex.IsInitialized());
1580         }
1581         
1582         void set(const Key &name, const Value &value)
1583         {
1584                 JMutexAutoLock lock(m_mutex);
1585
1586                 m_values[name] = value;
1587         }
1588         
1589         bool get(const Key &name, Value *result)
1590         {
1591                 JMutexAutoLock lock(m_mutex);
1592
1593                 typename core::map<Key, Value>::Node *n;
1594                 n = m_values.find(name);
1595
1596                 if(n == NULL)
1597                         return false;
1598
1599                 *result = n->getValue();
1600                 return true;
1601         }
1602
1603 private:
1604         core::map<Key, Value> m_values;
1605         JMutex m_mutex;
1606 };
1607 #endif
1608
1609 /*
1610         Generates ids for comparable values.
1611         Id=0 is reserved for "no value".
1612
1613         Is fast at:
1614         - Returning value by id (very fast)
1615         - Returning id by value
1616         - Generating a new id for a value
1617
1618         Is not able to:
1619         - Remove an id/value pair (is possible to implement but slow)
1620 */
1621 template<typename T>
1622 class MutexedIdGenerator
1623 {
1624 public:
1625         MutexedIdGenerator()
1626         {
1627                 m_mutex.Init();
1628                 assert(m_mutex.IsInitialized());
1629         }
1630         
1631         // Returns true if found
1632         bool getValue(u32 id, T &value)
1633         {
1634                 if(id == 0)
1635                         return false;
1636                 JMutexAutoLock lock(m_mutex);
1637                 if(m_id_to_value.size() < id)
1638                         return false;
1639                 value = m_id_to_value[id-1];
1640                 return true;
1641         }
1642         
1643         // If id exists for value, returns the id.
1644         // Otherwise generates an id for the value.
1645         u32 getId(const T &value)
1646         {
1647                 JMutexAutoLock lock(m_mutex);
1648                 typename core::map<T, u32>::Node *n;
1649                 n = m_value_to_id.find(value);
1650                 if(n != NULL)
1651                         return n->getValue();
1652                 m_id_to_value.push_back(value);
1653                 u32 new_id = m_id_to_value.size();
1654                 m_value_to_id.insert(value, new_id);
1655                 return new_id;
1656         }
1657
1658 private:
1659         JMutex m_mutex;
1660         // Values are stored here at id-1 position (id 1 = [0])
1661         core::array<T> m_id_to_value;
1662         core::map<T, u32> m_value_to_id;
1663 };
1664
1665 /*
1666         Checks if a string contains only supplied characters
1667 */
1668 inline bool string_allowed(const std::string &s, const std::string &allowed_chars)
1669 {
1670         for(u32 i=0; i<s.size(); i++)
1671         {
1672                 bool confirmed = false;
1673                 for(u32 j=0; j<allowed_chars.size(); j++)
1674                 {
1675                         if(s[i] == allowed_chars[j])
1676                         {
1677                                 confirmed = true;
1678                                 break;
1679                         }
1680                 }
1681                 if(confirmed == false)
1682                         return false;
1683         }
1684         return true;
1685 }
1686
1687 /*
1688         Some helper stuff
1689 */
1690 #define MYMIN(a,b) ((a)<(b)?(a):(b))
1691 #define MYMAX(a,b) ((a)>(b)?(a):(b))
1692
1693 #endif
1694