1 /*
2 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3 * Alexander Warg <warg@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
5 *
6 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU General Public License 2.
8 * Please see the COPYING-GPL-2 file for details.
9 */
10 #include <l4/re/log>
11 #include <l4/re/log-sys.h>
12 #include <l4/sys/kdebug.h>
13 #include <l4/cxx/minmax>
14
15 #include "globals.h"
16 #include "log.h"
17
18 #include <unistd.h>
19 #include <cstdio>
20 #include <stdarg.h>
21
22 static Moe::Log *last_log = 0;
23
24 class Pbuf
25 {
26 public:
Pbuf()27 Pbuf() : _p(0) {}
size() const28 unsigned long size() const { return sizeof(_b); }
29 void flush();
30 void printf(char const *fmt, ...)
31 __attribute__((format(printf, 2, 3)));
32 void outnstring(char const *str, unsigned long len);
33
34 private:
35 void checknflush(int n);
36 char _b[1024];
37 unsigned long _p;
38
fits(unsigned l) const39 bool fits(unsigned l) const { return (_p + l) < sizeof(_b); }
40 };
41
my_outnstring(char const * s,unsigned long len)42 static void my_outnstring(char const *s, unsigned long len)
43 {
44 write(1, s, len);
45 }
46
47
48
flush()49 void Pbuf::flush()
50 {
51 my_outnstring(_b, _p);
52 _p = 0;
53 }
54
checknflush(int n)55 void Pbuf::checknflush(int n)
56 {
57 char *x = 0;
58 x = (char*)memchr(_b, '\n', _p + n);
59
60 if (x)
61 {
62 int rem = n - (x - _b + 1 - _p);
63 _p = x - _b + 1;
64 flush();
65 if (rem)
66 memmove(_b, x + 1, rem);
67 _p = rem;
68 }
69 else
70 _p += n;
71 }
72
printf(char const * fmt,...)73 void Pbuf::printf(char const *fmt, ...)
74 {
75 if (!fits(strlen(fmt) + 50))
76 flush();
77 int n;
78 va_list arg;
79 va_start(arg, fmt);
80 n = vsnprintf(_b + _p, size() - _p, fmt, arg);
81 va_end(arg);
82 checknflush(n);
83 }
84
outnstring(char const * str,unsigned long len)85 void Pbuf::outnstring(char const *str, unsigned long len)
86 {
87 if (!fits(len))
88 flush();
89 memcpy(_b + _p, str, len);
90 checknflush(len);
91 }
92
93 l4_msgtag_t
op_dispatch(l4_utcb_t * utcb,l4_msgtag_t tag,L4::Vcon::Rights)94 Moe::Log::op_dispatch(l4_utcb_t *utcb, l4_msgtag_t tag, L4::Vcon::Rights)
95 {
96 enum { Max_tag = 8 };
97 if (tag.words() < 2)
98 return l4_msgtag(-L4_EINVAL, 0, 0, 0);
99
100 l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
101 L4::Opcode op = m->mr[0];
102
103 // we only have one opcode
104 if (op != L4Re::Log_::Print)
105 return l4_msgtag(-L4_ENOSYS, 0, 0, 0);
106
107 char *msg = log_buffer;
108 unsigned long len_msg = sizeof(log_buffer);
109
110 if (len_msg > (tag.words() - 2) * sizeof(l4_umword_t))
111 len_msg = (tag.words() - 2) * sizeof(l4_umword_t);
112
113 if (len_msg > m->mr[1])
114 len_msg = m->mr[1];
115
116 memcpy(msg, &m->mr[2], len_msg);
117
118 static Pbuf ob;
119
120 while (len_msg > 0 && msg[0])
121 {
122 if (color())
123 ob.printf("\033[%s3%dm", (color() & 8) ? "01;" : "", (color() & 7));
124 else
125 ob.printf("\033[0m");
126
127 if (last_log != this)
128 {
129 if (last_log != 0)
130 ob.printf("\n");
131
132 ob.outnstring(_tag, cxx::min<unsigned long>(_l, Max_tag));
133 if (_l < Max_tag)
134 ob.outnstring(" ", Max_tag-_l);
135
136 if (_in_line)
137 ob.printf(": ");
138 else
139 ob.printf("| ");
140 }
141
142 long i;
143 for (i = 0; i < (long)len_msg; ++i)
144 if (msg[i] == '\n' || msg[i] == 0)
145 break;
146
147 ob.outnstring(msg, i);
148
149 if (i < (long)len_msg && msg[i] == '\n')
150 {
151 if (color())
152 ob.printf("\033[0m\n");
153 else
154 ob.printf("\n");
155 _in_line = false;
156 last_log = 0;
157 ++i;
158 }
159 else
160 {
161 last_log = this;
162 _in_line = true;
163 }
164
165 msg += i;
166 len_msg -= i;
167 }
168
169 if (_in_line && color())
170 ob.printf("\033[0m");
171
172 // and finally done
173 return l4_msgtag(-L4_ENOREPLY, 0, 0, 0);
174 }
175
176
177 int
color_value(cxx::String const & col)178 Moe::Log::color_value(cxx::String const &col)
179 {
180 int c = 0, bright = 0;
181
182 if (col.empty())
183 return 0;
184
185 switch (col[0])
186 {
187 case 'N': bright = 1; /* FALLTHRU */ case 'n': c = 0; break;
188 case 'R': bright = 1; /* FALLTHRU */ case 'r': c = 1; break;
189 case 'G': bright = 1; /* FALLTHRU */ case 'g': c = 2; break;
190 case 'Y': bright = 1; /* FALLTHRU */ case 'y': c = 3; break;
191 case 'B': bright = 1; /* FALLTHRU */ case 'b': c = 4; break;
192 case 'M': bright = 1; /* FALLTHRU */ case 'm': c = 5; break;
193 case 'C': bright = 1; /* FALLTHRU */ case 'c': c = 6; break;
194 case 'W': bright = 1; /* FALLTHRU */ case 'w': c = 7; break;
195 default: c = 0;
196 }
197
198 return (bright << 3) | c;
199 }
200
201
202