]> git.lizzy.rs Git - dragonfireclient.git/blob - src/utility.h
484b5828b12c74c3986bcce33343dca6a0325713
[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 inline void writeU32(u8 *data, u32 i)
40 {
41         data[0] = ((i>>24)&0xff);
42         data[1] = ((i>>16)&0xff);
43         data[2] = ((i>> 8)&0xff);
44         data[3] = ((i>> 0)&0xff);
45 }
46
47 inline void writeU16(u8 *data, u16 i)
48 {
49         data[0] = ((i>> 8)&0xff);
50         data[1] = ((i>> 0)&0xff);
51 }
52
53 inline void writeU8(u8 *data, u8 i)
54 {
55         data[0] = ((i>> 0)&0xff);
56 }
57
58 inline u32 readU32(u8 *data)
59 {
60         return (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]<<0);
61 }
62
63 inline u16 readU16(u8 *data)
64 {
65         return (data[0]<<8) | (data[1]<<0);
66 }
67
68 inline u8 readU8(u8 *data)
69 {
70         return (data[0]<<0);
71 }
72
73 // Signed variants of the above
74
75 inline void writeS32(u8 *data, s32 i){
76         writeU32(data, (u32)i);
77 }
78 inline s32 readS32(u8 *data){
79         return (s32)readU32(data);
80 }
81
82 inline void writeS16(u8 *data, s16 i){
83         writeU16(data, (u16)i);
84 }
85 inline s16 readS16(u8 *data){
86         return (s16)readU16(data);
87 }
88
89 inline void writeV3S32(u8 *data, v3s32 p)
90 {
91         writeS32(&data[0], p.X);
92         writeS32(&data[4], p.Y);
93         writeS32(&data[8], p.Z);
94 }
95
96 inline v3s32 readV3S32(u8 *data)
97 {
98         v3s32 p;
99         p.X = readS32(&data[0]);
100         p.Y = readS32(&data[4]);
101         p.Z = readS32(&data[8]);
102         return p;
103 }
104
105 inline void writeV2S16(u8 *data, v2s16 p)
106 {
107         writeS16(&data[0], p.X);
108         writeS16(&data[2], p.Y);
109 }
110
111 inline v2s16 readV2S16(u8 *data)
112 {
113         v2s16 p;
114         p.X = readS16(&data[0]);
115         p.Y = readS16(&data[2]);
116         return p;
117 }
118
119 inline void writeV2S32(u8 *data, v2s32 p)
120 {
121         writeS32(&data[0], p.X);
122         writeS32(&data[2], p.Y);
123 }
124
125 inline v2s32 readV2S32(u8 *data)
126 {
127         v2s32 p;
128         p.X = readS32(&data[0]);
129         p.Y = readS32(&data[2]);
130         return p;
131 }
132
133 inline void writeV3S16(u8 *data, v3s16 p)
134 {
135         writeS16(&data[0], p.X);
136         writeS16(&data[2], p.Y);
137         writeS16(&data[4], p.Z);
138 }
139
140 inline v3s16 readV3S16(u8 *data)
141 {
142         v3s16 p;
143         p.X = readS16(&data[0]);
144         p.Y = readS16(&data[2]);
145         p.Z = readS16(&data[4]);
146         return p;
147 }
148
149 /*
150         None of these are used at the moment
151 */
152
153 template <typename T>
154 class SharedPtr
155 {
156 public:
157         SharedPtr(T *t=NULL)
158         {
159                 refcount = new int;
160                 *refcount = 1;
161                 ptr = t;
162         }
163         SharedPtr(SharedPtr<T> &t)
164         {
165                 //*this = t;
166                 drop();
167                 refcount = t.refcount;
168                 (*refcount)++;
169                 ptr = t.ptr;
170         }
171         ~SharedPtr()
172         {
173                 drop();
174         }
175         SharedPtr<T> & operator=(T *t)
176         {
177                 drop();
178                 refcount = new int;
179                 *refcount = 1;
180                 ptr = t;
181                 return *this;
182         }
183         SharedPtr<T> & operator=(SharedPtr<T> &t)
184         {
185                 drop();
186                 refcount = t.refcount;
187                 (*refcount)++;
188                 ptr = t.ptr;
189                 return *this;
190         }
191         T* operator->()
192         {
193                 return ptr;
194         }
195         T & operator*()
196         {
197                 return *ptr;
198         }
199         bool operator!=(T *t)
200         {
201                 return ptr != t;
202         }
203         bool operator==(T *t)
204         {
205                 return ptr == t;
206         }
207 private:
208         void drop()
209         {
210                 assert((*refcount) > 0);
211                 (*refcount)--;
212                 if(*refcount == 0)
213                 {
214                         delete refcount;
215                         if(ptr != NULL)
216                                 delete ptr;
217                 }
218         }
219         T *ptr;
220         int *refcount;
221 };
222
223 template <typename T>
224 class Buffer
225 {
226 public:
227         Buffer(unsigned int size)
228         {
229                 m_size = size;
230                 data = new T[size];
231         }
232         Buffer(const Buffer &buffer)
233         {
234                 m_size = buffer.m_size;
235                 data = new T[buffer.m_size];
236                 memcpy(data, buffer.data, buffer.m_size);
237         }
238         Buffer(T *t, unsigned int size)
239         {
240                 m_size = size;
241                 data = new T[size];
242                 memcpy(data, t, size);
243         }
244         ~Buffer()
245         {
246                 delete[] data;
247         }
248         T & operator[](unsigned int i) const
249         {
250                 return data[i];
251         }
252         T * operator*() const
253         {
254                 return data;
255         }
256         unsigned int getSize() const
257         {
258                 return m_size;
259         }
260 private:
261         T *data;
262         unsigned int m_size;
263 };
264
265 template <typename T>
266 class SharedBuffer
267 {
268 public:
269         SharedBuffer(unsigned int size)
270         {
271                 m_size = size;
272                 data = new T[size];
273                 refcount = new unsigned int;
274                 (*refcount) = 1;
275         }
276         SharedBuffer(const SharedBuffer &buffer)
277         {
278                 //std::cout<<"SharedBuffer(const SharedBuffer &buffer)"<<std::endl;
279                 m_size = buffer.m_size;
280                 data = buffer.data;
281                 refcount = buffer.refcount;
282                 (*refcount)++;
283         }
284         SharedBuffer & operator=(const SharedBuffer & buffer)
285         {
286                 //std::cout<<"SharedBuffer & operator=(const SharedBuffer & buffer)"<<std::endl;
287                 if(this == &buffer)
288                         return *this;
289                 drop();
290                 m_size = buffer.m_size;
291                 data = buffer.data;
292                 refcount = buffer.refcount;
293                 (*refcount)++;
294                 return *this;
295         }
296         /*
297                 Copies whole buffer
298         */
299         SharedBuffer(T *t, unsigned int size)
300         {
301                 m_size = size;
302                 data = new T[size];
303                 memcpy(data, t, size);
304                 refcount = new unsigned int;
305                 (*refcount) = 1;
306         }
307         /*
308                 Copies whole buffer
309         */
310         SharedBuffer(const Buffer<T> &buffer)
311         {
312                 m_size = buffer.m_size;
313                 data = new T[buffer.getSize()];
314                 memcpy(data, *buffer, buffer.getSize());
315                 refcount = new unsigned int;
316                 (*refcount) = 1;
317         }
318         ~SharedBuffer()
319         {
320                 drop();
321         }
322         T & operator[](unsigned int i) const
323         {
324                 return data[i];
325         }
326         T * operator*() const
327         {
328                 return data;
329         }
330         unsigned int getSize() const
331         {
332                 return m_size;
333         }
334 private:
335         void drop()
336         {
337                 assert((*refcount) > 0);
338                 (*refcount)--;
339                 if(*refcount == 0)
340                 {
341                         delete[] data;
342                         delete refcount;
343                 }
344         }
345         T *data;
346         unsigned int m_size;
347         unsigned int *refcount;
348 };
349
350 inline SharedBuffer<u8> SharedBufferFromString(const char *string)
351 {
352         SharedBuffer<u8> b((u8*)string, strlen(string)+1);
353         return b;
354 }
355
356 template<typename T>
357 class MutexedVariable
358 {
359 public:
360         MutexedVariable(T value):
361                 m_value(value)
362         {
363                 m_mutex.Init();
364         }
365
366         T get()
367         {
368                 JMutexAutoLock lock(m_mutex);
369                 return m_value;
370         }
371
372         void set(T value)
373         {
374                 JMutexAutoLock lock(m_mutex);
375                 m_value = value;
376         }
377         
378         // You'll want to grab this in a SharedPtr
379         JMutexAutoLock * getLock()
380         {
381                 return new JMutexAutoLock(m_mutex);
382         }
383         
384         // You pretty surely want to grab the lock when accessing this
385         T m_value;
386
387 private:
388         JMutex m_mutex;
389 };
390
391 /*
392         TimeTaker
393 */
394
395 class IrrlichtWrapper;
396
397 class TimeTaker
398 {
399 public:
400         TimeTaker(const char *name, u32 *result=NULL);
401
402         ~TimeTaker()
403         {
404                 stop();
405         }
406
407         u32 stop(bool quiet=false);
408
409 private:
410         const char *m_name;
411         u32 m_time1;
412         bool m_running;
413         u32 *m_result;
414 };
415
416 // Calculates the borders of a "d-radius" cube
417 inline void getFacePositions(core::list<v3s16> &list, u16 d)
418 {
419         if(d == 0)
420         {
421                 list.push_back(v3s16(0,0,0));
422                 return;
423         }
424         if(d == 1)
425         {
426                 /*
427                         This is an optimized sequence of coordinates.
428                 */
429                 list.push_back(v3s16( 0, 1, 0)); // top
430                 list.push_back(v3s16( 0, 0, 1)); // back
431                 list.push_back(v3s16(-1, 0, 0)); // left
432                 list.push_back(v3s16( 1, 0, 0)); // right
433                 list.push_back(v3s16( 0, 0,-1)); // front
434                 list.push_back(v3s16( 0,-1, 0)); // bottom
435                 // 6
436                 list.push_back(v3s16(-1, 0, 1)); // back left
437                 list.push_back(v3s16( 1, 0, 1)); // back right
438                 list.push_back(v3s16(-1, 0,-1)); // front left
439                 list.push_back(v3s16( 1, 0,-1)); // front right
440                 list.push_back(v3s16(-1,-1, 0)); // bottom left
441                 list.push_back(v3s16( 1,-1, 0)); // bottom right
442                 list.push_back(v3s16( 0,-1, 1)); // bottom back
443                 list.push_back(v3s16( 0,-1,-1)); // bottom front
444                 list.push_back(v3s16(-1, 1, 0)); // top left
445                 list.push_back(v3s16( 1, 1, 0)); // top right
446                 list.push_back(v3s16( 0, 1, 1)); // top back
447                 list.push_back(v3s16( 0, 1,-1)); // top front
448                 // 18
449                 list.push_back(v3s16(-1, 1, 1)); // top back-left
450                 list.push_back(v3s16( 1, 1, 1)); // top back-right
451                 list.push_back(v3s16(-1, 1,-1)); // top front-left
452                 list.push_back(v3s16( 1, 1,-1)); // top front-right
453                 list.push_back(v3s16(-1,-1, 1)); // bottom back-left
454                 list.push_back(v3s16( 1,-1, 1)); // bottom back-right
455                 list.push_back(v3s16(-1,-1,-1)); // bottom front-left
456                 list.push_back(v3s16( 1,-1,-1)); // bottom front-right
457                 // 26
458                 return;
459         }
460
461         // Take blocks in all sides, starting from y=0 and going +-y
462         for(s16 y=0; y<=d-1; y++)
463         {
464                 // Left and right side, including borders
465                 for(s16 z=-d; z<=d; z++)
466                 {
467                         list.push_back(v3s16(d,y,z));
468                         list.push_back(v3s16(-d,y,z));
469                         if(y != 0)
470                         {
471                                 list.push_back(v3s16(d,-y,z));
472                                 list.push_back(v3s16(-d,-y,z));
473                         }
474                 }
475                 // Back and front side, excluding borders
476                 for(s16 x=-d+1; x<=d-1; x++)
477                 {
478                         list.push_back(v3s16(x,y,d));
479                         list.push_back(v3s16(x,y,-d));
480                         if(y != 0)
481                         {
482                                 list.push_back(v3s16(x,-y,d));
483                                 list.push_back(v3s16(x,-y,-d));
484                         }
485                 }
486         }
487
488         // Take the bottom and top face with borders
489         // -d<x<d, y=+-d, -d<z<d
490         for(s16 x=-d; x<=d; x++)
491         for(s16 z=-d; z<=d; z++)
492         {
493                 list.push_back(v3s16(x,-d,z));
494                 list.push_back(v3s16(x,d,z));
495         }
496 }
497
498 class IndentationRaiser
499 {
500 public:
501         IndentationRaiser(u16 *indentation)
502         {
503                 m_indentation = indentation;
504                 (*m_indentation)++;
505         }
506         ~IndentationRaiser()
507         {
508                 (*m_indentation)--;
509         }
510 private:
511         u16 *m_indentation;
512 };
513
514 inline s16 getContainerPos(s16 p, s16 d)
515 {
516         return (p>=0 ? p : p-d+1) / d;
517 }
518
519 inline v2s16 getContainerPos(v2s16 p, s16 d)
520 {
521         return v2s16(
522                 getContainerPos(p.X, d),
523                 getContainerPos(p.Y, d)
524         );
525 }
526
527 inline v3s16 getContainerPos(v3s16 p, s16 d)
528 {
529         return v3s16(
530                 getContainerPos(p.X, d),
531                 getContainerPos(p.Y, d),
532                 getContainerPos(p.Z, d)
533         );
534 }
535
536 inline bool isInArea(v3s16 p, s16 d)
537 {
538         return (
539                 p.X >= 0 && p.X < d &&
540                 p.Y >= 0 && p.Y < d &&
541                 p.Z >= 0 && p.Z < d
542         );
543 }
544
545 inline bool isInArea(v2s16 p, s16 d)
546 {
547         return (
548                 p.X >= 0 && p.X < d &&
549                 p.Y >= 0 && p.Y < d
550         );
551 }
552
553 inline std::wstring narrow_to_wide(const std::string& mbs)
554 {
555         size_t wcl = mbs.size();
556         SharedBuffer<wchar_t> wcs(wcl+1);
557         size_t l = mbstowcs(*wcs, mbs.c_str(), wcl);
558         wcs[l] = 0;
559         return *wcs;
560 }
561
562 inline std::string wide_to_narrow(const std::wstring& wcs)
563 {
564         size_t mbl = wcs.size()*4;
565         SharedBuffer<char> mbs(mbl+1);
566         size_t l = wcstombs(*mbs, wcs.c_str(), mbl);
567         if((int)l == -1)
568                 mbs[0] = 0;
569         else
570                 mbs[l] = 0;
571         return *mbs;
572 }
573
574 /*
575         See test.cpp for example cases.
576         wraps degrees to the range of -360...360
577         NOTE: Wrapping to 0...360 is not used because pitch needs negative values.
578 */
579 inline float wrapDegrees(float f)
580 {
581         // Take examples of f=10, f=720.5, f=-0.5, f=-360.5
582         // This results in
583         // 10, 720, -1, -361
584         int i = floor(f);
585         // 0, 2, 0, -1
586         int l = i / 360;
587         // NOTE: This would be used for wrapping to 0...360
588         // 0, 2, -1, -2
589         /*if(i < 0)
590                 l -= 1;*/
591         // 0, 720, 0, -360
592         int k = l * 360;
593         // 10, 0.5, -0.5, -0.5
594         f -= float(k);
595         return f;
596 }
597
598 inline std::string lowercase(std::string s)
599 {
600         for(size_t i=0; i<s.size(); i++)
601         {
602                 if(s[i] >= 'A' && s[i] <= 'Z')
603                         s[i] -= 'A' - 'a';
604         }
605         return s;
606 }
607
608 inline bool is_yes(std::string s)
609 {
610         s = lowercase(trim(s));
611         if(s == "y" || s == "yes" || s == "true")
612                 return true;
613         return false;
614 }
615
616 inline s32 stoi(std::string s, s32 min, s32 max)
617 {
618         s32 i = atoi(s.c_str());
619         if(i < min)
620                 i = min;
621         if(i > max)
622                 i = max;
623         return i;
624 }
625
626 inline s32 stoi(std::string s)
627 {
628         return atoi(s.c_str());
629 }
630
631 /*
632         A base class for simple background thread implementation
633 */
634
635 class SimpleThread : public JThread
636 {
637         bool run;
638         JMutex run_mutex;
639
640 public:
641
642         SimpleThread():
643                 JThread(),
644                 run(true)
645         {
646                 run_mutex.Init();
647         }
648
649         virtual ~SimpleThread()
650         {}
651
652         virtual void * Thread() = 0;
653
654         bool getRun()
655         {
656                 JMutexAutoLock lock(run_mutex);
657                 return run;
658         }
659         void setRun(bool a_run)
660         {
661                 JMutexAutoLock lock(run_mutex);
662                 run = a_run;
663         }
664
665         void stop()
666         {
667                 setRun(false);
668                 while(IsRunning())
669                         sleep_ms(100);
670         }
671 };
672
673 /*
674         Config stuff
675 */
676
677 enum ValueType
678 {
679         VALUETYPE_STRING,
680         VALUETYPE_FLAG // Doesn't take any arguments
681 };
682
683 struct ValueSpec
684 {
685         ValueSpec(ValueType a_type, const char *a_help=NULL)
686         {
687                 type = a_type;
688                 help = a_help;
689         }
690         ValueType type;
691         const char *help;
692 };
693
694 class Settings
695 {
696 public:
697
698         // Returns false on EOF
699         bool parseConfigObject(std::istream &is)
700         {
701                 if(is.eof())
702                         return false;
703                 
704                 // NOTE: This function will be expanded to allow multi-line settings
705                 std::string line;
706                 std::getline(is, line);
707                 //dstream<<"got line: \""<<line<<"\""<<std::endl;
708
709                 std::string trimmedline = trim(line);
710                 
711                 // Ignore comments
712                 if(trimmedline[0] == '#')
713                         return true;
714
715                 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
716
717                 Strfnd sf(trim(line));
718
719                 std::string name = sf.next("=");
720                 name = trim(name);
721
722                 if(name == "")
723                         return true;
724                 
725                 std::string value = sf.next("\n");
726                 value = trim(value);
727
728                 dstream<<"Config name=\""<<name<<"\" value=\""
729                                 <<value<<"\""<<std::endl;
730                 
731                 m_settings[name] = value;
732                 
733                 return true;
734         }
735
736         /*
737                 Read configuration file
738
739                 Returns true on success
740         */
741         bool readConfigFile(const char *filename)
742         {
743                 std::ifstream is(filename);
744                 if(is.good() == false)
745                 {
746                         dstream<<"Error opening configuration file \""
747                                         <<filename<<"\""<<std::endl;
748                         return false;
749                 }
750
751                 dstream<<"Parsing configuration file: \""
752                                 <<filename<<"\""<<std::endl;
753                                 
754                 while(parseConfigObject(is));
755                 
756                 return true;
757         }
758
759         /*
760                 Reads a configuration object from stream (usually a single line)
761                 and adds it to dst.
762                 
763                 Preserves comments and empty lines.
764
765                 Settings that were added to dst are also added to updated.
766                 key of updated is setting name, value of updated is dummy.
767
768                 Returns false on EOF
769         */
770         bool getUpdatedConfigObject(std::istream &is,
771                         core::list<std::string> &dst,
772                         core::map<std::string, bool> &updated)
773         {
774                 if(is.eof())
775                         return false;
776                 
777                 // NOTE: This function will be expanded to allow multi-line settings
778                 std::string line;
779                 std::getline(is, line);
780
781                 std::string trimmedline = trim(line);
782
783                 std::string line_end = "";
784                 if(is.eof() == false)
785                         line_end = "\n";
786                 
787                 // Ignore comments
788                 if(trimmedline[0] == '#')
789                 {
790                         dst.push_back(line+line_end);
791                         return true;
792                 }
793
794                 Strfnd sf(trim(line));
795
796                 std::string name = sf.next("=");
797                 name = trim(name);
798
799                 if(name == "")
800                 {
801                         dst.push_back(line+line_end);
802                         return true;
803                 }
804                 
805                 std::string value = sf.next("\n");
806                 value = trim(value);
807                 
808                 if(m_settings.find(name))
809                 {
810                         std::string newvalue = m_settings[name];
811                         
812                         if(newvalue != value)
813                         {
814                                 dstream<<"Changing value of \""<<name<<"\" = \""
815                                                 <<value<<"\" -> \""<<newvalue<<"\""
816                                                 <<std::endl;
817                         }
818
819                         dst.push_back(name + " = " + newvalue + line_end);
820
821                         updated[name] = true;
822                 }
823                 
824                 return true;
825         }
826
827         /*
828                 Updates configuration file
829
830                 Returns true on success
831         */
832         bool updateConfigFile(const char *filename)
833         {
834                 dstream<<"Updating configuration file: \""
835                                 <<filename<<"\""<<std::endl;
836                 
837                 core::list<std::string> objects;
838                 core::map<std::string, bool> updated;
839                 
840                 // Read and modify stuff
841                 {
842                         std::ifstream is(filename);
843                         if(is.good() == false)
844                         {
845                                 dstream<<"Error opening configuration file"
846                                                 " for reading: \""
847                                                 <<filename<<"\""<<std::endl;
848                                 return false;
849                         }
850
851                         while(getUpdatedConfigObject(is, objects, updated));
852                 }
853                 
854                 // Write stuff back
855                 {
856                         std::ofstream os(filename);
857                         if(os.good() == false)
858                         {
859                                 dstream<<"Error opening configuration file"
860                                                 " for writing: \""
861                                                 <<filename<<"\""<<std::endl;
862                                 return false;
863                         }
864                         
865                         /*
866                                 Write updated stuff
867                         */
868                         for(core::list<std::string>::Iterator
869                                         i = objects.begin();
870                                         i != objects.end(); i++)
871                         {
872                                 os<<(*i);
873                         }
874
875                         /*
876                                 Write stuff that was not already in the file
877                         */
878                         for(core::map<std::string, std::string>::Iterator
879                                         i = m_settings.getIterator();
880                                         i.atEnd() == false; i++)
881                         {
882                                 if(updated.find(i.getNode()->getKey()))
883                                         continue;
884                                 std::string name = i.getNode()->getKey();
885                                 std::string value = i.getNode()->getValue();
886                                 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
887                                                 <<std::endl;
888                                 os<<name<<" = "<<value<<"\n";
889                         }
890                 }
891                 
892                 return true;
893         }
894
895         /*
896                 NOTE: Types of allowed_options are ignored
897
898                 returns true on success
899         */
900         bool parseCommandLine(int argc, char *argv[],
901                         core::map<std::string, ValueSpec> &allowed_options)
902         {
903                 int i=1;
904                 for(;;)
905                 {
906                         if(i >= argc)
907                                 break;
908                         std::string argname = argv[i];
909                         if(argname.substr(0, 2) != "--")
910                         {
911                                 dstream<<"Invalid command-line parameter \""
912                                                 <<argname<<"\": --<option> expected."<<std::endl;
913                                 return false;
914                         }
915                         i++;
916
917                         std::string name = argname.substr(2);
918
919                         core::map<std::string, ValueSpec>::Node *n;
920                         n = allowed_options.find(name);
921                         if(n == NULL)
922                         {
923                                 dstream<<"Unknown command-line parameter \""
924                                                 <<argname<<"\""<<std::endl;
925                                 return false;
926                         }
927
928                         ValueType type = n->getValue().type;
929
930                         std::string value = "";
931                         
932                         if(type == VALUETYPE_FLAG)
933                         {
934                                 value = "true";
935                         }
936                         else
937                         {
938                                 if(i >= argc)
939                                 {
940                                         dstream<<"Invalid command-line parameter \""
941                                                         <<name<<"\": missing value"<<std::endl;
942                                         return false;
943                                 }
944                                 value = argv[i];
945                                 i++;
946                         }
947                         
948
949                         dstream<<"Valid command-line parameter: \""
950                                         <<name<<"\" = \""<<value<<"\""
951                                         <<std::endl;
952                         set(name, value);
953                 }
954
955                 return true;
956         }
957
958         void set(std::string name, std::string value)
959         {
960                 m_settings[name] = value;
961         }
962
963         void setDefault(std::string name, std::string value)
964         {
965                 m_defaults[name] = value;
966         }
967
968         bool exists(std::string name)
969         {
970                 return (m_settings.find(name) || m_defaults.find(name));
971         }
972
973         std::string get(std::string name)
974         {
975                 core::map<std::string, std::string>::Node *n;
976                 n = m_settings.find(name);
977                 if(n == NULL)
978                 {
979                         n = m_defaults.find(name);
980                         if(n == NULL)
981                         {
982                                 throw SettingNotFoundException("Setting not found");
983                         }
984                 }
985
986                 return n->getValue();
987         }
988
989         bool getBool(std::string name)
990         {
991                 return is_yes(get(name));
992         }
993         
994         bool getFlag(std::string name)
995         {
996                 try
997                 {
998                         return getBool(name);
999                 }
1000                 catch(SettingNotFoundException &e)
1001                 {
1002                         return false;
1003                 }
1004         }
1005
1006         // Asks if empty
1007         bool getBoolAsk(std::string name, std::string question, bool def)
1008         {
1009                 std::string s = get(name);
1010                 if(s != "")
1011                         return is_yes(s);
1012                 
1013                 char templine[10];
1014                 std::cout<<question<<" [y/N]: ";
1015                 std::cin.getline(templine, 10);
1016                 s = templine;
1017
1018                 if(s == "")
1019                         return def;
1020
1021                 return is_yes(s);
1022         }
1023
1024         float getFloat(std::string name)
1025         {
1026                 float f;
1027                 std::istringstream vis(get(name));
1028                 vis>>f;
1029                 return f;
1030         }
1031
1032         u16 getU16(std::string name)
1033         {
1034                 return stoi(get(name), 0, 65535);
1035         }
1036
1037         u16 getU16Ask(std::string name, std::string question, u16 def)
1038         {
1039                 std::string s = get(name);
1040                 if(s != "")
1041                         return stoi(s, 0, 65535);
1042                 
1043                 char templine[10];
1044                 std::cout<<question<<" ["<<def<<"]: ";
1045                 std::cin.getline(templine, 10);
1046                 s = templine;
1047
1048                 if(s == "")
1049                         return def;
1050
1051                 return stoi(s, 0, 65535);
1052         }
1053
1054         s16 getS16(std::string name)
1055         {
1056                 return stoi(get(name), -32768, 32767);
1057         }
1058
1059         s32 getS32(std::string name)
1060         {
1061                 return stoi(get(name));
1062         }
1063
1064 private:
1065         core::map<std::string, std::string> m_settings;
1066         core::map<std::string, std::string> m_defaults;
1067 };
1068
1069 /*
1070         A thread-safe queue
1071 */
1072
1073 template<typename T>
1074 class MutexedQueue
1075 {
1076 public:
1077         MutexedQueue()
1078         {
1079                 m_mutex.Init();
1080         }
1081         u32 size()
1082         {
1083                 return m_list.size();
1084         }
1085         void push_back(T t)
1086         {
1087                 JMutexAutoLock lock(m_mutex);
1088                 m_list.push_back(t);
1089         }
1090         T pop_front(u32 wait_time_max_ms=0)
1091         {
1092                 u32 wait_time_ms = 0;
1093
1094                 for(;;)
1095                 {
1096                         {
1097                                 JMutexAutoLock lock(m_mutex);
1098
1099                                 if(m_list.size() > 0)
1100                                 {
1101                                         typename core::list<T>::Iterator begin = m_list.begin();
1102                                         T t = *begin;
1103                                         m_list.erase(begin);
1104                                         return t;
1105                                 }
1106
1107                                 if(wait_time_ms >= wait_time_max_ms)
1108                                         throw ItemNotFoundException("MutexedQueue: queue is empty");
1109                         }
1110
1111                         // Wait a while before trying again
1112                         sleep_ms(10);
1113                         wait_time_ms += 10;
1114                 }
1115         }
1116
1117         JMutex & getMutex()
1118         {
1119                 return m_mutex;
1120         }
1121
1122         core::list<T> & getList()
1123         {
1124                 return m_list;
1125         }
1126
1127 protected:
1128         JMutex m_mutex;
1129         core::list<T> m_list;
1130 };
1131
1132 template<typename Caller, typename Data>
1133 class CallerInfo
1134 {
1135 public:
1136         Caller caller;
1137         Data data;
1138 };
1139
1140 template<typename Key, typename T, typename Caller, typename CallerData>
1141 class GetResult
1142 {
1143 public:
1144         Key key;
1145         T item;
1146         core::list<CallerInfo<Caller, CallerData> > callers;
1147 };
1148
1149 template<typename Key, typename T, typename Caller, typename CallerData>
1150 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1151 {
1152 };
1153
1154 template<typename Key, typename T, typename Caller, typename CallerData>
1155 class GetRequest
1156 {
1157 public:
1158         GetRequest()
1159         {
1160                 dest = NULL;
1161         }
1162         GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1163         {
1164                 dest = a_dest;
1165         }
1166         GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1167                         Key a_key)
1168         {
1169                 dest = a_dest;
1170                 key = a_key;
1171         }
1172         ~GetRequest()
1173         {
1174         }
1175         
1176         Key key;
1177         ResultQueue<Key, T, Caller, CallerData> *dest;
1178         core::list<CallerInfo<Caller, CallerData> > callers;
1179 };
1180
1181 /*
1182         Quickhands for typical request-result queues.
1183         Used for distributing work between threads.
1184 */
1185
1186 template<typename Key, typename T, typename Caller, typename CallerData>
1187 class RequestQueue
1188 {
1189 public:
1190         u32 size()
1191         {
1192                 return m_queue.size();
1193         }
1194
1195         void add(Key key, Caller caller, CallerData callerdata,
1196                         ResultQueue<Key, T, Caller, CallerData> *dest)
1197         {
1198                 JMutexAutoLock lock(m_queue.getMutex());
1199                 
1200                 /*
1201                         If the caller is already on the list, only update CallerData
1202                 */
1203                 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1204                                 i = m_queue.getList().begin();
1205                                 i != m_queue.getList().end(); i++)
1206                 {
1207                         GetRequest<Key, T, Caller, CallerData> &request = *i;
1208
1209                         if(request.key == key)
1210                         {
1211                                 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1212                                                 i = request.callers.begin();
1213                                                 i != request.callers.end(); i++)
1214                                 {
1215                                         CallerInfo<Caller, CallerData> &ca = *i;
1216                                         if(ca.caller == caller)
1217                                         {
1218                                                 ca.data = callerdata;
1219                                                 return;
1220                                         }
1221                                 }
1222                                 CallerInfo<Caller, CallerData> ca;
1223                                 ca.caller = caller;
1224                                 ca.data = callerdata;
1225                                 request.callers.push_back(ca);
1226                                 return;
1227                         }
1228                 }
1229
1230                 /*
1231                         Else add a new request to the queue
1232                 */
1233
1234                 GetRequest<Key, T, Caller, CallerData> request;
1235                 request.key = key;
1236                 CallerInfo<Caller, CallerData> ca;
1237                 ca.caller = caller;
1238                 ca.data = callerdata;
1239                 request.callers.push_back(ca);
1240                 request.dest = dest;
1241                 
1242                 m_queue.getList().push_back(request);
1243         }
1244
1245         GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1246         {
1247                 return m_queue.pop_front(wait_if_empty);
1248         }
1249
1250 private:
1251         MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
1252 };
1253
1254 #endif
1255