]> git.lizzy.rs Git - dragonfireclient.git/blob - src/utility.h
work-in-progress gui system updating + some settings system updating
[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                 // If it is in settings
1013                 if(m_settings.find(name))
1014                         return getBool(name);
1015                 
1016                 std::string s;
1017                 char templine[10];
1018                 std::cout<<question<<" [y/N]: ";
1019                 std::cin.getline(templine, 10);
1020                 s = templine;
1021
1022                 if(s == "")
1023                         return def;
1024
1025                 return is_yes(s);
1026         }
1027
1028         float getFloat(std::string name)
1029         {
1030                 float f;
1031                 std::istringstream vis(get(name));
1032                 vis>>f;
1033                 return f;
1034         }
1035
1036         u16 getU16(std::string name)
1037         {
1038                 return stoi(get(name), 0, 65535);
1039         }
1040
1041         u16 getU16Ask(std::string name, std::string question, u16 def)
1042         {
1043                 // If it is in settings
1044                 if(m_settings.find(name))
1045                         return getU16(name);
1046                 
1047                 std::string s;
1048                 char templine[10];
1049                 std::cout<<question<<" ["<<def<<"]: ";
1050                 std::cin.getline(templine, 10);
1051                 s = templine;
1052
1053                 if(s == "")
1054                         return def;
1055
1056                 return stoi(s, 0, 65535);
1057         }
1058
1059         s16 getS16(std::string name)
1060         {
1061                 return stoi(get(name), -32768, 32767);
1062         }
1063
1064         s32 getS32(std::string name)
1065         {
1066                 return stoi(get(name));
1067         }
1068
1069 private:
1070         core::map<std::string, std::string> m_settings;
1071         core::map<std::string, std::string> m_defaults;
1072 };
1073
1074 /*
1075         FIFO queue
1076 */
1077 template<typename T>
1078 class Queue
1079 {
1080 public:
1081         void push_back(T t)
1082         {
1083                 m_list.push_back(t);
1084         }
1085         
1086         T pop_front()
1087         {
1088                 if(m_list.size() == 0)
1089                         throw ItemNotFoundException("MutexedQueue: queue is empty");
1090
1091                 typename core::list<T>::Iterator begin = m_list.begin();
1092                 T t = *begin;
1093                 m_list.erase(begin);
1094                 return t;
1095         }
1096
1097         u32 size()
1098         {
1099                 return m_list.size();
1100         }
1101
1102 protected:
1103         core::list<T> m_list;
1104 };
1105
1106 /*
1107         Thread-safe FIFO queue
1108 */
1109
1110 template<typename T>
1111 class MutexedQueue
1112 {
1113 public:
1114         MutexedQueue()
1115         {
1116                 m_mutex.Init();
1117         }
1118         u32 size()
1119         {
1120                 return m_list.size();
1121         }
1122         void push_back(T t)
1123         {
1124                 JMutexAutoLock lock(m_mutex);
1125                 m_list.push_back(t);
1126         }
1127         T pop_front(u32 wait_time_max_ms=0)
1128         {
1129                 u32 wait_time_ms = 0;
1130
1131                 for(;;)
1132                 {
1133                         {
1134                                 JMutexAutoLock lock(m_mutex);
1135
1136                                 if(m_list.size() > 0)
1137                                 {
1138                                         typename core::list<T>::Iterator begin = m_list.begin();
1139                                         T t = *begin;
1140                                         m_list.erase(begin);
1141                                         return t;
1142                                 }
1143
1144                                 if(wait_time_ms >= wait_time_max_ms)
1145                                         throw ItemNotFoundException("MutexedQueue: queue is empty");
1146                         }
1147
1148                         // Wait a while before trying again
1149                         sleep_ms(10);
1150                         wait_time_ms += 10;
1151                 }
1152         }
1153
1154         JMutex & getMutex()
1155         {
1156                 return m_mutex;
1157         }
1158
1159         core::list<T> & getList()
1160         {
1161                 return m_list;
1162         }
1163
1164 protected:
1165         JMutex m_mutex;
1166         core::list<T> m_list;
1167 };
1168
1169 template<typename Caller, typename Data>
1170 class CallerInfo
1171 {
1172 public:
1173         Caller caller;
1174         Data data;
1175 };
1176
1177 template<typename Key, typename T, typename Caller, typename CallerData>
1178 class GetResult
1179 {
1180 public:
1181         Key key;
1182         T item;
1183         core::list<CallerInfo<Caller, CallerData> > callers;
1184 };
1185
1186 template<typename Key, typename T, typename Caller, typename CallerData>
1187 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
1188 {
1189 };
1190
1191 template<typename Key, typename T, typename Caller, typename CallerData>
1192 class GetRequest
1193 {
1194 public:
1195         GetRequest()
1196         {
1197                 dest = NULL;
1198         }
1199         GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest)
1200         {
1201                 dest = a_dest;
1202         }
1203         GetRequest(ResultQueue<Key,T, Caller, CallerData> *a_dest,
1204                         Key a_key)
1205         {
1206                 dest = a_dest;
1207                 key = a_key;
1208         }
1209         ~GetRequest()
1210         {
1211         }
1212         
1213         Key key;
1214         ResultQueue<Key, T, Caller, CallerData> *dest;
1215         core::list<CallerInfo<Caller, CallerData> > callers;
1216 };
1217
1218 /*
1219         Quickhands for typical request-result queues.
1220         Used for distributing work between threads.
1221 */
1222
1223 template<typename Key, typename T, typename Caller, typename CallerData>
1224 class RequestQueue
1225 {
1226 public:
1227         u32 size()
1228         {
1229                 return m_queue.size();
1230         }
1231
1232         void add(Key key, Caller caller, CallerData callerdata,
1233                         ResultQueue<Key, T, Caller, CallerData> *dest)
1234         {
1235                 JMutexAutoLock lock(m_queue.getMutex());
1236                 
1237                 /*
1238                         If the caller is already on the list, only update CallerData
1239                 */
1240                 for(typename core::list< GetRequest<Key, T, Caller, CallerData> >::Iterator
1241                                 i = m_queue.getList().begin();
1242                                 i != m_queue.getList().end(); i++)
1243                 {
1244                         GetRequest<Key, T, Caller, CallerData> &request = *i;
1245
1246                         if(request.key == key)
1247                         {
1248                                 for(typename core::list< CallerInfo<Caller, CallerData> >::Iterator
1249                                                 i = request.callers.begin();
1250                                                 i != request.callers.end(); i++)
1251                                 {
1252                                         CallerInfo<Caller, CallerData> &ca = *i;
1253                                         if(ca.caller == caller)
1254                                         {
1255                                                 ca.data = callerdata;
1256                                                 return;
1257                                         }
1258                                 }
1259                                 CallerInfo<Caller, CallerData> ca;
1260                                 ca.caller = caller;
1261                                 ca.data = callerdata;
1262                                 request.callers.push_back(ca);
1263                                 return;
1264                         }
1265                 }
1266
1267                 /*
1268                         Else add a new request to the queue
1269                 */
1270
1271                 GetRequest<Key, T, Caller, CallerData> request;
1272                 request.key = key;
1273                 CallerInfo<Caller, CallerData> ca;
1274                 ca.caller = caller;
1275                 ca.data = callerdata;
1276                 request.callers.push_back(ca);
1277                 request.dest = dest;
1278                 
1279                 m_queue.getList().push_back(request);
1280         }
1281
1282         GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
1283         {
1284                 return m_queue.pop_front(wait_if_empty);
1285         }
1286
1287 private:
1288         MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
1289 };
1290
1291 #endif
1292