]> git.lizzy.rs Git - dragonfireclient.git/blob - src/utility.h
fixed crack animation timing in client
[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(const std::string &s)
599 {
600         std::string s2;
601         for(size_t i=0; i<s.size(); i++)
602         {
603                 char c = s[i];
604                 if(c >= 'A' && c <= 'Z')
605                         c -= 'A' - 'a';
606                 s2 += c;
607         }
608         return s2;
609 }
610
611 inline bool is_yes(const std::string &s)
612 {
613         std::string s2 = lowercase(trim(s));
614         if(s2 == "y" || s2 == "yes" || s2 == "true")
615                 return true;
616         return false;
617 }
618
619 inline s32 stoi(const std::string &s, s32 min, s32 max)
620 {
621         s32 i = atoi(s.c_str());
622         if(i < min)
623                 i = min;
624         if(i > max)
625                 i = max;
626         return i;
627 }
628
629 inline s32 stoi(std::string s)
630 {
631         return atoi(s.c_str());
632 }
633
634 /*
635         A base class for simple background thread implementation
636 */
637
638 class SimpleThread : public JThread
639 {
640         bool run;
641         JMutex run_mutex;
642
643 public:
644
645         SimpleThread():
646                 JThread(),
647                 run(true)
648         {
649                 run_mutex.Init();
650         }
651
652         virtual ~SimpleThread()
653         {}
654
655         virtual void * Thread() = 0;
656
657         bool getRun()
658         {
659                 JMutexAutoLock lock(run_mutex);
660                 return run;
661         }
662         void setRun(bool a_run)
663         {
664                 JMutexAutoLock lock(run_mutex);
665                 run = a_run;
666         }
667
668         void stop()
669         {
670                 setRun(false);
671                 while(IsRunning())
672                         sleep_ms(100);
673         }
674 };
675
676 /*
677         Config stuff
678 */
679
680 enum ValueType
681 {
682         VALUETYPE_STRING,
683         VALUETYPE_FLAG // Doesn't take any arguments
684 };
685
686 struct ValueSpec
687 {
688         ValueSpec(ValueType a_type, const char *a_help=NULL)
689         {
690                 type = a_type;
691                 help = a_help;
692         }
693         ValueType type;
694         const char *help;
695 };
696
697 class Settings
698 {
699 public:
700
701         // Returns false on EOF
702         bool parseConfigObject(std::istream &is)
703         {
704                 if(is.eof())
705                         return false;
706                 
707                 // NOTE: This function will be expanded to allow multi-line settings
708                 std::string line;
709                 std::getline(is, line);
710                 //dstream<<"got line: \""<<line<<"\""<<std::endl;
711
712                 std::string trimmedline = trim(line);
713                 
714                 // Ignore comments
715                 if(trimmedline[0] == '#')
716                         return true;
717
718                 //dstream<<"trimmedline=\""<<trimmedline<<"\""<<std::endl;
719
720                 Strfnd sf(trim(line));
721
722                 std::string name = sf.next("=");
723                 name = trim(name);
724
725                 if(name == "")
726                         return true;
727                 
728                 std::string value = sf.next("\n");
729                 value = trim(value);
730
731                 dstream<<"Config name=\""<<name<<"\" value=\""
732                                 <<value<<"\""<<std::endl;
733                 
734                 m_settings[name] = value;
735                 
736                 return true;
737         }
738
739         /*
740                 Read configuration file
741
742                 Returns true on success
743         */
744         bool readConfigFile(const char *filename)
745         {
746                 std::ifstream is(filename);
747                 if(is.good() == false)
748                 {
749                         dstream<<"Error opening configuration file \""
750                                         <<filename<<"\""<<std::endl;
751                         return false;
752                 }
753
754                 dstream<<"Parsing configuration file: \""
755                                 <<filename<<"\""<<std::endl;
756                                 
757                 while(parseConfigObject(is));
758                 
759                 return true;
760         }
761
762         /*
763                 Reads a configuration object from stream (usually a single line)
764                 and adds it to dst.
765                 
766                 Preserves comments and empty lines.
767
768                 Settings that were added to dst are also added to updated.
769                 key of updated is setting name, value of updated is dummy.
770
771                 Returns false on EOF
772         */
773         bool getUpdatedConfigObject(std::istream &is,
774                         core::list<std::string> &dst,
775                         core::map<std::string, bool> &updated)
776         {
777                 if(is.eof())
778                         return false;
779                 
780                 // NOTE: This function will be expanded to allow multi-line settings
781                 std::string line;
782                 std::getline(is, line);
783
784                 std::string trimmedline = trim(line);
785
786                 std::string line_end = "";
787                 if(is.eof() == false)
788                         line_end = "\n";
789                 
790                 // Ignore comments
791                 if(trimmedline[0] == '#')
792                 {
793                         dst.push_back(line+line_end);
794                         return true;
795                 }
796
797                 Strfnd sf(trim(line));
798
799                 std::string name = sf.next("=");
800                 name = trim(name);
801
802                 if(name == "")
803                 {
804                         dst.push_back(line+line_end);
805                         return true;
806                 }
807                 
808                 std::string value = sf.next("\n");
809                 value = trim(value);
810                 
811                 if(m_settings.find(name))
812                 {
813                         std::string newvalue = m_settings[name];
814                         
815                         if(newvalue != value)
816                         {
817                                 dstream<<"Changing value of \""<<name<<"\" = \""
818                                                 <<value<<"\" -> \""<<newvalue<<"\""
819                                                 <<std::endl;
820                         }
821
822                         dst.push_back(name + " = " + newvalue + line_end);
823
824                         updated[name] = true;
825                 }
826                 
827                 return true;
828         }
829
830         /*
831                 Updates configuration file
832
833                 Returns true on success
834         */
835         bool updateConfigFile(const char *filename)
836         {
837                 dstream<<"Updating configuration file: \""
838                                 <<filename<<"\""<<std::endl;
839                 
840                 core::list<std::string> objects;
841                 core::map<std::string, bool> updated;
842                 
843                 // Read and modify stuff
844                 {
845                         std::ifstream is(filename);
846                         if(is.good() == false)
847                         {
848                                 dstream<<"Error opening configuration file"
849                                                 " for reading: \""
850                                                 <<filename<<"\""<<std::endl;
851                                 return false;
852                         }
853
854                         while(getUpdatedConfigObject(is, objects, updated));
855                 }
856                 
857                 // Write stuff back
858                 {
859                         std::ofstream os(filename);
860                         if(os.good() == false)
861                         {
862                                 dstream<<"Error opening configuration file"
863                                                 " for writing: \""
864                                                 <<filename<<"\""<<std::endl;
865                                 return false;
866                         }
867                         
868                         /*
869                                 Write updated stuff
870                         */
871                         for(core::list<std::string>::Iterator
872                                         i = objects.begin();
873                                         i != objects.end(); i++)
874                         {
875                                 os<<(*i);
876                         }
877
878                         /*
879                                 Write stuff that was not already in the file
880                         */
881                         for(core::map<std::string, std::string>::Iterator
882                                         i = m_settings.getIterator();
883                                         i.atEnd() == false; i++)
884                         {
885                                 if(updated.find(i.getNode()->getKey()))
886                                         continue;
887                                 std::string name = i.getNode()->getKey();
888                                 std::string value = i.getNode()->getValue();
889                                 dstream<<"Adding \""<<name<<"\" = \""<<value<<"\""
890                                                 <<std::endl;
891                                 os<<name<<" = "<<value<<"\n";
892                         }
893                 }
894                 
895                 return true;
896         }
897
898         /*
899                 NOTE: Types of allowed_options are ignored
900
901                 returns true on success
902         */
903         bool parseCommandLine(int argc, char *argv[],
904                         core::map<std::string, ValueSpec> &allowed_options)
905         {
906                 int i=1;
907                 for(;;)
908                 {
909                         if(i >= argc)
910                                 break;
911                         std::string argname = argv[i];
912                         if(argname.substr(0, 2) != "--")
913                         {
914                                 dstream<<"Invalid command-line parameter \""
915                                                 <<argname<<"\": --<option> expected."<<std::endl;
916                                 return false;
917                         }
918                         i++;
919
920                         std::string name = argname.substr(2);
921
922                         core::map<std::string, ValueSpec>::Node *n;
923                         n = allowed_options.find(name);
924                         if(n == NULL)
925                         {
926                                 dstream<<"Unknown command-line parameter \""
927                                                 <<argname<<"\""<<std::endl;
928                                 return false;
929                         }
930
931                         ValueType type = n->getValue().type;
932
933                         std::string value = "";
934                         
935                         if(type == VALUETYPE_FLAG)
936                         {
937                                 value = "true";
938                         }
939                         else
940                         {
941                                 if(i >= argc)
942                                 {
943                                         dstream<<"Invalid command-line parameter \""
944                                                         <<name<<"\": missing value"<<std::endl;
945                                         return false;
946                                 }
947                                 value = argv[i];
948                                 i++;
949                         }
950                         
951
952                         dstream<<"Valid command-line parameter: \""
953                                         <<name<<"\" = \""<<value<<"\""
954                                         <<std::endl;
955                         set(name, value);
956                 }
957
958                 return true;
959         }
960
961         void set(std::string name, std::string value)
962         {
963                 m_settings[name] = value;
964         }
965
966         void setDefault(std::string name, std::string value)
967         {
968                 m_defaults[name] = value;
969         }
970
971         bool exists(std::string name)
972         {
973                 return (m_settings.find(name) || m_defaults.find(name));
974         }
975
976         std::string get(std::string name)
977         {
978                 core::map<std::string, std::string>::Node *n;
979                 n = m_settings.find(name);
980                 if(n == NULL)
981                 {
982                         n = m_defaults.find(name);
983                         if(n == NULL)
984                         {
985                                 throw SettingNotFoundException("Setting not found");
986                         }
987                 }
988
989                 return n->getValue();
990         }
991
992         bool getBool(std::string name)
993         {
994                 return is_yes(get(name));
995         }
996         
997         bool getFlag(std::string name)
998         {
999                 try
1000                 {
1001                         return getBool(name);
1002                 }
1003                 catch(SettingNotFoundException &e)
1004                 {
1005                         return false;
1006                 }
1007         }
1008
1009         // Asks if empty
1010         bool getBoolAsk(std::string name, std::string question, bool def)
1011         {
1012                 std::string s = get(name);
1013                 if(s != "")
1014                         return is_yes(s);
1015                 
1016                 char templine[10];
1017                 std::cout<<question<<" [y/N]: ";
1018                 std::cin.getline(templine, 10);
1019                 s = templine;
1020
1021                 if(s == "")
1022                         return def;
1023
1024                 return is_yes(s);
1025         }
1026
1027         float getFloat(std::string name)
1028         {
1029                 float f;
1030                 std::istringstream vis(get(name));
1031                 vis>>f;
1032                 return f;
1033         }
1034
1035         u16 getU16(std::string name)
1036         {
1037                 return stoi(get(name), 0, 65535);
1038         }
1039
1040         u16 getU16Ask(std::string name, std::string question, u16 def)
1041         {
1042                 std::string s = get(name);
1043                 if(s != "")
1044                         return stoi(s, 0, 65535);
1045                 
1046                 char templine[10];
1047                 std::cout<<question<<" ["<<def<<"]: ";
1048                 std::cin.getline(templine, 10);
1049                 s = templine;
1050
1051                 if(s == "")
1052                         return def;
1053
1054                 return stoi(s, 0, 65535);
1055         }
1056
1057         s16 getS16(std::string name)
1058         {
1059                 return stoi(get(name), -32768, 32767);
1060         }
1061
1062         s32 getS32(std::string name)
1063         {
1064                 return stoi(get(name));
1065         }
1066
1067 private:
1068         core::map<std::string, std::string> m_settings;
1069         core::map<std::string, std::string> m_defaults;
1070 };
1071
1072 /*
1073         FIFO queue
1074 */
1075 template<typename T>
1076 class Queue
1077 {
1078 public:
1079         void push_back(T t)
1080         {
1081                 m_list.push_back(t);
1082         }
1083         
1084         T pop_front()
1085         {
1086                 if(m_list.size() == 0)
1087                         throw ItemNotFoundException("MutexedQueue: queue is empty");
1088
1089                 typename core::list<T>::Iterator begin = m_list.begin();
1090                 T t = *begin;
1091                 m_list.erase(begin);
1092                 return t;
1093         }
1094
1095         u32 size()
1096         {
1097                 return m_list.size();
1098         }
1099
1100 protected:
1101         core::list<T> m_list;
1102 };
1103
1104 /*
1105         Thread-safe FIFO queue
1106 */
1107
1108 template<typename T>
1109 class MutexedQueue
1110 {
1111 public:
1112         MutexedQueue()
1113         {
1114                 m_mutex.Init();
1115         }
1116         u32 size()
1117         {
1118                 return m_list.size();
1119         }
1120         void push_back(T t)
1121         {
1122                 JMutexAutoLock lock(m_mutex);
1123                 m_list.push_back(t);
1124         }
1125         T pop_front(u32 wait_time_max_ms=0)
1126         {
1127                 u32 wait_time_ms = 0;
1128
1129                 for(;;)
1130                 {
1131                         {
1132                                 JMutexAutoLock lock(m_mutex);
1133
1134                                 if(m_list.size() > 0)
1135                                 {
1136                                         typename core::list<T>::Iterator begin = m_list.begin();
1137                                         T t = *begin;
1138                                         m_list.erase(begin);
1139                                         return t;
1140                                 }
1141
1142                                 if(wait_time_ms >= wait_time_max_ms)
1143                                         throw ItemNotFoundException("MutexedQueue: queue is empty");
1144                         }
1145
1146                         // Wait a while before trying again
1147                         sleep_ms(10);
1148                         wait_time_ms += 10;
1149                 }
1150         }
1151
1152         JMutex & getMutex()
1153         {
1154                 return m_mutex;
1155         }
1156
1157         core::list<T> & getList()
1158         {
1159                 return m_list;
1160         }
1161
1162 protected:
1163         JMutex m_mutex;
1164         core::list<T> m_list;
1165 };
1166
1167 template<typename Caller, typename Data>
1168 class CallerInfo
1169 {
1170 public:
1171         Caller caller;
1172         Data data;
1173 };
1174
1175 template<typename Key, typename T, typename Caller, typename CallerData>
1176 class GetResult
1177 {
1178 public:
1179         Key key;
1180         T item;
1181         core::list<CallerInfo<Caller, CallerData> > callers;
1182 };
1183
1184 template<typename Key, typename T, typename Caller, typename CallerData>
1185 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1186 {
1187 };
1188
1189 template<typename Key, typename T, typename Caller, typename CallerData>
1190 class GetRequest
1191 {
1192 public:
1193         GetRequest()
1194         {
1195                 dest = NULL;
1196         }
1197         GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1198         {
1199                 dest = a_dest;
1200         }
1201         GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1202                         Key a_key)
1203         {
1204                 dest = a_dest;
1205                 key = a_key;
1206         }
1207         ~GetRequest()
1208         {
1209         }
1210         
1211         Key key;
1212         ResultQueue<Key, T, Caller, CallerData> *dest;
1213         core::list<CallerInfo<Caller, CallerData> > callers;
1214 };
1215
1216 /*
1217         Quickhands for typical request-result queues.
1218         Used for distributing work between threads.
1219 */
1220
1221 template<typename Key, typename T, typename Caller, typename CallerData>
1222 class RequestQueue
1223 {
1224 public:
1225         u32 size()
1226         {
1227                 return m_queue.size();
1228         }
1229
1230         void add(Key key, Caller caller, CallerData callerdata,
1231                         ResultQueue<Key, T, Caller, CallerData> *dest)
1232         {
1233                 JMutexAutoLock lock(m_queue.getMutex());
1234                 
1235                 /*
1236                         If the caller is already on the list, only update CallerData
1237                 */
1238                 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1239                                 i = m_queue.getList().begin();
1240                                 i != m_queue.getList().end(); i++)
1241                 {
1242                         GetRequest<Key, T, Caller, CallerData> &request = *i;
1243
1244                         if(request.key == key)
1245                         {
1246                                 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1247                                                 i = request.callers.begin();
1248                                                 i != request.callers.end(); i++)
1249                                 {
1250                                         CallerInfo<Caller, CallerData> &ca = *i;
1251                                         if(ca.caller == caller)
1252                                         {
1253                                                 ca.data = callerdata;
1254                                                 return;
1255                                         }
1256                                 }
1257                                 CallerInfo<Caller, CallerData> ca;
1258                                 ca.caller = caller;
1259                                 ca.data = callerdata;
1260                                 request.callers.push_back(ca);
1261                                 return;
1262                         }
1263                 }
1264
1265                 /*
1266                         Else add a new request to the queue
1267                 */
1268
1269                 GetRequest<Key, T, Caller, CallerData> request;
1270                 request.key = key;
1271                 CallerInfo<Caller, CallerData> ca;
1272                 ca.caller = caller;
1273                 ca.data = callerdata;
1274                 request.callers.push_back(ca);
1275                 request.dest = dest;
1276                 
1277                 m_queue.getList().push_back(request);
1278         }
1279
1280         GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1281         {
1282                 return m_queue.pop_front(wait_if_empty);
1283         }
1284
1285 private:
1286         MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
1287 };
1288
1289 #endif
1290