7cbc90e48dc30eeacf20294a6aa11dac3682e8b4
[profile/ivi/speech-recognition.git] / src / plugins / speech-to-text / sphinx / logger.c
1 #include <stdio.h>
2 #include <unistd.h>
3 #define __USE_GNU                        /* F_SETPIPE_SZ */
4 #include <fcntl.h>
5 #include <string.h>
6 #include <errno.h>
7
8 #include <murphy/common/log.h>
9 #include <murphy/common/mainloop.h>
10
11 #include "sphinx-plugin.h"
12
13 #define SPHINX_INFO   "INFO: "
14 #define SPHINX_ERROR  "ERROR: "
15 #define SPHINX_WARN   "WARNING: "
16 #define SPHINX_SYSERR "SYSTEM_ERROR: "
17 #define SPHINX_FATAL  "FATAL_ERROR: "
18
19 #define RD 0
20 #define WR 1
21
22 typedef struct {
23     int             fd[2];               /* log message pipe */
24     FILE           *fp;                  /* log write stream */
25     mrp_io_watch_t *w;                   /* log I/O watch */
26     char            buf[4096];           /* log line buffer */
27     ssize_t         n;
28 } logger_t;
29
30
31 static ssize_t pull_log(logger_t *logger)
32 {
33     char    *p;
34     ssize_t  n, l;
35
36     p = logger->buf + logger->n;
37     l = sizeof(logger->buf) - logger->n - 1;
38
39     n = read(logger->fd[RD], p, l);
40
41     if (n <= 0)
42         return n;
43
44     p[n] = '\0';
45     logger->n += n;
46
47     return logger->n;
48 }
49
50
51 static void push_log(logger_t *logger)
52 {
53     char    *b, *e, *lb, *le, *file, lvl, name[1024];
54     int      line, len, nlen;
55     ssize_t  n;
56
57     name[sizeof(name) - 1] = '\0';
58
59     lvl  = 0;
60     file = NULL;
61
62     while (logger->n > 0) {
63         b = logger->buf;
64
65         if (!strncmp(b, SPHINX_INFO  , len = sizeof(SPHINX_INFO  ) - 1) ||
66             !strncmp(b, SPHINX_WARN  , len = sizeof(SPHINX_WARN  ) - 1) ||
67             !strncmp(b, SPHINX_ERROR , len = sizeof(SPHINX_ERROR ) - 1) ||
68             !strncmp(b, SPHINX_SYSERR, len = sizeof(SPHINX_SYSERR) - 1) ||
69             !strncmp(b, SPHINX_FATAL , len = sizeof(SPHINX_FATAL ) - 1)) {
70             lvl  = *b;
71             b   += len;
72             lb  = strchr(b, '(');
73         }
74         else
75             lvl = 0;
76
77         if ((e = strchr(b, '\n')) == NULL) {
78             if (logger->n >= sizeof(logger->buf) - 1) {
79                 mrp_log_warning("Discarding too long sphinx log buffer.");
80                 logger->n = 0;
81             }
82             return;
83         }
84
85         if (lb != NULL) {
86             line = (int)strtoul(lb + 1, &le, 10);
87
88             if (lb != NULL && *le == ')') {
89                 nlen = lb - b;
90                 snprintf(name, sizeof(name) - 1, "%*.*s", nlen, nlen, b);
91                 file = name;
92                 b = le + 1;
93                 if (b[0] == ':' && b[1] == ' ')
94                     b += 2;
95             }
96         }
97         else {
98             if (file == NULL)
99                 file = "<unknown-file>";
100         }
101
102         n = e - b;
103
104         switch (lvl) {
105         case 'I':
106         default:
107             if (mrp_debug_check(file, "sphinx", line))
108                 mrp_debug_msg("sphinx", line, file, "%*.*s", n, n, b);
109             break;
110         case 'W':
111             mrp_log_msg(MRP_LOG_WARNING, file, line, "sphinx", "%*.*s", n, n, b);
112             break;
113         case 'E':
114         case 'S':
115         case 'F':
116             mrp_log_msg(MRP_LOG_ERROR, file, line, "sphinx", "%*.*s", n, n, b);
117             break;
118         }
119
120         b = e + 1;
121
122         while (*b == '\n')
123             b++;
124
125         n = logger->n - (b - logger->buf);
126
127         if (n <= 0)
128             logger->n = 0;
129         else {
130             memmove(logger->buf, b, n);
131             logger->n = n;
132             logger->buf[n] = '\0';
133         }
134     }
135 }
136
137
138 static void log_cb(mrp_io_watch_t *w, int fd, mrp_io_event_t events,
139                    void *user_data)
140 {
141     logger_t *logger = (logger_t *)user_data;
142
143     MRP_UNUSED(fd);
144
145     if (events & MRP_IO_EVENT_IN)
146         while (pull_log(logger) > 0)
147             push_log(logger);
148
149     if (events & MRP_IO_EVENT_HUP)
150         mrp_del_io_watch(w);
151 }
152
153
154 FILE *logger_create(context_t *ctx)
155 {
156     static logger_t  logger = { { -1, -1 }, NULL, 0 };
157     mrp_mainloop_t  *ml     = plugin_get_mainloop(ctx->plugin);
158     mrp_io_event_t   events = MRP_IO_EVENT_IN | MRP_IO_EVENT_HUP;
159
160     if (logger.fp != NULL)
161         return logger.fp;
162
163     if (pipe(logger.fd) < 0) {
164         mrp_log_error("Failed to create sphinx logging pipe (error %d: %s).",
165                       errno, strerror(errno));
166         goto fail;
167     }
168
169     if ((logger.fp = fdopen(logger.fd[WR], "w")) == NULL)
170         goto fail;
171
172     setvbuf(logger.fp, NULL, _IOLBF, 0);
173
174     fcntl(logger.fd[WR], F_SETPIPE_SZ, 512 * 1024);
175     fcntl(logger.fd[WR], F_SETFL, O_NONBLOCK);
176     fcntl(logger.fd[RD], F_SETFL, O_NONBLOCK);
177
178     logger.w = mrp_add_io_watch(ml, logger.fd[RD], events, log_cb, &logger);
179
180     if (logger.w != NULL)
181         return logger.fp;
182
183     /* fallthru */
184
185  fail:
186     close(logger.fd[0]);
187     close(logger.fd[1]);
188     if (logger.fp != NULL)
189         fclose(logger.fp);
190
191     logger.fd[0] = -1;
192     logger.fd[1] = -1;
193     logger.fp = NULL;
194
195     return NULL;
196 }