Add a framework for UCS-4 strings.
[ccbs] / bigscreen / ccbs_bigscreen.cpp
1 #include <cstdio>
2 #include <cstring>
3 #include <iconv.h>
4 #include <unistd.h>
5 #include <pqxx/pqxx>
6 #include "glwindow.h"
7
8 iconv_t ucs4_iconv;
9
10 // UCS-4 string
11 class widestring : public std::basic_string<unsigned>
12 {
13 public:
14 };
15
16 template<>
17 void std::char_traits<unsigned>::assign(unsigned &to, unsigned const &from)
18 {
19         to = from;
20 }
21
22 template<>
23 unsigned *std::char_traits<unsigned>::copy(unsigned *to, unsigned const *from, unsigned n)
24 {
25         return static_cast<unsigned *>(memcpy(to, from, n * sizeof(unsigned)));
26 }
27
28 template<>
29 unsigned *std::char_traits<unsigned>::move(unsigned *to, unsigned const *from, unsigned n)
30 {
31         return static_cast<unsigned *>(memmove(to, from, n * sizeof(unsigned)));
32 }
33
34 template<>
35 unsigned *std::char_traits<unsigned>::assign(unsigned *to, size_t n, unsigned a)
36 {
37         for (unsigned i = 0; i < n; ++i)
38                 *to++ = a;
39         return to;
40 }
41
42
43 template<>
44 void pqxx::from_string<widestring>(const char *from, widestring &to)
45 {
46         unsigned bytes = std::strlen(from);
47         char *from_buf = strdup(from);
48         unsigned *to_buf = new unsigned[bytes + 1];
49         
50         char *inptr = from_buf, *outptr = reinterpret_cast<char *> (to_buf);
51         
52         size_t in_left = bytes;
53         size_t out_left = bytes * sizeof(unsigned);
54
55         size_t ret = iconv(ucs4_iconv, NULL, NULL, &outptr, &out_left);
56         if (ret == (size_t)(-1)) {
57                 throw std::runtime_error("Error in iconv during initialization");
58         }
59
60         ret = iconv(ucs4_iconv, &inptr, &in_left, &outptr, &out_left);
61         if (ret == (size_t)(-1)) {
62                 perror("iconv");
63                 throw std::runtime_error("Error in iconv during conversion");
64         }
65
66         to.erase(to.begin(), to.end());
67         std::copy(to_buf, reinterpret_cast<unsigned *> (outptr), std::back_inserter(to));
68
69         free(from_buf);
70         delete[] to_buf;
71 }
72
73 class Tournament {
74 public:
75         int id;
76         widestring name;
77 };
78
79 Tournament active_tournament;
80
81 /* A trigger that sets a flag whenever it's trigged. */
82 class FlagTrigger : pqxx::trigger {
83 private:
84         bool flag;
85         
86 public:
87         FlagTrigger(pqxx::connection_base &conn, const PGSTD::string &name)
88                 : pqxx::trigger(conn, name), flag(false) {}
89         virtual ~FlagTrigger() throw () {}
90         
91         virtual void operator() (int pid)
92         {
93                 flag = true;
94                 std::fprintf(stderr, "Received a flag trigger from pid %u\n", pid);
95         }
96
97         bool get_flag() const
98         {
99                 return flag;
100         }
101
102         void reset_flag()
103         {
104                 flag = false;
105         }
106 };
107
108 /* A transactor that fetches the current tournament and some information about it. */
109 class FetchCurrentTournament : public pqxx::transactor<> {
110 private:
111         Tournament *tourn;
112
113 public:
114         FetchCurrentTournament(Tournament *tourn) : tourn(tourn) {}
115         void operator() (pqxx::transaction<> &t)
116         {
117                 pqxx::result res( t.exec("SELECT * FROM bigscreen.active_tournament NATURAL JOIN tournaments") );
118                 try {
119                         pqxx::result::tuple tournament = res.at(0);
120
121                         tourn->id = tournament["tournament"].as(tourn->id);
122                         tourn->name = tournament["tournamentname"].as(tourn->name);
123                 } catch (PGSTD::out_of_range &e) {
124                         tourn->id = -1;
125 //                      tourn->name = "";
126                 }
127         }
128 };
129
130 void init(pqxx::connection &conn)
131 {
132         conn.perform(FetchCurrentTournament(&active_tournament));
133
134         if (active_tournament.id == -1) {
135                 std::fprintf(stderr, "No active tournament\n");
136         } else {
137                 std::fprintf(stderr, "Current tournament is %d (name: '%s')\n",
138                         active_tournament.id, active_tournament.name.c_str());
139         }
140 }
141
142 void main_loop(pqxx::connection &conn)
143 {
144         if (active_tournament.id == -1) {
145                 // No active tournament, sleep a second or so and exit
146                 sleep(1);
147                 return;
148         }
149         
150         pqxx::work t(conn, "trx");
151
152         // fetch all songs
153         pqxx::result res( t.exec("SELECT * FROM songs") );
154         for (pqxx::result::const_iterator i = res.begin(); i != res.end(); ++i) {
155                 std::fprintf(stderr, "%s\n", i["title"].c_str());
156         }
157         t.commit();
158         
159         sleep(1);
160 }
161
162 int main(int argc, char **argv)
163 {
164         ucs4_iconv = iconv_open("ucs-4", "utf-8");
165         
166 //      GLWindow glw("CCBS bigscreen", 800, 600, 32, false, 16, -1);
167         try {
168                 pqxx::connection conn("dbname=ccbs host=altersex.samfundet.no user=ccbs password=GeT|>>B_");
169                 FlagTrigger tournament_changed(conn, "active_tournament");
170                 
171                 // when active_tournament is changed, we destroy everything and start from scratch
172                 for ( ;; ) {
173                         tournament_changed.reset_flag();
174                         init(conn);
175                         do {
176                                 main_loop(conn);
177                                 conn.get_notifs();
178                         } while (!tournament_changed.get_flag());
179                         std::fprintf(stderr, "active_tournament changed, resetting...\n");
180                 }
181         } catch (const std::exception &e) {
182                 std::fprintf(stderr, "Exception: %s\n", e.what());
183                 exit(1);
184         }
185         
186         return 0;
187 }