OSDN Git Service

[Qt][LOGGER] copy_log(): Using arg ; start_size.
[csp-qt/common_source_project-fm7.git] / source / src / qt / gui / csp_logger.cpp
1 /*
2  * Log functions
3  * (C) 2014-06-30 K.Ohta
4  * History:
5  *  Dec 30, 2014 Move from XM7/SDL, this was Ohta's original code.
6  * Licence : GPLv2
7  */
8
9 #include <QMutex>
10 #include <QMutexLocker>
11
12 #include "csp_logger.h"
13 #include <string.h>
14 #include "emu.h"
15 #include "vm/vm.h"
16 #include "menu_flags.h"
17 #include "../osd.h"
18
19 CSP_Logger::CSP_Logger(bool b_syslog, bool cons, const char *devname)
20 {
21         lock_mutex = new QMutex(QMutex::Recursive);
22         this->reset();
23         this->open(b_syslog, cons, devname);
24 }
25
26
27 CSP_Logger::~CSP_Logger()
28 {
29         loglist.clear();
30         log_sysname.clear();
31         squeue.clear();
32         delete lock_mutex;
33 }
34
35 void CSP_Logger::reset(void)
36 {
37         QString tmps;
38         const char *p;
39
40         QMutexLocker locker(lock_mutex);
41         component_names.clear();
42         vfile_names.clear();
43         cpu_names.clear();
44         device_names.clear();
45         max_cpus = 0;
46         max_devices = 0;
47         
48         const char *components[] = {
49                 "GENERAL",
50                 "OSD",
51                 "EMU",
52                 "VM",
53                 "GUI",
54                 "SOUND",
55                 "VIDEO",
56                 "KEYBOARD",
57                 "MOUSE",
58                 "JOYSTICK",
59                 "MOVIE_LOADER",
60                 "MOVIE_SAVER",
61                 "SCREEN",
62                 "PRINTER",
63                 "SOCKET",
64                 "EVENT",
65                 "Undefined",
66                 NULL
67         };
68         for(int i = 0; ; i++) {
69                 p = components[i];
70                 if(p == NULL) break;
71                 tmps = QString::fromUtf8(p);
72                 component_names.append(tmps);
73         }
74         const char *vfiles[] = {
75                 "BINARY",
76                 "BUBBLE",
77                 "CART",
78                 "CMT",
79                 "CD",
80                 "FD",
81                 "LD",
82                 "QD",
83                 NULL
84         };
85         for(int i = 0; ; i++) {
86                 QString ss;
87                 int lim;
88                 p = vfiles[i];
89                 if(p == NULL) break;
90                 tmps = QString::fromUtf8(p);
91                 if(i == 5) { // FD
92                         lim = 16;
93                 } else if(i == 7) { // QD
94                         lim = 16;
95                 } else {
96                         lim = 8;
97                 }
98                 for(int j = 0; j < lim; j++) {
99                         ss.setNum(j + 1);
100                         vfile_names.append(tmps + ss);
101                 }
102         }
103         
104         tmps = QString::fromUtf8("CPU"); // Enable to update
105         for(int i = 0; i < 8; i++) {
106                 QString ss;
107                 ss.setNum(i);
108                 cpu_names.append(tmps + ss);
109                 for(int j = 0; j < CSP_LOG_LEVELS; j++) {
110                         level_cpu_out_record[i][j] = true;
111                         level_cpu_out_syslog[i][j] = false;
112                         level_cpu_out_console[i][j] = true;
113                 }
114         }
115         tmps = QString::fromUtf8("DEV"); // Enable to update
116         for(int i = 0; i < (256 - (32 + 8)); i++) {
117                 QString ss;
118                 ss.setNum(i);
119                 device_names.append(tmps + ss);
120                 for(int j = 0; j < CSP_LOG_LEVELS; j++) {
121                         level_dev_out_record[i][j] = true;
122                         level_dev_out_syslog[i][j] = false;
123                         level_dev_out_console[i][j] = true;
124                 }
125         }
126 }
127
128 //extern class USING_FLAGS *using_flags;
129 void CSP_Logger::open(bool b_syslog, bool cons, const char *devname)
130 {
131         int flags = 0;
132         
133         QMutexLocker locker(lock_mutex);
134         log_onoff = true;
135         
136         loglist.clear();
137         log_sysname.clear();
138         squeue.clear();
139         
140         QString dname;
141         if(devname != NULL) {
142                 dname = QString::fromUtf8(devname);
143         } else {
144                 dname = QString::fromUtf8("*Undefined*");
145         }
146         log_sysname = QString::fromUtf8("Common Source Code Project(");
147         log_sysname = log_sysname + dname + QString::fromUtf8(")");
148         
149         if(b_syslog) {
150                 syslog_flag = true;
151 #if defined(_SYS_SYSLOG_H) || defined(_SYSLOG_H)
152                 if(cons) { 
153                         flags = LOG_CONS;
154                 }
155                 openlog(log_sysname.toLocal8Bit().constData(), flags | LOG_PID | LOG_NOWAIT, LOG_USER);
156 #endif
157         } else {
158                 syslog_flag = false;
159         }
160         log_cons = cons;
161         log_opened = true;
162         log_cons_out = log_cons;
163         syslog_flag_out = syslog_flag;
164         
165         cons_log_levels = 1 << CSP_LOG_INFO;
166         linenum = 1;
167         line_wrap = 0;
168         
169         this->debug_log(CSP_LOG_INFO, "Start logging.");
170 }
171
172 void CSP_Logger::debug_log(int level, const char *fmt, ...)
173 {
174         char strbuf[4096];
175         va_list ap;
176         
177         va_start(ap, fmt);      
178         vsnprintf(strbuf, 4095, fmt, ap);
179         debug_log(level, 0, strbuf);
180         va_end(ap);
181 }
182
183
184 void CSP_Logger::debug_log(int level, int domain_num, const char *fmt, ...)
185 {
186         char strbuf[4096];
187         va_list ap;
188         
189         va_start(ap, fmt);      
190         vsnprintf(strbuf, 4095, fmt, ap);
191         debug_log(level, domain_num, strbuf);
192         va_end(ap);
193 }
194
195 void CSP_Logger::debug_log(int level, int domain_num, char *strbuf)
196 {
197         struct tm *timedat;
198         time_t nowtime;
199         char strbuf2[256];
200         char strbuf3[24];
201         struct timeval tv;
202         
203         if(!log_opened) return;
204         if(level < 0) level = 0;
205         if(level >= CSP_LOG_LEVELS) level = CSP_LOG_LEVELS - 1;
206                 
207 #if !defined(Q_OS_WIN)   
208         int level_flag = LOG_USER;
209         if(level == CSP_LOG_DEBUG) {
210            level_flag |= LOG_DEBUG;
211         } else if(level == CSP_LOG_INFO) { 
212            level_flag |= LOG_INFO;
213         } else if(level == CSP_LOG_WARN) {
214            level_flag |= LOG_WARNING;
215         } else {
216            level_flag |= LOG_DEBUG;
217         }
218 #endif  
219         char *p;
220         char *p_bak;
221         const char delim[2] = "\n";
222         {
223                 QMutexLocker locker(lock_mutex);
224 #ifdef __MINGW32__
225                 p = strtok(strbuf, delim);
226 #else
227                 p = strtok_r(strbuf, delim, &p_bak); 
228 #endif
229         }
230         if(strbuf != NULL) {
231                 nowtime = time(NULL);
232                 gettimeofday(&tv, NULL);
233                 if(log_cons != 0) { // Print only
234                         timedat = localtime(&nowtime);
235                         strftime(strbuf2, 255, "%Y-%m-%d %H:%M:%S", timedat);
236                         snprintf(strbuf3, 23, ".%06ld", tv.tv_usec);
237                 }
238                 QString time_s = QString::fromUtf8(strbuf2) + QString::fromUtf8(strbuf3);
239                 
240                 int cons_log_level_n = (1 << level) & cons_log_levels;
241                 int sys_log_level_n = (1 << level) & sys_log_levels;
242                 QString domain_s;
243                 bool record_flag = true;
244                 
245                 domain_s.clear();
246                 if((domain_num > 0) && (domain_num < CSP_LOG_TYPE_COMPONENT_END)) {
247                         domain_s = component_names.at(domain_num - 1);
248                 } else if((domain_num >= CSP_LOG_TYPE_VM_CPU0) && (domain_num < CSP_LOG_TYPE_VM_DEVICE_0)) {
249                         domain_s = cpu_names.at(domain_num - CSP_LOG_TYPE_VM_CPU0);
250                         
251                         record_flag = level_cpu_out_record[domain_num - CSP_LOG_TYPE_VM_CPU0][level];
252                         if(!level_cpu_out_syslog[domain_num - CSP_LOG_TYPE_VM_CPU0][level]) sys_log_level_n = 0;
253                         if(!level_cpu_out_console[domain_num - CSP_LOG_TYPE_VM_CPU0][level]) cons_log_level_n = 0;
254                 } else if((domain_num >= CSP_LOG_TYPE_VM_DEVICE_0) && (domain_num <= CSP_LOG_TYPE_VM_DEVICE_END)) {
255                         domain_s = device_names.at(domain_num - CSP_LOG_TYPE_VM_DEVICE_0);
256                         
257                         record_flag = level_dev_out_record[domain_num - CSP_LOG_TYPE_VM_DEVICE_0][level];
258                         if(!level_dev_out_syslog[domain_num - CSP_LOG_TYPE_VM_DEVICE_0][level]) sys_log_level_n = 0;
259                         if(!level_dev_out_console[domain_num - CSP_LOG_TYPE_VM_DEVICE_0][level]) cons_log_level_n = 0;
260                 } else if((domain_num >= CSP_LOG_TYPE_VFILE_HEAD) && (domain_num < CSP_LOG_TYPE_VFILE_END)) {
261                         domain_s = vfile_names.at(domain_num - CSP_LOG_TYPE_VFILE_HEAD);
262                 }
263                 if(!domain_s.isEmpty()) {
264                         domain_s = QString::fromUtf8("[") + domain_s + QString::fromUtf8("]");
265                 }
266                 if(!log_cons || !log_cons_out) cons_log_level_n = 0;
267                 if(!syslog_flag || !syslog_flag_out) sys_log_level_n = 0;
268                 
269                 do {
270                         if(p != NULL) {
271                                 CSP_LoggerLine *tmps;
272                                 tmps = new CSP_LoggerLine(linenum, level, domain_s, time_s, QString::fromUtf8(p));
273                                 if(log_onoff) {
274                                         if(cons_log_level_n != 0) {
275                                                 fprintf(stdout, "%s : %s\n",
276                                                                 log_sysname.toLocal8Bit().constData(),
277                                                                 tmps->get_element_console().toLocal8Bit().constData());
278                                         }
279 #if !defined(Q_OS_WIN)   
280                                         if(sys_log_level_n != 0) {
281                                                 syslog(level_flag, "uS=%06ld %s",
282                                                            tv.tv_usec,
283                                                            tmps->get_element_syslog().toLocal8Bit().constData());
284                                         }
285 #endif
286                                 }
287                                 {
288                                         QMutexLocker locker(lock_mutex);
289 #ifdef __MINGW32__
290                                         p = strtok(NULL, delim);
291 #else
292                                         p = strtok_r(NULL, delim, &p_bak);
293 #endif
294                                 }
295                                 if(!record_flag) {
296                                         delete tmps;
297                                 } else {
298                                         QMutexLocker locker(lock_mutex);
299                                         squeue.enqueue(tmps);
300                                         if(linenum == LLONG_MAX) {
301                                                 line_wrap++;
302                                                 linenum = 0;
303                                         } else {
304                                                 linenum++;
305                                         }
306                                 }
307                         }
308 #if defined(Q_OS_WIN)
309                         {
310                                 QMutexLocker locker(lock_mutex);
311                                 fflush(stdout);
312                         }
313 #endif                  
314                 } while(p != NULL);
315         }
316 }
317
318 void CSP_Logger::set_log_status(bool sw)
319 {
320         log_onoff = sw;
321 }
322    
323 void CSP_Logger::set_log_stdout(int level, bool sw)
324 {
325         if((level < 0) || (level >= 32)) {
326                 log_cons_out = sw;
327                 return;
328         }
329         int lv = 1 << level;
330         if(sw) {
331                 cons_log_levels |= lv;
332         } else {
333                 cons_log_levels &= ~lv;
334         }
335 }
336
337 void CSP_Logger::set_log_syslog(int level, bool sw)
338 {
339         if((level < 0) || (level >= 32)) {
340                 syslog_flag_out = sw;
341                 return;
342         }
343         int lv = 1 << level;
344         if(sw) {
345                 sys_log_levels |= lv;
346         } else {
347                 sys_log_levels &= ~lv;
348         }
349 }
350
351 bool CSP_Logger::get_status(void)
352 {
353         return log_opened;
354 }
355    
356         
357 void CSP_Logger::close(void)
358 {
359         QMutexLocker locker(lock_mutex);
360
361         log_opened = false;
362 #if !defined(Q_OS_WIN32)   
363         if(syslog_flag != 0) {
364              closelog();
365         }
366 #endif
367         syslog_flag = false;
368         syslog_flag_out = false;
369         
370         log_cons = false;
371         log_cons_out = false;
372         
373         log_onoff = false;
374         
375         while(!squeue.isEmpty()) {
376                 CSP_LoggerLine *p = squeue.dequeue();
377                 if(p != NULL) delete p;
378         }
379         loglist.clear();
380         log_sysname.clear();
381         squeue.clear();
382 }
383
384 void CSP_Logger::set_emu_vm_name(const char *devname)
385 {
386         QString dname;
387         if(devname != NULL) {
388                 dname = QString::fromUtf8(devname);
389         } else {
390                 dname = QString::fromUtf8("*Undefined*");
391         }
392         log_sysname = QString::fromUtf8("Common Source Code Project(");
393         log_sysname = log_sysname + dname + QString::fromUtf8(")");
394 }
395
396 void CSP_Logger::set_device_name(int num, char *devname)
397 {
398         QString tmps;
399         if(num < 0) return;
400         if(num > (CSP_LOG_TYPE_VM_DEVICE_END - CSP_LOG_TYPE_VM_DEVICE_0)) return;
401         if(devname == NULL) {
402                 QString s;
403                 s.setNum(num);
404                 tmps = QString::fromUtf8("Device#");
405                 tmps = tmps + s;
406         } else {
407                 tmps = QString::fromUtf8(devname);
408         }
409         device_names.replace(num, tmps);
410         if(max_devices <= num) max_devices = num + 1;
411 }
412
413 void CSP_Logger::set_cpu_name(int num, char *devname)
414 {
415         if(num < 0) return;
416         if(num > (CSP_LOG_TYPE_VM_CPU7 - CSP_LOG_TYPE_VM_CPU0)) return;
417         if(devname == NULL) return;
418         QString tmps = QString::fromUtf8(devname);
419         device_names.replace(num, tmps);
420         if(max_cpus <= num) max_cpus = num + 1;
421 }
422
423 void CSP_Logger::set_device_node_log(int device_id, int to_output, int type, bool flag)
424 {
425         if(type < 0) return;
426         if(type >= CSP_LOG_LEVELS) return;
427         if(to_output < 0) return;
428         if(to_output > 2) return;
429         if(device_id >= (CSP_LOG_TYPE_VM_DEVICE_END - CSP_LOG_TYPE_VM_DEVICE_0)) return;
430         if(device_id == -1) { // Flush all device
431                 for(int i = 0; i < (CSP_LOG_TYPE_VM_DEVICE_END - CSP_LOG_TYPE_VM_DEVICE_0 + 1); i++) {
432                         // 0 = record, 1 = syslog, 2 = console;
433                         switch(to_output)
434                         {
435                         case 0:
436                                 level_dev_out_record[i][type] = flag;
437                                 break;
438                         case 1:
439                                 level_dev_out_syslog[i][type] = flag;
440                                 break;
441                         case 2:
442                                 level_dev_out_console[i][type] = flag;
443                                 break;
444                         default:
445                                 break;
446                         }
447                 }
448         } else {
449                 // 0 = record, 1 = syslog, 2 = console;
450                 switch(to_output)
451                 {
452                 case 0:
453                         level_dev_out_record[device_id][type] = flag;
454                         break;
455                 case 1:
456                         level_dev_out_syslog[device_id][type] = flag;
457                         break;
458                 case 2:
459                         level_dev_out_console[device_id][type] = flag;
460                         break;
461                 default:
462                         break;
463                 }
464         }
465 }
466
467 void CSP_Logger::set_device_node_log(int to_output, int type, bool *flags, int start, int devices)
468 {
469         if(flags == NULL) return;
470         if(start < 0) return;
471
472         int i;
473         for(i = 0; i < devices; i++) {
474                 set_device_node_log(i + start, to_output, type, flags[i]);
475         }
476 }
477
478 void CSP_Logger::set_device_node_log(int to_output, int type, int *flags, int start, int devices)
479 {
480         if(flags == NULL) return;
481         if(start < 0) return;
482         
483         int i;
484         bool f;
485         for(i = 0; i < devices; i++) {
486                 f = (flags[i] == 0) ? false : true;
487                 set_device_node_log(i + start, to_output, type, f);
488         }
489 }
490
491 void CSP_Logger::output_event_log(int device_id, int level, const char *fmt, ...)
492 {
493         char strbuf[4500];
494         char strbuf2[4096];
495         char *p = NULL;
496         p = (char *)(device_names.at(device_id).toLocal8Bit().constData());
497         
498         va_list ap;
499         va_start(ap, fmt);      
500         vsnprintf(strbuf2, 4095, fmt, ap);
501         snprintf(strbuf, 4500, "[%s] %s", p, strbuf2); 
502         debug_log(level, CSP_LOG_TYPE_EVENT, strbuf);
503         va_end(ap);
504 }
505
506 int64_t CSP_Logger::get_console_list(char *buffer, int64_t buf_size, bool utf8, char *domainname, bool forget, int64_t start, int64_t end)
507 {
508         if((buffer == NULL) || (buf_size <= 0)) return (int64_t)-1;
509
510         QString dom;
511         char tmpbuf[8192];
512         bool not_match_domain = false;
513         if(domainname == NULL) not_match_domain = true;
514         if(!not_match_domain && (domainname != NULL)) dom = QString::fromUtf8(domainname);
515         if(dom.isEmpty()) not_match_domain = true;
516
517         int64_t total_size = 0;
518         CSP_LoggerLine *t;
519         QString tmps;
520         char *pp = buffer;
521         bool check_line = ((start >= 0) && (end >= start));
522         int ssize;
523         {
524                 QMutexLocker locker(lock_mutex);
525                 ssize=squeue.size();
526         }
527         for(int i = 0; i < ssize; i++) {
528                 if(forget) {
529                         QMutexLocker locker(lock_mutex);
530                         if(squeue.isEmpty()) break;
531                         t = squeue.dequeue();
532                 } else {
533                         QMutexLocker locker(lock_mutex);
534                         t = squeue.at(i);
535                 }
536                 if(t != NULL) {
537                         if(check_line) {
538                                 int64_t n_line = t->get_line_num();
539                                 if((n_line < start) || (n_line >= end)) {
540                                         if(forget) {
541                                                 QMutexLocker locker(lock_mutex);
542                                                 delete t;
543                                         }
544                                         continue;
545                                 }
546                         }
547
548                         if(not_match_domain) {
549                                 tmps = t->get_element_console();
550                         } else {
551                                 if(dom == t->get_domain()) {
552                                         tmps = t->get_element_console();
553                                 } else {
554                                         tmps.clear();
555                                 }
556                         }
557                         if(!tmps.isEmpty()) {
558                                 int l = 0;
559                                 QByteArray ns;
560                                 if(utf8) {
561                                         ns = tmps.toUtf8();
562                                 } else {
563                                         ns = tmps.toLocal8Bit();
564                                 }
565                                 l = ns.size();
566                                 if(l > 0) {
567                                         memset(tmpbuf, 0x00, 8192);
568                                         if(l >= 8192) l = 8192 -1;
569                                         strncpy(tmpbuf, ns.constData(), l);
570                                 }
571                                 if(((int64_t)l + total_size) < buf_size) {
572                                         strncpy(pp, tmpbuf, l);
573                                         pp += l;
574                                         total_size += (int64_t)l;
575                                 } else {
576                                         if(forget) {
577                                                 QMutexLocker locker(lock_mutex);
578                                                 delete t;
579                                         }
580                                         break;
581                                 }
582                         }
583                         if(forget) {
584                                 QMutexLocker locker(lock_mutex);
585                                 delete t;
586                         }
587                 }
588         }
589         return total_size;
590 }
591
592 void CSP_Logger::clear_log(void)
593 {
594         QMutexLocker locker(lock_mutex);
595         while(!squeue.isEmpty()) {
596                 CSP_LoggerLine *p = squeue.dequeue();
597                 if(p != NULL) delete p;
598         }
599 }
600
601 int64_t CSP_Logger::write_log(const _TCHAR *name, const char *domain_name, bool utf8, bool forget)
602 {
603         int64_t n_len = (int64_t)-1;
604         if(name == NULL) return n_len;
605         
606         FILEIO *fio = new FILEIO();
607         if(fio == NULL) return n_len;
608         
609         if(!fio->Fopen(name, FILEIO_READ_WRITE_BINARY)) {
610                 delete fio;
611                 return n_len;
612         }
613         if(fio->FileLength() > 0) fio->Fseek(0, FILEIO_SEEK_END);
614         n_len = 0;
615         char strbuf[0x20000];
616         int64_t len = 0;
617         do {
618                 memset(strbuf, 0x00, sizeof(strbuf));
619                 len = get_console_list(strbuf, 0x20000, utf8, (char *)domain_name, forget);
620                 if(len > 0x20000) break; // Illegal
621                 if(len <= 0) break;
622                 if(fio->Fwrite(strbuf, (uint32_t)len, 1) != len) break;
623                 n_len += len;
624         } while(len > 0);
625         fio->Fclose();
626         delete fio;
627         return n_len;
628 }
629
630 int64_t CSP_Logger::copy_log(char *buffer, int64_t buf_size, int64_t *lines, char *domainname, bool utf8, bool forget, int64_t start, int64_t start_size)
631 {
632         if((buffer == NULL) || (buf_size <= 0)) return (int64_t)-1;
633         int64_t line = start;
634         int64_t size = 0;
635         int64_t buf_left = buf_size;
636         int64_t lines_t = 0;
637         int64_t nlines = 0;
638         int64_t ssize = start_size;
639         if(ssize < 0) ssize = 0;
640         if(start_size >= buf_size) return -1;
641         
642         char *p = &(buffer[start_size]);
643         
644         if(line < 0) line = 0;
645         {
646                 QMutexLocker locker(lock_mutex);
647                 nlines = squeue.size();
648         }
649         for(; (buf_left > 0) && (nlines > 0);) {
650                 size = get_console_list(buffer, buf_left, utf8, domainname, forget, line, line + 1);
651                 if(size <= 0) break;
652                 buf_left -= size;
653                 ssize += size;
654                 p = &(p[size]);
655                 lines_t++;
656                 nlines--;
657         }
658         if(lines != NULL) *lines = *lines + lines_t;
659         return ssize;
660 }
661